Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
24 changes: 8 additions & 16 deletions Sentry.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -453,15 +453,13 @@
F44858132E03579D0013E63B /* SentryCrashDynamicLinker+Test.h in Headers */ = {isa = PBXBuildFile; fileRef = F44858122E0357940013E63B /* SentryCrashDynamicLinker+Test.h */; };
F44D2B5C2E6B7E8700FF31FA /* SentryProfilingScreenFramesHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = F44D2B5A2E6B7E8700FF31FA /* SentryProfilingScreenFramesHelper.h */; };
F44D2B5D2E6B7E8700FF31FA /* SentryProfilingScreenFramesHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = F44D2B5B2E6B7E8700FF31FA /* SentryProfilingScreenFramesHelper.m */; };
F452437E2DE60B71003E8F50 /* SentryUseNSExceptionCallstackWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = F452437D2DE60B71003E8F50 /* SentryUseNSExceptionCallstackWrapper.m */; };
F452438C2DE65BC0003E8F50 /* SentryUseNSExceptionCallstackWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = F452438B2DE65BC0003E8F50 /* SentryUseNSExceptionCallstackWrapper.h */; };
F459B01D2F2AB1480096AA8B /* SentryAppStartTrackerHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = F459B01C2F2AB1480096AA8B /* SentryAppStartTrackerHelper.m */; };
F459B0242F2AB1560096AA8B /* SentryAppStartTrackerHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = F459B0232F2AB1560096AA8B /* SentryAppStartTrackerHelper.h */; };
F485E2832F293E1A00B66F52 /* SentryUIViewControllerSwizzlingHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = F485E2822F293E1A00B66F52 /* SentryUIViewControllerSwizzlingHelper.m */; };
F485E28A2F293E2900B66F52 /* SentryUIViewControllerSwizzlingHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = F485E2892F293E2900B66F52 /* SentryUIViewControllerSwizzlingHelper.h */; };
F48F21F52EF1F05000E33FC1 /* SentryAppStartMeasurement+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = F48F21F42EF1F04C00E33FC1 /* SentryAppStartMeasurement+Private.h */; };
F49D419C2DEA30C300D9244E /* SentryCrashExceptionApplicationHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = F49D419B2DEA30B800D9244E /* SentryCrashExceptionApplicationHelper.h */; };
F49D419E2DEA3D0600D9244E /* SentryCrashExceptionApplicationHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = F49D419D2DEA3D0300D9244E /* SentryCrashExceptionApplicationHelper.m */; };
F49D419C2DEA30C300D9244E /* SentryNSExceptionCaptureHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = F49D419B2DEA30B800D9244E /* SentryNSExceptionCaptureHelper.h */; };
F49D419E2DEA3D0600D9244E /* SentryNSExceptionCaptureHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = F49D419D2DEA3D0300D9244E /* SentryNSExceptionCaptureHelper.m */; };
F4F33D4C2F1F35BA00753FE2 /* SentryNSDataSwizzlingHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = F4F33D4A2F1F35BA00753FE2 /* SentryNSDataSwizzlingHelper.m */; };
F4F33D4D2F1F35BA00753FE2 /* SentryNSFileManagerSwizzlingHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = F4F33D4B2F1F35BA00753FE2 /* SentryNSFileManagerSwizzlingHelper.m */; };
FA24E02A2EBBF6F900EFD92E /* SentryOptionsObjC.h in Headers */ = {isa = PBXBuildFile; fileRef = FA24E0292EBBF6F500EFD92E /* SentryOptionsObjC.h */; };
Expand Down Expand Up @@ -1115,15 +1113,13 @@
F44858122E0357940013E63B /* SentryCrashDynamicLinker+Test.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SentryCrashDynamicLinker+Test.h"; sourceTree = "<group>"; };
F44D2B5A2E6B7E8700FF31FA /* SentryProfilingScreenFramesHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SentryProfilingScreenFramesHelper.h; sourceTree = "<group>"; };
F44D2B5B2E6B7E8700FF31FA /* SentryProfilingScreenFramesHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryProfilingScreenFramesHelper.m; sourceTree = "<group>"; };
F452437D2DE60B71003E8F50 /* SentryUseNSExceptionCallstackWrapper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryUseNSExceptionCallstackWrapper.m; sourceTree = "<group>"; };
F452438B2DE65BC0003E8F50 /* SentryUseNSExceptionCallstackWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryUseNSExceptionCallstackWrapper.h; path = include/SentryUseNSExceptionCallstackWrapper.h; sourceTree = "<group>"; };
F459B01C2F2AB1480096AA8B /* SentryAppStartTrackerHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryAppStartTrackerHelper.m; sourceTree = "<group>"; };
F459B0232F2AB1560096AA8B /* SentryAppStartTrackerHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryAppStartTrackerHelper.h; path = include/SentryAppStartTrackerHelper.h; sourceTree = "<group>"; };
F485E2822F293E1A00B66F52 /* SentryUIViewControllerSwizzlingHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryUIViewControllerSwizzlingHelper.m; sourceTree = "<group>"; };
F485E2892F293E2900B66F52 /* SentryUIViewControllerSwizzlingHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryUIViewControllerSwizzlingHelper.h; path = include/SentryUIViewControllerSwizzlingHelper.h; sourceTree = "<group>"; };
F48F21F42EF1F04C00E33FC1 /* SentryAppStartMeasurement+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SentryAppStartMeasurement+Private.h"; path = "include/SentryAppStartMeasurement+Private.h"; sourceTree = "<group>"; };
F49D419B2DEA30B800D9244E /* SentryCrashExceptionApplicationHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryCrashExceptionApplicationHelper.h; path = include/SentryCrashExceptionApplicationHelper.h; sourceTree = "<group>"; };
F49D419D2DEA3D0300D9244E /* SentryCrashExceptionApplicationHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryCrashExceptionApplicationHelper.m; sourceTree = "<group>"; };
F49D419B2DEA30B800D9244E /* SentryNSExceptionCaptureHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryNSExceptionCaptureHelper.h; path = include/SentryNSExceptionCaptureHelper.h; sourceTree = "<group>"; };
F49D419D2DEA3D0300D9244E /* SentryNSExceptionCaptureHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryNSExceptionCaptureHelper.m; sourceTree = "<group>"; };
F4F33D4A2F1F35BA00753FE2 /* SentryNSDataSwizzlingHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryNSDataSwizzlingHelper.m; sourceTree = "<group>"; };
F4F33D4B2F1F35BA00753FE2 /* SentryNSFileManagerSwizzlingHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryNSFileManagerSwizzlingHelper.m; sourceTree = "<group>"; };
F4F33D4E2F1F35C500753FE2 /* SentryNSDataSwizzlingHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryNSDataSwizzlingHelper.h; path = include/SentryNSDataSwizzlingHelper.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1401,8 +1397,8 @@
children = (
632F434E1F581D5400A18A36 /* SentryCrashExceptionApplication.h */,
632F434F1F581D5400A18A36 /* SentryCrashExceptionApplication.m */,
F49D419B2DEA30B800D9244E /* SentryCrashExceptionApplicationHelper.h */,
F49D419D2DEA3D0300D9244E /* SentryCrashExceptionApplicationHelper.m */,
F49D419B2DEA30B800D9244E /* SentryNSExceptionCaptureHelper.h */,
F49D419D2DEA3D0300D9244E /* SentryNSExceptionCaptureHelper.m */,
6344DDB21EC309E000D9160D /* SentryCrashReportSink.h */,
6344DDB31EC309E000D9160D /* SentryCrashReportSink.m */,
6344DDB71EC3115C00D9160D /* SentryCrashReportConverter.h */,
Expand Down Expand Up @@ -1505,8 +1501,6 @@
844EDC75294144DB00C86F34 /* SentrySystemWrapper.mm */,
FAB359972E05D7E90083D5E3 /* SentryEventSwiftHelper.h */,
FAB359992E05D8080083D5E3 /* SentryEventSwiftHelper.m */,
F452438B2DE65BC0003E8F50 /* SentryUseNSExceptionCallstackWrapper.h */,
F452437D2DE60B71003E8F50 /* SentryUseNSExceptionCallstackWrapper.m */,
);
name = Helper;
sourceTree = "<group>";
Expand Down Expand Up @@ -2366,7 +2360,7 @@
84AF45A629A7FFA500FBB177 /* SentryProfiledTracerConcurrency.h in Headers */,
8EAE980B261E9F530073B6B3 /* SentryPerformanceTracker.h in Headers */,
63FE718520DA4C1100CDBAE8 /* SentryCrashC.h in Headers */,
F49D419C2DEA30C300D9244E /* SentryCrashExceptionApplicationHelper.h in Headers */,
F49D419C2DEA30C300D9244E /* SentryNSExceptionCaptureHelper.h in Headers */,
A8AFFCCD29069C3E00967CD7 /* SentryHttpStatusCodeRange.h in Headers */,
FAAB95DE2EA1EB470030A2DB /* SentryDeviceContextKeys.h in Headers */,
D83D079B2B7F9D1C00CC9674 /* SentryMsgPackSerializer.h in Headers */,
Expand Down Expand Up @@ -2486,7 +2480,6 @@
63FE716F20DA4C1100CDBAE8 /* SentryCrashCPU_Apple.h in Headers */,
639FCFA81EBC80CC00778193 /* SentryFrame.h in Headers */,
D8BFE37229A3782F002E73F3 /* SentryTimeToDisplayTracker.h in Headers */,
F452438C2DE65BC0003E8F50 /* SentryUseNSExceptionCallstackWrapper.h in Headers */,
63FE716D20DA4C1100CDBAE8 /* SentryCrashSysCtl.h in Headers */,
639889BB1EDED18400EA7442 /* SentrySwizzle.h in Headers */,
FA7206DF2E0B37850072FDD4 /* SentryProfileCollector.h in Headers */,
Expand Down Expand Up @@ -2900,7 +2893,7 @@
63FE712F20DA4C1100CDBAE8 /* SentryCrashSysCtl.c in Sources */,
7B3B473825D6CC7E00D01640 /* SentryNSError.m in Sources */,
621AE74D2C626C510012E730 /* SentryANRTrackerV2.m in Sources */,
F49D419E2DEA3D0600D9244E /* SentryCrashExceptionApplicationHelper.m in Sources */,
F49D419E2DEA3D0600D9244E /* SentryNSExceptionCaptureHelper.m in Sources */,
D8ACE3C82762187200F5A213 /* SentryFileIOTrackerHelper.m in Sources */,
D8B088B729C9E3FF00213258 /* SentryTracerConfiguration.m in Sources */,
FA7206E12E0B37C80072FDD4 /* SentryProfileCollector.mm in Sources */,
Expand Down Expand Up @@ -3000,7 +2993,6 @@
62C316832B1F2EA1000D7031 /* SentryDelayedFramesTracker.m in Sources */,
D8BFE37329A3782F002E73F3 /* SentryTimeToDisplayTracker.m in Sources */,
6334314320AD9AE40077E581 /* SentryMechanism.m in Sources */,
F452437E2DE60B71003E8F50 /* SentryUseNSExceptionCallstackWrapper.m in Sources */,
63FE70D320DA4C1000CDBAE8 /* SentryCrashMonitor_AppState.c in Sources */,
639FCFA51EBC809A00778193 /* SentryStacktrace.m in Sources */,
84A898542E163072009A551E /* SentryProfileConfiguration.m in Sources */,
Expand Down
9 changes: 0 additions & 9 deletions Sources/Sentry/SentryClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
#import "SentryTransport.h"
#import "SentryTransportAdapter.h"
#import "SentryTransportFactory.h"
#import "SentryUseNSExceptionCallstackWrapper.h"
#import "SentryUser.h"

