On Thu, 18 Dec 2025, Henryk Paluch wrote:

When I run just "glxinfo" on any machine (both virtual and bare metal) on 11.0_BETA - it appears to work but crashes on exit with Signal 11:
[...]
[1]   Segmentation fault (core dumped) glxinfo

What is even more puzzling that I'm unable to get decent stack-trace (have installed all sets including debug).

$ gdb glxinfo glxinfo.core

Reading symbols from glxinfo...
Reading symbols from /usr/libdata/debug//usr/X11R7/bin/glxinfo.debug...
[New process 1979]
Core was generated by `glxinfo'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00007b60f1d01eb3 in ?? ()
+bt
#0  0x00007b60f1d01eb3 in ?? ()
#1 0x00007b60f6b1795f in __cxa_finalize (dso=dso@entry=0x0) at /usr/src/lib/libc/stdlib/atexit.c:222 #2 0x00007b60f6b1753b in exit (status=0) at /usr/src/lib/libc/stdlib/exit.c:60 #3 0x0000000000b696d2 in ___start (cleanup=<optimized out>, ps_strings=0x7f7fff6dcfe0) at /usr/src/lib/csu/common/crt0-common.c:375
#4  0x00007f7ff77f08a8 in ?? () from /usr/libexec/ld.elf_so
#5  0x0000000000000001 in ?? ()
#6  0x00007f7fff6dc120 in ?? ()
#7  0x0000000000000000 in ?? ()
+q


Frame 0 crashing and gdb(1) not being able to find the function name for it
has the same cause: it's inside a .so file which's been unmapped by dlclose().

dlclose(), on amd64, calls _fini() in the shared object; which calls
__do_global_dtors_aux(); which calls __cxa_finalize(); this calls the handler
registered by the shared object using atexit(3). __cxa_finalize() will then
NULL the handler so that main() doesn't call it again when _it_ does the final
atexit(3) processing.

But, for some reason, __cxa_finalize() in the shared object never gets called
(and the atexit handlers don't run, of course) and main() then run the atexit
handlers in the _unmapped_ object.

Try the test code below. File a PR too!

Run the program in gdb(1), then when it crashes, compared the address against:

(gdb) info proc mappings

-RVP

---START---
==> Makefile <==
dl-atexit: dl-atexit.c libfoo.so
        cc -o dl-atexit dl-atexit.c -Wl,-rpath=$$(pwd)

libfoo.so: libfoo.c
        cc -shared -fPIC -o libfoo.so libfoo.c

run: dl-atexit
        ./dl-atexit

clean:
        rm -f dl-atexit *.so *.core

==> dl-atexit.c <==
#include <dlfcn.h>
#include <stdio.h>

int
main(void)
{
        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>

static void
die(void)
{
        printf("%s: atexit handler\n", __func__);
}

void
foo(void)
{
        atexit(die);
        printf("%s: atexit handler die() @ %p\n", __func__, die);
}
---END---

Reply via email to