LKML Archive on
help / color / mirror / Atom feed
From: Jan Kratochvil <>
To: Mike Frysinger <>
Cc: Mike Frysinger <>,
Subject: Re: inconsistent behavior with ptrace(TRACEME) and fork/exec
Date: Tue, 28 Oct 2008 15:58:32 +0100	[thread overview]
Message-ID: <> (raw)
In-Reply-To: <>

[-- Attachment #1: Type: text/plain, Size: 2104 bytes --]


sorry I had a race with signal()/pause() in my last post, fixed here.

On Mon, 27 Oct 2008 18:38:16 +0100, Mike Frysinger wrote:
> On Mon, Oct 27, 2008 at 10:56, Jan Kratochvil wrote:
> > On Wed, 19 Jul 2006 21:18:29 +0200, Mike Frysinger wrote:
> >> my understanding is that if a parent forks and the child does
> >> a ptrace(TRACEME) right before doing an exec(), the kernel should always
> >> halt it and wait indefinitely for the parent to start ptracing it.
> >
> > Yes, just the parent must process the event (signal).  In your testcase the
> > parent finished before the signal could be delivered.  If the tracer exits the
> > tracee's tracing is finished and it continues freely.
> no signal should have been generated.  the child should have gone
> straight to the exec and waited for the parent to process it.

Every ptrace event generates SIGCHLD.  vfork() frees the parent at the moment
the child calls exec() or _exit().  Here the child calls exec() which both
frees the parent to continue the execution AND delivers SIGCHLD with the
status WIFSTOPPED WSTOPSIG(SIGTRAP) to it.  I do not see a problem here.

> >> unfortunately, this behavior seems to be unreliable.
> >
> > Fixed the races in your code and I do not see there any problem, do you?
> > The ptrace problems/testsuite is being maintained at:
> >
> there is no race condition ... it's using vfork here remember ?

Yes but you said that you see the same problem even with fork():

On Wed, 19 Jul 2006 21:18:29 +0200, Mike Frysinger wrote:
# also, while the attached test uses vfork(), same behavior can be observed
# with fork().  

> it is impossible for the parent to have executed anything after the vfork()
> before the child made it into the exec() and gone to sleep

You must not rely on the vfork() specifics as vfork() can be just fork():

I hope there is no problem with the kernel at this moment, the attached
testcase works even with vfork() reliably.


[-- Attachment #2: ptrace-vfork-traceme.c --]
[-- Type: text/plain, Size: 2463 bytes --]

#define _GNU_SOURCE
#include <errno.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <assert.h>

#define fail(msg, args...) \
do { \
	fprintf(stderr, "FAIL:%i: " msg "\n", __LINE__, ## args); \
	exit(1); \
} while (0)

static volatile int caught = 0;

static void child_exit(int sig)
	int status;
#if 0 /* Correct behavior.  */
	printf("failure, child exited with %i: %s\n", sig, strsignal(sig));
	assert(sig == SIGCHLD);
	printf("wait() = %i\n", wait(&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.  */
	caught = 1;

int main(int argc, char *argv[])
	long pret;
	pid_t pid;

	/* 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...");
		{ puts ("child exiting"); exit (0); }

	/* Setup the handler already here as after vfork() there would be
	   a race setting it up before we get signalled.  */
	signal(SIGCHLD, child_exit);

	/* vfork() child must not call ptrace().  */
	pid = vfork();
	if (pid == -1)
		fail("vfork() didnt work: %m");
	else if (!pid) {
		/* do the child stuff here */
		errno = 0;
		pret = ptrace(PTRACE_TRACEME, 0, NULL, NULL);
		if (pret && errno)
			fail("ptrace(PTRACE_TRACEME) = %li: %m", pret);

		int eret = execlp(argv[0], argv[0], "child", NULL);
		fail("execlp() = %i", eret);
	/* do the parent stuff here */

	/* We cannot pause() here as the signal already could occur, we would
	   have to SIG_BLOCK SIGCHLD and sigsuspend() here.  */
	while (!caught);

	errno = 0;
	pret = ptrace(PTRACE_PEEKUSER, pid, NULL, NULL);
	if (pret && errno)
		fail("ptrace(PTRACE_PEEKUSER, %i) = %li: %m", pid, pret);

	puts("SUCCESS! :D");

	return 0;

  reply	other threads:[~2008-10-28 14:58 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-10-27 14:56 Jan Kratochvil
2008-10-27 17:38 ` Mike Frysinger
2008-10-28 14:58   ` Jan Kratochvil [this message]
2008-10-29 10:26     ` Mike Frysinger
  -- strict thread matches above, loose matches on Subject: below --
2008-10-27  8:55 Mike Frysinger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \ \ \ \ \ \
    --subject='Re: inconsistent behavior with ptrace(TRACEME) and fork/exec' \

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).