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]
Other format: [Raw text]

[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);
+				  }
+			      }
+			  }
+		      }
 		  }
 	      }
 	  }


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