MCPcopy Create free account
hub / github.com/apache/singa / ExecDeathTestSpawnChild

Function ExecDeathTestSpawnChild

test/gtest/gtest-all.cc:7496–7588  ·  view source on GitHub ↗

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

Source from the content-addressed store, hash-verified

7494// spawn(2) there instead. The function dies with an error message if
7495// anything goes wrong.
7496static 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);

Callers 1

AssumeRoleMethod · 0.85

Calls 7

DeathTestAbortFunction · 0.85
GetLastErrnoDescriptionFunction · 0.85
GetEnvironFunction · 0.85
sigactionClass · 0.85
StackGrowsDownFunction · 0.85
ExecDeathTestChildMainFunction · 0.85
original_working_dirMethod · 0.80

Tested by

no test coverage detected