From ad78d2b49327a85b58e9944cf9c876e5b96d6273 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Thu, 9 Oct 2025 00:18:21 +0200 Subject: [PATCH] Fix ARM64 ThreadAbort issue There is a problem with RtlRestoreContext not restoring context during ThreadAbort if that abort comes from injected APC callback on ARM64 and the processor supports SVE. In that case, the context provided by the APC callback can contain XSTATE and when we start walking stack from that context, we copy that context into the REGDISPLAY. The problem is that we copy the ContextFlags without changes, so if they contained CONTEXT_XSTATE flag, it is kept set even though the REGDISPLAY has only plain old CONTEXT without any xstate. When we call RtlRestoreContext in the ResumeAfterCatch, it fails because the XSTATE is not valid and so it returns. That's unexpected and we end up crashing with an assert. The fix clears the CONTEXT_XSTATE in ResumableFrame::UpdateRegDisplay so that the REGDISPLAY ContextFlags are validly representing the context. Close #120437 --- src/coreclr/vm/amd64/cgenamd64.cpp | 2 ++ src/coreclr/vm/arm64/stubs.cpp | 2 ++ src/coreclr/vm/threads.cpp | 1 + 3 files changed, 5 insertions(+) diff --git a/src/coreclr/vm/amd64/cgenamd64.cpp b/src/coreclr/vm/amd64/cgenamd64.cpp index 25309827d6214c..9cdb3c67560b86 100644 --- a/src/coreclr/vm/amd64/cgenamd64.cpp +++ b/src/coreclr/vm/amd64/cgenamd64.cpp @@ -207,6 +207,8 @@ void ResumableFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFlo CONTRACT_END; CopyMemory(pRD->pCurrentContext, m_Regs, sizeof(CONTEXT)); + // Clear the CONTEXT_XSTATE, since the REGDISPLAY contains just plain CONTEXT structure + pRD->pCurrentContext->ContextFlags &= ~(CONTEXT_XSTATE & CONTEXT_AREA_MASK); pRD->ControlPC = m_Regs->Rip; diff --git a/src/coreclr/vm/arm64/stubs.cpp b/src/coreclr/vm/arm64/stubs.cpp index c9b1f468d480df..3f1a5dc78f7cc3 100644 --- a/src/coreclr/vm/arm64/stubs.cpp +++ b/src/coreclr/vm/arm64/stubs.cpp @@ -350,6 +350,8 @@ void ResumableFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFlo CONTRACT_END; CopyMemory(pRD->pCurrentContext, m_Regs, sizeof(T_CONTEXT)); + // Clear the CONTEXT_XSTATE, since the REGDISPLAY contains just plain CONTEXT structure + pRD->pCurrentContext->ContextFlags &= ~(CONTEXT_XSTATE & CONTEXT_AREA_MASK); pRD->ControlPC = m_Regs->Pc; pRD->SP = m_Regs->Sp; diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp index fa2eedac5db392..509f5215747d46 100644 --- a/src/coreclr/vm/threads.cpp +++ b/src/coreclr/vm/threads.cpp @@ -7685,6 +7685,7 @@ void ClrRestoreNonvolatileContext(PCONTEXT ContextRecord, size_t targetSSP) // Falling back to RtlRestoreContext() for now, though it should be possible to have simpler variants for these cases RtlRestoreContext(ContextRecord, NULL); #endif + UNREACHABLE(); } #ifdef FEATURE_INTERPRETER