Skip to content

Commit 753e467

Browse files
authored
[release/9.0-staging] Fix crash during Async Break when APC and CET are enabled (#114932)
* backport 111408 * Fix compilation failure * Fix compilation * trying to fix compilation * Trying to fix compilation
1 parent 794589a commit 753e467

File tree

6 files changed

+90
-8
lines changed

6 files changed

+90
-8
lines changed

src/coreclr/debug/ee/controller.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4312,7 +4312,19 @@ bool DebuggerController::DispatchNativeException(EXCEPTION_RECORD *pException,
43124312
}
43134313
#endif
43144314

4315-
4315+
#ifdef FEATURE_SPECIAL_USER_MODE_APC
4316+
if (pCurThread->m_State & Thread::TS_SSToExitApcCall)
4317+
{
4318+
if (!CheckActivationSafePoint(GetIP(pContext)))
4319+
{
4320+
return FALSE;
4321+
}
4322+
pCurThread->SetThreadState(Thread::TS_SSToExitApcCallDone);
4323+
pCurThread->ResetThreadState(Thread::TS_SSToExitApcCall);
4324+
DebuggerController::UnapplyTraceFlag(pCurThread);
4325+
pCurThread->MarkForSuspensionAndWait(Thread::TS_DebugSuspendPending);
4326+
}
4327+
#endif
43164328

43174329
// Must restore the filter context. After the filter context is gone, we're
43184330
// unprotected again and unsafe for a GC.

src/coreclr/debug/ee/debugger.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15075,6 +15075,14 @@ HRESULT Debugger::FuncEvalSetup(DebuggerIPCE_FuncEvalInfo *pEvalInfo,
1507515075
return CORDBG_E_ILLEGAL_IN_STACK_OVERFLOW;
1507615076
}
1507715077

15078+
#ifdef FEATURE_SPECIAL_USER_MODE_APC
15079+
if (pThread->m_hasPendingActivation)
15080+
{
15081+
_ASSERTE(!"Should never get here with a pending activation. (Debugger::FuncEvalSetup)");
15082+
return CORDBG_E_ILLEGAL_IN_NATIVE_CODE;
15083+
}
15084+
#endif
15085+
1507815086
bool fInException = pEvalInfo->evalDuringException;
1507915087

1508015088
// The thread has to be at a GC safe place for now, just in case the func eval causes a collection. Processing an
@@ -16732,7 +16740,6 @@ Debugger::EnumMemoryRegionsIfFuncEvalFrame(CLRDataEnumMemoryFlags flags, Frame *
1673216740
}
1673316741
}
1673416742
}
16735-
1673616743
#endif // #ifdef DACCESS_COMPILE
1673716744

1673816745
#ifndef DACCESS_COMPILE
@@ -16820,7 +16827,6 @@ void Debugger::SendSetThreadContextNeeded(CONTEXT *context, DebuggerSteppingInfo
1682016827
LOG((LF_CORDB, LL_INFO10000, "D::SSTCN SetThreadContextNeededFlare returned\n"));
1682116828
_ASSERTE(!"We failed to SetThreadContext from out of process!");
1682216829
}
16823-
1682416830
BOOL Debugger::IsOutOfProcessSetContextEnabled()
1682516831
{
1682616832
return m_fOutOfProcessSetContextEnabled;
@@ -16837,6 +16843,16 @@ BOOL Debugger::IsOutOfProcessSetContextEnabled()
1683716843
}
1683816844
#endif // OUT_OF_PROCESS_SETTHREADCONTEXT
1683916845
#endif // DACCESS_COMPILE
16840-
16846+
#ifndef DACCESS_COMPILE
16847+
#ifdef FEATURE_SPECIAL_USER_MODE_APC
16848+
void Debugger::SingleStepToExitApcCall(Thread* pThread, CONTEXT *interruptedContext)
16849+
{
16850+
pThread->SetThreadState(Thread::TS_SSToExitApcCall);
16851+
g_pEEInterface->SetThreadFilterContext(pThread, interruptedContext);
16852+
DebuggerController::EnableSingleStep(pThread);
16853+
g_pEEInterface->SetThreadFilterContext(pThread, NULL);
16854+
}
16855+
#endif //FEATURE_SPECIAL_USER_MODE_APC
16856+
#endif // DACCESS_COMPILE
1684116857
#endif //DEBUGGING_SUPPORTED
1684216858

