1import core.memory; 2import core.sync.condition; 3import core.sync.mutex; 4import core.thread; 5 6__gshared Condition g_cond; 7__gshared Mutex g_mutex; 8__gshared int g_step = 0; 9 10class C 11{ 12 ~this() 13 { 14 import core.stdc.stdlib; 15 abort(); // this gets triggered although the instance always stays referenced 16 } 17} 18 19C c; 20 21static this() 22{ 23 c = new C; 24} 25 26static ~this() 27{ 28 import core.memory; 29 GC.free(cast(void*)c); // free without destruction to avoid triggering abort() 30} 31 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 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