Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
811ed51
docs: map existing codebase
itaybre Feb 13, 2026
10c5625
docs: initialize project
itaybre Feb 13, 2026
19fc5ab
chore: add project config
itaybre Feb 13, 2026
2065270
docs: define v1 requirements
itaybre Feb 13, 2026
2bf41d4
docs: create roadmap (5 phases)
itaybre Feb 13, 2026
ad95b86
docs(phase-01): research facade design domain
itaybre Feb 13, 2026
8356b89
docs(01-facade-design-implementation): create phase plan
itaybre Feb 13, 2026
a0ba83e
feat(01-facade-design-implementation): create SentryCrashBridge facad…
itaybre Feb 13, 2026
02debdd
docs(01-facade-design-implementation): complete 01-01-PLAN.md
itaybre Feb 13, 2026
22d7fd2
feat(01-facade-design-implementation): integrate SentryCrashBridge in…
itaybre Feb 13, 2026
f06b523
test(01-facade-design-implementation): add missing protocol conforman…
itaybre Feb 13, 2026
708b69a
docs(01-facade-design-implementation): complete 01-02-PLAN.md
itaybre Feb 13, 2026
55434e2
docs(phase-1): complete phase execution
itaybre Feb 13, 2026
5d6fb07
docs(02-swift-isolation): research Swift dependency injection and bri…
itaybre Feb 13, 2026
48f185b
docs(02-swift-isolation): create phase plan with 2 plans in wave 1
itaybre Feb 13, 2026
7bee0d1
feat(02-swift-isolation): inject bridge into SentryCrashWrapper
itaybre Feb 13, 2026
d74a3f2
test(02-swift-isolation): update tests for bridge parameter
itaybre Feb 13, 2026
d658ec1
feat(02-swift-isolation): inject bridge into SentryCrashIntegrationSe…
itaybre Feb 13, 2026
4e63349
docs(02-swift-isolation): complete 02-01-PLAN.md execution
itaybre Feb 13, 2026
51aa2e7
docs(02-swift-isolation): complete 02-02-PLAN.md
itaybre Feb 13, 2026
11bea7e
docs(phase-2): complete phase execution
itaybre Feb 13, 2026
bb18a7f
docs(03-objc-isolation): research phase domain
itaybre Feb 13, 2026
eef3e2b
docs(03-objc-isolation): create phase plans
itaybre Feb 13, 2026
5c86043
feat(03-03): eliminate container refs from SentryCrashWrapper
itaybre Feb 13, 2026
96df891
docs(03-03): complete eliminate container refs plan
itaybre Feb 13, 2026
cf45971
feat(03-objc-isolation): add bridge property to SentryCrash
itaybre Feb 13, 2026
9cd8332
feat(03-objc-isolation): wire bridge from SentryCrashIntegration to S…
itaybre Feb 13, 2026
d59ab2a
feat(03-objc-isolation): inject bridge into NSException monitor
itaybre Feb 13, 2026
599ee7b
docs(03-objc-isolation): complete 03-01 plan
itaybre Feb 13, 2026
4090604
feat(03-02): add bridge property to SentryCrashInstallation base class
itaybre Feb 13, 2026
b3301dc
feat(03-02): inject bridge into SentryCrashInstallation from SentryCr…
itaybre Feb 13, 2026
648f2a2
docs(03-02): complete SentryCrashInstallation bridge injection plan
itaybre Feb 13, 2026
5455e0f
docs(phase-03): complete phase execution
itaybre Feb 24, 2026
039641b
docs(04-verification): create phase plan
itaybre Feb 24, 2026
4abc6c5
docs(04-verification): create verification phase plan
itaybre Feb 24, 2026
81c5db6
plan(phase-5): add documentation plan for SentryCrashBridge facade pa…
itaybre Feb 24, 2026
16cc298
Remove planning docs
itaybre Feb 24, 2026
806596e
refactor(SentryDependencyContainer): implement lazy initialization fo…
itaybre Feb 24, 2026
a7bbc9c
Run format
itaybre Mar 10, 2026
f97754b
docs(SentryCrashBridge): enhance documentation for SentryCrashBridge …
itaybre Mar 10, 2026
cbb6d35
fix(SentryCrashWrapper): enable system monitor before reading systemI…
itaybre Mar 10, 2026
04d2f72
fix(SentryCrash): set NSException bridge before installation to ensur…
itaybre Mar 10, 2026
df19413
Make SentryCrashBridge non null
itaybre Mar 12, 2026
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
22 changes: 11 additions & 11 deletions Sources/Sentry/SentryClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,7 @@ - (SentryEvent *_Nullable)prepareEvent:(SentryEvent *_Nullable)event