src/coreclr/debug/ee/debugger.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3098,6 +3098,11 @@ class Debugger : public DebugInterface
30983098
// Used by Debugger::FirstChanceNativeException to update the context from out of process
30993099
void SendSetThreadContextNeeded(CONTEXT *context, DebuggerSteppingInfo *pDebuggerSteppingInfo = NULL);
31003100
BOOL IsOutOfProcessSetContextEnabled();
3101+
#ifndef DACCESS_COMPILE
3102+
#ifdef FEATURE_SPECIAL_USER_MODE_APC
3103+
void SingleStepToExitApcCall(Thread* pThread, CONTEXT *interruptedContext);
3104+
#endif // FEATURE_SPECIAL_USER_MODE_APC
3105+
#endif
31013106
};
31023107

31033108

src/coreclr/vm/dbginterface.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,9 @@ class DebugInterface
414414
#ifndef DACCESS_COMPILE
415415
virtual HRESULT DeoptimizeMethod(Module* pModule, mdMethodDef methodDef) = 0;
416416
virtual HRESULT IsMethodDeoptimized(Module *pModule, mdMethodDef methodDef, BOOL *pResult) = 0;
417+
#ifdef FEATURE_SPECIAL_USER_MODE_APC
418+
virtual void SingleStepToExitApcCall(Thread* pThread, CONTEXT *interruptedContext) = 0;
419+
#endif // FEATURE_SPECIAL_USER_MODE_APC
417420
#endif //DACCESS_COMPILE
418421
};
419422

src/coreclr/vm/threads.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,7 @@ class Thread
489489
friend void STDCALL OnHijackWorker(HijackArgs * pArgs);
490490
#ifdef FEATURE_THREAD_ACTIVATION
491491
friend void HandleSuspensionForInterruptedThread(CONTEXT *interruptedContext);
492+
friend void HandleSuspensionForInterruptedThread(CONTEXT *interruptedContext, bool suspendForDebugger);
492493
friend BOOL CheckActivationSafePoint(SIZE_T ip);
493494
#endif // FEATURE_THREAD_ACTIVATION
494495

@@ -557,7 +558,7 @@ class Thread
557558
TS_Hijacked = 0x00000080, // Return address has been hijacked
558559
#endif // FEATURE_HIJACK
559560

560-
// unused = 0x00000100,
561+
TS_SSToExitApcCall = 0x00000100, // Enable SS and resume the thread to exit an APC Call and keep the thread in suspend state
561562
TS_Background = 0x00000200, // Thread is a background thread
562563
TS_Unstarted = 0x00000400, // Thread has never been started
563564
TS_Dead = 0x00000800, // Thread is dead
@@ -574,7 +575,7 @@ class Thread
574575
TS_ReportDead = 0x00010000, // in WaitForOtherThreads()
575576
TS_FullyInitialized = 0x00020000, // Thread is fully initialized and we are ready to broadcast its existence to external clients
576577

577-
// unused = 0x00040000,
578+
TS_SSToExitApcCallDone = 0x00040000, // The thread exited an APC Call and it is already resumed and paused on SS
578579

579580
TS_SyncSuspended = 0x00080000, // Suspended via WaitSuspendEvent
580581
TS_DebugWillSync = 0x00100000, // Debugger will wait for this thread to sync
@@ -2568,6 +2569,9 @@ class Thread
25682569
// Waiting & Synchronization
25692570
//-------------------------------------------------------------
25702571

2572+
friend class DebuggerController;
2573+
protected:
2574+
void MarkForSuspensionAndWait(ULONG bit);
25712575
// For suspends. The thread waits on this event. A client sets the event to cause
25722576
// the thread to resume.
25732577
void WaitSuspendEvents();

src/coreclr/vm/threadsuspend.cpp

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4238,6 +4238,18 @@ bool Thread::SysSweepThreadsForDebug(bool forceSync)
42384238
if ((thread->m_State & TS_DebugWillSync) == 0)
42394239
continue;
42404240

