5f7b84
commit 11b451c8868d8a2b0edc5dfd44fc58d9ee538be0
5f7b84
Author: Mark Wielaard <mark@klomp.org>
5f7b84
Date:   Wed May 15 17:14:01 2019 +0200
5f7b84
5f7b84
    dlfcn: Guard __dlerror_main_freeres with __libc_once_get (once) [BZ# 24476]
5f7b84
    
5f7b84
    dlerror.c (__dlerror_main_freeres) will try to free resources which only
5f7b84
    have been initialized when init () has been called. That function is
5f7b84
    called when resources are needed using __libc_once (once, init) where
5f7b84
    once is a __libc_once_define (static, once) in the dlerror.c file.
5f7b84
    Trying to free those resources if init () hasn't been called will
5f7b84
    produce errors under valgrind memcheck. So guard the freeing of those
5f7b84
    resources using __libc_once_get (once) and make sure we have a valid
5f7b84
    key. Also add a similar guard to __dlerror ().
5f7b84
    
5f7b84
            * dlfcn/dlerror.c (__dlerror_main_freeres): Guard using
5f7b84
            __libc_once_get (once) and static_bug == NULL.
5f7b84
            (__dlerror): Check we have a valid key, set result to static_buf
5f7b84
            otherwise.
5f7b84
    
5f7b84
    Reviewed-by: Carlos O'Donell <carlos@redhat.com>
5f7b84
5f7b84
diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c
5f7b84
index 96bf92533335036b..06732460ea1512cd 100644
5f7b84
--- a/dlfcn/dlerror.c
5f7b84
+++ b/dlfcn/dlerror.c
5f7b84
@@ -72,9 +72,16 @@ __dlerror (void)
5f7b84
   __libc_once (once, init);
5f7b84
 
5f7b84
   /* Get error string.  */
5f7b84
-  result = (struct dl_action_result *) __libc_getspecific (key);
5f7b84
-  if (result == NULL)
5f7b84
-    result = &last_result;
5f7b84
+  if (static_buf != NULL)
5f7b84
+    result = static_buf;
5f7b84
+  else
5f7b84
+    {
5f7b84
+      /* init () has been run and we don't use the static buffer.
5f7b84
+	 So we have a valid key.  */
5f7b84
+      result = (struct dl_action_result *) __libc_getspecific (key);
5f7b84
+      if (result == NULL)
5f7b84
+	result = &last_result;
5f7b84
+    }
5f7b84
 
5f7b84
   /* Test whether we already returned the string.  */
5f7b84
   if (result->returned != 0)
5f7b84
@@ -230,13 +237,19 @@ free_key_mem (void *mem)
5f7b84
 void
5f7b84
 __dlerror_main_freeres (void)
5f7b84
 {
5f7b84
-  void *mem;
5f7b84
   /* Free the global memory if used.  */
5f7b84
   check_free (&last_result);
5f7b84
-  /* Free the TSD memory if used.  */
5f7b84
-  mem = __libc_getspecific (key);
5f7b84
-  if (mem != NULL)
5f7b84
-    free_key_mem (mem);
5f7b84
+
5f7b84
+  if (__libc_once_get (once) && static_buf == NULL)
5f7b84
+    {
5f7b84
+      /* init () has been run and we don't use the static buffer.
5f7b84
+	 So we have a valid key.  */
5f7b84
+      void *mem;
5f7b84
+      /* Free the TSD memory if used.  */
5f7b84
+      mem = __libc_getspecific (key);
5f7b84
+      if (mem != NULL)
5f7b84
+	free_key_mem (mem);
5f7b84
+    }
5f7b84
 }
5f7b84
 
5f7b84
 struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon));