8a8cfb
commit e621246ec6393ea08ae50310f9d5e72500f8c9bc
8a8cfb
Author: Carlos O'Donell <carlos@redhat.com>
8a8cfb
Date:   Mon Apr 8 17:35:05 2019 -0400
8a8cfb
8a8cfb
    malloc: Set and reset all hooks for tracing (Bug 16573)
8a8cfb
    
8a8cfb
    If an error occurs during the tracing operation, particularly during a
8a8cfb
    call to lock_and_info() which calls _dl_addr, we may end up calling back
8a8cfb
    into the malloc-subsystem and relock the loader lock and deadlock. For
8a8cfb
    all intents and purposes the call to _dl_addr can call any of the malloc
8a8cfb
    family API functions and so we should disable all tracing before calling
8a8cfb
    such loader functions.  This is similar to the strategy that the new
8a8cfb
    malloc tracer takes when calling the real malloc, namely that all
8a8cfb
    tracing ceases at the boundary to the real function and any faults at
8a8cfb
    that point are the purvue of the library (though the new tracer does
8a8cfb
    this on a per-thread basis in an MT-safe fashion). Since the new tracer
8a8cfb
    and the hook deprecation are not yet complete we must fix these issues
8a8cfb
    where we can.
8a8cfb
    
8a8cfb
    Tested on x86_64 with no regressions.
8a8cfb
    
8a8cfb
    Co-authored-by: Kwok Cheung Yeung <kcy@codesourcery.com>
8a8cfb
    Reviewed-by: DJ Delorie <dj@redhat.com>
8a8cfb
8a8cfb
diff --git a/malloc/mtrace.c b/malloc/mtrace.c
8a8cfb
index 9064f209ec3b24c6..546d37a26018bf41 100644
8a8cfb
--- a/malloc/mtrace.c
8a8cfb
+++ b/malloc/mtrace.c
8a8cfb
@@ -121,6 +121,41 @@ lock_and_info (const void *caller, Dl_info *mem)
8a8cfb
   return res;
8a8cfb
 }
8a8cfb
 
8a8cfb
+static void tr_freehook (void *, const void *);
8a8cfb
+static void * tr_mallochook (size_t, const void *);
8a8cfb
+static void * tr_reallochook (void *, size_t, const void *);
8a8cfb
+static void * tr_memalignhook (size_t, size_t, const void *);
8a8cfb
+
8a8cfb
+/* Set all the default non-trace hooks.  */
8a8cfb
+static __always_inline void
8a8cfb
+set_default_hooks (void)
8a8cfb
+{
8a8cfb
+  __free_hook = tr_old_free_hook;
8a8cfb
+  __malloc_hook = tr_old_malloc_hook;
8a8cfb
+  __realloc_hook = tr_old_realloc_hook;
8a8cfb
+  __memalign_hook = tr_old_memalign_hook;
8a8cfb
+}
8a8cfb
+
8a8cfb
+/* Set all of the tracing hooks used for mtrace.  */
8a8cfb
+static __always_inline void
8a8cfb
+set_trace_hooks (void)
8a8cfb
+{
8a8cfb
+  __free_hook = tr_freehook;
8a8cfb
+  __malloc_hook = tr_mallochook;
8a8cfb
+  __realloc_hook = tr_reallochook;
8a8cfb
+  __memalign_hook = tr_memalignhook;
8a8cfb
+}
8a8cfb
+
8a8cfb
+/* Save the current set of hooks as the default hooks.  */
8a8cfb
+static __always_inline void
8a8cfb
+save_default_hooks (void)
8a8cfb
+{
8a8cfb
+  tr_old_free_hook = __free_hook;
8a8cfb
+  tr_old_malloc_hook = __malloc_hook;
8a8cfb
+  tr_old_realloc_hook = __realloc_hook;
8a8cfb
+  tr_old_memalign_hook = __memalign_hook;
8a8cfb
+}
8a8cfb
+
8a8cfb
 static void
8a8cfb
 tr_freehook (void *ptr, const void *caller)
8a8cfb
 {
8a8cfb
@@ -138,12 +173,12 @@ tr_freehook (void *ptr, const void *caller)
8a8cfb
       tr_break ();
8a8cfb
       __libc_lock_lock (lock);
8a8cfb
     }
8a8cfb
-  __free_hook = tr_old_free_hook;
8a8cfb
+  set_default_hooks ();
8a8cfb
   if (tr_old_free_hook != NULL)
8a8cfb
     (*tr_old_free_hook)(ptr, caller);
8a8cfb
   else
8a8cfb
     free (ptr);
8a8cfb
-  __free_hook = tr_freehook;
8a8cfb
+  set_trace_hooks ();
8a8cfb
   __libc_lock_unlock (lock);
8a8cfb
 }
