This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Fix getpid in new threads after fork


I noticed a failure with thread cancellation after fork, which turned
out to be caused by the si_pid sanity check in sigcancel_handler.
The PID was stale.  This happened because the main program created a
thread, joined it, and then forked.  The cached thread was reused with
a stale PID.

Patch and testcase attached.  Tested on x86_64-pc-linux-gnu.

-- 
Daniel Jacobowitz
CodeSourcery

2006-07-31  Daniel Jacobowitz  <dan@codesourcery.com>

	* Makefile (tests): Run tst-getpid3.
	* allocatestack.c (__reclaim_stacks): Reset the PID on cached
	stacks.
	* tst-getpid3.c: New test.

Index: nptl/Makefile
===================================================================
RCS file: /cvs/glibc/libc/nptl/Makefile,v
retrieving revision 1.180
diff -u -p -r1.180 Makefile
--- nptl/Makefile	28 Mar 2006 04:13:27 -0000	1.180
+++ nptl/Makefile	31 Jul 2006 16:04:16 -0000
@@ -251,7 +251,7 @@ tests = tst-typesizes \
 	tst-backtrace1 \
 	tst-oddstacklimit \
 	tst-vfork1 tst-vfork2 tst-vfork1x tst-vfork2x \
-	tst-getpid1 tst-getpid2 \
+	tst-getpid1 tst-getpid2 tst-getpid3 \
 	tst-initializers1 $(patsubst %,tst-initializers1-%,c89 gnu89 c99 gnu99)
 xtests = tst-setuid1 tst-setuid1-static
 
Index: nptl/allocatestack.c
===================================================================
RCS file: /cvs/glibc/libc/nptl/allocatestack.c,v
retrieving revision 1.62
diff -u -p -r1.62 allocatestack.c
--- nptl/allocatestack.c	28 Mar 2006 04:14:00 -0000	1.62
+++ nptl/allocatestack.c	31 Jul 2006 16:04:17 -0000
@@ -758,6 +758,15 @@ __reclaim_stacks (void)
 	}
     }
 
+  /* Reset the PIDs in any cached stacks.  */
+  list_for_each (runp, &stack_cache)
+    {
+      struct pthread *curp;
+
+      curp = list_entry (runp, struct pthread, list);
+      curp->pid = self->pid;
+    }
+
   /* Add the stack of all running threads to the cache.  */
   list_splice (&stack_used, &stack_cache);
 
Index: nptl/tst-getpid3.c
===================================================================
RCS file: nptl/tst-getpid3.c
diff -N nptl/tst-getpid3.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ nptl/tst-getpid3.c	31 Jul 2006 16:04:17 -0000
@@ -0,0 +1,112 @@
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <pthread.h>
+#include <stdlib.h>
+
+static pid_t pid;
+
+static void *
+pid_thread (void *arg)
+{
+  if (pid != getpid ())
+    {
+      printf ("pid wrong in thread: %d / %d\n", pid, getpid ());
+      return (void *) 1L;
+    }
+
+  return NULL;
+}
+
+static int
+do_test (void)
+{
+  pthread_t thr;
+  int ret, status;
+  void *thr_ret;
+  pid_t child;
+
+  pid = getpid ();
+  ret = pthread_create (&thr, NULL, pid_thread, NULL);
+  if (ret)
+    {
+      printf ("pthread_create failed: %d\n", ret);
+      return 1;
+    }
+
+  ret = pthread_join (thr, &thr_ret);
+  if (ret)
+    {
+      printf ("pthread_create failed: %d\n", ret);
+      return 1;
+    }
+  else if (thr_ret)
+    {
+      printf ("thread getpid failed\n");
+      return 1;
+    }
+
+  child = fork ();
+  if (child == -1)
+    {
+      printf ("fork failed: %m\n");
+      return 1;
+    }
+  else if (child == 0)
+    {
+      if (pid == getpid ())
+	{
+	  puts ("pid did not change after fork");
+	  exit (1);
+	}
+
+      pid = getpid ();
+      ret = pthread_create (&thr, NULL, pid_thread, NULL);
+      if (ret)
+	{
+	  printf ("pthread_create failed: %d\n", ret);
+	  return 1;
+	}
+
+      ret = pthread_join (thr, &thr_ret);
+      if (ret)
+	{
+	  printf ("pthread_create failed: %d\n", ret);
+	  return 1;
+	}
+      else if (thr_ret)
+	{
+	  printf ("thread getpid failed\n");
+	  return 1;
+	}
+
+      return 0;
+    }
+
+  if (waitpid (child, &status, 0) != child)
+    {
+      puts ("waitpid failed");
+      kill (child, SIGKILL);
+      return 1;
+    }
+
+  if (!WIFEXITED (status))
+    {
+      if (WIFSIGNALED (status))
+	printf ("died from signal %s\n", strsignal (WTERMSIG (status)));
+      else
+	puts ("did not terminate correctly");
+      return 1;
+    }
+  if (WEXITSTATUS (status) != 0)
+    {
+      printf ("exit code %d\n", WEXITSTATUS (status));
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]