From 99d28cc0860e240357c02483f0c4016a6b30aad0 Mon Sep 17 00:00:00 2001 From: Carmelo Amoroso Date: Tue, 17 Jan 2012 18:23:43 +0100 Subject: libdl: fix dlclose handling of symbol scope Defer removal of the local scope of a dl-opened library after all the destructors (of itself and related dependencies) are actually get unloaded, otherwise any function registered via atexit() won't be resolved. Signed-off-by: Carmelo Amoroso Signed-off-by: Khem Raj Signed-off-by: Filippo Arcidiacono --- ldso/libdl/libdl.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'ldso/libdl') diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c index 32afe1c01..086a05932 100644 --- a/ldso/libdl/libdl.c +++ b/ldso/libdl/libdl.c @@ -781,7 +781,9 @@ static int do_dlclose(void *vhandle, int need_fini) struct dyn_elf *handle; unsigned int end = 0, start = 0xffffffff; unsigned int i, j; - struct r_scope_elem *ls; + struct r_scope_elem *ls, *ls_next = NULL; + struct elf_resolve **handle_rlist; + #if defined(USE_TLS) && USE_TLS bool any_tls = false; size_t tls_free_start = NO_TLS_OFFSET; @@ -814,6 +816,19 @@ static int do_dlclose(void *vhandle, int need_fini) free(handle); return 0; } + + /* Store the handle's local scope array for later removal */ + handle_rlist = handle->dyn->symbol_scope.r_list; + + /* Store references to the local scope entries for later removal */ + for (ls = &_dl_loaded_modules->symbol_scope; ls && ls->next; ls = ls->next) + if (ls->next->r_list[0] == handle->dyn) { + break; + } + /* ls points to the previous local symbol scope */ + if(ls && ls->next) + ls_next = ls->next->next; + /* OK, this is a valid handle - now close out the file */ for (j = 0; j < handle->init_fini.nlist; ++j) { tpnt = handle->init_fini.init_fini[j]; @@ -975,16 +990,6 @@ static int do_dlclose(void *vhandle, int need_fini) } } - if (handle->dyn == tpnt) { - /* Unlink the local scope from global one */ - for (ls = &_dl_loaded_modules->symbol_scope; ls; ls = ls->next) - if (ls->next->r_list[0] == tpnt) { - _dl_if_debug_print("removing symbol_scope: %s\n", tpnt->libname); - break; - } - ls->next = ls->next->next; - } - /* Next, remove tpnt from the global symbol table list */ if (_dl_symbol_tables) { if (_dl_symbol_tables->dyn == tpnt) { @@ -1006,10 +1011,14 @@ static int do_dlclose(void *vhandle, int need_fini) } } free(tpnt->libname); - free(tpnt->symbol_scope.r_list); free(tpnt); } } + /* Unlink and release the handle's local scope from global one */ + if(ls) + ls->next = ls_next; + free(handle_rlist); + for (rpnt1 = handle->next; rpnt1; rpnt1 = rpnt1_tmp) { rpnt1_tmp = rpnt1->next; free(rpnt1); -- cgit v1.2.3