8a8cfb
 
8a8cfb
@@ -155,12 +190,12 @@ tr_mallochook (size_t size, const void *caller)
8a8cfb
   Dl_info mem;
8a8cfb
   Dl_info *info = lock_and_info (caller, &mem;;
8a8cfb
 
8a8cfb
-  __malloc_hook = tr_old_malloc_hook;
8a8cfb
+  set_default_hooks ();
8a8cfb
   if (tr_old_malloc_hook != NULL)
8a8cfb
     hdr = (void *) (*tr_old_malloc_hook)(size, caller);
8a8cfb
   else
8a8cfb
     hdr = (void *) malloc (size);
8a8cfb
-  __malloc_hook = tr_mallochook;
8a8cfb
+  set_trace_hooks ();
8a8cfb
 
8a8cfb
   tr_where (caller, info);
8a8cfb
   /* We could be printing a NULL here; that's OK.  */
8a8cfb
@@ -185,16 +220,12 @@ tr_reallochook (void *ptr, size_t size, const void *caller)
8a8cfb
   Dl_info mem;
8a8cfb
   Dl_info *info = lock_and_info (caller, &mem;;
8a8cfb
 
8a8cfb
-  __free_hook = tr_old_free_hook;
8a8cfb
-  __malloc_hook = tr_old_malloc_hook;
8a8cfb
-  __realloc_hook = tr_old_realloc_hook;
8a8cfb
+  set_default_hooks ();
8a8cfb
   if (tr_old_realloc_hook != NULL)
8a8cfb
     hdr = (void *) (*tr_old_realloc_hook)(ptr, size, caller);
8a8cfb
   else
8a8cfb
     hdr = (void *) realloc (ptr, size);
8a8cfb
-  __free_hook = tr_freehook;
8a8cfb
-  __malloc_hook = tr_mallochook;
8a8cfb
-  __realloc_hook = tr_reallochook;
8a8cfb
+  set_trace_hooks ();
8a8cfb
 
8a8cfb
   tr_where (caller, info);
8a8cfb
   if (hdr == NULL)
8a8cfb
@@ -230,14 +261,12 @@ tr_memalignhook (size_t alignment, size_t size, const void *caller)
8a8cfb
   Dl_info mem;
8a8cfb
   Dl_info *info = lock_and_info (caller, &mem;;
8a8cfb
 
8a8cfb
-  __memalign_hook = tr_old_memalign_hook;
8a8cfb
-  __malloc_hook = tr_old_malloc_hook;
8a8cfb
+  set_default_hooks ();
8a8cfb
   if (tr_old_memalign_hook != NULL)
8a8cfb
     hdr = (void *) (*tr_old_memalign_hook)(alignment, size, caller);
8a8cfb
   else
8a8cfb
     hdr = (void *) memalign (alignment, size);
8a8cfb
-  __memalign_hook = tr_memalignhook;
8a8cfb
-  __malloc_hook = tr_mallochook;
8a8cfb
+  set_trace_hooks ();
8a8cfb
 
8a8cfb
   tr_where (caller, info);
8a8cfb
   /* We could be printing a NULL here; that's OK.  */
8a8cfb
@@ -305,14 +334,8 @@ mtrace (void)
8a8cfb
           malloc_trace_buffer = mtb;
8a8cfb
           setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
8a8cfb
           fprintf (mallstream, "= Start\n");
8a8cfb
-          tr_old_free_hook = __free_hook;
8a8cfb
-          __free_hook = tr_freehook;
8a8cfb
-          tr_old_malloc_hook = __malloc_hook;
8a8cfb
-          __malloc_hook = tr_mallochook;
8a8cfb
-          tr_old_realloc_hook = __realloc_hook;
8a8cfb
-          __realloc_hook = tr_reallochook;
8a8cfb
-          tr_old_memalign_hook = __memalign_hook;
8a8cfb
-          __memalign_hook = tr_memalignhook;
8a8cfb
+	  save_default_hooks ();
8a8cfb
+	  set_trace_hooks ();
8a8cfb
 #ifdef _LIBC
8a8cfb
           if (!added_atexit_handler)
8a8cfb
             {
8a8cfb
@@ -338,10 +361,7 @@ muntrace (void)
8a8cfb
      file.  */
8a8cfb
   FILE *f = mallstream;
8a8cfb
   mallstream = NULL;
8a8cfb
-  __free_hook = tr_old_free_hook;
8a8cfb
-  __malloc_hook = tr_old_malloc_hook;
8a8cfb
-  __realloc_hook = tr_old_realloc_hook;
8a8cfb
-  __memalign_hook = tr_old_memalign_hook;
8a8cfb
+  set_default_hooks ();
8a8cfb
 
8a8cfb
   fprintf (f, "= End\n");
8a8cfb
   fclose (f);