/* * Check tracing of looping threads. * * Copyright (c) 2009-2019 The strace developers. * All rights reserved. * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "tests.h" #include #include #include #include #include #include #include #include static void * thread(void *arg) { for (;;) getuid(); return arg; } int main(int ac, const char *av[]) { assert(ac == 3); int timeout = atoi(av[1]); assert(timeout > 0); int num_threads = atoi(av[2]); assert(num_threads > 0); /* * Unblock all signals. */ static sigset_t mask; if (sigprocmask(SIG_SETMASK, &mask, NULL)) perror_msg_and_fail("sigprocmask"); /* * Reset SIGALRM and SIGHUP signal handlers. */ static const struct sigaction sa_def = { .sa_handler = SIG_DFL }; if (sigaction(SIGHUP, &sa_def, NULL)) perror_msg_and_fail("sigaction SIGHUP"); if (sigaction(SIGALRM, &sa_def, NULL)) perror_msg_and_fail("sigaction SIGALRM"); /* * Create a new process group. */ if (setpgid(0, 0)) perror_msg_and_fail("setpgid"); /* * Set an alarm clock. */ alarm(timeout); /* * When the main process terminates, the process group becomes orphaned. * If any member of the orphaned process group is stopped, then * a SIGHUP signal followed by a SIGCONT signal is sent to each process * in the orphaned process group. * Create a process in a stopped state to activate this behaviour. */ const pid_t stopped = fork(); if (stopped < 0) perror_msg_and_fail("fork"); if (!stopped) { raise(SIGSTOP); _exit(0); } /* * Wait for the process to stop. */ int status; if (waitpid(stopped, &status, WUNTRACED) != stopped) perror_msg_and_fail("waitpid WUNTRACED"); if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP) error_msg_and_fail("waitpid WUNTRACED: " "unexpected wait status %d", status); /* * Create all threads in a subprocess, this guarantees that * their tracer will not be their parent. */ pid_t pid = fork(); if (pid < 0) perror_msg_and_fail("fork"); if (!pid) { for (int i = 0; i < num_threads; i++) { pthread_t t; if ((errno = pthread_create(&t, NULL, thread, NULL))) { if (EAGAIN == errno) break; perror_msg_and_fail("pthread_create #%d", i); } } /* This terminates all threads created above. */ _exit(0); } if (waitpid(pid, &status, 0) != pid) perror_msg_and_fail("waitpid"); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) error_msg_and_fail("waitpid: unexpected wait status %d", status); /* * Make the process group orphaned. */ return 0; }