Skip to content

Commit 1666de5

Browse files
authored
Merge df48cc1 into dced702
2 parents dced702 + df48cc1 commit 1666de5

File tree

14 files changed

+213
-10
lines changed

14 files changed

+213
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
- Fix axis-aligned transform detection for optimized opaque view clipping
5555
- Rename `SentryMechanismMeta` to `SentryMechanismContext` to resolve Kotlin Multi-Platform build errors (#6607)
5656
- Fix conversion of frame rate to time interval for session replay (#6623)
57+
- Fix AOT interop with managed .NET runtimes (#6193)
5758

5859
### Improvements
5960

Sources/Sentry/PrivateSentrySDKOnly.m

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ @implementation PrivateSentrySDKOnly
2828

2929
static SentryOnAppStartMeasurementAvailable _onAppStartMeasurementAvailable;
3030
static BOOL _appStartMeasurementHybridSDKMode = NO;
31+
static BOOL _isManagedRuntime = NO;
3132
#if SENTRY_HAS_UIKIT
3233
static BOOL _framesTrackingMeasurementHybridSDKMode = NO;
3334
#endif // SENTRY_HAS_UIKIT
@@ -147,6 +148,16 @@ + (void)setAppStartMeasurementHybridSDKMode:(BOOL)appStartMeasurementHybridSDKMo
147148
_appStartMeasurementHybridSDKMode = appStartMeasurementHybridSDKMode;
148149
}
149150

151+
+ (BOOL)isManagedRuntime
152+
{
153+
return _isManagedRuntime;
154+
}
155+
156+
+ (void)setIsManagedRuntime:(BOOL)isManagedRuntime
157+
{
158+
_isManagedRuntime = isManagedRuntime;
159+
}
160+
150161
+ (void)setSdkName:(NSString *)sdkName andVersionString:(NSString *)versionString
151162
{
152163
SentryMeta.sdkName = sdkName;

Sources/Sentry/SentryCrashIntegration.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#import "SentryCrashIntegration.h"
2+
3+
#import "PrivateSentrySDKOnly.h"
24
#import "SentryCrashC.h"
35
#import "SentryCrashInstallationReporter.h"
46
#import "SentryCrashIntegrationSessionHandler.h"
@@ -157,6 +159,7 @@ - (void)startCrashHandler:(NSString *)cacheDirectory
157159
}
158160

159161
sentrycrashcm_setEnableSigtermReporting(enableSigtermReporting);
162+
sentrycrashcm_setManagedRuntime([PrivateSentrySDKOnly isManagedRuntime]);
160163

161164
[installation install:cacheDirectory];
162165

Sources/Sentry/include/HybridPublic/PrivateSentrySDKOnly.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,12 @@ typedef void (^SentryOnAppStartMeasurementAvailable)(
127127
*/
128128
@property (class, nonatomic, assign) BOOL appStartMeasurementHybridSDKMode;
129129

130+
/**
131+
* Whether the SDK is running in a managed Mono/CoreCLR runtime environment and
132+
* needs to chain Unix signal handlers.
133+
*/
134+
@property (class, nonatomic, assign) BOOL isManagedRuntime;
135+
130136
#if SENTRY_UIKIT_AVAILABLE
131137
/**
132138
* Allows hybrid SDKs to enable frame tracking measurements despite other options.

Sources/Sentry/include/SentryCrashMonitor.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ bool sentrycrashcm_notifyFatalExceptionCaptured(bool isAsyncSafeEnvironment);
9393
*/
9494
void sentrycrashcm_handleException(struct SentryCrash_MonitorContext *context);
9595

96+
/** Whether to chain Unix signal handlers for managed Mono/CoreCLR runtimes.
97+
*/
98+
bool sentrycrashcm_isManagedRuntime(void);
99+
void sentrycrashcm_setManagedRuntime(bool isManagedRuntime);
100+
96101
#ifdef __cplusplus
97102
}
98103
#endif

Sources/SentryCrash/Recording/Monitors/SentryCrashMonitor.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ static SentryCrashMonitorType g_activeMonitors = SentryCrashMonitorTypeNone;
8585
static bool g_handlingFatalException = false;
8686
static bool g_crashedDuringExceptionHandling = false;
8787
static bool g_requiresAsyncSafety = false;
88+
static bool g_isManagedRuntime = false;
8889

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

@@ -226,3 +227,15 @@ sentrycrashcm_handleException(struct SentryCrash_MonitorContext *context)
226227
sentrycrashcm_setActiveMonitors(SentryCrashMonitorTypeNone);
227228
}
228229
}
230+
231+
bool
232+
sentrycrashcm_isManagedRuntime(void)
233+
{
234+
return g_isManagedRuntime;
235+
}
236+
237+
void
238+
sentrycrashcm_setManagedRuntime(bool isManagedRuntime)
239+
{
240+
g_isManagedRuntime = isManagedRuntime;
241+
}

