Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
* elf/dl-close.c: Include stddef.h.
	(_dl_close): If called recursively, just remember GC needs to be rerun
	and decrease l_direct_opencount.  Avoid GC if l_direct_opencount
	decreased to 1.  Rerun GC at the end if any destructor unloaded some
	additional libraries.
	* elf/Makefile: Add rules to build and run unload6 test.
	* elf/unload6.c: New test.
	* elf/unload6mod1.c: New file.
	* elf/unload6mod2.c: New file.
	* elf/unload6mod3.c: New file.

	* malloc/hooks.c (mem2chunk_check): Add magic_p argument, set *magic_p
	if magic_p is not NULL.
	(top_check): Invoke MALLOC_FAILURE_ACTION if MORECORE failed.
	(malloc_check): Fail if sz == -1.
	(free_check): Adjust mem2chunk_check caller.
	(realloc_check): Likewise.  Fail if bytes == -1.  If bytes == 0 and
	oldmem != NULL, call free_check and return NULL.  If reallocating
	and returning NULL, invert magic byte again to make oldmem valid
	region for further checking.
	(memalign_check): Fail if bytes == -1.
	* malloc/Makefile: Add rules to build and run tst-mcheck.
	* malloc/tst-mcheck.c: New test.
  • Loading branch information
Ulrich Drepper committed Apr 27, 2005
1 parent 462be69 commit bfc832c
Show file tree
Hide file tree
Showing 10 changed files with 302 additions and 26 deletions.
26 changes: 26 additions & 0 deletions ChangeLog
@@ -1,3 +1,29 @@
2005-04-26 Jakub Jelinek <jakub@redhat.com>

* elf/dl-close.c: Include stddef.h.
(_dl_close): If called recursively, just remember GC needs to be rerun
and decrease l_direct_opencount. Avoid GC if l_direct_opencount
decreased to 1. Rerun GC at the end if any destructor unloaded some
additional libraries.
* elf/Makefile: Add rules to build and run unload6 test.
* elf/unload6.c: New test.
* elf/unload6mod1.c: New file.
* elf/unload6mod2.c: New file.
* elf/unload6mod3.c: New file.

* malloc/hooks.c (mem2chunk_check): Add magic_p argument, set *magic_p
if magic_p is not NULL.
(top_check): Invoke MALLOC_FAILURE_ACTION if MORECORE failed.
(malloc_check): Fail if sz == -1.
(free_check): Adjust mem2chunk_check caller.
(realloc_check): Likewise. Fail if bytes == -1. If bytes == 0 and
oldmem != NULL, call free_check and return NULL. If reallocating
and returning NULL, invert magic byte again to make oldmem valid
region for further checking.
(memalign_check): Fail if bytes == -1.
* malloc/Makefile: Add rules to build and run tst-mcheck.
* malloc/tst-mcheck.c: New test.

2005-04-26 Ulrich Drepper <drepper@redhat.com>

* stdio-common/vfscanf.c: Correctly account for characters of
Expand Down
12 changes: 10 additions & 2 deletions elf/Makefile
Expand Up @@ -86,7 +86,7 @@ distribute := rtld-Rules \
tst-deep1mod1.c tst-deep1mod2.c tst-deep1mod3.c \
unload3mod1.c unload3mod2.c unload3mod3.c unload3mod4.c \
unload4mod1.c unload4mod2.c unload4mod3.c unload4mod4.c \
tst-auditmod1.c \
unload6mod1.c unload6mod2.c unload6mod3.c tst-auditmod1.c \
order2mod1.c order2mod2.c order2mod3.c order2mod4.c

CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables
Expand Down Expand Up @@ -162,7 +162,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 tst-align \
tst-align2 $(tests-execstack-$(have-z-execstack)) tst-dlmodcount \
tst-dlopenrpath tst-deep1 tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
unload3 unload4 unload5 tst-audit1 tst-global1 order2
unload3 unload4 unload5 unload6 tst-audit1 tst-global1 order2
# reldep9
test-srcs = tst-pathopt
tests-vis-yes = vismain
Expand Down Expand Up @@ -201,6 +201,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
tst-dlmopen1mod tst-auditmod1 \
unload3mod1 unload3mod2 unload3mod3 unload3mod4 \
unload4mod1 unload4mod2 unload4mod3 unload4mod4 \
unload6mod1 unload6mod2 unload6mod3 \
order2mod1 order2mod2 order2mod3 order2mod4
ifeq (yes,$(have-initfini-array))
modules-names += tst-array2dep
Expand Down Expand Up @@ -438,6 +439,9 @@ $(objpfx)unload3mod2.so: $(objpfx)unload3mod3.so
$(objpfx)unload3mod3.so: $(objpfx)unload3mod4.so
$(objpfx)unload4mod1.so: $(objpfx)unload4mod2.so $(objpfx)unload4mod3.so
$(objpfx)unload4mod2.so: $(objpfx)unload4mod4.so $(objpfx)unload4mod3.so
$(objpfx)unload6mod1.so: $(libdl)
$(objpfx)unload6mod2.so: $(libdl)
$(objpfx)unload6mod3.so: $(libdl)

