diff --git a/CHANGELOG.md b/CHANGELOG.md index 04bb2c5e2e1..b43f343d002 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -91,6 +91,7 @@ - Properties on SentryOptions that had no effect on the WithoutUIKit variant are now removed from the API (#6644) - Removes the SentryOptions.inAppExclude property because it had no effect (#6646) - Removes segment property on SentryUser, SentryBaggage, and SentryTraceContext (#5638) +- Removes local symbolication when `debug=True` which fixes various deadlocks (#6562) - Removes deprecated TraceContext initializers (#6348) - Removes deprecated user feedback API, this is replaced with the new feedback API (#5591) - Removes `enablePerformanceV2` option and makes this the default. The app start duration will now finish when the first frame is drawn instead of when the OS posts the UIWindowDidBecomeVisibleNotification. (#6008) diff --git a/Sentry.xcodeproj/project.pbxproj b/Sentry.xcodeproj/project.pbxproj index 3d21e31bb4f..c5493f9ae51 100644 --- a/Sentry.xcodeproj/project.pbxproj +++ b/Sentry.xcodeproj/project.pbxproj @@ -252,7 +252,6 @@ 63FE711B20DA4C1000CDBAE8 /* SentryCrashString.c in Sources */ = {isa = PBXBuildFile; fileRef = 63FE701420DA4C1000CDBAE8 /* SentryCrashString.c */; }; 63FE711D20DA4C1000CDBAE8 /* SentryCrashCPU_arm64.c in Sources */ = {isa = PBXBuildFile; fileRef = 63FE701520DA4C1000CDBAE8 /* SentryCrashCPU_arm64.c */; }; 63FE711F20DA4C1000CDBAE8 /* SentryCrashObjC.h in Headers */ = {isa = PBXBuildFile; fileRef = 63FE701620DA4C1000CDBAE8 /* SentryCrashObjC.h */; }; - 63FE712120DA4C1000CDBAE8 /* SentryCrashSymbolicator.c in Sources */ = {isa = PBXBuildFile; fileRef = 63FE701720DA4C1000CDBAE8 /* SentryCrashSymbolicator.c */; }; 63FE712320DA4C1000CDBAE8 /* SentryCrashID.h in Headers */ = {isa = PBXBuildFile; fileRef = 63FE701820DA4C1000CDBAE8 /* SentryCrashID.h */; }; 63FE712520DA4C1000CDBAE8 /* SentryCrashSignalInfo.c in Sources */ = {isa = PBXBuildFile; fileRef = 63FE701920DA4C1000CDBAE8 /* SentryCrashSignalInfo.c */; }; 63FE712720DA4C1000CDBAE8 /* SentryCrashThread.c in Sources */ = {isa = PBXBuildFile; fileRef = 63FE701A20DA4C1000CDBAE8 /* SentryCrashThread.c */; }; @@ -281,7 +280,6 @@ 63FE715720DA4C1100CDBAE8 /* SentryCrashThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 63FE703220DA4C1000CDBAE8 /* SentryCrashThread.h */; }; 63FE715920DA4C1100CDBAE8 /* SentryCrashCPU_x86_32.c in Sources */ = {isa = PBXBuildFile; fileRef = 63FE703320DA4C1000CDBAE8 /* SentryCrashCPU_x86_32.c */; }; 63FE715B20DA4C1100CDBAE8 /* SentryCrashSignalInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 63FE703420DA4C1000CDBAE8 /* SentryCrashSignalInfo.h */; }; - 63FE715D20DA4C1100CDBAE8 /* SentryCrashSymbolicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 63FE703520DA4C1000CDBAE8 /* SentryCrashSymbolicator.h */; }; 63FE715F20DA4C1100CDBAE8 /* SentryCrashID.c in Sources */ = {isa = PBXBuildFile; fileRef = 63FE703620DA4C1000CDBAE8 /* SentryCrashID.c */; }; 63FE716320DA4C1100CDBAE8 /* SentryCrashDynamicLinker.h in Headers */ = {isa = PBXBuildFile; fileRef = 63FE703820DA4C1000CDBAE8 /* SentryCrashDynamicLinker.h */; }; 63FE716520DA4C1100CDBAE8 /* SentryCrashMemory.h in Headers */ = {isa = PBXBuildFile; fileRef = 63FE703920DA4C1000CDBAE8 /* SentryCrashMemory.h */; }; @@ -1542,7 +1540,6 @@ 63FE701420DA4C1000CDBAE8 /* SentryCrashString.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SentryCrashString.c; sourceTree = ""; }; 63FE701520DA4C1000CDBAE8 /* SentryCrashCPU_arm64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SentryCrashCPU_arm64.c; sourceTree = ""; }; 63FE701620DA4C1000CDBAE8 /* SentryCrashObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SentryCrashObjC.h; sourceTree = ""; }; - 63FE701720DA4C1000CDBAE8 /* SentryCrashSymbolicator.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SentryCrashSymbolicator.c; sourceTree = ""; }; 63FE701820DA4C1000CDBAE8 /* SentryCrashID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SentryCrashID.h; sourceTree = ""; }; 63FE701920DA4C1000CDBAE8 /* SentryCrashSignalInfo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SentryCrashSignalInfo.c; sourceTree = ""; }; 63FE701A20DA4C1000CDBAE8 /* SentryCrashThread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SentryCrashThread.c; sourceTree = ""; }; @@ -1571,7 +1568,6 @@ 63FE703220DA4C1000CDBAE8 /* SentryCrashThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryCrashThread.h; path = ../../../Sentry/include/SentryCrashThread.h; sourceTree = ""; }; 63FE703320DA4C1000CDBAE8 /* SentryCrashCPU_x86_32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SentryCrashCPU_x86_32.c; sourceTree = ""; }; 63FE703420DA4C1000CDBAE8 /* SentryCrashSignalInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SentryCrashSignalInfo.h; sourceTree = ""; }; - 63FE703520DA4C1000CDBAE8 /* SentryCrashSymbolicator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SentryCrashSymbolicator.h; sourceTree = ""; }; 63FE703620DA4C1000CDBAE8 /* SentryCrashID.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SentryCrashID.c; sourceTree = ""; }; 63FE703820DA4C1000CDBAE8 /* SentryCrashDynamicLinker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryCrashDynamicLinker.h; path = ../../../Sentry/include/SentryCrashDynamicLinker.h; sourceTree = ""; }; 63FE703920DA4C1000CDBAE8 /* SentryCrashMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SentryCrashMemory.h; sourceTree = ""; }; @@ -3290,8 +3286,6 @@ 63FE701C20DA4C1000CDBAE8 /* SentryCrashStackCursor.h */, 63FE701420DA4C1000CDBAE8 /* SentryCrashString.c */, 63FE702C20DA4C1000CDBAE8 /* SentryCrashString.h */, - 63FE701720DA4C1000CDBAE8 /* SentryCrashSymbolicator.c */, - 63FE703520DA4C1000CDBAE8 /* SentryCrashSymbolicator.h */, 63FE701E20DA4C1000CDBAE8 /* SentryCrashSysCtl.c */, 63FE703D20DA4C1000CDBAE8 /* SentryCrashSysCtl.h */, 63FE701A20DA4C1000CDBAE8 /* SentryCrashThread.c */, @@ -5147,7 +5141,6 @@ 639FCF981EBC7B9700778193 /* SentryEvent.h in Headers */, 03F84D2527DD414C008FE43F /* SentryThreadState.hpp in Headers */, 8E4E7C6D25DAAAFE006AB9E2 /* SentryTransaction.h in Headers */, - 63FE715D20DA4C1100CDBAE8 /* SentryCrashSymbolicator.h in Headers */, FAE2DABA2E1F318900262307 /* SentryProfilingSwiftHelpers.h in Headers */, D8ACE3CF2762187D00F5A213 /* SentryFileIOTrackingIntegration.h in Headers */, FA27ECA12EBA325A00F2ECF7 /* SentryTraceContext+Private.h in Headers */, @@ -5893,7 +5886,6 @@ 63FE716720DA4C1100CDBAE8 /* SentryCrashCPU.c in Sources */, 63FE717320DA4C1100CDBAE8 /* SentryCrashC.c in Sources */, 6293F5752D422A95002BC3BD /* SentryStacktraceCodable.swift in Sources */, - 63FE712120DA4C1000CDBAE8 /* SentryCrashSymbolicator.c in Sources */, 627C77892D50B6840055E966 /* SentryBreadcrumbCodable.swift in Sources */, 63FE70D720DA4C1000CDBAE8 /* SentryCrashMonitor_MachException.c in Sources */, 7B96572226830D2400C66E25 /* SentryScopeSyncC.c in Sources */, diff --git a/Sources/Sentry/SentryCrashReportConverter.m b/Sources/Sentry/SentryCrashReportConverter.m index 7097414c8c8..c3f07965f0b 100644 --- a/Sources/Sentry/SentryCrashReportConverter.m +++ b/Sources/Sentry/SentryCrashReportConverter.m @@ -307,15 +307,11 @@ - (SentryFrame *)stackFrameAtIndex:(NSInteger)frameIndex inThreadIndex:(NSIntege = (uintptr_t)[frameDictionary[@"instruction_addr"] unsignedLongLongValue]; NSDictionary *binaryImage = [self binaryImageForAddress:instructionAddress]; SentryFrame *frame = [[SentryFrame alloc] init]; - frame.symbolAddress = sentry_formatHexAddress(frameDictionary[@"symbol_addr"]); frame.instructionAddress = sentry_formatHexAddress(frameDictionary[@"instruction_addr"]); frame.imageAddress = sentry_formatHexAddress(binaryImage[@"image_addr"]); frame.package = binaryImage[@"name"]; BOOL isInApp = [self.inAppLogic isInApp:binaryImage[@"name"]]; frame.inApp = @(isInApp); - if (frameDictionary[@"symbol_name"]) { - frame.function = frameDictionary[@"symbol_name"]; - } return frame; } diff --git a/Sources/Sentry/SentryCrashStackEntryMapper.m b/Sources/Sentry/SentryCrashStackEntryMapper.m index 78066fb1fda..f826330d981 100644 --- a/Sources/Sentry/SentryCrashStackEntryMapper.m +++ b/Sources/Sentry/SentryCrashStackEntryMapper.m @@ -25,36 +25,15 @@ - (SentryFrame *)sentryCrashStackEntryToSentryFrame:(SentryCrashStackEntry)stack { SentryFrame *frame = [[SentryFrame alloc] init]; - if (stackEntry.symbolAddress != 0) { - frame.symbolAddress = sentry_formatHexAddressUInt64(stackEntry.symbolAddress); - } - frame.instructionAddress = sentry_formatHexAddressUInt64(stackEntry.address); - if (stackEntry.symbolName != NULL) { - frame.function = [NSString stringWithCString:stackEntry.symbolName - encoding:NSUTF8StringEncoding]; - } - - // If there is no symbolication, because debug was disabled - // we get image from the cache. - if (stackEntry.imageAddress == 0 && stackEntry.imageName == NULL) { - SentryBinaryImageInfo *info = [SentryDependencyContainer.sharedInstance.binaryImageCache - imageByAddress:(uint64_t)stackEntry.address]; - - frame.imageAddress = sentry_formatHexAddressUInt64(info.address); - frame.package = info.name; - frame.inApp = @([self.inAppLogic isInApp:info.name]); - } else { - frame.imageAddress = sentry_formatHexAddressUInt64(stackEntry.imageAddress); + // Get image from the cache. + SentryBinaryImageInfo *info = [SentryDependencyContainer.sharedInstance.binaryImageCache + imageByAddress:(uint64_t)stackEntry.address]; - if (stackEntry.imageName != NULL) { - NSString *imageName = [NSString stringWithCString:stackEntry.imageName - encoding:NSUTF8StringEncoding]; - frame.package = imageName; - frame.inApp = @([self.inAppLogic isInApp:imageName]); - } - } + frame.imageAddress = sentry_formatHexAddressUInt64(info.address); + frame.package = info.name; + frame.inApp = @([self.inAppLogic isInApp:info.name]); return frame; } diff --git a/Sources/Sentry/SentryDefaultThreadInspector.m b/Sources/Sentry/SentryDefaultThreadInspector.m index b210aecf598..a772d6ef8a1 100644 --- a/Sources/Sentry/SentryDefaultThreadInspector.m +++ b/Sources/Sentry/SentryDefaultThreadInspector.m @@ -3,7 +3,6 @@ #import "SentryCrashStackCursor.h" #include "SentryCrashStackCursor_MachineContext.h" #import "SentryCrashStackEntryMapper.h" -#include "SentryCrashSymbolicator.h" #import "SentryFrame.h" #import "SentryStacktrace.h" #import "SentryStacktraceBuilder.h" @@ -31,7 +30,7 @@ @interface SentryDefaultThreadInspector () // async-signal-safe. unsigned int getStackEntriesFromThread(SentryCrashThread thread, struct SentryCrashMachineContext *context, - SentryCrashStackEntry *buffer, unsigned int maxEntries, bool asyncUnsafeSymbolicate) + SentryCrashStackEntry *buffer, unsigned int maxEntries) { sentrycrashmc_getContextForThread(thread, context, NO); SentryCrashStackCursor stackCursor; @@ -42,10 +41,8 @@ @interface SentryDefaultThreadInspector () while (stackCursor.advanceCursor(&stackCursor)) { if (entries == maxEntries) break; - if (asyncUnsafeSymbolicate == false || stackCursor.symbolicate(&stackCursor)) { - buffer[entries] = stackCursor.stackEntry; - entries++; - } + buffer[entries] = stackCursor.stackEntry; + entries++; } return entries; @@ -55,12 +52,10 @@ @implementation SentryDefaultThreadInspector - (id)initWithStacktraceBuilder:(SentryStacktraceBuilder *)stacktraceBuilder andMachineContextWrapper:(id)machineContextWrapper - symbolicate:(BOOL)symbolicate { if (self = [super init]) { self.stacktraceBuilder = stacktraceBuilder; self.machineContextWrapper = machineContextWrapper; - self.symbolicate = symbolicate; } return self; } @@ -73,13 +68,11 @@ - (instancetype)initWithOptions:(SentryOptions *_Nullable)options [[SentryCrashStackEntryMapper alloc] initWithInAppLogic:inAppLogic]; SentryStacktraceBuilder *stacktraceBuilder = [[SentryStacktraceBuilder alloc] initWithCrashStackEntryMapper:crashStackEntryMapper]; - stacktraceBuilder.symbolicate = options.debug; id machineContextWrapper = [[SentryCrashDefaultMachineContextWrapper alloc] init]; return [self initWithStacktraceBuilder:stacktraceBuilder - andMachineContextWrapper:machineContextWrapper - symbolicate:options.debug]; + andMachineContextWrapper:machineContextWrapper]; } - (SentryStacktrace *)stacktraceForCurrentThreadAsyncUnsafe @@ -142,8 +135,6 @@ - (SentryStacktrace *)stacktraceForCurrentThreadAsyncUnsafe thread_act_array_t suspendedThreads = NULL; mach_msg_type_number_t numSuspendedThreads = 0; - bool symbolicate = self.symbolicate; - // SentryThreadInspector is crashing when there is too many threads. // We add a limit of 70 threads because in test with up to 100 threads it seems fine. // We are giving it an extra safety margin. @@ -163,7 +154,7 @@ - (SentryStacktrace *)stacktraceForCurrentThreadAsyncUnsafe for (int i = 0; i < numSuspendedThreads; i++) { if (suspendedThreads[i] != currentThread) { int numberOfEntries = getStackEntriesFromThread(suspendedThreads[i], context, - threadsInfos[i].stackEntries, MAX_STACKTRACE_LENGTH, symbolicate); + threadsInfos[i].stackEntries, MAX_STACKTRACE_LENGTH); threadsInfos[i].stackLength = numberOfEntries; } else { // We can't use 'getStackEntriesFromThread' to retrieve stack frames from the diff --git a/Sources/Sentry/SentryStacktrace.m b/Sources/Sentry/SentryStacktrace.m index 0c66dd3f0a1..465d40331e0 100644 --- a/Sources/Sentry/SentryStacktrace.m +++ b/Sources/Sentry/SentryStacktrace.m @@ -29,12 +29,9 @@ - (void)fixDuplicateFrames return; } - SentryFrame *lastFrame = self.frames.lastObject; SentryFrame *beforeLastFrame = [self.frames objectAtIndex:self.frames.count - 2]; - if ([lastFrame.symbolAddress - isEqualToString:SENTRY_UNWRAP_NULLABLE(NSString, beforeLastFrame.symbolAddress)] - && [self.registers[@"lr"] + if ([self.registers[@"lr"] isEqualToString:SENTRY_UNWRAP_NULLABLE(NSString, beforeLastFrame.instructionAddress)]) { NSMutableArray *copyFrames = self.frames.mutableCopy; [copyFrames removeObjectAtIndex:self.frames.count - 2]; diff --git a/Sources/Sentry/SentryStacktraceBuilder.m b/Sources/Sentry/SentryStacktraceBuilder.m index 2753abb83d3..206930ca869 100644 --- a/Sources/Sentry/SentryStacktraceBuilder.m +++ b/Sources/Sentry/SentryStacktraceBuilder.m @@ -3,7 +3,6 @@ #import "SentryCrashStackCursor_MachineContext.h" #import "SentryCrashStackCursor_SelfThread.h" #import "SentryCrashStackEntryMapper.h" -#import "SentryCrashSymbolicator.h" #import "SentryFrame.h" #import "SentryLogC.h" #import "SentryStacktrace.h" @@ -24,7 +23,6 @@ - (id)initWithCrashStackEntryMapper:(SentryCrashStackEntryMapper *)crashStackEnt { if (self = [super init]) { self.crashStackEntryMapper = crashStackEntryMapper; - self.symbolicate = NO; } return self; } @@ -41,10 +39,8 @@ - (SentryStacktrace *)retrieveStacktraceFromCursor:(SentryCrashStackCursor)stack // skip the marker frame continue; } - if (self.symbolicate == NO || stackCursor.symbolicate(&stackCursor)) { - frame = [self.crashStackEntryMapper mapStackEntryWithCursor:stackCursor]; - [frames addObject:frame]; - } + frame = [self.crashStackEntryMapper mapStackEntryWithCursor:stackCursor]; + [frames addObject:frame]; } return [SentryStacktraceBuilder buildStacktraceFromFrames:frames]; @@ -96,7 +92,6 @@ - (nullable SentryStacktrace *)buildStacktraceForCurrentThreadAsyncUnsafe SENTRY_LOG_DEBUG(@"Building async-unsafe stack trace..."); SentryCrashStackCursor stackCursor; sentrycrashsc_initSelfThread(&stackCursor, 0); - stackCursor.symbolicate = sentrycrashsymbolicator_symbolicate_async_unsafe; return [self retrieveStacktraceFromCursor:stackCursor]; } diff --git a/Sources/Sentry/SentryUseNSExceptionCallstackWrapper.m b/Sources/Sentry/SentryUseNSExceptionCallstackWrapper.m index 99ed7b528f6..a37ce6d2f88 100644 --- a/Sources/Sentry/SentryUseNSExceptionCallstackWrapper.m +++ b/Sources/Sentry/SentryUseNSExceptionCallstackWrapper.m @@ -1,6 +1,5 @@ #import "SentryUseNSExceptionCallstackWrapper.h" #import "SentryCrashStackEntryMapper.h" -#import "SentryCrashSymbolicator.h" #import "SentrySDK+Private.h" #import "SentryStacktraceBuilder.h" #import "SentrySwift.h" @@ -39,12 +38,15 @@ - (instancetype)initWithName:(NSExceptionName)aName SentryCrashStackEntryMapper *crashStackToEntryMapper = [self buildCrashStackToEntryMapper]; NSMutableArray *frames = [NSMutableArray array]; - // Iterate over all the addresses, symbolicate and create a SentryFrame + // Iterate over all the addresses and create a SentryFrame [self.returnAddressesArray enumerateObjectsUsingBlock:^(NSNumber *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) { SentryCrashStackCursor stackCursor; stackCursor.stackEntry.address = [obj unsignedLongValue]; - sentrycrashsymbolicator_symbolicate_async_unsafe_sentryDlAddr(&stackCursor); + stackCursor.stackEntry.imageName = nil; + stackCursor.stackEntry.imageAddress = 0; + stackCursor.stackEntry.symbolAddress = 0; + stackCursor.stackEntry.symbolName = nil; [frames addObject:[crashStackToEntryMapper sentryCrashStackEntryToSentryFrame:stackCursor.stackEntry]]; diff --git a/Sources/Sentry/include/SentryCrashDynamicLinker.h b/Sources/Sentry/include/SentryCrashDynamicLinker.h index 1940953a7b3..5676b7e4fe3 100644 --- a/Sources/Sentry/include/SentryCrashDynamicLinker.h +++ b/Sources/Sentry/include/SentryCrashDynamicLinker.h @@ -97,26 +97,6 @@ uint32_t sentrycrashdl_imageNamed(const char *const imageName, bool exactMatch); */ const uint8_t *sentrycrashdl_imageUUID(const char *const imageName, bool exactMatch); -/** - * ATTENTION: This method isn't async-safe as it accesses @c _dyld_get_image_header, which acquires - * a lock. We plan on removing this method with - * https://github.com/getsentry/sentry-cocoa/issues/2996. - * - * - * This method searches the dynamic loader for information about any image - * containing the specified address. It may not be entirely successful in - * finding information, in which case any fields it could not find will be set - * to NULL. - * - * Unlike dladdr(), this method does not make use of locks, and does not call - * async-unsafe functions. - * - * @param address The address to search for. - * @param info Gets filled out by this function. - * @return true if at least some information was found. - */ -bool sentrycrashdl_dladdr(const uintptr_t address, Dl_info *const info); - void sentrycrashdl_getCrashInfo(uint64_t address, SentryCrashBinaryImage *buffer); void sentrycrashdl_initialize(void); diff --git a/Sources/Sentry/include/SentryDefaultThreadInspector.h b/Sources/Sentry/include/SentryDefaultThreadInspector.h index 83d3c9c1bad..68dda102154 100644 --- a/Sources/Sentry/include/SentryDefaultThreadInspector.h +++ b/Sources/Sentry/include/SentryDefaultThreadInspector.h @@ -15,8 +15,7 @@ NS_ASSUME_NONNULL_BEGIN SENTRY_NO_INIT - (id)initWithStacktraceBuilder:(SentryStacktraceBuilder *)stacktraceBuilder - andMachineContextWrapper:(id)machineContextWrapper - symbolicate:(BOOL)symbolicate; + andMachineContextWrapper:(id)machineContextWrapper; - (instancetype)initWithOptions:(SentryOptionsObjC *_Nullable)options; diff --git a/Sources/Sentry/include/SentryStacktraceBuilder.h b/Sources/Sentry/include/SentryStacktraceBuilder.h index 866b8b0c091..132f8c9fd3c 100644 --- a/Sources/Sentry/include/SentryStacktraceBuilder.h +++ b/Sources/Sentry/include/SentryStacktraceBuilder.h @@ -15,12 +15,6 @@ NS_ASSUME_NONNULL_BEGIN @interface SentryStacktraceBuilder : NSObject SENTRY_NO_INIT -/** - * Whether the stack trace frames should be fully symbolicated - * or only contain instruction address and binary image. - */ -@property (nonatomic) BOOL symbolicate; - - (id)initWithCrashStackEntryMapper:(SentryCrashStackEntryMapper *)crashStackEntryMapper; /** diff --git a/Sources/SentryCrash/Recording/SentryCrashDoctor.m b/Sources/SentryCrash/Recording/SentryCrashDoctor.m index 90739c617d9..2c7c4f440b8 100644 --- a/Sources/SentryCrash/Recording/SentryCrashDoctor.m +++ b/Sources/SentryCrash/Recording/SentryCrashDoctor.m @@ -262,30 +262,6 @@ - (NSDictionary *)basicRegistersFromThreadReport:(NSDictionary *)threadReport return basic; } -- (NSDictionary *)lastInAppStackEntry:(NSDictionary *)report -{ - NSString *executableName = [self mainExecutableNameForReport:report]; - NSDictionary *crashedThread = [self crashedThreadReport:report]; - NSArray *backtrace = [self backtraceFromThreadReport:crashedThread]; - for (NSDictionary *entry in backtrace) { - NSString *objectName = [entry objectForKey:@SentryCrashField_ObjectName]; - if ([objectName isEqualToString:executableName]) { - return entry; - } - } - return nil; -} - -- (NSDictionary *)lastStackEntry:(NSDictionary *)report -{ - NSDictionary *crashedThread = [self crashedThreadReport:report]; - NSArray *backtrace = [self backtraceFromThreadReport:crashedThread]; - if ([backtrace count] > 0) { - return [backtrace objectAtIndex:0]; - } - return nil; -} - - (BOOL)isInvalidAddress:(NSDictionary *)errorReport { NSDictionary *machError = [errorReport objectForKey:@SentryCrashField_Mach]; @@ -329,25 +305,6 @@ - (BOOL)isMemoryCorruption:(NSDictionary *)report } } - NSArray *backtrace = [self backtraceFromThreadReport:crashedThread]; - for (NSDictionary *entry in backtrace) { - NSString *objectName = [entry objectForKey:@SentryCrashField_ObjectName]; - NSString *symbolName = [entry objectForKey:@SentryCrashField_SymbolName]; - if ([symbolName isEqualToString:@"objc_autoreleasePoolPush"]) { - return YES; - } - if ([symbolName isEqualToString:@"free_list_checksum_botch"]) { - return YES; - } - if ([symbolName isEqualToString:@"szone_malloc_should_clear"]) { - return YES; - } - if ([symbolName isEqualToString:@"lookUpMethod"] && - [objectName isEqualToString:@"libobjc.A.dylib"]) { - return YES; - } - } - return NO; } @@ -359,8 +316,6 @@ - (BOOL)wasProgramTerminationRequested:(NSDictionary *)errorReport - (SentryCrashDoctorFunctionCall *)lastFunctionCall:(NSDictionary *)report { SentryCrashDoctorFunctionCall *function = [[SentryCrashDoctorFunctionCall alloc] init]; - NSDictionary *lastStackEntry = [self lastStackEntry:report]; - function.name = [lastStackEntry objectForKey:@SentryCrashField_SymbolName]; NSDictionary *crashedThread = [self crashedThreadReport:report]; NSDictionary *notableAddresses = @@ -425,13 +380,11 @@ - (BOOL)isStackOverflow:(NSDictionary *)crashedThreadReport - (NSString *)diagnoseCrash:(NSDictionary *)report { @try { - NSString *lastFunctionName = - [[self lastInAppStackEntry:report] objectForKey:@SentryCrashField_SymbolName]; NSDictionary *crashedThreadReport = [self crashedThreadReport:report]; NSDictionary *errorReport = [self errorReport:report]; if ([self isStackOverflow:crashedThreadReport]) { - return [NSString stringWithFormat:@"Stack overflow in %@", lastFunctionName]; + return [NSString stringWithFormat:@"Stack overflow"]; } NSString *crashType = [errorReport objectForKey:@SentryCrashField_Type]; diff --git a/Sources/SentryCrash/Recording/SentryCrashReport.c b/Sources/SentryCrash/Recording/SentryCrashReport.c index 6debdd9db21..72205a3e40c 100644 --- a/Sources/SentryCrash/Recording/SentryCrashReport.c +++ b/Sources/SentryCrash/Recording/SentryCrashReport.c @@ -799,20 +799,6 @@ writeBacktrace(const SentryCrashReportWriter *const writer, const char *const ke while (stackCursor->advanceCursor(stackCursor)) { writer->beginObject(writer, NULL); { - if (stackCursor->symbolicate(stackCursor)) { - if (stackCursor->stackEntry.imageName != NULL) { - writer->addStringElement(writer, SentryCrashField_ObjectName, - sentrycrashfu_lastPathEntry(stackCursor->stackEntry.imageName)); - } - writer->addUIntegerElement(writer, SentryCrashField_ObjectAddr, - stackCursor->stackEntry.imageAddress); - if (stackCursor->stackEntry.symbolName != NULL) { - writer->addStringElement(writer, SentryCrashField_SymbolName, - stackCursor->stackEntry.symbolName); - } - writer->addUIntegerElement(writer, SentryCrashField_SymbolAddr, - stackCursor->stackEntry.symbolAddress); - } writer->addUIntegerElement( writer, SentryCrashField_InstructionAddr, stackCursor->stackEntry.address); } diff --git a/Sources/SentryCrash/Recording/SentryCrashReportFields.h b/Sources/SentryCrash/Recording/SentryCrashReportFields.h index 96b8ce5df45..60a091f3439 100644 --- a/Sources/SentryCrash/Recording/SentryCrashReportFields.h +++ b/Sources/SentryCrash/Recording/SentryCrashReportFields.h @@ -77,11 +77,6 @@ #pragma mark - Backtrace - #define SentryCrashField_InstructionAddr "instruction_addr" -#define SentryCrashField_LineOfCode "line_of_code" -#define SentryCrashField_ObjectAddr "object_addr" -#define SentryCrashField_ObjectName "object_name" -#define SentryCrashField_SymbolAddr "symbol_addr" -#define SentryCrashField_SymbolName "symbol_name" #pragma mark - Stack Dump - diff --git a/Sources/SentryCrash/Recording/Tools/SentryCrashDynamicLinker.c b/Sources/SentryCrash/Recording/Tools/SentryCrashDynamicLinker.c index f26902f7277..da2e49af741 100644 --- a/Sources/SentryCrash/Recording/Tools/SentryCrashDynamicLinker.c +++ b/Sources/SentryCrash/Recording/Tools/SentryCrashDynamicLinker.c @@ -218,24 +218,6 @@ imageIndexContainingAddress(const uintptr_t address) return UINT_MAX; } -/** Get the segment base address of the specified image. - * - * This is required for any symtab command offsets. - * - * @param idx The image index. - * @return The image's base address, or 0 if none was found. - */ -static uintptr_t -segmentBaseOfImageIndex(const uint32_t idx) -{ - const struct mach_header *header = _dyld_get_image_header(idx); - const sentry_segment_command_t *segCmd = getSegmentCommand(header, SEG_LINKEDIT); - if (segCmd != NULL) { - return (uintptr_t)(segCmd->vmaddr - segCmd->fileoff); - } - return 0; -} - uint32_t sentrycrashdl_imageNamed(const char *const imageName, bool exactMatch) { @@ -283,99 +265,6 @@ sentrycrashdl_imageUUID(const char *const imageName, bool exactMatch) return NULL; } -bool -sentrycrashdl_dladdr(const uintptr_t address, Dl_info *const info) -{ - info->dli_fname = NULL; - info->dli_fbase = NULL; - info->dli_sname = NULL; - info->dli_saddr = NULL; - - const uint32_t idx = imageIndexContainingAddress(address); - - const struct mach_header *header = NULL; - uintptr_t imageVMAddrSlide = 0; - uintptr_t segmentBase = 0; - - if (idx == SENTRY_DYLD_INDEX) { - // Handle dyld manually - header = sentryDyldHeader; - if (header == NULL) { - return false; - } - - // Calculate dyld slide from __TEXT vmaddr - SentrySegmentAddress textSegment = getSegmentAddress(header, SEG_TEXT); - uintptr_t vmaddr = textSegment.start; - if (vmaddr != 0) { - imageVMAddrSlide = (uintptr_t)header - vmaddr; - segmentBase = (uintptr_t)header; - } - - info->dli_fname = "dyld"; - } else if (idx != UINT_MAX) { - // Normal image path - header = _dyld_get_image_header(idx); - imageVMAddrSlide = (uintptr_t)_dyld_get_image_vmaddr_slide(idx); - segmentBase = segmentBaseOfImageIndex(idx) + imageVMAddrSlide; - info->dli_fname = _dyld_get_image_name(idx); - } else { - return false; - } - const uintptr_t addressWithSlide = address - imageVMAddrSlide; - if (segmentBase == 0) { - return false; - } - - info->dli_fbase = (void *)header; - - // Find symbol tables and get whichever symbol is closest to the address. - const nlist_t *bestMatch = NULL; - uintptr_t bestDistance = ULONG_MAX; - uintptr_t cmdPtr = firstCmdAfterHeader(header); - if (cmdPtr == 0) { - return false; - } - for (uint32_t iCmd = 0; iCmd < header->ncmds; iCmd++) { - const struct load_command *loadCmd = (struct load_command *)cmdPtr; - if (loadCmd->cmd == LC_SYMTAB) { - const struct symtab_command *symtabCmd = (struct symtab_command *)cmdPtr; - const nlist_t *symbolTable = (nlist_t *)(segmentBase + symtabCmd->symoff); - const uintptr_t stringTable = segmentBase + symtabCmd->stroff; - - for (uint32_t iSym = 0; iSym < symtabCmd->nsyms; iSym++) { - // If n_value is 0, the symbol refers to an external object. - if (symbolTable[iSym].n_value != 0) { - uintptr_t symbolBase = symbolTable[iSym].n_value; - uintptr_t currentDistance = addressWithSlide - symbolBase; - if ((addressWithSlide >= symbolBase) && (currentDistance <= bestDistance)) { - bestMatch = symbolTable + iSym; - bestDistance = currentDistance; - } - } - } - if (bestMatch != NULL) { - info->dli_saddr = (void *)(bestMatch->n_value + imageVMAddrSlide); - if (bestMatch->n_desc == 16) { - // This image has been stripped. The name is meaningless, - // and almost certainly resolves to "_mh_execute_header" - info->dli_sname = NULL; - } else { - info->dli_sname - = (char *)((intptr_t)stringTable + (intptr_t)bestMatch->n_un.n_strx); - if (*info->dli_sname == '_') { - info->dli_sname++; - } - } - break; - } - } - cmdPtr += loadCmd->cmdsize; - } - - return true; -} - static bool isValidCrashInfoMessage(const char *str) { diff --git a/Sources/SentryCrash/Recording/Tools/SentryCrashStackCursor.c b/Sources/SentryCrash/Recording/Tools/SentryCrashStackCursor.c index 3f42e83a584..238aa5aad53 100644 --- a/Sources/SentryCrash/Recording/Tools/SentryCrashStackCursor.c +++ b/Sources/SentryCrash/Recording/Tools/SentryCrashStackCursor.c @@ -25,7 +25,6 @@ #include "SentryCrashStackCursor.h" #include "SentryCrashCPU.h" -#include "SentryCrashSymbolicator.h" #include #include "SentryAsyncSafeLog.h" @@ -46,17 +45,12 @@ sentrycrashsc_resetCursor(SentryCrashStackCursor *cursor) cursor->state.currentDepth = 0; cursor->state.hasGivenUp = false; cursor->stackEntry.address = 0; - cursor->stackEntry.imageAddress = 0; - cursor->stackEntry.imageName = NULL; - cursor->stackEntry.symbolAddress = 0; - cursor->stackEntry.symbolName = NULL; } void sentrycrashsc_initCursor(SentryCrashStackCursor *cursor, void (*resetCursor)(SentryCrashStackCursor *), bool (*advanceCursor)(SentryCrashStackCursor *)) { - cursor->symbolicate = sentrycrashsymbolicator_symbolicate_async_unsafe_sentryDlAddr; cursor->advanceCursor = advanceCursor != NULL ? advanceCursor : g_advanceCursor; cursor->resetCursor = resetCursor != NULL ? resetCursor : sentrycrashsc_resetCursor; cursor->resetCursor(cursor); diff --git a/Sources/SentryCrash/Recording/Tools/SentryCrashStackCursor.h b/Sources/SentryCrash/Recording/Tools/SentryCrashStackCursor.h index 0805ddaf2cd..f4e7d3fc031 100644 --- a/Sources/SentryCrash/Recording/Tools/SentryCrashStackCursor.h +++ b/Sources/SentryCrash/Recording/Tools/SentryCrashStackCursor.h @@ -79,10 +79,6 @@ typedef struct SentryCrashStackCursor { /** Advance the cursor to the next stack entry. */ bool (*advanceCursor)(struct SentryCrashStackCursor *); - /** Attempt to symbolicate the current address, filling in the fields in - * stackEntry. */ - bool (*symbolicate)(struct SentryCrashStackCursor *); - /** Internal context-specific information. */ void *context[SentryCrashSC_CONTEXT_SIZE]; } SentryCrashStackCursor; diff --git a/Sources/SentryCrash/Recording/Tools/SentryCrashSymbolicator.c b/Sources/SentryCrash/Recording/Tools/SentryCrashSymbolicator.c deleted file mode 100644 index ed6b9e026e0..00000000000 --- a/Sources/SentryCrash/Recording/Tools/SentryCrashSymbolicator.c +++ /dev/null @@ -1,105 +0,0 @@ -// Adapted from: https://github.com/kstenerud/KSCrash -// -// SentryCrashSymbolicator.c -// -// Copyright (c) 2016 Karl Stenerud. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall remain in place -// in this source code. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -#include "SentryCrashSymbolicator.h" -#include "SentryCrashDynamicLinker.h" -#import - -/** Remove any pointer tagging from an instruction address - * On armv7 the least significant bit of the pointer distinguishes - * between thumb mode (2-byte instructions) and normal mode (4-byte - * instructions). On arm64 all instructions are 4-bytes wide so the two least - * significant bytes should always be 0. On x86_64 and i386, instructions are - * variable length so all bits are signficant. - */ -#if defined(__arm__) -# define DETAG_INSTRUCTION_ADDRESS(A) ((A) & ~(1UL)) -#elif defined(__arm64__) -# define DETAG_INSTRUCTION_ADDRESS(A) ((A) & ~(3UL)) -#else -# define DETAG_INSTRUCTION_ADDRESS(A) (A) -#endif - -/** Step backwards by one instruction. - * The backtrace of an objective-C program is expected to contain return - * addresses not call instructions, as that is what can easily be read from - * the stack. This is not a problem except for a few cases where the return - * address is inside a different symbol than the call address. - */ -#define CALL_INSTRUCTION_FROM_RETURN_ADDRESS(A) (DETAG_INSTRUCTION_ADDRESS((A)) - 1) - -static bool -symbolicate_internal(SentryCrashStackCursor *cursor, bool useDlAddr) -{ - if (cursor->stackEntry.address == SentryCrashSC_ASYNC_MARKER) { - cursor->stackEntry.imageAddress = 0; - cursor->stackEntry.imageName = 0; - cursor->stackEntry.symbolAddress = 0; - cursor->stackEntry.symbolName = "__sentrycrash__async_marker__"; - return true; - } - - Dl_info symbolsBuffer; - - bool symbols_succeed = false; - - if (useDlAddr) { - symbols_succeed = dladdr((void *)cursor->stackEntry.address, &symbolsBuffer) != 0; - } else { - // sentrycrashdl_dladdr isn't async safe, but we've been using it for - // crashes since the beginning. We plan on removing it with - // https://github.com/getsentry/sentry-cocoa/issues/2996. - symbols_succeed = sentrycrashdl_dladdr( - CALL_INSTRUCTION_FROM_RETURN_ADDRESS(cursor->stackEntry.address), &symbolsBuffer); - } - - if (symbols_succeed) { - cursor->stackEntry.imageAddress = (uintptr_t)symbolsBuffer.dli_fbase; - cursor->stackEntry.imageName = symbolsBuffer.dli_fname; - cursor->stackEntry.symbolAddress = (uintptr_t)symbolsBuffer.dli_saddr; - cursor->stackEntry.symbolName = symbolsBuffer.dli_sname; - return true; - } - - cursor->stackEntry.imageAddress = 0; - cursor->stackEntry.imageName = 0; - cursor->stackEntry.symbolAddress = 0; - cursor->stackEntry.symbolName = 0; - return false; -} - -bool -sentrycrashsymbolicator_symbolicate_async_unsafe_sentryDlAddr(SentryCrashStackCursor *cursor) -{ - // Symbolicate using `sentrycrashdl_dladdr` note this is not async-signal-safe - return symbolicate_internal(cursor, false); -} - -bool -sentrycrashsymbolicator_symbolicate_async_unsafe(SentryCrashStackCursor *cursor) -{ - // Symbolicate using `dladdr` note this is not async-signal-safe - return symbolicate_internal(cursor, true); -} diff --git a/Sources/SentryCrash/Recording/Tools/SentryCrashSymbolicator.h b/Sources/SentryCrash/Recording/Tools/SentryCrashSymbolicator.h deleted file mode 100644 index 07d93bece74..00000000000 --- a/Sources/SentryCrash/Recording/Tools/SentryCrashSymbolicator.h +++ /dev/null @@ -1,52 +0,0 @@ -// Adapted from: https://github.com/kstenerud/KSCrash -// -// SentryCrashSymbolicator.h -// -// Copyright (c) 2016 Karl Stenerud. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall remain in place -// in this source code. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -#ifndef SentryCrashSymbolicator_h -#define SentryCrashSymbolicator_h - -#import "SentryCrashStackCursor.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** Symbolicate a stack cursor. - * - * @param cursor The cursor to symbolicate. - * - * @return True if successful. - */ -bool sentrycrashsymbolicator_symbolicate_async_unsafe_sentryDlAddr(SentryCrashStackCursor *cursor); - -/** Same as ``sentrycrashsymbolicator_symbolicate_async_unsafe_sentryDlAddr`` but faster. - */ -bool sentrycrashsymbolicator_symbolicate_async_unsafe(SentryCrashStackCursor *cursor); - -#ifdef __cplusplus -} -#endif - -#endif // SentryCrashSymbolicator_h diff --git a/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift b/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift index dd9729621e3..498526b25fd 100644 --- a/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift +++ b/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift @@ -99,7 +99,6 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { XCTAssertEqual(ex.type, "App Hanging") XCTAssertEqual(ex.value, "App hanging for at least 4500 ms.") XCTAssertNotNil(ex.stacktrace) - XCTAssertEqual(ex.stacktrace?.frames.first?.function, "main") XCTAssertEqual(ex.stacktrace?.snapshot?.boolValue, true) XCTAssertEqual(try XCTUnwrap(event?.threads?.first).current?.boolValue, true) XCTAssertEqual(event?.isAppHangEvent, true) @@ -140,7 +139,6 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { XCTAssertEqual(ex.type, "App Hang Fully Blocked") XCTAssertEqual(ex.value, "App hanging for at least 4500 ms.") XCTAssertNotNil(ex.stacktrace) - XCTAssertEqual(ex.stacktrace?.frames.first?.function, "main") XCTAssertEqual(ex.stacktrace?.snapshot?.boolValue, true) XCTAssertEqual(try XCTUnwrap(event?.threads?.first).current?.boolValue, true) XCTAssertEqual(event?.isAppHangEvent, true) @@ -182,7 +180,6 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { XCTAssertEqual(ex.value, "App hanging for at least 4500 ms.") XCTAssertNil(ex.mechanism?.data) XCTAssertNotNil(ex.stacktrace) - XCTAssertEqual(ex.stacktrace?.frames.first?.function, "main") XCTAssertEqual(ex.stacktrace?.snapshot?.boolValue, true) XCTAssertEqual(try XCTUnwrap(event?.threads?.first).current?.boolValue, true) XCTAssertEqual(event?.isAppHangEvent, true) @@ -224,7 +221,6 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { XCTAssertEqual(ex.value, "App hanging for at least 4500 ms.") XCTAssertNil(ex.mechanism?.data) XCTAssertNotNil(ex.stacktrace) - XCTAssertEqual(ex.stacktrace?.frames.first?.function, "main") XCTAssertEqual(ex.stacktrace?.snapshot?.boolValue, true) XCTAssertEqual(try XCTUnwrap(event?.threads?.first).current?.boolValue, true) XCTAssertEqual(event?.isAppHangEvent, true) @@ -384,20 +380,9 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { XCTAssertTrue(mechanismData.isEmpty) XCTAssertNotNil(ex.stacktrace) - XCTAssertEqual(ex.stacktrace?.frames.first?.function, "main") XCTAssertEqual(ex.stacktrace?.snapshot?.boolValue, true) XCTAssertEqual(try XCTUnwrap(event?.threads?.first).current?.boolValue, true) XCTAssertEqual(event?.isAppHangEvent, true) - - let threads = try XCTUnwrap(event?.threads) - - // Sometimes during tests its possible to have one thread without frames - // We just need to make sure we retrieve frame information for at least one other thread than the main thread - let threadsWithFrames = threads.filter { - ($0.stacktrace?.frames.count ?? 0) >= 1 - }.count - - XCTAssertTrue(threadsWithFrames > 1, "Not enough threads with frames") XCTAssertEqual(event?.debugMeta?.count, 1) let eventDebugImage = try XCTUnwrap(event?.debugMeta?.first) @@ -443,21 +428,10 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { XCTAssertTrue(mechanismData.isEmpty) XCTAssertNotNil(ex.stacktrace) - XCTAssertEqual(ex.stacktrace?.frames.first?.function, "main") XCTAssertEqual(ex.stacktrace?.snapshot?.boolValue, true) XCTAssertEqual(try XCTUnwrap(event?.threads?.first).current?.boolValue, true) XCTAssertEqual(event?.isAppHangEvent, true) - let threads = try XCTUnwrap(event?.threads) - - // Sometimes during tests its possible to have one thread without frames - // We just need to make sure we retrieve frame information for at least one other thread than the main thread - let threadsWithFrames = threads.filter { - ($0.stacktrace?.frames.count ?? 0) >= 1 - }.count - - XCTAssertTrue(threadsWithFrames > 1, "Not enough threads with frames") - XCTAssertEqual(event?.debugMeta?.count, 1) let eventDebugImage = try XCTUnwrap(event?.debugMeta?.first) XCTAssertEqual(eventDebugImage.debugID, TestData.debugImage.debugID) @@ -744,14 +718,12 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { if addThreads { let frame1 = Sentry.Frame() - frame1.function = "Second_frame_function" let thread1 = SentryThread(threadId: 0) thread1.stacktrace = SentryStacktrace(frames: [frame1], registers: [:]) thread1.current = true let frame2 = Sentry.Frame() - frame2.function = "main" let thread2 = SentryThread(threadId: 1) thread2.stacktrace = SentryStacktrace(frames: [frame2], registers: [:]) diff --git a/Tests/SentryTests/Integrations/MetricKit/SentryMetricKitIntegrationTests.swift b/Tests/SentryTests/Integrations/MetricKit/SentryMetricKitIntegrationTests.swift index 57709284438..ae8abead82a 100644 --- a/Tests/SentryTests/Integrations/MetricKit/SentryMetricKitIntegrationTests.swift +++ b/Tests/SentryTests/Integrations/MetricKit/SentryMetricKitIntegrationTests.swift @@ -201,7 +201,6 @@ final class SentryMetricKitIntegrationTests: SentrySDKIntegrationTestsBase { XCTAssertEqual(1, sentryFrames.count) let frame = sentryFrames.first - XCTAssertNil(frame?.function) XCTAssertEqual("0x000000021f1a0001", frame?.imageAddress) XCTAssertEqual("libsystem_pthread.dylib", frame?.package) XCTAssertFalse(frame?.inApp?.boolValue ?? true) diff --git a/Tests/SentryTests/Protocol/SentryFrameTests.swift b/Tests/SentryTests/Protocol/SentryFrameTests.swift index af23841d910..b6dab6aea95 100644 --- a/Tests/SentryTests/Protocol/SentryFrameTests.swift +++ b/Tests/SentryTests/Protocol/SentryFrameTests.swift @@ -13,7 +13,6 @@ class SentryFrameTests: XCTestCase { // Assert XCTAssertEqual(frame.symbolAddress, actual["symbol_addr"] as? String) XCTAssertEqual(frame.fileName, actual["filename"] as? String) - XCTAssertEqual(frame.function, actual["function"] as? String) XCTAssertEqual(frame.module, actual["module"] as? String) XCTAssertEqual(frame.lineNumber, actual["lineno"] as? NSNumber) XCTAssertEqual(frame.columnNumber, actual["colno"] as? NSNumber) @@ -39,7 +38,6 @@ class SentryFrameTests: XCTestCase { // Assert XCTAssertEqual(frame.symbolAddress, actual["symbol_addr"] as? String) XCTAssertEqual(frame.fileName, actual["filename"] as? String) - XCTAssertEqual(frame.function, actual["function"] as? String) XCTAssertEqual(frame.module, actual["module"] as? String) XCTAssertEqual(frame.lineNumber, actual["lineno"] as? NSNumber) XCTAssertEqual(frame.columnNumber, actual["colno"] as? NSNumber) @@ -66,7 +64,6 @@ class SentryFrameTests: XCTestCase { // Assert XCTAssertEqual(frame.symbolAddress, decoded.symbolAddress) XCTAssertEqual(frame.fileName, decoded.fileName) - XCTAssertEqual(frame.function, decoded.function) XCTAssertEqual(frame.module, decoded.module) XCTAssertEqual(frame.lineNumber, decoded.lineNumber) XCTAssertEqual(frame.columnNumber, decoded.columnNumber) @@ -93,7 +90,6 @@ class SentryFrameTests: XCTestCase { // Assert XCTAssertEqual(frame.symbolAddress, decoded.symbolAddress) XCTAssertEqual(frame.fileName, decoded.fileName) - XCTAssertEqual(frame.function, decoded.function) XCTAssertEqual(frame.module, decoded.module) XCTAssertEqual(frame.lineNumber, decoded.lineNumber) XCTAssertEqual(frame.columnNumber, decoded.columnNumber) @@ -120,7 +116,6 @@ class SentryFrameTests: XCTestCase { // Assert XCTAssertNil(decoded.symbolAddress) XCTAssertNil(decoded.fileName) - XCTAssertNil(decoded.function) XCTAssertNil(decoded.module) XCTAssertNil(decoded.lineNumber) XCTAssertNil(decoded.columnNumber) diff --git a/Tests/SentryTests/SentryClientTests.swift b/Tests/SentryTests/SentryClientTests.swift index d7bd84ae2e1..4a854819a2a 100644 --- a/Tests/SentryTests/SentryClientTests.swift +++ b/Tests/SentryTests/SentryClientTests.swift @@ -2244,15 +2244,7 @@ class SentryClientTests: XCTestCase { XCTAssertEqual(actual.threads?[0].isMain, true) // Make sure the stacktrace is not empty XCTAssertGreaterThan(actual.threads?[0].stacktrace?.frames.count ?? 0, 1) - // We will need to update it if the test class / module changes - let testMangledName = "$s11SentryTests0a6ClientB0C011testCaptureA16WrappedExceptionyyKF" - let frameWithTestFunction = actual.threads?[0].stacktrace?.frames.first { frame in - frame.function == testMangledName - } - XCTAssertNotNil(frameWithTestFunction, "Mangled name for testCaptureSentryWrappedException not found in stacktrace") - // Last frame should always be `__exceptionPreprocess` - XCTAssertEqual(actual.threads?[0].stacktrace?.frames.last?.function, "__exceptionPreprocess") #else throw XCTSkip("Test is disabled for this OS version") #endif // os(macOS) diff --git a/Tests/SentryTests/SentryCrash/SentryCrashDynamicLinkerTests.m b/Tests/SentryTests/SentryCrash/SentryCrashDynamicLinkerTests.m index a1942ff4fee..7df110f8061 100644 --- a/Tests/SentryTests/SentryCrash/SentryCrashDynamicLinkerTests.m +++ b/Tests/SentryTests/SentryCrash/SentryCrashDynamicLinkerTests.m @@ -47,73 +47,6 @@ - (void)testImageIndexContainingAddressWhenDyldIsNotSet XCTAssertEqual(index, UINT_MAX, @"Address should be found in dyld"); } -- (void)testDyldAddressLookup -{ - sentrycrashdl_initialize(); - - void *dyldAddress = (void *)&_dyld_image_count; - - Dl_info info; - bool result = sentrycrashdl_dladdr((uintptr_t)dyldAddress, &info); - XCTAssertTrue(result, @"dladdr should succeed for dyld address"); - XCTAssert(info.dli_fbase != NULL, @"Base address should not be NULL"); - XCTAssert(info.dli_fname != NULL, @"Image name should not be NULL"); - - XCTAssertTrue(strstr(info.dli_fname, "dyld") != NULL, @"Image name should contain 'dyld'"); - - XCTAssert(info.dli_sname != NULL, @"Symbol name should not be NULL"); - XCTAssertTrue(strstr(info.dli_sname, "_dyld_image_count") != NULL, - @"Symbol name should contain '_dyld_image_count'"); - - XCTAssert(info.dli_saddr != NULL, @"Symbol address should not be NULL"); - XCTAssertEqual(info.dli_saddr, dyldAddress, @"Symbol address should match the input address"); -} - -#if TARGET_OS_IOS -- (void)testUIKitAddressLookup -{ - // Get a known function from UIKit - void *uiKitAddress = (void *)&UIApplicationMain; - - Dl_info info; - bool result = sentrycrashdl_dladdr((uintptr_t)uiKitAddress, &info); - XCTAssertTrue(result, @"dladdr should succeed for UIKit address"); - XCTAssert(info.dli_fbase != NULL, @"Base address should not be NULL"); - XCTAssert(info.dli_fname != NULL, @"Image name should not be NULL"); - - XCTAssertTrue(strstr(info.dli_fname, "UIKit") != NULL, @"Image name should contain 'UIKit'"); - - XCTAssert(info.dli_sname != NULL, @"Symbol name should not be NULL"); - XCTAssertTrue(strstr(info.dli_sname, "UIApplicationMain") != NULL, - @"Symbol name should contain 'UIApplicationMain'"); - - XCTAssert(info.dli_saddr != NULL, @"Symbol address should not be NULL"); - XCTAssertEqual(info.dli_saddr, uiKitAddress, @"Symbol address should match the input address"); -} -#endif - -- (void)testKnownAddressLookup -{ - // Any function in Sentry will do - void *testAddress = (void *)&sentrycrashdl_clearDyld; - - Dl_info info; - bool result = sentrycrashdl_dladdr((uintptr_t)testAddress, &info); - XCTAssertTrue(result, @"dladdr should succeed for test bundle address"); - XCTAssert(info.dli_fbase != NULL, @"Base address should not be NULL"); - XCTAssert(info.dli_fname != NULL, @"Image name should not be NULL"); - - XCTAssertTrue( - strstr(info.dli_fname, "Sentry") != NULL, @"Image name should contain 'SentryTests'"); - - XCTAssert(info.dli_sname != NULL, @"Symbol name should not be NULL"); - XCTAssertTrue(strstr(info.dli_sname, "sentrycrashdl_clearDyld") != NULL, - @"Symbol name should contain 'sentrycrashdl_clearDyld'"); - - XCTAssert(info.dli_saddr != NULL, @"Symbol address should not be NULL"); - XCTAssertEqual(info.dli_saddr, testAddress, @"Symbol address should match the input address"); -} - // vmaddrs changes by platform, so we cannot use a static value - (uintptr_t)findDyldAddress { diff --git a/Tests/SentryTests/SentryCrash/SentryCrashStackEntryMapperTests.swift b/Tests/SentryTests/SentryCrash/SentryCrashStackEntryMapperTests.swift index 221977e05d9..b9472326be3 100644 --- a/Tests/SentryTests/SentryCrash/SentryCrashStackEntryMapperTests.swift +++ b/Tests/SentryTests/SentryCrash/SentryCrashStackEntryMapperTests.swift @@ -18,24 +18,6 @@ class SentryCrashStackEntryMapperTests: XCTestCase { super.tearDown() clearTestState() } - - func testSymbolAddress() { - var cursor = SentryCrashStackCursor() - cursor.stackEntry.symbolAddress = 2_391_813_104 - - let frame = sut.mapStackEntry(with: cursor) - - XCTAssertEqual("0x000000008e902bf0", frame.symbolAddress ?? "") - } - - func testSymbolAddress_IsZero() { - var cursor = SentryCrashStackCursor() - cursor.stackEntry.symbolAddress = 0 - - let frame = sut.mapStackEntry(with: cursor) - - XCTAssertNil(frame.symbolAddress) - } func testInstructionAddress() { var cursor = SentryCrashStackCursor() @@ -45,45 +27,6 @@ class SentryCrashStackEntryMapperTests: XCTestCase { XCTAssertEqual("0x000000008fd09c40", frame.instructionAddress ?? "") } - - func testSymbolNameIsNull() { - let frame = sut.mapStackEntry(with: SentryCrashStackCursor()) - - XCTAssertNil(frame.function) - } - - func testSymbolName() { - let symbolName = "-[SentryCrash symbolName]" - var cursor = SentryCrashStackCursor() - - let cString = symbolName.cString(using: String.Encoding.utf8) - cString?.withUnsafeBufferPointer { bufferPointer in - cursor.stackEntry.symbolName = bufferPointer.baseAddress - let frame = sut.mapStackEntry(with: cursor) - XCTAssertEqual(symbolName, frame.function) - } - } - - func testImageName() { - let imageName = "/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 13.4.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation" - let frame = getFrameWithImageName(imageName: imageName) - - XCTAssertEqual(imageName, frame.package) - } - - func testImageAddress() { - var cursor = SentryCrashStackCursor() - cursor.stackEntry.imageAddress = 2_488_998_912 - - let frame = sut.mapStackEntry(with: cursor) - - XCTAssertEqual("0x00000000945b1c00", frame.imageAddress ?? "") - } - - func testIsInApp() { - let frame = getFrameWithImageName(imageName: "/private/var/containers/Bundle/Application/03D20FB6-852C-4DD3-B69C-3231FB41C2B1/iOS-Swift.app/\(self.bundleExecutable)") - XCTAssertEqual(true, frame.inApp) - } func testImageFromCache() { let image = createCrashBinaryImage(2_488_998_912) @@ -104,19 +47,6 @@ class SentryCrashStackEntryMapperTests: XCTestCase { SentryDependencyContainer.sharedInstance().binaryImageCache.stop() } - - private func getFrameWithImageName(imageName: String) -> Frame { - var cursor = SentryCrashStackCursor() - - let cString = imageName.cString(using: String.Encoding.utf8) - var result: Frame = Frame() - cString?.withUnsafeBufferPointer { bufferPointer in - cursor.stackEntry.imageName = bufferPointer.baseAddress - result = sut.mapStackEntry(with: cursor) - } - - return result - } private func createCrashBinaryImage(_ address: UInt) -> SentryCrashBinaryImage { let name = "Expected Name at \(address)" diff --git a/Tests/SentryTests/SentryCrash/SentryDefaultThreadInspectorTests.swift b/Tests/SentryTests/SentryCrash/SentryDefaultThreadInspectorTests.swift index 441e0e834ab..9a8e17792a1 100644 --- a/Tests/SentryTests/SentryCrash/SentryDefaultThreadInspectorTests.swift +++ b/Tests/SentryTests/SentryCrash/SentryDefaultThreadInspectorTests.swift @@ -9,16 +9,14 @@ class SentryDefaultThreadInspectorTests: XCTestCase { var stacktraceBuilder = TestSentryStacktraceBuilder(crashStackEntryMapper: SentryCrashStackEntryMapper(inAppLogic: SentryInAppLogic(inAppIncludes: []))) var keepThreadAlive = true - func getSut(testWithRealMachineContextWrapper: Bool = false, symbolicate: Bool = true) -> SentryDefaultThreadInspector { + func getSut(testWithRealMachineContextWrapper: Bool = false) -> SentryDefaultThreadInspector { let machineContextWrapper = testWithRealMachineContextWrapper ? SentryCrashDefaultMachineContextWrapper() : testMachineContextWrapper as SentryCrashMachineContextWrapper let stacktraceBuilder = testWithRealMachineContextWrapper ? SentryStacktraceBuilder(crashStackEntryMapper: SentryCrashStackEntryMapper(inAppLogic: SentryInAppLogic(inAppIncludes: []))) : self.stacktraceBuilder - stacktraceBuilder.symbolicate = symbolicate - return SentryDefaultThreadInspector( stacktraceBuilder: stacktraceBuilder, - andMachineContextWrapper: machineContextWrapper, symbolicate: symbolicate + andMachineContextWrapper: machineContextWrapper ) } } @@ -48,7 +46,7 @@ class SentryDefaultThreadInspectorTests: XCTestCase { XCTAssertTrue(30 < stacktrace?.frames.count ?? 0, "Not enough stacktrace frames.") } - func testGetCurrentThreadsWithStacktrace_WithSymbolication() { + func testGetCurrentThreadsWithStacktrace() { let queue = DispatchQueue(label: "test-queue", attributes: [.concurrent, .initiallyInactive]) let expect = expectation(description: "Read every thread") @@ -56,66 +54,6 @@ class SentryDefaultThreadInspectorTests: XCTestCase { let sut = self.fixture.getSut(testWithRealMachineContextWrapper: true) - for _ in 0..<10 { - - queue.async { - let threads = sut.getCurrentThreadsWithStackTrace() - - if threads.count == 0 { - // If there are more than 70 threads getCurrentThreadsWithStackTrace - // returns an empty list because it can't handle so many threads. - // This is a known limitation SentryThreadInspector and should be - // addressed in https://github.com/getsentry/sentry-cocoa/issues/2825. - // We see this sometimes happening in CI. - expect.fulfill() - return - } - - var threadsWithStackTraceFrames = 0 - - for thread in threads { - - guard let frames = thread.stacktrace?.frames else { - continue - } - - if frames.count == 0 { - continue - } - - for frame in frames { - XCTAssertNotNil(frame.instructionAddress) - XCTAssertNotNil(frame.imageAddress) - - } - - threadsWithStackTraceFrames += 1 - } - - let percantageWithStacktraceFrames = Double(threadsWithStackTraceFrames) / Double(threads.count) - - // During testing we usually have around 90% to 100% - // We choose a bit lower threshold to avoid flaky tests in CI - // Especially during the test when launching multiple threads for the concurrent DispatchQueue - // it can occur that more than one thread have no stacktrace frames yet, because they just started. - XCTAssertGreaterThan(percantageWithStacktraceFrames, 0.6, "More than 60% of threads should have stacktrace frames, but got \(percantageWithStacktraceFrames * 100)%") - - expect.fulfill() - } - } - - queue.activate() - wait(for: [expect], timeout: 10) - } - - func testGetCurrentThreadsWithStacktrace_WithoutSymbolication() { - let queue = DispatchQueue(label: "test-queue", attributes: [.concurrent, .initiallyInactive]) - - let expect = expectation(description: "Read every thread") - expect.expectedFulfillmentCount = 10 - - let sut = self.fixture.getSut(testWithRealMachineContextWrapper: true, symbolicate: false) - for _ in 0..<10 { queue.async { @@ -198,29 +136,16 @@ class SentryDefaultThreadInspectorTests: XCTestCase { XCTAssertEqual(suspendedThreads.count, 0) } - func testStackTrackForCurrentThreadAsyncUnsafe() { - guard let stackTrace = fixture.getSut(testWithRealMachineContextWrapper: true).stacktraceForCurrentThreadAsyncUnsafe() else { - XCTFail("Stack Trace not found") - return - } - let stackTrace2 = fixture.getSut(testWithRealMachineContextWrapper: true).getCurrentThreadsWithStackTrace() + func testStackTrackForCurrentThreadAsyncUnsafe() throws { + let stacktrace = try XCTUnwrap(fixture.getSut(testWithRealMachineContextWrapper: true).stacktraceForCurrentThreadAsyncUnsafe()) - XCTAssertNotNil(stackTrace) - XCTAssertNotNil(stackTrace2) - XCTAssertGreaterThan(stackTrace.frames.count, 0) - XCTAssertNotEqual(stackTrace.frames.first?.instructionAddress, "0x0000000000000000") - XCTAssertNotEqual(stackTrace.frames.first?.function, "") - } + let frames = try XCTUnwrap(stacktrace.frames) - func testStackTrackForCurrentThreadAsyncUnsafe_NoSymbolication() { - guard let stackTrace = fixture.getSut(testWithRealMachineContextWrapper: true, symbolicate: false).stacktraceForCurrentThreadAsyncUnsafe() else { - XCTFail("Stack Trace not found") - return + for frame in frames { + XCTAssertNotNil(frame.instructionAddress) + XCTAssertNotNil(frame.imageAddress) + XCTAssertNil(frame.symbolAddress) } - - XCTAssertNotNil(stackTrace) - XCTAssertGreaterThan(stackTrace.frames.count, 0) - XCTAssertNil(stackTrace.frames.first?.function) } func testOnlyCurrentThreadHasStacktrace() throws { diff --git a/Tests/SentryTests/SentryCrash/SentryStacktraceBuilderTests.swift b/Tests/SentryTests/SentryCrash/SentryStacktraceBuilderTests.swift index a27bec99fda..454100209a1 100644 --- a/Tests/SentryTests/SentryCrash/SentryStacktraceBuilderTests.swift +++ b/Tests/SentryTests/SentryCrash/SentryStacktraceBuilderTests.swift @@ -10,7 +10,6 @@ class SentryStacktraceBuilderTests: XCTestCase { var sut: SentryStacktraceBuilder { SentryDependencyContainer.sharedInstance().reachability = TestSentryReachability() let res = SentryStacktraceBuilder(crashStackEntryMapper: SentryCrashStackEntryMapper(inAppLogic: SentryInAppLogic(inAppIncludes: []))) - res.symbolicate = true return res } } @@ -46,33 +45,29 @@ class SentryStacktraceBuilderTests: XCTestCase { // deterministic tests here. Therefore we just make sure they are // filled with some values. for frame in actual.frames { - XCTAssertNotNil(frame.symbolAddress) - XCTAssertNotNil(frame.function) XCTAssertNotNil(frame.imageAddress) XCTAssertNotNil(frame.instructionAddress) } } - func testFramesDontContainBuilderFunction() { - let actual = fixture.sut.buildStacktraceForCurrentThread() - - let result = actual.frames.contains { frame in - return frame.function?.contains("buildStacktraceForCurrentThread") ?? false - } - - XCTAssertFalse(result, "The stacktrace should not contain the function that builds the stacktrace") - } - func testFramesOrder() throws { // -- Act -- let actual = fixture.sut.buildStacktraceForCurrentThread() // -- Assert -- - // Make sure the first 4 frames contain main - let isMainInFirstFrames = actual.frames[...3].contains(where: { $0.function == "main" }) + // Make sure the first 4 frames contain an address close to the main function + let isMainInFirstFrames = actual.frames[...3].contains(where: { frame in + let inst = Int(frame.instructionAddress?.replacingOccurrences(of: "0x", with: "") ?? "", radix: 16) ?? 0 + // Use the symbol name for the first stack entry in dyld + #if targetEnvironment(simulator) + return name(for: inst) == "start_sim" + #else + return name(for: inst) == "start" + #endif + }) XCTAssertTrue( isMainInFirstFrames, - "Expected frames to be ordered from caller to callee (xctest's main expected in first few frames). Found instead:\n\(actual.frames.map({ " - \($0.function ?? "")" }).joined(separator: "\n"))" + "Expected frames to be ordered from caller to callee (xctest's main expected in first few frames)." ) } @@ -145,10 +140,24 @@ class SentryStacktraceBuilderTests: XCTestCase { private func innerFrame2() async -> Int { let needed = ["firstFrame", "innerFrame1", "innerFrame2"] let actual = fixture.sut.buildStacktraceForCurrentThreadAsyncUnsafe()! - let filteredFrames = actual.frames - .compactMap({ $0.function }) + let symbolNames = actual.frames + .compactMap({ $0.instructionAddress?.replacingOccurrences(of: "0x", with: "") }) + .compactMap { Int($0, radix: 16) } + .compactMap { addr in + name(for: addr) + } + let filteredFrames = symbolNames .filter { needed.contains(where: $0.contains) } print("\(Date()) [Sentry] [TEST] returning filtered frames.") return filteredFrames.count } + + private func name(for addr: Int) -> String? { + var sym = Dl_info() + dladdr(UnsafeMutableRawPointer(bitPattern: addr), &sym) + if let symName = sym.dli_sname { + return String(cString: symName) + } + return nil + } } diff --git a/Tests/SentryTests/SentryCrash/TestThreadInspector.swift b/Tests/SentryTests/SentryCrash/TestThreadInspector.swift index e0aa7062e65..0a9b3b4238e 100644 --- a/Tests/SentryTests/SentryCrash/TestThreadInspector.swift +++ b/Tests/SentryTests/SentryCrash/TestThreadInspector.swift @@ -10,7 +10,7 @@ class TestDefaultThreadInspector: SentryDefaultThreadInspector { let inAppLogic = SentryInAppLogic(inAppIncludes: []) let crashStackEntryMapper = SentryCrashStackEntryMapper(inAppLogic: inAppLogic) let stacktraceBuilder = SentryStacktraceBuilder(crashStackEntryMapper: crashStackEntryMapper) - return TestDefaultThreadInspector(stacktraceBuilder: stacktraceBuilder, andMachineContextWrapper: SentryCrashDefaultMachineContextWrapper(), symbolicate: false) + return TestDefaultThreadInspector(stacktraceBuilder: stacktraceBuilder, andMachineContextWrapper: SentryCrashDefaultMachineContextWrapper()) } override func stacktraceForCurrentThreadAsyncUnsafe() -> SentryStacktrace? { diff --git a/Tests/SentryTests/SentryCrashReportConverterTests.m b/Tests/SentryTests/SentryCrashReportConverterTests.m index cae05ffb0fb..d07312134e2 100644 --- a/Tests/SentryTests/SentryCrashReportConverterTests.m +++ b/Tests/SentryTests/SentryCrashReportConverterTests.m @@ -55,8 +55,6 @@ - (void)testConvertReport XCTAssertEqualObjects(firstDebugImage.imageSize, @(65536)); SentryException *exception = event.exceptions.firstObject; - XCTAssertEqualObjects( - exception.stacktrace.frames.lastObject.symbolAddress, @"0x000000010014c1ec"); XCTAssertEqualObjects( exception.stacktrace.frames.lastObject.instructionAddress, @"0x000000010014caa4"); XCTAssertEqualObjects( diff --git a/Tests/SentryTests/Transaction/SentrySpanTests.swift b/Tests/SentryTests/Transaction/SentrySpanTests.swift index 3cea6cb3eef..476b597e28d 100644 --- a/Tests/SentryTests/Transaction/SentrySpanTests.swift +++ b/Tests/SentryTests/Transaction/SentrySpanTests.swift @@ -470,8 +470,6 @@ class SentrySpanTests: XCTestCase { XCTAssertNotNil(serialization["data"]) let callStack = (serialization["data"] as? [String: Any])?["call_stack"] as? [[String: Any]] XCTAssertNotNil(callStack) - XCTAssertEqual(callStack?.first?["function"] as? String, TestData.mainFrame.function) - XCTAssertEqual(callStack?.last?["function"] as? String, TestData.testFrame.function) } func testSanitizeData() { diff --git a/develop-docs/DECISIONS.md b/develop-docs/DECISIONS.md index 9827b716b78..48ebf897564 100644 --- a/develop-docs/DECISIONS.md +++ b/develop-docs/DECISIONS.md @@ -1,5 +1,13 @@ # Decision Log +## No local symbolication of crashes + +Date: Nov 7th, 2025 +Contributors: @noahsmartin, @philipphofmann + +We decided to remove local symbolication. The existing local symbolication was not signal-safe and caused deadlocks (https://github.com/getsentry/sentry-cocoa/issues/6560). +It is possible to implement local symbolication that does not cause deadlocks; however, it would be a debug-only feature, since in production apps should have their symbols stripped and only available in the dSYM. Therefore, to quickly fix the issue, we decided to remove all unsafe local symbolication in v9. The addition of signal-safe symbolication for binaries with symbols can always be added in a future minor version. + ## Not capturing screenshots for crashes Date: April 21st 2022