Sources/SentryCrash/Recording/Monitors/SentryCrashMonitor_MachException.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,12 @@ installExceptionHandler(void)
486486
}
487487
}
488488

489+
if (sentrycrashcm_isManagedRuntime()) {
490+
SENTRY_ASYNC_SAFE_LOG_DEBUG("Not registering Mach exception port for EXC_BAD_ACCESS "
491+
"or EXC_MASK_ARITHMETIC in a managed Mono/CoreCLR runtime");
492+
mask &= ~(EXC_MASK_BAD_ACCESS | EXC_MASK_ARITHMETIC);
493+
}
494+
489495
SENTRY_ASYNC_SAFE_LOG_DEBUG("Installing port as exception handler.");
490496
kr = task_set_exception_ports(thisTask, mask, g_exceptionPort,
491497
(int)(EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES), THREAD_STATE_NONE);

Sources/SentryCrash/Recording/Monitors/SentryCrashMonitor_Signal.c

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
//
2727

2828
#include "SentryCrashMonitor_Signal.h"
29+
#include "SentryCrashCPU.h"
2930
#include "SentryCrashID.h"
3031
#include "SentryCrashMachineContext.h"
3132
#include "SentryCrashMonitorContext.h"
@@ -67,6 +68,29 @@ static char g_eventID[37];
6768
# pragma mark - Callbacks -
6869
// ============================================================================
6970

