about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog13
-rw-r--r--elf/Makefile10
-rw-r--r--elf/dl-close.c19
-rw-r--r--elf/unload7.c39
-rw-r--r--elf/unload7mod1.c11
-rw-r--r--elf/unload7mod2.c1
6 files changed, 90 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index 9b2c359bb3..5520fce35d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2006-09-19  Ulrich Drepper  <drepper@redhat.com>
+
+	* elf/dl-close.c (_dl_close): If dependency is not unloaded make
+	sure no reference to the unloaded map's search list remains in the
+	dependency's scope.
+
+2006-09-16  Jakub Jelinek  <jakub@redhat.com>
+
+	* elf/Makefile: Add rules to build and run unload7 test.
+	* elf/unload7.c: New test.
+	* elf/unload7mod1.c: New file.
+	* elf/unload7mod2.c: New file.
+
 2006-09-18  Jakub Jelinek  <jakub@redhat.com>
 
 	* sysdeps/unix/sysv/linux/sys/ptrace.h (PT_GETEVENTMSG): Fix pasto.
diff --git a/elf/Makefile b/elf/Makefile
index 6f4b0260c0..b1a9bab022 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -87,6 +87,7 @@ distribute	:= rtld-Rules \
 		   unload3mod1.c unload3mod2.c unload3mod3.c unload3mod4.c \
 		   unload4mod1.c unload4mod2.c unload4mod3.c unload4mod4.c \
 		   unload6mod1.c unload6mod2.c unload6mod3.c \
+		   unload7mod1.c unload7mod2.c \
 		   tst-auditmod1.c tst-audit.sh \
 		   order2mod1.c order2mod2.c order2mod3.c order2mod4.c \
 		   tst-stackguard1.c tst-stackguard1-static.c \
@@ -168,7 +169,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
 	 tst-align tst-align2 $(tests-execstack-$(have-z-execstack)) \
 	 tst-dlmodcount tst-dlopenrpath tst-deep1 \
 	 tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
-	 unload3 unload4 unload5 unload6 tst-global1 order2 \
+	 unload3 unload4 unload5 unload6 unload7 tst-global1 order2 \
 	 tst-audit1 tst-audit2 \
 	 tst-stackguard1 tst-addr1
 #	 reldep9
@@ -211,6 +212,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
 		unload3mod1 unload3mod2 unload3mod3 unload3mod4 \
 		unload4mod1 unload4mod2 unload4mod3 unload4mod4 \
 		unload6mod1 unload6mod2 unload6mod3 \
+		unload7mod1 unload7mod2 \
 		order2mod1 order2mod2 order2mod3 order2mod4
 ifeq (yes,$(have-initfini-array))
 modules-names += tst-array2dep tst-array5dep
@@ -455,6 +457,8 @@ $(objpfx)unload4mod2.so: $(objpfx)unload4mod4.so $(objpfx)unload4mod3.so
 $(objpfx)unload6mod1.so: $(libdl)
 $(objpfx)unload6mod2.so: $(libdl)
 $(objpfx)unload6mod3.so: $(libdl)
+$(objpfx)unload7mod1.so: $(libdl)
+$(objpfx)unload7mod2.so: $(objpfx)unload7mod1.so
 
 LDFLAGS-tst-tlsmod5.so = -nostdlib
 LDFLAGS-tst-tlsmod6.so = -nostdlib
@@ -732,6 +736,10 @@ $(objpfx)unload6: $(libdl)
 $(objpfx)unload6.out: $(objpfx)unload6mod1.so $(objpfx)unload6mod2.so \
 		      $(objpfx)unload6mod3.so
 
+$(objpfx)unload7: $(libdl)
+$(objpfx)unload7.out: $(objpfx)unload7mod1.so $(objpfx)unload7mod2.so
+unload7-ENV = MALLOC_PERTURB_=85
+
 ifdef libdl
 $(objpfx)tst-tls9-static: $(common-objpfx)dlfcn/libdl.a
 $(objpfx)tst-tls9-static.out: $(objpfx)tst-tlsmod5.so $(objpfx)tst-tlsmod6.so
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 754dd678fe..6a2ad976a7 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -1,5 +1,5 @@
 /* Close a shared object opened by `_dl_open'.
-   Copyright (C) 1996-2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1996-2005, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -330,7 +330,7 @@ _dl_close (void *_map)
 
 	      for (cnt = 0; imap->l_scope[cnt] != NULL; ++cnt)
 		/* This relies on l_scope[] entries being always set either
-		   to its own l_symbolic_searchlist address, or some other map's
+		   to its own l_symbolic_searchlist address, or some map's
 		   l_searchlist address.  */
 		if (imap->l_scope[cnt] != &imap->l_symbolic_searchlist)
 		  {
@@ -347,6 +347,21 @@ _dl_close (void *_map)
 		      }
 		  }
 	    }
+	  else
+	    {
+	      unsigned int cnt = 0;
+	      while (imap->l_scope[cnt] != NULL)
+		{
+		  if (imap->l_scope[cnt] == &map->l_searchlist)
+		    {
+		      while ((imap->l_scope[cnt] = imap->l_scope[cnt + 1])
+			     != NULL)
+			++cnt;
+		      break;
+		    }
+		  ++cnt;
+		}
+	    }
 
 	  /* The loader is gone, so mark the object as not having one.
 	     Note: l_idx != -1 -> object will be removed.  */
diff --git a/elf/unload7.c b/elf/unload7.c
new file mode 100644
index 0000000000..198f7db286
--- /dev/null
+++ b/elf/unload7.c
@@ -0,0 +1,39 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+main (void)
+{
+  void *h = dlopen ("$ORIGIN/unload7mod1.so", RTLD_LAZY);
+  if (h == NULL)
+    {
+      puts ("dlopen unload7mod1.so failed");
+      return 1;
+    }
+
+  int (*fn) (void);
+  fn = dlsym (h, "foo");
+  if (fn == NULL)
+    {
+      puts ("dlsym failed");
+      return 1;
+    }
+
+  int ret = 0;
+  if (fn () == 0)
+    ++ret;
+
+  void *h2 = dlopen ("$ORIGIN/unload7mod2.so", RTLD_LAZY);
+  if (h2 == NULL)
+    {
+      puts ("dlopen unload7mod2.so failed");
+      return 1;
+    }
+  dlclose (h2);
+
+  if (fn () == 0)
+    ++ret;
+
+  dlclose (h);
+  return ret;
+}
diff --git a/elf/unload7mod1.c b/elf/unload7mod1.c
new file mode 100644
index 0000000000..7435adce2c
--- /dev/null
+++ b/elf/unload7mod1.c
@@ -0,0 +1,11 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+int
+foo (int i)
+{
+  if (dlsym (RTLD_DEFAULT, "unload7_nonexistent_symbol") == NULL)
+    return 1;
+  puts ("dlsym returned non-NULL");
+  return 0;
+}
diff --git a/elf/unload7mod2.c b/elf/unload7mod2.c
new file mode 100644
index 0000000000..6d1a0d47b7
--- /dev/null
+++ b/elf/unload7mod2.c
@@ -0,0 +1 @@
+int x;