Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit f60eb35

Browse files
author
Mihails Strasuns
committed
Fix crash in destructor of detached thread
Fix issue 19314 Expectation is that after thread is detached from druntime, it becomes responsibility of external environment to terminate it properly (for example, by calling `join` from C/C++ code). However, `Thread` object for that thread will still remain and will eventually be collected by GC. Destructor tries to call `pthread_detach` unconditionally but it is undefined behaviour if thread was already joined before (see `man pthread_detach`).
1 parent 1f1cb92 commit f60eb35

File tree

2 files changed

+37
-6
lines changed

2 files changed

+37
-6
lines changed

src/core/thread.d

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,10 @@ class Thread
596596
*/
597597
~this() nothrow @nogc
598598
{
599-
if ( m_addr == m_addr.init )
599+
bool no_context = m_addr == m_addr.init;
600+
bool not_registered = !next && !prev && (sm_tbeg !is this);
601+
602+
if (no_context || not_registered)
600603
{
601604
return;
602605
}

test/thread/src/external_threads.d

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,50 @@
11
import core.sys.posix.pthread;
22
import core.memory;
3+
import core.thread;
4+
5+
extern (C) void rt_moduleTlsCtor();
6+
extern (C) void rt_moduleTlsDtor();
37

48
extern(C)
5-
void* entry_point(void*)
9+
void* entry_point1(void*)
610
{
711
// try collecting - GC must ignore this call because this thread
812
// is not registered in runtime
913
GC.collect();
1014
return null;
1115
}
1216

17+
extern(C)
18+
void* entry_point2(void*)
19+
{
20+
// This thread gets registered in druntime, does some work and gets
21+
// unregistered to be cleaned up manually
22+
thread_attachThis();
23+
rt_moduleTlsCtor();
24+
25+
auto x = new int[10];
26+
27+
rt_moduleTlsDtor();
28+
thread_detachThis();
29+
return null;
30+
}
31+
1332
void main()
1433
{
1534
// allocate some garbage
1635
auto x = new int[1000];
1736

18-
pthread_t thread;
19-
auto status = pthread_create(&thread, null, &entry_point, null);
20-
assert(status == 0);
21-
pthread_join(thread, null);
37+
{
38+
pthread_t thread;
39+
auto status = pthread_create(&thread, null, &entry_point1, null);
40+
assert(status == 0);
41+
pthread_join(thread, null);
42+
}
43+
44+
{
45+
pthread_t thread;
46+
auto status = pthread_create(&thread, null, &entry_point2, null);
47+
assert(status == 0);
48+
pthread_join(thread, null);
49+
}
2250
}

0 commit comments

Comments
 (0)