This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
Re: A ld.so bug
- To: GNU C Library <libc-alpha at sourceware dot cygnus dot com>
- Subject: Re: A ld.so bug
- From: "H . J . Lu" <hjl at lucon dot org>
- Date: Fri, 4 May 2001 22:45:29 -0700
- References: <20010504163630.A5485@lucon.org>
On Fri, May 04, 2001 at 04:36:30PM -0700, H . J . Lu wrote:
> # gcc d.c -ldl -D_GNU_SOURCE
> # a.out
> zsh: 5484 segmentation fault ./a.out
>
> The problem is _dl_signal_error is called with (xxx, NULL, xxx) in
> quite a few places. But _dl_signal_error does strlen (objname) without
> checking if objname is NULL.
>
> BTW, there is anther problem. I don't think _dlerror_run can use
> calloc for error reporting. I got a testcase with
>
# cc -o d d.c -ldl
# ./d
zsh: 5238 segmentation fault ./d
Here is a patch and a testcase.
H.J.
-----
2001-05-04 H.J. Lu <hjl@gnu.org>
* elf/dl-error.c (catch): Add 2 new fields, fatal and errcode.
(_dl_signal_error): Check if objname is NULL and prepare for
malloc failure.
(_dl_catch_error): Copy the "fatal" field from the old catch to
the new one.
--- libc/elf/dl-error.c.fatal Tue Feb 27 22:22:09 2001
+++ libc/elf/dl-error.c Fri May 4 22:26:59 2001
@@ -31,6 +31,8 @@ struct catch
{
const char *objname; /* Object/File name. */
const char *errstring; /* Error detail filled in here. */
+ int fatal; /* If any error is fatal. */
+ int errcode; /* The old error code. */
jmp_buf env; /* longjmp here on error. */
};
@@ -71,29 +73,55 @@ _dl_signal_error (int errcode, const cha
errstring = N_("DYNAMIC LINKER BUG!!!");
lcatch = tsd_getspecific ();
- if (lcatch != NULL)
+ if (lcatch != NULL && lcatch->fatal == 0)
{
/* 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;
+ size_t len_objname;
+ size_t len_errstring;
+ struct catch new_catch;
+
+ if (objname == NULL)
+ objname = _dl_argv[0] ?: "<main program>";
+
+ len_objname = strlen (objname) + 1;
+ len_errstring = strlen (errstring) + 1;
+
+ /* We have to prepare for any possible errors. */
+ new_catch.errstring = errstring;
+ new_catch.objname = objname;
+ new_catch.errcode = errcode;
+ new_catch.fatal = 1;
- lcatch->errstring = (char *) malloc (len_objname + len_errstring);
- if (lcatch->errstring != NULL)
- /* Make a copy of the object file name and the error string. */
- lcatch->objname = memcpy (__mempcpy ((char *) lcatch->errstring,
- errstring, len_errstring),
- objname, len_objname);
- else
+ errcode = setjmp (new_catch.env);
+ if (__builtin_expect (errcode, 0) == 0)
{
- /* This is better than nothing. */
- lcatch->objname = "";
- lcatch->errstring = _dl_out_of_memory;
+ tsd_setspecific (&new_catch);
+ lcatch->errstring = (char *) malloc (len_objname
+ + len_errstring);
+ if (lcatch->errstring != NULL)
+ /* Make a copy of the object file name and the error
+ string. */
+ lcatch->objname = memcpy (__mempcpy ((char *) lcatch->errstring,
+ errstring,
+ len_errstring),
+ objname, len_objname);
+ else
+ {
+ /* This is better than nothing. */
+ lcatch->objname = "";
+ lcatch->errstring = _dl_out_of_memory;
+ }
+ tsd_setspecific (lcatch);
+ longjmp (lcatch->env, errcode ?: -1);
}
- longjmp (lcatch->env, errcode ?: -1);
+ /* When we get here via longjmp, something must be worng. */
+ tsd_setspecific (lcatch);
+ objname = new_catch.objname;
+ errstring = new_catch.errstring;
+ errcode = new_catch.errcode;
}
- else
{
/* Lossage while resolving the program's own symbols is always fatal. */
char buffer[1024];
@@ -143,6 +171,8 @@ _dl_catch_error (const char **objname, c
c.errstring = NULL;
old = tsd_getspecific ();
+ c.fatal = old ? old->fatal : 0;
+
errcode = setjmp (c.env);
if (__builtin_expect (errcode, 0) == 0)
{
------
#undef _GNU_SOURCE
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
void *
malloc(size_t len)
{
void *(*mallocp) (size_t);
mallocp = (void *(*) (size_t)) dlsym (RTLD_NEXT, "malloc");
if (mallocp == NULL)
{
printf ("%s\n", dlerror ());
exit (1);
}
return (*mallocp)(len);
}
int
main(void)
{
void* ptr;
ptr = malloc(10);
free(ptr);
return 0;
}