diff options
author | Ulrich Drepper <drepper@redhat.com> | 1998-03-12 17:26:19 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 1998-03-12 17:26:19 +0000 |
commit | 8d9618b7f6ecbcd04fd572140bbecaf9be10d376 (patch) | |
tree | ce9f6b373142f8875c9d6a4543e20c732afab18a /elf/dlerror.c | |
parent | eb13b9a02d939ee7440472c5a5f86e55f3adbd54 (diff) | |
download | glibc-8d9618b7f6ecbcd04fd572140bbecaf9be10d376.tar.gz glibc-8d9618b7f6ecbcd04fd572140bbecaf9be10d376.tar.xz glibc-8d9618b7f6ecbcd04fd572140bbecaf9be10d376.zip |
Update.
1998-03-12 13:11 Tim Waugh <tim@cyberelk.demon.co.uk> * posix/wordexp-test.c: More tests. (main): Set up arena for pathname expansion tests (in a temporary directory). (testit): Don't check word count or word vector if return value is non-zero. * posix/wordexp.c (exec_comm): Always chop off terminating linefeed (just like bash does). (parse_param): Change lots of occurrences of "if (!*env)" to "if (!env || !*env)". (parse_param): For assignment inside parameter expansion, use all expanded words in assignment rather than just the first. (parse_param): Corrected return value for parameter expansion of an unset variable when WRDE_UNDEF is in effect. (parse_dollars): Don't field-split if quoted. (wordexp): Opening brace character isn't allowed unquoted. 1998-03-12 Ulrich Drepper <drepper@cygnus.com> * elf/dlerror.c: Fix concurrency problems with error string and number. * elf/dl-deps.c (_dl_map_object_deps): Print debug info when filter/auxiliary are being loaded. 1998-03-12 14:24 Ulrich Drepper <drepper@cygnus.com> * elf/dlerror.c (last_object_name): Removed. (dlerror): Don't use last_object_name. (_dl_error_run): Omit second argument to _dl_catch_error. * elf/dl-error.c (struct catch): Remove objname member. (_dl_signal_error): Construct string including objname when given. (_dl_catch_error): Remove objname handling. * elf/link.h (_dl_catch_error): Fix prototype and comment. * elf/rtld.c (dl_main): Call _dl_catch_error correctly. * elf/dl-deps.c (_dl_map_objet_deps): Likewise. * nss/nsswitch.c (nss_dlerror_run): Likewise. * iconv/gconv_dl.c (dlerror_run): Likewise. [Corrects PR libc/501].
Diffstat (limited to 'elf/dlerror.c')
-rw-r--r-- | elf/dlerror.c | 127 |
1 files changed, 100 insertions, 27 deletions
diff --git a/elf/dlerror.c b/elf/dlerror.c index e2b1ac94a9..3edafe4f1c 100644 --- a/elf/dlerror.c +++ b/elf/dlerror.c @@ -1,5 +1,5 @@ /* Return error detail for failing <dlfcn.h> functions. - Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 1995, 1996, 1997, 1998 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 @@ -22,16 +22,32 @@ #include <stdio.h> #include <string.h> #include <stdlib.h> +#include <bits/libc-lock.h> + + +/* Type for storing results of dynamic loading actions. */ +struct dl_action_result + { + int errcode; + char *errstring; + }; +static struct dl_action_result last_result; +static struct dl_action_result *static_buf; + + +/* This is the key for the thread specific memory. */ +static __libc_key_t key; + +/* Destructor for the thread-specific data. */ +static void init (void); +static void free_key_mem (void *mem); -static int last_errcode; -static char *last_errstring; -static const char *last_object_name; char * dlerror (void) { static char *buf; - char *ret; + struct dl_action_result *result; if (buf) { @@ -39,39 +55,96 @@ dlerror (void) buf = NULL; } - if (! last_errstring) + /* Get error string. */ + if (__libc_internal_tsd_get != NULL) + { + result = (struct dl_action_result *) __libc_getspecific (key); + if (result == NULL) + result = &last_result; + } + else + result = &last_result; + + if (! result->errstring) return NULL; - if (last_errcode == 0 && ! last_object_name) - ret = (char *) last_errstring; - else if (last_errcode == 0) - ret = (asprintf (&buf, "%s: %s", last_object_name, last_errstring) == -1 - ? NULL : buf); - else if (! last_object_name) - ret = (asprintf (&buf, "%s: %s", - last_errstring, strerror (last_errcode)) == -1 - ? NULL : buf); + if (result->errcode == 0) + buf = result->errstring; else - ret = (asprintf (&buf, "%s: %s: %s", - last_object_name, last_errstring, - strerror (last_errcode)) == -1 - ? NULL : buf); + { + if (asprintf (&buf, "%s: %s", + result->errstring, strerror (result->errcode)) == -1) + buf = NULL; + + /* We don't need the error string anymore. */ + free (result->errstring); + } /* Reset the error indicator. */ - free (last_errstring); - last_errstring = NULL; - return ret; + result->errstring = NULL; + + return buf; } int _dlerror_run (void (*operate) (void *), void *args) { - if (last_errstring != NULL) + __libc_once_define (static, once); + struct dl_action_result *result; + + /* If we have not yet initialized the buffer do it now. */ + __libc_once (once, init); + + /* Get error string and number. */ + if (static_buf != NULL) + result = static_buf; + else + { + /* We don't use the static buffer and so we have a key. Use it + to get the thread-specific buffer. */ + result = __libc_getspecific (key); + if (result == NULL) + { + result = (struct dl_action_result *) calloc (1, sizeof (*result)); + if (result == NULL) + /* We are out of memory. Since this is no really critical + situation we carry on by using the global variable. + This might lead to conflicts between the threads but + they soon all will have memory problems. */ + result = &last_result; + else + /* Set the tsd. */ + __libc_setspecific (key, result); + } + } + + if (result->errstring != NULL) /* Free the error string from the last failed command. This can happen if `dlerror' was not run after an error was found. */ - free (last_errstring); + free (result->errstring); + + result->errcode = _dl_catch_error (&result->errstring, operate, args); + + return result->errstring != NULL; +} + - last_errcode = _dl_catch_error (&last_errstring, &last_object_name, - operate, args); - return last_errstring != NULL; +/* Initialize buffers for results. */ +static void +init (void) +{ + if (__libc_key_create (&key, free_key_mem)) + /* Creating the key failed. This means something really went + wrong. In any case use a static buffer which is better than + nothing. */ + static_buf = &last_result; +} + + +/* Free the thread specific data, this is done if a thread terminates. */ +static void +free_key_mem (void *mem) +{ + free (mem); + __libc_setspecific (key, NULL); } |