--- ptrace-vfork-traceme.c-orig 2008-10-27 15:41:51.000000000 +0100 +++ ptrace-vfork-traceme.c 2008-10-27 15:47:05.000000000 +0100 @@ -18,14 +18,23 @@ do { \ static void child_exit(int sig) { int status; +#if 0 /* Correct behavior. */ printf("failure, child exited with %i: %s\n", sig, strsignal(sig)); +#endif printf("wait() = %i\n", wait(&status)); - printf("status = %i\n", status); + printf("status = 0x%x\n", status); printf("\tWIFEXITED = %i\n", WIFEXITED(status)); printf("\tWEXITSTATUS = %i\n", WEXITSTATUS(status)); printf("\tWIFSIGNALED = %i\n", WIFSIGNALED(status)); printf("\tWTERMSIG = %i (%s)\n", WTERMSIG(status), strsignal(WTERMSIG(status))); + /* WIFSTOPPED happens. */ + printf("\tWIFSTOPPED = %i\n", WIFSTOPPED(status)); + /* SIGTRAP happens. */ + printf("\tWSTOPSIG = %i (%s)\n", WSTOPSIG(status), strsignal(WSTOPSIG(status))); +#if 0 /* We can continue. Just calling printf() from a signal handler is not + correct. */ exit(1); +#endif } int main(int argc, char *argv[]) @@ -35,9 +44,15 @@ int main(int argc, char *argv[]) /* child process ... shouldnt be executed, but just in case ... */ if (argc > 1 && !strcmp(argv[1], "child")) +#if 0 /* Parent did not kill us, after its child_exit() messages we should get + here. */ fail("kernel should have halted me..."); +#else + { puts ("child exiting"); exit (0); } +#endif - pid = vfork(); + /* vfork() child must not call ptrace(). */ + pid = fork(); if (pid == -1) fail("vfork() didnt work: %m"); else if (!pid) { @@ -54,6 +69,10 @@ int main(int argc, char *argv[]) /* do the parent stuff here */ signal(SIGCHLD, child_exit); + /* We cannot PTRACE_PEEKUSER here as the child still may not have + called PTRACE_TRACEME. */ + pause (); + errno = 0; pret = ptrace(PTRACE_PEEKUSER, pid, NULL, NULL); if (pret && errno)