Module Name: src Committed By: kamil Date: Thu Nov 3 11:20:45 UTC 2016
Modified Files: src/tests/kernel: t_ptrace.c Log Message: Add new test traceme4 in t_ptrace This test verifies calling raise(2) with the SIGCONT argument in the child. The parent is notified with it and asserts that WIFCONTINUED() and WIFSTOPPED() are both set. XXX: This behavior is surprising. Linux for the same code-path returns false for WIFCONTINUED() and true for WIFSTOPPED(). Include <stdlib.h> for EXIT_FAILURE. This code covers (uncovers issues?) WIFCONTINUED() and is the last planned test in the ptraceme category. Sponsored by <The NetBSD Foundation>. For future reference and convenience, an out-of-ATF test is as follows: #include <sys/param.h> #include <sys/types.h> #include <sys/ptrace.h> #include <sys/wait.h> #include <assert.h> #include <err.h> #include <errno.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #define ATF_REQUIRE(a) assert(a) #if defined(linux) #define WALLSIG __WALL #define sys_signame sys_siglist #endif int main(int argc, char **argv) { int status; const int exitval = 5; const int sigval = SIGSTOP, sigsent = SIGCONT; pid_t child, wpid; printf("1: Before forking process PID=%d\n", getpid()); ATF_REQUIRE((child = fork()) != -1); if (child == 0) { /* printf(3) messages from a child aren't intercepted by ATF */ /* "2: Child process PID=%d\n", getpid() */ /* "2: Before calling ptrace(PT_TRACE_ME, ...)\n" */ if (ptrace(PT_TRACE_ME, 0, NULL, 0) == -1) { /* XXX: Is it safe to use ATF functions in a child? */ err(EXIT_FAILURE, "2: ptrace(2) call failed with " "status %s", sys_errlist[errno]); } /* "2: Before raising SIGSTOP\n" */ raise(sigval); /* "2: Before raising SIGCONT\n" */ raise(sigsent); /* "2: Before calling _exit(%d)\n", exitval */ _exit(exitval); } else { printf("1: Parent process PID=%d, child's PID=%d\n", getpid(), child); printf("1: Before calling waitpid() for the child\n"); wpid = waitpid(child, &status, 0); printf("1: Validating child's PID (expected %d, got %d)\n", child, wpid); ATF_REQUIRE(child == wpid); printf("1: Ensuring that the child has not been exited\n"); ATF_REQUIRE(!WIFEXITED(status)); printf("1: Ensuring that the child has not been continued\n"); ATF_REQUIRE(!WIFCONTINUED(status)); printf("1: Ensuring that the child has not been terminated " "with a signal\n"); ATF_REQUIRE(!WIFSIGNALED(status)); printf("1: Ensuring that the child has been stopped\n"); ATF_REQUIRE(WIFSTOPPED(status)); printf("1: Verifying that he child has been stopped with the" " %s signal (received %s)\n", sys_signame[sigval], sys_signame[WSTOPSIG(status)]); ATF_REQUIRE(WSTOPSIG(status) == sigval); printf("1: Before resuming the child process where it left " "off and without signal to be sent\n"); ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); printf("1: Before calling waitpid() for the child\n"); wpid = waitpid(child, &status, WALLSIG); printf("1: Validating that child's PID is still there\n"); ATF_REQUIRE(wpid == child); printf("1: Ensuring that the child has not been exited\n"); ATF_REQUIRE(!WIFEXITED(status)); printf("1: Ensuring that the child has been continued\n"); ATF_REQUIRE(WIFCONTINUED(status)); printf("1: Ensuring that the child has not been terminated " "with a signal\n"); ATF_REQUIRE(!WIFSIGNALED(status)); printf("1: Ensuring that the child has not been stopped\n"); ATF_REQUIRE(WIFSTOPPED(status)); printf("1: Before resuming the child process where it left " "off and without signal to be sent\n"); ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); printf("1: Before calling waitpid() for the child\n"); wpid = waitpid(child, &status, 0); printf("1: Validating that child's PID is still there\n"); ATF_REQUIRE(wpid == child); printf("1: Ensuring that the child has been exited\n"); ATF_REQUIRE(WIFEXITED(status)); printf("1: Ensuring that the child has not been continued\n"); ATF_REQUIRE(!WIFCONTINUED(status)); printf("1: Ensuring that the child has not been terminated " "with a signal\n"); ATF_REQUIRE(!WIFSIGNALED(status)); printf("1: Ensuring that the child has not been stopped\n"); ATF_REQUIRE(!WIFSTOPPED(status)); printf("1: Verifying that he child has exited with the " "%d status (received %d)\n", exitval, WEXITSTATUS(status)); ATF_REQUIRE(WEXITSTATUS(status) == exitval); printf("1: Before calling waitpid() for the exited child\n"); wpid = waitpid(child, &status, 0); printf("1: Validating that child's PID no longer exists\n"); ATF_REQUIRE(wpid == -1); printf("1: Validating that errno is set to %s (got %s)\n", sys_errlist[ECHILD], sys_errlist[errno]); ATF_REQUIRE(errno == ECHILD); } } To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/tests/kernel/t_ptrace.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.