Skip to content

Commit

Permalink
Fix Windows Arm64 unwinding
Browse files Browse the repository at this point in the history
There was an issue with unwinding native code functions in case of calls
to no-return function placed at an end of a function code block. The
return address was not in range of the function code, so
RtlLookupFunctionEntry was not finding anything, we were thinking that
it was a leaf function due to that and tried to unwind using LR only,
which was wrong and resulted in staying on the same instruction. Thus
the unwinding ended up in an infinite loop for those cases.
The fix, that matches what RtlUnwind does, is to adjust the instruction
pointer at call sites back. This is arm64 specific.

Close dotnet#101921
  • Loading branch information
janvorli committed May 15, 2024
1 parent ddff593 commit a7e2509
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 51 deletions.
73 changes: 24 additions & 49 deletions src/coreclr/vm/stackwalk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,13 @@ PCODE Thread::VirtualUnwindCallFrame(T_CONTEXT* pContext,
UINT_PTR uImageBase;
PT_RUNTIME_FUNCTION pFunctionEntry;

#if !defined(TARGET_UNIX) && defined(CONTEXT_UNWOUND_TO_CALL)
if ((pContext->ContextFlags & CONTEXT_UNWOUND_TO_CALL) != 0)
{
uControlPc -= STACKWALK_CONTROLPC_ADJUST_OFFSET;
}
#endif // !TARGET_UNIX && CONTEXT_UNWOUND_TO_CALL

if (pCodeInfo == NULL)
{
#ifndef TARGET_UNIX
Expand Down Expand Up @@ -592,7 +599,23 @@ PCODE Thread::VirtualUnwindCallFrame(T_CONTEXT* pContext,

if (pFunctionEntry)
{
uControlPc = VirtualUnwindNonLeafCallFrame(pContext, pContextPointers, pFunctionEntry, uImageBase);
#ifdef HOST_64BIT
UINT64 EstablisherFrame;
#else // HOST_64BIT
DWORD EstablisherFrame;
#endif // HOST_64BIT
PVOID HandlerData;

RtlVirtualUnwind(0,
uImageBase,
uControlPc,
pFunctionEntry,
pContext,
&HandlerData,
&EstablisherFrame,
pContextPointers);

uControlPc = GetIP(pContext);
}
else
{
Expand Down Expand Up @@ -661,54 +684,6 @@ PCODE Thread::VirtualUnwindLeafCallFrame(T_CONTEXT* pContext)
return uControlPc;
}

// static
PCODE Thread::VirtualUnwindNonLeafCallFrame(T_CONTEXT* pContext, KNONVOLATILE_CONTEXT_POINTERS* pContextPointers,
PT_RUNTIME_FUNCTION pFunctionEntry, UINT_PTR uImageBase)
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
PRECONDITION(CheckPointer(pContext, NULL_NOT_OK));
PRECONDITION(CheckPointer(pContextPointers, NULL_OK));
PRECONDITION(CheckPointer(pFunctionEntry, NULL_OK));
}
CONTRACTL_END;

PCODE uControlPc = GetIP(pContext);
#ifdef HOST_64BIT
UINT64 EstablisherFrame;
#else // HOST_64BIT
DWORD EstablisherFrame;
#endif // HOST_64BIT
PVOID HandlerData;

if (NULL == pFunctionEntry)
{
#ifndef TARGET_UNIX
pFunctionEntry = RtlLookupFunctionEntry(uControlPc,
ARM_ONLY((DWORD*))(&uImageBase),
NULL);
#endif
if (NULL == pFunctionEntry)
{
return (PCODE)NULL;
}
}

RtlVirtualUnwind(0,
uImageBase,
uControlPc,
pFunctionEntry,
pContext,
&HandlerData,
&EstablisherFrame,
pContextPointers);

uControlPc = GetIP(pContext);
return uControlPc;
}

extern void* g_hostingApiReturnAddress;

// static
Expand Down
2 changes: 0 additions & 2 deletions src/coreclr/vm/threads.h
Original file line number Diff line number Diff line change
Expand Up @@ -2369,8 +2369,6 @@ class Thread
static UINT_PTR VirtualUnwindCallFrame(PREGDISPLAY pRD, EECodeInfo * pCodeInfo = NULL);
#ifndef DACCESS_COMPILE
static PCODE VirtualUnwindLeafCallFrame(T_CONTEXT* pContext);
static PCODE VirtualUnwindNonLeafCallFrame(T_CONTEXT* pContext, T_KNONVOLATILE_CONTEXT_POINTERS* pContextPointers = NULL,
PT_RUNTIME_FUNCTION pFunctionEntry = NULL, UINT_PTR uImageBase = 0);
static UINT_PTR VirtualUnwindToFirstManagedCallFrame(T_CONTEXT* pContext);
#endif // DACCESS_COMPILE
#endif // FEATURE_EH_FUNCLETS
Expand Down

0 comments on commit a7e2509

Please sign in to comment.