about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@gmail.com>2011-05-16 00:58:33 -0400
committerUlrich Drepper <drepper@gmail.com>2011-05-16 00:58:33 -0400
commit56e5eb4619a936a3b63ae71f89038d69becd2999 (patch)
treee6005c7864f9b4ecd3f3bdfcae9b5bad9c294045
parent6ce7537960cf42a0a6b0fc70957d5ce2ba9838de (diff)
downloadglibc-56e5eb4619a936a3b63ae71f89038d69becd2999.tar.gz
glibc-56e5eb4619a936a3b63ae71f89038d69becd2999.tar.xz
glibc-56e5eb4619a936a3b63ae71f89038d69becd2999.zip
Avoid potential deadlock in mtrace
The _dl_addr function might have to call malloc which would lead
to a deadlock.  Avoid by calling _dl_addr early.
-rw-r--r--ChangeLog10
-rw-r--r--NEWS16
-rw-r--r--malloc/mtrace.c64
3 files changed, 59 insertions, 31 deletions
diff --git a/ChangeLog b/ChangeLog
index cd89f3f7e4..4d3cf6d4ec 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
 2011-05-16  Ulrich Drepper  <drepper@gmail.com>
 
+	[BZ #6420]
+	* malloc/mtrace.c (tr_where): Add additional parameter to point to
+	symbol info.  Use it instead of calling _dl_addr locally.
+	(lock_and_info): New function.
+	(tr_freehook): Call lock_and_info and pass symbol info as additional
+	parameter to tr_where.
+	(tr_mallochook): Likewise.
+	(tr_reallochook): Likewise.
+	(tr_memalignhook): Likewise.
+
 	* malloc/mtrace.c: Remove support for USE_MTRACE_FILE.  It is not
 	used and couldn't be at all thread-safe.
 
diff --git a/NEWS b/NEWS
index 7100e1dbcb..74e676fd84 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-GNU C Library NEWS -- history of user-visible changes.  2011-5-15
+GNU C Library NEWS -- history of user-visible changes.  2011-5-16
 Copyright (C) 1992-2009, 2010, 2011 Free Software Foundation, Inc.
 See the end for copying conditions.
 
@@ -9,13 +9,13 @@ Version 2.14
 
 * The following bugs are resolved with this release:
 
-  386, 7101, 9730, 9732, 9809, 10138, 10149, 10157, 11257, 11258, 11487,
-  11532, 11578, 11653, 11668, 11724, 11901, 11945, 11947, 11952, 12052,
-  12083, 12158, 12178, 12200, 12346, 12393, 12420, 12432, 12445, 12449,
-  12453, 12454, 12460, 12469, 12489, 12509, 12510, 12511, 12518, 12527,
-  12541, 12545, 12551, 12582, 12583, 12587, 12597, 12601, 12611, 12625,
-  12626, 12631, 12650, 12653, 12655, 12660, 12681, 12685, 12711, 12713,
-  12714, 12717, 12723, 12724, 12734, 12738
+  386, 6420, 7101, 9730, 9732, 9809, 10138, 10149, 10157, 11257, 11258,
+  11487, 11532, 11578, 11653, 11668, 11724, 11901, 11945, 11947, 11952,
+  12052, 12083, 12158, 12178, 12200, 12346, 12393, 12420, 12432, 12445,
+  12449, 12453, 12454, 12460, 12469, 12489, 12509, 12510, 12511, 12518,
+  12527, 12541, 12545, 12551, 12582, 12583, 12587, 12597, 12601, 12611,
+  12625, 12626, 12631, 12650, 12653, 12655, 12660, 12681, 12685, 12711,
+  12713, 12714, 12717, 12723, 12724, 12734, 12738
 
 * The RPC implementation in libc is obsoleted.  Old programs keep working
   but new programs cannot be linked with the routines in libc anymore.
diff --git a/malloc/mtrace.c b/malloc/mtrace.c
index 51be396aaa..b55449f1ea 100644
--- a/malloc/mtrace.c
+++ b/malloc/mtrace.c
@@ -79,46 +79,59 @@ tr_break ()
 }
 libc_hidden_def (tr_break)
 
-static void tr_where (const __ptr_t) __THROW internal_function;
+static void tr_where (const __ptr_t, Dl_info *) __THROW internal_function;
 static void
 internal_function
-tr_where (caller)
+tr_where (caller, info)
      const __ptr_t caller;
