You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Interpreter] ResumeAfterCatchException escapes ThrowControlForThread when compiled code raises a thread abort again and an interpreted frame catches it #135532
With DOTNET_InterpMode=1 (user code interpreted, CoreLib compiled), a ControlledExecution action that cancels itself crashes the process:
linux-x64 and osx-arm64 (Checked): terminate called after throwing an instance of 'ResumeAfterCatchException'
windows-x64 (Checked): an assert in exception handling
This is the case of ControlledExecutionTests.CancelItselfOutsideOfTryCatchFinally, which has been disabled since #122308. It is separate from #135463 (fixed by #135520): it still fails with that fix, and #135520's test does not cover it.
CancellationTokenSource.Cancel (compiled) catches the ThreadAbortException, and at the end of that catch EECodeManager::ResumeAfterCatch raises it again through ThrowControlForThread. The abort is then caught by an interpreted frame further up (ControlledExecution.Run translates it, or the user's catch). Resuming in an interpreted frame unwinds the native frames with a C++ ResumeAfterCatchException. Other places that start a dispatch on top of managed frames catch it and rethrow it past those frames with INSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_CONTEXT (IL_Throw, HandleManagedFault), but ThrowControlForThread does not, so the exception runs into the managed frames the thread was redirected from.
Adding that handler fixes linux-x64 and osx-arm64. On windows-x64 with shadow stacks it then asserts *(ULONG64*)targetSSP == pContext->Rip in ExecuteFunctionBelowContext. RethrowResumeAfterCatchExceptionSkipManagedFrames searches for a "precise" SSP on the assumption that the slot below the SSP holds a return address in the context's frame. The SSP that RedirectForThrowControl records belongs to a frame that was interrupted, not stopped at a call, so that slot is stale and the search moves one slot too far. The same mismatch is behind #135530.
I have a fix that adds the handler and tells it that the context was interrupted, so it uses the SSP as it is. With it and #135520, the case above passes under DOTNET_InterpMode 1, 2 and 3 on linux-x64, osx-arm64 and windows-x64 (Checked, CET enabled on Windows). I'll open it as a draft PR stacked on #135520.
Note
This issue was prepared with AI assistance (Anthropic Claude).
Activity
dotnet-policy-service commentedon Oct 9, 2026
Tagging subscribers to this area: @agocke
See info in area-owners.md if you want to be subscribed.
dotnet-policy-service commentedon Oct 9, 2026
Tagging subscribers to this area: @JulieLeeMSFT, @BrzVlad, @janvorli
See info in area-owners.md if you want to be subscribed.