Spawns a child process with the same executable as the current process in a thread-safe manner and instructs it to run the death test. The implementation uses fork(2) + exec. On systems where clone(2) is available, it is used instead, being slightly more thread-safe. On QNX, fork supports only single-threaded environments, so this function uses spawn(2) there instead. The function dies with an
| 7494 | // spawn(2) there instead. The function dies with an error message if |
| 7495 | // anything goes wrong. |
| 7496 | static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { |
| 7497 | ExecDeathTestArgs args = { argv, close_fd }; |
| 7498 | pid_t child_pid = -1; |
| 7499 | |
| 7500 | # if GTEST_OS_QNX |
| 7501 | // Obtains the current directory and sets it to be closed in the child |
| 7502 | // process. |
| 7503 | const int cwd_fd = open(".", O_RDONLY); |
| 7504 | GTEST_DEATH_TEST_CHECK_(cwd_fd != -1); |
| 7505 | GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC)); |
| 7506 | // We need to execute the test program in the same environment where |
| 7507 | // it was originally invoked. Therefore we change to the original |
| 7508 | // working directory first. |
| 7509 | const char* const original_dir = |
| 7510 | UnitTest::GetInstance()->original_working_dir(); |
| 7511 | // We can safely call chdir() as it's a direct system call. |
| 7512 | if (chdir(original_dir) != 0) { |
| 7513 | DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + |
| 7514 | GetLastErrnoDescription()); |
| 7515 | return EXIT_FAILURE; |
| 7516 | } |
| 7517 | |
| 7518 | int fd_flags; |
| 7519 | // Set close_fd to be closed after spawn. |
| 7520 | GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD)); |
| 7521 | GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD, |
| 7522 | fd_flags | FD_CLOEXEC)); |
| 7523 | struct inheritance inherit = {0}; |
| 7524 | // spawn is a system call. |
| 7525 | child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron()); |
| 7526 | // Restores the current working directory. |
| 7527 | GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); |
| 7528 | GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); |
| 7529 | |
| 7530 | # else // GTEST_OS_QNX |
| 7531 | # if GTEST_OS_LINUX |
| 7532 | // When a SIGPROF signal is received while fork() or clone() are executing, |
| 7533 | // the process may hang. To avoid this, we ignore SIGPROF here and re-enable |
| 7534 | // it after the call to fork()/clone() is complete. |
| 7535 | struct sigaction saved_sigprof_action; |
| 7536 | struct sigaction ignore_sigprof_action; |
| 7537 | memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action)); |
| 7538 | sigemptyset(&ignore_sigprof_action.sa_mask); |
| 7539 | ignore_sigprof_action.sa_handler = SIG_IGN; |
| 7540 | GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction( |
| 7541 | SIGPROF, &ignore_sigprof_action, &saved_sigprof_action)); |
| 7542 | # endif // GTEST_OS_LINUX |
| 7543 | |
| 7544 | # if GTEST_HAS_CLONE |
| 7545 | const bool use_fork = GTEST_FLAG(death_test_use_fork); |
| 7546 | |
| 7547 | if (!use_fork) { |
| 7548 | static const bool stack_grows_down = StackGrowsDown(); |
| 7549 | const size_t stack_size = getpagesize(); |
| 7550 | // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. |
| 7551 | void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, |
| 7552 | MAP_ANON | MAP_PRIVATE, -1, 0); |
| 7553 | GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); |
no test coverage detected