Currently, an application can shoot itself in the tail by
registering a symbol with atexit and then dlclose-ing the
library, which provides the symbol.
Programs aren't supposed to that, but sometimes they do --
most notably ImageMagick, which dlopens libjasper, which
registers its own clean-up routine with atexit.
The proposed patch will make such bugs easier to diagnose --
the ImageMagick problem (crash upon exiting) was mystifying
people for years...
The up-to-date version of the patch can be found here:
It exposes the __atexit pointer defined in atexit.c and its
type and modifies dlclose to scan through all listed functions
looking for those, that belong to the object being dlclosed.
The method to check whether a symbol belongs to an object
is to check, whether the address is between mapbase and
mapbase+mapsize of the entry.
What could be improved is the addition of a an addr_to_name
lookup -- to print the _name_ of the function found to be
registered with atexit, rather than merely the function's
--- Gordon Stratton <email@example.com> wrote:
> I did some testing, and the patch does seem to help. However, there seem
> to be a couple cases where a segmentation fault still occurs. The first
> is when I attempt to open a file with PHP that does not exist:
> $ php doesntexist
> Could not open input file: doesntexist
> Segmentation fault
> The second case involves a different PHP extension, pdo_dblib.so (the
> OCI8 extensions seem to work OK now):
> (gdb) bt
> #0 0x2912313c in ?? ()
> #1 0x285855c7 in pthread_mutex_lock () from /lib/libc.so.6
> #2 0x28f09bf3 in dbexit () from /usr/local/lib/libsybdb.so.5
> #3 0x28efb86b in zm_shutdown_pdo_dblib () from
> #4 0x0816ceb0 in module_destructor (module=0x832a300) at
> #5 0x0817171a in zend_hash_apply_deleter (ht=0x826c620, p=0x8330280)
> at /usr/ports/lang/php5/work/php-5.2.3/Zend/zend_hash.c:611
> #6 0x08171873 in zend_hash_graceful_reverse_destroy (ht=0x826c620) at
> #7 0x08166ca7 in zend_shutdown () at
> #8 0x081205f5 in php_module_shutdown () at
> #9 0x081ce73b in main (argc=20, argv=0xbfbfeca0) at
Have those two cases (doesntexist and pdo_dblib) segfaulted without this patch?
Yahoo! oneSearch: Finally, mobile search
that gives answers, not web links.
> On 9/13/07, Simun Mikecin <firstname.lastname@example.org> wrote:
> Have those two cases (doesntexist and pdo_dblib) segfaulted without this patch?
(CC'ing lists this time, my apologies)
doesntexist segfaults without the patch for sure, I can't say for sure
about pdo_dblib.. I never _saw_ it but it's possible that other modules
were segfaulting first so it never got a chance to segfault. There is at
least one case now where PHP does not segfault with the patch where it
This remains a problem on 8.2 today. multimedia/vlc port always dumps
core on exit and the core's stack always contains __cxa_atexit()
The patch I submitted with this PR 4 years ago still applies.
Created attachment 153231 [details]
Upload the patch so that it's easier to review and doesn't got lost.
For bugs matching the following conditions:
- Status == In Progress
- Assignee == "bugs@FreeBSD.org"
- Last Modified Year <= 2017
- Set Status to "Open"
Old discussion here: https://freebsd-arch.freebsd.narkive.com/zzyHX3Bw/dlclose-vs-atexit
glibc handles this:
Since glibc 2.2.3, atexit() (and on_exit(3)) can be used within a shared library to establish functions that are called when the shared library is unloaded.
The patch here is interesting but not something that should be committed. A real
solution should be committed that prevents a crash.
Perhaps making atexit() aware that it is being called from a dso and properly
registering that dso in atexit_register(), etc.
*Very naive and untested*.
It seems like we need something like this:
diff --git lib/libc/stdlib/atexit.c lib/libc/stdlib/atexit.c
index bc9ad3ebd7bf..8df6cd4e31b0 100644
@@ -125,6 +125,8 @@ atexit_register(struct atexit_fn *fptr)
+extern void *__dso_handle __hidden;
* Register a function to be performed at exit.
@@ -137,7 +139,7 @@ atexit(void (*func)(void))
fn.fn_type = ATEXIT_FN_STD;
fn.fn_ptr.std_func = func;
fn.fn_arg = NULL;
- fn.fn_dso = NULL;
+ fn.fn_dso = __dso_handle;
error = atexit_register(&fn);