#if SENTRY_HAS_UIKIT
Expand Down Expand Up @@ -184,14 +183,6 @@ - (SentryEvent *)buildExceptionEvent:(NSException *)exception

event.exceptions = @[ sentryException ];

#if TARGET_OS_OSX
// When a exception class is SentryUseNSExceptionCallstackWrapper, we should use the thread from
// it
if ([exception isKindOfClass:[SentryUseNSExceptionCallstackWrapper class]]) {
event.threads = [(SentryUseNSExceptionCallstackWrapper *)exception buildThreads];
}
#endif

[self setUserInfo:exception.userInfo withEvent:event];
return event;
}
Expand Down
14 changes: 11 additions & 3 deletions Sources/Sentry/SentryCrashExceptionApplication.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@
#if TARGET_OS_OSX && !SENTRY_NO_UI_FRAMEWORK

# import "SentryCrashExceptionApplication.h"
# import "SentryCrashExceptionApplicationHelper.h"
# import "SentryNSExceptionCaptureHelper.h"
# import "SentryUncaughtNSExceptions.h"
# import <AppKit/NSApplication.h>

// Private AppKit method called on the application instance during CATransaction flush.
@interface NSApplication (SentryCrashOnException)
- (void)_crashOnException:(NSException *)exception;
@end

