Skip to content
Draft
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Fixes

- Fix potential app launch hang caused by the SentrySDK (#6181) Fixed by removing the call to `_dyld_get_image_header` on the main thread.
- Fix interop with managed Mono/CoreCLR runtimes (#6193)

## 8.56.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,12 @@ installExceptionHandler(void)
}
}

if (sentrycrashcm_isManagedRuntime()) {
SENTRY_ASYNC_SAFE_LOG_DEBUG("Detected managed Mono/CoreCLR runtime. Not registering "
"exception port for EXC_BAD_ACCESS or EXC_MASK_ARITHMETIC.");
mask &= ~(EXC_MASK_BAD_ACCESS | EXC_MASK_ARITHMETIC);
}

SENTRY_ASYNC_SAFE_LOG_DEBUG("Installing port as exception handler.");
kr = task_set_exception_ports(thisTask, mask, g_exceptionPort,
(int)(EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES), THREAD_STATE_NONE);
Expand Down Expand Up @@ -562,6 +568,23 @@ addContextualInfoToEvent(struct SentryCrash_MonitorContext *eventContext)

#endif // SENTRY_HAS_MACH

bool
sentrycrashcm_isManagedRuntime(void)
{
#if SENTRY_HAS_MACH
for (mach_msg_type_number_t i = 0; i < g_previousExceptionPorts.count; i++) {
// https://github.com/dotnet/runtime/blob/6d96e28597e7da0d790d495ba834cc4908e442cd/src/mono/mono/mini/mini-darwin.c#L85-L90
// https://github.com/dotnet/runtime/blob/6d96e28597e7da0d790d495ba834cc4908e442cd/src/coreclr/nativeaot/Runtime/unix/HardwareExceptions.cpp#L615-L621
if (g_previousExceptionPorts.masks[i] == (EXC_MASK_BAD_ACCESS | EXC_MASK_ARITHMETIC)
&& g_previousExceptionPorts.behaviors[i] == EXCEPTION_STATE_IDENTITY
&& g_previousExceptionPorts.flavors[i] == MACHINE_THREAD_STATE) {
return true;
}
}
#endif // SENTRY_HAS_MACH
return false;
}

SentryCrashMonitorAPI *
sentrycrashcm_machexception_getAPI(void)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ bool sentrycrashcm_isReservedThread(thread_t thread);
*/
bool sentrycrashcm_hasReservedThreads(void);

/** Detect managed Mono/CoreCLR runtime's Mach exception port.
*/
bool sentrycrashcm_isManagedRuntime(void);

#ifdef __cplusplus
}
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@
//

#include "SentryCrashMonitor_Signal.h"
#include "SentryCrashCPU.h"
#include "SentryCrashID.h"
#include "SentryCrashMachineContext.h"
#include "SentryCrashMonitorContext.h"
#include "SentryCrashMonitor_MachException.h"
#include "SentryCrashSignalInfo.h"
#include "SentryCrashStackCursor_MachineContext.h"
#include "SentryInternalCDefines.h"
Expand All @@ -49,6 +51,7 @@

static volatile bool g_isEnabled = false;
static bool g_isSigtermReportingEnabled = false;
static bool g_isManagedRuntime = false;

static SentryCrash_MonitorContext g_monitorContext;
static SentryCrashStackCursor g_stackCursor;
Expand All @@ -67,6 +70,29 @@ static char g_eventID[37];
# pragma mark - Callbacks -
// ============================================================================

/**
*
*/
static void
invokePreviousSignalHandlers(int sigNum, siginfo_t *signalInfo, void *userContext)
{
const int *fatalSignals = sentrycrashsignal_fatalSignals();
int fatalSignalsCount = sentrycrashsignal_numFatalSignals();

for (int i = 0; i < fatalSignalsCount; ++i) {
if (fatalSignals[i] == sigNum) {
struct sigaction *handler = &g_previousSignalHandlers[i];
if (handler->sa_flags & SA_SIGINFO) {
handler->sa_sigaction(sigNum, signalInfo, userContext);
} else if (handler->sa_handler != SIG_DFL && handler->sa_handler != SIG_IGN) {
// This handler can only handle to signal number (ANSI C)
void (*func)(int) = handler->sa_handler;
func(sigNum);
}
}
}
}

