2000-08-19  Ulrich Drepper  <drepper@redhat.com>

	* elf/Versions [ld] (GLIBC_2.2): Export _dl_check_map_versions.
	* elf/dl-deps.c (_dl_map_object_deps): If object was dependency of
	a dynamically loaded object remove old l_initfini list.
	* elf/dl-libc.c (free_mem): Used as __libc_subfreeres callback to
	remove some dynamically allocated memory blocks in the dynamic
	loading data structures.
	* elf/dl-load.c (add_name_to_object): Initialize dont_free to 0.
	* elf/dl-open.c (dl_open_workder): Don't call _dl_check_all_versions.
	Instead call _dl_check_map_versions only for the dependencies.
	* elf/rtld.c: Avoid unneccessary initializations.  Mark l_libname
	information of initial objects as not free-able.
	* sysdeps/generic/ldsodefs.h (struct libname_list): Add dont_free
	element.

	* elf/filter.c: Call mtrace.
	* elf/restest1.c: Likewise.  Close the objects.
	* elf/loadtest.c: Call mtrace.  Check result of dlclose.  Print more
	debug information.

	* elf/constload1.c: Add comment explaining not freed memory.
This commit is contained in:
Ulrich Drepper 2000-08-19 07:17:09 +00:00
parent 003715fa0d
commit 752a2a50d4
11 changed files with 122 additions and 11 deletions

View File

@ -1,3 +1,26 @@
2000-08-19 Ulrich Drepper <drepper@redhat.com>
* elf/Versions [ld] (GLIBC_2.2): Export _dl_check_map_versions.
* elf/dl-deps.c (_dl_map_object_deps): If object was dependency of
a dynamically loaded object remove old l_initfini list.
* elf/dl-libc.c (free_mem): Used as __libc_subfreeres callback to
remove some dynamically allocated memory blocks in the dynamic
loading data structures.
* elf/dl-load.c (add_name_to_object): Initialize dont_free to 0.
* elf/dl-open.c (dl_open_workder): Don't call _dl_check_all_versions.
Instead call _dl_check_map_versions only for the dependencies.
* elf/rtld.c: Avoid unneccessary initializations. Mark l_libname
information of initial objects as not free-able.
* sysdeps/generic/ldsodefs.h (struct libname_list): Add dont_free
element.
* elf/filter.c: Call mtrace.
* elf/restest1.c: Likewise. Close the objects.
* elf/loadtest.c: Call mtrace. Check result of dlclose. Print more
debug information.
* elf/constload1.c: Add comment explaining not freed memory.
2000-08-18 Andreas Jaeger <aj@suse.de> 2000-08-18 Andreas Jaeger <aj@suse.de>
* sysdeps/unix/sysv/linux/mips/bits/stat.h: Add pads to show * sysdeps/unix/sysv/linux/mips/bits/stat.h: Add pads to show

View File

