Hi, I try to give it one more attempt with a bit more description about the bug.
After calling dlclose in _dl_notify_unload_shlib_ group reference counts are decreased by following the object's grpref-list. Unfortunately the references are removed from the list during the graph traversal. dlclose will run all destructors of the unused objects and tries to unload all objects reachable from the closed object's child and grpref-list. Since the grpref-list references were removed, the unused destructed object stays in memory as garbage. Next time when this object is loaded it is found in the memory and crashes during load. This patch unloads all unused objects instead of following the closed object's child and grpref list. Best regards, Peter Hajdu
Index: dlfcn.c =================================================================== RCS file: /cvs/src/libexec/ld.so/dlfcn.c,v retrieving revision 1.91 diff -u -p -r1.91 dlfcn.c --- dlfcn.c 19 Sep 2015 20:56:47 -0000 1.91 +++ dlfcn.c 21 Oct 2015 13:52:46 -0000 @@ -302,7 +302,7 @@ _dl_real_close(void *handle) object->opencount--; _dl_notify_unload_shlib(object); _dl_run_all_dtors(); - _dl_unload_shlib(object); + _dl_unload_unused(); _dl_cleanup_objects(); return (0); } Index: library.c =================================================================== RCS file: /cvs/src/libexec/ld.so/library.c,v retrieving revision 1.71 diff -u -p -r1.71 library.c --- library.c 16 Jan 2015 16:18:07 -0000 1.71 +++ library.c 21 Oct 2015 13:52:46 -0000 @@ -74,6 +74,22 @@ _dl_unload_shlib(elf_object_t *object) } } +void +_dl_unload_unused(void) +{ + elf_object_t *obj, *next; + + for (obj = _dl_objects->next; obj != NULL; obj = next) { + next = obj->next; + if (OBJECT_REF_CNT(obj) != 0 || obj->status & STAT_UNLOADED) + continue; + obj->status |= STAT_UNLOADED; + _dl_load_list_free(obj->load_list); + _dl_munmap((void *)obj->load_base, obj->load_size); + _dl_remove_object(obj); + } +} + elf_object_t * _dl_tryload_shlib(const char *libname, int type, int flags) { Index: library_mquery.c =================================================================== RCS file: /cvs/src/libexec/ld.so/library_mquery.c,v retrieving revision 1.49 diff -u -p -r1.49 library_mquery.c --- library_mquery.c 22 Jan 2015 05:48:17 -0000 1.49 +++ library_mquery.c 21 Oct 2015 13:52:46 -0000 @@ -79,6 +79,20 @@ _dl_unload_shlib(elf_object_t *object) } } +void +_dl_unload_unused(void) +{ + elf_object_t *obj, *next; + + for (obj = _dl_objects->next; obj != NULL; obj = next) { + next = obj->next; + if (OBJECT_REF_CNT(obj) != 0 || obj->status & STAT_UNLOADED) + continue; + obj->status |= STAT_UNLOADED; + _dl_load_list_free(obj->load_list); + _dl_remove_object(obj); + } +} elf_object_t * _dl_tryload_shlib(const char *libname, int type, int flags) Index: resolve.h =================================================================== RCS file: /cvs/src/libexec/ld.so/resolve.h,v retrieving revision 1.73 diff -u -p -r1.73 resolve.h --- resolve.h 19 Sep 2015 20:56:47 -0000 1.73 +++ resolve.h 21 Oct 2015 13:52:46 -0000 @@ -223,6 +223,7 @@ void _dl_unlink_dlopen(elf_object_t *dep void _dl_notify_unload_shlib(elf_object_t *object); void _dl_unload_shlib(elf_object_t *object); void _dl_unload_dlopen(void); +void _dl_unload_unused(void); void _dl_run_all_dtors(void);