Update.
authorUlrich Drepper <drepper@redhat.com>
Sun, 31 Dec 2000 06:09:08 +0000 (06:09 +0000)
committerUlrich Drepper <drepper@redhat.com>
Sun, 31 Dec 2000 06:09:08 +0000 (06:09 +0000)
2000-12-30  Ulrich Drepper  <drepper@redhat.com>

* elf/dl-close.c (_dl_close): We can ignore the NODELETE flag if the
object was not yet initialized.

2000-12-28  H.J. Lu  <hjl@gnu.org>

* elf/dl-deps.c (_dl_map_object_deps): Make sure the DSO state
is always consistent even if its dependency is failed.

* elf/dl-open.c (_dl_open): Increment the open count before
calling _dl_close () in case of failure.

* elf/neededtest4.c: New file.
* elf/neededobj5.c: New file.
* elf/neededobj6.c: New file.

* elf/Makefile (distribute): Add neededobj5.c and neededobj6.c.
(tests): Add neededtest4.
(modules-names): Add neededobj5 and neededobj6.
($(objpfx)neededobj6.so): New target.
($(objpfx)neededtest4): New target.
($(objpfx)neededtest4.out): New target.

ChangeLog
elf/Makefile
elf/dl-close.c
elf/dl-deps.c
elf/dl-open.c
elf/neededobj5.c [new file with mode: 0644]
elf/neededobj6.c [new file with mode: 0644]
elf/neededtest4.c [new file with mode: 0644]

index 5a7d023..241e38b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2000-12-30  Ulrich Drepper  <drepper@redhat.com>
+
+       * elf/dl-close.c (_dl_close): We can ignore the NODELETE flag if the
+       object was not yet initialized.
+
+2000-12-28  H.J. Lu  <hjl@gnu.org>
+
+       * elf/dl-deps.c (_dl_map_object_deps): Make sure the DSO state
+       is always consistent even if its dependency is failed.
+
+       * elf/dl-open.c (_dl_open): Increment the open count before
+       calling _dl_close () in case of failure.
+
+       * elf/neededtest4.c: New file.
+       * elf/neededobj5.c: New file.
+       * elf/neededobj6.c: New file.
+
+       * elf/Makefile (distribute): Add neededobj5.c and neededobj6.c.
+       (tests): Add neededtest4.
+       (modules-names): Add neededobj5 and neededobj6.
+       ($(objpfx)neededobj6.so): New target.
+       ($(objpfx)neededtest4): New target.
+       ($(objpfx)neededtest4.out): New target.
+
 2000-12-28  Joseph S. Myers  <jsm28@cam.ac.uk>
 
        * misc/sys/cdefs.h (__attribute_format_strfmon__): Define.
index 6359f22..459d986 100644 (file)
@@ -55,6 +55,7 @@ distribute    := $(rtld-routines:=.c) dynamic-link.h do-rel.h dl-machine.h \
                   reldepmod1.c reldepmod2.c reldepmod3.c reldepmod4.c \
                   nextmod1.c nextmod2.c pathoptobj.c tst-pathopt.sh \
                   neededobj1.c neededobj2.c neededobj3.c neededobj4.c \
+                  neededobj5.c neededobj6.c \
                   unload2mod.c unload2dep.c ltglobmod1.c ltglobmod2.c \
                   testobj.h vismod.h
 
@@ -100,7 +101,7 @@ tests = loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
        constload1 order $(tests-vis-$(have-protected)) noload filter unload \
        reldep reldep2 reldep3 next $(tests-nodelete-$(have-z-nodelete)) \
        $(tests-nodlopen-$(have-z-nodlopen)) neededtest neededtest2 \
-       neededtest3 unload2 lateglobal
+       neededtest3 neededtest4 unload2 lateglobal
 test-srcs = tst-pathopt
 tests-vis-yes = vismain
 tests-nodelete-yes = nodelete
@@ -113,6 +114,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
                $(modules-nodlopen-$(have-z-nodlopen)) filtmod1 filtmod2 \
                reldepmod1 reldepmod2 reldepmod3 reldepmod4 nextmod1 nextmod2 \
                neededobj1 neededobj2 neededobj3 neededobj4 \
+               neededobj5 neededobj6 \
                unload2mod unload2dep ltglobmod1 ltglobmod2 pathoptobj
 modules-vis-yes = vismod1 vismod2 vismod3
 modules-nodelete-yes = nodelmod1 nodelmod2 nodelmod3 nodelmod4