@ -18,6 +18,10 @@ main (void)
error (EXIT_FAILURE, errno, "cannot load module \"constload2.so\""); error (EXIT_FAILURE, errno, "cannot load module \"constload2.so\"");
foo = dlsym (h, "foo"); foo = dlsym (h, "foo");
ret = foo (); ret = foo ();
/* Note that the following dlclose() call cannot unload the objects.
Due to the introduced relocation dependency constload2.so depends
on constload3.so and the dependencies of constload2.so on constload3.so
is not visible to ld.so since it's done using dlopen(). */
if (dlclose (h) != 0) if (dlclose (h) != 0)
{ {
puts ("failed to close"); puts ("failed to close");

View File

@ -467,6 +467,14 @@ _dl_map_object_deps (struct link_map *map,
while (runp != NULL && runp->done); while (runp != NULL && runp->done);
} }
if (map->l_initfini != NULL && map->l_type == lt_loaded)
{
/* This object was previously loaded as a dependency and we have
a separate l_initfini list. We don't need it anymore. */
assert (map->l_searchlist.r_list == NULL);
free (map->l_initfini);
}
/* Store the search list we built in the object. It will be used for /* Store the search list we built in the object. It will be used for
searches in the scope of this object. */ searches in the scope of this object. */
map->l_searchlist.r_list = malloc ((2 * nlist + 1 map->l_searchlist.r_list = malloc ((2 * nlist + 1

View File

@ -120,3 +120,27 @@ __libc_dlclose (void *__map)
{ {
return dlerror_run (do_dlclose, __map); return dlerror_run (do_dlclose, __map);
} }
static void
free_mem (void)
{
struct link_map *l;
/* Remove all additional names added to the objects. */
for (l = _dl_loaded; l != NULL; l = l->l_next)
{
struct libname_list *lnp = l->l_libname->next;
l->l_libname->next = NULL;
while (lnp != NULL)
{
struct libname_list *old = lnp;
lnp = lnp->next;
if (! old->dont_free)
free (old);
}
}
}
text_set_element (__libc_subfreeres, free_mem);

View File

@ -322,6 +322,7 @@ add_name_to_object (struct link_map *l, const char *name)
newname->name = memcpy (newname + 1, name, name_len); newname->name = memcpy (newname + 1, name, name_len);
newname->next = NULL; newname->next = NULL;
newname->dont_free = 0;
lastp->next = newname; lastp->next = newname;
} }

View File

@ -88,6 +88,7 @@ dl_open_worker (void *a)
struct link_map *new, *l; struct link_map *new, *l;
const char *dst; const char *dst;
int lazy; int lazy;
unsigned int i;
/* Maybe we have to expand a DST. */ /* Maybe we have to expand a DST. */
dst = strchr (file, '$'); dst = strchr (file, '$');
@ -163,7 +164,9 @@ dl_open_worker (void *a)
_dl_map_object_deps (new, NULL, 0, 0); _dl_map_object_deps (new, NULL, 0, 0);
/* So far, so good. Now check the versions. */ /* So far, so good. Now check the versions. */
(void) _dl_check_all_versions (new, 0, 0); for (i = 0; i < new->l_searchlist.r_nlist; ++i)
if (new->l_searchlist.r_list[i]->l_versions == NULL)
(void) _dl_check_map_versions (new->l_searchlist.r_list[i], 0, 0);
#ifdef SCOPE_DEBUG #ifdef SCOPE_DEBUG
show_scope (new); show_scope (new);

View File

@ -1,3 +1,4 @@
#include <mcheck.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -6,7 +7,11 @@ extern const char *foo (void);
int int
main (void) main (void)
{ {
const char *s = foo (); const char *s;
mtrace ();
s = foo ();
printf ("called `foo' from `%s'\n", s); printf ("called `foo' from `%s'\n", s);

View File

@ -2,6 +2,7 @@
#include <dlfcn.h> #include <dlfcn.h>
#include <errno.h> #include <errno.h>
#include <error.h> #include <error.h>
#include <mcheck.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -66,10 +67,16 @@ static const struct
#define NTESTS (sizeof (tests) / sizeof (tests[0])) #define NTESTS (sizeof (tests) / sizeof (tests[0]))
#include <include/link.h>
int int
main (void) main (void)
{ {
int count = TEST_ROUNDS; int count = TEST_ROUNDS;
int result = 0;
mtrace ();
/* Just a seed. */ /* Just a seed. */
srandom (TEST_ROUNDS); srandom (TEST_ROUNDS);
@ -102,23 +109,38 @@ main (void)
fct (10); fct (10);
printf ("successfully loaded `%s'\n", testobjs[index].name); printf ("successfully loaded `%s', handle %p\n",
testobjs[index].name, testobjs[index].handle);
} }
else else
{ {
dlclose (testobjs[index].handle); if (dlclose (testobjs[index].handle) != 0)
testobjs[index].handle = NULL; {
printf ("failed to close %s\n", testobjs[index].name);
result = 1;
}
else
printf ("successfully unloaded `%s', handle %p\n",
testobjs[index].name, testobjs[index].handle);
printf ("successfully unloaded `%s'\n", testobjs[index].name); testobjs[index].handle = NULL;
} }
} }
/* Unload all loaded modules. */ /* Unload all loaded modules. */
for (count = 0; count < NOBJS; ++count) for (count = 0; count < NOBJS; ++count)
if (testobjs[count].handle != NULL) if (testobjs[count].handle != NULL)
dlclose (testobjs[count].handle); { printf ("\nclose: %s: l_initfini = %p, l_versions = %p\n",
testobjs[count].name,
((struct link_map*)testobjs[count].handle)->l_initfini,
((struct link_map*)testobjs[count].handle)->l_versions);
if (dlclose (testobjs[count].handle) != 0)
{
printf ("failed to close %s\n", testobjs[count].name);
result = 1;
} }
return 0; return result;
} }

View File

@ -1,5 +1,6 @@
#include <dlfcn.h> #include <dlfcn.h>
#include <error.h> #include <error.h>
#include <mcheck.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -13,6 +14,8 @@ main (void)
int res1; int res1;
int res2; int res2;
mtrace ();
h1 = dlopen ("testobj1.so", RTLD_LAZY); h1 = dlopen ("testobj1.so", RTLD_LAZY);
if (h1 == NULL) if (h1 == NULL)
error (EXIT_FAILURE, 0, "while loading `%s': %s", "testobj1.so", error (EXIT_FAILURE, 0, "while loading `%s': %s", "testobj1.so",
@ -37,6 +40,11 @@ main (void)
res2 = fp2 (10); res2 = fp2 (10);
printf ("fp1(10) = %d\nfp2(10) = %d\n", res1, res2); printf ("fp1(10) = %d\nfp2(10) = %d\n", res1, res2);
if (dlclose (h1) != 0)
error (EXIT_FAILURE, 0, "cannot close testobj1.so: %s\n", dlerror ());
if (dlclose (h2) != 0)
error (EXIT_FAILURE, 0, "cannot close testobj1_1.so: %s\n", dlerror ());
return res1 != 42 || res2 != 72; return res1 != 42 || res2 != 72;
} }

View File

@ -590,7 +590,7 @@ of this helper program; chances are you did not intend to run this program.\n\
the shared object is already loaded. */ the shared object is already loaded. */
_dl_rtld_libname.name = ((const char *) _dl_loaded->l_addr _dl_rtld_libname.name = ((const char *) _dl_loaded->l_addr
+ ph->p_vaddr); + ph->p_vaddr);
_dl_rtld_libname.next = NULL; /* _dl_rtld_libname.next = NULL; Already zero. */
_dl_rtld_map.l_libname = &_dl_rtld_libname; _dl_rtld_map.l_libname = &_dl_rtld_libname;
/* Ordinarilly, we would get additional names for the loader from /* Ordinarilly, we would get additional names for the loader from
@ -604,7 +604,7 @@ of this helper program; chances are you did not intend to run this program.\n\
if (p) if (p)
{ {
_dl_rtld_libname2.name = p+1; _dl_rtld_libname2.name = p+1;
_dl_rtld_libname2.next = NULL; /* _dl_rtld_libname2.next = NULL; Already zero. */
_dl_rtld_libname.next = &_dl_rtld_libname2; _dl_rtld_libname.next = &_dl_rtld_libname2;
} }
} }
@ -626,7 +626,7 @@ of this helper program; chances are you did not intend to run this program.\n\
/* We were invoked directly, so the program might not have a /* We were invoked directly, so the program might not have a
PT_INTERP. */ PT_INTERP. */
_dl_rtld_libname.name = _dl_rtld_map.l_name; _dl_rtld_libname.name = _dl_rtld_map.l_name;
_dl_rtld_libname.next = NULL; /* _dl_rtld_libname.next = NULL; Alread zero. */
_dl_rtld_map.l_libname = &_dl_rtld_libname; _dl_rtld_map.l_libname = &_dl_rtld_libname;
} }
else else
@ -1059,6 +1059,17 @@ of this helper program; chances are you did not intend to run this program.\n\
HP_TIMING_NOW (start); HP_TIMING_NOW (start);
do do
{ {
/* While we are at it, help the memory handling a bit. We have to
mark some data structures as allocated with the fake malloc()
implementation in ld.so. */
struct libname_list *lnp = l->l_libname->next;
while (__builtin_expect (lnp != NULL, 0))
{
lnp->dont_free = 1;
lnp = lnp->next;
}
if (l != &_dl_rtld_map) if (l != &_dl_rtld_map)
_dl_relocate_object (l, l->l_scope, _dl_lazy, consider_profiling); _dl_relocate_object (l, l->l_scope, _dl_lazy, consider_profiling);

View File

@ -115,6 +115,8 @@ struct libname_list
{ {
const char *name; /* Name requested (before search). */ const char *name; /* Name requested (before search). */
struct libname_list *next; /* Link to next name for this object. */ struct libname_list *next; /* Link to next name for this object. */
int dont_free; /* Flag whether this element should be freed
if the object is not entirely unloaded. */
}; };