From fa4a502e77ac60968bcdb153f0d698eed51a46d3 Mon Sep 17 00:00:00 2001 From: Alexander Kabaev Date: Mon, 17 Feb 2003 20:58:27 +0000 Subject: [PATCH] Do not remove object from the lists at the unref_dag() stage. Introduce a new unlink_object() function and call it in unload_object() instead. Removing the object in unref_dag() is too early, rtld calls _fini() function after that and shared objects might fail resolve their own symbols. --- libexec/rtld-elf/rtld.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 2334d1a7ed52..2016ce01e235 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -120,6 +120,7 @@ static const Elf_Sym *symlook_default(const char *, unsigned long hash, static const Elf_Sym *symlook_list(const char *, unsigned long, Objlist *, const Obj_Entry **, bool in_plt, DoneList *); static void trace_loaded_objects(Obj_Entry *obj); +static void unlink_object(Obj_Entry *); static void unload_object(Obj_Entry *); static void unref_dag(Obj_Entry *); @@ -2363,6 +2364,12 @@ unload_object(Obj_Entry *root) assert(root->refcount == 0); + /* + * Pass over the DAG removing unreferenced objects from + * appropriate lists. + */ + unlink_object(root); + /* Unmap all objects that are no longer referenced. */ linkp = &obj_list->next; while ((obj = *linkp) != NULL) { @@ -2380,19 +2387,12 @@ unload_object(Obj_Entry *root) } static void -unref_dag(Obj_Entry *root) +unlink_object(Obj_Entry *root) { const Needed_Entry *needed; Objlist_Entry *elm; - if (root->refcount == 0) - return; - root->refcount--; if (root->refcount == 0) { - for (needed = root->needed; needed != NULL; needed = needed->next) - if (needed->obj != NULL) - unref_dag(needed->obj); - /* Remove the object from the RTLD_GLOBAL list. */ objlist_remove(&list_global, root); @@ -2400,4 +2400,22 @@ unref_dag(Obj_Entry *root) STAILQ_FOREACH(elm, &root->dagmembers , link) objlist_remove(&elm->obj->dldags, root); } + + for (needed = root->needed; needed != NULL; needed = needed->next) + if (needed->obj != NULL) + unlink_object(needed->obj); +} + +static void +unref_dag(Obj_Entry *root) +{ + const Needed_Entry *needed; + + if (root->refcount == 0) + return; + root->refcount--; + if (root->refcount == 0) + for (needed = root->needed; needed != NULL; needed = needed->next) + if (needed->obj != NULL) + unref_dag(needed->obj); }