import core.memory; import core.sync.condition; import core.sync.mutex; import core.thread; __gshared Condition g_cond; __gshared Mutex g_mutex; __gshared int g_step = 0; class C { ~this() { import core.stdc.stdlib; abort(); // this gets triggered although the instance always stays referenced } } C c; static this() { c = new C; } static ~this() { import core.memory; GC.free(cast(void*)c); // free without destruction to avoid triggering abort() } void test() { assert(c !is null); // notify the main thread of the finished initialization synchronized (g_mutex) g_step = 1; g_cond.notifyAll(); // wait until the GC collection is done synchronized (g_mutex) { while (g_step != 2) g_cond.wait(); } } void main() { g_mutex = new Mutex; g_cond = new Condition(g_mutex); auto th = new Thread(&test); th.start(); // wait for thread to be fully initialized synchronized (g_mutex) { while (g_step != 1) g_cond.wait(); } // this causes the other thread's C instance to be reaped with the bug present GC.collect(); // allow the thread to shut down synchronized (g_mutex) g_step = 2; g_cond.notifyAll(); th.join(); }