summaryrefslogtreecommitdiffstats
path: root/libexec
diff options
context:
space:
mode:
authorkan <kan@FreeBSD.org>2003-02-17 20:58:27 +0000
committerkan <kan@FreeBSD.org>2003-02-17 20:58:27 +0000
commit80e27851f2afb65a95c749d65636a67daacc2309 (patch)
tree2be8922e0921c62fdc256eb4d01ed4b4933d73e9 /libexec
parentdc964efac4183176c7acdacdf11a046259cb7feb (diff)
downloadFreeBSD-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.c34
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);
}
OpenPOWER on IntegriCloud