diff options
29 files changed, 529 insertions, 239 deletions
@@ -1,5 +1,65 @@ 2017-08-10 Florian Weimer <fweimer@redhat.com> + Introduce ld.so exceptions. + * sysdeps/generic/ldsodefs.h (struct dl_exception): Define. + (_dl_exception_create, _dl_exception_create_format) + (_dl_exception_free, _dl_signal_exception, _dl_signal_cexception) + (_dl_catch_exception): Declare. + (_dl_catch_error): Update comment. + * elf/dl-error-skeleton.c (struct catch): Replace objname, + errstring, malloced members with exception member. + (_dl_out_of_memory): Remove. + (fatal_error): New function, extracted from _dl_signal_error. + (_dl_signal_exception, _dl_signal_cexception): New functions. + (_dl_signal_error): Call _dl_exception_create to allocate an + exception object. + (_dl_catch_exception): New function, based on _dl_catch_error. + (_dl_catch_error): Implement using _dl_catch_exception. + * elf/dl-exception.c: New file. + * elf/Makefile (dl-routines): Add dl-exception. + (elide-routines.os): Likewise. + * elf/Version (ld/GLIBC_PRIVATE): Add _dl_exception_create, + _dl_exception_create_format, _dl_exception_free. + * elf/dl-deps.c (_dl_map_object_deps): Use _dl_catch_exception and + _dl_signal_exception. + * elf/dl-lookup.c (make_string): Remove. + (_dl_lookup_symbol_x): Use _dl_exception_create_format, + _dl_signal_cexception, _dl_exception_free. + * elf/dl-open.c (_dl_open): Use _dl_catch_exception and + _dl_signal_exception. + * elf/dl-sym.c (do_sym): Likewise. + * elf/dl-version.c (make_string): Remove. + (match_symbol): Use _dl_exception_create_format, + _dl_signal_cexception, _dl_exception_free. + (_dl_check_map_versions): Likewise. + * sysdeps/generic/localplt.data (ld.so): Add _dl_signal_exception, + _dl_catch_exception. + * sysdeps/unix/sysv/linux/aarch64/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/alpha/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/arm/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/hppa/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/i386/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/ia64/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/m68k/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/microblaze/localplt.data (ld.so): + Likewise. + * sysdeps/unix/sysv/linux/nios2/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data + (ld.so): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data + (ld.so): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data (ld.so): + Likewise. + * sysdeps/unix/sysv/linux/s390/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/sh/localplt.data (ld.so): Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data (ld.so): + Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data (ld.so): + Likewise. + * sysdeps/x86_64/localplt.data (ld.so): Likewise. + +2017-08-10 Florian Weimer <fweimer@redhat.com> + * inet/net-internal.h (__inet6_scopeid_pton): Remove attribute_hidden, internal_function. * inet/inet6_scopeid_pton.c (__inet6_scopeid_pton): Remove diff --git a/elf/Makefile b/elf/Makefile index b54ebf8..d314a5f 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -31,7 +31,8 @@ routines = $(all-dl-routines) dl-support dl-iteratephdr \ dl-routines = $(addprefix dl-,load lookup object reloc deps hwcaps \ runtime init fini debug misc \ version profile tls origin scope \ - execstack caller open close trampoline) + execstack caller open close trampoline \ + exception) ifeq (yes,$(use-ldconfig)) dl-routines += dl-cache endif @@ -51,7 +52,7 @@ endif all-dl-routines = $(dl-routines) $(sysdep-dl-routines) # But they are absent from the shared libc, because that code is in ld.so. elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \ - dl-sysdep + dl-sysdep dl-exception shared-only-routines += dl-caller # ld.so uses those routines, plus some special stuff for being the program diff --git a/elf/Versions b/elf/Versions index e65f2fa..79ffaf7 100644 --- a/elf/Versions +++ b/elf/Versions @@ -28,6 +28,7 @@ libc { __libc_dlclose; __libc_dlopen_mode; __libc_dlsym; # Internal error handling support. Interposes the functions in ld.so. + _dl_signal_exception; _dl_catch_exception; _dl_signal_error; _dl_catch_error; } } @@ -68,7 +69,11 @@ ld { # Pointer protection. __pointer_chk_guard; + # Internal error handling support. + _dl_exception_create; _dl_exception_create_format; _dl_exception_free; + # Internal error handling support. Interposed by libc.so. + _dl_signal_exception; _dl_catch_exception; _dl_signal_error; _dl_catch_error; # Set value of a tunable. diff --git a/elf/dl-deps.c b/elf/dl-deps.c index 1b8bac6..7c82d42 100644 --- a/elf/dl-deps.c +++ b/elf/dl-deps.c @@ -165,8 +165,7 @@ _dl_map_object_deps (struct link_map *map, const char *name; int errno_saved; int errno_reason; - const char *errstring; - const char *objname; + struct dl_exception exception; /* No loaded object so far. */ nlist = 0; @@ -200,7 +199,6 @@ _dl_map_object_deps (struct link_map *map, alloca means we cannot use recursive function calls. */ errno_saved = errno; errno_reason = 0; - errstring = NULL; errno = 0; name = NULL; for (runp = known; runp; ) @@ -250,17 +248,9 @@ _dl_map_object_deps (struct link_map *map, /* Store the tag in the argument structure. */ args.name = name; - bool malloced; - int err = _dl_catch_error (&objname, &errstring, &malloced, - openaux, &args); - if (__glibc_unlikely (errstring != NULL)) + int err = _dl_catch_exception (&exception, openaux, &args); + if (__glibc_unlikely (exception.errstring != NULL)) { - char *new_errstring = strdupa (errstring); - objname = strdupa (objname); - if (malloced) - free ((char *) errstring); - errstring = new_errstring; - if (err) errno_reason = err; else @@ -313,31 +303,18 @@ _dl_map_object_deps (struct link_map *map, /* We must be prepared that the addressed shared object is not available. For filter objects the dependency must be available. */ - bool malloced; - int err = _dl_catch_error (&objname, &errstring, &malloced, - openaux, &args); - - if (__glibc_unlikely (errstring != NULL)) + int err = _dl_catch_exception (&exception, openaux, &args); + if (__glibc_unlikely (exception.errstring != NULL)) { if (d->d_tag == DT_AUXILIARY) { /* We are not interested in the error message. */ - assert (errstring != NULL); - if (malloced) - free ((char *) errstring); - + _dl_exception_free (&exception); /* Simply ignore this error and continue the work. */ continue; } else { - - char *new_errstring = strdupa (errstring); - objname = strdupa (objname); - if (malloced) - free ((char *) errstring); - errstring = new_errstring; - if (err) errno_reason = err; else @@ -683,6 +660,6 @@ Filters not supported with LD_TRACE_PRELINKING")); _dl_scope_free (old_l_initfini); if (errno_reason) - _dl_signal_error (errno_reason == -1 ? 0 : errno_reason, objname, - NULL, errstring); + _dl_signal_exception (errno_reason == -1 ? 0 : errno_reason, + &exception, NULL); } diff --git a/elf/dl-error-skeleton.c b/elf/dl-error-skeleton.c index 8e5888d..8de6c87 100644 --- a/elf/dl-error-skeleton.c +++ b/elf/dl-error-skeleton.c @@ -39,10 +39,7 @@ _dl_signal_error. */ struct catch { - const char **objname; /* Object/File name. */ - const char **errstring; /* Error detail filled in here. */ - bool *malloced; /* Nonzero if the string is malloced - by the libc malloc. */ + struct dl_exception *exception; /* The exception data is stored there. */ volatile int *errcode; /* Return value of _dl_signal_error. */ jmp_buf env; /* longjmp here on error. */ }; @@ -60,11 +57,6 @@ static __thread struct catch *catch_hook attribute_tls_model_ie; static struct catch *catch_hook; #endif -/* This message we return as a last resort. We define the string in a - variable since we have to avoid freeing it and so have to enable - a pointer comparison. See below and in dlfcn/dlerror.c. */ -static const char _dl_out_of_memory[] = "out of memory"; - #if DL_ERROR_BOOTSTRAP /* This points to a function which is called when an continuable error is received. Unlike the handling of `catch' this function may return. @@ -76,6 +68,41 @@ static const char _dl_out_of_memory[] = "out of memory"; static receiver_fct receiver; #endif /* DL_ERROR_BOOTSTRAP */ +/* Lossage while resolving the program's own symbols is always fatal. */ +static void +__attribute__ ((noreturn)) +fatal_error (int errcode, const char *objname, const char *occasion, + const char *errstring) +{ + char buffer[1024]; + _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n", + RTLD_PROGNAME, + occasion ?: N_("error while loading shared libraries"), + objname, *objname ? ": " : "", + errstring, errcode ? ": " : "", + (errcode + ? __strerror_r (errcode, buffer, sizeof buffer) + : "")); +} + +void +_dl_signal_exception (int errcode, struct dl_exception *exception, + const char *occasion) +{ + struct catch *lcatch = catch_hook; + if (lcatch != NULL) + { + *lcatch->exception = *exception; + *lcatch->errcode = errcode; + + /* We do not restore the signal mask because none was saved. */ + __longjmp (lcatch->env[0].__jmpbuf, 1); + } + else + fatal_error (errcode, exception->objname, occasion, exception->errstring); +} +libc_hidden_def (_dl_signal_exception) + void internal_function _dl_signal_error (int errcode, const char *objname, const char *occation, @@ -86,66 +113,43 @@ _dl_signal_error (int errcode, const char *objname, const char *occation, if (! errstring) errstring = N_("DYNAMIC LINKER BUG!!!"); - if (objname == NULL) - objname = ""; if (lcatch != NULL) { - /* We are inside _dl_catch_error. Return to it. We have to - duplicate the error string since it might be allocated on the - stack. The object name is always a string constant. */ - size_t len_objname = strlen (objname) + 1; - size_t len_errstring = strlen (errstring) + 1; - - char *errstring_copy = malloc (len_objname + len_errstring); - if (errstring_copy != NULL) - { - /* Make a copy of the object file name and the error string. */ - *lcatch->objname = memcpy (__mempcpy (errstring_copy, - errstring, len_errstring), - objname, len_objname); - *lcatch->errstring = errstring_copy; - - /* If the main executable is relocated it means the libc's malloc - is used. */ - bool malloced = true; -#ifdef SHARED - malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL - && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated != 0)); -#endif - *lcatch->malloced = malloced; - } - else - { - /* This is better than nothing. */ - *lcatch->objname = ""; - *lcatch->errstring = _dl_out_of_memory; - *lcatch->malloced = false; - } - + _dl_exception_create (lcatch->exception, objname, errstring); *lcatch->errcode = errcode; /* We do not restore the signal mask because none was saved. */ __longjmp (lcatch->env[0].__jmpbuf, 1); } else - { - /* Lossage while resolving the program's own symbols is always fatal. */ - char buffer[1024]; - _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n", - RTLD_PROGNAME, - occation ?: N_("error while loading shared libraries"), - objname, *objname ? ": " : "", - errstring, errcode ? ": " : "", - (errcode - ? __strerror_r (errcode, buffer, sizeof buffer) - : "")); - } + fatal_error (errcode, objname, occation, errstring); } libc_hidden_def (_dl_signal_error) #if DL_ERROR_BOOTSTRAP void +_dl_signal_cexception (int errcode, struct dl_exception *exception, + const char *occasion) +{ + if (__builtin_expect (GLRO(dl_debug_mask) + & ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0)) + _dl_debug_printf ("%s: error: %s: %s (%s)\n", + exception->objname, occasion, + exception->errstring, receiver ? "continued" : "fatal"); + + if (receiver) + { + /* We are inside _dl_receive_error. Call the user supplied + handler and resume the work. The receiver will still be + installed. */ + (*receiver) (errcode, exception->objname, exception->errstring); + } + else + _dl_signal_exception (errcode, exception, occasion); +} + +void internal_function _dl_signal_cerror (int errcode, const char *objname, const char *occation, const char *errstring) @@ -167,11 +171,9 @@ _dl_signal_cerror (int errcode, const char *objname, const char *occation, } #endif /* DL_ERROR_BOOTSTRAP */ - int -internal_function -_dl_catch_error (const char **objname, const char **errstring, - bool *mallocedp, void (*operate) (void *), void *args) +_dl_catch_exception (struct dl_exception *exception, + void (*operate) (void *), void *args) { /* We need not handle `receiver' since setting a `catch' is handled before it. */ @@ -184,9 +186,7 @@ _dl_catch_error (const char **objname, const char **errstring, struct catch c; /* Don't use an initializer since we don't need to clear C.env. */ - c.objname = objname; - c.errstring = errstring; - c.malloced = mallocedp; + c.exception = exception; c.errcode = &errcode; struct catch *const old = catch_hook; @@ -197,17 +197,30 @@ _dl_catch_error (const char **objname, const char **errstring, { (*operate) (args); catch_hook = old; - *objname = NULL; - *errstring = NULL; - *mallocedp = false; + *exception = (struct dl_exception) { NULL }; return 0; } - /* We get here only if we longjmp'd out of OPERATE. _dl_signal_error has - already stored values into *OBJNAME, *ERRSTRING, and *MALLOCEDP. */ + /* We get here only if we longjmp'd out of OPERATE. + _dl_signal_exception has already stored values into + *EXCEPTION. */ catch_hook = old; return errcode; } +libc_hidden_def (_dl_catch_exception) + +int +internal_function +_dl_catch_error (const char **objname, const char **errstring, + bool *mallocedp, void (*operate) (void *), void *args) +{ + struct dl_exception exception; + int errorcode = _dl_catch_exception (&exception, operate, args); + *objname = exception.objname; + *errstring = exception.errstring; + *mallocedp = exception.message_buffer == exception.errstring; + return errorcode; +} libc_hidden_def (_dl_catch_error) #if DL_ERROR_BOOTSTRAP diff --git a/elf/dl-exception.c b/elf/dl-exception.c new file mode 100644 index 0000000..b4d0ca7 --- /dev/null +++ b/elf/dl-exception.c @@ -0,0 +1,202 @@ +/* ld.so error exception allocation and deallocation. + Copyright (C) 1995-2017 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 + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + <http://www.gnu.org/licenses/>. */ + +#include <ldsodefs.h> +#include <limits.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +/* This message we return as a last resort. We define the string in a + variable since we have to avoid freeing it and so have to enable + a pointer comparison. See below and in dlfcn/dlerror.c. */ +static const char _dl_out_of_memory[] = "out of memory"; + +/* Dummy allocation object used if allocating the message buffer + fails. */ +static void +oom_exception (struct dl_exception *exception) +{ + exception->objname = ""; + exception->errstring = _dl_out_of_memory; + exception->message_buffer = NULL; +} + +static void +__attribute__ ((noreturn)) +length_mismatch (void) +{ + _dl_fatal_printf ("Fatal error: " + "length accounting in _dl_exception_create_format\n"); +} + +/* Adjust the message buffer to indicate whether it is possible to + free it. EXCEPTION->errstring must be a potentially deallocatable + pointer. */ +static void +adjust_message_buffer (struct dl_exception *exception) +{ + /* If the main executable is relocated it means the libc's malloc + is used. */ + bool malloced = true; +#ifdef SHARED + malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL + && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated != 0)); +#endif + if (malloced) + exception->message_buffer = (char *) exception->errstring; + else + exception->message_buffer = NULL; +} + +void +_dl_exception_create (struct dl_exception *exception, const char *objname, + const char *errstring) +{ + if (objname == NULL) + objname = ""; + size_t len_objname = strlen (objname) + 1; + size_t len_errstring = strlen (errstring) + 1; + char *errstring_copy = malloc (len_objname + len_errstring); + if (errstring_copy != NULL) + { + /* Make a copy of the object file name and the error string. */ + exception->objname = memcpy (__mempcpy (errstring_copy, + errstring, len_errstring), + objname, len_objname); + exception->errstring = errstring_copy; + adjust_message_buffer (exception); + } + else + oom_exception (exception); +} +rtld_hidden_def (_dl_exception_create) + +void +_dl_exception_create_format (struct dl_exception *exception, const char *objname, + const char *fmt, ...) +{ + if (objname == NULL) + objname = ""; + size_t len_objname = strlen (objname) + 1; + /* Compute the length of the result. Include room for two NUL + bytes. */ + size_t length = len_objname + 1; + { + va_list ap; + va_start (ap, fmt); + for (const char *p = fmt; *p != '\0'; ++p) + if (*p == '%') + { + ++p; + switch (*p) + { + case 's': + length += strlen (va_arg (ap, const char *)); + break; + default: + /* Assumed to be '%'. */ + ++length; + break; + } + } + else + ++length; + va_end (ap); + } + + if (length > PTRDIFF_MAX) + { + oom_exception (exception); + return; + } + char *errstring = malloc (length); + if (errstring == NULL) + { + oom_exception (exception); + return; + } + exception->errstring = errstring; + adjust_message_buffer (exception); + + /* Copy the error message to errstring. */ + { + /* Next byte to be written in errstring. */ + char *wptr = errstring; + /* End of the allocated string. */ + char *const end = errstring + length; + + va_list ap; + va_start (ap, fmt); + + for (const char *p = fmt; *p != '\0'; ++p) + if (*p == '%') + { + ++p; + switch (*p) + { + case 's': + { + const char *ptr = va_arg (ap, const char *); + size_t len_ptr = strlen (ptr); + if (len_ptr > end - wptr) + length_mismatch (); + wptr = __mempcpy (wptr, ptr, len_ptr); + } + break; + case '%': + if (wptr == end) + length_mismatch (); + *wptr = '%'; + ++wptr; + break; + default: + _dl_fatal_printf ("Fatal error:" + " invalid format in exception string\n"); + } + } + else + { + if (wptr == end) + length_mismatch (); + *wptr = *p; + ++wptr; + } + + if (wptr == end) + length_mismatch (); + *wptr = '\0'; + ++wptr; + if (len_objname != end - wptr) + length_mismatch (); + exception->objname = memcpy (wptr, objname, len_objname); + } +} +rtld_hidden_def (_dl_exception_create_format) + +void +_dl_exception_free (struct dl_exception *exception) +{ + free (exception->message_buffer); + exception->objname = NULL; + exception->errstring = NULL; + exception->message_buffer = NULL; +} +rtld_hidden_def (_dl_exception_free) diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c index 3d2369d..645dc3e 100644 --- a/elf/dl-lookup.c +++ b/elf/dl-lookup.c @@ -47,23 +47,6 @@ struct sym_val }; -#define make_string(string, rest...) \ - ({ \ - const char *all[] = { string, ## rest }; \ - size_t len, cnt; \ - char *result, *cp; \ - \ - len = 1; \ - for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ - len += strlen (all[cnt]); \ - \ - cp = result = alloca (len); \ - for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ - cp = __stpcpy (cp, all[cnt]); \ - \ - result; \ - }) - /* Statistics function. */ #ifdef SHARED # define bump_num_relocations() ++GL(dl_num_relocations) @@ -843,17 +826,16 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map, for unversioned lookups. */ assert (version != NULL); const char *reference_name = undef_map ? undef_map->l_name : ""; - + struct dl_exception exception; /* XXX We cannot translate the message. */ - _dl_signal_cerror (0, DSO_FILENAME (reference_name), - N_("relocation error"), - make_string ("symbol ", undef_name, ", version ", - version->name, - " not defined in file ", - version->filename, - " with link time reference", - res == -2 - ? " (no version symbols)" : "")); + _dl_exception_create_format + (&exception, DSO_FILENAME (reference_name), + "symbol %s version %s not defined in file %s" + " with link time reference%s", + undef_name, version->name, version->filename, + res == -2 ? " (no version symbols)" : ""); + _dl_signal_cexception (0, &exception, N_("relocation error")); + _dl_exception_free (&exception); *ref = NULL; return 0; } @@ -869,12 +851,14 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map, const char *versionstr = version ? ", version " : ""; const char *versionname = (version && version->name ? version->name : ""); - + struct dl_exception exception; /* XXX We cannot translate the message. */ - _dl_signal_cerror (0, DSO_FILENAME (reference_name), - N_("symbol lookup error"), - make_string ("undefined symbol: ", undef_name, - versionstr, versionname)); + _dl_exception_create_format + (&exception, DSO_FILENAME (reference_name), + "undefined symbol: %s%s%s", + undef_name, versionstr, versionname); + _dl_signal_cexception (0, &exception, N_("symbol lookup error")); + _dl_exception_free (&exception); } *ref = NULL; return 0; diff --git a/elf/dl-open.c b/elf/dl-open.c index cec54db..91a1d1a 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -643,11 +643,8 @@ no more namespaces available for dlmopen()")); args.argv = argv; args.env = env; - const char *objname; - const char *errstring; - bool malloced; - int errcode = _dl_catch_error (&objname, &errstring, &malloced, - dl_open_worker, &args); + struct dl_exception exception; + int errcode = _dl_catch_exception (&exception, dl_open_worker, &args); #if defined USE_LDCONFIG && !defined MAP_COPY /* We must unmap the cache file. */ @@ -655,7 +652,7 @@ no more namespaces available for dlmopen()")); #endif /* See if an error occurred during loading. */ - if (__glibc_unlikely (errstring != NULL)) + if (__glibc_unlikely (exception.errstring != NULL)) { /* Remove the object from memory. It may be in an inconsistent state if relocation failed, for example. */ @@ -679,28 +676,8 @@ no more namespaces available for dlmopen()")); /* Release the lock. */ __rtld_lock_unlock_recursive (GL(dl_load_lock)); - /* Make a local copy of the error string so that we can release the - memory allocated for it. */ - size_t len_errstring = strlen (errstring) + 1; - char *local_errstring; - if (objname == errstring + len_errstring) - { - size_t total_len = len_errstring + strlen (objname) + 1; - local_errstring = alloca (total_len); - memcpy (local_errstring, errstring, total_len); - objname = local_errstring + len_errstring; - } - else - { - local_errstring = alloca (len_errstring); - memcpy (local_errstring, errstring, len_errstring); - } - - if (malloced) - free ((char *) errstring); - /* Reraise the error. */ - _dl_signal_error (errcode, objname, NULL, local_errstring); + _dl_signal_exception (errcode, &exception, NULL); } assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT); diff --git a/elf/dl-sym.c b/elf/dl-sym.c index 7cd6e97..fb54a91 100644 --- a/elf/dl-sym.c +++ b/elf/dl-sym.c @@ -119,26 +119,11 @@ do_sym (void *handle, const char *name, void *who, args.refp = &ref; THREAD_GSCOPE_SET_FLAG (); - - const char *objname; - const char *errstring = NULL; - bool malloced; - int err = _dl_catch_error (&objname, &errstring, &malloced, - call_dl_lookup, &args); - + struct dl_exception exception; + int err = _dl_catch_exception (&exception, call_dl_lookup, &args); THREAD_GSCOPE_RESET_FLAG (); - - if (__glibc_unlikely (errstring != NULL)) - { - /* The lookup was unsuccessful. Rethrow the error. */ - char *errstring_dup = strdupa (errstring); - char *objname_dup = strdupa (objname); - if (malloced) - free ((char *) errstring); - - _dl_signal_error (err, objname_dup, NULL, errstring_dup); - /* NOTREACHED */ - } + if (__glibc_unlikely (exception.errstring != NULL)) + _dl_signal_exception (err, &exception, NULL); result = args.map; } diff --git a/elf/dl-version.c b/elf/dl-version.c index c00078e..c0d76ad 100644 --- a/elf/dl-version.c +++ b/elf/dl-version.c @@ -27,25 +27,6 @@ #include <assert.h> - -#define make_string(string, rest...) \ - ({ \ - const char *all[] = { string, ## rest }; \ - size_t len, cnt; \ - char *result, *cp; \ - \ - len = 1; \ - for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ - len += strlen (all[cnt]); \ - \ - cp = result = alloca (len); \ - for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ - cp = __stpcpy (cp, all[cnt]); \ - \ - result; \ - }) - - static inline struct link_map * __attribute ((always_inline)) find_needed (const char *name, struct link_map *map) @@ -78,8 +59,8 @@ match_symbol (const char *name, Lmid_t ns, ElfW(Word) hash, const char *string, ElfW(Addr) def_offset; ElfW(Verdef) *def; /* Initialize to make the compiler happy. */ - const char *errstring = NULL; int result = 0; + struct dl_exception exception; /* Display information about what we are doing while debugging. */ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_VERSIONS)) @@ -96,8 +77,9 @@ checking for version `%s' in file %s [%lu] required by file %s [%lu]\n", if (verbose) { /* XXX We cannot translate the messages. */ - errstring = make_string ("\ -no version information available (required by ", name, ")"); + _dl_exception_create_format + (&exception, DSO_FILENAME (map->l_name), + "no version information available (required by %s)", name); goto call_cerror; } return 0; @@ -116,10 +98,10 @@ no version information available (required by ", name, ")"); char buf[20]; buf[sizeof (buf) - 1] = '\0'; /* XXX We cannot translate the message. */ - errstring = make_string ("unsupported version ", - _itoa (def->vd_version, - &buf[sizeof (buf) - 1], 10, 0), - " of Verdef record"); + _dl_exception_create_format + (&exception, DSO_FILENAME (map->l_name), + "unsupported version %s of Verdef record", + _itoa (def->vd_version, &buf[sizeof (buf) - 1], 10, 0)); result = 1; goto call_cerror; } @@ -150,20 +132,22 @@ no version information available (required by ", name, ")"); if (verbose) { /* XXX We cannot translate the message. */ - errstring = make_string ("weak version `", string, - "' not found (required by ", name, ")"); + _dl_exception_create_format + (&exception, DSO_FILENAME (map->l_name), + "weak version `%s' not found (required by %s)", string, name); goto call_cerror; } return 0; } /* XXX We cannot translate the message. */ - errstring = make_string ("version `", string, "' not found (required by ", - name, ")"); + _dl_exception_create_format + (&exception, DSO_FILENAME (map->l_name), + "version `%s' not found (required by %s)", string, name); result = 1; call_cerror: - _dl_signal_cerror (0, DSO_FILENAME (map->l_name), - N_("version lookup error"), errstring); + _dl_signal_cexception (0, &exception, N_("version lookup error")); + _dl_exception_free (&exception); return result; } @@ -181,8 +165,8 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode) /* We need to find out which is the highest version index used in a dependecy. */ unsigned int ndx_high = 0; + struct dl_exception exception; /* Initialize to make the compiler happy. */ - const char *errstring = NULL; int errval = 0; /* If we don't have a string table, we must be ok. */ @@ -205,13 +189,12 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode) char buf[20]; buf[sizeof (buf) - 1] = '\0'; /* XXX We cannot translate the message. */ - errstring = make_string ("unsupported version ", - _itoa (ent->vn_version, - &buf[sizeof (buf) - 1], 10, 0), - " of Verneed record\n"); + _dl_exception_create_format + (&exception, DSO_FILENAME (map->l_name), + "unsupported version %s of Verneed record", + _itoa (ent->vn_version, &buf[sizeof (buf) - 1], 10, 0)); call_error: - _dl_signal_error (errval, DSO_FILENAME (map->l_name), - NULL, errstring); + _dl_signal_exception (errval, &exception, NULL); } while (1) @@ -293,7 +276,9 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode) calloc (ndx_high + 1, sizeof (*map->l_versions)); if (__glibc_unlikely (map->l_versions == NULL)) { - errstring = N_("cannot allocate version reference table"); + _dl_exception_create + (&exception, DSO_FILENAME (map->l_name), + N_("cannot allocate version reference table")); errval = ENOMEM; goto call_error; } diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index 4508365..1c0b9cb 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -732,31 +732,88 @@ _dl_dprintf (int fd, const char *fmt, ...) while (1) -/* This function is called by all the internal dynamic linker functions - when they encounter an error. ERRCODE is either an `errno' code or - zero; OBJECT is the name of the problematical shared object, or null if - it is a general problem; ERRSTRING is a string describing the specific - problem. */ +/* An exception raised by the _dl_signal_error function family and + caught by _dl_catch_error function family. Exceptions themselves + are copied as part of the raise operation, but the strings are + not. */ +struct dl_exception +{ + const char *objname; + const char *errstring; + + /* This buffer typically stores both objname and errstring + above. */ + char *message_buffer; +}; + +/* Creates a new exception. This calls malloc; if allocation fails, + dummy values are inserted. OBJECT is the name of the problematical + shared object, or null if its a general problem. ERRSTRING is a + string describing the specific problem. */ +void _dl_exception_create (struct dl_exception *, const char *object, + const char *errstring) + __attribute__ ((nonnull (1, 3))); +rtld_hidden_proto (_dl_exception_create) + +/* Like _dl_exception_create, but create errstring from a format + string FMT. Currently, only "%s" and "%%" are supported as format + directives. */ +void _dl_exception_create_format (struct dl_exception *, const char *objname, + const char *fmt, ...) + __attribute__ ((nonnull (1, 3), format (printf, 3, 4))); +rtld_hidden_proto (_dl_exception_create_format) + +/* Deallocate the exception, freeing allocated buffers (if + possible). */ +void _dl_exception_free (struct dl_exception *) + __attribute__ ((nonnull (1))); +rtld_hidden_proto (_dl_exception_free) + +/* This function is called by all the internal dynamic linker + functions when they encounter an error. ERRCODE is either an + `errno' code or zero; it specifies the return value of + _dl_catch_error. OCCASION is included in the error message if the + process is terminated immediately. */ +void _dl_signal_exception (int errcode, struct dl_exception *, + const char *occasion) + __attribute__ ((__noreturn__)); +libc_hidden_proto (_dl_signal_exception) + +/* Like _dl_signal_exception, but creates the exception first. */ extern void _dl_signal_error (int errcode, const char *object, - const char *occurred, const char *errstring) + const char *occasion, const char *errstring) internal_function __attribute__ ((__noreturn__)); libc_hidden_proto (_dl_signal_error) -/* Like _dl_signal_error, but may return when called in the context of - _dl_receive_error. This is only used during ld.so bootstrap. In - static and profiled builds, this is equivalent to - _dl_signal_error. */ +/* Like _dl_signal_exception, but may return when called in the + context of _dl_receive_error. This is only used during ld.so + bootstrap. In static and profiled builds, this is equivalent to + _dl_signal_exception. */ +#if IS_IN (rtld) +extern void _dl_signal_cexception (int errcode, struct dl_exception *, + const char *occasion) attribute_hidden; +#else +__attribute__ ((always_inline)) +static inline void +_dl_signal_cexception (int errcode, struct dl_exception *exception, + const char *occasion) +{ + _dl_signal_exception (errcode, exception, occasion); +} +#endif + +/* See _dl_signal_cexception above. */ #if IS_IN (rtld) extern void _dl_signal_cerror (int errcode, const char *object, - const char *occation, const char *errstring) + const char *occasion, const char *errstring) internal_function attribute_hidden; #else __attribute__ ((always_inline)) static inline void _dl_signal_cerror (int errcode, const char *object, - const char *occation, const char *errstring) + const char *occasion, const char *errstring) { - _dl_signal_error (errcode, object, occation, errstring); + _dl_signal_error (errcode, object, occasion, errstring); } #endif @@ -768,20 +825,28 @@ extern void _dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args) internal_function attribute_hidden; -/* Call OPERATE, catching errors from `dl_signal_error'. If there is no - error, *ERRSTRING is set to null. If there is an error, *ERRSTRING is - set to a string constructed from the strings passed to _dl_signal_error, - and the error code passed is the return value and *OBJNAME is set to - the object name which experienced the problems. ERRSTRING if nonzero - points to a malloc'ed string which the caller has to free after use. - ARGS is passed as argument to OPERATE. MALLOCEDP is set to true only - if the returned string is allocated using the libc's malloc. */ +/* Call OPERATE, catching errors from `_dl_signal_error' and related + functions. If there is no error, *ERRSTRING is set to null. If + there is an error, *ERRSTRING is set to a string constructed from + the strings passed to _dl_signal_error, and the error code passed + is the return value and *OBJNAME is set to the object name which + experienced the problems. ERRSTRING if nonzero points to a + malloc'ed string which the caller has to free after use. ARGS is + passed as argument to OPERATE. MALLOCEDP is set to true only if + the returned string is allocated using the libc's malloc. */ extern int _dl_catch_error (const char **objname, const char **errstring, bool *mallocedp, void (*operate) (void *), void *args) internal_function; libc_hidden_proto (_dl_catch_error) +/* Call OPERATE (ARGS). If no error occurs, set *EXCEPTION to zero. + Otherwise, store a copy of the raised exception in *EXCEPTION, + which has to be freed by _dl_exception_free. */ +int _dl_catch_exception (struct dl_exception *exception, + void (*operate) (void *), void *args); +libc_hidden_proto (_dl_catch_exception) + /* Open the shared object NAME and map in its segments. LOADER's DT_RPATH is used in searching for NAME. If the object is already opened, returns its existing map. */ diff --git a/sysdeps/generic/localplt.data b/sysdeps/generic/localplt.data index 81c741b..2d5c66a 100644 --- a/sysdeps/generic/localplt.data +++ b/sysdeps/generic/localplt.data @@ -16,3 +16,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/aarch64/localplt.data b/sysdeps/unix/sysv/linux/aarch64/localplt.data index bb18ff9..a60053b 100644 --- a/sysdeps/unix/sysv/linux/aarch64/localplt.data +++ b/sysdeps/unix/sysv/linux/aarch64/localplt.data @@ -18,3 +18,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/alpha/localplt.data b/sysdeps/unix/sysv/linux/alpha/localplt.data index 1f0e3b4..c69eb04 100644 --- a/sysdeps/unix/sysv/linux/alpha/localplt.data +++ b/sysdeps/unix/sysv/linux/alpha/localplt.data @@ -35,3 +35,5 @@ ld.so: free + RELA R_ALPHA_GLOB_DAT # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error + RELA R_ALPHA_GLOB_DAT ld.so: _dl_catch_error + RELA R_ALPHA_GLOB_DAT +ld.so: _dl_signal_exception + RELA R_ALPHA_GLOB_DAT +ld.so: _dl_catch_exception + RELA R_ALPHA_GLOB_DAT diff --git a/sysdeps/unix/sysv/linux/arm/localplt.data b/sysdeps/unix/sysv/linux/arm/localplt.data index 19d3299..7bd541c 100644 --- a/sysdeps/unix/sysv/linux/arm/localplt.data +++ b/sysdeps/unix/sysv/linux/arm/localplt.data @@ -17,3 +17,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/hppa/localplt.data b/sysdeps/unix/sysv/linux/hppa/localplt.data index db9e24b..3279c0a 100644 --- a/sysdeps/unix/sysv/linux/hppa/localplt.data +++ b/sysdeps/unix/sysv/linux/hppa/localplt.data @@ -21,3 +21,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data b/sysdeps/unix/sysv/linux/i386/localplt.data index 8ea4333..f6f20a5 100644 --- a/sysdeps/unix/sysv/linux/i386/localplt.data +++ b/sysdeps/unix/sysv/linux/i386/localplt.data @@ -16,3 +16,5 @@ ld.so: free + REL R_386_GLOB_DAT # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error + REL R_386_GLOB_DAT ld.so: _dl_catch_error + REL R_386_GLOB_DAT +ld.so: _dl_signal_exception + REL R_386_GLOB_DAT +ld.so: _dl_catch_exception + REL R_386_GLOB_DAT diff --git a/sysdeps/unix/sysv/linux/ia64/localplt.data b/sysdeps/unix/sysv/linux/ia64/localplt.data index fd2b98c..3820e2a 100644 --- a/sysdeps/unix/sysv/linux/ia64/localplt.data +++ b/sysdeps/unix/sysv/linux/ia64/localplt.data @@ -15,3 +15,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/m68k/localplt.data b/sysdeps/unix/sysv/linux/m68k/localplt.data index 1a2acfd..c70d6ea 100644 --- a/sysdeps/unix/sysv/linux/m68k/localplt.data +++ b/sysdeps/unix/sysv/linux/m68k/localplt.data @@ -15,3 +15,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/microblaze/localplt.data b/sysdeps/unix/sysv/linux/microblaze/localplt.data index ca476be..8ca2389 100644 --- a/sysdeps/unix/sysv/linux/microblaze/localplt.data +++ b/sysdeps/unix/sysv/linux/microblaze/localplt.data @@ -16,3 +16,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/nios2/localplt.data b/sysdeps/unix/sysv/linux/nios2/localplt.data index b0d6dca..4430a58 100644 --- a/sysdeps/unix/sysv/linux/nios2/localplt.data +++ b/sysdeps/unix/sysv/linux/nios2/localplt.data @@ -36,3 +36,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data index 5000631..e822e0a 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data @@ -14,3 +14,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data index 1c20d2f..fead931 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data @@ -44,3 +44,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data index 6f8ed25..c120933 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data @@ -13,3 +13,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/s390/localplt.data b/sysdeps/unix/sysv/linux/s390/localplt.data index 5000631..e822e0a 100644 --- a/sysdeps/unix/sysv/linux/s390/localplt.data +++ b/sysdeps/unix/sysv/linux/s390/localplt.data @@ -14,3 +14,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/sh/localplt.data b/sysdeps/unix/sysv/linux/sh/localplt.data index f1f5eff..2753547 100644 --- a/sysdeps/unix/sysv/linux/sh/localplt.data +++ b/sysdeps/unix/sysv/linux/sh/localplt.data @@ -19,3 +19,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data index 2f6ff3c..1668f40 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data @@ -26,3 +26,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data index 912bd1a..b881b90 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data @@ -27,3 +27,5 @@ ld.so: free # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error ld.so: _dl_catch_error +ld.so: _dl_signal_exception +ld.so: _dl_catch_exception diff --git a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data index a1840cf..c27a02b 100644 --- a/sysdeps/x86_64/localplt.data +++ b/sysdeps/x86_64/localplt.data @@ -18,3 +18,5 @@ ld.so: free + RELA R_X86_64_GLOB_DAT # The TLS-enabled version of these functions is interposed from libc.so. ld.so: _dl_signal_error + RELA R_X86_64_GLOB_DAT ld.so: _dl_catch_error + RELA R_X86_64_GLOB_DAT +ld.so: _dl_signal_exception + RELA R_X86_64_GLOB_DAT +ld.so: _dl_catch_exception + RELA R_X86_64_GLOB_DAT |