Compiling pure C (no D source) with dmd and using dynamic loading (not dynamic linking) causes a crash on program exit under certain conditions, where a gcc compilation of the same source works fine.
Rewriting the C in D and compiling with dmd with identical switches causes the same crash.
The following two examples are attached, using dlfcn.h from C source and core.sys.posix.dlfcn from D source. Both crash.
A.
====
dmd -c main.c
dmd -of=main -L-E main.o -L-ldl
dmd -c -fPIC dynamic_lib.c
dmd -of=dynamic_lib.so -shared -fPIC dynamic_lib.o
====
B.
====
dmd -c main.d
dmd -of=main -L-E main.o -L-ldl
dmd -c -fPIC dynamic_lib.d
dmd -of=dynamic_lib.so -shared -fPIC dynamic_lib.o
====
A. and B.
* main dynamically loads dynamic_lib.so
* main calls a function in dynamic_lib.so which calls a function in main
* main is linked with a switch to export all symbols so this works
When A. is built with gcc it works fine.
Failure to call dlclose before main exits causes the crash; main runs correctly before that. (If the commented out call of dlclose is made then everything works.)
Crash:
====
$ main
1
2
3
4
Aborting from src/rt/sections_elf_shared.d(512) DSO being unregistered isn't current last one.Aborted (core dumped)
====
This crash occurs only if
1.
Both main and dynamic_lib are built with dmd.
(either from C source or D source)
(If one of main, dynamic_lib.so is built with gcc, everything works.)
2.
Main is NOT linked with -defaultlib=libphobos2.so
(irrespective of how dynamic_lib is linked to phobos)
Comment #1 by sturtivant — 2024-03-01T20:37:14Z
Created attachment 1907
main.c
Comment #2 by sturtivant — 2024-03-01T20:37:54Z
Created attachment 1908
dynamic_lib.c
Comment #3 by sturtivant — 2024-03-01T20:38:43Z
Created attachment 1909
main.d
Comment #4 by sturtivant — 2024-03-01T20:39:15Z
Created attachment 1910
dynamic_lib.d
Comment #5 by alphaglosined — 2024-03-01T20:51:38Z
Just to clarify:
Does a crash only occur when the executable has druntime linked in and initialized?
If you load a shared library that has druntime linked in, does it also crash if you initialize druntime?
Does this happen with ldc?
Comment #6 by sturtivant — 2024-03-01T21:50:35Z
1.
lcd did not produce the bug, using --link-defaultlib-shared=false for both the main program and the dynamic library.
2.
When the dynamic library C source is compiled and linked with -betterC the error does not occur.
3.
It does crash with druntime initialized in the dynamic library.
Comment #7 by alphaglosined — 2024-03-01T21:54:15Z
When using ldc does it crash when druntime is a shared library and initialized?
This will confirm that it is a druntime bug.
Comment #8 by sturtivant — 2024-03-01T22:01:52Z
> When using ldc does it crash when druntime is a shared library and initialized?
Is this the default for ldc?
Comment #9 by alphaglosined — 2024-03-01T22:06:05Z
The default phobos/druntime shared/static may depend upon platform and distribution.
Comment #10 by sturtivant — 2024-03-01T22:54:36Z
(In reply to Richard Cattermole from comment #9)
> The default phobos/druntime shared/static may depend upon platform and
> distribution.
I used the --link-defaultlib-shared=true option which I assume also shares druntime. I found no switch mentioning sharing or statically linking druntime explicitly.
Neither main.c nor dynamic_lib.c will link with --link-defaultlib-shared=true
With that false, the C version just works.
By contrast, D source links for all four combinations of true/false for --link-defaultlib-shared for each build. Three work, one crashes.
====
$ ldc2 -c main.d
$ ldc2 -of=main -L-E main.o -L-ldl --link-defaultlib-shared=false
$ ldc2 -c --relocation-model=pic dynamic_lib.d
$ + ldc2 -of=dynamic_lib.so -shared -relocation-model=pic dynamic_lib.o --link-defaultlib-shared=true
$ main
Aborting from rt/sections_elf_shared.d(605) Only one D shared object allowed for static runtime. Link with shared runtime via LDC switch '-link-defaultlib-shared'.Aborted (core dumped)
====
Comment #11 by sturtivant — 2024-03-01T23:09:23Z
(In reply to Carl Sturtivant from comment #10)
> (In reply to Richard Cattermole from comment #9)
====
$ ldc2 -c main.d
$ ldc2 -of=main -L-E main.o -L-ldl
$ ldc2 -c --relocation-model=pic dynamic_lib.d
$ ldc2 -of=dynamic_lib.so -shared -relocation-model=pic dynamic_lib.o
(dmd-2.107.0)carl@palmtree ~/Documents/dprogs/dl $ main
Aborting from rt/sections_elf_shared.d(605) Only one D shared object allowed for static runtime. Link with shared runtime via LDC switch '-link-defaultlib-shared'.Aborted (core dumped)
====
--- looks like the crash options are the default: not shared for main and shared for the dynamic library.
Comment #12 by alphaglosined — 2024-03-01T23:33:42Z
Okay, ldc and dmd have differing implementations of ``rt.sections_elf_shared``.
With ldc yes, you need to stick with only shared library build of druntime, it cannot be mixed.
From what I can tell it's an ordering problem due to not explicitly loading then unloading druntime in the right order.
Comment #13 by sturtivant — 2024-03-01T23:56:42Z
(In reply to Richard Cattermole from comment #12)
> From what I can tell it's an ordering problem due to not explicitly loading
> then unloading druntime in the right order.
That's intuitively reasonable.
Comment #14 by robert.schadek — 2024-12-07T13:43:17Z