@implementation SentryCrashExceptionApplication

Expand All @@ -13,13 +19,15 @@ - (void)reportException:(NSException *)exception
[SentryUncaughtNSExceptions configureCrashOnExceptions];
// We cannot test an NSApplication because you create more than one at a time, so we use a
// helper to hold the logic.
[SentryCrashExceptionApplicationHelper reportException:exception];
[SentryNSExceptionCaptureHelper reportException:exception];
[super reportException:exception];
[SentryNSExceptionCaptureHelper reportExceptionDidFinish];
}

- (void)_crashOnException:(NSException *)exception
{
[SentryCrashExceptionApplicationHelper _crashOnException:exception];
[SentryNSExceptionCaptureHelper crashOnException:exception];
[super _crashOnException:exception];
}

@end
Expand Down
32 changes: 0 additions & 32 deletions Sources/Sentry/SentryCrashExceptionApplicationHelper.m

This file was deleted.

47 changes: 47 additions & 0 deletions Sources/Sentry/SentryNSExceptionCaptureHelper.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#import <Foundation/Foundation.h>

#if TARGET_OS_OSX && !SENTRY_NO_UI_FRAMEWORK

# import "SentryCrash.h"
# import "SentryNSExceptionCaptureHelper.h"
# import "SentrySwift.h"
# import <stdatomic.h>