/** Our custom signal handler.
* Restore the default signal handlers, record the signal information, and
* write a crash report.
Expand All @@ -83,6 +109,29 @@ static void
handleSignal(int sigNum, siginfo_t *signalInfo, void *userContext)
{
SENTRY_ASYNC_SAFE_LOG_DEBUG("Trapped signal %d", sigNum);

// Let managed Mono/CoreCLR runtime handle the signal first,
// as they may convert it into a managed exception.
if (g_isManagedRuntime) {
SENTRY_ASYNC_SAFE_LOG_DEBUG(
"Detected managed Mono/CoreCLR runtime. Passing signal to previous handlers.");

uintptr_t sp = sentrycrashcpu_stackPointerFromUserContext(userContext);
uintptr_t ip = sentrycrashcpu_instructionAddressFromUserContext(userContext);

invokePreviousSignalHandlers(sigNum, signalInfo, userContext);

// If the stack or instruction pointer changed, the managed runtime
// converted the signal into a managed exception and changed the context.
// https://github.com/dotnet/runtime/blob/6d96e28597e7da0d790d495ba834cc4908e442cd/src/mono/mono/mini/exceptions-arm64.c#L538
if (sp != sentrycrashcpu_stackPointerFromUserContext(userContext)
|| ip != sentrycrashcpu_instructionAddressFromUserContext(userContext)) {
SENTRY_ASYNC_SAFE_LOG_DEBUG(
"Signal converted to a managed exception. Aborting signal handling.");
return;
}
}

if (g_isEnabled) {
thread_act_array_t threads = NULL;
mach_msg_type_number_t numThreads = 0;
Expand Down Expand Up @@ -110,9 +159,13 @@ handleSignal(int sigNum, siginfo_t *signalInfo, void *userContext)
sentrycrashmc_resumeEnvironment(threads, numThreads);
}

SENTRY_ASYNC_SAFE_LOG_DEBUG("Re-raising signal for regular handlers to catch.");
// This is technically not allowed, but it works in OSX and iOS.
raise(sigNum);
// Re-raise the signal to invoke the previous handlers unless already called
// above for managed runtimes.
if (!g_isManagedRuntime) {
SENTRY_ASYNC_SAFE_LOG_DEBUG("Re-raising signal for regular handlers to catch.");
// This is technically not allowed, but it works in OSX and iOS.
raise(sigNum);
}
}

// ============================================================================
Expand All @@ -124,6 +177,8 @@ installSignalHandler(void)
{
SENTRY_ASYNC_SAFE_LOG_DEBUG("Installing signal handler.");

g_isManagedRuntime = sentrycrashcm_isManagedRuntime();

# if SENTRY_HAS_SIGNAL_STACK

if (g_signalStack.ss_size == 0) {
Expand Down
3 changes: 3 additions & 0 deletions Sources/SentryCrash/Recording/Tools/SentryCrashCPU.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const char *sentrycrashcpu_currentArch(void);
* @return The context's frame pointer.
*/
uintptr_t sentrycrashcpu_framePointer(const struct SentryCrashMachineContext *const context);
uintptr_t sentrycrashcpu_framePointerFromUserContext(const void *const userContext);

/** Get the current stack pointer for a machine context.
*
Expand All @@ -59,6 +60,7 @@ uintptr_t sentrycrashcpu_framePointer(const struct SentryCrashMachineContext *co
* @return The context's stack pointer.
*/
uintptr_t sentrycrashcpu_stackPointer(const struct SentryCrashMachineContext *const context);
uintptr_t sentrycrashcpu_stackPointerFromUserContext(const void *const userContext);