@@ -263,6 +265,7 @@ $(objpfx)neededobj2.so: $(objpfx)neededobj1.so $(libdl)
 $(objpfx)neededobj3.so: $(objpfx)neededobj1.so $(objpfx)neededobj2.so $(libdl)
 $(objpfx)neededobj4.so: $(objpfx)neededobj1.so $(objpfx)neededobj2.so \
                        $(objpfx)neededobj3.so $(libdl)
+$(objpfx)neededobj6.so: $(objpfx)neededobj5.so
 $(objpfx)unload2mod.so: $(objpfx)unload2dep.so
 $(objpfx)ltglobmod2.so: $(libdl)
 
@@ -287,6 +290,10 @@ $(objpfx)neededtest3: $(libdl)
 $(objpfx)neededtest3.out: $(objpfx)neededobj1.so $(objpfx)neededobj2.so \
                          $(objpfx)neededobj3.so $(objpfx)neededobj4.so
 
+neededtest4-ENV = LC_ALL=C LANGUAGE=C
+$(objpfx)neededtest4: $(libdl) $(objpfx)neededobj1.so
+$(objpfx)neededtest4.out: $(objpfx)neededobj5.so $(objpfx)neededobj6.so
+
 $(objpfx)restest1: $(objpfx)testobj1.so $(objpfx)testobj1_1.so $(libdl)
 LDFLAGS-restest1 = -rdynamic
 
index 6c17593..cd4e44e 100644 (file)
@@ -55,7 +55,7 @@ _dl_close (void *_map)
   unsigned int *new_opencount;
 
   /* First see whether we can remove the object at all.  */
-  if (map->l_flags_1 & DF_1_NODELETE)
+  if ((map->l_flags_1 & DF_1_NODELETE) && map->l_init_called)
     /* Nope.  Do nothing.  */
     return;
 
@@ -101,7 +101,7 @@ _dl_close (void *_map)
     }
   --new_opencount[0];
   for (i = 1; list[i] != NULL; ++i)