+     Dl_info *info;
 {
   if (caller != NULL)
     {
-#ifdef HAVE_ELF
-      Dl_info info;
-      if (_dl_addr (caller, &info, NULL, NULL))
+      if (info != NULL)
 	{
 	  char *buf = (char *) "";
-	  if (info.dli_sname != NULL)
+	  if (info->dli_sname != NULL)
 	    {
-	      size_t len = strlen (info.dli_sname);
+	      size_t len = strlen (info->dli_sname);
 	      buf = alloca (len + 6 + 2 * sizeof (void *));
 
 	      buf[0] = '(';
-	      __stpcpy (_fitoa (caller >= (const __ptr_t) info.dli_saddr
-				? caller - (const __ptr_t) info.dli_saddr
-				: (const __ptr_t) info.dli_saddr - caller,
-				__stpcpy (__mempcpy (buf + 1, info.dli_sname,
+	      __stpcpy (_fitoa (caller >= (const __ptr_t) info->dli_saddr
+				? caller - (const __ptr_t) info->dli_saddr
+				: (const __ptr_t) info->dli_saddr - caller,
+				__stpcpy (__mempcpy (buf + 1, info->dli_sname,
 						     len),
-					  caller >= (__ptr_t) info.dli_saddr
+					  caller >= (__ptr_t) info->dli_saddr
 					  ? "+0x" : "-0x"),
 				16, 0),
 			")");
 	    }
 
 	  fprintf (mallstream, "@ %s%s%s[%p] ",
-		   info.dli_fname ?: "", info.dli_fname ? ":" : "",
+		   info->dli_fname ?: "", info->dli_fname ? ":" : "",
 		   buf, caller);
 	}
       else
-#endif
 	fprintf (mallstream, "@ [%p] ", caller);
     }
 }
 
+
+static Dl_info *
+lock_and_info (const __ptr_t caller, Dl_info *mem)
+{
+  if (caller == NULL)
+    return NULL;
+
+  Dl_info *res = _dl_addr (caller, mem, NULL, NULL) ? mem : NULL;
+
+  __libc_lock_lock (lock);
+
+  return res;
+}
+
+
 static void tr_freehook (__ptr_t, const __ptr_t) __THROW;
 static void
 tr_freehook (ptr, caller)
@@ -127,8 +140,10 @@ tr_freehook (ptr, caller)
 {
   if (ptr == NULL)
     return;
-  __libc_lock_lock (lock);
-  tr_where (caller);
+
+  Dl_info mem;
+  Dl_info *info = lock_and_info (caller, &mem);
+  tr_where (caller, info);
   /* Be sure to print it first.  */
   fprintf (mallstream, "- %p\n", ptr);
   __libc_lock_unlock (lock);
@@ -152,7 +167,8 @@ tr_mallochook (size, caller)
 {
   __ptr_t hdr;
 
-  __libc_lock_lock (lock);
+  Dl_info mem;
+  Dl_info *info = lock_and_info (caller, &mem);
 
   __malloc_hook = tr_old_malloc_hook;
   if (tr_old_malloc_hook != NULL)
@@ -161,7 +177,7 @@ tr_mallochook (size, caller)
     hdr = (__ptr_t) malloc (size);
   __malloc_hook = tr_mallochook;
 
-  tr_where (caller);
+  tr_where (caller, info);
   /* We could be printing a NULL here; that's OK.  */
   fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
 
@@ -186,7 +202,8 @@ tr_reallochook (ptr, size, caller)
   if (ptr == mallwatch)
     tr_break ();
 
-  __libc_lock_lock (lock);
+  Dl_info mem;
+  Dl_info *info = lock_and_info (caller, &mem);
 
   __free_hook = tr_old_free_hook;
   __malloc_hook = tr_old_malloc_hook;
@@ -199,7 +216,7 @@ tr_reallochook (ptr, size, caller)
   __malloc_hook = tr_mallochook;
   __realloc_hook = tr_reallochook;
 
-  tr_where (caller);
+  tr_where (caller, info);
   if (hdr == NULL)
     /* Failed realloc.  */
     fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
@@ -208,7 +225,7 @@ tr_reallochook (ptr, size, caller)
   else
     {
       fprintf (mallstream, "< %p\n", ptr);
-      tr_where (caller);
+      tr_where (caller, info);
       fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
     }
 
@@ -229,7 +246,8 @@ tr_memalignhook (alignment, size, caller)
 {
   __ptr_t hdr;
 
-  __libc_lock_lock (lock);
+  Dl_info mem;
+  Dl_info *info = lock_and_info (caller, &mem);
 
   __memalign_hook = tr_old_memalign_hook;
   __malloc_hook = tr_old_malloc_hook;
@@ -240,7 +258,7 @@ tr_memalignhook (alignment, size, caller)
   __memalign_hook = tr_memalignhook;
   __malloc_hook = tr_mallochook;
 
-  tr_where (caller);
+  tr_where (caller, info);
   /* We could be printing a NULL here; that's OK.  */
   fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);