From 4251e539f3f58869302c4b345a883f8581fdbc5d Mon Sep 17 00:00:00 2001 From: Philip Niedertscheider Date: Fri, 13 Dec 2024 16:27:31 +0100 Subject: [PATCH 1/2] feat: rename strncpy to strlcpy; added tests --- Sentry.xcodeproj/project.pbxproj | 20 +- Sources/Sentry/SentryAsyncSafeLog.c | 2 +- .../SentryCrashMonitor_CPPException.cpp | 3 +- Sources/SentryCrash/Recording/SentryCrashC.c | 2 +- .../SentryCrash/Recording/SentryCrashReport.c | 4 +- .../Recording/SentryCrashReportFixer.c | 2 +- .../Recording/Tools/SentryCrashFileUtils.c | 2 +- .../Recording/Tools/SentryCrashJSONCodec.c | 3 +- .../Filters/Tools/SentryStringUtils.h | 29 --- .../Recording/SentryCrashCTests.swift | 212 ++++++++++++++++++ .../SentryCrash/SentryCrashFileUtils_Tests.m | 82 +++++++ .../SentryCrash/SentryStringUtils.swift | 31 --- .../SentryTests/SentryTests-Bridging-Header.h | 1 - 13 files changed, 314 insertions(+), 79 deletions(-) delete mode 100644 Sources/SentryCrash/Reporting/Filters/Tools/SentryStringUtils.h create mode 100644 Tests/SentryTests/Recording/SentryCrashCTests.swift delete mode 100644 Tests/SentryTests/SentryCrash/SentryStringUtils.swift diff --git a/Sentry.xcodeproj/project.pbxproj b/Sentry.xcodeproj/project.pbxproj index fad17aaa0dd..093a3c917b5 100644 --- a/Sentry.xcodeproj/project.pbxproj +++ b/Sentry.xcodeproj/project.pbxproj @@ -780,6 +780,7 @@ A8AFFCD42907E0CA00967CD7 /* SentryRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8AFFCD32907E0CA00967CD7 /* SentryRequestTests.swift */; }; A8F17B2E2901765900990B25 /* SentryRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = A8F17B2D2901765900990B25 /* SentryRequest.m */; }; A8F17B342902870300990B25 /* SentryHttpStatusCodeRange.m in Sources */ = {isa = PBXBuildFile; fileRef = A8F17B332902870300990B25 /* SentryHttpStatusCodeRange.m */; }; + D4F2B5352D0C69D500649E42 /* SentryCrashCTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4F2B5342D0C69D100649E42 /* SentryCrashCTests.swift */; }; D8019910286B089000C277F0 /* SentryCrashReportSinkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D801990F286B089000C277F0 /* SentryCrashReportSinkTests.swift */; }; D802994E2BA836EF000F0081 /* SentryOnDemandReplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = D802994D2BA836EF000F0081 /* SentryOnDemandReplay.swift */; }; D80299502BA83A88000F0081 /* SentryPixelBuffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D802994F2BA83A88000F0081 /* SentryPixelBuffer.swift */; }; @@ -828,8 +829,6 @@ D84DAD5A2B1742C1003CF120 /* SentryTestUtilsDynamic.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D84DAD4D2B17428D003CF120 /* SentryTestUtilsDynamic.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; D84F833D2A1CC401005828E0 /* SentrySwiftAsyncIntegration.h in Headers */ = {isa = PBXBuildFile; fileRef = D84F833B2A1CC401005828E0 /* SentrySwiftAsyncIntegration.h */; }; D84F833E2A1CC401005828E0 /* SentrySwiftAsyncIntegration.m in Sources */ = {isa = PBXBuildFile; fileRef = D84F833C2A1CC401005828E0 /* SentrySwiftAsyncIntegration.m */; }; - D851527F2C9971020070F669 /* SentryStringUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = D851527E2C9971020070F669 /* SentryStringUtils.h */; }; - D85152832C997A280070F669 /* SentryStringUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D85152822C997A1F0070F669 /* SentryStringUtils.swift */; }; D85153002CA2B5F60070F669 /* SentrySwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8199DAA29376E9B0074249E /* SentrySwiftUI.framework */; }; D85153012CA2B5F60070F669 /* SentrySwiftUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D8199DAA29376E9B0074249E /* SentrySwiftUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; D851530C2CA2B7B00070F669 /* SentryRedactModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D851530B2CA2B7A30070F669 /* SentryRedactModifierTests.swift */; }; @@ -1855,6 +1854,7 @@ A8AFFCD32907E0CA00967CD7 /* SentryRequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryRequestTests.swift; sourceTree = ""; }; A8F17B2D2901765900990B25 /* SentryRequest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryRequest.m; sourceTree = ""; }; A8F17B332902870300990B25 /* SentryHttpStatusCodeRange.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryHttpStatusCodeRange.m; sourceTree = ""; }; + D4F2B5342D0C69D100649E42 /* SentryCrashCTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryCrashCTests.swift; sourceTree = ""; }; D800942628F82F3A005D3943 /* SwiftDescriptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftDescriptor.swift; sourceTree = ""; }; D801990F286B089000C277F0 /* SentryCrashReportSinkTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryCrashReportSinkTests.swift; sourceTree = ""; }; D802994D2BA836EF000F0081 /* SentryOnDemandReplay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryOnDemandReplay.swift; sourceTree = ""; }; @@ -1907,8 +1907,6 @@ D84F833B2A1CC401005828E0 /* SentrySwiftAsyncIntegration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentrySwiftAsyncIntegration.h; path = include/SentrySwiftAsyncIntegration.h; sourceTree = ""; }; D84F833C2A1CC401005828E0 /* SentrySwiftAsyncIntegration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentrySwiftAsyncIntegration.m; sourceTree = ""; }; D8511F722BAC8F750015E6FD /* Sentry.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = Sentry.modulemap; sourceTree = ""; }; - D851527E2C9971020070F669 /* SentryStringUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SentryStringUtils.h; sourceTree = ""; }; - D85152822C997A1F0070F669 /* SentryStringUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryStringUtils.swift; sourceTree = ""; }; D851530B2CA2B7A30070F669 /* SentryRedactModifierTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryRedactModifierTests.swift; sourceTree = ""; }; D85596F1280580F10041FF8B /* SentryScreenshotIntegration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryScreenshotIntegration.m; sourceTree = ""; }; D855AD61286ED6A4002573E1 /* SentryCrashTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryCrashTests.m; sourceTree = ""; }; @@ -2503,6 +2501,7 @@ 63AA75931EB8AEDB00D153DE /* SentryTests */ = { isa = PBXGroup; children = ( + D4F2B5332D0C69CC00649E42 /* Recording */, 62872B602BA1B84400A4FA7D /* Swift */, 7B3878E92490D90400EBDEA2 /* SentryClient+TestInit.h */, D8BC83BA2AFCF08C00A662B7 /* SentryUIApplication+Private.h */, @@ -2651,7 +2650,6 @@ 63FE6FC120DA4C1000CDBAE8 /* SentryCrashVarArgs.h */, 63FE6FBF20DA4C1000CDBAE8 /* SentryDictionaryDeepSearch.h */, 63FE6FBD20DA4C1000CDBAE8 /* SentryDictionaryDeepSearch.m */, - D851527E2C9971020070F669 /* SentryStringUtils.h */, ); path = Tools; sourceTree = ""; @@ -2833,7 +2831,6 @@ 0ADC33EF28D9BE690078D980 /* TestSentryUIDeviceWrapper.swift */, 7B984A9E28E572AF001F4BEE /* CrashReport.swift */, 7BF69E062987D1FE002EBCA4 /* SentryCrashDoctorTests.swift */, - D85152822C997A1F0070F669 /* SentryStringUtils.swift */, ); path = SentryCrash; sourceTree = ""; @@ -3614,6 +3611,14 @@ name = Transaction; sourceTree = ""; }; + D4F2B5332D0C69CC00649E42 /* Recording */ = { + isa = PBXGroup; + children = ( + D4F2B5342D0C69D100649E42 /* SentryCrashCTests.swift */, + ); + path = Recording; + sourceTree = ""; + }; D800942328F82E8D005D3943 /* Swift */ = { isa = PBXGroup; children = ( @@ -4195,7 +4200,6 @@ 7B0DC72F288698F70039995F /* NSMutableDictionary+Sentry.h in Headers */, 63FE713920DA4C1100CDBAE8 /* SentryCrashMach.h in Headers */, 63EED6BE2237923600E02400 /* SentryOptions.h in Headers */, - D851527F2C9971020070F669 /* SentryStringUtils.h in Headers */, 7BD86EC5264A63F6005439DB /* SentrySysctl.h in Headers */, 63BE85701ECEC6DE00DC44F5 /* SentryDateUtils.h in Headers */, 63FE709520DA4C1000CDBAE8 /* SentryCrashReportFilterBasic.h in Headers */, @@ -4936,6 +4940,7 @@ 7B2A70DF27D60904008B0D15 /* SentryTestThreadWrapper.swift in Sources */, 62F4DDA12C04CB9700588890 /* SentryBaggageSerializationTests.swift in Sources */, 7BE912AF272166DD00E49E62 /* SentryNoOpSpanTests.swift in Sources */, + D4F2B5352D0C69D500649E42 /* SentryCrashCTests.swift in Sources */, 7B56D73524616E5600B842DA /* SentryConcurrentRateLimitsDictionaryTests.swift in Sources */, 7B7D8730248648AD00D2ECFF /* SentryStacktraceBuilderTests.swift in Sources */, 62E081AB29ED4322000F69FC /* SentryBreadcrumbTestDelegate.swift in Sources */, @@ -4953,7 +4958,6 @@ 7BA61CCF247EB59500C130A8 /* SentryCrashUUIDConversionTests.swift in Sources */, 7BBD188D2448453600427C76 /* SentryHttpDateParserTests.swift in Sources */, 7B72D23A28D074BC0014798A /* TestExtensions.swift in Sources */, - D85152832C997A280070F669 /* SentryStringUtils.swift in Sources */, 7BBD18BB24530D2600427C76 /* SentryFileManagerTests.swift in Sources */, 63FE722020DA66EC00CDBAE8 /* SentryCrashObjC_Tests.m in Sources */, 7B58816727FC5D790098B121 /* SentryDiscardReasonMapperTests.swift in Sources */, diff --git a/Sources/Sentry/SentryAsyncSafeLog.c b/Sources/Sentry/SentryAsyncSafeLog.c index c720f1019f4..5c9594eeb4d 100644 --- a/Sources/Sentry/SentryAsyncSafeLog.c +++ b/Sources/Sentry/SentryAsyncSafeLog.c @@ -140,7 +140,7 @@ sentry_asyncLogSetFileName(const char *filename, bool overwrite) fd = open(filename, openMask, 0644); unlikely_if(fd < 0) { return 1; } if (filename != g_logFilename) { - strncpy(g_logFilename, filename, sizeof(g_logFilename)); + strlcpy(g_logFilename, filename, sizeof(g_logFilename)); } } diff --git a/Sources/SentryCrash/Recording/Monitors/SentryCrashMonitor_CPPException.cpp b/Sources/SentryCrash/Recording/Monitors/SentryCrashMonitor_CPPException.cpp index 2324995afa6..f0b9688e390 100644 --- a/Sources/SentryCrash/Recording/Monitors/SentryCrashMonitor_CPPException.cpp +++ b/Sources/SentryCrash/Recording/Monitors/SentryCrashMonitor_CPPException.cpp @@ -32,7 +32,6 @@ #include "SentryAsyncSafeLog.h" -#include "SentryStringUtils.h" #include #include #include @@ -161,7 +160,7 @@ CPPExceptionTerminate(void) try { throw; } catch (std::exception &exc) { - strncpy_safe(descriptionBuff, exc.what(), sizeof(descriptionBuff)); + strlcpy(descriptionBuff, exc.what(), sizeof(descriptionBuff)); } #define CATCH_VALUE(TYPE, PRINTFTYPE) \ catch (TYPE value) \ diff --git a/Sources/SentryCrash/Recording/SentryCrashC.c b/Sources/SentryCrash/Recording/SentryCrashC.c index 3944bb44738..116357fe63b 100644 --- a/Sources/SentryCrash/Recording/SentryCrashC.c +++ b/Sources/SentryCrash/Recording/SentryCrashC.c @@ -82,7 +82,7 @@ onCrash(struct SentryCrash_MonitorContext *monitorContext) } else { char crashReportFilePath[SentryCrashFU_MAX_PATH_LENGTH]; sentrycrashcrs_getNextCrashReportPath(crashReportFilePath); - strncpy(g_lastCrashReportFilePath, crashReportFilePath, sizeof(g_lastCrashReportFilePath)); + strlcpy(g_lastCrashReportFilePath, crashReportFilePath, sizeof(g_lastCrashReportFilePath)); sentrycrashreport_writeStandardReport(monitorContext, crashReportFilePath); sentrySessionReplaySync_writeInfo(); } diff --git a/Sources/SentryCrash/Recording/SentryCrashReport.c b/Sources/SentryCrash/Recording/SentryCrashReport.c index 7e842ed9143..e30891e816b 100644 --- a/Sources/SentryCrash/Recording/SentryCrashReport.c +++ b/Sources/SentryCrash/Recording/SentryCrashReport.c @@ -1474,8 +1474,8 @@ sentrycrashreport_writeRecrashReport( char writeBuffer[1024]; SentryCrashBufferedWriter bufferedWriter; static char tempPath[SentryCrashFU_MAX_PATH_LENGTH]; - strncpy(tempPath, path, sizeof(tempPath) - 10); - strncpy(tempPath + strlen(tempPath) - 5, ".old", 5); + strlcpy(tempPath, path, sizeof(tempPath) - 10); + strlcpy(tempPath + strlen(tempPath) - 5, ".old", 5); SENTRY_ASYNC_SAFE_LOG_INFO("Writing recrash report to %s", path); if (rename(path, tempPath) < 0) { diff --git a/Sources/SentryCrash/Recording/SentryCrashReportFixer.c b/Sources/SentryCrash/Recording/SentryCrashReportFixer.c index 0315f7a8bb2..e4e4f1540cd 100644 --- a/Sources/SentryCrash/Recording/SentryCrashReportFixer.c +++ b/Sources/SentryCrash/Recording/SentryCrashReportFixer.c @@ -60,7 +60,7 @@ increaseDepth(FixupContext *context, const char *name) if (name == NULL) { *context->objectPath[context->currentDepth] = '\0'; } else { - strncpy(context->objectPath[context->currentDepth], name, + strlcpy(context->objectPath[context->currentDepth], name, sizeof(context->objectPath[context->currentDepth])); } context->currentDepth++; diff --git a/Sources/SentryCrash/Recording/Tools/SentryCrashFileUtils.c b/Sources/SentryCrash/Recording/Tools/SentryCrashFileUtils.c index 9d548fd9efe..39428ca8981 100644 --- a/Sources/SentryCrash/Recording/Tools/SentryCrashFileUtils.c +++ b/Sources/SentryCrash/Recording/Tools/SentryCrashFileUtils.c @@ -161,7 +161,7 @@ deletePathContents(const char *path, bool deleteTopLevelPathAlso) for (int i = 0; i < entryCount; i++) { char *entry = entries[i]; if (entry != NULL && canDeletePath(entry)) { - strncpy(pathPtr, entry, pathRemainingLength); + strlcpy(pathPtr, entry, pathRemainingLength); deletePathContents(pathBuffer, true); } } diff --git a/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodec.c b/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodec.c index 713b10356e8..48d9ab1f073 100644 --- a/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodec.c +++ b/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodec.c @@ -1256,8 +1256,7 @@ decodeElement(const char *const name, SentryCrashJSONDecodeContext *context) SENTRY_ASYNC_SAFE_LOG_DEBUG("Number is too long."); return SentryCrashJSON_ERROR_DATA_TOO_LONG; } - strncpy(context->stringBuffer, start, len); - context->stringBuffer[len] = '\0'; + strlcpy(context->stringBuffer, start, len); sscanf(context->stringBuffer, "%lg", &value); diff --git a/Sources/SentryCrash/Reporting/Filters/Tools/SentryStringUtils.h b/Sources/SentryCrash/Reporting/Filters/Tools/SentryStringUtils.h deleted file mode 100644 index c240ef40d52..00000000000 --- a/Sources/SentryCrash/Reporting/Filters/Tools/SentryStringUtils.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef Sentry_StringUtils_h -#define Sentry_StringUtils_h -#include - -/** - * @brief Copies a string safely ensuring null-termination. - * - * This function copies up to `n-1` characters from the `src` string to - * the `dst` buffer and ensures that the `dst` string is null-terminated. - * It behaves similarly to `strncpy`, but guarantees null-termination. - * - * @param dst The destination buffer where the string will be copied. - * @param src The source string to copy from. - * @param n The size of the destination buffer, including space for the null terminator. - * - * @return Returns the destination. - * - * @note Ensure that `n` is greater than 0. - * This can silently truncate src if it is larger than `n` - 1. - */ -static inline char * -strncpy_safe(char *dst, const char *src, size_t n) -{ - strncpy(dst, src, n - 1); - dst[n - 1] = '\0'; - return dst; -} - -#endif diff --git a/Tests/SentryTests/Recording/SentryCrashCTests.swift b/Tests/SentryTests/Recording/SentryCrashCTests.swift new file mode 100644 index 00000000000..f4bea920eff --- /dev/null +++ b/Tests/SentryTests/Recording/SentryCrashCTests.swift @@ -0,0 +1,212 @@ +// +// SentryCrashCTests.swift +// Sentry +// +// Created by Philip Niedertscheider on 13.12.24. +// Copyright © 2024 Sentry. All rights reserved. +// + +@testable import Sentry +import XCTest + +class SentryCrashCTests: XCTestCase { + + func testOnCrash_notCrashedDuringCrashHandling_shouldWriteReportToDisk() { + // -- Arrange -- + var appName = "SentryCrashCTests" + .cString(using: .utf8)! + let workDir = URL(fileURLWithPath: NSTemporaryDirectory()) + .appendingPathComponent("test-case-\(UUID().uuidString)") + let installDir = workDir + .appendingPathComponent(Array(repeating: "X", count: 100).joined()) + var installPath = installDir + .path + .cString(using: .utf8)! + + // Installing the sentrycrash will setup the exception handler + sentrycrash_install(&appName, &installPath) + + var monitorContext = SentryCrash_MonitorContext( + eventID: nil, + requiresAsyncSafety: false, + handlingCrash: false, + crashedDuringCrashHandling: false, + registersAreValid: false, + isStackOverflow: false, + offendingMachineContext: nil, + faultAddress: 0, + crashType: SentryCrashMonitorTypeCPPException, + exceptionName: nil, + crashReason: nil, + stackCursor: nil, + mach: SentryCrash_MonitorContext.__Unnamed_struct_mach(), + NSException: SentryCrash_MonitorContext.__Unnamed_struct_NSException(), + CPPException: SentryCrash_MonitorContext.__Unnamed_struct_CPPException(), + signal: SentryCrash_MonitorContext.__Unnamed_struct_signal(), + userException: SentryCrash_MonitorContext.__Unnamed_struct_userException(), + AppState: SentryCrash_MonitorContext.__Unnamed_struct_AppState(), + System: SentryCrash_MonitorContext.__Unnamed_struct_System(), + ZombieException: SentryCrash_MonitorContext.__Unnamed_struct_ZombieException() + ) + // -- Act -- + // Calling the handle exception will trigger the onCrash handler + sentrycrashcm_handleException(&monitorContext) + + // -- Assert -- + let expectedCrashStatePath = installDir + .appendingPathComponent("Data") + .appendingPathComponent("CrashState") + .appendingPathExtension("json") + .path + XCTAssertTrue(FileManager.default.fileExists(atPath: expectedCrashStatePath)) + } + + func testOnCrash_notCrashedDuringCrashHandling_installFilePathTooLong_shouldNotWriteToDisk() { + // -- Arrange -- + var appName = "SentryCrashCTests" + .cString(using: .utf8)! + let workDir = URL(fileURLWithPath: NSTemporaryDirectory()) + .appendingPathComponent("test-case-\(UUID().uuidString)") + let installDir = workDir + .appendingPathComponent(Array(repeating: "X", count: 500).joined()) + var installPath = installDir + .path + .cString(using: .utf8)! + + // Installing the sentrycrash will setup the exception handler + sentrycrash_install(&appName, &installPath) + + var monitorContext = SentryCrash_MonitorContext( + eventID: nil, + requiresAsyncSafety: false, + handlingCrash: false, + crashedDuringCrashHandling: false, + registersAreValid: false, + isStackOverflow: false, + offendingMachineContext: nil, + faultAddress: 0, + crashType: SentryCrashMonitorTypeCPPException, + exceptionName: nil, + crashReason: nil, + stackCursor: nil, + mach: SentryCrash_MonitorContext.__Unnamed_struct_mach(), + NSException: SentryCrash_MonitorContext.__Unnamed_struct_NSException(), + CPPException: SentryCrash_MonitorContext.__Unnamed_struct_CPPException(), + signal: SentryCrash_MonitorContext.__Unnamed_struct_signal(), + userException: SentryCrash_MonitorContext.__Unnamed_struct_userException(), + AppState: SentryCrash_MonitorContext.__Unnamed_struct_AppState(), + System: SentryCrash_MonitorContext.__Unnamed_struct_System(), + ZombieException: SentryCrash_MonitorContext.__Unnamed_struct_ZombieException() + ) + // -- Act -- + // Calling the handle exception will trigger the onCrash handler + sentrycrashcm_handleException(&monitorContext) + + // -- Assert -- + // Check the report was written to the truncated file path + let expectedCrashStatePath = installDir + .appendingPathComponent("Data") + .appendingPathComponent("CrashState") + .appendingPathExtension("json") + XCTAssertFalse(FileManager.default.fileExists(atPath: expectedCrashStatePath.path)) + } + +// func testOnCrash_crashedDuringCrashHandling_shouldWriteReportToDisk() { +// // -- Arrange -- +// var appName = "SentryCrashCTests" +// .cString(using: .utf8)! +// let workDir = URL(fileURLWithPath: NSTemporaryDirectory()) +// .appendingPathComponent("test-case-\(UUID().uuidString)") +// let installDir = workDir +// .appendingPathComponent(Array(repeating: "X", count: 100).joined()) +// var installPath = installDir +// .path +// .cString(using: .utf8)! +// +// // Installing the sentrycrash will setup the exception handler +// sentrycrash_install(&appName, &installPath) +// +// // -- Act -- +// // Calling the handle exception will trigger the onCrash handler +// var monitorContext = SentryCrash_MonitorContext( +// eventID: nil, +// requiresAsyncSafety: false, +// handlingCrash: false, +// crashedDuringCrashHandling: false, +// registersAreValid: false, +// isStackOverflow: false, +// offendingMachineContext: nil, +// faultAddress: 0, +// crashType: SentryCrashMonitorTypeCPPException, +// exceptionName: nil, +// crashReason: nil, +// stackCursor: nil, +// mach: SentryCrash_MonitorContext.__Unnamed_struct_mach(), +// NSException: SentryCrash_MonitorContext.__Unnamed_struct_NSException(), +// CPPException: SentryCrash_MonitorContext.__Unnamed_struct_CPPException(), +// signal: SentryCrash_MonitorContext.__Unnamed_struct_signal(), +// userException: SentryCrash_MonitorContext.__Unnamed_struct_userException(), +// AppState: SentryCrash_MonitorContext.__Unnamed_struct_AppState(), +// System: SentryCrash_MonitorContext.__Unnamed_struct_System(), +// ZombieException: SentryCrash_MonitorContext.__Unnamed_struct_ZombieException() +// ) +// sentrycrashcm_handleException(&monitorContext) +// +// // Calling the handler again with 'crashedDuringCrashHandling' will rewrite the crash report +// struct SentryCrashMachineContext { +// var thisThread: thread_t // Maps directly if imported from C +// var allThreads: [thread_t] // Array to handle up to 100 threads +// var threadCount: Int +// var isCrashedContext: Bool +// var isCurrentThread: Bool +// var isStackOverflow: Bool +// var isSignalContext: Bool +// } +// var machineContext = SentryCrashMachineContext( +// thisThread: 0, +// allThreads: Array(repeating: 0, count: 100), +// threadCount: 0, +// isCrashedContext: false, +// isCurrentThread: false, +// isStackOverflow: false, +// isSignalContext: false +// ) +// withUnsafeMutablePointer(to: &machineContext) { offendingMachineContextPtr in +// SentryCrashDefaultMachineContextWrapper() +// .fillContext( +// forCurrentThread: OpaquePointer(offendingMachineContextPtr) +// ) +// monitorContext = SentryCrash_MonitorContext( +// eventID: nil, +// requiresAsyncSafety: false, +// handlingCrash: false, +// crashedDuringCrashHandling: true, +// registersAreValid: false, +// isStackOverflow: false, +// offendingMachineContext: OpaquePointer(offendingMachineContextPtr), +// faultAddress: 0, +// crashType: SentryCrashMonitorTypeCPPException, +// exceptionName: nil, +// crashReason: nil, +// stackCursor: nil, +// mach: SentryCrash_MonitorContext.__Unnamed_struct_mach(), +// NSException: SentryCrash_MonitorContext.__Unnamed_struct_NSException(), +// CPPException: SentryCrash_MonitorContext.__Unnamed_struct_CPPException(), +// signal: SentryCrash_MonitorContext.__Unnamed_struct_signal(), +// userException: SentryCrash_MonitorContext.__Unnamed_struct_userException(), +// AppState: SentryCrash_MonitorContext.__Unnamed_struct_AppState(), +// System: SentryCrash_MonitorContext.__Unnamed_struct_System(), +// ZombieException: SentryCrash_MonitorContext.__Unnamed_struct_ZombieException() +// ) +// sentrycrashcm_handleException(&monitorContext) +// } +// +// // -- Assert -- +// let expectedCrashStatePath = installDir +// .appendingPathComponent("Data") +// .appendingPathComponent("CrashState") +// .appendingPathExtension("json") +// .path +// XCTAssertTrue(FileManager.default.fileExists(atPath: expectedCrashStatePath)) +// } +} diff --git a/Tests/SentryTests/SentryCrash/SentryCrashFileUtils_Tests.m b/Tests/SentryTests/SentryCrash/SentryCrashFileUtils_Tests.m index fb5f5197b4e..0ea9615e32b 100644 --- a/Tests/SentryTests/SentryCrash/SentryCrashFileUtils_Tests.m +++ b/Tests/SentryTests/SentryCrash/SentryCrashFileUtils_Tests.m @@ -622,4 +622,86 @@ - (void)testReadLineFromFD XCTAssertTrue(bytesRead == 0, @""); } +- (void)testDeleteContentsOfPath_canNotDeletePath_shouldNotDeleteTopLevelPath +{ + // -- Arrange -- + NSString *notDeleteablePath = @"."; + // -- Act -- + bool result = sentrycrashfu_deleteContentsOfPath([notDeleteablePath UTF8String]); + // -- Assert -- + XCTAssertFalse(result); +} + +- (void)testDeleteContentsOfPath_unknownFile_shouldNotDeleteTopLevelPath +{ + // -- Arrange -- + NSString *unknownFilePath = @"/invalid/path"; + // -- Act -- + bool result = sentrycrashfu_deleteContentsOfPath([unknownFilePath UTF8String]); + // -- Assert -- + XCTAssertFalse(result); +} + +- (void)testDeleteContentsOfPath_filePath_shouldDeleteFile +{ + // -- Arrange -- + NSString *filePath = [self.tempPath stringByAppendingPathComponent:@"test.txt"]; + NSError *error; + [@"Hello World" writeToFile:filePath + atomically:true + encoding:NSUTF8StringEncoding + error:&error]; + XCTAssertNil(error); + // Smoke-test the file got created + int fd = open([filePath UTF8String], O_RDONLY); + XCTAssertTrue(fd >= -1, "Failed to create test file"); + + // -- Act -- + bool result = sentrycrashfu_deleteContentsOfPath([filePath UTF8String]); + + // -- Assert -- + XCTAssertTrue(result); + // Validate the file got deleted + fd = open([filePath UTF8String], O_RDONLY); + XCTAssertTrue(fd == -1, "Test file was not deleted"); +} + +- (void)testDeleteContentsOfPath_dirPath_shouldDeleteAllFiles +{ + // -- Arrange -- + NSString *directoryPath = + [self.tempPath stringByAppendingPathComponent:[@"" stringByPaddingToLength:100 + withString:@"D" + startingAtIndex:0]]; + NSString *filePath = + [[directoryPath stringByAppendingPathComponent:[@"" stringByPaddingToLength:100 + withString:@"F" + startingAtIndex:0]] + stringByAppendingPathExtension:@"txt"]; + + NSError *error; + [[NSFileManager defaultManager] createDirectoryAtPath:directoryPath + withIntermediateDirectories:true + attributes:nil + error:&error]; + XCTAssertNil(error, "Failed to create temporary test folder"); + + [@"Hello World" writeToFile:filePath + atomically:true + encoding:NSUTF8StringEncoding + error:&error]; + XCTAssertNil(error, "Failed to create temporary test file"); + // Smoke-test the file got created + int fd = open([filePath UTF8String], O_RDONLY); + XCTAssertTrue(fd >= 0, "Failed to create test file"); + + // -- Act -- + bool result = sentrycrashfu_deleteContentsOfPath([directoryPath UTF8String]); + + // -- Assert -- + XCTAssertTrue(result); + // Validate the file got deleted + fd = open([filePath UTF8String], O_RDONLY); + XCTAssertTrue(fd == -1, "Test file was not deleted"); +} @end diff --git a/Tests/SentryTests/SentryCrash/SentryStringUtils.swift b/Tests/SentryTests/SentryCrash/SentryStringUtils.swift deleted file mode 100644 index afa894c4443..00000000000 --- a/Tests/SentryTests/SentryCrash/SentryStringUtils.swift +++ /dev/null @@ -1,31 +0,0 @@ -import XCTest - -final class SentryStringUtils: XCTestCase { - - func testStrncpy_safe_BiggerBuffer() throws { - let strn = "Hello, World!" - let dstBufferSize = strn.count + 1 - - let dst = UnsafeMutablePointer.allocate(capacity: dstBufferSize) - defer { dst.deallocate() } - - let n = try XCTUnwrap(strncpy_safe(dst, strn, dstBufferSize)) - let result = String(cString: n) - - XCTAssertEqual(result, strn) - } - - func testStrncpy_safe_smallerBuffer() throws { - let strn = "Hello, World!" - let dstBufferSize = 6 - - let dst = UnsafeMutablePointer.allocate(capacity: dstBufferSize) - defer { dst.deallocate() } - - let n = try XCTUnwrap(strncpy_safe(dst, strn, dstBufferSize)) - let result = String(cString: n) - - XCTAssertEqual(result, "Hello") - } - -} diff --git a/Tests/SentryTests/SentryTests-Bridging-Header.h b/Tests/SentryTests/SentryTests-Bridging-Header.h index a29c3704325..07e34aa39eb 100644 --- a/Tests/SentryTests/SentryTests-Bridging-Header.h +++ b/Tests/SentryTests/SentryTests-Bridging-Header.h @@ -244,4 +244,3 @@ #import "SentryCrashInstallation+Private.h" #import "SentryCrashMonitor_MachException.h" #import "SentrySessionReplaySyncC.h" -#import "SentryStringUtils.h" From 3926467e8fb0d0057a107b2ba6a1079c403a2d14 Mon Sep 17 00:00:00 2001 From: Philip Niedertscheider Date: Fri, 13 Dec 2024 16:33:18 +0100 Subject: [PATCH 2/2] add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5fe232fb89..ecc69fea743 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ ### Fixes - `SentrySdkInfo.packages` should be an array (#4626) +- Replace occurences of `strncpy` with `strlcpy` (#4636) ### Internal