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