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