diff options
author | kan <kan@FreeBSD.org> | 2003-02-17 20:58:27 +0000 |
---|---|---|
committer | kan <kan@FreeBSD.org> | 2003-02-17 20:58:27 +0000 |
commit | 80e27851f2afb65a95c749d65636a67daacc2309 (patch) | |
tree | 2be8922e0921c62fdc256eb4d01ed4b4933d73e9 /libexec | |
parent | dc964efac4183176c7acdacdf11a046259cb7feb (diff) | |
download | FreeBSD-src-80e27851f2afb65a95c749d65636a67daacc2309.zip FreeBSD-src-80e27851f2afb65a95c749d65636a67daacc2309.tar.gz |
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.
Diffstat (limited to 'libexec')
-rw-r--r-- | libexec/rtld-elf/rtld.c | 34 |
1 files changed, 26 insertions, 8 deletions
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 2334d1a..2016ce0 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); } |