#if SENTRY_HAS_UIKIT
if (!isFatalEvent && eventIsNotReplay) {
NSDictionary *currentContext = event.context ?: @{};
NSDictionary *currentContext = event.context ?: @{ };
event.context = [self.eventContextEnricher enrichWithAppState:currentContext];
}
#endif
Expand Down Expand Up @@ -975,19 +975,19 @@ - (void)applyExtraDeviceContextToEvent:(SentryEvent *)event
[extraContext[SENTRY_CONTEXT_DEVICE_KEY]
isKindOfClass:NSDictionary.class]) {
[device addEntriesFromDictionary:extraContext[SENTRY_CONTEXT_DEVICE_KEY]
?: @ {}];
?: @ { }];
}
}];

[self
modifyContext:event
key:SENTRY_CONTEXT_APP_KEY
block:^(NSMutableDictionary *app) {
if (extraContext[SENTRY_CONTEXT_APP_KEY] != nil &&
[extraContext[SENTRY_CONTEXT_APP_KEY] isKindOfClass:NSDictionary.class]) {
[app addEntriesFromDictionary:extraContext[SENTRY_CONTEXT_APP_KEY] ?: @ {}];
}
}];
[self modifyContext:event
key:SENTRY_CONTEXT_APP_KEY
block:^(NSMutableDictionary *app) {
if (extraContext[SENTRY_CONTEXT_APP_KEY] != nil &&
[extraContext[SENTRY_CONTEXT_APP_KEY] isKindOfClass:NSDictionary.class]) {
[app addEntriesFromDictionary:extraContext[SENTRY_CONTEXT_APP_KEY]
?: @ { }];
}
}];
}

#if SENTRY_HAS_UIKIT
Expand Down
9 changes: 5 additions & 4 deletions Sources/Sentry/SentryCrashReportConverter.m
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ - (instancetype)initWithReport:(NSDictionary *)report inAppLogic:(SentryInAppLog
// here. For more details please check out SentryCrashScopeObserver.
NSMutableDictionary *userContextMerged =
[[NSMutableDictionary alloc] initWithDictionary:userContextUnMerged];
[userContextMerged addEntriesFromDictionary:report[@"sentry_sdk_scope"] ?: @{}];
[userContextMerged addEntriesFromDictionary:report[@"sentry_sdk_scope"] ?: @{ }];
[userContextMerged removeObjectForKey:@"sentry_sdk_scope"];
self.userContext = userContextMerged;

Expand Down Expand Up @@ -120,7 +120,7 @@ - (SentryEvent *_Nullable)convertReportToEvent
event.environment = self.userContext[@"environment"];

NSMutableDictionary *mutableContext =
[[NSMutableDictionary alloc] initWithDictionary:self.userContext[@"context"] ?: @{}];
[[NSMutableDictionary alloc] initWithDictionary:self.userContext[@"context"] ?: @{ }];
if (self.userContext[@"traceContext"]) {
mutableContext[@"trace"] = self.userContext[@"traceContext"];
}
Expand Down Expand Up @@ -513,8 +513,9 @@ - (void)enhanceValueFromNotableAddresses:(SentryException *)exception
}
}
if (reasons.count > 0) {
exception.value = [[[reasons array] sortedArrayUsingSelector:@selector
(localizedCaseInsensitiveCompare:)] componentsJoinedByString:@" > "];
exception.value =
[[[reasons array] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]
componentsJoinedByString:@" > "];
}
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/Sentry/SentryHub.m
Original file line number Diff line number Diff line change
Expand Up @@ -399,15 +399,15 @@ - (void)captureReplayEvent:(SentryReplayEvent *)replayEvent

- (id<SentrySpan>)startTransactionWithContext:(SentryTransactionContext *)transactionContext
{
return [self startTransactionWithContext:transactionContext customSamplingContext:@{}];
return [self startTransactionWithContext:transactionContext customSamplingContext:@{ }];
}

- (id<SentrySpan>)startTransactionWithContext:(SentryTransactionContext *)transactionContext
bindToScope:(BOOL)bindToScope
{
return [self startTransactionWithContext:transactionContext
bindToScope:bindToScope
customSamplingContext:@{}];
customSamplingContext:@{ }];
}

