about summary refs log tree commit diff
path: root/elf/dl-close.c
diff options
context:
space:
mode:
Diffstat (limited to 'elf/dl-close.c')
-rw-r--r--elf/dl-close.c127
1 files changed, 87 insertions, 40 deletions
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 7e4626e3d6..0953fab210 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-2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1996-2002, 2003 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
@@ -138,7 +138,7 @@ _dl_close (void *_map)
 	_dl_debug_printf ("\nclosing file=%s; opencount == %u\n",
 			  map->l_name, map->l_opencount);
 
-      /* One decrement the object itself, not the dependencies.  */
+      /* Decrement the object's reference counter, not the dependencies'.  */
       --map->l_opencount;
 
       __rtld_lock_unlock_recursive (GL(dl_load_lock));
@@ -165,7 +165,7 @@ _dl_close (void *_map)
     }
   --new_opencount[0];
   for (i = 1; list[i] != NULL; ++i)
-    if ((! (list[i]->l_flags_1 & DF_1_NODELETE) || ! list[i]->l_init_called)
+    if ((list[i]->l_flags_1 & DF_1_NODELETE) == 0
 	/* Decrement counter.  */
 	&& --new_opencount[i] == 0)
       {
@@ -185,7 +185,10 @@ _dl_close (void *_map)
 		{
 		  assert (dep_list[j]->l_idx < map->l_searchlist.r_nlist);
 		  if (--new_opencount[dep_list[j]->l_idx] == 0)
-		    mark_removed (dep_list[j]);
+		    {
+		      assert (dep_list[j]->l_type == lt_loaded);
+		      mark_removed (dep_list[j]);
+		    }
 		}
 	      }
 
@@ -200,8 +203,11 @@ _dl_close (void *_map)
 			    == remmap->l_reldeps[j]))
 		      /* Yes, it is.  */
 		      if (--new_opencount[remmap->l_reldeps[j]->l_idx] == 0)
-			/* This one is now gone, too.  */
-			mark_removed (remmap->l_reldeps[j]);
+			{
+			  /* This one is now gone, too.  */
+			  assert (remmap->l_reldeps[j]->l_type == lt_loaded);
+			  mark_removed (remmap->l_reldeps[j]);
+			}
 		  }
 	      }
 	  }
