From 1c7ab4c531d4bb5bebe3774f9da4a4f3d6118b44 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 1 May 2026 05:32:21 +0000 Subject: [PATCH 1/3] Initial plan From 39bc3ada1abd02c945359df5c2d31d44fc463bb4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 1 May 2026 05:51:16 +0000 Subject: [PATCH 2/3] Fix !m_RedirectContextInUse assert on win-x86: replace HandleThreadAbort() with COMPlusCheckForAbort() in RestoreContextSimulated Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/8fa490ef-11e1-443a-bf1d-8d2d2dc09add Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/threadsuspend.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/coreclr/vm/threadsuspend.cpp b/src/coreclr/vm/threadsuspend.cpp index f265094ce9876a..1c6db552cdeb0a 100644 --- a/src/coreclr/vm/threadsuspend.cpp +++ b/src/coreclr/vm/threadsuspend.cpp @@ -2586,7 +2586,21 @@ extern "C" PCONTEXT __stdcall GetCurrentSavedRedirectContext() void Thread::RestoreContextSimulated(Thread* pThread, CONTEXT* pCtx, void* pFrame, DWORD dwLastError) { - pThread->HandleThreadAbort(); // Might throw an exception. + // Check for a pending abort and redirect pCtx to the abort handler if needed. + // This matches the non-x86 approach in RedirectedHandledJITCase: instead of calling + // HandleThreadAbort() directly (which runs managed code while the redirect context is + // still in use and could trigger a 2nd redirect asserting !m_RedirectContextInUse), + // we use COMPlusCheckForAbort() (NOTHROW/GC_NOTRIGGER) to get the abort handler + // address and redirect pCtx to it. The abort exception is then raised after context + // has been restored and the redirect context is no longer in use. + UINT_PTR uResumePC = (UINT_PTR)GetIP(pCtx); + CopyOSContext(pThread->m_OSContext, pCtx); + UINT_PTR uAbortAddr = (UINT_PTR)COMPlusCheckForAbort(); + if (uAbortAddr) + { + SetIP(pThread->m_OSContext, uResumePC); + SetIP(pCtx, uAbortAddr); + } // A counter to avoid a nasty case where an // up-stack filter throws another exception From f33ab32bd81abf40560cce9c715cb5d37a61b5b9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 1 May 2026 19:08:36 +0000 Subject: [PATCH 3/3] Refactor: move RestoreContextSimulated call after abort check in RedirectedHandledJITCase Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/c055bf10-808a-4e92-9cee-1841d7cfd155 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- src/coreclr/vm/threadsuspend.cpp | 36 +++++++++----------------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/src/coreclr/vm/threadsuspend.cpp b/src/coreclr/vm/threadsuspend.cpp index 1c6db552cdeb0a..b2e81e569ea905 100644 --- a/src/coreclr/vm/threadsuspend.cpp +++ b/src/coreclr/vm/threadsuspend.cpp @@ -2586,22 +2586,6 @@ extern "C" PCONTEXT __stdcall GetCurrentSavedRedirectContext() void Thread::RestoreContextSimulated(Thread* pThread, CONTEXT* pCtx, void* pFrame, DWORD dwLastError) { - // Check for a pending abort and redirect pCtx to the abort handler if needed. - // This matches the non-x86 approach in RedirectedHandledJITCase: instead of calling - // HandleThreadAbort() directly (which runs managed code while the redirect context is - // still in use and could trigger a 2nd redirect asserting !m_RedirectContextInUse), - // we use COMPlusCheckForAbort() (NOTHROW/GC_NOTRIGGER) to get the abort handler - // address and redirect pCtx to it. The abort exception is then raised after context - // has been restored and the redirect context is no longer in use. - UINT_PTR uResumePC = (UINT_PTR)GetIP(pCtx); - CopyOSContext(pThread->m_OSContext, pCtx); - UINT_PTR uAbortAddr = (UINT_PTR)COMPlusCheckForAbort(); - if (uAbortAddr) - { - SetIP(pThread->m_OSContext, uResumePC); - SetIP(pCtx, uAbortAddr); - } - // A counter to avoid a nasty case where an // up-stack filter throws another exception // causing our filter to be run again for @@ -2686,16 +2670,6 @@ void __stdcall Thread::RedirectedHandledJITCase(RedirectReason reason) // We will restore the state as it was at the point of redirection // and continue normal execution. -#ifdef TARGET_X86 - if (!g_pfnRtlRestoreContext) - { - RestoreContextSimulated(pThread, pCtx, &frame, dwLastError); - - // we never return to the caller. - UNREACHABLE(); - } -#endif // TARGET_X86 - UINT_PTR uAbortAddr; UINT_PTR uResumePC = (UINT_PTR)GetIP(pCtx); CopyOSContext(pThread->m_OSContext, pCtx); @@ -2721,6 +2695,16 @@ void __stdcall Thread::RedirectedHandledJITCase(RedirectReason reason) SetIP(pCtx, uAbortAddr); } +#ifdef TARGET_X86 + if (!g_pfnRtlRestoreContext) + { + RestoreContextSimulated(pThread, pCtx, &frame, dwLastError); + + // we never return to the caller. + UNREACHABLE(); + } +#endif // TARGET_X86 + // Unlink the frame in preparation for resuming in managed code frame.Pop();