LDFLAGS-tst-tlsmod5.so = -nostdlib
LDFLAGS-tst-tlsmod6.so = -nostdlib
Expand Down Expand Up @@ -710,6 +714,10 @@ $(objpfx)unload5: $(libdl)
$(objpfx)unload5.out: $(objpfx)unload3mod1.so $(objpfx)unload3mod2.so \
$(objpfx)unload3mod3.so $(objpfx)unload3mod4.so

$(objpfx)unload6: $(libdl)
$(objpfx)unload6.out: $(objpfx)unload6mod1.so $(objpfx)unload6mod2.so \
$(objpfx)unload6mod3.so

ifdef libdl
$(objpfx)tst-tls9-static: $(common-objpfx)dlfcn/libdl.a
$(objpfx)tst-tls9-static.out: $(objpfx)tst-tlsmod5.so $(objpfx)tst-tlsmod6.so
Expand Down
55 changes: 41 additions & 14 deletions elf/dl-close.c
Expand Up @@ -20,6 +20,7 @@
#include <assert.h>
#include <dlfcn.h>
#include <libintl.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -105,10 +106,6 @@ _dl_close (void *_map)
struct link_map *map = _map;
Lmid_t ns = map->l_ns;
unsigned int i;
#ifdef USE_TLS
bool any_tls = false;
#endif

/* First see whether we can remove the object at all. */
if (__builtin_expect (map->l_flags_1 & DF_1_NODELETE, 0)
&& map->l_init_called)
Expand All @@ -124,9 +121,17 @@ _dl_close (void *_map)
/* One less direct use. */
--map->l_direct_opencount;

/* Decrement the reference count. */
if (map->l_direct_opencount > 1 || map->l_type != lt_loaded)
/* If _dl_close is called recursively (some destructor call dlclose),
just record that the parent _dl_close will need to do garbage collection
again and return. */
static enum { not_pending, pending, rerun } dl_close_state;

if (map->l_direct_opencount > 0 || map->l_type != lt_loaded
|| dl_close_state != not_pending)
{
if (map->l_direct_opencount == 0 && map->l_type == lt_loaded)
dl_close_state = rerun;

/* There are still references to this object. Do nothing more. */
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
_dl_debug_printf ("\nclosing file=%s; direct_opencount=%u\n",
Expand All @@ -136,12 +141,18 @@ _dl_close (void *_map)
return;
}

retry:
dl_close_state = pending;

#ifdef USE_TLS
bool any_tls = false;
#endif
const unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
char used[nloaded];
char done[nloaded];
struct link_map *maps[nloaded];

/* Run over the list and assign indeces to the link maps and enter
/* Run over the list and assign indexes to the link maps and enter
them into the MAPS array. */
int idx = 0;
for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
Expand Down Expand Up @@ -302,7 +313,7 @@ _dl_close (void *_map)
if (imap->l_searchlist.r_list == NULL
&& imap->l_initfini != NULL)
{
/* The object is still used. But the object we are
/* The object is still used. But one of the objects we are
unloading right now is responsible for loading it. If
the current object does not have it's own scope yet we
have to create one. This has to be done before running
Expand All @@ -318,15 +329,27 @@ _dl_close (void *_map)
imap->l_searchlist.r_nlist = cnt;

for (cnt = 0; imap->l_scope[cnt] != NULL; ++cnt)
if (imap->l_scope[cnt] == &map->l_searchlist)
/* This relies on l_scope[] entries being always set either
to its own l_symbolic_searchlist address, or some other map's
l_searchlist address. */
if (imap->l_scope[cnt] != &imap->l_symbolic_searchlist)
{
imap->l_scope[cnt] = &imap->l_searchlist;
break;
struct link_map *tmap;

tmap = (struct link_map *) ((char *) imap->l_scope[cnt]
- offsetof (struct link_map,
l_searchlist));
assert (tmap->l_ns == ns);
if (tmap->l_idx != -1)
{
imap->l_scope[cnt] = &imap->l_searchlist;
break;
}
}
}

/* The loader is gone, so mark the object as not having one.
Note: l_idx == -1 -> object will be removed. */
Note: l_idx != -1 -> object will be removed. */
if (imap->l_loader != NULL && imap->l_loader->l_idx != -1)
imap->l_loader = NULL;

Expand Down Expand Up @@ -583,8 +606,12 @@ _dl_close (void *_map)
r->r_state = RT_CONSISTENT;
_dl_debug_state ();

/* Release the lock. */
/* Recheck if we need to retry, release the lock. */
out:
if (dl_close_state == rerun)
goto retry;

dl_close_state = not_pending;
__rtld_lock_unlock_recursive (GL(dl_load_lock));
}

