diff options
author | jdp <jdp@FreeBSD.org> | 1999-07-09 16:22:55 +0000 |
---|---|---|
committer | jdp <jdp@FreeBSD.org> | 1999-07-09 16:22:55 +0000 |
commit | 5587b52c7549e7a364a775fba40dd0b4842d9db1 (patch) | |
tree | e1ce93478f4c37036674d03c14ca3a1533c9b8b8 | |
parent | 63354e88d91aef0b1bc6330177f7770740f21203 (diff) | |
download | FreeBSD-src-5587b52c7549e7a364a775fba40dd0b4842d9db1.zip FreeBSD-src-5587b52c7549e7a364a775fba40dd0b4842d9db1.tar.gz |
Fix bug: if a dlopen() failed (e.g., because of undefined symbols),
the dynamic linker didn't clean up properly. A subsequent dlopen()
of the same object would appear to succeed.
Another excellent fix from Max Khon.
PR: bin/12471
Submitted by: Max Khon <fjoe@iclub.nsu.ru>
-rw-r--r-- | libexec/rtld-elf/rtld.c | 82 |
1 files changed, 44 insertions, 38 deletions
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 1ff518e..8a69de1 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -22,7 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: rtld.c,v 1.25 1999/06/25 04:50:06 jdp Exp $ + * $Id: rtld.c,v 1.26 1999/07/03 23:54:02 jdp Exp $ */ /* @@ -89,8 +89,9 @@ static int relocate_objects(Obj_Entry *, bool); static void rtld_exit(void); static char *search_library_path(const char *, const char *); static void set_program_var(const char *, const void *); -static void unref_object_dag(Obj_Entry *); static void trace_loaded_objects(Obj_Entry *obj); +static void unload_object(Obj_Entry *, bool do_fini_funcs); +static void unref_object_dag(Obj_Entry *); void r_debug_state(void); void xprintf(const char *, ...); @@ -942,6 +943,7 @@ load_object(char *path) _rtld_error("Cannot open \"%s\"", path); return NULL; } + dbg("loading \"%s\"", path); obj = map_object(fd); close(fd); if (obj == NULL) { @@ -1106,38 +1108,8 @@ dlclose(void *handle) return -1; GDB_STATE(RT_DELETE); - + unload_object(root, true); root->dl_refcount--; - unref_object_dag(root); - if (root->refcount == 0) { /* We are finished with some objects. */ - Obj_Entry *obj; - Obj_Entry **linkp; - - /* Finalize objects that are about to be unmapped. */ - for (obj = obj_list->next; obj != NULL; obj = obj->next) - if (obj->refcount == 0 && obj->fini != NULL) - (*obj->fini)(); - - /* Unmap all objects that are no longer referenced. */ - linkp = &obj_list->next; - while ((obj = *linkp) != NULL) { - if (obj->refcount == 0) { - munmap(obj->mapbase, obj->mapsize); - free(obj->path); - while (obj->needed != NULL) { - Needed_Entry *needed = obj->needed; - obj->needed = needed->next; - free(needed); - } - linkmap_delete(obj); - *linkp = obj->next; - free(obj); - } else - linkp = &obj->next; - } - obj_tail = linkp; - } - GDB_STATE(RT_CONSISTENT); return 0; @@ -1173,11 +1145,9 @@ dlopen(const char *name, int mode) if (*old_obj_tail != NULL) { /* We loaded something new. */ assert(*old_obj_tail == obj); - /* XXX - Clean up properly after an error. */ - if (load_needed_objects(obj) == -1) { - obj->dl_refcount--; - obj = NULL; - } else if (relocate_objects(obj, mode == RTLD_NOW) == -1) { + if (load_needed_objects(obj) == -1 || + relocate_objects(obj, mode == RTLD_NOW) == -1) { + unload_object(obj, false); obj->dl_refcount--; obj = NULL; } else @@ -1503,6 +1473,42 @@ trace_loaded_objects(Obj_Entry *obj) } static void +unload_object(Obj_Entry *root, bool do_fini_funcs) +{ + unref_object_dag(root); + if (root->refcount == 0) { /* We are finished with some objects. */ + Obj_Entry *obj; + Obj_Entry **linkp; + + /* Finalize objects that are about to be unmapped. */ + if (do_fini_funcs) + for (obj = obj_list->next; obj != NULL; obj = obj->next) + if (obj->refcount == 0 && obj->fini != NULL) + (*obj->fini)(); + + /* Unmap all objects that are no longer referenced. */ + linkp = &obj_list->next; + while ((obj = *linkp) != NULL) { + if (obj->refcount == 0) { + dbg("unloading \"%s\"", obj->path); + munmap(obj->mapbase, obj->mapsize); + free(obj->path); + while (obj->needed != NULL) { + Needed_Entry *needed = obj->needed; + obj->needed = needed->next; + free(needed); + } + linkmap_delete(obj); + *linkp = obj->next; + free(obj); + } else + linkp = &obj->next; + } + obj_tail = linkp; + } +} + +static void unref_object_dag(Obj_Entry *root) { assert(root->refcount != 0); |