This is the mail archive of the libc-alpha@sources.redhat.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Reference counting bug in ld-linux.so.2 (2.1.2, 2.1.3, 2.1.9x, et. al.)


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;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]