diff --git a/Bugsnag.xcodeproj/project.pbxproj b/Bugsnag.xcodeproj/project.pbxproj index cb11b3ac4..b569d5367 100644 --- a/Bugsnag.xcodeproj/project.pbxproj +++ b/Bugsnag.xcodeproj/project.pbxproj @@ -696,6 +696,9 @@ 01B14C57251CE55F00118748 /* report-react-native-promise-rejection.json in Resources */ = {isa = PBXBuildFile; fileRef = 01B14C55251CE55F00118748 /* report-react-native-promise-rejection.json */; }; 01B14C58251CE55F00118748 /* report-react-native-promise-rejection.json in Resources */ = {isa = PBXBuildFile; fileRef = 01B14C55251CE55F00118748 /* report-react-native-promise-rejection.json */; }; 01B6BB7E25D5777F00FC4DE6 /* BugsnagSwiftPublicAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 008966B02486D43500DC48C2 /* BugsnagSwiftPublicAPITests.swift */; }; + 01B74E9C27903326004B9765 /* BSG_KSFileTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01B74E9B27903326004B9765 /* BSG_KSFileTests.m */; }; + 01B74E9D27903326004B9765 /* BSG_KSFileTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01B74E9B27903326004B9765 /* BSG_KSFileTests.m */; }; + 01B74E9E27903326004B9765 /* BSG_KSFileTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01B74E9B27903326004B9765 /* BSG_KSFileTests.m */; }; 01B79DA9267CC4A000C8CC5E /* BSGUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 01B79DA7267CC4A000C8CC5E /* BSGUtils.h */; }; 01B79DAA267CC4A000C8CC5E /* BSGUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 01B79DA7267CC4A000C8CC5E /* BSGUtils.h */; }; 01B79DAB267CC4A000C8CC5E /* BSGUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 01B79DA7267CC4A000C8CC5E /* BSGUtils.h */; }; @@ -712,6 +715,13 @@ 01C17AE72542ED7F00C102C9 /* KSCrashReportWriterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01C17AE62542ED7F00C102C9 /* KSCrashReportWriterTests.m */; }; 01C17AE82542ED7F00C102C9 /* KSCrashReportWriterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01C17AE62542ED7F00C102C9 /* KSCrashReportWriterTests.m */; }; 01C17AE92542ED7F00C102C9 /* KSCrashReportWriterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01C17AE62542ED7F00C102C9 /* KSCrashReportWriterTests.m */; }; + 01CB95BF278F0C830077744A /* BSG_KSFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 01CB95BD278F0C830077744A /* BSG_KSFile.h */; }; + 01CB95C0278F0C830077744A /* BSG_KSFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 01CB95BD278F0C830077744A /* BSG_KSFile.h */; }; + 01CB95C1278F0C830077744A /* BSG_KSFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 01CB95BD278F0C830077744A /* BSG_KSFile.h */; }; + 01CB95C2278F0C830077744A /* BSG_KSFile.c in Sources */ = {isa = PBXBuildFile; fileRef = 01CB95BE278F0C830077744A /* BSG_KSFile.c */; }; + 01CB95C3278F0C830077744A /* BSG_KSFile.c in Sources */ = {isa = PBXBuildFile; fileRef = 01CB95BE278F0C830077744A /* BSG_KSFile.c */; }; + 01CB95C4278F0C830077744A /* BSG_KSFile.c in Sources */ = {isa = PBXBuildFile; fileRef = 01CB95BE278F0C830077744A /* BSG_KSFile.c */; }; + 01CB95C5278F0C830077744A /* BSG_KSFile.c in Sources */ = {isa = PBXBuildFile; fileRef = 01CB95BE278F0C830077744A /* BSG_KSFile.c */; }; 01CCAEEA25D414D60057268D /* BugsnagLastRunInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 01CCAEE825D414D60057268D /* BugsnagLastRunInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; 01CCAEEB25D414D60057268D /* BugsnagLastRunInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 01CCAEE825D414D60057268D /* BugsnagLastRunInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; 01CCAEEC25D414D60057268D /* BugsnagLastRunInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 01CCAEE825D414D60057268D /* BugsnagLastRunInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1378,6 +1388,7 @@ 01A617842733D15C00024A0B /* BugsnagNetworkRequestPlugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BugsnagNetworkRequestPlugin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 01ABD8782786DF9A009A5CA2 /* BSG_KSCrashReportTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BSG_KSCrashReportTests.m; sourceTree = ""; }; 01B14C55251CE55F00118748 /* report-react-native-promise-rejection.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "report-react-native-promise-rejection.json"; sourceTree = ""; }; + 01B74E9B27903326004B9765 /* BSG_KSFileTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BSG_KSFileTests.m; sourceTree = ""; }; 01B79DA7267CC4A000C8CC5E /* BSGUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BSGUtils.h; sourceTree = ""; }; 01B79DA8267CC4A000C8CC5E /* BSGUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BSGUtils.m; sourceTree = ""; }; 01BDB1CE25DEBF4600A91FAF /* BSGEventUploadKSCrashReportOperationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BSGEventUploadKSCrashReportOperationTests.m; sourceTree = ""; }; @@ -1385,6 +1396,8 @@ 01C17AE62542ED7F00C102C9 /* KSCrashReportWriterTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KSCrashReportWriterTests.m; sourceTree = ""; }; 01C2769B2601F44D006901EA /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = ""; }; 01C2769C2601F455006901EA /* CONTRIBUTING.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CONTRIBUTING.md; sourceTree = ""; }; + 01CB95BD278F0C830077744A /* BSG_KSFile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BSG_KSFile.h; sourceTree = ""; }; + 01CB95BE278F0C830077744A /* BSG_KSFile.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = BSG_KSFile.c; sourceTree = ""; }; 01CCAEE825D414D60057268D /* BugsnagLastRunInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BugsnagLastRunInfo.h; sourceTree = ""; }; 01CCAEE925D414D60057268D /* BugsnagLastRunInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BugsnagLastRunInfo.m; sourceTree = ""; }; 01CCAEFF25D4151C0057268D /* BugsnagLastRunInfo+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BugsnagLastRunInfo+Private.h"; sourceTree = ""; }; @@ -1535,6 +1548,7 @@ isa = PBXGroup; children = ( 01ABD8782786DF9A009A5CA2 /* BSG_KSCrashReportTests.m */, + 01B74E9B27903326004B9765 /* BSG_KSFileTests.m */, 008966D82486D43700DC48C2 /* BSG_KSMachHeadersTests.m */, 008966EA2486D43700DC48C2 /* BSG_KSMachTests.m */, 008966D62486D43700DC48C2 /* FileBasedTestCase.h */, @@ -1628,6 +1642,8 @@ 008969292486DAD000DC48C2 /* BSG_KSCrashState.m */, 0089692B2486DAD000DC48C2 /* BSG_KSCrashType.c */, 008969482486DAD000DC48C2 /* BSG_KSCrashType.h */, + 01CB95BE278F0C830077744A /* BSG_KSFile.c */, + 01CB95BD278F0C830077744A /* BSG_KSFile.h */, 0089692F2486DAD000DC48C2 /* BSG_KSSystemInfo.h */, 0089694C2486DAD000DC48C2 /* BSG_KSSystemInfo.m */, 008969312486DAD000DC48C2 /* BSG_KSSystemInfoC.h */, @@ -2146,6 +2162,7 @@ 010FF28425ED2A8D00E4F2B0 /* BSGAppHangDetector.h in Headers */, 008967F42486DA4500DC48C2 /* BSGSessionUploader.h in Headers */, 0126DF1B257A92860031A70C /* BugsnagSession+Private.h in Headers */, + 01CB95BF278F0C830077744A /* BSG_KSFile.h in Headers */, 008969E12486DAD100DC48C2 /* BSG_KSSystemInfo.h in Headers */, 00896A0E2486DAD100DC48C2 /* BSG_KSCrashSentry.h in Headers */, 008969D22486DAD100DC48C2 /* BSG_KSCrashContext.h in Headers */, @@ -2252,6 +2269,7 @@ 008967F52486DA4500DC48C2 /* BSGSessionUploader.h in Headers */, 010FF28525ED2A8D00E4F2B0 /* BSGAppHangDetector.h in Headers */, 008969E22486DAD100DC48C2 /* BSG_KSSystemInfo.h in Headers */, + 01CB95C0278F0C830077744A /* BSG_KSFile.h in Headers */, 0126DF1C257A92860031A70C /* BugsnagSession+Private.h in Headers */, 00896A0F2486DAD100DC48C2 /* BSG_KSCrashSentry.h in Headers */, 008969D32486DAD100DC48C2 /* BSG_KSCrashContext.h in Headers */, @@ -2358,6 +2376,7 @@ 008967F62486DA4500DC48C2 /* BSGSessionUploader.h in Headers */, 010FF28625ED2A8D00E4F2B0 /* BSGAppHangDetector.h in Headers */, 008969E32486DAD100DC48C2 /* BSG_KSSystemInfo.h in Headers */, + 01CB95C1278F0C830077744A /* BSG_KSFile.h in Headers */, 0126DF1D257A92860031A70C /* BugsnagSession+Private.h in Headers */, 00896A102486DAD100DC48C2 /* BSG_KSCrashSentry.h in Headers */, 008969D42486DAD100DC48C2 /* BSG_KSCrashContext.h in Headers */, @@ -2741,6 +2760,7 @@ 01840B7225DC26E200F95648 /* BSGEventUploader.m in Sources */, 008968C32486DA9600DC48C2 /* BugsnagUser.m in Sources */, CBAB4DD82510D2460092CBAA /* BugsnagKVStoreObjC.m in Sources */, + 01CB95C2278F0C830077744A /* BSG_KSFile.c in Sources */, 008968A72486DA9600DC48C2 /* BugsnagSession.m in Sources */, 0089683A2486DA6C00DC48C2 /* BugsnagMetadata.m in Sources */, 013D9CD426C5262F0077F0AD /* UISceneStub.m in Sources */, @@ -2844,6 +2864,7 @@ 008967752486D43700DC48C2 /* XCTestCase+KSCrash.m in Sources */, CB9103642502320A00E9D1E2 /* BugsnagApiClientTest.m in Sources */, 008967602486D43700DC48C2 /* BugsnagBreadcrumbsTest.m in Sources */, + 01B74E9C27903326004B9765 /* BSG_KSFileTests.m in Sources */, CB10E53F250BA8DE00AF5824 /* BugsnagKVStoreTest.m in Sources */, CB6419AB25A73E8C00613D25 /* BSGStorageMigratorTests.m in Sources */, E701FAA72490EF77008D842F /* ClientApiValidationTest.m in Sources */, @@ -2898,6 +2919,7 @@ 008968BA2486DA9600DC48C2 /* BugsnagStacktrace.m in Sources */, 00896A152486DAD100DC48C2 /* BSG_KSCrashSentry_Signal.c in Sources */, 01468F5625876DC1002B0519 /* BSGNotificationBreadcrumbs.m in Sources */, + 01CB95C3278F0C830077744A /* BSG_KSFile.c in Sources */, 008967BF2486DA1900DC48C2 /* BugsnagClient.m in Sources */, 008968962486DA9600DC48C2 /* BugsnagHandledState.m in Sources */, 008969C42486DAD100DC48C2 /* BSG_KSObjC.c in Sources */, @@ -3009,6 +3031,7 @@ 008967A02486D43700DC48C2 /* KSCrashSentry_Tests.m in Sources */, 008967432486D43700DC48C2 /* BugsnagSessionTrackerStopTest.m in Sources */, 008967972486D43700DC48C2 /* KSCrashState_Tests.m in Sources */, + 01B74E9D27903326004B9765 /* BSG_KSFileTests.m in Sources */, 008967762486D43700DC48C2 /* XCTestCase+KSCrash.m in Sources */, 01E8765F256684E700F4B70A /* URLSessionMock.m in Sources */, 008967312486D43700DC48C2 /* BSGClientObserverTests.m in Sources */, @@ -3088,6 +3111,7 @@ 01840B7425DC26E200F95648 /* BSGEventUploader.m in Sources */, 008968C52486DA9600DC48C2 /* BugsnagUser.m in Sources */, CBAB4DDA2510D2460092CBAA /* BugsnagKVStoreObjC.m in Sources */, + 01CB95C4278F0C830077744A /* BSG_KSFile.c in Sources */, 008968A92486DA9600DC48C2 /* BugsnagSession.m in Sources */, 0089683C2486DA6C00DC48C2 /* BugsnagMetadata.m in Sources */, 013D9CD626C5262F0077F0AD /* UISceneStub.m in Sources */, @@ -3182,6 +3206,7 @@ 008967322486D43700DC48C2 /* BSGClientObserverTests.m in Sources */, CBA2249D251E429C00B87416 /* TestSupport.m in Sources */, 01847DAE26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m in Sources */, + 01B74E9E27903326004B9765 /* BSG_KSFileTests.m in Sources */, 004E35372487AFF2007FBAE4 /* BugsnagHandledStateTest.m in Sources */, 016875C8258D003200DFFF69 /* NSUserDefaultsStub.m in Sources */, 01935AE3275E68E9007498B3 /* UIApplicationStub.m in Sources */, @@ -3261,6 +3286,7 @@ 008967DD2486DA2D00DC48C2 /* BugsnagConfiguration.m in Sources */, 008968E42486DAA700DC48C2 /* BugsnagPluginClient.m in Sources */, 01840B7525DC26E200F95648 /* BSGEventUploader.m in Sources */, + 01CB95C5278F0C830077744A /* BSG_KSFile.c in Sources */, 008968BC2486DA9600DC48C2 /* BugsnagStacktrace.m in Sources */, 008968242486DA5600DC48C2 /* BugsnagKeys.m in Sources */, 008967B72486D9D800DC48C2 /* BugsnagBreadcrumbs.m in Sources */, diff --git a/Bugsnag.xcodeproj/xcshareddata/xcbaselines/00AD1C7A24869B0E00A27979.xcbaseline/B9A70F85-2A05-489B-A5BA-1129C478B0A1.plist b/Bugsnag.xcodeproj/xcshareddata/xcbaselines/00AD1C7A24869B0E00A27979.xcbaseline/B9A70F85-2A05-489B-A5BA-1129C478B0A1.plist index e066634d3..b7e07688b 100644 --- a/Bugsnag.xcodeproj/xcshareddata/xcbaselines/00AD1C7A24869B0E00A27979.xcbaseline/B9A70F85-2A05-489B-A5BA-1129C478B0A1.plist +++ b/Bugsnag.xcodeproj/xcshareddata/xcbaselines/00AD1C7A24869B0E00A27979.xcbaseline/B9A70F85-2A05-489B-A5BA-1129C478B0A1.plist @@ -11,7 +11,7 @@ com.apple.XCTPerformanceMetric_WallClockTime baselineAverage - 0.065700 + 0.034600 baselineIntegrationDisplayName Local Baseline diff --git a/Bugsnag.xcodeproj/xcshareddata/xcbaselines/00AD1C7A24869B0E00A27979.xcbaseline/D90C8D39-16DA-4CCB-8283-66F4A3B10BA2.plist b/Bugsnag.xcodeproj/xcshareddata/xcbaselines/00AD1C7A24869B0E00A27979.xcbaseline/D90C8D39-16DA-4CCB-8283-66F4A3B10BA2.plist index 6406c2649..8f62ee943 100644 --- a/Bugsnag.xcodeproj/xcshareddata/xcbaselines/00AD1C7A24869B0E00A27979.xcbaseline/D90C8D39-16DA-4CCB-8283-66F4A3B10BA2.plist +++ b/Bugsnag.xcodeproj/xcshareddata/xcbaselines/00AD1C7A24869B0E00A27979.xcbaseline/D90C8D39-16DA-4CCB-8283-66F4A3B10BA2.plist @@ -11,7 +11,7 @@ com.apple.XCTPerformanceMetric_WallClockTime baselineAverage - 0.468000 + 0.195000 baselineIntegrationDisplayName Local Baseline diff --git a/Bugsnag.xcodeproj/xcshareddata/xcbaselines/00AD1CB424869C1200A27979.xcbaseline/7E1A1286-DD8C-4E45-9E88-4335CD976176.plist b/Bugsnag.xcodeproj/xcshareddata/xcbaselines/00AD1CB424869C1200A27979.xcbaseline/7E1A1286-DD8C-4E45-9E88-4335CD976176.plist index abeac13f9..ee9597963 100644 --- a/Bugsnag.xcodeproj/xcshareddata/xcbaselines/00AD1CB424869C1200A27979.xcbaseline/7E1A1286-DD8C-4E45-9E88-4335CD976176.plist +++ b/Bugsnag.xcodeproj/xcshareddata/xcbaselines/00AD1CB424869C1200A27979.xcbaseline/7E1A1286-DD8C-4E45-9E88-4335CD976176.plist @@ -11,7 +11,7 @@ com.apple.XCTPerformanceMetric_WallClockTime baselineAverage - 0.091900 + 0.042200 baselineIntegrationDisplayName Local Baseline diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c index fa8b1d60e..092e3f56e 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c @@ -29,6 +29,7 @@ #include "BSG_KSBacktrace_Private.h" #include "BSG_KSCrashReportFields.h" #include "BSG_KSCrashReportVersion.h" +#include "BSG_KSFile.h" #include "BSG_KSFileUtils.h" #include "BSG_KSJSONCodec.h" #include "BSG_KSMach.h" @@ -308,8 +309,7 @@ void bsg_kscrw_i_endContainer(const BSG_KSCrashReportWriter *const writer) { int bsg_kscrw_i_addJSONData(const char *const data, const size_t length, void *const userData) { - const int fd = *((int *)userData); - const bool success = bsg_ksfuwriteBytesToFD(fd, data, (ssize_t)length); + bool success = BSG_KSFileWrite(userData, data, length); return success ? BSG_KSJSON_OK : BSG_KSJSON_ERROR_CANNOT_ADD_DATA; } @@ -1502,14 +1502,18 @@ void bsg_kscrashreport_writeMinimalReport( bsg_kscrw_i_updateStackOverflowStatus(crashContext); + BSG_KSFile file; + char buffer[512]; + BSG_KSFileInit(&file, fd, buffer, sizeof(buffer) / sizeof(*buffer)); + BSG_KSJSONEncodeContext jsonContext; - jsonContext.userData = &fd; + jsonContext.userData = &file; BSG_KSCrashReportWriter concreteWriter; BSG_KSCrashReportWriter *writer = &concreteWriter; bsg_kscrw_i_prepareReportWriter(writer, &jsonContext); bsg_ksjsonbeginEncode(bsg_getJsonContext(writer), false, - bsg_kscrw_i_addJSONData, &fd); + bsg_kscrw_i_addJSONData, &file); writer->beginObject(writer, BSG_KSCrashField_Report); { @@ -1541,6 +1545,7 @@ void bsg_kscrashreport_writeMinimalReport( bsg_ksjsonendEncode(bsg_getJsonContext(writer)); + BSG_KSFileFlush(&file); close(fd); } @@ -1557,14 +1562,18 @@ void bsg_kscrashreport_writeStandardReport( bsg_kscrw_i_updateStackOverflowStatus(crashContext); + BSG_KSFile file; + char buffer[4096]; + BSG_KSFileInit(&file, fd, buffer, sizeof(buffer) / sizeof(*buffer)); + BSG_KSJSONEncodeContext jsonContext; - jsonContext.userData = &fd; + jsonContext.userData = &file; BSG_KSCrashReportWriter concreteWriter; BSG_KSCrashReportWriter *writer = &concreteWriter; bsg_kscrw_i_prepareReportWriter(writer, &jsonContext); bsg_ksjsonbeginEncode(bsg_getJsonContext(writer), false, - bsg_kscrw_i_addJSONData, &fd); + bsg_kscrw_i_addJSONData, &file); writer->beginObject(writer, BSG_KSCrashField_Report); { @@ -1588,6 +1597,7 @@ void bsg_kscrashreport_writeStandardReport( bsg_ksjsonendEncode(bsg_getJsonContext(writer)); + BSG_KSFileFlush(&file); close(fd); } diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m index dff9b7231..3b96c6047 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m @@ -26,7 +26,7 @@ #include "BSG_KSCrashState.h" -#include "BSG_KSFileUtils.h" +#include "BSG_KSFile.h" #include "BSG_KSJSONCodec.h" #include "BSG_KSJSONCodecObjC.h" #include "BSG_KSMach.h" @@ -154,8 +154,7 @@ int bsg_kscrashstate_i_onEndData(__unused void *const userData) { */ int bsg_kscrashstate_i_addJSONData(const char *const data, const size_t length, void *const userData) { - const int fd = *((int *)userData); - const bool success = bsg_ksfuwriteBytesToFD(fd, data, (ssize_t)length); + bool success = BSG_KSFileWrite(userData, data, length); return success ? BSG_KSJSON_OK : BSG_KSJSON_ERROR_CANNOT_ADD_DATA; } @@ -227,9 +226,13 @@ bool bsg_kscrashstate_i_saveState(const BSG_KSCrash_State *const state, return false; } + BSG_KSFile file; + char buffer[256]; + BSG_KSFileInit(&file, fd, buffer, sizeof(buffer) / sizeof(*buffer)); + BSG_KSJSONEncodeContext JSONContext; bsg_ksjsonbeginEncode(&JSONContext, false, bsg_kscrashstate_i_addJSONData, - &fd); + &file); int result; if ((result = bsg_ksjsonbeginObject(&JSONContext, NULL)) != BSG_KSJSON_OK) { @@ -269,6 +272,7 @@ bool bsg_kscrashstate_i_saveState(const BSG_KSCrash_State *const state, result = bsg_ksjsonendEncode(&JSONContext); done: + BSG_KSFileFlush(&file); close(fd); if (result != BSG_KSJSON_OK) { diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSFile.c b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSFile.c new file mode 100644 index 000000000..353fc201e --- /dev/null +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSFile.c @@ -0,0 +1,59 @@ +// +// BSG_KSFile.c +// Bugsnag +// +// Created by Nick Dowell on 12/01/2022. +// Copyright © 2022 Bugsnag Inc. All rights reserved. +// + +#include "BSG_KSFile.h" + +#include "BSG_KSFileUtils.h" + +#include +#include + +static inline bool bsg_write(const int fd, const char *bytes, size_t length) { + return bsg_ksfuwriteBytesToFD(fd, bytes, (ssize_t)length); +} + +void BSG_KSFileInit(BSG_KSFile *file, int fd, char *buffer, size_t length) { + file->fd = fd; + file->buffer = buffer; + file->bufferSize = length; + file->bufferUsed = 0; +} + +bool BSG_KSFileWrite(BSG_KSFile *file, const char *data, size_t length) { + const size_t bytesCopied = MIN(file->bufferSize - file->bufferUsed, length); + memcpy(file->buffer + file->bufferUsed, data, bytesCopied); + file->bufferUsed += bytesCopied; + data += bytesCopied; + length -= bytesCopied; + + if (file->bufferUsed == file->bufferSize) { + if (!BSG_KSFileFlush(file)) { + return false; + } + } + + if (!length) { + return true; + } + + if (length >= file->bufferSize) { + return bsg_write(file->fd, data, length); + } + + memcpy(file->buffer, data, length); + file->bufferUsed = length; + return true; +} + +bool BSG_KSFileFlush(BSG_KSFile *file) { + if (!bsg_write(file->fd, file->buffer, file->bufferUsed)) { + return false; + } + file->bufferUsed = 0; + return true; +} diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSFile.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSFile.h new file mode 100644 index 000000000..96f0306fa --- /dev/null +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSFile.h @@ -0,0 +1,25 @@ +// +// BSG_KSFile.h +// Bugsnag +// +// Created by Nick Dowell on 12/01/2022. +// Copyright © 2022 Bugsnag Inc. All rights reserved. +// + +#pragma once + +#include +#include + +typedef struct { + int fd; + char *buffer; + size_t bufferSize; + size_t bufferUsed; +} BSG_KSFile; + +void BSG_KSFileInit(BSG_KSFile *file, int fd, char *buffer, size_t length); + +bool BSG_KSFileWrite(BSG_KSFile *file, const char *data, size_t length); + +bool BSG_KSFileFlush(BSG_KSFile *file); diff --git a/CHANGELOG.md b/CHANGELOG.md index 13b65c155..4592612e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ Changelog ========= +## TBD + +### Bug fixes + +* Improve crash report writing performance with buffered output. + [#1281](https://github.com/bugsnag/bugsnag-cocoa/pull/1281) + ## 6.16.0 (2022-01-12) ### Enhancements diff --git a/Tests/KSCrashTests/BSG_KSCrashReportTests.m b/Tests/KSCrashTests/BSG_KSCrashReportTests.m index ebe9887f3..d24a466c8 100644 --- a/Tests/KSCrashTests/BSG_KSCrashReportTests.m +++ b/Tests/KSCrashTests/BSG_KSCrashReportTests.m @@ -22,10 +22,9 @@ @interface BSG_KSCrashReportTests : XCTestCase @implementation BSG_KSCrashReportTests - (void)testBinaryImages { - NSString *directory = NSTemporaryDirectory(); - NSString *crashReportFilePath = [directory stringByAppendingPathComponent:@"crash_report"]; - NSString *recrashReportFilePath = [directory stringByAppendingPathComponent:@"recrash_report"]; - NSString *stateFilePath = [directory stringByAppendingPathComponent:@"kscrash_state"]; + NSString *crashReportFilePath = [self temporaryFile:@"crash_report.json"]; + NSString *recrashReportFilePath = [self temporaryFile:@"recrash_report"]; + NSString *stateFilePath = [self temporaryFile:@"kscrash_state"]; NSString *crashID = [[NSUUID UUID] UUIDString]; bsg_kscrash_init(); @@ -62,17 +61,12 @@ - (void)testBinaryImages { [backtraceImageAddrs removeObject:[NSNull null]]; XCTAssertEqualObjects(binaryImageAddrs, backtraceImageAddrs); - - [[NSFileManager defaultManager] removeItemAtPath:crashReportFilePath error:nil]; - [[NSFileManager defaultManager] removeItemAtPath:recrashReportFilePath error:nil]; - [[NSFileManager defaultManager] removeItemAtPath:stateFilePath error:nil]; } - (void)testWriteStandardReportPerformance { - NSString *directory = NSTemporaryDirectory(); - NSString *crashReportFilePath = [directory stringByAppendingPathComponent:@"crash_report"]; - NSString *recrashReportFilePath = [directory stringByAppendingPathComponent:@"recrash_report"]; - NSString *stateFilePath = [directory stringByAppendingPathComponent:@"kscrash_state"]; + NSString *crashReportFilePath = [self temporaryFile:@"crash_report"]; + NSString *recrashReportFilePath = [self temporaryFile:@"recrash_report"]; + NSString *stateFilePath = [self temporaryFile:@"kscrash_state"]; NSString *crashID = [[NSUUID UUID] UUIDString]; bsg_kscrash_init(); @@ -111,11 +105,19 @@ - (void)testWriteStandardReportPerformance { } [self stopMeasuring]; + NSDictionary *report = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:crashReportFilePath] options:0 error:nil]; + XCTAssert([report isKindOfClass:[NSDictionary class]], @"%@", report); [[NSFileManager defaultManager] removeItemAtPath:crashReportFilePath error:nil]; }]; - - [[NSFileManager defaultManager] removeItemAtPath:recrashReportFilePath error:nil]; - [[NSFileManager defaultManager] removeItemAtPath:stateFilePath error:nil]; +} + +- (NSString *)temporaryFile:(NSString *)fileName { + NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName]; + [[NSFileManager defaultManager] removeItemAtPath:path error:nil]; + [self addTeardownBlock:^{ + [[NSFileManager defaultManager] removeItemAtPath:path error:nil]; + }]; + return path; } @end diff --git a/Tests/KSCrashTests/BSG_KSFileTests.m b/Tests/KSCrashTests/BSG_KSFileTests.m new file mode 100644 index 000000000..622563519 --- /dev/null +++ b/Tests/KSCrashTests/BSG_KSFileTests.m @@ -0,0 +1,64 @@ +// +// BSG_KSFileTests.m +// Bugsnag +// +// Created by Nick Dowell on 13/01/2022. +// Copyright © 2022 Bugsnag Inc. All rights reserved. +// + +#import + +#import "BSG_KSFile.h" + +@interface BSG_KSFileTests : XCTestCase + +@property NSString *filePath; +@property int fileDescriptor; + +@end + +@implementation BSG_KSFileTests + +- (void)setUp { + self.filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[self description]]; + self.fileDescriptor = open(self.filePath.fileSystemRepresentation, O_RDWR | O_CREAT | O_EXCL, 0644); +} + +- (void)tearDown { + close(self.fileDescriptor); + unlink(self.filePath.fileSystemRepresentation); +} + +- (void)testFileWrite { + BSG_KSFile file; + const size_t bufferSize = 8; + char buffer[bufferSize]; + + BSG_KSFileInit(&file, self.fileDescriptor, buffer, bufferSize); + XCTAssertEqual(file.bufferSize, bufferSize); + XCTAssertEqual(file.bufferUsed, 0); + + BSG_KSFileWrite(&file, "Someone", 7); + XCTAssertEqual(file.bufferUsed, 7, @"The buffer should not be flushed until filled"); + BSG_KSFileWrite(&file, " ", 1); + XCTAssertEqual(file.bufferUsed, 0, @"The buffer should be flushed once filled"); + + BSG_KSFileWrite(&file, "says", 4); + BSG_KSFileWrite(&file, ": ", 2); + XCTAssertEqual(file.bufferUsed, 6, @"The buffer should not be flushed until filled"); + + BSG_KSFileWrite(&file, "Hello, ", 7); + XCTAssertEqual(file.bufferUsed, (6 + 7) % bufferSize); + + BSG_KSFileWrite(&file, "Supercalifragilisticexpialidocious", 34); + XCTAssertEqual(file.bufferUsed, 0, @"Large writes should flush the buffer and leave it empty"); + + BSG_KSFileFlush(&file); + XCTAssertEqualObjects([self fileContentsAsString], @"Someone says: Hello, Supercalifragilisticexpialidocious"); +} + +- (NSString *)fileContentsAsString { + return [NSString stringWithContentsOfFile:self.filePath encoding:NSUTF8StringEncoding error:nil]; +} + +@end diff --git a/Tests/KSCrashTests/KSCrashState_Tests.m b/Tests/KSCrashTests/KSCrashState_Tests.m index f269a41db..e659edbff 100755 --- a/Tests/KSCrashTests/KSCrashState_Tests.m +++ b/Tests/KSCrashTests/KSCrashState_Tests.m @@ -483,4 +483,20 @@ - (void)testBGFGCrash XCTAssertTrue(context.crashedLastLaunch, @""); } +- (void)testPersistence +{ + NSString *file = [self.tempPath stringByAppendingPathComponent:@"state.json"]; + + BSG_KSCrash_State state = {0}; + bsg_kscrashstate_init([file fileSystemRepresentation], &state); + + id json = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:file] options:0 error:nil]; + XCTAssertEqualObjects([json objectForKey:@"crashedLastLaunch"], @NO); + + bsg_kscrashstate_notifyAppCrash(); + + json = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:file] options:0 error:nil]; + XCTAssertEqualObjects([json objectForKey:@"crashedLastLaunch"], @YES); +} + @end