Hello!
I have found exact cause while atexit(3) from dlopen(3) crashes later
under NetBSD (tested all major releases since 8.3) while it works under
Linux, OpenBSD and FreeBSD.
It is because NetBSD's atexit(3) on
https://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/stdlib/atexit.c?rev=1.35;content-type=text%2Fx-cvsweb-markup
calls __cxa_atexit_internal with dso=NULL (last argument):
int
atexit(void (*func)(void))
{
return (__cxa_atexit_internal((void (*)(void *))func, NULL, NULL));
}
When later __cxa_finalize is run on dlclose(3) it will not call its
callback because condition (dso == ah->ah_dso) will be always false (
ah->ah_dso == NULL which is != dso) - that was set in atexit(3) call.
Therefore DSO callback will be called on global exit (when DSO is no
longer mapped to memory) causing SIGSEGV.
I looked into OpenBSD 7.8's /usr/src/lib/csu/crtbeginS.c that does
something like:
int
atexit(void (*fn)(void))
{
return (__cxa_atexit((void (*)(void *))fn, NULL, &__dso_handle));
}
asm(".hidden atexit");
which properly passes implicit __dso_handle making this case to work.
So now it is up to you to decide what to do:
a) implement similar mechanism as other BSDs and Linux to make atexit(3)
work properly from dlopen(3)ed DSOs
b) replace all dlopen(3)ed DSOs atexit(3) calls with destructor attribute
Below is patch for RVP's example that does later (works as expected):
diff -up atexit-example/libfoo.c dtor-example/libfoo.c
--- atexit-example/libfoo.c 2025-12-18 17:33:15.952473568 +0100
+++ dtor-example/libfoo.c 2025-12-20 10:22:29.112508712 +0100
@@ -4,6 +4,7 @@
#include <stdlib.h>
static void
+__attribute__((__destructor__))
die(void)
{
printf("%s: atexit handler\n", __func__);
@@ -12,6 +13,6 @@ die(void)
void
foo(void)
{
- atexit(die);
+ //atexit(die);
printf("%s: atexit handler die() @ %p\n", __func__, die);
}
If you plan to stick to later solution I strongly suggest to update
manual page for atexit(3) to clearly state that NetBSD does not support
calling atexit(3) from dlopen(3)ed DSO and suggest using
__attribute__((__destructor__)) for such case.
Once decision is made I can create PR - category depending on solution:
if it will be xsrc component or lib.
Regards
--Henryk Paluch
On 12/19/25 07:36, Martin Husemann wrote:
On Fri, Dec 19, 2025 at 06:52:04AM +0100, Henryk Paluch wrote:
These places seem to permit atexit(3) in DSOs:
1. https://gnats.netbsd.org/18379
That is not talking about atexit(3).
3. https://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/stdlib/atexit.c
And this is something else. The DSO has not been unloaded before the
exit happens - this case clearly needs to work.
Martin