[git commit] libdl: fix dlclose handling of symbol scope

Khem Raj raj.khem at gmail.com
Tue Jan 24 00:21:18 UTC 2012


commit: http://git.uclibc.org/uClibc/commit/?id=99d28cc0860e240357c02483f0c4016a6b30aad0
branch: http://git.uclibc.org/uClibc/commit/?id=refs/heads/master

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 <carmelo.amoroso at st.com>
Signed-off-by: Khem Raj <raj.khem at gmail.com>
Signed-off-by: Filippo Arcidiacono <filippo.arcidiacono at st.com>
---
 ldso/libdl/libdl.c |   33 +++++++++++++++++++++------------
 1 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c
index 32afe1c..086a059 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);


More information about the uClibc-cvs mailing list