1 import core.memory; 2 import core.sync.condition; 3 import core.sync.mutex; 4 import core.thread; 5 6 __gshared Condition g_cond; 7 __gshared Mutex g_mutex; 8 __gshared int g_step = 0; 9 10 class C 11 { ~this()12 ~this() 13 { 14 import core.stdc.stdlib; 15 abort(); // this gets triggered although the instance always stays referenced 16 } 17 } 18 19 C c; 20 this()21static this() 22 { 23 c = new C; 24 } 25 ~this()26static ~this() 27 { 28 import core.memory; 29 GC.free(cast(void*)c); // free without destruction to avoid triggering abort() 30 } 31 test()32void test() 33 { 34 assert(c !is null); 35 36 // notify the main thread of the finished initialization 37 synchronized (g_mutex) g_step = 1; 38 g_cond.notifyAll(); 39 40 // wait until the GC collection is done 41 synchronized (g_mutex) { 42 while (g_step != 2) 43 g_cond.wait(); 44 } 45 } 46 47 main()48void main() 49 { 50 g_mutex = new Mutex; 51 g_cond = new Condition(g_mutex); 52 53 auto th = new Thread(&test); 54 th.start(); 55 56 // wait for thread to be fully initialized 57 synchronized (g_mutex) { 58 while (g_step != 1) 59 g_cond.wait(); 60 } 61 62 // this causes the other thread's C instance to be reaped with the bug present 63 GC.collect(); 64 65 // allow the thread to shut down 66 synchronized (g_mutex) g_step = 2; 67 g_cond.notifyAll(); 68 69 th.join(); 70 } 71