Commit 2bb4caaa authored by Roland McGrath's avatar Roland McGrath Committed by Linus Torvalds

[PATCH] fix bogus ECHILD return from wait* with zombie group leader

Klaus Dittrich observed this bug and posted a test case for it.

This patch fixes both that failure mode and some others possible.  What
Klaus saw was a false negative (i.e.  ECHILD when there was a child)
when the group leader was a zombie but delayed because other children
live; in the test program this happens in a race between the two threads
dying on a signal.

The change to the TASK_TRACED case avoids a potential false positive
(blocking, or WNOHANG returning 0, when there are really no children
left), in the race condition where my_ptrace_child returns zero.
Signed-off-by: default avatarRoland McGrath <roland@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent c5c0f921
...@@ -1319,6 +1319,10 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop, ...@@ -1319,6 +1319,10 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
add_wait_queue(&current->wait_chldexit,&wait); add_wait_queue(&current->wait_chldexit,&wait);
repeat: repeat:
/*
* We will set this flag if we see any child that might later
* match our criteria, even if we are not able to reap it yet.
*/
flag = 0; flag = 0;
current->state = TASK_INTERRUPTIBLE; current->state = TASK_INTERRUPTIBLE;
read_lock(&tasklist_lock); read_lock(&tasklist_lock);
...@@ -1337,11 +1341,14 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop, ...@@ -1337,11 +1341,14 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
switch (p->state) { switch (p->state) {
case TASK_TRACED: case TASK_TRACED:
flag = 1;
if (!my_ptrace_child(p)) if (!my_ptrace_child(p))
continue; continue;
/*FALLTHROUGH*/ /*FALLTHROUGH*/
case TASK_STOPPED: case TASK_STOPPED:
/*
* It's stopped now, so it might later
* continue, exit, or stop again.
*/
flag = 1; flag = 1;
if (!(options & WUNTRACED) && if (!(options & WUNTRACED) &&
!my_ptrace_child(p)) !my_ptrace_child(p))
...@@ -1377,8 +1384,12 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop, ...@@ -1377,8 +1384,12 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
goto end; goto end;
break; break;
} }
flag = 1;
check_continued: check_continued:
/*
* It's running now, so it might later
* exit, stop, or stop and then continue.
*/
flag = 1;
if (!unlikely(options & WCONTINUED)) if (!unlikely(options & WCONTINUED))
continue; continue;
retval = wait_task_continued( retval = wait_task_continued(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment