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); } }
This commit is contained in:
parent
30572e03fd
commit
9a8dc0b4a1
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: t_ptrace.c,v 1.3 2016/11/03 08:48:53 kamil Exp $ */
|
||||
/* $NetBSD: t_ptrace.c,v 1.4 2016/11/03 11:20:45 kamil Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2016 The NetBSD Foundation, Inc.
|
||||
|
@ -27,7 +27,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: t_ptrace.c,v 1.3 2016/11/03 08:48:53 kamil Exp $");
|
||||
__RCSID("$NetBSD: t_ptrace.c,v 1.4 2016/11/03 11:20:45 kamil Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -37,6 +37,7 @@ __RCSID("$NetBSD: t_ptrace.c,v 1.3 2016/11/03 08:48:53 kamil Exp $");
|
|||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <atf-c.h>
|
||||
|
@ -380,11 +381,142 @@ ATF_TC_BODY(traceme3, tc)
|
|||
}
|
||||
}
|
||||
|
||||
ATF_TC(traceme4);
|
||||
ATF_TC_HEAD(traceme4, tc)
|
||||
{
|
||||
atf_tc_set_md_var(tc, "descr",
|
||||
"Verify SIGSTOP followed by SIGCONT and _exit(2) in a child");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(traceme4, tc)
|
||||
{
|
||||
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));
|
||||
|
||||
/* XXX: Linux and NetBSD behavior differ here, is it a bug or
|
||||
* a valid result? ptrace(2) is out of POSIX scope so there is
|
||||
* no standard to verify it. */
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
ATF_TP_ADD_TCS(tp)
|
||||
{
|
||||
ATF_TP_ADD_TC(tp, traceme1);
|
||||
ATF_TP_ADD_TC(tp, traceme2);
|
||||
ATF_TP_ADD_TC(tp, traceme3);
|
||||
ATF_TP_ADD_TC(tp, traceme4);
|
||||
|
||||
return atf_no_error();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue