]> Git Repo - uclibc-ng.git/commitdiff
ldso: fix dlsym hang when reloading DSOs
authorLeonid Lisovskiy <[email protected]>
Mon, 20 Jun 2016 17:29:45 +0000 (20:29 +0300)
committerWaldemar Brodkorb <[email protected]>
Wed, 22 Jun 2016 06:02:51 +0000 (08:02 +0200)
It can happen under certain cases that the DSO had refcount 0,
but was already loaded. (NODELETE flag is set, or it is pulled
in via both NEEDED dependency and explicit dlopen()).

Add extra reference count for NODELETE objects, this will
ensure that the reference count never drops below one.

It is improved version of
 http://lists.busybox.net/pipermail/uclibc/2013-June/047826.html

Signed-off-by: Leonid Lisovskiy <[email protected]>
ldso/ldso/dl-elf.c
ldso/libdl/libdl.c
test/dlopen/Makefile.in
test/dlopen/nodelete1.c [new file with mode: 0644]

index 8f71aeb055a666bda98adf648647dddbf5087706..a046aeb748bfebd264c5ac0e9df0b834a26396a9 100644 (file)
@@ -884,6 +884,8 @@ struct elf_resolve *_dl_load_elf_shared_library(unsigned int rflags,
 #endif
        (*rpnt)->dyn = tpnt;
        tpnt->usage_count++;
+       if (tpnt->rtld_flags & RTLD_NODELETE)
+               tpnt->usage_count++;
 #ifdef __LDSO_STANDALONE_SUPPORT__
        tpnt->libtype = (epnt->e_type == ET_DYN) ? elf_lib : elf_executable;
 #else
index 489c78759022da6b1b861b1fa8639c22f1407cc7..0cf3b7037ed5dd73714372675d536dd155e36a5b 100644 (file)
@@ -818,7 +818,7 @@ static int do_dlclose(void *vhandle, int need_fini)
                _dl_handles = rpnt->next_handle;
        _dl_if_debug_print("%s: usage count: %d\n",
                        handle->dyn->libname, handle->dyn->usage_count);
-       if (handle->dyn->usage_count != 1 || (handle->dyn->rtld_flags & RTLD_NODELETE)) {
+       if (handle->dyn->usage_count != 1) {
                handle->dyn->usage_count--;
                free(handle);
                return 0;
@@ -840,7 +840,7 @@ static int do_dlclose(void *vhandle, int need_fini)
        for (j = 0; j < handle->init_fini.nlist; ++j) {
                tpnt = handle->init_fini.init_fini[j];
                tpnt->usage_count--;
-               if (tpnt->usage_count == 0 && !(tpnt->rtld_flags & RTLD_NODELETE)) {
+               if (tpnt->usage_count == 0) {
                        if ((tpnt->dynamic_info[DT_FINI]
                             || tpnt->dynamic_info[DT_FINI_ARRAY])
                         && need_fini
index 0bed0f7491e43678035599b3d1050f7ddeb95750..740453a19388293b3bc90e47fc6be93a9876496a 100644 (file)
@@ -5,7 +5,7 @@
 export UCLIBC_ONLY := 1
 
 TESTS := dltest dltest2 dlstatic test1 test2 test3 dlundef dlafk dladdr \
-       testscope nodelete tst-origin
+       testscope nodelete nodelete1 tst-origin
 
 ifneq ($(HAVE_SHARED),y)
 TESTS_DISABLED := test3
@@ -80,3 +80,5 @@ LDFLAGS_nodelete := -rdynamic -ldl
 LDFLAGS_nodelmod1.so := -Wl,-z,nodelete
 LDFLAGS_nodelmod3.so := ./nodelmod4.so
 LDFLAGS_nodelmod4.so := -Wl,-z,nodelete
+nodelete1: nodelmod1.so nodelmod2.so
+LDFLAGS_nodelete1 := -rdynamic -ldl
diff --git a/test/dlopen/nodelete1.c b/test/dlopen/nodelete1.c
new file mode 100644 (file)
index 0000000..720e37f
--- /dev/null
@@ -0,0 +1,59 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+int fini_ran;
+
+#define LIBNAME1       "nodelmod1.so"
+
+static int
+do_test (void)
+{
+  /* Verify ability to reload RTLD_NODELETE libraries.
+   */
+  void *p;
+
+  p = dlopen (LIBNAME1, RTLD_NOW);
+  if (p == NULL)
+  {
+      printf ("failed to load "LIBNAME1": %s\n", dlerror ());
+      exit (1);
+  }
+
+  if (dlclose (p) != 0)
+  {
+      puts ("failed to close "LIBNAME1"");
+      exit (1);
+  }
+
+  p = dlopen (LIBNAME1, RTLD_LAZY);
+  if (p == NULL)
+  {
+      printf ("failed to load "LIBNAME1": %s\n", dlerror ());
+      exit (1);
+  }
+
+  if (dlclose (p) != 0)
+  {
+      puts ("failed to close "LIBNAME1"");
+      exit (1);
+  }
+
+  p = dlopen ("nodelmod2.so", RTLD_LAZY);
+  if (p == NULL)
+  {
+      printf ("failed to load \"nodelmod2.so\": %s\n", dlerror ());
+      exit (1);
+  }
+  if (dlclose (p) != 0)
+  {
+      puts ("failed to close \"nodelmod2.so\"");
+      exit (1);
+  }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
This page took 0.038278 seconds and 4 git commands to generate.