Description
Description
As described in documentation ICorProfilerInfo::ForceGC
requires separate native thread for working. The thread will be finished by my profiler during detaching procedure. And I see it in lldb. However, after attaching again to the process the ICorProfilerInfo4::EnumThreads
call returns me the already dead thread where ICorProfilerInfo::ForceGC
was called sometime ago .
It's the important problem because the thread id can be already reused for a new native thread.
My investigation shows the CoreCLR keeps the static list of managed threads. and only alive threads will be returned in ICorProfilerInfo4::EnumThreads
. On the other hand the ICorProfilerInfo::ForceGC
adds current thread in this list.
Reproduction Steps
- Create following "hello world" application:
using System;
namespace test { class Program { static void Main(string[] args) {
Console.WriteLine("Hello World!");
Console.ReadLine();
}}}
- Publish it as a self contained application and run it in separate console
- Attach and detach a profiler which use
ICorProfilerInfo::ForceGC
and dump somewhere the thread id after the call. - Attach lldb and dump the thread list. Check that the thread id is not in the list.
- Attach a profiler which use
ICorProfilerInfo4::EnumThreads
and see that the dead thread id is in the list of managed threads.
Actual behavior
The native thread id which interesting us is 1BCF69
.
The part of the first profiler log;
00000000001BCF69 0 0000000000000000 GCCQ::ForceGcThread
00000000001BCF69 0 0000000000000000 GCCQ::ForceGc // <-- ICorProfilerInfo::ForceGC started
00000000001BCF69 1 000000014180AA00 MProf::GarbageCollectionStarted gcNumber=0 reason=induced c=5
00000000001BCF69 1 000000014180AA00 GCCQ::OnStarted gcNumber=0 gcState=normal
00000000001BCF69 1 000000014180AA00 MDG2::FlushMetadata
00000000001BCF69 1 000000014180AA00 MDG2::FlushMetadata res=ok
00000000001BCF69 1 000000014180AA00 MProf::GarbageCollectionStarted gcNumber=0 res=ok
00000000001BCF69 1 000000014180AA00 MProf::FinalizeableObjectQueued f=C oid=000000010122F650
00000000001BCF69 1 000000014180AA00 MProf::FinalizeableObjectQueued f=C oid=000000010122FA50
00000000001BCF69 1 000000014180AA00 MProf::FinalizeableObjectQueued f=C oid=000000010122FC40
00000000001BCF69 1 000000014180AA00 MProf::FinalizeableObjectQueued f=C oid=000000010122FCC0
00000000001BCF69 1 000000014180AA00 MProf::FinalizeableObjectQueued f=C oid=000000010122FD40
00000000001BCF69 1 000000014180AA00 MProf::FinalizeableObjectQueued f=C oid=000000010122FDC0
00000000001BCF69 1 000000014180AA00 MProf::FinalizeableObjectQueued f=C oid=000000010122FE48
00000000001BCF69 1 000000014180AA00 MProf::SurvivingReferences2 c=1
00000000001BCF69 1 000000014180AA00 MProf::SurvivingReferences2 c=91
00000000001BCF69 1 000000014180AA00 MProf::RootReferences2 c=42
00000000001BCF69 1 000000014180AA00 BProf::RootReferences c=42
00000000001BCF69 1 000000014180AA00 MProf::ObjectReferences oid=0000000101220048 cid=0000000280E48C80 c=0
00000000001BCF69 1 000000014180AA00 MProf::GarbageCollectionFinished gcNumber=0
00000000001BCF69 1 000000014180AA00 MProf::GarbageCollectionFinished gcNumber=0 res=ok
00000000001BCF69 1 000000014180AA00 GCCQ::OnFinished gcNumber=0 gcState=normal
00000000001BCF69 0 0000000000000000 GCCQ::ForceGc res=ok // <-- ICorProfilerInfo::ForceGC finished
00000000001BCF69 0 0000000000000000 GCCQ::ForceGcThread res=ok
lldb check:
(lldb) thread list
Process 52251 stopped
* thread #1: tid = 0x1bce01, 0x0000000194e1a538 libsystem_kernel.dylib`read + 8, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
thread #2: tid = 0x1bce03, 0x0000000194e19954 libsystem_kernel.dylib`mach_msg_trap + 8
thread #3: tid = 0x1bce04, 0x0000000194e1f8cc libsystem_kernel.dylib`kevent + 8
thread #4: tid = 0x1bce05, 0x0000000194e21ad0 libsystem_kernel.dylib`poll + 8
thread #5: tid = 0x1bce06, 0x0000000194e1a3d4 libsystem_kernel.dylib`__open + 8
thread #6: tid = 0x1bce07, 0x0000000194e1d0c0 libsystem_kernel.dylib`__psynch_cvwait + 8
thread #7: tid = 0x1bce08, 0x0000000194e1d0c0 libsystem_kernel.dylib`__psynch_cvwait + 8
thread #8: tid = 0x1bce0a, 0x0000000194e1a538 libsystem_kernel.dylib`read + 8
thread #9: tid = 0x1bcf5c, 0x0000000194e1d0c0 libsystem_kernel.dylib`__psynch_cvwait + 8
thread #10: tid = 0x1bcf5d, 0x0000000194e1b604 libsystem_kernel.dylib`__workq_kernreturn + 8
The part of the second profiler log:
00000000001BCE05 1 0000000000000000 BProf::ProfilerAttachComplete // <--- ICorProfilerCallback3::ProfilerAttachComplete
00000000001BCE05 1 0000000000000000 BProf::ProfilerAttachComplete tid=000000015200C000
00000000001BCE05 1 0000000000000000 BPPool::DoThreadRecovered tid=000000015200C000 osTid=001BCE01
00000000001BCE05 1 0000000000000000 BPool::DoThreadRecovered tid=000000015200C000 osTid=001BCE01 (1822209)
00000000001BCE05 1 0000000000000000 BPool::DoThreadRecovered tid=000000015200C000 id=00000001
00000000001BCE05 1 0000000000000000 BProf::ProfilerAttachComplete tid=000000015200C600
00000000001BCE05 1 0000000000000000 BPPool::DoThreadRecovered tid=000000015200C600 osTid=001BCE08
00000000001BCE05 1 0000000000000000 BPool::DoThreadRecovered tid=000000015200C600 osTid=001BCE08 (1822216)
00000000001BCE05 1 0000000000000000 BPool::DoThreadRecovered tid=000000015200C600 id=00000002
00000000001BCE05 1 0000000000000000 BProf::ProfilerAttachComplete tid=0000000131808200
00000000001BCE05 1 0000000000000000 BPPool::DoThreadRecovered tid=0000000131808200 osTid=001BCE0A
00000000001BCE05 1 0000000000000000 BPool::DoThreadRecovered tid=0000000131808200 osTid=001BCE0A (1822218)
00000000001BCE05 1 0000000000000000 BPool::DoThreadRecovered tid=0000000131808200 id=00000003
00000000001BCE05 1 0000000000000000 BProf::ProfilerAttachComplete tid=000000014180AA00 // <--- The dead thread reported here!!!
00000000001BCE05 1 0000000000000000 BPPool::DoThreadRecovered tid=000000014180AA00 osTid=001BCF69
00000000001BCE05 1 0000000000000000 BPool::DoThreadRecovered tid=000000014180AA00 osTid=001BCF69 (1822569)
00000000001BCE05 1 0000000000000000 BPool::DoThreadRecovered tid=000000014180AA00 id=00000004
00000000001BCE05 1 0000000000000000 ERROR: No such thread
Configuration
I reproduced the issue on macOS:
- Catalina x64: .NET v5.0.402 x64
- Big Sur x64: .NET v5.0.402 x64 / v6.0-rc2 x64
- Monterey arm64: .NET v5.0.402 x64 + Rosetta2 / v6.0-rc2 x64 + Rosetta2 / v6.0-rc2 arm64
The Linux x64/arm64 versions work properly.