]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - dlfcn/dlerror.c
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / dlfcn / dlerror.c
index 7ea31d4392860fab3f4df6a81e361701720989db..48b4c25bead9f0c89fbafc90dafec105d01a15e5 100644 (file)
@@ -1,5 +1,5 @@
 /* Return error detail for failing <dlfcn.h> functions.
-   Copyright (C) 1995-2000,2002,2003,2004,2005 Free Software Foundation, Inc.
+   Copyright (C) 1995-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -13,9 +13,8 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
 
 #include <dlfcn.h>
 #include <libintl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <bits/libc-lock.h>
+#include <libc-lock.h>
 #include <ldsodefs.h>
+#include <libc-symbols.h>
 
-#if !defined SHARED && defined IS_IN_libdl
+#if !defined SHARED && IS_IN (libdl)
 
 char *
 dlerror (void)
@@ -64,7 +64,7 @@ __dlerror (void)
   struct dl_action_result *result;
 
 # ifdef SHARED
-  if (__builtin_expect (_dlfcn_hook != NULL, 0))
+  if (!rtld_active ())
     return _dlfcn_hook->dlerror ();
 # endif
 
@@ -72,9 +72,16 @@ __dlerror (void)
   __libc_once (once, init);
 
   /* Get error string.  */
-  result = (struct dl_action_result *) __libc_getspecific (key);
-  if (result == NULL)
-    result = &last_result;
+  if (static_buf != NULL)
+    result = static_buf;
+  else
+    {
+      /* init () has been run and we don't use the static buffer.
+        So we have a valid key.  */
+      result = (struct dl_action_result *) __libc_getspecific (key);
+      if (result == NULL)
+       result = &last_result;
+    }
 
   /* Test whether we already returned the string.  */
   if (result->returned != 0)
@@ -121,7 +128,6 @@ strong_alias (__dlerror, dlerror)
 # endif
 
 int
-internal_function
 _dlerror_run (void (*operate) (void *), void *args)
 {
   struct dl_action_result *result;
@@ -161,8 +167,8 @@ _dlerror_run (void (*operate) (void *), void *args)
       result->errstring = NULL;
     }
 
-  result->errcode = GLRO(dl_catch_error) (&result->objname, &result->errstring,
-                                         &result->malloced, operate, args);
+  result->errcode = _dl_catch_error (&result->objname, &result->errstring,
+                                    &result->malloced, operate, args);
 
   /* If no error we mark that no error string is available.  */
   result->returned = result->errstring == NULL;
@@ -191,12 +197,18 @@ check_free (struct dl_action_result *rec)
     {
       /* We can free the string only if the allocation happened in the
         C library used by the dynamic linker.  This means, it is
-        always the C library in the base namespave.  */
+        always the C library in the base namespace.  When we're statically
+         linked, the dynamic linker is part of the program and so always
+        uses the same C library we use here.  */
+#ifdef SHARED
       struct link_map *map = NULL;
       Dl_info info;
-      if (_dl_addr (check_free, &info, &map, NULL) != 0
-         && map != NULL && map->l_ns == 0)
-       free ((char *) rec->errstring);
+      if (_dl_addr (check_free, &info, &map, NULL) != 0 && map->l_ns == 0)
+#endif
+       {
+         free ((char *) rec->errstring);
+         rec->errstring = NULL;
+       }
     }
 }
 
@@ -221,6 +233,25 @@ free_key_mem (void *mem)
 
 # ifdef SHARED
 
+/* Free the dlerror-related resources.  */
+void
+__dlerror_main_freeres (void)
+{
+  /* Free the global memory if used.  */
+  check_free (&last_result);
+
+  if (__libc_once_get (once) && static_buf == NULL)
+    {
+      /* init () has been run and we don't use the static buffer.
+        So we have a valid key.  */
+      void *mem;
+      /* Free the TSD memory if used.  */
+      mem = __libc_getspecific (key);
+      if (mem != NULL)
+       free_key_mem (mem);
+    }
+}
+
 struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon));
 libdl_hidden_data_def (_dlfcn_hook)