GThread: handle thread names safely
authorMatthias Clasen <mclasen@redhat.com>
Tue, 15 Nov 2011 03:18:13 +0000 (22:18 -0500)
committerMatthias Clasen <mclasen@redhat.com>
Tue, 15 Nov 2011 03:18:13 +0000 (22:18 -0500)
Avoid a race condition where the string may be freed before
the new thread got around to using it. Also add a test for
thread names.

https://bugzilla.gnome.org/show_bug.cgi?id=663381

glib/gthread.c
glib/gthreadprivate.h
glib/tests/thread.c

index b17280f..d956308 100644 (file)
@@ -57,6 +57,7 @@
 #endif /* G_OS_WIN32 */
 
 #include "gslice.h"
+#include "gstrfuncs.h"
 #include "gtestutils.h"
 
 /**
@@ -781,9 +782,6 @@ g_thread_proxy (gpointer data)
 
   g_assert (data);
 
-  if (thread->name)
-    g_system_thread_set_name (thread->name);
-
   /* This has to happen before G_LOCK, as that might call g_thread_self */
   g_private_set (&g_thread_specific_private, data);
 
@@ -793,6 +791,13 @@ g_thread_proxy (gpointer data)
   G_LOCK (g_thread_new);
   G_UNLOCK (g_thread_new);
 
+  if (thread->name)
+    {
+      g_system_thread_set_name (thread->name);
+      g_free (thread->name);
+      thread->name = NULL;
+    }
+
   thread->retval = thread->thread.func (thread->thread.data);
 
   return NULL;
@@ -886,7 +891,7 @@ g_thread_new_internal (const gchar   *name,
       thread->thread.joinable = TRUE;
       thread->thread.func = func;
       thread->thread.data = data;
-      thread->name = name;
+      thread->name = g_strdup (name);
     }
   G_UNLOCK (g_thread_new);
 
index 3670b2f..6b974de 100644 (file)
@@ -32,7 +32,7 @@ struct  _GRealThread
 
   gint ref_count;
   gboolean ours;
-  const gchar *name;
+  gchar *name;
   gpointer retval;
 };
 
index a614c27..b6bb5a9 100644 (file)
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
+
 
 #include <glib.h>
 
@@ -160,6 +164,29 @@ test_thread5 (void)
   g_thread_unref (thread);
 }
 
+static gpointer
+thread6_func (gpointer data)
+{
+  const gchar name[16];
+
+#ifdef HAVE_SYS_PRCTL_H
+  prctl (PR_GET_NAME, name, 0, 0, 0, 0);
+
+  g_assert_cmpstr (name, ==, (gchar*)data);
+#endif
+
+  return NULL;
+}
+
+static void
+test_thread6 (void)
+{
+  GThread *thread;
+
+  thread = g_thread_new ("abc", thread6_func, "abc");
+  g_thread_join (thread);
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -170,6 +197,7 @@ main (int argc, char *argv[])
   g_test_add_func ("/thread/thread3", test_thread3);
   g_test_add_func ("/thread/thread4", test_thread4);
   g_test_add_func ("/thread/thread5", test_thread5);
+  g_test_add_func ("/thread/thread6", test_thread6);
 
   return g_test_run ();
 }