This is the mail archive of the libc-hacker@sources.redhat.com mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


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

[PATCH] Fix linuxthreads race


Hi!

If a signal other than __pthread_sig_cancel is sent to a newly
created thread before it INIT_THREAD_SELF in pthread_start_thread,
it will have wrong thread_self ().
The following patch should fix this (tested
on i386 --without-tls --without-__thread non-FS, i686 --with-tls
--without-__thread non-FS and i686 --with-tls --without-__thread FS).

2003-09-17  Jakub Jelinek  <jakub@redhat.com>

	* pthread.c (manager_thread): Remove static, add attribute_hidden.
	(thread_self_stack): Rename to...
	(__pthread_self_stack): ... this.  Remove static.
	(pthread_handle_sigcancel): Adjust caller.
	(pthread_handle_sigrestart): Do INIT_THREAD_SELF if signal is received
	before INIT_THREAD_SELF in pthread_start_thread.
	* sighandler.c (manager_thread): Define.
	(CHECK_THREAD_SELF): Define.
	(__pthread_sighandler, __pthread_sighandler_rt): Use it.
	* descr.h (manager_thread): Declare.
	* internals.h (__pthread_self_stack): New prototype.

--- libc/linuxthreads/pthread.c.jj	2003-09-02 03:08:54.000000000 -0400
+++ libc/linuxthreads/pthread.c	2003-09-16 16:29:56.000000000 -0400
@@ -55,7 +55,7 @@ extern struct __res_state _res;
 #ifdef USE_TLS
 
 /* We need only a few variables.  */
-static pthread_descr manager_thread;
+pthread_descr manager_thread attribute_hidden;
 
 #else
 
@@ -896,7 +896,7 @@ pthread_descr __pthread_find_self(void)
 
 #else
 
-static pthread_descr thread_self_stack(void)
+pthread_descr __pthread_self_stack(void)
 {
   char *sp = CURRENT_STACK_FRAME;
   pthread_handle h;
@@ -1024,6 +1024,22 @@ static void pthread_atexit_retcode(void 
 static void pthread_handle_sigrestart(int sig)
 {
   pthread_descr self = thread_self();
+#if defined THREAD_SELF && defined INIT_THREAD_SELF
+  if (self == manager_thread)
+    {
+      /* A new thread might get a cancel signal before it is fully
+	 initialized, so that the thread register might still point to the
+	 manager thread.  Double check that this is really the manager
+	 thread.  */
+      pthread_descr real_self = __pthread_self_stack();
+      if (real_self != manager_thread)
+	{
+	  /* Oops, thread_self() isn't working yet..  */
+	  self = real_self;
+	  INIT_THREAD_SELF(self, self->p_nr);
+	}
+    }
+#endif
   THREAD_SETMEM(self, p_signal, sig);
   if (THREAD_GETMEM(self, p_signal_jmp) != NULL)
     siglongjmp(*THREAD_GETMEM(self, p_signal_jmp), 1);
@@ -1046,7 +1062,7 @@ static void pthread_handle_sigcancel(int
 	 initialized, so that the thread register might still point to the
 	 manager thread.  Double check that this is really the manager
 	 thread.  */
-      pthread_descr real_self = thread_self_stack();
+      pthread_descr real_self = __pthread_self_stack();
       if (real_self == manager_thread)
 	{
 	  __pthread_manager_sighandler(sig);
--- libc/linuxthreads/internals.h.jj	2003-09-02 03:08:54.000000000 -0400
+++ libc/linuxthreads/internals.h	2003-09-16 16:29:00.000000000 -0400
@@ -363,6 +363,7 @@ extern int __pthread_condattr_init (pthr
 extern int __pthread_condattr_destroy (pthread_condattr_t *attr);
 extern pthread_t __pthread_self (void);
 extern pthread_descr __pthread_thread_self (void);
+extern pthread_descr __pthread_self_stack (void) attribute_hidden;
 extern int __pthread_equal (pthread_t thread1, pthread_t thread2);
 extern void __pthread_exit (void *retval);
 extern int __pthread_getschedparam (pthread_t thread, int *policy,
--- libc/linuxthreads/descr.h.jj	2003-07-23 03:56:17.000000000 -0400
+++ libc/linuxthreads/descr.h	2003-09-16 16:26:35.000000000 -0400
@@ -217,6 +217,7 @@ extern char *__pthread_manager_thread_to
 /* Descriptor of the manager thread */
 
 extern struct _pthread_descr_struct __pthread_manager_thread;
+extern pthread_descr manager_thread attribute_hidden;
 
 /* Indicate whether at least one thread has a user-defined stack (if 1),
    or all threads have stacks supplied by LinuxThreads (if 0). */
--- libc/linuxthreads/sighandler.c.jj	2002-05-03 03:36:37.000000000 -0400
+++ libc/linuxthreads/sighandler.c	2003-09-16 16:35:48.000000000 -0400
@@ -16,6 +16,31 @@
 
 #include "internals.h"
 
+#if defined THREAD_SELF && defined INIT_THREAD_SELF
+# ifndef USE_TLS
+#  define manager_thread (&__pthread_manager_thread)
+# endif
+# define CHECK_THREAD_SELF(self) \
+do {									     \
+  if (self == manager_thread)						     \
+    {									     \
+      /* A new thread might get a cancel signal before it is fully	     \
+	 initialized, so that the thread register might still point to the   \
+	 manager thread.  Double check that this is really the manager	     \
+	 thread.  */							     \
+      pthread_descr real_self = __pthread_self_stack();			     \
+      if (real_self != manager_thread)					     \
+	{								     \
+	  /* Oops, thread_self() isn't working yet..  */		     \
+	  self = real_self;						     \
+	  INIT_THREAD_SELF(self, self->p_nr);				     \
+	}								     \
+    }									     \
+} while (0)
+#else
+# define CHECK_THREAD_SELF(self) do { } while (0)
+#endif
+
 
 /* The wrapper around user-provided signal handlers */
 void __pthread_sighandler(int signo, SIGCONTEXT ctx)
@@ -23,6 +48,7 @@ void __pthread_sighandler(int signo, SIG
   pthread_descr self;
   char * in_sighandler;
   self = thread_self();
+  CHECK_THREAD_SELF(self);
   /* If we're in a sigwait operation, just record the signal received
      and return without calling the user's handler */
   if (THREAD_GETMEM(self, p_sigwaiting)) {
@@ -47,6 +73,7 @@ void __pthread_sighandler_rt(int signo, 
   pthread_descr self;
   char * in_sighandler;
   self =  thread_self();
+  CHECK_THREAD_SELF(self);
   /* If we're in a sigwait operation, just record the signal received
      and return without calling the user's handler */
   if (THREAD_GETMEM(self, p_sigwaiting)) {

	Jakub


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