| 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(); | |
| } |