This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
Re: Reference counting bug in ld-linux.so.2 (2.1.2, 2.1.3, 2.1.9x, et. al.)
- To: Allen Bauer <kylix_rd at borland dot com>
- Subject: Re: Reference counting bug in ld-linux.so.2 (2.1.2, 2.1.3, 2.1.9x, et. al.)
- From: "H . J . Lu" <hjl at lucon dot org>
- Date: Wed, 18 Oct 2000 21:16:21 -0700
- Cc: libc-alpha at sources dot redhat dot com
- References: <OE31bBYcVx7dATNd1Dg00001c3d@hotmail.com>
On Wed, Oct 18, 2000 at 04:25:32PM -0700, Allen Bauer wrote:
> Hello,
>
> My name is Allen Bauer, and I am one of the senior developers for the Kylix
> project here at Borland. I have come across what I think is a serious flaw
> in how the dynamic loader handles references to shared objects. Attached is
> a simple test case that demonstrates the problem. Basically the scenario is
> this:
>
> Executable dynamically loads lib-a.so which requires lib-b.so and lib-c.so.
> lib-b.so also requires lib-c.so. Then the executable dynamically loads
> lib-b.so. Later, it decides to unload lib-b.so, then finally unloads
> lib-a.so. This will cause lib-c.so to be left in memory with a lone
> reference count of 1. This can lead to all sorts of interesting behaviours
> later when other shared objects (or even these same ones) get re-loaded. I
> have had the lazy-binding system fail miserably.
>
Thanks for your testcase. This patch seems to work for me.
H.J.
----
2000-10-18 H.J. Lu <hjl@gnu.org>
* elf/dl-close.c (_dl_close): Decrement l_opencount for DSOs on
the l_initfini list if l_opencount on the DSO to be closed > 1.
Index: elf/dl-close.c
===================================================================
RCS file: /work/cvs/gnu/glibc/elf/dl-close.c,v
retrieving revision 1.1.1.10
diff -u -p -r1.1.1.10 dl-close.c
--- elf/dl-close.c 2000/10/08 23:01:33 1.1.1.10
+++ elf/dl-close.c 2000/10/19 04:01:11
@@ -61,6 +61,9 @@ _dl_close (void *_map)
/* Acquire the lock. */
__libc_lock_lock (_dl_load_lock);
+ list = map->l_searchlist.r_list;
+ nsearchlist = map->l_searchlist.r_nlist;
+
/* Decrement the reference count. */
if (map->l_opencount > 1 || map->l_type != lt_loaded)
{
@@ -78,13 +81,21 @@ _dl_close (void *_map)
"\n", NULL);
}
+ /* Even if we don't unload it now, we still need to decrement
+ l_opencount on l_initfini. Otherwise, they may not get
+ unloaded later. */
+ for (i = 0; i < nsearchlist; ++i)
+ {
+ struct link_map *imap = map->l_initfini[i];
+ if (imap != map && imap->l_opencount > 1
+ && imap->l_type == lt_loaded)
+ imap->l_opencount--;
+ }
+
--map->l_opencount;
__libc_lock_unlock (_dl_load_lock);
return;
}
-
- list = map->l_searchlist.r_list;
- nsearchlist = map->l_searchlist.r_nlist;
rellist = map->l_reldeps;
nrellist = map->l_reldepsact;