This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
[PATCH] fix dlclose() that does not unload all depended libraries
- From: GOTO Masanori <gotom at debian dot or dot jp>
- To: libc-alpha at sources dot redhat dot com
- Cc: GOTO Masanori <gotom at debian dot or dot jp>
- Date: Fri, 10 Sep 2004 00:50:07 +0900
- Subject: [PATCH] fix dlclose() that does not unload all depended libraries
This patch fixes dlclose() that does not unload all depended libraries
currently.
Test program attached in Bugzilla#77 is a sample program that executes
as follows:
(1) handle = dlopen("lib1").
(2) dlsym(handle, "func1"), func1 is in lib1.
(3) dlclose(handle).
(4) repeat (1), (2) and (3).
And lib1 calls lib2:func2, lib2:func2 calls lib3:func3, lib3:func3
calls lib4:func4. When you see /proc/<pid>/maps (on Linux), you find
that lib1, lib2, lib3 is successfully unloaded, but lib4 is not
unloaded between (3) and (4). Buzilla#77 attachment program has
static int counter, and it warns unload is failed (at (4)).
This patch fixes this problem. In dl-lookup.c:add_dependency called
from _dl_lookup_symbol, we bump up map->l_opencount if
map->l_searchlist.r_list is not NULL. But if map->l_searchlist.r_list
is NULL, we bump up l_opencount of all l_initfini maps:
if (__builtin_expect (act < undef_map->l_reldepsmax, 1))
undef_map->l_reldeps[undef_map->l_reldepsact++] = map;
if (map->l_searchlist.r_list != NULL)
/* And increment the counter in the referenced object. */
++map->l_opencount;
else
/* We have to bump the counts for all dependencies since so far
this object was only a normal or transitive dependency.
Now it might be closed with _dl_close() directly. */
for (list = map->l_initfini; *list != NULL; ++list)
++(*list)->l_opencount;
Inversely, we need to count down l_opencount in _dl_close() under the
condition to check whether l_searchlist.r_list is NULL or not when
l_reldepsact is > 0.
I think this patch fixes not only BZ#77, but also BZ#311.
Regards,
-- gotom
2004-09-09 GOTO Masanori <gotom@debian.or.jp>
[BZ #77]
* elf/dl-close.c: Count down l_opencount to check not only for
l_reldeps, but also l_initfini.
Index: elf/dl-close.c
===================================================================
RCS file: /cvs/glibc/libc/elf/dl-close.c,v
retrieving revision 1.104
diff -u -r1.104 dl-close.c
--- elf/dl-close.c 4 Aug 2004 21:45:38 -0000 1.104
+++ elf/dl-close.c 9 Sep 2004 04:06:46 -0000
@@ -197,17 +197,39 @@
unsigned int j;
for (j = 0; j < remmap->l_reldepsact; ++j)
{
+ struct link_map *depmap = remmap->l_reldeps[j];
+
/* Find out whether this object is in our list. */
- if (remmap->l_reldeps[j]->l_idx < nopencount
- && (list[remmap->l_reldeps[j]->l_idx]
- == remmap->l_reldeps[j]))
- /* Yes, it is. */
- if (--new_opencount[remmap->l_reldeps[j]->l_idx] == 0)
- {
- /* This one is now gone, too. */
- assert (remmap->l_reldeps[j]->l_type == lt_loaded);
- mark_removed (remmap->l_reldeps[j]);
- }
+ if (depmap->l_idx < nopencount
+ && (list[depmap->l_idx] == depmap))
+ {
+ /* Yes, it is. */
+ if (depmap->l_searchlist.r_list != NULL)
+ {
+ if (--new_opencount[depmap->l_idx] == 0)
+ {
+ /* This one is now gone, too. */
+ assert (depmap->l_type == lt_loaded);
+ mark_removed (depmap);
+ }
+ }
+ else
+ {
+ /* When it's NULL, we need to check all
+ dependencies for this object. */
+ struct link_map **ifmap;
+ for (ifmap = depmap->l_initfini;
+ *ifmap != NULL; ++ifmap)
+ {
+ if (--new_opencount[(*ifmap)->l_idx] == 0)
+ {
+ /* This one is now gone, too. */
+ assert ((*ifmap)->l_type == lt_loaded);
+ mark_removed (*ifmap);
+ }
+ }
+ }
+ }
}
}
}