@implementation SentryNSExceptionCaptureHelper

// Thread-safe flag to prevent duplicate exception captures when
// _crashOnException: is called from within reportException:
static _Atomic BOOL _insideReportException = NO;

+ (void)reportException:(NSException *)exception
{
atomic_store(&_insideReportException, YES);
[self captureException:exception];
}

+ (void)reportExceptionDidFinish
{
atomic_store(&_insideReportException, NO);
}

+ (void)crashOnException:(NSException *)exception
{
// When called from within reportException: (i.e., [super reportException:] internally
// dispatches to _crashOnException: when NSApplicationCrashOnExceptions is YES),
// the exception was already captured, so skip to avoid duplicate reports.
if (!atomic_load(&_insideReportException)) {
[self captureException:exception];
}
}

+ (void)captureException:(NSException *)exception
{
SentryCrashSwift *crash = SentryDependencyContainer.sharedInstance.crashReporter;
if (nil != crash.uncaughtExceptionHandler && nil != exception) {
crash.uncaughtExceptionHandler(exception);
}
}

@end

#endif // TARGET_OS_OSX
17 changes: 0 additions & 17 deletions Sources/Sentry/SentrySDKInternal.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#import "SentrySpanInternal.h"
#import "SentrySwift.h"
#import "SentryTransactionContext.h"
#import "SentryUseNSExceptionCallstackWrapper.h"

#if TARGET_OS_OSX
# import "SentryCrashExceptionApplication.h"
Expand Down Expand Up @@ -358,22 +357,6 @@ + (SentryId *)captureException:(NSException *)exception withScope:(SentryScope *
return [SentrySDKInternal.currentHub captureException:exception withScope:scope];
}

#if TARGET_OS_OSX

+ (SentryId *)captureCrashOnException:(NSException *)exception
{
SentryUseNSExceptionCallstackWrapper *wrappedException =
[[SentryUseNSExceptionCallstackWrapper alloc]
initWithName:exception.name
reason:exception.reason
userInfo:exception.userInfo
callStackReturnAddresses:exception.callStackReturnAddresses];
return [SentrySDKInternal captureException:wrappedException
withScope:SentrySDKInternal.currentHub.scope];
}

