TEST(spawn, posix_spawnp) {
  ExecTestHelper eth;
  eth.SetArgs({"true", nullptr});
  pid_t pid;
  ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), nullptr, nullptr, eth.GetArgs(), nullptr));
  AssertChildExited(pid, 0);
}
TEST(UNISTD_TEST, lockf_with_child) {
  constexpr off64_t file_size = 32*1024LL;

  TemporaryFile tf;
  ASSERT_EQ(0, ftruncate(tf.fd, file_size));

  // Lock everything.
  ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
  ASSERT_EQ(0, lockf64(tf.fd, F_LOCK, file_size));

  // Fork a child process
  pid_t pid = fork();
  ASSERT_NE(-1, pid);
  if (pid == 0) {
    // Check that the child cannot lock the file.
    ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
    ASSERT_EQ(-1, lockf64(tf.fd, F_TLOCK, file_size));
    ASSERT_EQ(EAGAIN, errno);
    // Check also that it reports itself as locked.
    ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
    ASSERT_EQ(-1, lockf64(tf.fd, F_TEST, file_size));
    ASSERT_EQ(EACCES, errno);
    _exit(0);
  }
  AssertChildExited(pid, 0);
}
TEST(UNISTD_TEST, lockf_partial_with_child) {
  constexpr off64_t file_size = 32*1024LL;

  TemporaryFile tf;
  ASSERT_EQ(0, ftruncate(tf.fd, file_size));

  // Lock the first half of the file.
  ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
  ASSERT_EQ(0, lockf64(tf.fd, F_LOCK, file_size/2));

  // Fork a child process.
  pid_t pid = fork();
  ASSERT_NE(-1, pid);
  if (pid == 0) {
    // Check that the child can lock the other half.
    ASSERT_EQ(file_size/2, lseek64(tf.fd, file_size/2, SEEK_SET));
    ASSERT_EQ(0, lockf64(tf.fd, F_TLOCK, file_size/2));
    // Check that the child cannot lock the first half.
    ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
    ASSERT_EQ(-1, lockf64(tf.fd, F_TEST, file_size/2));
    ASSERT_EQ(EACCES, errno);
    // Check also that it reports itself as locked.
    ASSERT_EQ(0, lseek64(tf.fd, 0, SEEK_SET));
    ASSERT_EQ(-1, lockf64(tf.fd, F_TEST, file_size/2));
    ASSERT_EQ(EACCES, errno);
    _exit(0);
  }
  AssertChildExited(pid, 0);

  // The second half was locked by the child, but the lock disappeared
  // when the process exited, so check it can be locked now.
  ASSERT_EQ(file_size/2, lseek64(tf.fd, file_size/2, SEEK_SET));
  ASSERT_EQ(0, lockf64(tf.fd, F_TLOCK, file_size/2));
}
TEST(spawn, posix_spawn_file_actions) {
  int fds[2];
  ASSERT_NE(-1, pipe(fds));

  posix_spawn_file_actions_t fa;
  ASSERT_EQ(0, posix_spawn_file_actions_init(&fa));

  ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[0]));
  ASSERT_EQ(0, posix_spawn_file_actions_adddup2(&fa, fds[1], 1));
  ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[1]));
  // Check that close(2) failures are ignored by closing the same fd again.
  ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[1]));
  ASSERT_EQ(0, posix_spawn_file_actions_addopen(&fa, 56, "/proc/version", O_RDONLY, 0));

  ExecTestHelper eth;
  eth.SetArgs({"ls", "-l", "/proc/self/fd", nullptr});
  pid_t pid;
  ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), &fa, nullptr, eth.GetArgs(), eth.GetEnv()));
  ASSERT_EQ(0, posix_spawn_file_actions_destroy(&fa));

  ASSERT_EQ(0, close(fds[1]));
  std::string content;
  ASSERT_TRUE(android::base::ReadFdToString(fds[0], &content));
  ASSERT_EQ(0, close(fds[0]));

  AssertChildExited(pid, 0);

  // We'll know the dup2 worked if we see any ls(1) output in our pipe.
  // The open we can check manually...
  bool open_to_fd_56_worked = false;
  for (const auto& line : android::base::Split(content, "\n")) {
    if (line.find(" 56 -> /proc/version") != std::string::npos) open_to_fd_56_worked = true;
  }
  ASSERT_TRUE(open_to_fd_56_worked);
}
  void CreateRelroFile(const char* lib, const char* relro_file) {
    int relro_fd = open(relro_file, O_RDWR | O_TRUNC);
    ASSERT_NOERROR(relro_fd);

    pid_t pid = fork();
    if (pid == 0) {
      // child process
      extinfo_.flags |= ANDROID_DLEXT_WRITE_RELRO;
      extinfo_.relro_fd = relro_fd;
      void* handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
      if (handle == nullptr) {
        fprintf(stderr, "in child: %s\n", dlerror());
        exit(1);
      }
      exit(0);
    }

    // continuing in parent
    ASSERT_NOERROR(close(relro_fd));
    ASSERT_NOERROR(pid);
    AssertChildExited(pid, 0);

    // reopen file for reading so it can be used
    relro_fd = open(relro_file, O_RDONLY);
    ASSERT_NOERROR(relro_fd);
    extinfo_.flags |= ANDROID_DLEXT_USE_RELRO;
    extinfo_.relro_fd = relro_fd;
  }