- (id<SentrySpan>)startTransactionWithContext:(SentryTransactionContext *)transactionContext
Expand Down
4 changes: 2 additions & 2 deletions Sources/Sentry/SentryNoOpSpan.m
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ - (void)setMeasurement:(NSString *)name value:(NSNumber *)value unit:(SentryMeas

- (NSDictionary<NSString *, id> *)tags
{
return @{};
return @{ };
}

- (BOOL)isFinished
Expand All @@ -95,7 +95,7 @@ - (SentryTraceHeader *)toTraceHeader

- (NSDictionary *)serialize
{
return @{};
return @{ };
}

@end
Expand Down
2 changes: 1 addition & 1 deletion Sources/Sentry/SentryPerformanceTracker.m
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ - (SentrySpanId *)startSpanWithName:(NSString *)name
newSpan = [SentrySDKInternal.currentHub
startTransactionWithContext:context
bindToScope:bindToScope
customSamplingContext:@{}
customSamplingContext:@{ }
configuration:[SentryTracerConfiguration configurationWithBlock:^(
SentryTracerConfiguration *configuration) {
configuration.waitForChildren = YES;
Expand Down
2 changes: 1 addition & 1 deletion Sources/Sentry/SentryStacktraceBuilder.m
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ + (SentryStacktrace *_Nonnull)buildStacktraceFromFrames:(NSArray<SentryFrame *>
// The frames must be ordered from caller to callee, or oldest to youngest
NSArray<SentryFrame *> *framesReversed = [[framesCleared reverseObjectEnumerator] allObjects];

return [[SentryStacktrace alloc] initWithFrames:framesReversed registers:@{}];
return [[SentryStacktrace alloc] initWithFrames:framesReversed registers:@{ }];
}

@end
Expand Down
8 changes: 4 additions & 4 deletions Sources/Sentry/SentryThreadHandle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,14 @@ namespace profiling {
{
const auto handle = pthreadHandle();
if (handle == nullptr) {
return {};
return { };
}
char name[MAXTHREADNAMESIZE];
if (SENTRY_ASYNC_SAFE_LOG_ERRNO_RETURN(pthread_getname_np(handle, name, sizeof(name)))
== 0) {
return std::string(name);
}
return {};
return { };
}

int
Expand Down Expand Up @@ -158,7 +158,7 @@ namespace profiling {
ThreadHandle::cpuInfo() const noexcept
{
if (handle_ == THREAD_NULL) {
return {};
return { };
}
ThreadCPUInfo cpuInfo;
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
Expand Down Expand Up @@ -203,7 +203,7 @@ namespace profiling {
{
const auto handle = pthreadHandle();
if (handle == nullptr) {
return {};
return { };
}
const auto start = reinterpret_cast<std::uintptr_t>(pthread_get_stackaddr_np(handle));
const auto end = start - pthread_get_stacksize_np(handle);
Expand Down
2 changes: 1 addition & 1 deletion Sources/Sentry/SentryTracer.m
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,7 @@ - (void)addAppStartMeasurements:(SentryTransaction *)transaction
? [NSString stringWithFormat:@"%@.prewarmed", appContextType]
: appContextType;
NSMutableDictionary *context =
[[NSMutableDictionary alloc] initWithDictionary:[transaction context] ?: @{}];
[[NSMutableDictionary alloc] initWithDictionary:[transaction context] ?: @{ }];
NSDictionary *appContext = @{ @"app" : @ { @"start_type" : appStartType } };
[SentryDictionary mergeEntriesFromDictionary:appContext intoDictionary:context];
[transaction setContext:context];
Expand Down
4 changes: 2 additions & 2 deletions Sources/Sentry/SentryTransaction.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ - (instancetype)initWithTrace:(SentryTracer *)trace children:(NSArray<id<SentryS
}

// Merge event tags and tracer tags (tracer tags take precedence)
NSDictionary<NSString *, NSString *> *eventTags = [super tags] ?: @{};
NSDictionary<NSString *, NSString *> *tracerTags = self.trace.tags ?: @{};
NSDictionary<NSString *, NSString *> *eventTags = [super tags] ?: @{ };
NSDictionary<NSString *, NSString *> *tracerTags = self.trace.tags ?: @{ };

// Merge both, with tracer tags taking precedence
// Note: We return a mutable dictionary copy (though declared as NSDictionary *).
Expand Down
2 changes: 1 addition & 1 deletion Sources/Sentry/SentryUIEventTrackerTransactionMode.m
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ - (void)handleUIEvent:(NSString *)action
__block SentryTracer *transaction = [SentrySDKInternal.currentHub
startTransactionWithContext:context
bindToScope:YES
customSamplingContext:@{}
customSamplingContext:@{ }
configuration:[SentryTracerConfiguration configurationWithBlock:^(
SentryTracerConfiguration *config) {
config.idleTimeout = self.idleTimeout;
Expand Down
24 changes: 17 additions & 7 deletions Sources/Sentry/include/SentryCrash.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
#import "SentryCrashReportWriter.h"
#import "SentryDefines.h"

@class SentryCrashBridge;

typedef enum {
SentryCrashDemangleLanguageNone = 0,
SentryCrashDemangleLanguageCPlusPlus = 1,
Expand All @@ -43,7 +45,9 @@ typedef enum {
SentryCrashCDeleteAlways
} SentryCrashCDeleteBehavior;

static NSString *const SENTRYCRASH_REPORT_ATTACHMENTS_ITEM = @"attachments";
static NSString *_Nonnull const SENTRYCRASH_REPORT_ATTACHMENTS_ITEM = @"attachments";

NS_ASSUME_NONNULL_BEGIN

/**
* Reports any crashes that occur in the application.
Expand All @@ -57,18 +61,22 @@ static NSString *const SENTRYCRASH_REPORT_ATTACHMENTS_ITEM = @"attachments";
SENTRY_NO_INIT

/** Init SentryCrash instance with custom base path. */
- (instancetype)initWithBasePath:(NSString *)basePath NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithBasePath:(nullable NSString *)basePath NS_DESIGNATED_INITIALIZER;

/** Cache directory base path. */
@property (nonatomic, readwrite, retain) NSString *basePath;

/** Bridge to SDK services (notification center, date provider, crash reporter).
* Must be set before calling install. */
@property (nonatomic, strong) SentryCrashBridge *bridge;

/** A dictionary containing any info you'd like to appear in crash reports. Must
* contain only JSON-safe data: NSString for keys, and NSDictionary, NSArray,
* NSString, NSDate, and NSNumber for values.
*
* Default: nil
*/
@property (atomic, readwrite, retain) NSDictionary *userInfo;
@property (atomic, readwrite, retain, nullable) NSDictionary *userInfo;

/** What to do after sending reports via sendAllReportsWithCompletion:
*
Expand Down Expand Up @@ -110,7 +118,7 @@ SENTRY_NO_INIT
*
* Default: nil
*/
@property (nonatomic, readwrite, retain) NSArray *doNotIntrospectClasses;
@property (nonatomic, readwrite, retain, nullable) NSArray *doNotIntrospectClasses;

/** The maximum number of reports allowed on disk before old ones get deleted.
*
Expand All @@ -125,7 +133,7 @@ SENTRY_NO_INIT
* Note: If you use an installation, it will automatically set this property.
* Do not modify it in such a case.
*/
@property (nonatomic, readwrite, retain) id<SentryCrashReportFilter> sink;
@property (nonatomic, readwrite, retain, nullable) id<SentryCrashReportFilter> sink;

/** C Function to call during a crash report to give the callee an opportunity
* to add to the report. NULL = ignore.
Expand All @@ -136,7 +144,7 @@ SENTRY_NO_INIT
* Note: If you use an installation, it will automatically set this property.
* Do not modify it in such a case.
*/
@property (nonatomic, readwrite, assign) SentryCrashReportWriteCallback onCrash;
@property (nonatomic, readwrite, assign, nullable) SentryCrashReportWriteCallback onCrash;

/** Print the previous app run log to the console when installing SentryCrash.
* This is primarily for debugging purposes.
Expand All @@ -149,7 +157,7 @@ SENTRY_NO_INIT

/** Exposes the uncaughtExceptionHandler if set from SentryCrash. Is nil if
* debugger is running. **/
@property (nonatomic, assign) NSUncaughtExceptionHandler *uncaughtExceptionHandler;
@property (nonatomic, assign, nullable) NSUncaughtExceptionHandler *uncaughtExceptionHandler;

#pragma mark - Information -

Expand Down Expand Up @@ -241,6 +249,8 @@ SENTRY_NO_INIT

@end

NS_ASSUME_NONNULL_END

//! Project version number for SentryCrashFramework.
FOUNDATION_EXPORT const double SentryCrashFrameworkVersionNumber;

Expand Down
6 changes: 6 additions & 0 deletions Sources/Sentry/include/SentryCrashInstallation.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

NS_ASSUME_NONNULL_BEGIN

@class SentryCrashBridge;

/**
* Crash system installation which handles backend-specific details.
*
Expand Down Expand Up @@ -60,6 +62,10 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)sendAllReportsWithCompletion:(nullable SentryCrashReportFilterCompletion)onCompletion;

/** Bridge for accessing SDK services without dependency container.
* Must be set by SentryCrashIntegration before calling install. */
@property (nonatomic, strong) SentryCrashBridge *bridge;

@end

NS_ASSUME_NONNULL_END
8 changes: 4 additions & 4 deletions Sources/SentryCrash/Installations/SentryCrashInstallation.m
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ - (id)initWithRequiredProperties:(NSArray *)requiredProperties

- (void)dealloc
{
SentryCrashSwift *handler = SentryDependencyContainer.sharedInstance.crashReporter;
SentryCrashSwift *handler = self.bridge.crashReporter;
@synchronized(handler) {
if (g_crashHandlerData == self.crashHandlerData) {
g_crashHandlerData = NULL;
Expand Down Expand Up @@ -162,7 +162,7 @@ - (NSArray *)makeKeyPaths:(NSArray *)keyPaths

- (void)install:(NSString *)customCacheDirectory
{
SentryCrashSwift *handler = SentryDependencyContainer.sharedInstance.crashReporter;
SentryCrashSwift *handler = self.bridge.crashReporter;
@synchronized(handler) {
handler.basePath = customCacheDirectory;
g_crashHandlerData = self.crashHandlerData;
Expand All @@ -173,7 +173,7 @@ - (void)install:(NSString *)customCacheDirectory

- (void)uninstall
{
SentryCrashSwift *handler = SentryDependencyContainer.sharedInstance.crashReporter;
SentryCrashSwift *handler = self.bridge.crashReporter;
@synchronized(handler) {
if (g_crashHandlerData == self.crashHandlerData) {
g_crashHandlerData = NULL;
Expand Down Expand Up @@ -204,7 +204,7 @@ - (void)sendAllReportsWithCompletion:(SentryCrashReportFilterCompletion)onComple

sink = [SentryCrashReportFilterPipeline filterWithFilters:sink, nil];

SentryCrashSwift *handler = SentryDependencyContainer.sharedInstance.crashReporter;
SentryCrashSwift *handler = self.bridge.crashReporter;
handler.sink =
[[SentryCrashReportFilterSwift alloc] initWithFilterReports:^(NSArray *_Nonnull array,
void (^_Nonnull completion)(NSArray *_Nullable, BOOL, NSError *_Nullable)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,24 @@
#ifndef HDR_SentryCrashMonitor_NSException_h
#define HDR_SentryCrashMonitor_NSException_h

#ifdef __OBJC__
@class SentryCrashBridge;
#endif

#ifdef __cplusplus
extern "C" {
#endif

#include "SentryCrashMonitor.h"

#ifdef __OBJC__
/** Set the bridge for accessing SDK services. Must be called before enabling the monitor. */
void sentrycrashcm_nsexception_setBridge(SentryCrashBridge *_Nullable bridge);
#endif

/** Access the Monitor API.
*/
SentryCrashMonitorAPI *sentrycrashcm_nsexception_getAPI(void);
SentryCrashMonitorAPI *_Nonnull sentrycrashcm_nsexception_getAPI(void);

#ifdef __cplusplus
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
/** The exception handler that was in place before we installed ours. */
static NSUncaughtExceptionHandler *g_previousUncaughtExceptionHandler;

/** Bridge for accessing SDK services. */
static SentryCrashBridge *g_bridge = nil;

// ============================================================================
#pragma mark - Callbacks -
// ============================================================================
Expand Down Expand Up @@ -113,6 +116,12 @@
#pragma mark - API -
// ============================================================================

void
sentrycrashcm_nsexception_setBridge(SentryCrashBridge *bridge)
{
g_bridge = bridge;
}

static void
setEnabled(bool isEnabled)
{
Expand All @@ -124,8 +133,7 @@

SENTRY_LOG_DEBUG(@"Setting new handler.");
NSSetUncaughtExceptionHandler(&handleUncaughtException);
SentryDependencyContainer.sharedInstance.crashReporter.uncaughtExceptionHandler
= &handleUncaughtException;
g_bridge.crashReporter.uncaughtExceptionHandler = &handleUncaughtException;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nil bridge silently skips uncaught exception handler registration

High Severity

If g_bridge is nil when the NSException monitor is enabled, g_bridge.crashReporter.uncaughtExceptionHandler = &handleUncaughtException silently becomes a no-op due to ObjC nil messaging. The handler is still installed globally via NSSetUncaughtExceptionHandler, but the crash reporter's uncaughtExceptionHandler property won't be set. The previous code via SentryDependencyContainer.sharedInstance guaranteed non-nil access. No warning or error is logged for this failure.

Fix in Cursor Fix in Web

} else {
SENTRY_LOG_DEBUG(@"Restoring original handler.");
NSSetUncaughtExceptionHandler(g_previousUncaughtExceptionHandler);
Expand Down
Loading
Loading