Skip to content

Commit

Permalink
Remove CONTEXT_XSTATE in FaultingExceptionFrame::UpdateRegDisplay (#1…
Browse files Browse the repository at this point in the history
…05569)

* Remove CONTEXT_XSTATE in FaultingExceptionFrame::UpdateRegDisplay

There is a bug in updating REGDISPLAY from a faulting exception frame.
The context stored in the frame can contain extended state, but we only
copy the basic CONTEXT part. But we are not removing the CONTEXT_XSTATE
flag. There was an issue found on arm64 Windows with SVE enabled. The
context from a hardware exception contains the SVE extended state and
when we resume after catch for the exception or start propagating it
through native frames, the RtlRestoreContext probably uses some garbage
to try to restore the extended state and ends up corrupting memory.

The fix is to remove the CONTEXT_XSTATE flag from the context after we
copy it to the REGDISPLAY.

While we have hit this problem on Windows ARM64 with SVE only, I have
made the same change for other targets that can have extended state too.

Close #105483

* Move the CONTEXT_XSTATE definition to clrnt.h

---------

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
  • Loading branch information
janvorli and jkotas authored Jul 27, 2024
1 parent 4c3edd5 commit 827c834
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 20 deletions.
18 changes: 18 additions & 0 deletions src/coreclr/inc/clrnt.h
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,24 @@ RtlVirtualUnwind(
IN OUT PKNONVOLATILE_CONTEXT_POINTERS ContextPointers OPTIONAL
);

// Mirror the XSTATE_ARM64_SVE flags from winnt.h

#ifndef XSTATE_ARM64_SVE
#define XSTATE_ARM64_SVE (2)
#endif // XSTATE_ARM64_SVE

#ifndef XSTATE_MASK_ARM64_SVE
#define XSTATE_MASK_ARM64_SVE (1ui64 << (XSTATE_ARM64_SVE))
#endif // XSTATE_MASK_ARM64_SVE

#ifndef CONTEXT_ARM64_XSTATE
#define CONTEXT_ARM64_XSTATE (CONTEXT_ARM64 | 0x20L)
#endif // CONTEXT_ARM64_XSTATE

#ifndef CONTEXT_XSTATE
#define CONTEXT_XSTATE CONTEXT_ARM64_XSTATE
#endif // CONTEXT_XSTATE

#endif

#ifdef TARGET_LOONGARCH64
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/vm/amd64/cgenamd64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool update

memcpy(pRD->pCurrentContext, &m_ctx, sizeof(CONTEXT));

// Clear the CONTEXT_XSTATE, since the REGDISPLAY contains just plain CONTEXT structure
// that cannot contain any extended state.
pRD->pCurrentContext->ContextFlags &= ~CONTEXT_XSTATE;

pRD->ControlPC = m_ctx.Rip;

pRD->SP = m_ctx.Rsp;
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/vm/arm64/stubs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,10 @@ void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool update
// Copy the context to regdisplay
memcpy(pRD->pCurrentContext, &m_ctx, sizeof(T_CONTEXT));

// Clear the CONTEXT_XSTATE, since the REGDISPLAY contains just plain CONTEXT structure
// that cannot contain any extended state.
pRD->pCurrentContext->ContextFlags &= ~CONTEXT_XSTATE;

pRD->ControlPC = ::GetIP(&m_ctx);
pRD->SP = ::GetSP(&m_ctx);

Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/vm/i386/cgenx86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,10 @@ void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool update

memcpy(pRD->pCurrentContext, &m_ctx, sizeof(CONTEXT));

// Clear the CONTEXT_XSTATE, since the REGDISPLAY contains just plain CONTEXT structure
// that cannot contain any extended state.
pRD->pCurrentContext->ContextFlags &= ~CONTEXT_XSTATE;

pRD->SP = m_ctx.Esp;
pRD->ControlPC = m_ctx.Eip;

Expand Down
20 changes: 0 additions & 20 deletions src/coreclr/vm/threadsuspend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,6 @@ ThreadSuspend::SUSPEND_REASON ThreadSuspend::m_suspendReason;
void* ThreadSuspend::g_returnAddressHijackTarget = NULL;
#endif // TARGET_WINDOWS

#if defined(TARGET_ARM64)
// Mirror the XSTATE_ARM64_SVE flags from winnt.h

#ifndef XSTATE_ARM64_SVE
#define XSTATE_ARM64_SVE (2)
#endif // XSTATE_ARM64_SVE

#ifndef XSTATE_MASK_ARM64_SVE
#define XSTATE_MASK_ARM64_SVE (1ui64 << (XSTATE_ARM64_SVE))
#endif // XSTATE_MASK_ARM64_SVE

#ifndef CONTEXT_ARM64_XSTATE
#define CONTEXT_ARM64_XSTATE (CONTEXT_ARM64 | 0x20L)
#endif // CONTEXT_ARM64_XSTATE

#ifndef CONTEXT_XSTATE
#define CONTEXT_XSTATE CONTEXT_ARM64_XSTATE
#endif // CONTEXT_XSTATE
#endif // TARGET_ARM64

// If you add any thread redirection function, make sure the debugger can 1) recognize the redirection
// function, and 2) retrieve the original CONTEXT. See code:Debugger.InitializeHijackFunctionAddress and
// code:DacDbiInterfaceImpl.RetrieveHijackedContext.
Expand Down

0 comments on commit 827c834

Please sign in to comment.