Skip to content

Commit

Permalink
Revert "Display stack trace at stack overflow (#31956)" (#32153)
Browse files Browse the repository at this point in the history
This reverts commit 65587ba.
  • Loading branch information
safern committed Feb 12, 2020
1 parent fff8f5a commit 90e9614
Show file tree
Hide file tree
Showing 28 changed files with 133 additions and 391 deletions.
2 changes: 1 addition & 1 deletion src/coreclr/src/debug/ee/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8961,7 +8961,7 @@ bool DebuggerContinuableExceptionBreakpoint::SendEvent(Thread *thread, bool fIpC
CONTEXT contextToAdjust;
BOOL adjustedContext = FALSE;
memcpy(&contextToAdjust, pContext, sizeof(CONTEXT));
adjustedContext = g_pEEInterface->AdjustContextForJITHelpersForDebugger(&contextToAdjust);
adjustedContext = g_pEEInterface->AdjustContextForWriteBarrierForDebugger(&contextToAdjust);
if (adjustedContext)
{
LOG((LF_CORDB, LL_INFO10000, "D::DDBP: HIT DATA BREAKPOINT INSIDE WRITE BARRIER...\n"));
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/src/inc/ex.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ void GenerateTopLevelHRExceptionMessage(HRESULT hresult, SString &result);
// We save current ExceptionPointers using VectoredExceptionHandler. The save data is only valid
// duing exception handling. GetCurrentExceptionPointers returns the saved data.
// ---------------------------------------------------------------------------
void GetCurrentExceptionPointers(PEXCEPTION_POINTERS pExceptionInfo DEBUG_ARG(bool checkExceptionRecordLocation));
void GetCurrentExceptionPointers(PEXCEPTION_POINTERS pExceptionInfo);

// ---------------------------------------------------------------------------
// We save current ExceptionPointers using VectoredExceptionHandler. The save data is only valid
Expand Down
20 changes: 7 additions & 13 deletions src/coreclr/src/pal/src/arch/amd64/signalhandlerhelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,24 @@ SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do

/*++
Function :
ExecuteHandlerOnCustomStack
signal_handler_worker
Execute signal handler on a custom stack, the current stack pointer is specified by the customSp
If the customSp is 0, then the handler is executed on the original stack where the signal was fired.
It installs a fake stack frame to enable stack unwinding to the signal source location.
Handles signal on the original stack where the signal occured.
Invoked via setcontext.
Parameters :
POSIX signal handler parameter list ("man sigaction" for details)
returnPoint - context to which the function returns if the common_signal_handler returns
(no return value)
--*/
void ExecuteHandlerOnCustomStack(int code, siginfo_t *siginfo, void *context, size_t customSp, SignalHandlerWorkerReturnPoint* returnPoint)
void ExecuteHandlerOnOriginalStack(int code, siginfo_t *siginfo, void *context, SignalHandlerWorkerReturnPoint* returnPoint)
{
ucontext_t *ucontext = (ucontext_t *)context;
size_t faultSp = (size_t)MCREG_Rsp(ucontext->uc_mcontext);

_ASSERTE(IS_ALIGNED(faultSp, 8));

if (customSp == 0)
{
// preserve 128 bytes long red zone and align stack pointer
customSp = ALIGN_DOWN(faultSp - 128, 16);
}

size_t fakeFrameReturnAddress;

if (IS_ALIGNED(faultSp, 16))
Expand All @@ -49,15 +42,16 @@ void ExecuteHandlerOnCustomStack(int code, siginfo_t *siginfo, void *context, si
fakeFrameReturnAddress = (size_t)SignalHandlerWorkerReturnOffset8 + (size_t)CallSignalHandlerWrapper8;
}

size_t* sp = (size_t*)customSp;
// preserve 128 bytes long red zone and align stack pointer
size_t* sp = (size_t*)ALIGN_DOWN(faultSp - 128, 16);

// Build fake stack frame to enable the stack unwinder to unwind from signal_handler_worker to the faulting instruction
*--sp = (size_t)MCREG_Rip(ucontext->uc_mcontext);
*--sp = (size_t)MCREG_Rbp(ucontext->uc_mcontext);
size_t fp = (size_t)sp;
*--sp = fakeFrameReturnAddress;

// Switch the current context to the signal_handler_worker and the custom stack
// Switch the current context to the signal_handler_worker and the original stack
CONTEXT context2;
RtlCaptureContext(&context2);

Expand Down
18 changes: 6 additions & 12 deletions src/coreclr/src/pal/src/arch/arm/signalhandlerhelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,24 @@ SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do

/*++
Function :
ExecuteHandlerOnCustomStack
signal_handler_worker
Execute signal handler on a custom stack, the current stack pointer is specified by the customSp
If the customSp is 0, then the handler is executed on the original stack where the signal was fired.
It installs a fake stack frame to enable stack unwinding to the signal source location.
Handles signal on the original stack where the signal occured.
Invoked via setcontext.
Parameters :
POSIX signal handler parameter list ("man sigaction" for details)
returnPoint - context to which the function returns if the common_signal_handler returns
(no return value)
--*/
void ExecuteHandlerOnCustomStack(int code, siginfo_t *siginfo, void *context, size_t customSp, SignalHandlerWorkerReturnPoint* returnPoint)
void ExecuteHandlerOnOriginalStack(int code, siginfo_t *siginfo, void *context, SignalHandlerWorkerReturnPoint* returnPoint)
{
ucontext_t *ucontext = (ucontext_t *)context;
size_t faultSp = (size_t)MCREG_Sp(ucontext->uc_mcontext);

_ASSERTE(IS_ALIGNED(faultSp, 4));

if (customSp == 0)
{
// preserve 8 bytes long red zone and align stack pointer
customSp = ALIGN_DOWN(faultSp - 8, 8);
}

size_t fakeFrameReturnAddress;

if (IS_ALIGNED(faultSp, 8))
Expand All @@ -49,7 +42,8 @@ void ExecuteHandlerOnCustomStack(int code, siginfo_t *siginfo, void *context, si
fakeFrameReturnAddress = (size_t)SignalHandlerWorkerReturnOffset4 + (size_t)CallSignalHandlerWrapper4;
}

size_t* sp = (size_t*)customSp;
// preserve 8 bytes long red zone and align stack pointer
size_t* sp = (size_t*)ALIGN_DOWN(faultSp - 8, 8);

#ifndef __linux__
size_t cpsr = (size_t)MCREG_Cpsr(ucontext->uc_mcontext);
Expand Down
17 changes: 5 additions & 12 deletions src/coreclr/src/pal/src/arch/arm64/signalhandlerhelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,23 @@ SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do

/*++
Function :
ExecuteHandlerOnCustomStack
signal_handler_worker
Execute signal handler on a custom stack, the current stack pointer is specified by the customSp
If the customSp is 0, then the handler is executed on the original stack where the signal was fired.
It installs a fake stack frame to enable stack unwinding to the signal source location.
Handles signal on the original stack where the signal occured.
Invoked via setcontext.
Parameters :
POSIX signal handler parameter list ("man sigaction" for details)
returnPoint - context to which the function returns if the common_signal_handler returns
(no return value)
--*/
void ExecuteHandlerOnCustomStack(int code, siginfo_t *siginfo, void *context, size_t customSp, SignalHandlerWorkerReturnPoint* returnPoint)
void ExecuteHandlerOnOriginalStack(int code, siginfo_t *siginfo, void *context, SignalHandlerWorkerReturnPoint* returnPoint)
{
ucontext_t *ucontext = (ucontext_t *)context;
size_t faultSp = (size_t)MCREG_Sp(ucontext->uc_mcontext);
_ASSERTE(IS_ALIGNED(faultSp, 8));

if (customSp == 0)
{
// preserve 128 bytes long red zone and align stack pointer
customSp = ALIGN_DOWN(faultSp - 128, 16);
}

size_t fakeFrameReturnAddress;

if (IS_ALIGNED(faultSp, 16))
Expand All @@ -49,7 +42,7 @@ void ExecuteHandlerOnCustomStack(int code, siginfo_t *siginfo, void *context, si
}

// preserve 128 bytes long red zone and align stack pointer
size_t* sp = (size_t*)customSp;
size_t* sp = (size_t*)ALIGN_DOWN(faultSp - 128, 16);

// Build fake stack frame to enable the stack unwinder to unwind from signal_handler_worker to the faulting instruction
// pushed LR
Expand Down
16 changes: 5 additions & 11 deletions src/coreclr/src/pal/src/arch/i386/signalhandlerhelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,24 @@ SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do

/*++
Function :
ExecuteHandlerOnCustomStack
signal_handler_worker
Execute signal handler on a custom stack, the current stack pointer is specified by the customSp
If the customSp is 0, then the handler is executed on the original stack where the signal was fired.
It installs a fake stack frame to enable stack unwinding to the signal source location.
Handles signal on the original stack where the signal occured.
Invoked via setcontext.
Parameters :
POSIX signal handler parameter list ("man sigaction" for details)
returnPoint - context to which the function returns if the common_signal_handler returns
(no return value)
--*/
void ExecuteHandlerOnCustomStack(int code, siginfo_t *siginfo, void *context, size_t customSp, SignalHandlerWorkerReturnPoint* returnPoint)
void ExecuteHandlerOnOriginalStack(int code, siginfo_t *siginfo, void *context, SignalHandlerWorkerReturnPoint* returnPoint)
{
ucontext_t *ucontext = (ucontext_t *)context;
size_t faultSp = (size_t)MCREG_Esp(ucontext->uc_mcontext);

_ASSERTE(IS_ALIGNED(faultSp, 4));

if (customSp == 0)
{
customSp = ALIGN_DOWN(faultSp, 16);
}

size_t fakeFrameReturnAddress;

switch (faultSp & 0xc)
Expand All @@ -55,7 +49,7 @@ void ExecuteHandlerOnCustomStack(int code, siginfo_t *siginfo, void *context, si
break;
}

size_t* sp = (size_t*)customSp;
size_t* sp = (size_t*)ALIGN_DOWN(faultSp, 16);

// Build fake stack frame to enable the stack unwinder to unwind from signal_handler_worker to the faulting instruction
*--sp = (size_t)MCREG_Eip(ucontext->uc_mcontext);
Expand Down
15 changes: 6 additions & 9 deletions src/coreclr/src/pal/src/exception/seh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ Module Name:
#include "pal/process.h"
#include "pal/malloc.hpp"
#include "pal/signal.hpp"
#include "pal/virtual.h"

#if HAVE_MACH_EXCEPTIONS
#include "machexception.h"
Expand Down Expand Up @@ -269,16 +268,14 @@ SEHProcessException(PAL_SEHException* exception)
// Check if the failed access has hit a stack guard page. In such case, it
// was a stack probe that detected that there is not enough stack left.
void* stackLimit = CPalThread::GetStackLimit();
void* stackOverflowBottom = (void*)((size_t)stackLimit - GetVirtualPageSize());
// On some versions of glibc / platforms the stackLimit is an address of the guard page, on some
// it is right above the guard page.
// So consider SIGSEGV in one page above and below stack limit to be stack overflow.
void* stackOverflowTop = (void*)((size_t)stackLimit + GetVirtualPageSize());
void* stackGuard = (void*)((size_t)stackLimit - getpagesize());
void* violationAddr = (void*)exceptionRecord->ExceptionInformation[1];

if ((violationAddr >= stackOverflowBottom) && (violationAddr < stackOverflowTop))
if ((violationAddr >= stackGuard) && (violationAddr < stackLimit))
{
exceptionRecord->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
// The exception happened in the page right below the stack limit,
// so it is a stack overflow
(void)write(STDERR_FILENO, StackOverflowMessage, sizeof(StackOverflowMessage) - 1);
PROCAbort();
}
}

Expand Down
108 changes: 21 additions & 87 deletions src/coreclr/src/pal/src/exception/signal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,6 @@ struct sigaction g_previous_activation;
// Offset of the local variable containing pointer to windows style context in the common_signal_handler function.
// This offset is relative to the frame pointer.
int g_common_signal_handler_context_locvar_offset = 0;

// TOP of special stack for handling stack overflow
volatile void* g_stackOverflowHandlerStack = NULL;
#endif // !HAVE_MACH_EXCEPTIONS

/* public function definitions ************************************************/
Expand Down Expand Up @@ -178,26 +175,6 @@ BOOL SEHInitializeSignals(CorUnix::CPalThread *pthrCurrent, DWORD flags)
{
return FALSE;
}

// Allocate the minimal stack necessary for handling stack overflow
int stackOverflowStackSize = ALIGN_UP(sizeof(SignalHandlerWorkerReturnPoint), 16) + 7 * 4096;
// Align the size to virtual page size and add one virtual page as a stack guard
stackOverflowStackSize = ALIGN_UP(stackOverflowStackSize, GetVirtualPageSize()) + GetVirtualPageSize();
g_stackOverflowHandlerStack = mmap(NULL, stackOverflowStackSize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_STACK | MAP_PRIVATE, -1, 0);
if (g_stackOverflowHandlerStack == MAP_FAILED)
{
return FALSE;
}

// create a guard page for the alternate stack
int st = mprotect((void*)g_stackOverflowHandlerStack, GetVirtualPageSize(), PROT_NONE);
if (st != 0)
{
munmap((void*)g_stackOverflowHandlerStack, stackOverflowStackSize);
return FALSE;
}

g_stackOverflowHandlerStack = (void*)((size_t)g_stackOverflowHandlerStack + stackOverflowStackSize);
}

/* The default action for SIGPIPE is process termination.
Expand Down Expand Up @@ -453,41 +430,6 @@ bool IsRunningOnAlternateStack(void *context)
return isRunningOnAlternateStack;
}

/*++
Function :
SwitchStackAndExecuteHandler
Switch to the stack specified by the sp argument
Parameters :
POSIX signal handler parameter list ("man sigaction" for details)
sp - stack pointer of the stack to execute the handler on.
If sp == 0, execute it on the original stack where the signal has occured.
Return :
The return value from the signal handler
--*/
static bool SwitchStackAndExecuteHandler(int code, siginfo_t *siginfo, void *context, size_t sp)
{
// Establish a return point in case the common_signal_handler returns

volatile bool contextInitialization = true;

void *ptr = alloca(sizeof(SignalHandlerWorkerReturnPoint) + alignof(SignalHandlerWorkerReturnPoint) - 1);
SignalHandlerWorkerReturnPoint *pReturnPoint = (SignalHandlerWorkerReturnPoint *)ALIGN_UP(ptr, alignof(SignalHandlerWorkerReturnPoint));
RtlCaptureContext(&pReturnPoint->context);

// When the signal handler worker completes, it uses setcontext to return to this point

if (contextInitialization)
{
contextInitialization = false;
ExecuteHandlerOnCustomStack(code, siginfo, context, sp, pReturnPoint);
_ASSERTE(FALSE); // The ExecuteHandlerOnCustomStack should never return
}

return pReturnPoint->returnFromHandler;
}

/*++
Function :
sigsegv_handler
Expand All @@ -511,38 +453,33 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
// we have a stack overflow.
if ((failureAddress - (sp - GetVirtualPageSize())) < 2 * GetVirtualPageSize())
{
if (GetCurrentPalThread())
{
size_t handlerStackTop = __sync_val_compare_and_swap((size_t*)&g_stackOverflowHandlerStack, (size_t)g_stackOverflowHandlerStack, 0);
if (handlerStackTop == 0)
{
// We have only one stack for handling stack overflow preallocated. We let only the first thread that hits stack overflow to
// run the exception handling code on that stack (which ends up just dumping the stack trace and aborting the process).
// Other threads are held spinning and sleeping here until the process exits.
while (true)
{
sleep(1);
}
}

if (SwitchStackAndExecuteHandler(code, siginfo, context, (size_t)handlerStackTop))
{
PROCAbort();
}
}
else
{
(void)write(STDERR_FILENO, StackOverflowMessage, sizeof(StackOverflowMessage) - 1);
PROCAbort();
}
(void)write(STDERR_FILENO, StackOverflowMessage, sizeof(StackOverflowMessage) - 1);
PROCAbort();
}

// Now that we know the SIGSEGV didn't happen due to a stack overflow, execute the common
// hardware signal handler on the original stack.

if (GetCurrentPalThread() && IsRunningOnAlternateStack(context))
{
if (SwitchStackAndExecuteHandler(code, siginfo, context, 0 /* sp */)) // sp == 0 indicates execution on the original stack
// Establish a return point in case the common_signal_handler returns

volatile bool contextInitialization = true;

void *ptr = alloca(sizeof(SignalHandlerWorkerReturnPoint) + alignof(SignalHandlerWorkerReturnPoint) - 1);
SignalHandlerWorkerReturnPoint *pReturnPoint = (SignalHandlerWorkerReturnPoint *)ALIGN_UP(ptr, alignof(SignalHandlerWorkerReturnPoint));
RtlCaptureContext(&pReturnPoint->context);

// When the signal handler worker completes, it uses setcontext to return to this point

if (contextInitialization)
{
contextInitialization = false;
ExecuteHandlerOnOriginalStack(code, siginfo, context, pReturnPoint);
_ASSERTE(FALSE); // The ExecuteHandlerOnOriginalStack should never return
}

if (pReturnPoint->returnFromHandler)
{
return;
}
Expand Down Expand Up @@ -755,10 +692,7 @@ PAL_ERROR InjectActivationInternal(CorUnix::CPalThread* pThread)
{
#ifdef INJECT_ACTIVATION_SIGNAL
int status = pthread_kill(pThread->GetPThreadSelf(), INJECT_ACTIVATION_SIGNAL);
// We can get EAGAIN when printing stack overflow stack trace and when other threads hit
// stack overflow too. Those are held in the sigsegv_handler with blocked signals until
// the process exits.
if ((status != 0) && (status != EAGAIN))
if (status != 0)
{
// Failure to send the signal is fatal. There are only two cases when sending
// the signal can fail. First, if the signal ID is invalid and second,
Expand Down
Loading

0 comments on commit 90e9614

Please sign in to comment.