Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
- Fix axis-aligned transform detection for optimized opaque view clipping
- Rename `SentryMechanismMeta` to `SentryMechanismContext` to resolve Kotlin Multi-Platform build errors (#6607)
- Fix conversion of frame rate to time interval for session replay (#6623)
- Fix AOT interop with managed .NET runtimes (#6193)
- Change Session Replay masking to prevent semi‑transparent full‑screen overlays from clearing redactions by making opaque clipping stricter (#6629)
Views now need to be fully opaque (view and layer backgrounds with alpha == 1) and report opaque to qualify for clip‑out.
This avoids leaks at the cost of fewer clip‑out optimizations.
Expand Down
11 changes: 11 additions & 0 deletions Sources/Sentry/PrivateSentrySDKOnly.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ @implementation PrivateSentrySDKOnly

static SentryOnAppStartMeasurementAvailable _onAppStartMeasurementAvailable;
static BOOL _appStartMeasurementHybridSDKMode = NO;
static BOOL _isManagedRuntime = NO;
#if SENTRY_HAS_UIKIT
static BOOL _framesTrackingMeasurementHybridSDKMode = NO;
#endif // SENTRY_HAS_UIKIT
Expand Down Expand Up @@ -147,6 +148,16 @@ + (void)setAppStartMeasurementHybridSDKMode:(BOOL)appStartMeasurementHybridSDKMo
_appStartMeasurementHybridSDKMode = appStartMeasurementHybridSDKMode;
}

+ (BOOL)isManagedRuntime
{
return _isManagedRuntime;
}

+ (void)setIsManagedRuntime:(BOOL)isManagedRuntime
{
_isManagedRuntime = isManagedRuntime;
}

+ (void)setSdkName:(NSString *)sdkName andVersionString:(NSString *)versionString
{
SentryMeta.sdkName = sdkName;
Expand Down
3 changes: 3 additions & 0 deletions Sources/Sentry/SentryCrashIntegration.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#import "SentryCrashIntegration.h"

#import "PrivateSentrySDKOnly.h"
#import "SentryCrashC.h"
#import "SentryCrashInstallationReporter.h"
#import "SentryCrashIntegrationSessionHandler.h"
Expand Down Expand Up @@ -157,6 +159,7 @@ - (void)startCrashHandler:(NSString *)cacheDirectory
}

sentrycrashcm_setEnableSigtermReporting(enableSigtermReporting);
sentrycrashcm_setManagedRuntime([PrivateSentrySDKOnly isManagedRuntime]);

[installation install:cacheDirectory];

Expand Down
6 changes: 6 additions & 0 deletions Sources/Sentry/include/HybridPublic/PrivateSentrySDKOnly.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ typedef void (^SentryOnAppStartMeasurementAvailable)(
*/
@property (class, nonatomic, assign) BOOL appStartMeasurementHybridSDKMode;

/**
* Whether the SDK is running in a managed Mono/CoreCLR runtime environment and
* needs to chain Unix signal handlers.
*/
@property (class, nonatomic, assign) BOOL isManagedRuntime;

#if SENTRY_UIKIT_AVAILABLE
/**
* Allows hybrid SDKs to enable frame tracking measurements despite other options.
Expand Down
5 changes: 5 additions & 0 deletions Sources/Sentry/include/SentryCrashMonitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ bool sentrycrashcm_notifyFatalExceptionCaptured(bool isAsyncSafeEnvironment);
*/
void sentrycrashcm_handleException(struct SentryCrash_MonitorContext *context);

/** Whether to chain Unix signal handlers for managed Mono/CoreCLR runtimes.
*/
bool sentrycrashcm_isManagedRuntime(void);
void sentrycrashcm_setManagedRuntime(bool isManagedRuntime);

#ifdef __cplusplus
}
#endif
Expand Down
13 changes: 13 additions & 0 deletions Sources/SentryCrash/Recording/Monitors/SentryCrashMonitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ static SentryCrashMonitorType g_activeMonitors = SentryCrashMonitorTypeNone;
static bool g_handlingFatalException = false;
static bool g_crashedDuringExceptionHandling = false;
static bool g_requiresAsyncSafety = false;
static bool g_isManagedRuntime = false;

static void (*g_onExceptionEvent)(struct SentryCrash_MonitorContext *monitorContext);

Expand Down Expand Up @@ -226,3 +227,15 @@ sentrycrashcm_handleException(struct SentryCrash_MonitorContext *context)
sentrycrashcm_setActiveMonitors(SentryCrashMonitorTypeNone);
}
}

bool
sentrycrashcm_isManagedRuntime(void)
{
return g_isManagedRuntime;
}

void
sentrycrashcm_setManagedRuntime(bool isManagedRuntime)
{
g_isManagedRuntime = isManagedRuntime;
}
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("Not registering Mach exception port for EXC_BAD_ACCESS "
"or EXC_MASK_ARITHMETIC in a managed Mono/CoreCLR runtime");
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
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
//

#include "SentryCrashMonitor_Signal.h"
#include "SentryCrashCPU.h"
#include "SentryCrashID.h"
#include "SentryCrashMachineContext.h"
#include "SentryCrashMonitorContext.h"
Expand Down Expand Up @@ -67,6 +68,29 @@ static char g_eventID[37];
# pragma mark - Callbacks -
// ============================================================================

/** Invoke previously installed signal handlers, adapted from Sentry Native:
* https://github.com/getsentry/sentry-native/blob/9895a5c3ffab4e59e0c8020484cdd5dbc648666d/src/backends/sentry_backend_inproc.c#L59-L76
*/
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 +107,29 @@ static void
handleSignal(int sigNum, siginfo_t *signalInfo, void *userContext)
{
SENTRY_ASYNC_SAFE_LOG_DEBUG("Trapped signal %d", sigNum);

if (sentrycrashcm_isManagedRuntime()) {
// Let managed Mono/CoreCLR runtime handle the signal first,
// as they may convert it into a managed exception.
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 +157,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 (!sentrycrashcm_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 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
Loading
Loading