summaryrefslogtreecommitdiff
path: root/ldso
diff options
context:
space:
mode:
authorLeonid Lisovskiy <lly.dev@gmail.com>2016-06-20 20:29:45 +0300
committerWaldemar Brodkorb <wbx@uclibc-ng.org>2016-06-22 08:02:51 +0200
commitbc5949fd4f8cddf4eee74492c86a8a72f4dee0e7 (patch)
tree68cf04f3eade770ecd41bfb782bc5e9f51acbe94 /ldso
parent0bc1394750885d4e4b2064aff6c48dd542c6f4b8 (diff)
ldso: fix dlsym hang when reloading DSOs
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 <lly.dev@gmail.com>
Diffstat (limited to 'ldso')
-rw-r--r--ldso/ldso/dl-elf.c2
-rw-r--r--ldso/libdl/libdl.c4
2 files changed, 4 insertions, 2 deletions
diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c
index 8f71aeb05..a046aeb74 100644
--- a/ldso/ldso/dl-elf.c
+++ b/ldso/ldso/dl-elf.c
@@ -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
diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c
index 489c78759..0cf3b7037 100644
--- a/ldso/libdl/libdl.c
+++ b/ldso/libdl/libdl.c
@@ -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