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>
This commit is contained in:
John Polstra 1999-07-09 16:22:55 +00:00
parent 68d0ed40e4
commit 8d05e8c453

View File

@ -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
@ -1502,6 +1472,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)
{