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