diff --git a/Bugsnag.xcodeproj/project.pbxproj b/Bugsnag.xcodeproj/project.pbxproj index a881fbfcd..356219d2a 100644 --- a/Bugsnag.xcodeproj/project.pbxproj +++ b/Bugsnag.xcodeproj/project.pbxproj @@ -34,9 +34,6 @@ 008966F42486D43700DC48C2 /* BugsnagThreadTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 008966A72486D43400DC48C2 /* BugsnagThreadTest.m */; }; 008966F52486D43700DC48C2 /* BugsnagThreadTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 008966A72486D43400DC48C2 /* BugsnagThreadTest.m */; }; 008966F62486D43700DC48C2 /* BugsnagThreadTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 008966A72486D43400DC48C2 /* BugsnagThreadTest.m */; }; - 008966F72486D43700DC48C2 /* RegisterErrorDataTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 008966A92486D43400DC48C2 /* RegisterErrorDataTest.m */; }; - 008966F82486D43700DC48C2 /* RegisterErrorDataTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 008966A92486D43400DC48C2 /* RegisterErrorDataTest.m */; }; - 008966F92486D43700DC48C2 /* RegisterErrorDataTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 008966A92486D43400DC48C2 /* RegisterErrorDataTest.m */; }; 008966FD2486D43700DC48C2 /* BugsnagOnBreadcrumbTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 008966AB2486D43500DC48C2 /* BugsnagOnBreadcrumbTest.m */; }; 008966FE2486D43700DC48C2 /* BugsnagOnBreadcrumbTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 008966AB2486D43500DC48C2 /* BugsnagOnBreadcrumbTest.m */; }; 008966FF2486D43700DC48C2 /* BugsnagOnBreadcrumbTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 008966AB2486D43500DC48C2 /* BugsnagOnBreadcrumbTest.m */; }; @@ -423,9 +420,9 @@ 008969812486DAD100DC48C2 /* BSG_KSObjC.h in Headers */ = {isa = PBXBuildFile; fileRef = 0089690F2486DAD000DC48C2 /* BSG_KSObjC.h */; }; 008969822486DAD100DC48C2 /* BSG_KSObjC.h in Headers */ = {isa = PBXBuildFile; fileRef = 0089690F2486DAD000DC48C2 /* BSG_KSObjC.h */; }; 008969832486DAD100DC48C2 /* BSG_KSObjC.h in Headers */ = {isa = PBXBuildFile; fileRef = 0089690F2486DAD000DC48C2 /* BSG_KSObjC.h */; }; - 008969842486DAD100DC48C2 /* BSG_KSMachHeaders.m in Sources */ = {isa = PBXBuildFile; fileRef = 008969102486DAD000DC48C2 /* BSG_KSMachHeaders.m */; }; - 008969852486DAD100DC48C2 /* BSG_KSMachHeaders.m in Sources */ = {isa = PBXBuildFile; fileRef = 008969102486DAD000DC48C2 /* BSG_KSMachHeaders.m */; }; - 008969862486DAD100DC48C2 /* BSG_KSMachHeaders.m in Sources */ = {isa = PBXBuildFile; fileRef = 008969102486DAD000DC48C2 /* BSG_KSMachHeaders.m */; }; + 008969842486DAD100DC48C2 /* BSG_KSMachHeaders.c in Sources */ = {isa = PBXBuildFile; fileRef = 008969102486DAD000DC48C2 /* BSG_KSMachHeaders.c */; }; + 008969852486DAD100DC48C2 /* BSG_KSMachHeaders.c in Sources */ = {isa = PBXBuildFile; fileRef = 008969102486DAD000DC48C2 /* BSG_KSMachHeaders.c */; }; + 008969862486DAD100DC48C2 /* BSG_KSMachHeaders.c in Sources */ = {isa = PBXBuildFile; fileRef = 008969102486DAD000DC48C2 /* BSG_KSMachHeaders.c */; }; 008969872486DAD100DC48C2 /* BSG_KSMachApple.h in Headers */ = {isa = PBXBuildFile; fileRef = 008969112486DAD000DC48C2 /* BSG_KSMachApple.h */; }; 008969882486DAD100DC48C2 /* BSG_KSMachApple.h in Headers */ = {isa = PBXBuildFile; fileRef = 008969112486DAD000DC48C2 /* BSG_KSMachApple.h */; }; 008969892486DAD100DC48C2 /* BSG_KSMachApple.h in Headers */ = {isa = PBXBuildFile; fileRef = 008969112486DAD000DC48C2 /* BSG_KSMachApple.h */; }; @@ -609,13 +606,6 @@ 00AD1C7C24869B0E00A27979 /* Bugsnag.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00AD1C7224869B0E00A27979 /* Bugsnag.framework */; }; 00AD1CB624869C1200A27979 /* Bugsnag.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00AD1CAD24869C1200A27979 /* Bugsnag.framework */; }; 00AD1CD224869C2400A27979 /* Bugsnag.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00AD1CC924869C2400A27979 /* Bugsnag.framework */; }; - 00AD1F022486A17900A27979 /* RegisterErrorData.h in Headers */ = {isa = PBXBuildFile; fileRef = 00AD1EF42486A17600A27979 /* RegisterErrorData.h */; }; - 00AD1F032486A17900A27979 /* RegisterErrorData.h in Headers */ = {isa = PBXBuildFile; fileRef = 00AD1EF42486A17600A27979 /* RegisterErrorData.h */; }; - 00AD1F042486A17900A27979 /* RegisterErrorData.h in Headers */ = {isa = PBXBuildFile; fileRef = 00AD1EF42486A17600A27979 /* RegisterErrorData.h */; }; - 00AD1F052486A17900A27979 /* RegisterErrorData.m in Sources */ = {isa = PBXBuildFile; fileRef = 00AD1EF52486A17600A27979 /* RegisterErrorData.m */; }; - 00AD1F062486A17900A27979 /* RegisterErrorData.m in Sources */ = {isa = PBXBuildFile; fileRef = 00AD1EF52486A17600A27979 /* RegisterErrorData.m */; }; - 00AD1F072486A17900A27979 /* RegisterErrorData.m in Sources */ = {isa = PBXBuildFile; fileRef = 00AD1EF52486A17600A27979 /* RegisterErrorData.m */; }; - 00AD1F082486A17900A27979 /* RegisterErrorData.m in Sources */ = {isa = PBXBuildFile; fileRef = 00AD1EF52486A17600A27979 /* RegisterErrorData.m */; }; 00AD1F102486A17900A27979 /* BugsnagSessionTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = 00AD1EF82486A17700A27979 /* BugsnagSessionTracker.h */; }; 00AD1F112486A17900A27979 /* BugsnagSessionTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = 00AD1EF82486A17700A27979 /* BugsnagSessionTracker.h */; }; 00AD1F122486A17900A27979 /* BugsnagSessionTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = 00AD1EF82486A17700A27979 /* BugsnagSessionTracker.h */; }; @@ -807,7 +797,7 @@ E701FAB12490EFE8008D842F /* ConfigurationApiValidationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E701FAAE2490EFE8008D842F /* ConfigurationApiValidationTest.m */; }; E74628FC248907C100F92D67 /* BSG_KSCrashDoctor.m in Sources */ = {isa = PBXBuildFile; fileRef = 008969002486DAD000DC48C2 /* BSG_KSCrashDoctor.m */; }; E74628FD248907C100F92D67 /* BSG_KSJSONCodecObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 008969082486DAD000DC48C2 /* BSG_KSJSONCodecObjC.m */; }; - E74628FF248907C100F92D67 /* BSG_KSMachHeaders.m in Sources */ = {isa = PBXBuildFile; fileRef = 008969102486DAD000DC48C2 /* BSG_KSMachHeaders.m */; }; + E74628FF248907C100F92D67 /* BSG_KSMachHeaders.c in Sources */ = {isa = PBXBuildFile; fileRef = 008969102486DAD000DC48C2 /* BSG_KSMachHeaders.c */; }; E7462900248907C100F92D67 /* NSError+BSG_SimpleConstructor.m in Sources */ = {isa = PBXBuildFile; fileRef = 0089691E2486DAD000DC48C2 /* NSError+BSG_SimpleConstructor.m */; }; E7462901248907C100F92D67 /* BSG_KSLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 008969262486DAD000DC48C2 /* BSG_KSLogger.m */; }; E7462902248907C100F92D67 /* BSG_KSCrashState.m in Sources */ = {isa = PBXBuildFile; fileRef = 008969292486DAD000DC48C2 /* BSG_KSCrashState.m */; }; @@ -914,7 +904,6 @@ E746299524890D3200F92D67 /* BugsnagCrashSentry.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 00AD1F002486A17900A27979 /* BugsnagCrashSentry.h */; }; E746299624890D3200F92D67 /* BugsnagSessionTracker.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 00AD1EF82486A17700A27979 /* BugsnagSessionTracker.h */; }; E746299724890D3200F92D67 /* BugsnagErrorReportSink.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 00AD1EFD2486A17800A27979 /* BugsnagErrorReportSink.h */; }; - E746299824890D3200F92D67 /* RegisterErrorData.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 00AD1EF42486A17600A27979 /* RegisterErrorData.h */; }; E75A5CDB248A5D97005D2C74 /* BugsnagErrorReportSink.h in Headers */ = {isa = PBXBuildFile; fileRef = 00AD1EFD2486A17800A27979 /* BugsnagErrorReportSink.h */; }; E75A5CDC248A5DA2005D2C74 /* BugsnagErrorReportSink.m in Sources */ = {isa = PBXBuildFile; fileRef = 00AD1EF92486A17700A27979 /* BugsnagErrorReportSink.m */; }; /* End PBXBuildFile section */ @@ -1033,7 +1022,6 @@ E746299524890D3200F92D67 /* BugsnagCrashSentry.h in CopyFiles */, E746299624890D3200F92D67 /* BugsnagSessionTracker.h in CopyFiles */, E746299724890D3200F92D67 /* BugsnagErrorReportSink.h in CopyFiles */, - E746299824890D3200F92D67 /* RegisterErrorData.h in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1047,7 +1035,6 @@ 008966A62486D43400DC48C2 /* BugsnagMetadataRedactionTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BugsnagMetadataRedactionTest.m; sourceTree = ""; }; 008966A72486D43400DC48C2 /* BugsnagThreadTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BugsnagThreadTest.m; sourceTree = ""; }; 008966A82486D43400DC48C2 /* BugsnagTestConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BugsnagTestConstants.h; sourceTree = ""; }; - 008966A92486D43400DC48C2 /* RegisterErrorDataTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RegisterErrorDataTest.m; sourceTree = ""; }; 008966AB2486D43500DC48C2 /* BugsnagOnBreadcrumbTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BugsnagOnBreadcrumbTest.m; sourceTree = ""; }; 008966AC2486D43500DC48C2 /* BugsnagEventPersistLoadTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BugsnagEventPersistLoadTest.m; sourceTree = ""; }; 008966AD2486D43500DC48C2 /* BugsnagThreadSerializationTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BugsnagThreadSerializationTest.m; sourceTree = ""; }; @@ -1175,7 +1162,7 @@ 0089690C2486DAD000DC48C2 /* NSError+BSG_SimpleConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+BSG_SimpleConstructor.h"; sourceTree = ""; }; 0089690E2486DAD000DC48C2 /* BSG_KSArchSpecific.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSG_KSArchSpecific.h; sourceTree = ""; }; 0089690F2486DAD000DC48C2 /* BSG_KSObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSG_KSObjC.h; sourceTree = ""; }; - 008969102486DAD000DC48C2 /* BSG_KSMachHeaders.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSG_KSMachHeaders.m; sourceTree = ""; }; + 008969102486DAD000DC48C2 /* BSG_KSMachHeaders.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = BSG_KSMachHeaders.c; sourceTree = ""; }; 008969112486DAD000DC48C2 /* BSG_KSMachApple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSG_KSMachApple.h; sourceTree = ""; }; 008969122486DAD000DC48C2 /* BSG_KSString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSG_KSString.h; sourceTree = ""; }; 008969132486DAD000DC48C2 /* BSG_KSMach.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = BSG_KSMach.c; sourceTree = ""; }; @@ -1245,8 +1232,6 @@ 00AD1CC924869C2400A27979 /* Bugsnag.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Bugsnag.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 00AD1CD124869C2400A27979 /* Bugsnag-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Bugsnag-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 00AD1CE424869C6C00A27979 /* libBugsnagStatic.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libBugsnagStatic.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 00AD1EF42486A17600A27979 /* RegisterErrorData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterErrorData.h; sourceTree = ""; }; - 00AD1EF52486A17600A27979 /* RegisterErrorData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RegisterErrorData.m; sourceTree = ""; }; 00AD1EF82486A17700A27979 /* BugsnagSessionTracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BugsnagSessionTracker.h; sourceTree = ""; }; 00AD1EF92486A17700A27979 /* BugsnagErrorReportSink.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BugsnagErrorReportSink.m; sourceTree = ""; }; 00AD1EFD2486A17800A27979 /* BugsnagErrorReportSink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BugsnagErrorReportSink.h; sourceTree = ""; }; @@ -1558,7 +1543,7 @@ 008969282486DAD000DC48C2 /* BSG_KSMach.h */, 008969112486DAD000DC48C2 /* BSG_KSMachApple.h */, 008969232486DAD000DC48C2 /* BSG_KSMachHeaders.h */, - 008969102486DAD000DC48C2 /* BSG_KSMachHeaders.m */, + 008969102486DAD000DC48C2 /* BSG_KSMachHeaders.c */, 008969252486DAD000DC48C2 /* BSG_KSObjC.c */, 0089690F2486DAD000DC48C2 /* BSG_KSObjC.h */, 008969202486DAD000DC48C2 /* BSG_KSObjCApple.h */, @@ -1636,8 +1621,6 @@ 01937D09257A7ED000F2DE31 /* BugsnagSessionTracker+Private.h */, CBB0928B2519F891007698BC /* BugsnagSystemState.h */, CBB0928A2519F891007698BC /* BugsnagSystemState.m */, - 00AD1EF42486A17600A27979 /* RegisterErrorData.h */, - 00AD1EF52486A17600A27979 /* RegisterErrorData.m */, 00AD1CF124869EBD00A27979 /* Breadcrumbs */, 00AD1CF224869ECF00A27979 /* Client */, 00AD1CF324869ED700A27979 /* Configuration */, @@ -1706,7 +1689,6 @@ 016875C4258D003200DFFF69 /* NSUserDefaultsStub.h */, 016875C5258D003200DFFF69 /* NSUserDefaultsStub.m */, 0163BF5825823D8D008DC28B /* NotificationBreadcrumbTests.m */, - 008966A92486D43400DC48C2 /* RegisterErrorDataTest.m */, 01B14C55251CE55F00118748 /* report-react-native-promise-rejection.json */, 008966B72486D43500DC48C2 /* report.json */, 008966AE2486D43500DC48C2 /* Swift Tests */, @@ -2019,7 +2001,6 @@ 00896A112486DAD100DC48C2 /* BSG_KSCrashSentry_CPPException.h in Headers */, 008969ED2486DAD100DC48C2 /* BSG_KSCrashDoctor.h in Headers */, 01468F5225876DC1002B0519 /* BSGNotificationBreadcrumbs.h in Headers */, - 00AD1F022486A17900A27979 /* RegisterErrorData.h in Headers */, 008968ED2486DAB800DC48C2 /* BugsnagFileStore.h in Headers */, 00896A292486DAD100DC48C2 /* BSG_KSCrashType.h in Headers */, 008969DB2486DAD100DC48C2 /* BSG_KSCrash.h in Headers */, @@ -2115,7 +2096,6 @@ 008969972486DAD100DC48C2 /* BSG_KSBacktrace_Private.h in Headers */, 00896A122486DAD100DC48C2 /* BSG_KSCrashSentry_CPPException.h in Headers */, 008969EE2486DAD100DC48C2 /* BSG_KSCrashDoctor.h in Headers */, - 00AD1F032486A17900A27979 /* RegisterErrorData.h in Headers */, 01468F5325876DC1002B0519 /* BSGNotificationBreadcrumbs.h in Headers */, 008968EE2486DAB800DC48C2 /* BugsnagFileStore.h in Headers */, 00896A2A2486DAD100DC48C2 /* BSG_KSCrashType.h in Headers */, @@ -2213,7 +2193,6 @@ 008969982486DAD100DC48C2 /* BSG_KSBacktrace_Private.h in Headers */, 00896A132486DAD100DC48C2 /* BSG_KSCrashSentry_CPPException.h in Headers */, 008969EF2486DAD100DC48C2 /* BSG_KSCrashDoctor.h in Headers */, - 00AD1F042486A17900A27979 /* RegisterErrorData.h in Headers */, 01468F5425876DC1002B0519 /* BSGNotificationBreadcrumbs.h in Headers */, 008968EF2486DAB800DC48C2 /* BugsnagFileStore.h in Headers */, 00896A2B2486DAD100DC48C2 /* BSG_KSCrashType.h in Headers */, @@ -2482,7 +2461,7 @@ 008969992486DAD100DC48C2 /* BSG_KSMach_Arm64.c in Sources */, 008967E82486DA2D00DC48C2 /* BugsnagErrorTypes.m in Sources */, 008968722486DA9500DC48C2 /* BugsnagDevice.m in Sources */, - 008969842486DAD100DC48C2 /* BSG_KSMachHeaders.m in Sources */, + 008969842486DAD100DC48C2 /* BSG_KSMachHeaders.c in Sources */, 00896A322486DAD100DC48C2 /* BSG_KSCrashC.c in Sources */, 008969902486DAD100DC48C2 /* BSG_RFC3339DateTool.m in Sources */, 008968AB2486DA9600DC48C2 /* BugsnagStateEvent.m in Sources */, @@ -2534,7 +2513,6 @@ 008968C32486DA9600DC48C2 /* BugsnagUser.m in Sources */, CBAB4DD82510D2460092CBAA /* BugsnagKVStoreObjC.m in Sources */, 008968A72486DA9600DC48C2 /* BugsnagSession.m in Sources */, - 00AD1F052486A17900A27979 /* RegisterErrorData.m in Sources */, 0089683A2486DA6C00DC48C2 /* BugsnagMetadata.m in Sources */, 008969F62486DAD100DC48C2 /* BSG_KSCrash.m in Sources */, 0089695D2486DAD000DC48C2 /* BSG_KSMach_x86_32.c in Sources */, @@ -2612,7 +2590,6 @@ 008967332486D43700DC48C2 /* BugsnagClientTests.m in Sources */, 004E353F2487B3BD007FBAE4 /* BugsnagSwiftConfigurationTests.swift in Sources */, 008967542486D43700DC48C2 /* BugsnagOnCrashTest.m in Sources */, - 008966F72486D43700DC48C2 /* RegisterErrorDataTest.m in Sources */, 008967152486D43700DC48C2 /* BugsnagCollectionsBSGDictMergeTest.m in Sources */, 01E8765E256684E700F4B70A /* URLSessionMock.m in Sources */, 008967AB2486D43700DC48C2 /* KSMach_Tests.m in Sources */, @@ -2646,7 +2623,7 @@ 0089699A2486DAD100DC48C2 /* BSG_KSMach_Arm64.c in Sources */, 008967E92486DA2D00DC48C2 /* BugsnagErrorTypes.m in Sources */, 008968732486DA9500DC48C2 /* BugsnagDevice.m in Sources */, - 008969852486DAD100DC48C2 /* BSG_KSMachHeaders.m in Sources */, + 008969852486DAD100DC48C2 /* BSG_KSMachHeaders.c in Sources */, 00896A332486DAD100DC48C2 /* BSG_KSCrashC.c in Sources */, 008969912486DAD100DC48C2 /* BSG_RFC3339DateTool.m in Sources */, 008968AC2486DA9600DC48C2 /* BugsnagStateEvent.m in Sources */, @@ -2699,7 +2676,6 @@ 008968C42486DA9600DC48C2 /* BugsnagUser.m in Sources */, CBAB4DD92510D2460092CBAA /* BugsnagKVStoreObjC.m in Sources */, 008968A82486DA9600DC48C2 /* BugsnagSession.m in Sources */, - 00AD1F062486A17900A27979 /* RegisterErrorData.m in Sources */, 0089683B2486DA6C00DC48C2 /* BugsnagMetadata.m in Sources */, 008969F72486DAD100DC48C2 /* BSG_KSCrash.m in Sources */, 0089695E2486DAD000DC48C2 /* BSG_KSMach_x86_32.c in Sources */, @@ -2737,7 +2713,6 @@ 0089679A2486D43700DC48C2 /* FileBasedTestCase.m in Sources */, 008967912486D43700DC48C2 /* KSJSONCodec_Tests.m in Sources */, 008967732486D43700DC48C2 /* KSSysCtl_Tests.m in Sources */, - 008966F82486D43700DC48C2 /* RegisterErrorDataTest.m in Sources */, E701FAAC2490EFD9008D842F /* EventApiValidationTest.m in Sources */, 0089674F2486D43700DC48C2 /* BugsnagPluginTest.m in Sources */, 008967132486D43700DC48C2 /* BugsnagEventTests.m in Sources */, @@ -2809,7 +2784,7 @@ 0089699B2486DAD100DC48C2 /* BSG_KSMach_Arm64.c in Sources */, 008967EA2486DA2D00DC48C2 /* BugsnagErrorTypes.m in Sources */, 008968742486DA9500DC48C2 /* BugsnagDevice.m in Sources */, - 008969862486DAD100DC48C2 /* BSG_KSMachHeaders.m in Sources */, + 008969862486DAD100DC48C2 /* BSG_KSMachHeaders.c in Sources */, 00896A342486DAD100DC48C2 /* BSG_KSCrashC.c in Sources */, 008969922486DAD100DC48C2 /* BSG_RFC3339DateTool.m in Sources */, 008968AD2486DA9600DC48C2 /* BugsnagStateEvent.m in Sources */, @@ -2862,7 +2837,6 @@ 008968C52486DA9600DC48C2 /* BugsnagUser.m in Sources */, CBAB4DDA2510D2460092CBAA /* BugsnagKVStoreObjC.m in Sources */, 008968A92486DA9600DC48C2 /* BugsnagSession.m in Sources */, - 00AD1F072486A17900A27979 /* RegisterErrorData.m in Sources */, 0089683C2486DA6C00DC48C2 /* BugsnagMetadata.m in Sources */, 008969F82486DAD100DC48C2 /* BSG_KSCrash.m in Sources */, 0089695F2486DAD000DC48C2 /* BSG_KSMach_x86_32.c in Sources */, @@ -2897,7 +2871,6 @@ CB10E541250BA8E000AF5824 /* BugsnagKVStoreTest.m in Sources */, 008967922486D43700DC48C2 /* KSJSONCodec_Tests.m in Sources */, 008967742486D43700DC48C2 /* KSSysCtl_Tests.m in Sources */, - 008966F92486D43700DC48C2 /* RegisterErrorDataTest.m in Sources */, 008967502486D43700DC48C2 /* BugsnagPluginTest.m in Sources */, 008967142486D43700DC48C2 /* BugsnagEventTests.m in Sources */, 0089675C2486D43700DC48C2 /* BugsnagEnabledBreadcrumbTest.m in Sources */, @@ -2991,7 +2964,7 @@ E746291C248907E500F92D67 /* BSG_KSCrashC.c in Sources */, E74628FC248907C100F92D67 /* BSG_KSCrashDoctor.m in Sources */, E74628FD248907C100F92D67 /* BSG_KSJSONCodecObjC.m in Sources */, - E74628FF248907C100F92D67 /* BSG_KSMachHeaders.m in Sources */, + E74628FF248907C100F92D67 /* BSG_KSMachHeaders.c in Sources */, E7462900248907C100F92D67 /* NSError+BSG_SimpleConstructor.m in Sources */, E7462901248907C100F92D67 /* BSG_KSLogger.m in Sources */, E7462902248907C100F92D67 /* BSG_KSCrashState.m in Sources */, @@ -3040,7 +3013,6 @@ 008968942486DA9600DC48C2 /* BugsnagError.m in Sources */, 008967E12486DA2D00DC48C2 /* BSGConfigurationBuilder.m in Sources */, 008967FD2486DA4500DC48C2 /* BugsnagApiClient.m in Sources */, - 00AD1F082486A17900A27979 /* RegisterErrorData.m in Sources */, 008968EC2486DAB800DC48C2 /* BugsnagSessionFileStore.m in Sources */, 008968F32486DAB800DC48C2 /* BugsnagFileStore.m in Sources */, ); diff --git a/Bugsnag/BugsnagCrashSentry.m b/Bugsnag/BugsnagCrashSentry.m index 4b9935505..1b5d05e5a 100644 --- a/Bugsnag/BugsnagCrashSentry.m +++ b/Bugsnag/BugsnagCrashSentry.m @@ -26,7 +26,7 @@ - (void)install:(BugsnagConfiguration *)config BugsnagErrorReportSink *sink = [[BugsnagErrorReportSink alloc] initWithApiClient:apiClient configuration:config notifier:notifier]; BSG_KSCrash *ksCrash = [BSG_KSCrash sharedInstance]; ksCrash.sink = sink; - ksCrash.introspectMemory = YES; + ksCrash.introspectMemory = NO; ksCrash.onCrash = onCrash; ksCrash.maxStoredReports = (int)config.maxPersistedEvents; diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c index 20207a14a..59d728d19 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c @@ -965,6 +965,27 @@ void bsg_kscrw_i_writeNotableAddresses( writer->endContainer(writer); } +/** Write the message from the `__crash_info` Mach section into the report. + * + * @param writer The writer. + * + * @param key The object key. + * + * @param address The address of the first frame in the backtrace. + */ +void bsg_kscrw_i_writeCrashInfoMessage(const BSG_KSCrashReportWriter *const writer, + const char *key, uintptr_t address) { + BSG_Mach_Header_Info *image = bsg_mach_headers_image_at_address(address); + if (!image) { + BSG_KSLOG_ERROR("Could not locate mach header info"); + return; + } + const char *message = bsg_mach_headers_get_crash_info_message(image); + if (message) { + writer->addStringElement(writer, key, message); + } +} + /** Write information about a thread to the report. * * @param writer The writer. @@ -1021,6 +1042,10 @@ void bsg_kscrw_i_writeThread(const BSG_KSCrashReportWriter *const writer, writer, BSG_KSCrashField_NotableAddresses, machineContext); } } + if (isCrashedThread && backtrace && backtraceLength) { + bsg_kscrw_i_writeCrashInfoMessage(writer, BSG_KSCrashField_CrashInfoMessage, + backtrace[0]); + } } writer->endContainer(writer); } diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReportFields.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReportFields.h index 475c7e005..44aa19d5f 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReportFields.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReportFields.h @@ -95,6 +95,7 @@ #define BSG_KSCrashField_Backtrace "backtrace" #define BSG_KSCrashField_Basic "basic" #define BSG_KSCrashField_Crashed "crashed" +#define BSG_KSCrashField_CrashInfoMessage "crash_info_message" #define BSG_KSCrashField_CurrentThread "current_thread" #define BSG_KSCrashField_DispatchQueue "dispatch_queue" #define BSG_KSCrashField_NotableAddresses "notable_addresses" diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.c similarity index 72% rename from Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.m rename to Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.c index 277ff55dd..4b3049609 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.c @@ -1,16 +1,36 @@ // -// BSG_KSMachHeaders.m +// BSG_KSMachHeaders.c // Bugsnag // // Created by Robin Macharg on 04/05/2020. // Copyright © 2020 Bugsnag. All rights reserved. // -#import -#import -#import -#import "BSG_KSDynamicLinker.h" -#import "BSG_KSMachHeaders.h" +#include "BSG_KSMachHeaders.h" + +#include "BSG_KSDynamicLinker.h" +#include "BSG_KSMach.h" + +#include +#include +#include +#include + +// Copied from https://github.com/apple/swift/blob/swift-5.0-RELEASE/include/swift/Runtime/Debug.h#L28-L40 + +#define CRASHREPORTER_ANNOTATIONS_VERSION 5 +#define CRASHREPORTER_ANNOTATIONS_SECTION "__crash_info" + +struct crashreporter_annotations_t { + uint64_t version; // unsigned long + uint64_t message; // char * + uint64_t signature_string; // char * + uint64_t backtrace; // char * + uint64_t message2; // char * + uint64_t thread; // uint64_t + uint64_t dialog_mode; // unsigned int + uint64_t abort_cause; // unsigned int +}; // MARK: - Mach Header Linked List @@ -255,3 +275,66 @@ uintptr_t bsg_mach_headers_image_at_base_of_image_index(const struct mach_header return 0; } +static uintptr_t bsg_mach_header_info_get_section_addr_named(const BSG_Mach_Header_Info *header, const char *name) { + uintptr_t cmdPtr = bsg_mach_headers_first_cmd_after_header(header->header); + if (!cmdPtr) { + return 0; + } + for (uint32_t i = 0; i < header->header->ncmds; i++) { + const struct load_command *loadCmd = (struct load_command *)cmdPtr; + if (loadCmd->cmd == LC_SEGMENT) { + const struct segment_command *segment = (void *)cmdPtr; + char *sectionPtr = (void *)(cmdPtr + sizeof(*segment)); + for (uint32_t i = 0; i < segment->nsects; i++) { + struct section *section = (void *)sectionPtr; + if (strcmp(name, section->sectname) == 0) { + return section->addr + header->slide; + } + sectionPtr += sizeof(*section); + } + } else if (loadCmd->cmd == LC_SEGMENT_64) { + const struct segment_command_64 *segment = (void *)cmdPtr; + char *sectionPtr = (void *)(cmdPtr + sizeof(*segment)); + for (uint32_t i = 0; i < segment->nsects; i++) { + struct section_64 *section = (void *)sectionPtr; + if (strcmp(name, section->sectname) == 0) { + return (uintptr_t)section->addr + header->slide; + } + sectionPtr += sizeof(*section); + } + } + cmdPtr += loadCmd->cmdsize; + } + return 0; +} + +const char *bsg_mach_headers_get_crash_info_message(const BSG_Mach_Header_Info *header) { + struct crashreporter_annotations_t info; + uintptr_t sectionAddress = bsg_mach_header_info_get_section_addr_named(header, CRASHREPORTER_ANNOTATIONS_SECTION); + if (!sectionAddress) { + return NULL; + } + if (bsg_ksmachcopyMem((void *)sectionAddress, &info, sizeof(info)) != KERN_SUCCESS) { + return NULL; + } + // Version 4 was in use until iOS 9 / Swift 2.0 when the version was bumped to 5. + if (info.version > CRASHREPORTER_ANNOTATIONS_VERSION) { + return NULL; + } + if (!info.message) { + return NULL; + } + // Probe the string to ensure it's safe to read. + for (uintptr_t i = 0; i < 500; i++) { + char c; + if (bsg_ksmachcopyMem((void *)(info.message + i), &c, sizeof(c)) != KERN_SUCCESS) { + // String is not readable. + return NULL; + } + if (c == '\0') { + // Found end of string. + return (const char *)info.message; + } + } + return NULL; +} diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.h index 38f22f985..376aad0e0 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.h @@ -99,4 +99,11 @@ uintptr_t bsg_mach_headers_first_cmd_after_header(const struct mach_header *head */ uintptr_t bsg_mach_headers_image_at_base_of_image_index(const struct mach_header *header); +/** Get the __crash_info message of the specified image. + * + * @param header The header to get commands for. + * @return The __crash_info message, or NULL if no readable message could be found. + */ +const char *bsg_mach_headers_get_crash_info_message(const BSG_Mach_Header_Info *header); + #endif /* BSG_KSMachHeaders_h */ diff --git a/Bugsnag/Payload/BugsnagError+Private.h b/Bugsnag/Payload/BugsnagError+Private.h index 395fc45e7..99308add9 100644 --- a/Bugsnag/Payload/BugsnagError+Private.h +++ b/Bugsnag/Payload/BugsnagError+Private.h @@ -23,6 +23,9 @@ NS_ASSUME_NONNULL_BEGIN + (BugsnagError *)errorFromJson:(NSDictionary *)json; +/// Parses the `__crash_info` message and updates the `errorClass` and `errorMessage` as appropriate. +- (void)updateWithCrashInfoMessage:(NSString *)crashInfoMessage; + - (NSDictionary *)toDictionary; @end diff --git a/Bugsnag/Payload/BugsnagError.m b/Bugsnag/Payload/BugsnagError.m index 960113a27..5771a3c1c 100644 --- a/Bugsnag/Payload/BugsnagError.m +++ b/Bugsnag/Payload/BugsnagError.m @@ -6,14 +6,16 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -#import "BugsnagError.h" +#import "BugsnagError+Private.h" +#import "BSG_KSCrashReportFields.h" +#import "BugsnagCollections.h" #import "BugsnagKeys.h" +#import "BugsnagLogger.h" #import "BugsnagStackframe+Private.h" #import "BugsnagStacktrace.h" -#import "BugsnagCollections.h" -#import "RegisterErrorData.h" -#import "BugsnagThread.h" +#import "BugsnagThread+Private.h" + NSString *_Nonnull BSGSerializeErrorType(BSGErrorType errorType) { switch (errorType) { @@ -87,12 +89,6 @@ - (instancetype)initWithEvent:(NSDictionary *)event errorReportingThread:(Bugsna _type = BSGErrorTypeCocoa; if (![[event valueForKeyPath:@"user.state.didOOM"] boolValue]) { - NSArray *threadDict = [event valueForKeyPath:@"crash.threads"]; - RegisterErrorData *data = [RegisterErrorData errorDataFromThreads:threadDict]; - if (data) { - _errorClass = data.errorClass; - _errorMessage = data.errorMessage; - } _stacktrace = thread.stacktrace; } } @@ -132,6 +128,36 @@ + (BugsnagError *)errorFromJson:(NSDictionary *)json { return error; } +- (void)updateWithCrashInfoMessage:(NSString *)crashInfoMessage { + @try { + // Messages that match this pattern should override the errorClass (and errorMessage if there is enough information.) + NSString *pattern = @"^(Assertion failed|Fatal error|Precondition failed): ((.+): )?file .+, line \\d+\n$"; + NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:nil]; + NSArray *matches = [regex matchesInString:crashInfoMessage options:0 range:NSMakeRange(0, crashInfoMessage.length)]; + if (matches.count != 1 || matches[0].numberOfRanges != 4) { + if (!self.errorMessage.length) { + // It's better to fall back to the raw string than have an empty errorMessage. + self.errorMessage = crashInfoMessage; + } + return; + } + NSRange errorClassRange = [matches[0] rangeAtIndex:1]; + if (errorClassRange.location != NSNotFound) { + self.errorClass = [crashInfoMessage substringWithRange:errorClassRange]; + } + NSRange errorMessageRange = [matches[0] rangeAtIndex:3]; + if (errorMessageRange.location != NSNotFound) { + self.errorMessage = [crashInfoMessage substringWithRange:errorMessageRange]; + } + } @catch (NSException *exception) { + bsg_log_err(@"Exception thrown while parsing crash info message: %@", exception); + if (!self.errorMessage.length) { + // It's better to fall back to the raw string than have an empty errorMessage. + self.errorMessage = crashInfoMessage; + } + } +} + - (NSDictionary *)findErrorReportingThread:(NSDictionary *)event { NSArray *threads = [event valueForKeyPath:@"crash.threads"]; diff --git a/Bugsnag/Payload/BugsnagEvent.m b/Bugsnag/Payload/BugsnagEvent.m index ff9094b06..8787468cd 100644 --- a/Bugsnag/Payload/BugsnagEvent.m +++ b/Bugsnag/Payload/BugsnagEvent.m @@ -8,6 +8,8 @@ #import "BugsnagPlatformConditional.h" +#import "BugsnagEvent+Private.h" + #if BSG_PLATFORM_IOS #import "BSGUIKit.h" #include @@ -27,7 +29,6 @@ #import "BugsnagConfiguration+Private.h" #import "BugsnagDeviceWithState+Private.h" #import "BugsnagError+Private.h" -#import "BugsnagEvent+Private.h" #import "BugsnagHandledState.h" #import "BugsnagKeys.h" #import "BugsnagMetadata+Private.h" @@ -36,7 +37,7 @@ #import "BugsnagStacktrace+Private.h" #import "BugsnagThread+Private.h" #import "BugsnagUser+Private.h" -#import "RegisterErrorData.h" + static NSString *const DEFAULT_EXCEPTION_TYPE = @"cocoa"; @@ -267,7 +268,7 @@ - (instancetype)initWithOOMData:(NSDictionary *)event { * @return a BugsnagEvent containing the parsed information */ - (instancetype)initWithKSCrashData:(NSDictionary *)event { - NSDictionary *error = [event valueForKeyPath:@"crash.error"]; + NSMutableDictionary *error = [[event valueForKeyPath:@"crash.error"] mutableCopy]; NSString *errorType = error[BSGKeyType]; // Always assume that a report coming from KSCrash is by default an unhandled error. @@ -333,6 +334,11 @@ - (instancetype)initWithKSCrashData:(NSDictionary *)event { NSArray *errors = @[[[BugsnagError alloc] initWithEvent:event errorReportingThread:errorReportingThread]]; + if (errorReportingThread.crashInfoMessage) { + [errors[0] updateWithCrashInfoMessage:errorReportingThread.crashInfoMessage]; + error[@"crashInfo"] = errorReportingThread.crashInfoMessage; + } + BugsnagHandledState *handledState; if (recordedState) { handledState = [[BugsnagHandledState alloc] initWithDictionary:recordedState]; diff --git a/Bugsnag/Payload/BugsnagThread+Private.h b/Bugsnag/Payload/BugsnagThread+Private.h index 1caf2459d..3616e22c0 100644 --- a/Bugsnag/Payload/BugsnagThread+Private.h +++ b/Bugsnag/Payload/BugsnagThread+Private.h @@ -18,6 +18,8 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)threadFromJson:(NSDictionary *)json; +@property (readonly) NSString *crashInfoMessage; + + (NSDictionary *)enhanceThreadInfo:(NSDictionary *)thread depth:(NSUInteger)depth errorType:(nullable NSString *)errorType; diff --git a/Bugsnag/Payload/BugsnagThread.m b/Bugsnag/Payload/BugsnagThread.m index cc2f73c08..fb6864399 100644 --- a/Bugsnag/Payload/BugsnagThread.m +++ b/Bugsnag/Payload/BugsnagThread.m @@ -6,8 +6,9 @@ // Copyright © 2020 Bugsnag. All rights reserved. // -#import "BugsnagThread.h" +#import "BugsnagThread+Private.h" +#import "BSG_KSCrashReportFields.h" #import "BugsnagCollections.h" #import "BugsnagStackframe+Private.h" #import "BugsnagStacktrace+Private.h" @@ -56,13 +57,13 @@ - (instancetype)initWithId:(NSString *)id - (instancetype)initWithThread:(NSDictionary *)thread binaryImages:(NSArray *)binaryImages { if (self = [super init]) { - _errorReportingThread = [thread[@"crashed"] boolValue]; - self.id = [thread[@"index"] stringValue]; - self.type = BSGThreadTypeCocoa; - - NSArray *backtrace = thread[@"backtrace"][@"contents"]; + _errorReportingThread = [thread[@(BSG_KSCrashField_Crashed)] boolValue]; + _id = [thread[@(BSG_KSCrashField_Index)] stringValue]; + _type = BSGThreadTypeCocoa; + _crashInfoMessage = [thread[@(BSG_KSCrashField_CrashInfoMessage)] copy]; + NSArray *backtrace = thread[@(BSG_KSCrashField_Backtrace)][@(BSG_KSCrashField_Contents)]; BugsnagStacktrace *frames = [[BugsnagStacktrace alloc] initWithTrace:backtrace binaryImages:binaryImages]; - self.stacktrace = frames.trace; + _stacktrace = [frames.trace copy]; } return self; } diff --git a/Bugsnag/RegisterErrorData.h b/Bugsnag/RegisterErrorData.h deleted file mode 100644 index 6bf108c91..000000000 --- a/Bugsnag/RegisterErrorData.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// RegisterErrorData.h -// Bugsnag -// -// Created by Jamie Lynch on 07/04/2020. -// Copyright © 2020 Bugsnag. All rights reserved. -// - -#import - -/** - * Inspects data from the register captured by the KSCrash report for - * useful information that can be added to the error class/message. For - * example, this can enhance the error message set for Swift's fatalError(). - */ -@interface RegisterErrorData : NSObject -@property (nonatomic, strong) NSString *_Nullable errorClass; -@property (nonatomic, strong) NSString *_Nullable errorMessage; -+ (instancetype _Nullable )errorDataFromThreads:(NSArray *_Nullable)threads; -- (instancetype _Nonnull )initWithClass:(NSString *_Nonnull)errorClass - message:(NSString *_Nonnull)errorMessage - NS_DESIGNATED_INITIALIZER; -@end diff --git a/Bugsnag/RegisterErrorData.m b/Bugsnag/RegisterErrorData.m deleted file mode 100644 index bd96c9b74..000000000 --- a/Bugsnag/RegisterErrorData.m +++ /dev/null @@ -1,82 +0,0 @@ -// -// RegisterErrorData.m -// Bugsnag -// -// Created by Jamie Lynch on 07/04/2020. -// Copyright © 2020 Bugsnag. All rights reserved. -// - -#import "RegisterErrorData.h" -#import "BugsnagKeys.h" - -@implementation RegisterErrorData -+ (instancetype)errorDataFromThreads:(NSArray *)threads { - for (NSDictionary *thread in threads) { - if (![thread[@"crashed"] boolValue]) { - continue; - } - NSDictionary *notableAddresses = thread[@"notable_addresses"]; - NSMutableArray *interestingValues = [NSMutableArray new]; - NSString *reservedWord = nil; - - for (NSString *key in notableAddresses) { - NSDictionary *data = notableAddresses[key]; - if (![@"string" isEqualToString:data[BSGKeyType]]) { - continue; - } - NSString *contentValue = data[@"value"]; - - if (contentValue == nil || ![contentValue isKindOfClass:[NSString class]]) { - continue; - } - - if ([self isReservedWord:contentValue]) { - reservedWord = contentValue; - } else if ([[contentValue componentsSeparatedByString:@"/"] count] <= 2) { - // must be a string that isn't a reserved word and isn't a filepath - [interestingValues addObject:contentValue]; - } - } - - [interestingValues sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; - - NSString *message = [interestingValues componentsJoinedByString:@" | "]; - // reservedWord *shouldn't* equal nil, but since RegisterErrorData expects a non-nil - // argument guard against it anyway, and fall through. - if (reservedWord != nil) { - return [[RegisterErrorData alloc] initWithClass:reservedWord - message:message]; - } - } - return nil; -} - -/** - * Determines whether a string is a "reserved word" that identifies it as a known value. - * - * For fatalError, preconditionFailure, and assertionFailure, "fatal error" will be in one of the registers. - * - * For assert, "assertion failed" will be in one of the registers. - */ -+ (BOOL)isReservedWord:(NSString *)contentValue { - return [@"assertion failed" caseInsensitiveCompare:contentValue] == NSOrderedSame - || [@"fatal error" caseInsensitiveCompare:contentValue] == NSOrderedSame - || [@"precondition failed" caseInsensitiveCompare:contentValue] == NSOrderedSame; -} - -- (instancetype)init { - return [self initWithClass:@"Unknown" message:@""]; -} - -- (instancetype)initWithClass:(NSString *)errorClass message:(NSString *)errorMessage { - if (errorClass.length == 0) { - return nil; - } - if (self = [super init]) { - _errorClass = errorClass; - _errorMessage = errorMessage; - } - return self; -} - -@end diff --git a/Tests/BugsnagErrorTest.m b/Tests/BugsnagErrorTest.m index 2edcf0602..ac727bb75 100644 --- a/Tests/BugsnagErrorTest.m +++ b/Tests/BugsnagErrorTest.m @@ -24,10 +24,6 @@ @interface BugsnagErrorTest : XCTestCase @implementation BugsnagErrorTest - (void)setUp { - self.event = [self generateEvent:@{}]; -} - -- (NSDictionary *)generateEvent:(NSDictionary *)notableAddresses { NSDictionary *thread = @{ @"current_thread": @YES, @"crashed": @YES, @@ -43,8 +39,7 @@ - (NSDictionary *)generateEvent:(NSDictionary *)notableAddresses { @"object_addr": @4490747904 } ] - }, - @"notable_addresses": notableAddresses + } }; NSDictionary *binaryImage = @{ @"uuid": @"D0A41830-4FD2-3B02-A23B-0741AD4C7F52", @@ -53,7 +48,7 @@ - (NSDictionary *)generateEvent:(NSDictionary *)notableAddresses { @"image_size": @483328, @"name": @"/Users/joesmith/foo", }; - return @{ + self.event = @{ @"crash": @{ @"error": @{ @"type": @"user", @@ -112,48 +107,6 @@ - (BugsnagThread *)findErrorReportingThread:(NSDictionary *)event { return nil; } -/** - * If notable addresses are in the event, the error message/class should be enhanced - * with these values - */ -- (void)testMessageEnhancement { - self.event = [self generateEvent:@{ - @"x9": @{ - @"address": @4511086448, - @"type": @"string", - @"value": @"Something went wrong" - }, - @"r16": @{ - @"address": @4511089532, - @"type": @"string", - @"value": @"Fatal error" - } - }]; - BugsnagError *error = [[BugsnagError alloc] initWithEvent:self.event errorReportingThread:nil]; - NSDictionary *dict = [error toDictionary]; - XCTAssertEqualObjects(@"Fatal error", dict[@"errorClass"]); - XCTAssertEqualObjects(@"Something went wrong", dict[@"message"]); -} - -- (void) testEmptyErrorDataFromThreads { - self.event = [self generateEvent:@{ - @"x9": @{ - @"address": @4511086448, - @"type": @"string", - @"value": @"Something went wrong" - }, - @"r16": @{ - @"address": @4511089532, - @"type": @"string", - @"value": [NSNull null] - } - }]; - BugsnagError *error = [[BugsnagError alloc] initWithEvent:self.event errorReportingThread:nil]; - NSDictionary *dict = [error toDictionary]; - XCTAssertEqualObjects(@"Foo Exception", dict[@"errorClass"]); - XCTAssertEqualObjects(@"Foo overload", dict[@"message"]); -} - - (void)testErrorClassParse { XCTAssertEqualObjects(@"foo", BSGParseErrorClass(@{@"cpp_exception": @{@"name": @"foo"}}, @"cpp_exception")); XCTAssertEqualObjects(@"bar", BSGParseErrorClass(@{@"mach": @{@"exception_name": @"bar"}}, @"mach")); @@ -195,4 +148,109 @@ - (void)testStacktraceOverride { XCTAssertEqual(0, error.stacktrace.count); } +- (void)testUpdateWithCrashInfoMessage { + BugsnagError *error = [[BugsnagError alloc] initWithErrorClass:@"" errorMessage:@"" errorType:BSGErrorTypeCocoa stacktrace:nil]; + + // Swift fatal errors with a message. + // The errorClass and errorMessage should be overwritten with values extracted from the crash info message. + + error.errorClass = nil; + error.errorMessage = nil; + [error updateWithCrashInfoMessage:@"Assertion failed: This should NEVER happen: file bugsnag_example/AnotherClass.swift, line 24\n"]; + XCTAssertEqualObjects(error.errorClass, @"Assertion failed"); + XCTAssertEqualObjects(error.errorMessage, @"This should NEVER happen"); + + error.errorClass = nil; + error.errorMessage = nil; + [error updateWithCrashInfoMessage:@"assertion failed: This should NEVER happen: file bugsnag_example/AnotherClass.swift, line 24\n"]; + XCTAssertEqualObjects(error.errorClass, @"assertion failed"); + XCTAssertEqualObjects(error.errorMessage, @"This should NEVER happen"); + + error.errorClass = nil; + error.errorMessage = nil; + [error updateWithCrashInfoMessage:@"Fatal error: This should NEVER happen: file bugsnag_example/AnotherClass.swift, line 24\n"]; + XCTAssertEqualObjects(error.errorClass, @"Fatal error"); + XCTAssertEqualObjects(error.errorMessage, @"This should NEVER happen"); + + error.errorClass = nil; + error.errorMessage = nil; + [error updateWithCrashInfoMessage:@"fatal error: This should NEVER happen: file bugsnag_example/AnotherClass.swift, line 24\n"]; + XCTAssertEqualObjects(error.errorClass, @"fatal error"); + XCTAssertEqualObjects(error.errorMessage, @"This should NEVER happen"); + + error.errorClass = nil; + error.errorMessage = nil; + [error updateWithCrashInfoMessage:@"Precondition failed: : strange formatting 😱::: file bugsnag_example/AnotherClass.swift, line 24\n"]; + XCTAssertEqualObjects(error.errorClass, @"Precondition failed"); + XCTAssertEqualObjects(error.errorMessage, @" : strange formatting 😱::"); + + error.errorClass = nil; + error.errorMessage = nil; + [error updateWithCrashInfoMessage:@"precondition failed: : strange formatting 😱::: file bugsnag_example/AnotherClass.swift, line 24\n"]; + XCTAssertEqualObjects(error.errorClass, @"precondition failed"); + XCTAssertEqualObjects(error.errorMessage, @" : strange formatting 😱::"); + + // Swift fatal errors without a message. + // The errorClass should be overwritten but the errorMessage left as-is. + + error.errorClass = nil; + error.errorMessage = nil; + [error updateWithCrashInfoMessage:@"Assertion failed: file bugsnag_example/AnotherClass.swift, line 24\n"]; + XCTAssertEqualObjects(error.errorClass, @"Assertion failed"); + XCTAssertEqualObjects(error.errorMessage, nil); + + error.errorClass = nil; + error.errorMessage = @"Expected message"; + [error updateWithCrashInfoMessage:@"Assertion failed: file bugsnag_example/AnotherClass.swift, line 24\n"]; + XCTAssertEqualObjects(error.errorClass, @"Assertion failed"); + XCTAssertEqualObjects(error.errorMessage, @"Expected message"); + + error.errorClass = nil; + error.errorMessage = @"Expected message"; + [error updateWithCrashInfoMessage:@"Fatal error: file bugsnag_example/AnotherClass.swift, line 24\n"]; + XCTAssertEqualObjects(error.errorClass, @"Fatal error"); + XCTAssertEqualObjects(error.errorMessage, @"Expected message"); + + error.errorClass = nil; + error.errorMessage = @"Expected message"; + [error updateWithCrashInfoMessage:@"Precondition failed: file bugsnag_example/AnotherClass.swift, line 24\n"]; + XCTAssertEqualObjects(error.errorClass, @"Precondition failed"); + XCTAssertEqualObjects(error.errorMessage, @"Expected message"); + + // Non-matching crash info messages. + // The errorClass should not be overwritten, the errorMessage should be overwritten if it was previously empty / nil. + + error.errorClass = nil; + error.errorMessage = @"Expected message"; + [error updateWithCrashInfoMessage:@"Assertion failed: This should NEVER happen: file bugsnag_example/AnotherClass.swift, line 24\njunk"]; + XCTAssertEqualObjects(error.errorClass, nil,); + XCTAssertEqualObjects(error.errorMessage, @"Expected message"); + + error.errorClass = @"Expected error class"; + error.errorMessage = @"Expected message"; + [error updateWithCrashInfoMessage:@"BUG IN CLIENT OF LIBDISPATCH: dispatch_sync called on queue already owned by current thread"]; + XCTAssertEqualObjects(error.errorClass, @"Expected error class"); + + error.errorClass = @"Expected error class"; + error.errorMessage = nil; + [error updateWithCrashInfoMessage:@"BUG IN CLIENT OF LIBDISPATCH: dispatch_sync called on queue already owned by current thread"]; + XCTAssertEqualObjects(error.errorClass, @"Expected error class",); + XCTAssertEqualObjects(error.errorMessage, @"BUG IN CLIENT OF LIBDISPATCH: dispatch_sync called on queue already owned by current thread"); + + error.errorClass = @"Expected error class"; + error.errorMessage = @"Expected message"; + [error updateWithCrashInfoMessage:@""]; + XCTAssertEqualObjects(error.errorClass, @"Expected error class"); + XCTAssertEqualObjects(error.errorMessage, @"Expected message",); + + error.errorClass = @"Expected error class"; + error.errorMessage = @"Expected message"; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnonnull" + [error updateWithCrashInfoMessage:nil]; +#pragma clang diagnostic pop + XCTAssertEqualObjects(error.errorClass, @"Expected error class",); + XCTAssertEqualObjects(error.errorMessage, @"Expected message",); +} + @end diff --git a/Tests/BugsnagEventTests.m b/Tests/BugsnagEventTests.m index ec9d216e3..fe487e95d 100644 --- a/Tests/BugsnagEventTests.m +++ b/Tests/BugsnagEventTests.m @@ -97,233 +97,6 @@ - (void)testDefaultErrorMessageNilForEmptyThreads { payload[@"exceptions"][0][@"message"]); } -- (void)testEnhancedErrorMessageNilForEmptyNotableAddresses { - BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{ - @"threads" : @[ @{@"crashed" : @YES, @"notable_addresses" : @{}} ] - }]; - NSDictionary *payload = [event toJson]; - XCTAssertEqualObjects(@"Exception", - payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(@"", payload[@"exceptions"][0][@"message"]); - XCTAssertEqualObjects(event.errors[0].errorClass, - payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(event.errors[0].errorMessage, - payload[@"exceptions"][0][@"message"]); -} - -- (void)testEnhancedErrorMessageForFatalErrorWithoutAdditionalMessage { - BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{ - @"crash" : @{ - @"threads" : @[ @{ - @"crashed" : @YES, - @"notable_addresses" : @{ - @"r14" : @{ - @"address" : @4511089532, - @"type" : @"string", - @"value" : @"fatal error" - } - } - } ] - } - }]; - NSDictionary *payload = [event toJson]; - XCTAssertEqualObjects(@"fatal error", - payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(@"", payload[@"exceptions"][0][@"message"]); - XCTAssertEqualObjects(event.errors[0].errorClass, - payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(event.errors[0].errorMessage, - payload[@"exceptions"][0][@"message"]); -} - -- (void)testEnhancedErrorMessageForAssertionWithoutAdditionalMessage { - BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{ - @"crash" : @{ - @"threads" : @[ @{ - @"crashed" : @YES, - @"notable_addresses" : @{ - @"r14" : @{ - @"address" : @4511089532, - @"type" : @"string", - @"value" : @"assertion failed" - } - } - } ] - } - }]; - NSDictionary *payload = [event toJson]; - XCTAssertEqualObjects(@"assertion failed", - payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(@"", payload[@"exceptions"][0][@"message"]); - XCTAssertEqualObjects(event.errors[0].errorClass, - payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(event.errors[0].errorMessage, - payload[@"exceptions"][0][@"message"]); -} - -- (void)testEnhancedErrorMessageForAssertionError { - for (NSString *assertionName in @[ - @"assertion failed", @"Assertion failed", @"fatal error", - @"Fatal error" - ]) { - BugsnagEvent *event = - [[BugsnagEvent alloc] initWithKSReport:@{ - @"crash" : @{ - @"threads" : @[ @{ - @"crashed" : @YES, - @"notable_addresses" : @{ - @"x9" : @{ - @"address" : @4511086448, - @"type" : @"string", - @"value" : @"Something went wrong" - }, - @"r16" : @{ - @"address" : @4511089532, - @"type" : @"string", - @"value" : assertionName - } - } - } ] - } - }]; - NSDictionary *payload = [event toJson]; - XCTAssertEqualObjects(assertionName, - payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(@"Something went wrong", - payload[@"exceptions"][0][@"message"]); - XCTAssertEqualObjects(event.errors[0].errorClass, - payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(event.errors[0].errorMessage, - payload[@"exceptions"][0][@"message"]); - } -} - -- (void)testEnhancedErrorMessageIgnoresFilePaths { - BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{ - @"crash" : @{ - @"threads" : @[ @{ - @"crashed" : @YES, - @"notable_addresses" : @{ - @"x9" : @{ - @"address" : @4511086448, - @"type" : @"string", - @"value" : @"/usr/include/lib/something.swift" - }, - @"r16" : @{ - @"address" : @4511089532, - @"type" : @"string", - @"value" : @"fatal error" - } - } - } ] - } - }]; - NSDictionary *payload = [event toJson]; - XCTAssertEqualObjects(@"fatal error", - payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(@"", payload[@"exceptions"][0][@"message"]); - XCTAssertEqualObjects(event.errors[0].errorClass, - payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(event.errors[0].errorMessage, - payload[@"exceptions"][0][@"message"]); -} - -- (void)testEnhancedErrorMessageIgnoresNonStrings { - BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{ - @"crash" : @{ - @"threads" : @[ @{ - @"crashed" : @YES, - @"notable_addresses" : @{ - @"x9" : @{ - @"address" : @4511086448, - @"type" : @"long", - @"value" : @"A message from beyond" - }, - @"r16" : @{ - @"address" : @4511089532, - @"type" : @"string", - @"value" : @"fatal error" - } - } - } ] - } - }]; - NSDictionary *payload = [event toJson]; - XCTAssertEqualObjects(@"fatal error", - payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(@"", payload[@"exceptions"][0][@"message"]); - XCTAssertEqualObjects(event.errors[0].errorClass, - payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(event.errors[0].errorMessage, - payload[@"exceptions"][0][@"message"]); -} - -- (void)testEnhancedErrorMessageConcatenatesMultipleMessages { - BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{ - @"crash" : @{ - @"threads" : @[ @{ - @"crashed" : @YES, - @"notable_addresses" : @{ - @"x9" : @{ - @"address" : @4511086448, - @"type" : @"string", - @"value" : @"A message from beyond" - }, - @"r14" : @{ - @"address" : @4511086448, - @"type" : @"string", - @"value" : @"Wo0o0o" - }, - @"r16" : @{ - @"address" : @4511089532, - @"type" : @"string", - @"value" : @"Fatal error" - } - } - } ] - } - }]; - NSDictionary *payload = [event toJson]; - XCTAssertEqualObjects(@"Fatal error", - payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(@"A message from beyond | Wo0o0o", - payload[@"exceptions"][0][@"message"]); - XCTAssertEqualObjects(event.errors[0].errorClass, - payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(event.errors[0].errorMessage, - payload[@"exceptions"][0][@"message"]); -} - -- (void)testEnhancedErrorMessageIgnoresUnknownAssertionTypes { - BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{ - @"crash" : @{ - @"threads" : @[ @{ - @"crashed" : @YES, - @"notable_addresses" : @{ - @"x9" : @{ - @"address" : @4511086448, - @"type" : @"string", - @"value" : @"A message from beyond" - }, - @"r14" : @{ - @"address" : @4511086448, - @"type" : @"string", - @"value" : @"Wo0o0o" - } - } - } ] - } - }]; - NSDictionary *payload = [event toJson]; - XCTAssertEqualObjects(@"Exception", - payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(@"", payload[@"exceptions"][0][@"message"]); - XCTAssertEqualObjects(event.errors[0].errorClass, - payload[@"exceptions"][0][@"errorClass"]); - XCTAssertEqualObjects(event.errors[0].errorMessage, - payload[@"exceptions"][0][@"message"]); -} - - (void)testEmptyReport { BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:@{}]; XCTAssertNil(event); diff --git a/Tests/RegisterErrorDataTest.m b/Tests/RegisterErrorDataTest.m deleted file mode 100644 index c302835a9..000000000 --- a/Tests/RegisterErrorDataTest.m +++ /dev/null @@ -1,262 +0,0 @@ -// -// Created by Jamie Lynch on 11/06/2018. -// Copyright (c) 2018 Bugsnag. All rights reserved. -// - - -#import -#import - -@interface RegisterErrorData -+ (instancetype)errorDataFromThreads:(NSArray *)threads; -@property (nonatomic, strong) NSString *errorClass; -@property (nonatomic, strong) NSString *errorMessage; -@end - -@interface RegisterErrorDataTest : XCTestCase -@end - -@implementation RegisterErrorDataTest - - -- (void)testNilAddresses { - XCTAssertNil([RegisterErrorData errorDataFromThreads:nil]); -} - -- (void)testEmptyAddresses { - XCTAssertNil([RegisterErrorData errorDataFromThreads:@[]]); -} - -- (void)testEmptyCrashedThreadDict { - NSDictionary *thread = @{ - @"crashed": @YES - }; - XCTAssertNil([RegisterErrorData errorDataFromThreads:@[thread]]); -} - -- (void)testEmptyNotableAddresses { - NSDictionary *thread = @{ - @"crashed": @YES, - @"notable_addresses": @{} - }; - RegisterErrorData *data = [RegisterErrorData errorDataFromThreads:@[thread]]; - XCTAssertNil(data); -} - -- (void)testEmptyContentValue { - NSDictionary *thread = @{ - @"crashed": @YES, - @"notable_addresses": @{ - @"hello_world": @{} - } - }; - RegisterErrorData *data = [RegisterErrorData errorDataFromThreads:@[thread]]; - XCTAssertNil(data); -} - -- (void)testNilValueImplicit { - NSDictionary *thread = @{ - @"crashed": @YES, - @"notable_addresses": @{ - @"hello_world": @{ - @"type": @"string" - } - } - }; - RegisterErrorData *data = [RegisterErrorData errorDataFromThreads:@[thread]]; - XCTAssertNil(data); -} - -- (void)testNilValueExplicit { - NSDictionary *thread = @{ - @"crashed": @YES, - @"notable_addresses": @{ - @"hello_world": @{ - @"type": @"string", - @"value": [NSNull null] - } - } - }; - RegisterErrorData *data = [RegisterErrorData errorDataFromThreads:@[thread]]; - XCTAssertNil(data); -} - -- (void)testHasTypeAndValue{ - NSDictionary *thread = @{ - @"crashed": @YES, - @"notable_addresses": @{ - @"hello_world": @{ - @"type": @"string", - @"value": @"Hello, World!" - } - } - }; - RegisterErrorData *data = [RegisterErrorData errorDataFromThreads:@[thread]]; - XCTAssertNil(data); -} - -- (void)testFatalError { - NSDictionary *thread = @{ - @"crashed": @YES, - @"notable_addresses": @{ - @"hello_world": @{ - @"type": @"string", - @"value": @"fatal error" - } - } - }; - RegisterErrorData *data = [RegisterErrorData errorDataFromThreads:@[thread]]; - XCTAssertNotNil(data); - XCTAssertEqualObjects(@"fatal error", data.errorClass); - XCTAssertEqualObjects(@"", data.errorMessage); -} - -- (void)testAssertionFailed { - NSDictionary *thread = @{ - @"crashed": @YES, - @"notable_addresses": @{ - @"hello_world": @{ - @"type": @"string", - @"value": @"assertion failed" - } - } - }; - RegisterErrorData *data = [RegisterErrorData errorDataFromThreads:@[thread]]; - XCTAssertNotNil(data); - XCTAssertEqualObjects(@"assertion failed", data.errorClass); - XCTAssertEqualObjects(@"", data.errorMessage); -} - -- (void)testPreconditionFailed { - NSDictionary *thread = @{ - @"crashed": @YES, - @"notable_addresses": @{ - @"hello_world": @{ - @"type": @"string", - @"value": @"precondition failed" - } - } - }; - RegisterErrorData *data = [RegisterErrorData errorDataFromThreads:@[thread]]; - XCTAssertNotNil(data); - XCTAssertEqualObjects(@"precondition failed", data.errorClass); - XCTAssertEqualObjects(@"", data.errorMessage); -} - -- (void)testSingleMessageValue { - NSDictionary *thread = @{ - @"crashed": @YES, - @"notable_addresses": @{ - @"hello_world": @{ - @"type": @"string", - @"value": @"fatal error" - }, - @"message": @{ - @"type": @"string", - @"value": @"Single Message" - } - } - }; - RegisterErrorData *data = [RegisterErrorData errorDataFromThreads:@[thread]]; - XCTAssertEqualObjects(@"Single Message", data.errorMessage); -} - -- (void)testMultiMessageValue { - NSDictionary *thread = @{ - @"crashed": @YES, - @"notable_addresses": @{ - @"hello_world": @{ - @"type": @"string", - @"value": @"fatal error" - }, - @"message": @{ - @"type": @"string", - @"value": @"A is for aardvark" - }, - @"message2": @{ - @"type": @"string", - @"value": @"Z is for zebra" - }, - @"message3": @{ - @"type": @"string", - @"value": @"C is for crayfish" - } - } - }; - RegisterErrorData *data = [RegisterErrorData errorDataFromThreads:@[thread]]; - XCTAssertEqualObjects(@"A is for aardvark | C is for crayfish | Z is for zebra", data.errorMessage); -} - -- (void)testStackExcluded { - NSDictionary *thread = @{ - @"crashed": @YES, - @"notable_addresses": @{ - @"hello_world": @{ - @"type": @"string", - @"value": @"fatal error" - }, - @"message": @{ - @"type": @"stack", - @"value": @"0xf0924501" - } - } - }; - RegisterErrorData *data = [RegisterErrorData errorDataFromThreads:@[thread]]; - XCTAssertEqualObjects(@"", data.errorMessage); -} - -- (void)testOtherTypesExcluded { - NSDictionary *thread = @{ - @"crashed": @YES, - @"notable_addresses": @{ - @"hello_world": @{ - @"type": @"string", - @"value": @"fatal error" - }, - @"message": @{ - @"type": @"someOtherType", - @"value": @"do not serialise" - } - } - }; - RegisterErrorData *data = [RegisterErrorData errorDataFromThreads:@[thread]]; - XCTAssertEqualObjects(@"", data.errorMessage); -} - -- (void)testFilepathExcluded { - NSDictionary *thread = @{ - @"crashed": @YES, - @"notable_addresses": @{ - @"hello_world": @{ - @"type": @"string", - @"value": @"fatal error" - }, - @"message": @{ - @"type": @"string", - @"value": @"/usr/share/locale" - } - } - }; - RegisterErrorData *data = [RegisterErrorData errorDataFromThreads:@[thread]]; - XCTAssertEqualObjects(@"", data.errorMessage); -} - -- (void)testForwardSlashIncluded { - NSDictionary *thread = @{ - @"crashed": @YES, - @"notable_addresses": @{ - @"hello_world": @{ - @"type": @"string", - @"value": @"fatal error" - }, - @"message": @{ - @"type": @"string", - @"value": @"usr/share" - } - } - }; - RegisterErrorData *data = [RegisterErrorData errorDataFromThreads:@[thread]]; - XCTAssertEqualObjects(@"usr/share", data.errorMessage); -} - -@end diff --git a/features/crashprobe.feature b/features/crashprobe.feature index e371f3ffc..2dd19f4a7 100644 --- a/features/crashprobe.feature +++ b/features/crashprobe.feature @@ -101,26 +101,23 @@ Feature: Reporting crash events And the "method" of stack frame 0 equals "objc_msgSend" And the "method" of stack frame 1 equals "__29-[ReleasedObjectScenario run]_block_invoke" -# N.B. this scenario is "imprecise" on CrashProbe due to line number info, -# which is not tested here as this would require symbolication Scenario: Crash within Swift code When I run "SwiftCrash" and relaunch the app And I configure Bugsnag for "SwiftCrash" And I wait to receive a request Then the request is valid for the error reporting API version "4.0" for the "iOS Bugsnag Notifier" notifier - # And the exception "message" equals "Unexpectedly found nil while unwrapping an Optional value" And the exception "errorClass" equals "Fatal error" + And the exception "message" equals "Unexpectedly found nil while unwrapping an Optional value" + And the event "metaData.error.crashInfo" matches "Fatal error: Unexpectedly found nil while unwrapping an Optional value: file .+\.swift, line \d+\n" Scenario: Assertion failure in Swift code When I run "SwiftAssertion" and relaunch the app And I configure Bugsnag for "SwiftAssertion" And I wait to receive a request Then the request is valid for the error reporting API version "4.0" for the "iOS Bugsnag Notifier" notifier - # Temporary workaround until potential issue is investigated thoroughly [PLAT-4875] - And the exception "errorClass" equals one of: - | Fatal error | - | EXC_BREAKPOINT | - # And the exception "message" equals "several unfortunate things just happened" + And the exception "errorClass" equals "Fatal error" + And the exception "message" equals "several unfortunate things just happened" + And the event "metaData.error.crashInfo" matches "Fatal error: several unfortunate things just happened: file .+\.swift, line \d+\n" Scenario: Dereference a null pointer When I run "NullPointerScenario" and relaunch the app @@ -160,3 +157,12 @@ Feature: Reporting crash events And the exception "message" equals "Attempted to dereference garbage pointer 0x10." And the exception "errorClass" equals "EXC_BAD_ACCESS" And the "method" of stack frame 0 equals "objc_msgSend" + + Scenario: Misuse of libdispatch + When I run "DispatchCrashScenario" and relaunch the app + And I configure Bugsnag for "DispatchCrashScenario" + And I wait to receive a request + Then the request is valid for the error reporting API version "4.0" for the "iOS Bugsnag Notifier" notifier + And the exception "errorClass" equals "EXC_BREAKPOINT" + And the exception "message" starts with "BUG IN CLIENT OF LIBDISPATCH: dispatch_" + And the event "metaData.error.crashInfo" starts with "BUG IN CLIENT OF LIBDISPATCH: dispatch_" diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp.xcodeproj/project.pbxproj b/features/fixtures/ios-swift-cocoapods/iOSTestApp.xcodeproj/project.pbxproj index 5b651bb6f..804c25955 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp.xcodeproj/project.pbxproj +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 00432CC4240912A100826D05 /* EnabledErrorTypesCxxScenario.mm in Sources */ = {isa = PBXBuildFile; fileRef = 00432CC2240912A000826D05 /* EnabledErrorTypesCxxScenario.mm */; }; 00507A64242BFE5600EF1B87 /* EnabledBreadcrumbTypesIsNilScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00507A63242BFE5600EF1B87 /* EnabledBreadcrumbTypesIsNilScenario.swift */; }; 00CEB60D24080C690004793D /* EnabledErrorTypesScenario.m in Sources */ = {isa = PBXBuildFile; fileRef = 00CEB60C24080C690004793D /* EnabledErrorTypesScenario.m */; }; + 0104085F258CA0A100933C60 /* DispatchCrashScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0104085E258CA0A100933C60 /* DispatchCrashScenario.swift */; }; 0163BFA72583B3CF008DC28B /* DiscardClassesScenarios.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0163BFA62583B3CF008DC28B /* DiscardClassesScenarios.swift */; }; 01AF6A53258A112F00FFC803 /* BareboneTestScenarios.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01AF6A52258A112F00FFC803 /* BareboneTestScenarios.swift */; }; 6526A0D4248A83350002E2C9 /* LoadConfigFromFileAutoScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6526A0D3248A83350002E2C9 /* LoadConfigFromFileAutoScenario.swift */; }; @@ -161,6 +162,7 @@ 00A98315240DBB7A0016A57E /* out_of_memory.feature */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = out_of_memory.feature; path = ../../../out_of_memory.feature; sourceTree = ""; }; 00CEB60B24080C690004793D /* EnabledErrorTypesScenario.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EnabledErrorTypesScenario.h; sourceTree = ""; }; 00CEB60C24080C690004793D /* EnabledErrorTypesScenario.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EnabledErrorTypesScenario.m; sourceTree = ""; }; + 0104085E258CA0A100933C60 /* DispatchCrashScenario.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DispatchCrashScenario.swift; sourceTree = ""; }; 0163BFA62583B3CF008DC28B /* DiscardClassesScenarios.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiscardClassesScenarios.swift; sourceTree = ""; }; 01AF6A52258A112F00FFC803 /* BareboneTestScenarios.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BareboneTestScenarios.swift; sourceTree = ""; }; 4994F05E0421A0B037DD2CC5 /* Pods_iOSTestApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iOSTestApp.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -602,6 +604,7 @@ F42956D34274D4ED16B4D491 /* BuiltinTrapScenario.m */, F42951B01B327C380EC2D8A6 /* CxxExceptionScenario.h */, F429550B682F8F9677305881 /* CxxExceptionScenario.mm */, + 0104085E258CA0A100933C60 /* DispatchCrashScenario.swift */, F42950D49A5F24FF7155EEE1 /* NonExistentMethodScenario.h */, F4295F13EBCAC9CB0ABC4008 /* NonExistentMethodScenario.m */, F4295C1C7C54101194B61E93 /* NullPointerScenario.h */, @@ -937,6 +940,7 @@ 8A840FBA21AF5C450041DBFA /* SwiftAssertion.swift in Sources */, E753F24824927412001FB671 /* OnSendErrorCallbackCrashScenario.swift in Sources */, 001E5502243B8FDA0009E31D /* AutoCaptureRunScenario.m in Sources */, + 0104085F258CA0A100933C60 /* DispatchCrashScenario.swift in Sources */, E700EE55247D3204008CFFB6 /* OnSendOverwriteScenario.swift in Sources */, F429538D8941382EC2C857CE /* AsyncSafeThreadScenario.m in Sources */, F42955869D33EE0E510B9651 /* ReadGarbagePointerScenario.m in Sources */, diff --git a/features/fixtures/macos/macOSTestApp.xcodeproj/project.pbxproj b/features/fixtures/macos/macOSTestApp.xcodeproj/project.pbxproj index 1cfdb6e8b..b4523be65 100644 --- a/features/fixtures/macos/macOSTestApp.xcodeproj/project.pbxproj +++ b/features/fixtures/macos/macOSTestApp.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 0176C0B6254AE81B0066E0F3 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0176C0B4254AE81B0066E0F3 /* MainMenu.xib */; }; 017FBFB8254B09C300809042 /* MainWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 017FBFB6254B09C300809042 /* MainWindowController.m */; }; 017FBFB9254B09C300809042 /* MainWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 017FBFB7254B09C300809042 /* MainWindowController.xib */; }; + 01AF6A84258BB38A00FFC803 /* DispatchCrashScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01AF6A83258BB38A00FFC803 /* DispatchCrashScenario.swift */; }; 01AF6A50258A00DE00FFC803 /* BareboneTestScenarios.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01AF6A4F258A00DE00FFC803 /* BareboneTestScenarios.swift */; }; 01F47CC4254B1B3100B184AD /* OriginalErrorNSExceptionScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F47C21254B1B2C00B184AD /* OriginalErrorNSExceptionScenario.swift */; }; 01F47CC5254B1B3100B184AD /* LoadConfigFromFileAutoScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01F47C23254B1B2C00B184AD /* LoadConfigFromFileAutoScenario.swift */; }; @@ -159,6 +160,7 @@ 017FBFB5254B09C300809042 /* MainWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MainWindowController.h; sourceTree = ""; }; 017FBFB6254B09C300809042 /* MainWindowController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MainWindowController.m; sourceTree = ""; }; 017FBFB7254B09C300809042 /* MainWindowController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindowController.xib; sourceTree = ""; }; + 01AF6A83258BB38A00FFC803 /* DispatchCrashScenario.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DispatchCrashScenario.swift; sourceTree = ""; }; 01AF6A4F258A00DE00FFC803 /* BareboneTestScenarios.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BareboneTestScenarios.swift; sourceTree = ""; }; 01F47C21254B1B2C00B184AD /* OriginalErrorNSExceptionScenario.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OriginalErrorNSExceptionScenario.swift; sourceTree = ""; }; 01F47C22254B1B2C00B184AD /* ThreadScenarios.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadScenarios.h; sourceTree = ""; }; @@ -388,6 +390,7 @@ 0163BF9A2583AF2A008DC28B /* DiscardClassesScenarios.swift */, 01F47CA8254B1B3000B184AD /* DiscardedBreadcrumbTypeScenario.swift */, 01F47CB6254B1B3000B184AD /* DiscardSessionScenario.swift */, + 01AF6A83258BB38A00FFC803 /* DispatchCrashScenario.swift */, 01F47C3D254B1B2D00B184AD /* EnabledBreadcrumbTypesIsNilScenario.swift */, 01F47C5C254B1B2E00B184AD /* EnabledErrorTypesCxxScenario.h */, 01F47C81254B1B2F00B184AD /* EnabledErrorTypesCxxScenario.mm */, @@ -702,6 +705,7 @@ 01F47D30254B1B3100B184AD /* AutoContextNSExceptionScenario.swift in Sources */, 01F47CE1254B1B3100B184AD /* ManualSessionWithUserScenario.m in Sources */, 01F47D01254B1B3100B184AD /* SessionCallbackOrderScenario.swift in Sources */, + 01AF6A84258BB38A00FFC803 /* DispatchCrashScenario.swift in Sources */, 01F47D0A254B1B3100B184AD /* CxxExceptionScenario.mm in Sources */, 01F47D03254B1B3100B184AD /* OriginalErrorNSErrorScenario.swift in Sources */, 01F47D28254B1B3100B184AD /* ReadGarbagePointerScenario.m in Sources */, diff --git a/features/fixtures/shared/scenarios/DispatchCrashScenario.swift b/features/fixtures/shared/scenarios/DispatchCrashScenario.swift new file mode 100644 index 000000000..d3b6168e4 --- /dev/null +++ b/features/fixtures/shared/scenarios/DispatchCrashScenario.swift @@ -0,0 +1,22 @@ +// +// DispatchCrashScenario.swift +// iOSTestApp +// +// Created by Nick Dowell on 17/12/2020. +// Copyright © 2020 Bugsnag. All rights reserved. +// + +class DispatchCrashScenario: Scenario { + + override func startBugsnag() { + config.autoTrackSessions = false + super.startBugsnag() + } + + override func run() { + precondition(Thread.isMainThread) + DispatchQueue.main.sync { + print("This code will never run because DispatchQueue.main.sync was called on the main thread") + } + } +}