4241+
#ifdef FEATURE_SPECIAL_USER_MODE_APC
4242+
if (thread->m_State & Thread::TS_SSToExitApcCallDone)
4243+
{
4244+
thread->ResetThreadState(Thread::TS_SSToExitApcCallDone);
4245+
goto Label_MarkThreadAsSynced;
4246+
}
4247+
if (thread->m_State & Thread::TS_SSToExitApcCall)
4248+
{
4249+
continue;
4250+
}
4251+
#endif
4252+
42414253
if (!UseContextBasedThreadRedirection())
42424254
{
42434255
// On platforms that do not support safe thread suspension we either
@@ -5353,6 +5365,19 @@ BOOL Thread::HandledJITCase()
53535365
#endif // FEATURE_HIJACK
53545366

53555367
// Some simple helpers to keep track of the threads we are waiting for
5368+
void Thread::MarkForSuspensionAndWait(ULONG bit)
5369+
{
5370+
CONTRACTL {
5371+
NOTHROW;
5372+
GC_NOTRIGGER;
5373+
}
5374+
CONTRACTL_END;
5375+
m_DebugSuspendEvent.Reset();
5376+
InterlockedOr((LONG*)&m_State, bit);
5377+
ThreadStore::IncrementTrapReturningThreads();
5378+
m_DebugSuspendEvent.Wait(INFINITE,FALSE);
5379+
}
5380+
53565381
void Thread::MarkForSuspension(ULONG bit)
53575382
{
53585383
CONTRACTL {
@@ -5775,7 +5800,7 @@ BOOL CheckActivationSafePoint(SIZE_T ip)
57755800
// address to take the thread to the appropriate stub (based on the return
57765801
// type of the method) which will then handle preparing the thread for GC.
57775802
//
5778-
void HandleSuspensionForInterruptedThread(CONTEXT *interruptedContext)
5803+
void HandleSuspensionForInterruptedThread(CONTEXT *interruptedContext, bool suspendForDebugger)
57795804
{
57805805
struct AutoClearPendingThreadActivation
57815806
{
@@ -5811,6 +5836,18 @@ void HandleSuspensionForInterruptedThread(CONTEXT *interruptedContext)
58115836
if (!codeInfo.IsValid())
58125837
return;
58135838

5839+
#ifdef FEATURE_SPECIAL_USER_MODE_APC
5840+
// It's not allowed to change the IP while paused in an APC Callback for security reasons if CET is turned on
5841+
// So we enable the single step in the thread that is running the APC Callback
5842+
// and then it will be paused using single step exception after exiting the APC callback
5843+
// this will allow the debugger to setIp to execute FuncEvalHijack.
5844+
if (suspendForDebugger)
5845+
{
5846+
g_pDebugInterface->SingleStepToExitApcCall(pThread, interruptedContext);
5847+
return;
5848+
}
5849+
#endif
5850+
58145851
DWORD addrOffset = codeInfo.GetRelOffset();
58155852

58165853
ICodeManager *pEECM = codeInfo.GetCodeManager();
@@ -5886,6 +5923,11 @@ void HandleSuspensionForInterruptedThread(CONTEXT *interruptedContext)
58865923
}
58875924
}
58885925

5926+
void HandleSuspensionForInterruptedThread(CONTEXT *interruptedContext)
5927+
{
5928+
HandleSuspensionForInterruptedThread(interruptedContext, false);
5929+
}
5930+
58895931
#ifdef FEATURE_SPECIAL_USER_MODE_APC
58905932
void Thread::ApcActivationCallback(ULONG_PTR Parameter)
58915933
{
@@ -5915,7 +5957,7 @@ void Thread::ApcActivationCallback(ULONG_PTR Parameter)
59155957
case ActivationReason::SuspendForGC:
59165958
case ActivationReason::SuspendForDebugger:
59175959
case ActivationReason::ThreadAbort:
5918-
HandleSuspensionForInterruptedThread(pContext);
5960+
HandleSuspensionForInterruptedThread(pContext, reason == ActivationReason::SuspendForDebugger);
59195961
break;
59205962

59215963
default:

0 commit comments

Comments
 (0)