diff options
author | kan <kan@FreeBSD.org> | 2003-05-08 01:31:36 +0000 |
---|---|---|
committer | kan <kan@FreeBSD.org> | 2003-05-08 01:31:36 +0000 |
commit | c47ebbd98f7167ae78a7885c1afa61c6439b5f90 (patch) | |
tree | 45d48a8463c8db69b73ca13955997b0d172f2c95 /libexec | |
parent | 2d5f55a20d28a25fb5707f3162e2a66f2b58e0a2 (diff) | |
download | FreeBSD-src-c47ebbd98f7167ae78a7885c1afa61c6439b5f90.zip FreeBSD-src-c47ebbd98f7167ae78a7885c1afa61c6439b5f90.tar.gz |
Rethink the way we count module references. Simply following
DT_NEEDED links is not flexible enough for cases where dynamically
loaded modules form a dependency cycle.
This should fix an infinite recursion problem encountered by Yahoo.
Approved by: re (jhb)
Diffstat (limited to 'libexec')
-rw-r--r-- | libexec/rtld-elf/rtld.c | 48 |
1 files changed, 30 insertions, 18 deletions
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 06a78a6..adb156a 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -126,6 +126,7 @@ 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 *); +static void ref_dag(Obj_Entry *); void r_debug_state(struct r_debug*, struct link_map*); @@ -361,7 +362,6 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) *obj_tail = obj_main; obj_tail = &obj_main->next; obj_count++; - obj_main->refcount++; /* Make sure we don't call the main program's init and fini functions. */ obj_main->init = obj_main->fini = NULL; @@ -383,8 +383,10 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) die(); /* Make a list of all objects loaded at startup. */ - for (obj = obj_list; obj != NULL; obj = obj->next) + for (obj = obj_list; obj != NULL; obj = obj->next) { objlist_push_tail(&list_main, obj); + obj->refcount++; + } if (ld_tracing) { /* We're done */ trace_loaded_objects(obj_main); @@ -970,6 +972,8 @@ init_dag1(Obj_Entry *root, Obj_Entry *obj, DoneList *dlp) if (donelist_check(dlp, obj)) return; + + obj->refcount++; objlist_push_tail(&obj->dldags, root); objlist_push_tail(&root->dagmembers, obj); for (needed = obj->needed; needed != NULL; needed = needed->next) @@ -1223,7 +1227,6 @@ load_object(char *path) } else free(path); - obj->refcount++; return obj; } @@ -1579,6 +1582,7 @@ dlclose(void *handle) /* Unreference the object and its dependencies. */ root->dl_refcount--; + unref_dag(root); if (root->refcount == 0) { @@ -1682,8 +1686,14 @@ dlopen(const char *name, int mode) /* Make list of init functions to call. */ initlist_add_objects(obj, &obj->next, &initlist); } - } else if (ld_tracing) - goto trace; + } else { + + /* Bump the reference counts for objects on this DAG. */ + ref_dag(obj); + + if (ld_tracing) + goto trace; + } } GDB_STATE(RT_CONSISTENT,obj ? &obj->linkmap : NULL); @@ -2405,7 +2415,6 @@ unload_object(Obj_Entry *root) static void unlink_object(Obj_Entry *root) { - const Needed_Entry *needed; Objlist_Entry *elm; if (root->refcount == 0) { @@ -2413,25 +2422,28 @@ unlink_object(Obj_Entry *root) objlist_remove(&list_global, root); /* Remove the object from all objects' DAG lists. */ - STAILQ_FOREACH(elm, &root->dagmembers , link) + STAILQ_FOREACH(elm, &root->dagmembers , link) { objlist_remove(&elm->obj->dldags, root); + if (elm->obj != root) + unlink_object(elm->obj); + } } +} - for (needed = root->needed; needed != NULL; needed = needed->next) - if (needed->obj != NULL) - unlink_object(needed->obj); +static void +ref_dag(Obj_Entry *root) +{ + Objlist_Entry *elm; + + STAILQ_FOREACH(elm, &root->dagmembers , link) + elm->obj->refcount++; } static void unref_dag(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); + STAILQ_FOREACH(elm, &root->dagmembers , link) + elm->obj->refcount--; } |