mirror of
git://sourceware.org/git/glibc.git
synced 2025-04-12 14:21:18 +08:00
2005-04-26 Jakub Jelinek <jakub@redhat.com>
[BZ #1081] * 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.
This commit is contained in:
parent
32c4e3d07b
commit
d85f197097
11
elf/Makefile
11
elf/Makefile
@ -86,6 +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 \
|
||||
unload6mod1.c unload6mod2.c unload6mod3.c \
|
||||
order2mod1.c order2mod2.c order2mod3.c order2mod4.c
|
||||
|
||||
CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables
|
||||
@ -158,7 +159,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
|
||||
tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 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-global1 order2
|
||||
unload3 unload4 unload5 unload6 tst-global1 order2
|
||||
# reldep9
|
||||
test-srcs = tst-pathopt
|
||||
tests-vis-yes = vismain
|
||||
@ -196,6 +197,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
|
||||
tst-dlmopen1mod \
|
||||
unload3mod1 unload3mod2 unload3mod3 unload3mod4 \
|
||||
unload4mod1 unload4mod2 unload4mod3 unload4mod4 \
|
||||
unload6mod1 unload6mod2 unload6mod3 \
|
||||
order2mod1 order2mod2 order2mod3 order2mod4
|
||||
ifeq (yes,$(have-initfini-array))
|
||||
modules-names += tst-array2dep
|
||||
@ -433,6 +435,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
|
||||
@ -701,6 +706,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
|
||||
|
@ -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>
|
||||
@ -105,9 +106,6 @@ _dl_close (void *_map)
|
||||
struct link_map *map = _map;
|
||||
unsigned int i;
|
||||
Lmid_t ns = map->l_ns;
|
||||
#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)
|
||||
@ -124,9 +122,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))
|
||||
GLRO(dl_debug_printf) ("\nclosing file=%s; direct_opencount == %u\n",
|
||||
@ -136,12 +142,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)
|
||||
@ -278,7 +290,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
|
||||
@ -294,15 +306,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;
|
||||
|
||||
@ -514,8 +538,12 @@ _dl_close (void *_map)
|
||||
_r_debug.r_state = RT_CONSISTENT;
|
||||
GLRO(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));
|
||||
}
|
||||
libc_hidden_def (_dl_close)
|
||||
@ -586,7 +614,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);
|
||||
|
30
elf/unload6.c
Normal file
30
elf/unload6.c
Normal file
@ -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
elf/unload6mod1.c
Normal file
16
elf/unload6mod1.c
Normal file
@ -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
elf/unload6mod2.c
Normal file
23
elf/unload6mod2.c
Normal file
@ -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
elf/unload6mod3.c
Normal file
23
elf/unload6mod3.c
Normal file
@ -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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user