Expand Down Expand Up @@ -654,7 +681,7 @@ libc_freeres_fn (free_mem)
free_slotinfo (&GL(dl_tls_dtv_slotinfo_list));
else
# endif
/* The first element of the list does not have to be deallocated.
/* The first element of the list does not have to be deallocated.
It was allocated in the dynamic linker (i.e., with a different
malloc), and in the static library it's in .bss space. */
free_slotinfo (&GL(dl_tls_dtv_slotinfo_list)->next);
Expand Down
30 changes: 30 additions & 0 deletions elf/unload6.c
@@ -0,0 +1,30 @@
#include <dlfcn.h>
#include <stdio.h>

int
main (void)
{
void *h = dlopen ("unload6mod1.so", RTLD_LAZY);
if (h == NULL)
{
puts ("dlopen unload6mod1.so failed");
return 1;
}

int (*fn) (int);
fn = dlsym (h, "foo");
if (fn == NULL)
{
puts ("dlsym failed");
return 1;
}

int val = fn (16);
if (val != 24)
{
printf ("foo returned %d != 24\n", val);
return 1;
}

return 0;
}
16 changes: 16 additions & 0 deletions elf/unload6mod1.c
@@ -0,0 +1,16 @@
#include <dlfcn.h>
#include <stdio.h>

int
foo (int i)
{
void *h = dlopen ("unload6mod2.so", RTLD_LAZY);
if (h == NULL)
{
puts ("dlopen unload6mod2.so failed");
return 1;
}

dlclose (h);
return i + 8;
}
23 changes: 23 additions & 0 deletions elf/unload6mod2.c
@@ -0,0 +1,23 @@
#include <dlfcn.h>
#include <stdio.h>
#include <unistd.h>

static void *h;

static void __attribute__((constructor))
mod2init (void)
{
h = dlopen ("unload6mod3.so", RTLD_LAZY);
if (h == NULL)
{
puts ("dlopen unload6mod3.so failed");
fflush (stdout);
_exit (1);
}
}

static void __attribute__((destructor))
mod2fini (void)
{
dlclose (h);
}
23 changes: 23 additions & 0 deletions elf/unload6mod3.c
@@ -0,0 +1,23 @@
#include <dlfcn.h>
#include <stdio.h>
#include <unistd.h>

static void *h;

static void __attribute__((constructor))
mod3init (void)
{
h = dlopen ("unload6mod1.so", RTLD_LAZY);
if (h == NULL)
{
puts ("dlopen unload6mod1.so failed");
fflush (stdout);
_exit (1);
}
}

static void __attribute__((destructor))
mod3fini (void)
{
dlclose (h);
}
7 changes: 5 additions & 2 deletions malloc/Makefile
@@ -1,4 +1,5 @@
# Copyright (C) 1991-1999,2000,2001,2002,2003 Free Software Foundation, Inc.
# Copyright (C) 1991-1999, 2000, 2001, 2002, 2003, 2005
# 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
Expand Down Expand Up @@ -26,7 +27,7 @@ all:
dist-headers := malloc.h
headers := $(dist-headers) obstack.h mcheck.h
tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
tst-mallocstate
tst-mallocstate tst-mcheck
test-srcs = tst-mtrace

distribute = thread-m.h mtrace.pl mcheck-init.c stackinfo.h memusage.h \
Expand Down Expand Up @@ -120,6 +121,8 @@ endif
endif
endif

tst-mcheck-ENV = MALLOC_CHECK_=3

# Uncomment this for test releases. For public releases it is too expensive.
#CPPFLAGS-malloc.o += -DMALLOC_DEBUG=1

Expand Down

0 comments on commit bfc832c

Please sign in to comment.