/** Get the address of the instruction about to be, or being executed by a
* machine context.
Expand All @@ -68,6 +70,7 @@ uintptr_t sentrycrashcpu_stackPointer(const struct SentryCrashMachineContext *co
* @return The context's next instruction address.
*/
uintptr_t sentrycrashcpu_instructionAddress(const struct SentryCrashMachineContext *const context);
uintptr_t sentrycrashcpu_instructionAddressFromUserContext(const void *const userContext);

/** Get the address stored in the link register (arm only). This may
* contain the first return address of the stack.
Expand Down
18 changes: 18 additions & 0 deletions Sources/SentryCrash/Recording/Tools/SentryCrashCPU_arm.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,36 @@ sentrycrashcpu_framePointer(const SentryCrashMachineContext *const context)
return context->machineContext.__ss.__r[7];
}

uintptr_t
sentrycrashcpu_framePointerFromUserContext(const void *const userContext)
{
return ((const ucontext_t *)userContext)->uc_mcontext->__ss.__r[7];
}

uintptr_t
sentrycrashcpu_stackPointer(const SentryCrashMachineContext *const context)
{
return context->machineContext.__ss.__sp;
}

uintptr_t
sentrycrashcpu_stackPointerFromUserContext(const void *const userContext)
{
return ((const ucontext_t *)userContext)->uc_mcontext->__ss.__sp;
}

uintptr_t
sentrycrashcpu_instructionAddress(const SentryCrashMachineContext *const context)
{
return context->machineContext.__ss.__pc;
}

uintptr_t
sentrycrashcpu_instructionAddressFromUserContext(const void *const userContext)
{
return ((const ucontext_t *)userContext)->uc_mcontext->__ss.__pc;
}

uintptr_t
sentrycrashcpu_linkRegister(const SentryCrashMachineContext *const context)
{
Expand Down
51 changes: 44 additions & 7 deletions Sources/SentryCrash/Recording/Tools/SentryCrashCPU_arm64.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
# include "SentryCrashMachineContext.h"
# include "SentryCrashMachineContext_Apple.h"
# include <stdlib.h>
# include <sys/_types/_ucontext64.h>

# include "SentryAsyncSafeLog.h"

Expand All @@ -46,36 +47,72 @@ static const char *g_exceptionRegisterNames[] = { "exception", "esr", "far" };
static const int g_exceptionRegisterNamesCount
= sizeof(g_exceptionRegisterNames) / sizeof(*g_exceptionRegisterNames);

uintptr_t
sentrycrashcpu_framePointer(const SentryCrashMachineContext *const context)
static inline uintptr_t
getFramePointer(const _STRUCT_MCONTEXT64 *const context)
{
// We don't want this from stopping us to enable warnings as errors. This needs to be fixed.
# pragma clang diagnostic push
# pragma GCC diagnostic ignored "-Wshorten-64-to-32"
return arm_thread_state64_get_fp(context->machineContext.__ss);
return arm_thread_state64_get_fp(context->__ss);
# pragma clang diagnostic pop
}

uintptr_t
sentrycrashcpu_stackPointer(const SentryCrashMachineContext *const context)
sentrycrashcpu_framePointer(const SentryCrashMachineContext *const context)
{
return getFramePointer(&context->machineContext);
}

uintptr_t
sentrycrashcpu_framePointerFromUserContext(const void *const userContext)
{
return getFramePointer(((const ucontext64_t *)userContext)->uc_mcontext64);
}

static inline uintptr_t
getStackPointer(const _STRUCT_MCONTEXT64 *const context)
{
// We don't want this from stopping us to enable warnings as errors. This needs to be fixed.
# pragma clang diagnostic push
# pragma GCC diagnostic ignored "-Wshorten-64-to-32"
return arm_thread_state64_get_sp(context->machineContext.__ss);
return arm_thread_state64_get_sp(context->__ss);
# pragma clang diagnostic pop
}

uintptr_t
sentrycrashcpu_instructionAddress(const SentryCrashMachineContext *const context)
sentrycrashcpu_stackPointer(const SentryCrashMachineContext *const context)
{
return getStackPointer(&context->machineContext);
}

uintptr_t
sentrycrashcpu_stackPointerFromUserContext(const void *const userContext)
{
return getStackPointer(((const ucontext64_t *)userContext)->uc_mcontext64);
}

static inline uintptr_t
getInstructionAddress(const _STRUCT_MCONTEXT64 *const context)
{
// We don't want this from stopping us to enable warnings as errors. This needs to be fixed.
# pragma clang diagnostic push
# pragma GCC diagnostic ignored "-Wshorten-64-to-32"
return arm_thread_state64_get_pc(context->machineContext.__ss);
return arm_thread_state64_get_pc(context->__ss);
# pragma clang diagnostic pop
}

uintptr_t
sentrycrashcpu_instructionAddress(const SentryCrashMachineContext *const context)
{
return getInstructionAddress(&context->machineContext);
}

uintptr_t
sentrycrashcpu_instructionAddressFromUserContext(const void *const userContext)
{
return getInstructionAddress(((const ucontext64_t *)userContext)->uc_mcontext64);
}

uintptr_t
sentrycrashcpu_linkRegister(const SentryCrashMachineContext *const context)
{
Expand Down
18 changes: 18 additions & 0 deletions Sources/SentryCrash/Recording/Tools/SentryCrashCPU_x86_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,36 @@ sentrycrashcpu_framePointer(const SentryCrashMachineContext *const context)
return context->machineContext.__ss.__ebp;
}

uintptr_t
sentrycrashcpu_framePointerFromUserContext(const void *const userContext)
{
return ((const ucontext_t *)userContext)->uc_mcontext->__ss.__ebp;
}

uintptr_t
sentrycrashcpu_stackPointer(const SentryCrashMachineContext *const context)
{
return context->machineContext.__ss.__esp;
}

uintptr_t
sentrycrashcpu_stackPointerFromUserContext(const void *const userContext)
{
return ((const ucontext_t *)userContext)->uc_mcontext->__ss.__esp;
}

uintptr_t
sentrycrashcpu_instructionAddress(const SentryCrashMachineContext *const context)
{
return context->machineContext.__ss.__eip;
}

uintptr_t
sentrycrashcpu_instructionAddressFromUserContext(const void *const userContext)
{
return ((const ucontext_t *)userContext)->uc_mcontext->__ss.__eip;
}

uintptr_t
sentrycrashcpu_linkRegister(__unused const SentryCrashMachineContext *const context)
{
Expand Down
18 changes: 18 additions & 0 deletions Sources/SentryCrash/Recording/Tools/SentryCrashCPU_x86_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,36 @@ sentrycrashcpu_framePointer(const SentryCrashMachineContext *const context)
return context->machineContext.__ss.__rbp;
}

uintptr_t
sentrycrashcpu_framePointerFromUserContext(const void *const userContext)
{
return ((const ucontext_t *)userContext)->uc_mcontext->__ss.__rbp;
}

uintptr_t
sentrycrashcpu_stackPointer(const SentryCrashMachineContext *const context)
{
return context->machineContext.__ss.__rsp;
}

uintptr_t
sentrycrashcpu_stackPointerFromUserContext(const void *const userContext)
{
return ((const ucontext_t *)userContext)->uc_mcontext->__ss.__rsp;
}

uintptr_t
sentrycrashcpu_instructionAddress(const SentryCrashMachineContext *const context)
{
return context->machineContext.__ss.__rip;
}

uintptr_t
sentrycrashcpu_instructionAddressFromUserContext(const void *const userContext)
{
return ((const ucontext_t *)userContext)->uc_mcontext->__ss.__rip;
}

uintptr_t
sentrycrashcpu_linkRegister(__unused const SentryCrashMachineContext *const context)
{
Expand Down
Loading
Loading