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