Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,6 @@ public static partial class ControlledExecution
[Obsolete(Obsoletions.ControlledExecutionRunMessage, DiagnosticId = Obsoletions.ControlledExecutionRunDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
public static void Run(Action action, CancellationToken cancellationToken)
{
if (!OperatingSystem.IsWindows())
{
throw new PlatformNotSupportedException();
}

ArgumentNullException.ThrowIfNull(action);

// ControlledExecution.Run does not support nested invocations. If there's one already in flight
Expand Down
15 changes: 15 additions & 0 deletions src/coreclr/pal/src/exception/seh-unwind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,9 @@ void GetContextPointers(unw_cursor_t *cursor, unw_context_t *unwContext, KNONVOL
// Frame pointer relative offset of a local containing a pointer to the windows style context of a location
// where a hardware exception occurred.
int g_hardware_exception_context_locvar_offset = 0;
// Frame pointer relative offset of a local containing a pointer to the windows style context of a location
// where an activation signal interrupted the thread.
int g_inject_activation_context_locvar_offset = 0;

BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers)
{
Expand All @@ -579,6 +582,18 @@ BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextP
return TRUE;
}

// Check if the PC is the return address from the InvokeActivationHandler.
// If that's the case, extract its local variable containing a pointer to the windows style context of the activation
// injection location and return that. This skips the signal handler trampoline that the libunwind
// cannot cross on some systems.
if ((void*)curPc == g_InvokeActivationHandlerReturnAddress)
{
CONTEXT* activationContext = (CONTEXT*)(CONTEXTGetFP(context) + g_inject_activation_context_locvar_offset);
memcpy_s(context, sizeof(CONTEXT), activationContext, sizeof(CONTEXT));

return TRUE;
}

if ((context->ContextFlags & CONTEXT_EXCEPTION_ACTIVE) != 0)
{
// The current frame is a source of hardware exception. Due to the fact that
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/pal/src/exception/seh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ PGET_GCMARKER_EXCEPTION_CODE g_getGcMarkerExceptionCode = NULL;
// Return address of the SEHProcessException, which is used to enable walking over
// the signal handler trampoline on some Unixes where the libunwind cannot do that.
void* g_SEHProcessExceptionReturnAddress = NULL;
void* g_InvokeActivationHandlerReturnAddress = NULL;

/* Internal function definitions **********************************************/

Expand Down
39 changes: 37 additions & 2 deletions src/coreclr/pal/src/exception/signal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ typedef void (*SIGFUNC)(int, siginfo_t *, void *);
static void sigterm_handler(int code, siginfo_t *siginfo, void *context);
#ifdef INJECT_ACTIVATION_SIGNAL
static void inject_activation_handler(int code, siginfo_t *siginfo, void *context);
extern void* g_InvokeActivationHandlerReturnAddress;
#endif

static void sigill_handler(int code, siginfo_t *siginfo, void *context);
Expand Down Expand Up @@ -775,6 +776,29 @@ static void sigterm_handler(int code, siginfo_t *siginfo, void *context)
}

#ifdef INJECT_ACTIVATION_SIGNAL

/*++
Function :
InvokeActivationHandler

Invoke the registered activation handler.
It also saves the return address (inject_activation_handler) so that PAL_VirtualUnwind can detect that
it has reached that method and use the context stored in the winContext there to unwind to the code
where the activation was injected. This is necessary on Alpine Linux where the libunwind cannot correctly
unwind past the signal frame.

Parameters :
Windows style context of the location where the activation was injected

(no return value)
--*/
__attribute__((noinline))
static void InvokeActivationHandler(CONTEXT *pWinContext)
{
g_InvokeActivationHandlerReturnAddress = __builtin_return_address(0);
g_activationFunction(pWinContext);
}

/*++
Function :
inject_activation_handler
Expand Down Expand Up @@ -803,15 +827,26 @@ static void inject_activation_handler(int code, siginfo_t *siginfo, void *contex
native_context_t *ucontext = (native_context_t *)context;

CONTEXT winContext;
// Pre-populate context with data from current frame, because ucontext doesn't have some data (e.g. SS register)
// which is required for restoring context
RtlCaptureContext(&winContext);

ULONG contextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT;

#if defined(HOST_AMD64)
contextFlags |= CONTEXT_XSTATE;
#endif

CONTEXTFromNativeContext(
ucontext,
&winContext,
CONTEXT_CONTROL | CONTEXT_INTEGER);
contextFlags);

if (g_safeActivationCheckFunction(CONTEXTGetPC(&winContext), /* checkingCurrentThread */ TRUE))
{
g_inject_activation_context_locvar_offset = (int)((char*)&winContext - (char*)__builtin_frame_address(0));
int savedErrNo = errno; // Make sure that errno is not modified
g_activationFunction(&winContext);
InvokeActivationHandler(&winContext);
errno = savedErrNo;

// Activation function may have modified the context, so update it.
Expand Down
4 changes: 3 additions & 1 deletion src/coreclr/pal/src/include/pal/seh.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,9 @@ CorUnix::PAL_ERROR SEHDisable(CorUnix::CPalThread *pthrCurrent);
// Offset of the local variable containing pointer to windows style context in the common_signal_handler / PAL_DispatchException function.
// This offset is relative to the frame pointer.
extern int g_hardware_exception_context_locvar_offset;

// Offset of the local variable containing pointer to windows style context in the inject_activation_handler.
// This offset is relative to the frame pointer.
extern int g_inject_activation_context_locvar_offset;

#endif /* _PAL_SEH_HPP_ */

3 changes: 2 additions & 1 deletion src/coreclr/vm/threads.h
Original file line number Diff line number Diff line change
Expand Up @@ -3837,7 +3837,7 @@ class Thread
#endif
}

void UnmarkRedirectContextInUse(PTR_CONTEXT pCtx)
bool UnmarkRedirectContextInUse(PTR_CONTEXT pCtx)
{
LIMITED_METHOD_CONTRACT;
#ifdef _DEBUG
Expand All @@ -3848,6 +3848,7 @@ class Thread
m_RedirectContextInUse = false;
}
#endif
return (pCtx == m_pSavedRedirectContext);
}
#endif //DACCESS_COMPILE

Expand Down
Loading