Skip to content

Commit 463efbb

Browse files
authored
Fix debugger funceval deadlock (#72179)
Fixes #60565 Visual Studio devs reported that debugger funcevals were deadlocking because the PinnedHeapHandleTableCrst was held while threads were suspended. This change refactors that code path so that the AllocateHandles() operation where the lock is held gets split into two parts and the GC allocation where the debugger could suspend is outside the region where the critical section is held. In the old code the PinnedHeapHandleTable was synchronized by one of two different locks, either the AppDomainHandleTable lock or the GlobalStringLiteralMap. In the new code AppDomainHandleTable lock is renamed to PinnedHeapHandleTable lock and this lock is always what synchronizes the PinnedHeapHandleTable code. In the string literal code path the GlobalStringLiteralMap is taken first and the PinnedHeapHandleTable lock is taken second, but the PinnedHeapHandleTable is no longer reliant on that outer GlobalStringLiteralMap lock for correctness. In terms of testing I can verify under a debugger that I can suspend in the GC allocation point and the PinnedHeapHandleTable lock isn't held. This doesn't of course prevent other locks from being held so at best it is a partial fix for the issue. Nobody had a known repro so I wasn't able to verify anything more specifically. I also confirmed the race cases on the InterlockedExchange paths worked how they were intended by forcing them with a native debugger.
1 parent 5097317 commit 463efbb

File tree

5 files changed

+216
-284
lines changed

5 files changed

+216
-284
lines changed

src/coreclr/inc/CrstTypes.def

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ Crst AppDomainCache
7777
AcquiredBefore UniqueStack UnresolvedClassLock
7878
End
7979

80-
Crst AppDomainHandleTable
80+
Crst PinnedHeapHandleTable
8181
AcquiredBefore AvailableParamTypes HandleTable IbcProfile SyncBlockCache SystemDomainDelayedUnloadList
82-
ThreadStore SystemDomain
82+
SystemDomain
8383
End
8484

8585
Crst ArgBasedStubCache
@@ -185,7 +185,7 @@ Crst DelegateToFPtrHash
185185
End
186186

187187
Crst DomainLocalBlock
188-
AcquiredBefore AppDomainHandleTable IbcProfile LoaderHeap SystemDomainDelayedUnloadList UniqueStack
188+
AcquiredBefore PinnedHeapHandleTable IbcProfile LoaderHeap SystemDomainDelayedUnloadList UniqueStack
189189
End
190190

191191
Crst DynamicIL
@@ -230,7 +230,7 @@ Crst GCCover
230230
End
231231

232232
Crst GlobalStrLiteralMap
233-
AcquiredBefore HandleTable IbcProfile SyncBlockCache SystemDomainDelayedUnloadList ThreadStore UniqueStack
233+
AcquiredBefore PinnedHeapHandleTable HandleTable IbcProfile SyncBlockCache SystemDomainDelayedUnloadList ThreadStore UniqueStack
234234
End
235235

236236
Crst HandleTable
@@ -256,7 +256,7 @@ Crst InstMethodHashTable
256256
End
257257

258258
Crst Interop
259-
AcquiredBefore AppDomainHandleTable AvailableParamTypes ClassInit DeadlockDetection DomainLocalBlock
259+
AcquiredBefore PinnedHeapHandleTable AvailableParamTypes ClassInit DeadlockDetection DomainLocalBlock
260260
HandleTable InstMethodHashTable InteropData JitGenericHandleCache LoaderHeap SigConvert
261261
StubDispatchCache StubUnwindInfoHeapSegments SyncBlockCache TypeIDMap UnresolvedClassLock
262262
PendingTypeLoadEntry
@@ -305,7 +305,7 @@ Crst LeafLock
305305
End
306306

307307
Crst LoaderAllocator
308-
AcquiredBefore AppDomainHandleTable HandleTable UniqueStack ThreadStore
308+
AcquiredBefore PinnedHeapHandleTable HandleTable UniqueStack ThreadStore
309309
AcquiredAfter DomainLocalBlock
310310
End
311311

@@ -334,7 +334,7 @@ Crst Module
334334
End
335335

336336
Crst ModuleFixup
337-
AcquiredBefore AppDomainHandleTable GlobalStrLiteralMap IbcProfile SyncBlockCache
337+
AcquiredBefore PinnedHeapHandleTable GlobalStrLiteralMap IbcProfile SyncBlockCache
338338
End
339339

340340
Crst ModuleLookupTable
@@ -353,7 +353,7 @@ Crst PEImage
353353
End
354354

355355
Crst PendingTypeLoadEntry
356-
AcquiredBefore AppDomainCache AppDomainHandleTable AssemblyLoader AvailableClass AvailableParamTypes
356+
AcquiredBefore AppDomainCache PinnedHeapHandleTable AssemblyLoader AvailableClass AvailableParamTypes
357357
BaseDomain ClassInit DeadlockDetection DebuggerController DebuggerJitInfo DebuggerMutex
358358
DomainLocalBlock Exception ExecuteManRangeLock FuncPtrStubs
359359
FusionAppCtx GlobalStrLiteralMap HandleTable IbcProfile

src/coreclr/inc/crsttypes.h

Lines changed: 83 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -16,85 +16,85 @@
1616
enum CrstType
1717
{
1818
CrstAppDomainCache = 0,
19-
CrstAppDomainHandleTable = 1,
20-
CrstArgBasedStubCache = 2,
21-
CrstAssemblyList = 3,
22-
CrstAssemblyLoader = 4,
23-
CrstAvailableClass = 5,
24-
CrstAvailableParamTypes = 6,
25-
CrstBaseDomain = 7,
26-
CrstCCompRC = 8,
27-
CrstClassFactInfoHash = 9,
28-
CrstClassInit = 10,
29-
CrstClrNotification = 11,
30-
CrstCodeFragmentHeap = 12,
31-
CrstCodeVersioning = 13,
32-
CrstCOMCallWrapper = 14,
33-
CrstCOMWrapperCache = 15,
34-
CrstDataTest1 = 16,
35-
CrstDataTest2 = 17,
36-
CrstDbgTransport = 18,
37-
CrstDeadlockDetection = 19,
38-
CrstDebuggerController = 20,
39-
CrstDebuggerFavorLock = 21,
40-
CrstDebuggerHeapExecMemLock = 22,
41-
CrstDebuggerHeapLock = 23,
42-
CrstDebuggerJitInfo = 24,
43-
CrstDebuggerMutex = 25,
44-
CrstDelegateToFPtrHash = 26,
45-
CrstDomainLocalBlock = 27,
46-
CrstDynamicIL = 28,
47-
CrstDynamicMT = 29,
48-
CrstEtwTypeLogHash = 30,
49-
CrstEventPipe = 31,
50-
CrstEventStore = 32,
51-
CrstException = 33,
52-
CrstExecutableAllocatorLock = 34,
53-
CrstExecuteManRangeLock = 35,
54-
CrstExternalObjectContextCache = 36,
55-
CrstFCall = 37,
56-
CrstFuncPtrStubs = 38,
57-
CrstFusionAppCtx = 39,
58-
CrstGCCover = 40,
59-
CrstGlobalStrLiteralMap = 41,
60-
CrstHandleTable = 42,
61-
CrstIbcProfile = 43,
62-
CrstIJWFixupData = 44,
63-
CrstIJWHash = 45,
64-
CrstILStubGen = 46,
65-
CrstInlineTrackingMap = 47,
66-
CrstInstMethodHashTable = 48,
67-
CrstInterop = 49,
68-
CrstInteropData = 50,
69-
CrstIsJMCMethod = 51,
70-
CrstISymUnmanagedReader = 52,
71-
CrstJit = 53,
72-
CrstJitGenericHandleCache = 54,
73-
CrstJitInlineTrackingMap = 55,
74-
CrstJitPatchpoint = 56,
75-
CrstJitPerf = 57,
76-
CrstJumpStubCache = 58,
77-
CrstLeafLock = 59,
78-
CrstListLock = 60,
79-
CrstLoaderAllocator = 61,
80-
CrstLoaderAllocatorReferences = 62,
81-
CrstLoaderHeap = 63,
82-
CrstManagedObjectWrapperMap = 64,
83-
CrstMethodDescBackpatchInfoTracker = 65,
84-
CrstModule = 66,
85-
CrstModuleFixup = 67,
86-
CrstModuleLookupTable = 68,
87-
CrstMulticoreJitHash = 69,
88-
CrstMulticoreJitManager = 70,
89-
CrstNativeImageEagerFixups = 71,
90-
CrstNativeImageLoad = 72,
91-
CrstNls = 73,
92-
CrstNotifyGdb = 74,
93-
CrstObjectList = 75,
94-
CrstPEImage = 76,
95-
CrstPendingTypeLoadEntry = 77,
96-
CrstPgoData = 78,
97-
CrstPinnedByrefValidation = 79,
19+
CrstArgBasedStubCache = 1,
20+
CrstAssemblyList = 2,
21+
CrstAssemblyLoader = 3,
22+
CrstAvailableClass = 4,
23+
CrstAvailableParamTypes = 5,
24+
CrstBaseDomain = 6,
25+
CrstCCompRC = 7,
26+
CrstClassFactInfoHash = 8,
27+
CrstClassInit = 9,
28+
CrstClrNotification = 10,
29+
CrstCodeFragmentHeap = 11,
30+
CrstCodeVersioning = 12,
31+
CrstCOMCallWrapper = 13,
32+
CrstCOMWrapperCache = 14,
33+
CrstDataTest1 = 15,
34+
CrstDataTest2 = 16,
35+
CrstDbgTransport = 17,
36+
CrstDeadlockDetection = 18,
37+
CrstDebuggerController = 19,
38+
CrstDebuggerFavorLock = 20,
39+
CrstDebuggerHeapExecMemLock = 21,
40+
CrstDebuggerHeapLock = 22,
41+
CrstDebuggerJitInfo = 23,
42+
CrstDebuggerMutex = 24,
43+
CrstDelegateToFPtrHash = 25,
44+
CrstDomainLocalBlock = 26,
45+
CrstDynamicIL = 27,
46+
CrstDynamicMT = 28,
47+
CrstEtwTypeLogHash = 29,
48+
CrstEventPipe = 30,
49+
CrstEventStore = 31,
50+
CrstException = 32,
51+
CrstExecutableAllocatorLock = 33,
52+
CrstExecuteManRangeLock = 34,
53+
CrstExternalObjectContextCache = 35,
54+
CrstFCall = 36,
55+
CrstFuncPtrStubs = 37,
56+
CrstFusionAppCtx = 38,
57+
CrstGCCover = 39,
58+
CrstGlobalStrLiteralMap = 40,
59+
CrstHandleTable = 41,
60+
CrstIbcProfile = 42,
61+
CrstIJWFixupData = 43,
62+
CrstIJWHash = 44,
63+
CrstILStubGen = 45,
64+
CrstInlineTrackingMap = 46,
65+
CrstInstMethodHashTable = 47,
66+
CrstInterop = 48,
67+
CrstInteropData = 49,
68+
CrstIsJMCMethod = 50,
69+
CrstISymUnmanagedReader = 51,
70+
CrstJit = 52,
71+
CrstJitGenericHandleCache = 53,
72+
CrstJitInlineTrackingMap = 54,
73+
CrstJitPatchpoint = 55,
74+
CrstJitPerf = 56,
75+
CrstJumpStubCache = 57,
76+
CrstLeafLock = 58,
77+
CrstListLock = 59,
78+
CrstLoaderAllocator = 60,
79+
CrstLoaderAllocatorReferences = 61,
80+
CrstLoaderHeap = 62,
81+
CrstManagedObjectWrapperMap = 63,
82+
CrstMethodDescBackpatchInfoTracker = 64,
83+
CrstModule = 65,
84+
CrstModuleFixup = 66,
85+
CrstModuleLookupTable = 67,
86+
CrstMulticoreJitHash = 68,
87+
CrstMulticoreJitManager = 69,
88+
CrstNativeImageEagerFixups = 70,
89+
CrstNativeImageLoad = 71,
90+
CrstNls = 72,
91+
CrstNotifyGdb = 73,
92+
CrstObjectList = 74,
93+
CrstPEImage = 75,
94+
CrstPendingTypeLoadEntry = 76,
95+
CrstPgoData = 77,
96+
CrstPinnedByrefValidation = 78,
97+
CrstPinnedHeapHandleTable = 79,
9898
CrstProfilerGCRefDataFreeList = 80,
9999
CrstProfilingAPIStatus = 81,
100100
CrstRCWCache = 82,
@@ -146,7 +146,6 @@ enum CrstType
146146
int g_rgCrstLevelMap[] =
147147
{
148148
10, // CrstAppDomainCache
149-
14, // CrstAppDomainHandleTable
150149
3, // CrstArgBasedStubCache
151150
0, // CrstAssemblyList
152151
12, // CrstAssemblyLoader
@@ -186,7 +185,7 @@ int g_rgCrstLevelMap[] =
186185
7, // CrstFuncPtrStubs
187186
10, // CrstFusionAppCtx
188187
10, // CrstGCCover
189-
13, // CrstGlobalStrLiteralMap
188+
15, // CrstGlobalStrLiteralMap
190189
1, // CrstHandleTable
191190
0, // CrstIbcProfile
192191
8, // CrstIJWFixupData
@@ -212,7 +211,7 @@ int g_rgCrstLevelMap[] =
212211
3, // CrstManagedObjectWrapperMap
213212
10, // CrstMethodDescBackpatchInfoTracker
214213
5, // CrstModule
215-
15, // CrstModuleFixup
214+
16, // CrstModuleFixup
216215
4, // CrstModuleLookupTable
217216
0, // CrstMulticoreJitHash
218217
13, // CrstMulticoreJitManager
@@ -225,6 +224,7 @@ int g_rgCrstLevelMap[] =
225224
19, // CrstPendingTypeLoadEntry
226225
4, // CrstPgoData
227226
0, // CrstPinnedByrefValidation
227+
14, // CrstPinnedHeapHandleTable
228228
0, // CrstProfilerGCRefDataFreeList
229229
13, // CrstProfilingAPIStatus
230230
4, // CrstRCWCache
@@ -270,7 +270,6 @@ int g_rgCrstLevelMap[] =
270270
LPCSTR g_rgCrstNameMap[] =
271271
{
272272
"CrstAppDomainCache",
273-
"CrstAppDomainHandleTable",
274273
"CrstArgBasedStubCache",
275274
"CrstAssemblyList",
276275
"CrstAssemblyLoader",
@@ -349,6 +348,7 @@ LPCSTR g_rgCrstNameMap[] =
349348
"CrstPendingTypeLoadEntry",
350349
"CrstPgoData",
351350
"CrstPinnedByrefValidation",
351+
"CrstPinnedHeapHandleTable",
352352
"CrstProfilerGCRefDataFreeList",
353353
"CrstProfilingAPIStatus",
354354
"CrstRCWCache",

0 commit comments

Comments
 (0)