Hello! Today I found two important things.1. Mesa seems to use both __attribute__((__destructor__)) AND atexit(3) at same time, but destructor call is not executed or gdb does not catch destructor call (?) 2. Crash seems to occurs only in /usr/X11R7/lib/modules/dri/swrast_dri.so (swrast driver). When I tried "modesetting" Intel Broxton "HD Graphics 500 (APL 2)") it works (after several unrelated tweaks)
Ad 1: Looking closely on source at https://cvsweb.netbsd.org/bsdweb.cgi/xsrc/external/mit/MesaLib/dist/src/mesa/main/context.c?rev=1.9;content-type=text%2Fplain we can see both:
static void __attribute__((__destructor__))
one_time_fini(void)
{
if (api_init_mask) {
glsl_type_singleton_decref();
_mesa_locale_fini();
}
}
static void
one_time_init(void)
{
// ...
atexit(one_time_fini);
// ...
}
But when I place deferred brakpoint at one_time_fini() only final
handler call is caught (that one which cause SIGSEGV) where GDB properly
warns:
warning: Temporarily disabling breakpoints for unloaded shared library "/usr/X11R7/lib/modules/dri/swrast_dri.so"
Thread 1 "" received signal SIGSEGV, Segmentation fault. So now I have 2 mysteries: 1. why there is used both __destructor__ and atexit(3) in Mesa's context.c 2. why my gdb does not catch __destructor__ call - is it called or not? Regards --Henryk Paluch On 12/21/25 09:04, Henryk Paluch wrote:
Hello! New example with __cxa_atexit works for me. Let me summarize things:Problem: any program using new Mesa from (xsrc/external/mit/MesaLib/ dist/src/mesa/main/context.c r1.9), including NetBSD 11.0_BETA will crash on exit, because Mesa now calls atexit(3) from dlopen(3) DSO that is not supported in NetBSD. In base system this affects at least:- glxinfo - glxgearsAnd possibly some ports. Unfortunately I had not enough time to build any major browser (Firefox, Chromium) so can't confirm if these are also affected.Possible solutions: 1. fix atexit(3) to work properly from DSOs (as done on most other systems) 2. use __attribute__((destructor)) 3. use __cxa_atexitSo we have to decide what solution is best. Personally I think that this problem is blocker for 11.0_RELEASE. We can't ship system where major X programs just crash on exit.Regards --Henryk Paluch On 12/21/25 00:54, RVP wrote:On Sat, 20 Dec 2025, RVP wrote:Shared libs. should use __cxa_atexit() with a non-NULL `dso' parameter.This works on FreeBSD, OpenBSD, Linux and even OpenIndiana. (Anything whichsupports C++ would be my bet.) -RVP ---START--- ==> dl-atexit.c <== #include <dlfcn.h> #include <stdio.h> #include <stdlib.h> static void diemain(void) { printf("%s: atexit handler\n", __func__); } int main(void) { extern const void* const __dso_handle; printf("__dso_handle = %p\n", __dso_handle); atexit(diemain); void *h = dlopen("libfoo.so", RTLD_LOCAL | RTLD_LAZY); if (h == NULL) { fprintf(stderr, "dlopen(): %s\n", dlerror()); return 1; } void (*foo)(void) = dlsym(h, "foo"); if (foo == NULL) { fprintf(stderr, "dlsym(foo): %s\n", dlerror()); return 1; } printf("%s: calling foo()\n", __func__); foo(); printf("%s: calling dlclose()\n", __func__); dlclose(h); printf("%s: exiting...\n", __func__); return 0; } ==> libfoo.c <== #include <stdio.h> #include <stdlib.h> extern int __cxa_atexit(void (*)(void*), void*, const void*); extern const void* const __dso_handle; static void // die(void) die(void* v) { printf("%s: atexit handler\n", __func__); } void foo(void) { printf("__dso_handle = %p\n", __dso_handle); // atexit(die); __cxa_atexit(die, NULL, __dso_handle); printf("%s: atexit handler die() @ %p\n", __func__, die); } ==> Makefile <== LDFLAGS= -fuse-linker-plugin -Wl,--enable-new-dtags,-z,relro,-z,now dl-atexit: dl-atexit.c libfoo.so cc -pie -fPIE -o dl-atexit dl-atexit.c -Wl,-rpath=$$(pwd) ${LDFLAGS} libfoo.so: libfoo.c cc -shared -DPIC -fPIC -o libfoo.so libfoo.c ${LDFLAGS} run: dl-atexit ./dl-atexit clean: rm -f dl-atexit *.so *.core ---END---