-    if (! (list[i]->l_flags_1 & DF_1_NODELETE)
+    if ((! (list[i]->l_flags_1 & DF_1_NODELETE) || ! list[i]->l_init_called)
        /* Decrement counter.  */
        && --new_opencount[i] == 0
        /* Test whether this object was also loaded directly.  */
@@ -113,7 +113,8 @@ _dl_close (void *_map)
        struct link_map **dep_list = list[i]->l_searchlist.r_list;
 
        for (j = 1; j < list[i]->l_searchlist.r_nlist; ++j)
-         if (! (dep_list[j]->l_flags_1 & DF_1_NODELETE))
+         if (! (dep_list[j]->l_flags_1 & DF_1_NODELETE)
+             || ! dep_list[j]->l_init_called)
            {
              assert (dep_list[j]->l_idx < map->l_searchlist.r_nlist);
              --new_opencount[dep_list[j]->l_idx];
@@ -127,7 +128,7 @@ _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_flags_1 & DF_1_NODELETE) || ! imap->l_init_called)
          /* Skip any half-cooked objects that were never initialized.  */
          && imap->l_init_called)
        {
index df1db89..d723981 100644 (file)
@@ -141,6 +141,10 @@ _dl_map_object_deps (struct link_map *map,
   struct list known[1 + npreloads + 1];
   struct list *runp, *utail, *dtail;
   unsigned int nlist, nduplist, i;
+  /* Object name.  */
+  const char *name;
+  int errno_saved;
+  int errno_reason;
 
   auto inline void preload (struct link_map *map);
 
@@ -192,6 +196,10 @@ _dl_map_object_deps (struct link_map *map,
      The whole process is complicated by the fact that we better
      should use alloca for the temporary list elements.  But using
      alloca means we cannot use recursive function calls.  */
+  errno_saved = errno;
+  errno_reason = 0;
+  errno = 0;
+  name = NULL;
   for (runp = known; runp; )
     {
       struct link_map *l = runp->map;
@@ -227,15 +235,24 @@ _dl_map_object_deps (struct link_map *map,
                struct link_map *dep;
                /* Allocate new entry.  */
                struct list *newp;
-               /* Object name.  */
-               const char *name;
+               const char *objname;
+               const char *errstring;
 
                /* Recognize DSTs.  */
                name = expand_dst (l, strtab + d->d_un.d_val, 0);
+               /* Store the tag in the argument structure.  */
+               args.name = name;
 
-               dep = _dl_map_object (l, name, 0,
-                                     l->l_type == lt_executable ? lt_library :
-                                     l->l_type, trace_mode, 0);
+               if (_dl_catch_error (&objname, &errstring, openaux, &args))
+                 {
+                   if (errno)
+                     errno_reason = errno;
+                   else
+                     errno_reason = -1;
+                   goto out;
+                 }
+               else
+                 dep = args.aux;
 
                /* Add it in any case to the duplicate list.  */
                newp = alloca (sizeof (struct list));
@@ -266,18 +283,15 @@ _dl_map_object_deps (struct link_map *map,
                const char *objname;
                const char *errstring;
                struct list *newp;
-               /* Object name.  */
-               const char *name;
 
                /* Recognize DSTs.  */
                name = expand_dst (l, strtab + d->d_un.d_val,
                                   d->d_tag == DT_AUXILIARY);
+               /* Store the tag in the argument structure.  */
+               args.name = name;
 
                if (d->d_tag == DT_AUXILIARY)
                  {
-                   /* Store the tag in the argument structure.  */
-                   args.name = name;
-
                    /* Say that we are about to load an auxiliary library.  */
                    if (__builtin_expect (_dl_debug_libs, 0))
                      _dl_debug_message (1, "load auxiliary object=",
@@ -310,10 +324,14 @@ _dl_map_object_deps (struct link_map *map,
                                         "\n", NULL);
 
                    /* For filter objects the dependency must be available.  */
-                   args.aux = _dl_map_object (l, name, 0,
-                                              (l->l_type == lt_executable
-                                               ? lt_library : l->l_type),
-                                              trace_mode, 0);
+                   if (_dl_catch_error (&objname, &errstring, openaux, &args))
+                     {
+                       if (errno)
+                         errno_reason = errno;
+                       else
+                         errno_reason = -1;
+                       goto out;
+                     }
                  }
 
                /* The auxiliary object is actually available.
@@ -460,6 +478,10 @@ _dl_map_object_deps (struct link_map *map,
        while (runp != NULL && runp->done);
     }
 
+out:
+  if (errno == 0 && errno_saved != 0)
+    __set_errno (errno_saved);
+
   if (map->l_initfini != NULL && map->l_type == lt_loaded)
     {
       /* This object was previously loaded as a dependency and we have
@@ -558,4 +580,8 @@ _dl_map_object_deps (struct link_map *map,
     }
   /* Terminate the list of dependencies.  */
   map->l_initfini[nlist] = NULL;
+
+  if (errno_reason)
+    _dl_signal_error (errno_reason == -1 ? 0 : errno_reason,
+                     name ?: "", N_("cannot load shared object file"));
 }
index 931e226..d1ccfd4 100644 (file)
@@ -396,7 +396,17 @@ _dl_open (const char *file, int mode, const void *caller)
       /* Remove the object from memory.  It may be in an inconsistent
         state if relocation failed, for example.  */
       if (args.map)
-       _dl_close (args.map);
+       {
+         int i;
+
+         /* Increment open counters for all objects which did not get
+            correctly loaded.  */
+         for (i = 0; i < args.map->l_searchlist.r_nlist; ++i)
+           if (args.map->l_searchlist.r_list[i]->l_opencount == 0)
+             args.map->l_searchlist.r_list[i]->l_opencount = 1;
+
+         _dl_close (args.map);
+       }
 
       /* Make a local copy of the error string so that we can release the
         memory allocated for it.  */
diff --git a/elf/neededobj5.c b/elf/neededobj5.c
new file mode 100644 (file)
index 0000000..2d629b0
--- /dev/null
@@ -0,0 +1,5 @@
+extern void a1_function (void);
+
+void a1_function (void)
+{
+}
diff --git a/elf/neededobj6.c b/elf/neededobj6.c
new file mode 100644 (file)
index 0000000..639b6f1
--- /dev/null
@@ -0,0 +1,7 @@
+extern void a1_function (void);
+extern void a2_function (void);
+
+void a2_function (void)
+{
+  a1_function ();
+}
diff --git a/elf/neededtest4.c b/elf/neededtest4.c
new file mode 100644 (file)
index 0000000..04ab10e
--- /dev/null
@@ -0,0 +1,156 @@
+#include <dlfcn.h>
+#include <libintl.h>
+#include <link.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int
+check_loaded_objects (const char **loaded)
+{
+  struct link_map *lm;
+  int n;
+  int *found = NULL;
+  int errors = 0;
+
+  for (n = 0; loaded[n]; n++)
+    /* NOTHING */;
+
+  if (n)
+    {
+      found = (int *) alloca (sizeof (int) * n);
+      memset (found, 0, sizeof (int) * n);
+    }
+
+  printf("   Name\n");
+  printf(" --------------------------------------------------------\n");
+  for (lm = _r_debug.r_map; lm; lm = lm->l_next)
+    {
+      if (lm->l_name && lm->l_name[0])
+       printf(" %s, count = %d\n", lm->l_name, (int) lm->l_opencount);
+      if (lm->l_type == lt_loaded && lm->l_name)
+       {
+         int match = 0;
+         for (n = 0; loaded[n] != NULL; n++)
+           {
+             if (strcmp (basename (loaded[n]), basename (lm->l_name)) == 0)
+               {
+                 found[n] = 1;
+                 match = 1;
+                 break;
+               }
+           }
+
+         if (match == 0)
+           {
+             ++errors;
+             printf ("ERRORS: %s is not unloaded\n", lm->l_name);
+           }
+       }
+    }
+
+  for (n = 0; loaded[n] != NULL; n++)
+    {
+      if (found[n] == 0)
+        {
+         ++errors;
+         printf ("ERRORS: %s is not loaded\n", loaded[n]);
+       }
+    }
+
+  return errors;
+}
+
+extern void c_function (void);
+extern char *dirname (__const char *__filename);
+
+int
+main (int argc, char **argv)
+{
+  void *obj;
+  const char *loaded[] = { NULL, NULL, NULL};
+  int errors = 0;
+  void (*f) (void);
+  const char *dir = dirname (argv [0]);
+  char *oldfilename;
+  char *newfilename;
+
+  c_function ();
+
+  printf ("\nThis is what is in memory now:\n");
+  errors += check_loaded_objects (loaded);
+
+  printf( "Loading shared object neededobj6.so\n");
+  obj = dlopen( "neededobj6.so", RTLD_LAZY);
+  if (obj == NULL)
+    {
+      printf ("%s\n", dlerror ());
+      exit (1);
+    }
+  f = dlsym (obj, "a2_function");
+  if (f == NULL)
+    {
+      printf ("%s\n", dlerror ());
+      exit (1);
+    }
+  f ();
+  loaded[0] = "neededobj5.so";
+  loaded[1] = "neededobj6.so";
+  errors += check_loaded_objects (loaded);
+
+  printf ("Closing neededobj6.so\n");
+  dlclose (obj);
+  loaded[0] = NULL;
+  errors += check_loaded_objects (loaded);
+
+  printf ("Rename neededobj5.so\n");
+  oldfilename = alloca (strlen (dir) + 1 + sizeof ("neededobj5.so"));
+  strcpy (oldfilename, dir);
+  strcat (oldfilename, "/");
+  strcat (oldfilename, "neededobj5.so");
+  newfilename = alloca (strlen (oldfilename) + sizeof (".renamed"));
+  strcpy (newfilename, oldfilename);
+  strcat (newfilename, ".renamed");
+  if (rename (oldfilename, newfilename))
+    {
+      perror ("rename");
+      exit (1);
+    }
+
+  printf( "Loading shared object neededobj6.so\n");
+  obj = dlopen( "neededobj6.so", RTLD_LAZY);
+  if (obj == NULL)
+    printf ("%s\n", dlerror ());
+  else
+    {
+      printf ("neededobj6.so should fail to load\n");
+      exit (1);
+    }
+
+  printf( "Loading shared object neededobj1.so\n");
+  obj = dlopen( "neededobj1.so", RTLD_LAZY);
+  if (obj == NULL)
+    {
+      printf ("%s\n", dlerror ());
+      exit (1);
+    }
+  errors += check_loaded_objects (loaded);
+  f = dlsym (obj, "c_function");
+  if (f == NULL)
+    {
+      printf ("%s\n", dlerror ());
+      exit (1);
+    }
+  f ();
+
+  printf ("Restore neededobj5.so\n");
+  if (rename (newfilename, oldfilename))
+    {
+      perror ("rename");
+      exit (1);
+    }
+
+  if (errors != 0)
+    printf ("%d errors found\n", errors);
+  return errors;
+}