71+
/** Invoke previously installed signal handlers, adapted from Sentry Native:
72+
* https://github.com/getsentry/sentry-native/blob/9895a5c3ffab4e59e0c8020484cdd5dbc648666d/src/backends/sentry_backend_inproc.c#L59-L76
73+
*/
74+
static void
75+
invokePreviousSignalHandlers(int sigNum, siginfo_t *signalInfo, void *userContext)
76+
{
77+
const int *fatalSignals = sentrycrashsignal_fatalSignals();
78+
int fatalSignalsCount = sentrycrashsignal_numFatalSignals();
79+
80+
for (int i = 0; i < fatalSignalsCount; ++i) {
81+
if (fatalSignals[i] == sigNum) {
82+
struct sigaction *handler = &g_previousSignalHandlers[i];
83+
if (handler->sa_flags & SA_SIGINFO) {
84+
handler->sa_sigaction(sigNum, signalInfo, userContext);
85+
} else if (handler->sa_handler != SIG_DFL && handler->sa_handler != SIG_IGN) {
86+
// This handler can only handle to signal number (ANSI C)
87+
void (*func)(int) = handler->sa_handler;
88+
func(sigNum);
89+
}
90+
}
91+
}
92+
}
93+
7094
/** Our custom signal handler.
7195
* Restore the default signal handlers, record the signal information, and
7296
* write a crash report.
@@ -83,6 +107,29 @@ static void
83107
handleSignal(int sigNum, siginfo_t *signalInfo, void *userContext)
84108
{
85109
SENTRY_ASYNC_SAFE_LOG_DEBUG("Trapped signal %d", sigNum);
110+
111+
if (sentrycrashcm_isManagedRuntime()) {
112+
// Let managed Mono/CoreCLR runtime handle the signal first,
113+
// as they may convert it into a managed exception.
114+
SENTRY_ASYNC_SAFE_LOG_DEBUG(
115+
"Detected managed Mono/CoreCLR runtime. Passing signal to previous handlers.");
116+
117+
uintptr_t sp = sentrycrashcpu_stackPointerFromUserContext(userContext);
118+
uintptr_t ip = sentrycrashcpu_instructionAddressFromUserContext(userContext);
119+
120+
invokePreviousSignalHandlers(sigNum, signalInfo, userContext);
121+
122+
// If the stack or instruction pointer changed, the managed runtime
123+
// converted the signal into a managed exception and changed the context.
124+
// https://github.com/dotnet/runtime/blob/6d96e28597e7da0d790d495ba834cc4908e442cd/src/mono/mono/mini/exceptions-arm64.c#L538
125+
if (sp != sentrycrashcpu_stackPointerFromUserContext(userContext)
126+
|| ip != sentrycrashcpu_instructionAddressFromUserContext(userContext)) {
127+
SENTRY_ASYNC_SAFE_LOG_DEBUG(
128+
"Signal converted to a managed exception. Aborting signal handling.");
129+
return;
130+
}
131+
}
132+
86133
if (g_isEnabled) {
87134
thread_act_array_t threads = NULL;
88135
mach_msg_type_number_t numThreads = 0;
@@ -110,9 +157,13 @@ handleSignal(int sigNum, siginfo_t *signalInfo, void *userContext)
110157
sentrycrashmc_resumeEnvironment(threads, numThreads);
111158
}
112159

113-
SENTRY_ASYNC_SAFE_LOG_DEBUG("Re-raising signal for regular handlers to catch.");
114-
// This is technically not allowed, but it works in OSX and iOS.
115-
raise(sigNum);
160+
// Re-raise the signal to invoke the previous handlers unless already called
161+
// above for managed runtimes.
162+
if (!sentrycrashcm_isManagedRuntime()) {
163+
SENTRY_ASYNC_SAFE_LOG_DEBUG("Re-raising signal for regular handlers to catch.");
164+
// This is technically not allowed, but it works in OSX and iOS.
165+
raise(sigNum);
166+
}
116167
}
117168

118169
// ============================================================================

Sources/SentryCrash/Recording/Tools/SentryCrashCPU.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ const char *sentrycrashcpu_currentArch(void);
5151
* @return The context's frame pointer.
5252
*/
5353
uintptr_t sentrycrashcpu_framePointer(const struct SentryCrashMachineContext *const context);
54+
uintptr_t sentrycrashcpu_framePointerFromUserContext(const void *const userContext);
5455

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

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

7275
/** Get the address stored in the link register (arm only). This may
7376
* contain the first return address of the stack.

Sources/SentryCrash/Recording/Tools/SentryCrashCPU_arm.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,36 @@ sentrycrashcpu_framePointer(const SentryCrashMachineContext *const context)
4949
return context->machineContext.__ss.__r[7];
5050
}
5151

52+
uintptr_t
53+
sentrycrashcpu_framePointerFromUserContext(const void *const userContext)
54+
{
55+
return ((const ucontext_t *)userContext)->uc_mcontext->__ss.__r[7];
56+
}
57+
5258
uintptr_t
5359
sentrycrashcpu_stackPointer(const SentryCrashMachineContext *const context)
5460
{
5561
return context->machineContext.__ss.__sp;
5662
}
5763

64+
uintptr_t
65+
sentrycrashcpu_stackPointerFromUserContext(const void *const userContext)
66+
{
67+
return ((const ucontext_t *)userContext)->uc_mcontext->__ss.__sp;
68+
}
69+
5870
uintptr_t
5971
sentrycrashcpu_instructionAddress(const SentryCrashMachineContext *const context)
6072
{
6173
return context->machineContext.__ss.__pc;
6274
}
6375

76+
uintptr_t
77+
sentrycrashcpu_instructionAddressFromUserContext(const void *const userContext)
78+
{
79+
return ((const ucontext_t *)userContext)->uc_mcontext->__ss.__pc;
80+
}
81+
6482
uintptr_t
6583
sentrycrashcpu_linkRegister(const SentryCrashMachineContext *const context)
6684
{

0 commit comments

Comments
 (0)