#endif // TARGET_OS_OSX

+ (SentryId *)captureMessage:(NSString *)message
{
return [SentrySDKInternal captureMessage:message withScope:SentrySDKInternal.currentHub.scope];
Expand Down
67 changes: 53 additions & 14 deletions Sources/Sentry/SentryUncaughtNSExceptions.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

#if TARGET_OS_OSX && !SENTRY_NO_UI_FRAMEWORK

# import "SentryCrash.h"
# import <objc/runtime.h>

# import "SentryInternalDefines.h"
# import "SentrySwift.h"
# import "SentryNSExceptionCaptureHelper.h"
# import "SentrySwizzle.h"
# import "SentryUncaughtNSExceptions.h"
# import <AppKit/NSApplication.h>
Expand All @@ -26,26 +27,64 @@ + (void)swizzleNSApplicationReportException
SEL selector = NSSelectorFromString(@"reportException:");
SentrySwizzleInstanceMethod(NSApplication, selector, SentrySWReturnType(void),
SentrySWArguments(NSException * exception), SentrySWReplacement({
[SentryUncaughtNSExceptions capture:exception];
return SentrySWCallOriginal(exception);
[SentryNSExceptionCaptureHelper reportException:exception];
SentrySWCallOriginal(exception);
[SentryNSExceptionCaptureHelper reportExceptionDidFinish];
}),
SentrySwizzleModeOncePerClassAndSuperclasses, (void *)selector);
# pragma clang diagnostic pop
}

+ (void)capture:(nullable NSException *)exception
+ (void)swizzleNSApplicationCrashOnException
{
SentryCrashSwift *crash = SentryDependencyContainer.sharedInstance.crashReporter;

if (crash.uncaughtExceptionHandler == nil) {
return;
}
// SentrySwizzleClassMethod has no built-in deduplication, so guard against repeated SDK starts.
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wshadow"
# if SENTRY_TEST || SENTRY_TEST_CI
# pragma clang diagnostic ignored "-Wunused-variable"
# endif
// AppKit calls _crashOnException: when an exception is caught during CATransaction flush
// or view layout, bypassing reportException: entirely. Depending on macOS version, AppKit
// may call the class method +[NSApplication _crashOnException:] or the instance method
// -[NSApp _crashOnException:], so we swizzle both.
//
// SentryNSExceptionCaptureHelper handles deduplication: when _crashOnException: is
// called from within reportException: (e.g., when NSApplicationCrashOnExceptions is YES),
// the exception is only captured once.
SEL selector = NSSelectorFromString(@"_crashOnException:");

if (exception == nil) {
return;
}
// _crashOnException: is a private AppKit method that may not exist on all macOS versions.
// Only swizzle if the method is actually present on the class/instance.
if (class_getClassMethod([NSApplication class], selector)) {
SentrySwizzleClassMethod(NSApplication, selector, SentrySWReturnType(void),
SentrySWArguments(NSException * exception), SentrySWReplacement({
[SentryNSExceptionCaptureHelper crashOnException:exception];
# if SENTRY_TEST || SENTRY_TEST_CI
// Don't call the original in tests as it would abort() the process.
swizzleInfo.originalCalled = YES;
# else
return SentrySWCallOriginal(exception);
# endif
}));
}

crash.uncaughtExceptionHandler(SENTRY_UNWRAP_NULLABLE(NSException, exception));
if (class_getInstanceMethod([NSApplication class], selector)) {
SentrySwizzleInstanceMethod(NSApplication, selector, SentrySWReturnType(void),
SentrySWArguments(NSException * exception), SentrySWReplacement({
[SentryNSExceptionCaptureHelper crashOnException:exception];
# if SENTRY_TEST || SENTRY_TEST_CI
// Don't call the original in tests as it would abort() the process.
swizzleInfo.originalCalled = YES;
# else
return SentrySWCallOriginal(exception);
# endif
}),
SentrySwizzleModeOncePerClassAndSuperclasses, (void *)selector);
}
# pragma clang diagnostic pop
});
}

@end
Expand Down
Loading
Loading