@@ -215,57 +221,98 @@ _dl_close (void *_map)
     {
       struct link_map *imap = list[i];
       if (new_opencount[i] == 0 && imap->l_type == lt_loaded
-	  && (imap->l_info[DT_FINI] || imap->l_info[DT_FINI_ARRAY])
-	  && (! (imap->l_flags_1 & DF_1_NODELETE) || ! imap->l_init_called)
-	  /* Skip any half-cooked objects that were never initialized.  */
-	  && imap->l_init_called)
+	  && (imap->l_flags_1 & DF_1_NODELETE) == 0)
 	{
 	  /* When debugging print a message first.  */
 	  if (__builtin_expect (GL(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
 	    _dl_debug_printf ("\ncalling fini: %s\n\n", imap->l_name);
 
-	  /* Call its termination function.  */
-	  if (imap->l_info[DT_FINI_ARRAY] != NULL)
+	  /* Call its termination function.  Do not do it for
+	     half-cooked objects.  */
+	  if (imap->l_init_called)
 	    {
-	      ElfW(Addr) *array =
-		(ElfW(Addr) *) (imap->l_addr
-				+ imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
-	      unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
-				 / sizeof (ElfW(Addr)));
-	      unsigned int cnt;
-
-	      for (cnt = 0; cnt < sz; ++cnt)
-		((fini_t) (imap->l_addr + array[cnt])) ();
+	      if (imap->l_info[DT_FINI_ARRAY] != NULL)
+		{
+		  ElfW(Addr) *array =
+		    (ElfW(Addr) *) (imap->l_addr
+				    + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
+		  unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
+				     / sizeof (ElfW(Addr)));
+		  unsigned int cnt;
+
+		  for (cnt = 0; cnt < sz; ++cnt)
+		    ((fini_t) (imap->l_addr + array[cnt])) ();
+		}
+
+	      /* Next try the old-style destructor.  */
+	      if (imap->l_info[DT_FINI] != NULL)
+		(*(void (*) (void)) DL_DT_FINI_ADDRESS
+		 (imap, ((void *) imap->l_addr
+			 + imap->l_info[DT_FINI]->d_un.d_ptr))) ();
 	    }
 
-	  /* Next try the old-style destructor.  */
-	  if (imap->l_info[DT_FINI] != NULL)
-	    (*(void (*) (void)) DL_DT_FINI_ADDRESS
-	      (imap, (void *) imap->l_addr
-		     + imap->l_info[DT_FINI]->d_un.d_ptr)) ();
+	  /* This object must not be used anymore.  We must remove the
+	     reference from the scope.  */
+	  unsigned int j;
+	  struct link_map **searchlist = map->l_searchlist.r_list;
+	  unsigned int nsearchlist = map->l_searchlist.r_nlist;
+
+#ifndef NDEBUG
+	  bool found = false;
+#endif
+	  for (j = 0; j < nsearchlist; ++j)
+	    if (imap == searchlist[j])
+	      {
+		/* This is the object to remove.  Copy all the
+		   following ones.  */
+		while (++j < nsearchlist)
+		  searchlist[j - 1] = searchlist[j];
+
+		searchlist[j - 1] = NULL;
+
+		--map->l_searchlist.r_nlist;
+
+#ifndef NDEBUG
+		found = true;
+#endif
+		break;
+	      }
+	  assert (found);
 	}
-      else if (new_opencount[i] != 0 && imap->l_type == lt_loaded)
+      else if (new_opencount[i] != 0 && imap->l_type == lt_loaded
+	       && imap->l_searchlist.r_list == NULL
+	       && imap->l_initfini != NULL)
 	{
-	  /* The object is still used.  But the object we are unloading
-	     right now is responsible for loading it and therefore we
-	     have the search list of the current object in its scope.
-	     Remove it.  */
-	  struct r_scope_elem **runp = imap->l_scope;
-
-	  while (*runp != NULL)
-	    if (*runp == &map->l_searchlist)
+	  /* The object is still used.  But the object we are
+	     unloading right now is responsible for loading it.  If
+	     the current object does not have it's own scope yet we
+	     have to create one.  This has to be done before running
+	     the finalizers.
+
+	     To do this count the number of dependencies.  */
+	  unsigned int cnt;
+	  for (cnt = 1; imap->l_initfini[cnt] != NULL; ++cnt)
+	    if (imap->l_initfini[cnt]->l_idx >= i
+		&& imap->l_initfini[cnt]->l_idx < nopencount)
+	      ++new_opencount[imap->l_initfini[cnt]->l_idx];
+	    else
+	      ++imap->l_initfini[cnt]->l_opencount;
+
+	  /* We simply reuse the l_initfini list.  */
+	  imap->l_searchlist.r_list = &imap->l_initfini[cnt + 1];
+	  imap->l_searchlist.r_nlist = cnt;
+
+	  for (cnt = 0; imap->l_scope[cnt] != NULL; ++cnt)
+	    if (imap->l_scope[cnt] = &map->l_searchlist)
 	      {
-		/* Copy all later elements.  */
-		while ((runp[0] = runp[1]) != NULL)
-		  ++runp;
+		imap->l_scope[cnt] = &imap->l_searchlist;
 		break;
 	      }
-	    else
-	      ++runp;
 	}
 
       /* Store the new l_opencount value.  */
       imap->l_opencount = new_opencount[i];
+
       /* Just a sanity check.  */
       assert (imap->l_type == lt_loaded || imap->l_opencount > 0);
     }