text: // https://syzkaller.appspot.com/bug?id=3baad588490e1e65c3f8f62d1875d50d89b1339a
  // autogenerated by syzkaller (https://github.com/google/syzkaller)
  
  #define _GNU_SOURCE
  
  #include <arpa/inet.h>
  #include <dirent.h>
  #include <endian.h>
  #include <errno.h>
  #include <fcntl.h>
  #include <net/if.h>
  #include <netinet/in.h>
  #include <pthread.h>
  #include <setjmp.h>
  #include <signal.h>
  #include <stdarg.h>
  #include <stdbool.h>
  #include <stddef.h>
  #include <stdint.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <sys/ioctl.h>
  #include <sys/mount.h>
  #include <sys/prctl.h>
  #include <sys/socket.h>
  #include <sys/stat.h>
  #include <sys/syscall.h>
  #include <sys/types.h>
  #include <sys/wait.h>
  #include <time.h>
  #include <unistd.h>
  
  #include <linux/futex.h>
  #include <linux/genetlink.h>
  #include <linux/if_addr.h>
  #include <linux/if_link.h>
  #include <linux/in6.h>
  #include <linux/loop.h>
  #include <linux/neighbour.h>
  #include <linux/net.h>
  #include <linux/netlink.h>
  #include <linux/rtnetlink.h>
  #include <linux/veth.h>
  
  static unsigned long long procid;
  
  static __thread int skip_segv;
  static __thread jmp_buf segv_env;
  
  static void segv_handler(int sig, siginfo_t* info, void* ctx)
  {
    uintptr_t addr = (uintptr_t)info->si_addr;
    const uintptr_t prog_start = 1 << 20;
    const uintptr_t prog_end = 100 << 20;
    int skip = __atomic_load_n(&skip_segv, __ATOMIC_RELAXED) != 0;
    int valid = addr < prog_start || addr > prog_end;
    if (skip && valid) {
      _longjmp(segv_env, 1);
    }
    exit(sig);
  }
  
  static void install_segv_handler(void)
  {
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = SIG_IGN;
    syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
    syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
    memset(&sa, 0, sizeof(sa));
    sa.sa_sigaction = segv_handler;
    sa.sa_flags = SA_NODEFER | SA_SIGINFO;
    sigaction(SIGSEGV, &sa, NULL);
    sigaction(SIGBUS, &sa, NULL);
  }
  
  #define NONFAILING(...)                                                        \
    ({                                                                           \
      int ok = 1;                                                                \
      __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
      if (_setjmp(segv_env) == 0) {                                              \
        __VA_ARGS__;                                                             \
      } else                                                                     \
        ok = 0;                                                                  \
      __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST);                       \
      ok;                                                                        \
    })
  
  static void sleep_ms(uint64_t ms)
  {
    usleep(ms * 1000);
  }
  
  static uint64_t current_time_ms(void)
  {
    struct timespec ts;
    if (clock_gettime(CLOCK_MONOTONIC, &ts))
      exit(1);
    return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
  }
  
  static void use_temporary_dir(void)
  {
    char tmpdir_template[] = "./syzkaller.XXXXXX";
    char* tmpdir = mkdtemp(tmpdir_template);
    if (!tmpdir)
      exit(1);
    if (chmod(tmpdir, 0777))
      exit(1);
    if (chdir(tmpdir))
      exit(1);
  }
  
  static void thread_start(void* (*fn)(void*), void* arg)
  {
    pthread_t th;
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setstacksize(&attr, 128 << 10);
    int i = 0;
    for (; i < 100; i++) {
      if (pthread_create(&th, &attr, fn, arg) == 0) {
        pthread_attr_destroy(&attr);
        return;
      }
      if (errno == EAGAIN) {
        usleep(50);
        continue;
      }
      break;
    }
    exit(1);
  }
  
  #define BITMASK(bf_off, bf_len) (((1ull << (bf_len)) - 1) << (bf_off))
  #define STORE_BY_BITMASK(type, htobe, addr, val, bf_off, bf_len)               \
    *(type*)(addr) =                                                             \
        htobe((htobe(*(type*)(addr)) & ~BITMASK((bf_off), (bf_len))) |           \
              (((type)(val) << (bf_off)) & BITMASK((bf_off), (bf_len))))
  
  typedef struct {
    int state;
  } event_t;
  
  static void event_init(event_t* ev)
  {
    ev->state = 0;
  }
  
  static void event_reset(event_t* ev)
  {
    ev->state = 0;
  }
  
  static void event_set(event_t* ev)
  {
    if (ev->state)
      exit(1);
    __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
    syscall(SYS_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
  }
  
  static void event_wait(event_t* ev)
  {
    while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
      syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
  }
  
  static int event_isset(event_t* ev)
  {
    return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
  }
  
  static int event_timedwait(event_t* ev, uint64_t timeout)
  {
    uint64_t start = current_time_ms();
    uint64_t now = start;
    for (;;) {
      uint64_t remain = timeout - (now - start);
      struct timespec ts;
      ts.tv_sec = remain / 1000;
      ts.tv_nsec = (remain % 1000) * 1000 * 1000;
      syscall(SYS_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
      if (__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
        return 1;
      now = current_time_ms();
      if (now - start > timeout)
        return 0;
    }
  }
  
  static bool write_file(const char* file, const char* what, ...)
  {
    char buf[1024];
    va_list args;
    va_start(args, what);
    vsnprintf(buf, sizeof(buf), what, args);
    va_end(args);
    buf[sizeof(buf) - 1] = 0;
    int len = strlen(buf);
    int fd = open(file, O_WRONLY | O_CLOEXEC);
    if (fd == -1)
      return false;
    if (write(fd, buf, len) != len) {
      int err = errno;
      close(fd);
      errno = err;
      return false;
    }
    close(fd);
    return true;
  }
  
  struct nlmsg {
    char* pos;
    int nesting;
    struct nlattr* nested[8];
    char buf[4096];
  };
  
  static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,
                           const void* data, int size)
  {
    memset(nlmsg, 0, sizeof(*nlmsg));
    struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
    hdr->nlmsg_type = typ;
    hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
    memcpy(hdr + 1, data, size);
    nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);
  }
  
  static void netlink_attr(struct nlmsg* nlmsg, int typ, const void* data,
                           int size)
  {
    struct nlattr* attr = (struct nlattr*)nlmsg->pos;
    attr->nla_len = sizeof(*attr) + size;
    attr->nla_type = typ;
    if (size > 0)
      memcpy(attr + 1, data, size);
    nlmsg->pos += NLMSG_ALIGN(attr->nla_len);
  }
  
  static void netlink_nest(struct nlmsg* nlmsg, int typ)
  {
    struct nlattr* attr = (struct nlattr*)nlmsg->pos;
    attr->nla_type = typ;
    nlmsg->pos += sizeof(*attr);
    nlmsg->nested[nlmsg->nesting++] = attr;
  }
  
  static void netlink_done(struct nlmsg* nlmsg)
  {
    struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];
    attr->nla_len = nlmsg->pos - (char*)attr;
  }
  
  static int netlink_send_ext(struct nlmsg* nlmsg, int sock, uint16_t reply_type,
                              int* reply_len, bool dofail)
  {
    if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)
      exit(1);
    struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;
    hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;
    struct sockaddr_nl addr;
    memset(&addr, 0, sizeof(addr));
    addr.nl_family = AF_NETLINK;
    ssize_t n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0,
                       (struct sockaddr*)&addr, sizeof(addr));
    if (n != (ssize_t)hdr->nlmsg_len) {
      if (dofail)
        exit(1);
      return -1;
    }
    n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
    if (reply_len)
      *reply_len = 0;
    if (n < 0) {
      if (dofail)
        exit(1);
      return -1;
    }
    if (n < (ssize_t)sizeof(struct nlmsghdr)) {
      errno = EINVAL;
      if (dofail)
        exit(1);
      return -1;
    }
    if (hdr->nlmsg_type == NLMSG_DONE)
      return 0;
    if (reply_len && hdr->nlmsg_type == reply_type) {
      *reply_len = n;
      return 0;
    }
    if (n < (ssize_t)(sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))) {
      errno = EINVAL;
      if (dofail)
        exit(1);
      return -1;
    }
    if (hdr->nlmsg_type != NLMSG_ERROR) {
      errno = EINVAL;
      if (dofail)
        exit(1);
      return -1;
    }
    errno = -((struct nlmsgerr*)(hdr + 1))->error;
    return -errno;
  }
  
  static int netlink_send(struct nlmsg* nlmsg, int sock)
  {
    return netlink_send_ext(nlmsg, sock, 0, NULL, true);
  }
  
  static int netlink_query_family_id(struct nlmsg* nlmsg, int sock,
                                     const char* family_name, bool dofail)
  {
    struct genlmsghdr genlhdr;
    memset(&genlhdr, 0, sizeof(genlhdr));
    genlhdr.cmd = CTRL_CMD_GETFAMILY;
    netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));
    netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, family_name,
                 strnlen(family_name, GENL_NAMSIZ - 1) + 1);
    int n = 0;
    int err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n, dofail);
    if (err < 0) {
      return -1;
    }
    uint16_t id = 0;
    struct nlattr* attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN +
                                           NLMSG_ALIGN(sizeof(genlhdr)));
    for (; (char*)attr < nlmsg->buf + n;
         attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) {
      if (attr->nla_type == CTRL_ATTR_FAMILY_ID) {
        id = *(uint16_t*)(attr + 1);
        break;
      }
    }
    if (!id) {
      errno = EINVAL;
      return -1;
    }
    recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);
    return id;
  }
  
  static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,
                                      const char* name)
  {
    struct ifinfomsg hdr;
    memset(&hdr, 0, sizeof(hdr));
    netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr,
                 sizeof(hdr));
    if (name)
      netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));
    netlink_nest(nlmsg, IFLA_LINKINFO);
    netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));
  }
  
  static void netlink_device_change(struct nlmsg* nlmsg, int sock,
                                    const char* name, bool up, const char* master,
                                    const void* mac, int macsize,
                                    const char* new_name)
  {
    struct ifinfomsg hdr;
    memset(&hdr, 0, sizeof(hdr));
    if (up)
      hdr.ifi_flags = hdr.ifi_change = IFF_UP;
    hdr.ifi_index = if_nametoindex(name);
    netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));
    if (new_name)
      netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));
    if (master) {
      int ifindex = if_nametoindex(master);
      netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));
    }
    if (macsize)
      netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);
    int err = netlink_send(nlmsg, sock);
    if (err < 0) {
    }
  }
  
  static struct nlmsg nlmsg;
  
  struct fs_image_segment {
    void* data;
    uintptr_t size;
    uintptr_t offset;
  };
  
  #define IMAGE_MAX_SEGMENTS 4096
  #define IMAGE_MAX_SIZE (129 << 20)
  
  #define sys_memfd_create 319
  
  static unsigned long fs_image_segment_check(unsigned long size,
                                              unsigned long nsegs,
                                              struct fs_image_segment* segs)
  {
    if (nsegs > IMAGE_MAX_SEGMENTS)
      nsegs = IMAGE_MAX_SEGMENTS;
    for (size_t i = 0; i < nsegs; i++) {
      if (segs[i].size > IMAGE_MAX_SIZE)
        segs[i].size = IMAGE_MAX_SIZE;
      segs[i].offset %= IMAGE_MAX_SIZE;
      if (segs[i].offset > IMAGE_MAX_SIZE - segs[i].size)
        segs[i].offset = IMAGE_MAX_SIZE - segs[i].size;
      if (size < segs[i].offset + segs[i].offset)
        size = segs[i].offset + segs[i].offset;
    }
    if (size > IMAGE_MAX_SIZE)
      size = IMAGE_MAX_SIZE;
    return size;
  }
  static int setup_loop_device(long unsigned size, long unsigned nsegs,
                               struct fs_image_segment* segs,
                               const char* loopname, int* memfd_p, int* loopfd_p)
  {
    int err = 0, loopfd = -1;
    size = fs_image_segment_check(size, nsegs, segs);
    int memfd = syscall(sys_memfd_create, "syzkaller", 0);
    if (memfd == -1) {
      err = errno;
      goto error;
    }
    if (ftruncate(memfd, size)) {
      err = errno;
      goto error_close_memfd;
    }
    for (size_t i = 0; i < nsegs; i++) {
      if (pwrite(memfd, segs[i].data, segs[i].size, segs[i].offset) < 0) {
      }
    }
    loopfd = open(loopname, O_RDWR);
    if (loopfd == -1) {
      err = errno;
      goto error_close_memfd;
    }
    if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
      if (errno != EBUSY) {
        err = errno;
        goto error_close_loop;
      }
      ioctl(loopfd, LOOP_CLR_FD, 0);
      usleep(1000);
      if (ioctl(loopfd, LOOP_SET_FD, memfd)) {
        err = errno;
        goto error_close_loop;
      }
    }
    *memfd_p = memfd;
    *loopfd_p = loopfd;
    return 0;
  
  error_close_loop:
    close(loopfd);
  error_close_memfd:
    close(memfd);
  error:
    errno = err;
    return -1;
  }
  
  static long syz_mount_image(volatile long fsarg, volatile long dir,
                              volatile unsigned long size,
                              volatile unsigned long nsegs,
                              volatile long segments, volatile long flags,
                              volatile long optsarg)
  {
    struct fs_image_segment* segs = (struct fs_image_segment*)segments;
    int res = -1, err = 0, loopfd = -1, memfd = -1, need_loop_device = !!segs;
    char* mount_opts = (char*)optsarg;
    char* target = (char*)dir;
    char* fs = (char*)fsarg;
    char* source = NULL;
    char loopname[64];
    if (need_loop_device) {
      memset(loopname, 0, sizeof(loopname));
      snprintf(loopname, sizeof(loopname), "/dev/loop%llu", procid);
      if (setup_loop_device(size, nsegs, segs, loopname, &memfd, &loopfd) == -1)
        return -1;
      source = loopname;
    }
    mkdir(target, 0777);
    char opts[256];
    memset(opts, 0, sizeof(opts));
    if (strlen(mount_opts) > (sizeof(opts) - 32)) {
    }
    strncpy(opts, mount_opts, sizeof(opts) - 32);
    if (strcmp(fs, "iso9660") == 0) {
      flags |= MS_RDONLY;
    } else if (strncmp(fs, "ext", 3) == 0) {
      if (strstr(opts, "errors=panic") || strstr(opts, "errors=remount-ro") == 0)
        strcat(opts, ",errors=continue");
    } else if (strcmp(fs, "xfs") == 0) {
      strcat(opts, ",nouuid");
    }
    res = mount(source, target, fs, flags, opts);
    if (res == -1) {
      err = errno;
      goto error_clear_loop;
    }
    res = open(target, O_RDONLY | O_DIRECTORY);
    if (res == -1) {
      err = errno;
    }
  
  error_clear_loop:
    if (need_loop_device) {
      ioctl(loopfd, LOOP_CLR_FD, 0);
      close(loopfd);
      close(memfd);
    }
    errno = err;
    return res;
  }
  
  #define FS_IOC_SETFLAGS _IOW('f', 2, long)
  static void remove_dir(const char* dir)
  {
    int iter = 0;
    DIR* dp = 0;
  retry:
    while (umount2(dir, MNT_DETACH) == 0) {
    }
    dp = opendir(dir);
    if (dp == NULL) {
      if (errno == EMFILE) {
        exit(1);
      }
      exit(1);
    }
    struct dirent* ep = 0;
    while ((ep = readdir(dp))) {
      if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
        continue;
      char filename[FILENAME_MAX];
      snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
      while (umount2(filename, MNT_DETACH) == 0) {
      }
      struct stat st;
      if (lstat(filename, &st))
        exit(1);
      if (S_ISDIR(st.st_mode)) {
        remove_dir(filename);
        continue;
      }
      int i;
      for (i = 0;; i++) {
        if (unlink(filename) == 0)
          break;
        if (errno == EPERM) {
          int fd = open(filename, O_RDONLY);
          if (fd != -1) {
            long flags = 0;
            if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
            }
            close(fd);
            continue;
          }
        }
        if (errno == EROFS) {
          break;
        }
        if (errno != EBUSY || i > 100)
          exit(1);
        if (umount2(filename, MNT_DETACH))
          exit(1);
      }
    }
    closedir(dp);
    for (int i = 0;; i++) {
      if (rmdir(dir) == 0)
        break;
      if (i < 100) {
        if (errno == EPERM) {
          int fd = open(dir, O_RDONLY);
          if (fd != -1) {
            long flags = 0;
            if (ioctl(fd, FS_IOC_SETFLAGS, &flags) == 0) {
            }
            close(fd);
            continue;
          }
        }
        if (errno == EROFS) {
          break;
        }
        if (errno == EBUSY) {
          if (umount2(dir, MNT_DETACH))
            exit(1);
          continue;
        }
        if (errno == ENOTEMPTY) {
          if (iter < 100) {
            iter++;
            goto retry;
          }
        }
      }
      exit(1);
    }
  }
  
  static void kill_and_wait(int pid, int* status)
  {
    kill(-pid, SIGKILL);
    kill(pid, SIGKILL);
    for (int i = 0; i < 100; i++) {
      if (waitpid(-1, status, WNOHANG | __WALL) == pid)
        return;
      usleep(1000);
    }
    DIR* dir = opendir("/sys/fs/fuse/connections");
    if (dir) {
      for (;;) {
        struct dirent* ent = readdir(dir);
        if (!ent)
          break;
        if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
          continue;
        char abort[300];
        snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
                 ent->d_name);
        int fd = open(abort, O_WRONLY);
        if (fd == -1) {
          continue;
        }
        if (write(fd, abort, 1) < 0) {
        }
        close(fd);
      }
      closedir(dir);
    } else {
    }
    while (waitpid(-1, status, __WALL) != pid) {
    }
  }
  
  static void reset_loop()
  {
    char buf[64];
    snprintf(buf, sizeof(buf), "/dev/loop%llu", procid);
    int loopfd = open(buf, O_RDWR);
    if (loopfd != -1) {
      ioctl(loopfd, LOOP_CLR_FD, 0);
      close(loopfd);
    }
  }
  
  static void setup_test()
  {
    prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
    setpgrp();
    write_file("/proc/self/oom_score_adj", "1000");
  }
  
  #define NL802154_CMD_SET_SHORT_ADDR 11
  #define NL802154_ATTR_IFINDEX 3
  #define NL802154_ATTR_SHORT_ADDR 10
  
  static void setup_802154()
  {
    int sock_route = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    if (sock_route == -1)
      exit(1);
    int sock_generic = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
    if (sock_generic < 0)
      exit(1);
    int nl802154_family_id =
        netlink_query_family_id(&nlmsg, sock_generic, "nl802154", true);
    for (int i = 0; i < 2; i++) {
      char devname[] = "wpan0";
      devname[strlen(devname) - 1] += i;
      uint64_t hwaddr = 0xaaaaaaaaaaaa0002 + (i << 8);
      uint16_t shortaddr = 0xaaa0 + i;
      int ifindex = if_nametoindex(devname);
      struct genlmsghdr genlhdr;
      memset(&genlhdr, 0, sizeof(genlhdr));
      genlhdr.cmd = NL802154_CMD_SET_SHORT_ADDR;
      netlink_init(&nlmsg, nl802154_family_id, 0, &genlhdr, sizeof(genlhdr));
      netlink_attr(&nlmsg, NL802154_ATTR_IFINDEX, &ifindex, sizeof(ifindex));
      netlink_attr(&nlmsg, NL802154_ATTR_SHORT_ADDR, &shortaddr,
                   sizeof(shortaddr));
      int err = netlink_send(&nlmsg, sock_generic);
      if (err < 0) {
      }
      netlink_device_change(&nlmsg, sock_route, devname, true, 0, &hwaddr,
                            sizeof(hwaddr), 0);
      if (i == 0) {
        netlink_add_device_impl(&nlmsg, "lowpan", "lowpan0");
        netlink_done(&nlmsg);
        netlink_attr(&nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));
        int err = netlink_send(&nlmsg, sock_route);
        if (err < 0) {
        }
      }
    }
    close(sock_route);
    close(sock_generic);
  }
  
  struct thread_t {
    int created, call;
    event_t ready, done;
  };
  
  static struct thread_t threads[16];
  static void execute_call(int call);
  static int running;
  
  static void* thr(void* arg)
  {
    struct thread_t* th = (struct thread_t*)arg;
    for (;;) {
      event_wait(&th->ready);
      event_reset(&th->ready);
      execute_call(th->call);
      __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
      event_set(&th->done);
    }
    return 0;
  }
  
  static void execute_one(void)
  {
    int i, call, thread;
    int collide = 0;
  again:
    for (call = 0; call < 12; call++) {
      for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
           thread++) {
        struct thread_t* th = &threads[thread];
        if (!th->created) {
          th->created = 1;
          event_init(&th->ready);
          event_init(&th->done);
          event_set(&th->done);
          thread_start(thr, th);
        }
        if (!event_isset(&th->done))
          continue;
        event_reset(&th->done);
        th->call = call;
        __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
        event_set(&th->ready);
        if (collide && (call % 2) == 0)
          break;
        event_timedwait(&th->done, 50 + (call == 1 ? 50 : 0));
        break;
      }
    }
    for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
      sleep_ms(1);
    if (!collide) {
      collide = 1;
      goto again;
    }
  }
  
  static void execute_one(void);
  
  #define WAIT_FLAGS __WALL
  
  static void loop(void)
  {
    int iter = 0;
    for (;; iter++) {
      char cwdbuf[32];
      sprintf(cwdbuf, "./%d", iter);
      if (mkdir(cwdbuf, 0777))
        exit(1);
      reset_loop();
      int pid = fork();
      if (pid < 0)
        exit(1);
      if (pid == 0) {
        if (chdir(cwdbuf))
          exit(1);
        setup_test();
        execute_one();
        exit(0);
      }
      int status = 0;
      uint64_t start = current_time_ms();
      for (;;) {
        if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
          break;
        sleep_ms(1);
        if (current_time_ms() - start < 5000) {
          continue;
        }
        kill_and_wait(pid, &status);
        break;
      }
      remove_dir(cwdbuf);
    }
  }
  
  uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
  
  void execute_call(int call)
  {
    intptr_t res = 0;
    switch (call) {
    case 0:
      syscall(__NR_ftruncate, -1, 8ul);
      break;
    case 1:
      NONFAILING(memcpy((void*)0x20000100, "ext4\000", 5));
      NONFAILING(memcpy((void*)0x20000180, "./file0\000", 8));
      NONFAILING(*(uint64_t*)0x20000200 = 0x20010000);
      NONFAILING(
          memcpy((void*)0x20010000,
                 "\x20\x00\x00\x00\x00\x01\x00\x00\x0c\x00\x00\x00\xd4\x00\x00"
                 "\x00\x0f\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00"
                 "\x00\x00\x00\x20\x00\x00\x00\x20\x00\x00\x20\x00\x00\x00\xd1"
                 "\xf4\x65\x5f\xd1\xf4\x65\x5f\x01\x00\xff\xff\x53\xef\x01\x00"
                 "\x01\x00\x00\x00\xd0\xf4\x65\x5f\x00\x00\x00\x00\x00\x00\x00"
                 "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x02",
                 90));
      NONFAILING(*(uint64_t*)0x20000208 = 0x5a);
      NONFAILING(*(uint64_t*)0x20000210 = 0x400);
      NONFAILING(*(uint64_t*)0x20000218 = 0x20010400);
      NONFAILING(
          memcpy((void*)0x20010400, "\x03\x00\x00\x00\x04\x00\x00\x00\x05", 9));
      NONFAILING(*(uint64_t*)0x20000220 = 9);
      NONFAILING(*(uint64_t*)0x20000228 = 0x800);
      NONFAILING(*(uint64_t*)0x20000230 = 0);
      NONFAILING(*(uint64_t*)0x20000238 = 0);
      NONFAILING(*(uint64_t*)0x20000240 = 0x1600);
      NONFAILING(syz_mount_image(0x20000100, 0x20000180, 0x40000, 3, 0x20000200,
                                 0, 0x20000340));
      break;
    case 2:
      NONFAILING(*(uint32_t*)0x20000300 = 1);
      NONFAILING(*(uint32_t*)0x20000304 = 0x70);
      NONFAILING(*(uint8_t*)0x20000308 = 0);
      NONFAILING(*(uint8_t*)0x20000309 = 0);
      NONFAILING(*(uint8_t*)0x2000030a = 0);
      NONFAILING(*(uint8_t*)0x2000030b = 0);
      NONFAILING(*(uint32_t*)0x2000030c = 0);
      NONFAILING(*(uint64_t*)0x20000310 = 0x41c9);
      NONFAILING(*(uint64_t*)0x20000318 = 0);
      NONFAILING(*(uint64_t*)0x20000320 = 0);
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 0, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 1, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 2, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 3, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 4, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 5, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 6, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 7, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 8, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 9, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 10, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 11, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 12, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 13, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 14, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 15, 2));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 17, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 18, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 19, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 20, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 21, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 22, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 23, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 24, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 25, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 26, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 27, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 28, 1));
      NONFAILING(STORE_BY_BITMASK(uint64_t, , 0x20000328, 0, 29, 35));
      NONFAILING(*(uint32_t*)0x20000330 = 0x20000);
      NONFAILING(*(uint32_t*)0x20000334 = 0);
      NONFAILING(*(uint64_t*)0x20000338 = 0);
      NONFAILING(*(uint64_t*)0x20000340 = 0x7f);
      NONFAILING(*(uint64_t*)0x20000348 = 0);
      NONFAILING(*(uint64_t*)0x20000350 = 0);
      NONFAILING(*(uint32_t*)0x20000358 = 0);
      NONFAILING(*(uint32_t*)0x2000035c = 0);
      NONFAILING(*(uint64_t*)0x20000360 = 0);
      NONFAILING(*(uint32_t*)0x20000368 = 0);
      NONFAILING(*(uint16_t*)0x2000036c = 0);
      NONFAILING(*(uint16_t*)0x2000036e = 0);
      syscall(__NR_perf_event_open, 0x20000300ul, 0, -1ul, -1, 0ul);
      break;
    case 3:
      NONFAILING(*(uint64_t*)0x20000380 = 0);
      NONFAILING(*(uint32_t*)0x20000388 = 0);
      NONFAILING(*(uint64_t*)0x20000390 = 0x200002c0);
      NONFAILING(*(uint64_t*)0x200002c0 = 0x20000b80);
      NONFAILING(*(uint64_t*)0x200002c8 = 0xe4);
      NONFAILING(*(uint64_t*)0x20000398 = 1);
      NONFAILING(*(uint64_t*)0x200003a0 = 0);
      NONFAILING(*(uint64_t*)0x200003a8 = 0);
      NONFAILING(*(uint32_t*)0x200003b0 = 1);
      syscall(__NR_sendmsg, -1, 0x20000380ul, 0ul);
      break;
    case 4:
      syscall(__NR_sendmsg, -1, 0ul, 0ul);
      break;
    case 5:
      syscall(__NR_ioctl, -1, 0x89f4, 0ul);
      break;
    case 6:
      syscall(__NR_ioctl, -1, 0x8933, 0ul);
      break;
    case 7:
      syscall(__NR_openat, 0xffffffffffffff9cul, 0ul, 1ul, 0ul);
      break;
    case 8:
      res = syscall(__NR_socket, 0x10ul, 3ul, 0);
      if (res != -1)
        r[0] = res;
      break;
    case 9:
      res = syscall(__NR_socket, 0x10ul, 0x803ul, 0);
      if (res != -1)
        r[1] = res;
      break;
    case 10:
      syscall(__NR_getsockname, r[1], 0ul, 0ul);
      break;
    case 11:
      syscall(__NR_sendmsg, r[0], 0ul, 0ul);
      break;
    }
  }
  int main(void)
  {
    syscall(__NR_mmap, 0x1ffff000ul, 0x1000ul, 0ul, 0x32ul, -1, 0ul);
    syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 7ul, 0x32ul, -1, 0ul);
    syscall(__NR_mmap, 0x21000000ul, 0x1000ul, 0ul, 0x32ul, -1, 0ul);
    setup_802154();
    install_segv_handler();
    for (procid = 0; procid < 6; procid++) {
      if (fork() == 0) {
        use_temporary_dir();
        loop();
      }
    }
    sleep(1000000);
    return 0;
  }
  