June 08
https://issues.dlang.org/show_bug.cgi?id=24590

          Issue ID: 24590
           Summary: Illegal instruction with module constructors cycle and
                    shared libphobos2 in _d_criticalenter2
           Product: D
           Version: D2
          Hardware: x86_64
                OS: Linux
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: druntime
          Assignee: nobody@puremagic.com
          Reporter: a.horodniceanu@proton.me

Take the two files:
----
module a;
import b;
shared static this(){}
----
----
module b;
import a;
shared static this(){}
----
compiled with `dmd a.d b.d -defaultlib=libphobos2.so -main -ofmain`.

Running main produces:
----
$ ./main
object.Error@src/rt/minfo.d(372): Cyclic dependency between module
constructors/destructors of b and a
b* ->
a* ->
b*

----------------
??:? nothrow bool
rt.minfo.ModuleGroup.sortCtors(immutable(char)[]).findDeps(ulong, ulong*)
[0x7f240dc5a1e9]
??:? nothrow bool
rt.minfo.ModuleGroup.sortCtors(immutable(char)[]).processMod(ulong)
[0x7f240dc5a3fa]
??:? nothrow bool
rt.minfo.ModuleGroup.sortCtors(immutable(char)[]).processMod(ulong)
[0x7f240dc5a4eb]
??:? nothrow bool
rt.minfo.ModuleGroup.sortCtors(immutable(char)[]).doSort(ulong, ref
immutable(object.ModuleInfo)*[]) [0x7f240dc5a773]
??:? nothrow void rt.minfo.ModuleGroup.sortCtors(immutable(char)[])
[0x7f240dc59c89]
??:? void rt.minfo.ModuleGroup.sortCtors() [0x7f240dc5a838]
??:? int rt.minfo.rt_moduleCtor().__foreachbody1(ref
rt.sections_elf_shared.DSO) [0x7f240dc5abe8]
??:? int rt.sections_elf_shared.DSO.opApply(scope int delegate(ref
rt.sections_elf_shared.DSO)) [0x7f240dc5c557]
??:? rt_moduleCtor [0x7f240dc5abc8]
??:? rt_init [0x7f240dc524c9]
??:? void rt.dmain2._d_run_main2(char[][], ulong, extern (C) int
function(char[][])*).runAll() [0x7f240dc52a6f]
??:? void rt.dmain2._d_run_main2(char[][], ulong, extern (C) int
function(char[][])*).tryExec(scope void delegate()) [0x7f240dc52a0d]
??:? _d_run_main2 [0x7f240dc52976]
??:? _d_run_main [0x7f240dc5275f]
??:? main [0x55f47ddba1af]
??:? [0x7f240d5660cf]
??:? __libc_start_main [0x7f240d566188]
??:? _start [0x55f47ddba084]
Illegal instruction (core dumped)
----

The core dump shows:
----
(gdb) bt
#0  0x00007f240dc519dd in _d_criticalenter2 () from
/usr/lib/dmd/2.108/lib64/libphobos2.so.0.108
#1  0x00007f240dc5f498 in rt.trace._staticDtor_L408_C1() () from
/usr/lib/dmd/2.108/lib64/libphobos2.so.0.108
#2  0x00007f240dc603c1 in rt.trace.__moddtor() () from
/usr/lib/dmd/2.108/lib64/libphobos2.so.0.108
#3  0x00007f240dc5aece in
rt.minfo.runModuleFuncsRev!(rt.minfo.ModuleGroup.runTlsDtors().__lambda1).runModuleFuncsRev(const(immutable(object.ModuleInfo)*)[])
() from /usr/lib/dmd/2.108/lib64/libphobos2.so.0.108
#4  0x00007f240dc5a8b9 in rt.minfo.ModuleGroup.runTlsDtors() () from
/usr/lib/dmd/2.108/lib64/libphobos2.so.0.108
#5  0x00007f240dc5d5c2 in _d_dso_registry () from
/usr/lib/dmd/2.108/lib64/libphobos2.so.0.108
#6  0x00007f240dbe83b6 in ?? () from
/usr/lib/dmd/2.108/lib64/libphobos2.so.0.108
#7  0x0000000000000001 in ?? ()
#8  0x00007f240dda99a0 in ?? () from
/usr/lib/dmd/2.108/lib64/libphobos2.so.0.108
#9  0x00007f240ddd2fe0 in vtable for etc.linux.memoryerror.NullPointerError ()
from /usr/lib/dmd/2.108/lib64/libphobos2.so.0.108
#10 0x00007f240ddd4660 in ?? () from
/usr/lib/dmd/2.108/lib64/libphobos2.so.0.108
#11 0x00007f240de640b0 in ?? ()
#12 0x00007f240de670e2 in _dl_call_fini () from /lib64/ld-linux-x86-64.so.2
#13 0x00007f240de6af9e in _dl_fini () from /lib64/ld-linux-x86-64.so.2
#14 0x00007f240d57e656 in ?? () from /usr/lib64/libc.so.6
#15 0x00007f240d57e790 in exit () from /usr/lib64/libc.so.6
#16 0x00007f240d5660d7 in ?? () from /usr/lib64/libc.so.6
#17 0x00007f240d566189 in __libc_start_main () from /usr/lib64/libc.so.6
#18 0x000055f47ddba085 in _start ()
----

And the surrounding assembly:
----
Dump of assembler code for function _d_criticalenter2:
   0x00007f240dc519a8 <+0>:     push   %rbp
   0x00007f240dc519a9 <+1>:     mov    %rsp,%rbp
   0x00007f240dc519ac <+4>:     sub    $0x30,%rsp
   0x00007f240dc519b0 <+8>:     mov    %rbx,-0x28(%rbp)
   0x00007f240dc519b4 <+12>:    mov    %r12,-0x20(%rbp)
   0x00007f240dc519b8 <+16>:    mov    %rdi,%r12
   0x00007f240dc519bb <+19>:    cmpq   $0x0,(%r12)
   0x00007f240dc519c0 <+24>:    jne    0x7f240dc51a5e <_d_criticalenter2+182>
   0x00007f240dc519c6 <+30>:    mov    0xff003(%rip),%rbx        #
0x7f240dd509d0
   0x00007f240dc519cd <+37>:    add    $0x8,%rbx
   0x00007f240dc519d1 <+41>:    mov    %rbx,%rdi
   0x00007f240dc519d4 <+44>:    call   0x7f240da893b0 <pthread_mutex_lock@plt>
   0x00007f240dc519d9 <+49>:    test   %eax,%eax
   0x00007f240dc519db <+51>:    je     0x7f240dc519df <_d_criticalenter2+55>
=> 0x00007f240dc519dd <+53>:    ud2
   0x00007f240dc519df <+55>:    cmpq   $0x0,(%r12)
   0x00007f240dc519e4 <+60>:    jne    0x7f240dc51a45 <_d_criticalenter2+157>
# <snip>
----

Note that the eax register has the value 22 which is EINVAL which would indicate that the mutex passed to pthread_mutex_lock is uninitialized. I say this yet I don't know how the code got past the `test %eax,%eax`.

The code above fails with both dmd and ldc2 but not with gdc.

--