Exemple #6
0
TEST(fenv, feenableexcept_fegetexcept) {
#if defined(__aarch64__) || defined(__arm__)
  // ARM doesn't support this. They used to if you go back far enough, but it was removed in
  // the Cortex-A8 between r3p1 and r3p2.
  ASSERT_EQ(-1, feenableexcept(FE_INVALID));
  ASSERT_EQ(0, fegetexcept());
  ASSERT_EQ(-1, feenableexcept(FE_DIVBYZERO));
  ASSERT_EQ(0, fegetexcept());
  ASSERT_EQ(-1, feenableexcept(FE_OVERFLOW));
  ASSERT_EQ(0, fegetexcept());
  ASSERT_EQ(-1, feenableexcept(FE_UNDERFLOW));
  ASSERT_EQ(0, fegetexcept());
  ASSERT_EQ(-1, feenableexcept(FE_INEXACT));
  ASSERT_EQ(0, fegetexcept());
  ASSERT_EQ(-1, feenableexcept(FE_DENORMAL));
  ASSERT_EQ(0, fegetexcept());
#else
  // We can't recover from SIGFPE, so sacrifice a child...
  pid_t pid = fork();
  ASSERT_NE(-1, pid) << strerror(errno);

  if (pid == 0) {
    feclearexcept(FE_ALL_EXCEPT);
    ASSERT_EQ(0, fetestexcept(FE_ALL_EXCEPT));
    ASSERT_EQ(0, feenableexcept(FE_INVALID));
    ASSERT_EQ(FE_INVALID, fegetexcept());
    ASSERT_EQ(0, feraiseexcept(FE_INVALID));
    _exit(123);
  }

  AssertChildExited(pid, -SIGFPE);
#endif
}
TEST(spawn, posix_spawnp_not_found) {
  ExecTestHelper eth;
  eth.SetArgs({"does-not-exist", nullptr});
  pid_t pid;
  ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), nullptr, nullptr, eth.GetArgs(), nullptr));
  AssertChildExited(pid, 127);
}
TEST(spawn, posix_spawn_environment) {
  ExecTestHelper eth;
  eth.SetArgs({"sh", "-c", "exit $posix_spawn_environment_test", nullptr});
  eth.SetEnv({"posix_spawn_environment_test=66", nullptr});
  pid_t pid;
  ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), nullptr, nullptr, eth.GetArgs(), eth.GetEnv()));
  AssertChildExited(pid, 66);
}
TEST(pthread, pthread_atfork_with_dlclose) {
  ASSERT_EQ(0, pthread_atfork(AtForkPrepare1, AtForkParent1, AtForkChild1));

  void* handle = dlopen("libtest_pthread_atfork.so", RTLD_NOW | RTLD_LOCAL);
  ASSERT_TRUE(handle != nullptr) << dlerror();
  typedef int (*fn_t)(void (*)(void), void (*)(void), void (*)(void));
  fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "proxy_pthread_atfork"));
  ASSERT_TRUE(fn != nullptr) << dlerror();
  // the library registers 2 additional atfork handlers in a constructor
  ASSERT_EQ(0, fn(AtForkPrepare2, AtForkParent2, AtForkChild2));
  ASSERT_EQ(0, fn(AtForkPrepare3, AtForkParent3, AtForkChild3));

  ASSERT_EQ(0, pthread_atfork(AtForkPrepare4, AtForkParent4, AtForkChild4));

  pid_t pid = fork();

  ASSERT_NE(-1, pid) << strerror(errno);

  if (pid == 0) {
    ASSERT_EQ(1234, g_atfork_child_calls);
    _exit(0);
  }

  ASSERT_EQ(1234, g_atfork_parent_calls);
  ASSERT_EQ(4321, g_atfork_prepare_calls);

  EXPECT_EQ(0, dlclose(handle));
  g_atfork_prepare_calls = g_atfork_parent_calls = g_atfork_child_calls = 0;

  AssertChildExited(pid, 0);

  pid = fork();

  ASSERT_NE(-1, pid) << strerror(errno);

  if (pid == 0) {
    ASSERT_EQ(14, g_atfork_child_calls);
    _exit(0);
  }

  ASSERT_EQ(14, g_atfork_parent_calls);
  ASSERT_EQ(41, g_atfork_prepare_calls);

  AssertChildExited(pid, 0);
}
Exemple #10
0
TEST(stdlib, quick_exit) {
  pid_t pid = fork();
  ASSERT_NE(-1, pid) << strerror(errno);

  if (pid == 0) {
    quick_exit(99);
  }

  AssertChildExited(pid, 99);
}
TEST(UNISTD_TEST, _exit) {
  pid_t pid = fork();
  ASSERT_NE(-1, pid) << strerror(errno);

  if (pid == 0) {
    _exit(99);
  }

  AssertChildExited(pid, 99);
}
Exemple #12
0
TEST(unistd, _Exit) {
  pid_t pid = fork();
  ASSERT_NE(-1, pid) << strerror(errno);

  if (pid == 0) {
    _Exit(99);
  }

  AssertChildExited(pid, 99);
}
TEST(spawn, signal_stress) {
  // Ensure that posix_spawn doesn't restore the caller's signal mask in the
  // child without first defaulting any caught signals (http://b/68707996).
  static pid_t parent = getpid();

  setpgid(0, 0);
  signal(SIGRTMIN, SIG_IGN);

  pid_t pid = fork();
  ASSERT_NE(-1, pid);

  if (pid == 0) {
    for (size_t i = 0; i < 1024; ++i) {
      kill(0, SIGRTMIN);
      usleep(10);
    }
    _exit(99);
  }

  // We test both with and without attributes, because they used to be
  // different codepaths. We also test with an empty `sigdefault` set.
  posix_spawnattr_t attr1;
  posix_spawnattr_init(&attr1);

  sigset_t empty_mask = {};
  posix_spawnattr_t attr2;
  posix_spawnattr_init(&attr2);
  posix_spawnattr_setflags(&attr2, POSIX_SPAWN_SETSIGDEF);
  posix_spawnattr_setsigdefault(&attr2, &empty_mask);

  posix_spawnattr_t* attrs[] = { nullptr, &attr1, &attr2 };

  // We use a real-time signal because that's a tricky case for LP32
  // because our sigset_t was too small.
  ScopedSignalHandler ssh(SIGRTMIN, [](int) { ASSERT_EQ(getpid(), parent); });

  const size_t pid_count = 128;
  pid_t spawned_pids[pid_count];

  ExecTestHelper eth;
  eth.SetArgs({"true", nullptr});
  for (size_t i = 0; i < pid_count; ++i) {
    pid_t spawned_pid;
    ASSERT_EQ(0, posix_spawn(&spawned_pid, "true", nullptr, attrs[i % 3], eth.GetArgs(), nullptr));
    spawned_pids[i] = spawned_pid;
  }

  for (pid_t spawned_pid : spawned_pids) {
    ASSERT_EQ(spawned_pid, TEMP_FAILURE_RETRY(waitpid(spawned_pid, nullptr, 0)));
  }

  AssertChildExited(pid, 99);
}
Exemple #14
0
TEST(stdlib, at_quick_exit) {
  pid_t pid = fork();
  ASSERT_NE(-1, pid) << strerror(errno);

  if (pid == 0) {
    ASSERT_EQ(at_quick_exit(quick_exit_2), 0);
    ASSERT_EQ(at_quick_exit(quick_exit_1), 0);
    atexit(not_run);
    quick_exit(99);
  }

  AssertChildExited(pid, 99);
}
TEST(UNISTD_TEST, getpid_caching_and_clone) {
  pid_t parent_pid = getpid();
  ASSERT_EQ(syscall(__NR_getpid), parent_pid);

  void* child_stack[1024];
  int clone_result = clone(GetPidCachingCloneStartRoutine, &child_stack[1024], CLONE_NEWNS | SIGCHLD, NULL);
  if (clone_result == -1 && errno == EPERM && getuid() != 0) {
    GTEST_LOG_(INFO) << "This test only works if you have permission to CLONE_NEWNS; try running as root.\n";
    return;
  }
  ASSERT_NE(clone_result, -1);

  ASSERT_EQ(parent_pid, getpid());

  AssertChildExited(clone_result, 123);
}
static void TestGetPidCachingWithFork(int (*fork_fn)()) {
  pid_t parent_pid = getpid();
  ASSERT_EQ(syscall(__NR_getpid), parent_pid);

  pid_t fork_result = fork_fn();
  ASSERT_NE(fork_result, -1);
  if (fork_result == 0) {
    // We're the child.
    AssertGetPidCorrect();
    ASSERT_EQ(parent_pid, getppid());
    _exit(123);
  } else {
    // We're the parent.
    ASSERT_EQ(parent_pid, getpid());
    AssertChildExited(fork_result, 123);
  }
}
Exemple #17
0
TEST(pty, forkpty) {
  pid_t sid = getsid(0);

  int master;
  pid_t pid = forkpty(&master, NULL, NULL, NULL);
  ASSERT_NE(-1, pid);

  if (pid == 0) {
    // We're the child.
    ASSERT_NE(sid, getsid(0));
    _exit(0);
  }

  ASSERT_EQ(sid, getsid(0));

  AssertChildExited(pid, 0);

  close(master);
}
static void CatFileToString(posix_spawnattr_t* sa, const char* path, std::string* content) {
  int fds[2];
  ASSERT_NE(-1, pipe(fds));

  posix_spawn_file_actions_t fa;
  ASSERT_EQ(0, posix_spawn_file_actions_init(&fa));
  ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[0]));
  ASSERT_EQ(0, posix_spawn_file_actions_adddup2(&fa, fds[1], 1));
  ASSERT_EQ(0, posix_spawn_file_actions_addclose(&fa, fds[1]));

  ExecTestHelper eth;
  eth.SetArgs({"cat", path, nullptr});
  pid_t pid;
  ASSERT_EQ(0, posix_spawnp(&pid, eth.GetArg0(), &fa, sa, eth.GetArgs(), nullptr));
  ASSERT_EQ(0, posix_spawn_file_actions_destroy(&fa));

  ASSERT_EQ(0, close(fds[1]));
  ASSERT_TRUE(android::base::ReadFdToString(fds[0], content));
  ASSERT_EQ(0, close(fds[0]));
  AssertChildExited(pid, 0);
}
TEST(time, timer_create) {
  sigevent_t se;
  memset(&se, 0, sizeof(se));
  se.sigev_notify = SIGEV_THREAD;
  se.sigev_notify_function = NoOpNotifyFunction;
  timer_t timer_id;
  ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, &se, &timer_id));

  pid_t pid = fork();
  ASSERT_NE(-1, pid) << strerror(errno);

  if (pid == 0) {
    // Timers are not inherited by the child.
    ASSERT_EQ(-1, timer_delete(timer_id));
    ASSERT_EQ(EINVAL, errno);
    _exit(0);
  }

  AssertChildExited(pid, 0);

  ASSERT_EQ(0, timer_delete(timer_id));
}
void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, bool share_relro,
                                                       size_t* pss_out) {
  const int CHILDREN = 20;

  // Create children
  pid_t child_pids[CHILDREN];
  int childpipe[CHILDREN];
  for (int i=0; i<CHILDREN; ++i) {
    char read_buf;
    int child_done_pipe[2], parent_done_pipe[2];
    ASSERT_NOERROR(pipe(child_done_pipe));
    ASSERT_NOERROR(pipe(parent_done_pipe));

    pid_t child = fork();
    if (child == 0) {
      // close the 'wrong' ends of the pipes in the child
      close(child_done_pipe[0]);
      close(parent_done_pipe[1]);

      // open the library
      void* handle;
      if (share_relro) {
        handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo_);
      } else {
        handle = dlopen(lib, RTLD_NOW);
      }
      if (handle == nullptr) {
        fprintf(stderr, "in child: %s\n", dlerror());
        exit(1);
      }

      // close write end of child_done_pipe to signal the parent that we're done.
      close(child_done_pipe[1]);

      // wait for the parent to close parent_done_pipe, then exit
      read(parent_done_pipe[0], &read_buf, 1);
      exit(0);
    }

    ASSERT_NOERROR(child);

    // close the 'wrong' ends of the pipes in the parent
    close(child_done_pipe[1]);
    close(parent_done_pipe[0]);

    // wait for the child to be done
    read(child_done_pipe[0], &read_buf, 1);
    close(child_done_pipe[0]);

    // save the child's pid and the parent_done_pipe
    child_pids[i] = child;
    childpipe[i] = parent_done_pipe[1];
  }

  // Sum the PSS of all the children
  size_t total_pss = 0;
  for (int i=0; i<CHILDREN; ++i) {
    size_t child_pss;
    ASSERT_NO_FATAL_FAILURE(getPss(child_pids[i], &child_pss));
    total_pss += child_pss;
  }
  *pss_out = total_pss;

  // Close pipes and wait for children to exit
  for (int i=0; i<CHILDREN; ++i) {
    ASSERT_NOERROR(close(childpipe[i]));
  }
  for (int i = 0; i < CHILDREN; ++i) {
    AssertChildExited(child_pids[i], 0);
  }
}