diff --git a/.buildkite/pipeline.full.yml b/.buildkite/pipeline.full.yml index 25fb99a88..62b3cb3e4 100644 --- a/.buildkite/pipeline.full.yml +++ b/.buildkite/pipeline.full.yml @@ -87,7 +87,7 @@ steps: plugins: artifacts#v1.3.0: download: ["features/fixtures/macos/output/macOSTestApp.zip"] - upload: ["macOSTestApp.log"] + upload: ["macOSTestApp.log", "appium_server.log"] commands: - bundle install - bundle exec maze-runner @@ -107,7 +107,7 @@ steps: plugins: artifacts#v1.3.0: download: ["features/fixtures/macos/output/macOSTestApp.zip"] - upload: ["macOSTestApp.log"] + upload: ["macOSTestApp.log", "appium_server.log"] commands: - bundle install - bundle exec maze-runner @@ -127,7 +127,7 @@ steps: plugins: artifacts#v1.3.0: download: ["features/fixtures/macos/output/macOSTestApp.zip"] - upload: ["macOSTestApp.log"] + upload: ["macOSTestApp.log", "appium_server.log"] commands: - bundle install - bundle exec maze-runner diff --git a/.buildkite/pipeline.quick.yml b/.buildkite/pipeline.quick.yml index 90f5ee9e7..de01bddf2 100644 --- a/.buildkite/pipeline.quick.yml +++ b/.buildkite/pipeline.quick.yml @@ -169,7 +169,7 @@ steps: plugins: artifacts#v1.3.0: download: ["features/fixtures/macos/output/macOSTestApp.zip"] - upload: ["macOSTestApp.log"] + upload: ["macOSTestApp.log", "appium_server.log"] commands: - bundle install - bundle exec maze-runner diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 514fb103a..539c5d0e4 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -1,4 +1,17 @@ +env: + LANG: "en_GB.UTF-8" + steps: + - label: 'Trigger RN tests for all builds of our next branch' + if: build.branch == "next" + trigger: 'bugsnag-js' + build: + branch: 'next' + message: 'Run RN tests with latest Cocoa next branch' + env: + BUILD_RN_WITH_LATEST_NATIVES: "true" + async: true + - label: Build cocoa IPA key: cocoa_fixture timeout_in_minutes: 20 @@ -186,7 +199,7 @@ steps: plugins: artifacts#v1.3.0: download: ["features/fixtures/macos/output/macOSTestApp.zip"] - upload: ["macOSTestApp.log"] + upload: ["macOSTestApp.log", "appium_server.log"] commands: - bundle install - bundle exec maze-runner @@ -205,13 +218,17 @@ steps: env: STRESS_TEST: "true" commands: + - echo "--- Bundle install" - bundle install + - echo "--- Build" + - make -C features/fixtures/macos-stress-test + - echo "--- Test" - bundle exec maze-runner features/stress_test.feature --no-log-requests artifact_paths: - - features/fixtures/macos-stress-test/BugsnagStressTest.stdout.log - - features/fixtures/macos-stress-test/BugsnagStressTest.stderr.log + - features/fixtures/macos-stress-test/*.log + - features/fixtures/macos-stress-test/*.crash - label: 'Conditionally trigger full set of tests' command: sh -c .buildkite/pipeline_trigger.sh diff --git a/.jazzy.yaml b/.jazzy.yaml index 6e6c31efb..52e1e5d11 100644 --- a/.jazzy.yaml +++ b/.jazzy.yaml @@ -2,11 +2,11 @@ author_url: "https://www.bugsnag.com" author: "Bugsnag Inc" clean: false # avoid deleting docs/.git framework_root: "Bugsnag" -github_file_prefix: "https://github.com/bugsnag/bugsnag-cocoa/tree/v6.9.1/Bugsnag" +github_file_prefix: "https://github.com/bugsnag/bugsnag-cocoa/tree/v6.9.2/Bugsnag" github_url: "https://github.com/bugsnag/bugsnag-cocoa" hide_documentation_coverage: true module: "Bugsnag" -module_version: "6.9.1" +module_version: "6.9.2" objc: true output: "docs" readme: "README.md" diff --git a/Bugsnag.podspec.json b/Bugsnag.podspec.json index f93f11910..f03df6ced 100644 --- a/Bugsnag.podspec.json +++ b/Bugsnag.podspec.json @@ -1,6 +1,6 @@ { "name": "Bugsnag", - "version": "6.9.1", + "version": "6.9.2", "summary": "The Bugsnag crash reporting framework for Apple platforms.", "homepage": "https://bugsnag.com", "license": "MIT", @@ -9,7 +9,7 @@ }, "source": { "git": "https://github.com/bugsnag/bugsnag-cocoa.git", - "tag": "v6.9.1" + "tag": "v6.9.2" }, "frameworks": [ "Foundation", @@ -28,6 +28,7 @@ "Bugsnag/{**/,}*.{m,h,mm,c}" ], "requires_arc": true, + "prefix_header_file": false, "public_header_files": [ "Bugsnag/include/Bugsnag/*.h" ] diff --git a/Bugsnag.xcconfig b/Bugsnag.xcconfig index 3a471aaa6..dd370fbd7 100644 --- a/Bugsnag.xcconfig +++ b/Bugsnag.xcconfig @@ -1,19 +1,99 @@ -GCC_TREAT_WARNINGS_AS_ERRORS = YES - -WARNING_CFLAGS = $(inherited) -Warc-repeated-use-of-weak -Wassign-enum -WARNING_CFLAGS = $(WARNING_CFLAGS) -Wblock-capture-autoreleasing -Wbool-conversion -WARNING_CFLAGS = $(WARNING_CFLAGS) -Wcomma -Wconditional-uninitialized -Wconstant-conversion -Wconversion -WARNING_CFLAGS = $(WARNING_CFLAGS) -Wdeprecated-declarations -Wdeprecated-implementations -Wdeprecated-objc-isa-usage -Wdocumentation -Wduplicate-method-match -WARNING_CFLAGS = $(WARNING_CFLAGS) -Wempty-body -Wenum-conversion -Wexplicit-ownership-type -WARNING_CFLAGS = $(WARNING_CFLAGS) -Wfloat-conversion -Wfour-char-constants -Wframework-include-private-from-public -WARNING_CFLAGS = $(WARNING_CFLAGS) -Wimplicit-atomic-properties -Wimplicit-int-float-conversion -Wimplicit-retain-self -Wincompatible-pointer-types -WARNING_CFLAGS = $(WARNING_CFLAGS) -Wincomplete-implementation -Winfinite-recursion -Wint-conversion -WARNING_CFLAGS = $(WARNING_CFLAGS) -Wmissing-braces -WARNING_CFLAGS = $(WARNING_CFLAGS) -Wno-unknown-warning-option -Wnon-literal-null-conversion -Wnonportable-include-path -Wnullable-to-nonnull-conversion -WARNING_CFLAGS = $(WARNING_CFLAGS) -Wobjc-literal-conversion -Wobjc-root-class -WARNING_CFLAGS = $(WARNING_CFLAGS) -Wparentheses -Wpointer-sign -Wprotocol -WARNING_CFLAGS = $(WARNING_CFLAGS) -Wreturn-type -WARNING_CFLAGS = $(WARNING_CFLAGS) -Wshadow -Wshorten-64-to-32 -Wsign-compare -Wsign-conversion -Wstrict-prototypes -Wstrict-selector-match -Wswitch -WARNING_CFLAGS = $(WARNING_CFLAGS) -Wundeclared-selector -Wunguarded-availability -Wuninitialized -Wunknown-pragmas -Wunreachable-code -WARNING_CFLAGS = $(WARNING_CFLAGS) -Wunused-function -Wunused-label -Wunused-parameter -Wunused-value -Wunused-variable +// Apple Clang - Warning Policies + +GCC_TREAT_WARNINGS_AS_ERRORS = YES // -Werror +GCC_WARN_INHIBIT_ALL_WARNINGS = NO +GCC_WARN_PEDANTIC = NO + +// Apple Clang - Warnings - All languages + +CLANG_WARN_ASSIGN_ENUM = YES // -Wassign-enum +CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES // -Wblock-capture-autoreleasing +CLANG_WARN_BOOL_CONVERSION = YES // -Wbool-conversion +CLANG_WARN_COMMA = YES // -Wcomma +CLANG_WARN_CONSTANT_CONVERSION = YES // -Wconstant-conversion +CLANG_WARN_DOCUMENTATION_COMMENTS = YES // -Wdocumentation +CLANG_WARN_EMPTY_BODY = YES // -Wempty-body +CLANG_WARN_ENUM_CONVERSION = YES // -Wenum-conversion +CLANG_WARN_FLOAT_CONVERSION = YES // -Wfloat-conversion +CLANG_WARN_FRAMEWORK_INCLUDE_PRIVATE_FROM_PUBLIC = YES // -Wframework-include-private-from-public +CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES // -Wsign-conversion +CLANG_WARN_INFINITE_RECURSION = YES // -Winfinite-recursion +CLANG_WARN_INT_CONVERSION = YES // -Wint-conversion +CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES // -Wnon-literal-null-conversion +CLANG_WARN_PRAGMA_PACK = YES // -Wpragma-pack +CLANG_WARN_PRIVATE_MODULE = YES // -Wprivate-module +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES // -Wquoted-include-in-framework-header +CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES // -Wsemicolon-before-method-body +CLANG_WARN_STRICT_PROTOTYPES = YES // -Wstrict-prototypes +CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES // -Wconversion -Wconstant-conversion -Wint-conversion -Wbool-conversion -Wenum-conversion -Wfloat-conversion -Wnon-literal-null-conversion -Wobjc-literal-conversion +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE // -Wunguarded-availability +CLANG_WARN_UNREACHABLE_CODE = YES // -Wunreachable-code +GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES +GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES // -Wincompatible-pointer-types +GCC_WARN_64_TO_32_BIT_CONVERSION = YES // -Wshorten-64-to-32 +GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES // -Wdeprecated-declarations +GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO // -Wmissing-field-initializers +GCC_WARN_ABOUT_MISSING_NEWLINE = YES // -Wnewline-eof +GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO // -Wmissing-prototypes +GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES +GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR // -Wreturn-type +GCC_WARN_CHECK_SWITCH_STATEMENTS = YES // -Wswitch +GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES // -Wfour-char-constants +GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES // -Wmissing-braces +GCC_WARN_MISSING_PARENTHESES = YES // -Wparentheses +GCC_WARN_SHADOW = YES // -Wshadow +GCC_WARN_SIGN_COMPARE = YES // -Wsign-compare +GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES // -Wformat +GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE // -Wuninitialized +GCC_WARN_UNKNOWN_PRAGMAS = YES // -Wunknown-pragmas +GCC_WARN_UNUSED_FUNCTION = YES // -Wunused-function +GCC_WARN_UNUSED_LABEL = YES // -Wunused-label +GCC_WARN_UNUSED_PARAMETER = YES // -Wunused-parameter +GCC_WARN_UNUSED_VALUE = YES // -Wunused-value +GCC_WARN_UNUSED_VARIABLE = YES // -Wunused-variable + +// Apple Clang - Warnings - C++ + +CLANG_WARN_ATOMIC_IMPLICIT_SEQ_CST = YES // -Watomic-implicit-seq-cst +CLANG_WARN_CXX0X_EXTENSIONS = YES // -Wc++11-extensions +CLANG_WARN_DELETE_NON_VIRTUAL_DTOR = YES // -Wdelete-non-virtual-dtor +CLANG_WARN_RANGE_LOOP_ANALYSIS = YES // -Wrange-loop-analysis +CLANG_WARN_SUSPICIOUS_MOVE = YES // -Wmove +CLANG_WARN_VEXING_PARSE = YES // -Wvexing-parse +CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES // -Wexit-time-destructors +GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES // -Winvalid-offsetof +GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES // -Woverloaded-virtual +GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES // -Wnon-virtual-dtor + +// Apple Clang - Warnings - Objective-C + +CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES // -Wdeprecated-implementations +CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES // -Wdeprecated-objc-isa-usage +CLANG_WARN_MISSING_NOESCAPE = YES // -Wmissing-noescape +CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES // -Wimplicit-atomic-properties +CLANG_WARN_OBJC_INTERFACE_IVARS = YES // -Wobjc-interface-ivars +CLANG_WARN_OBJC_LITERAL_CONVERSION = YES // -Wobjc-literal-conversion +CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = NO // -Wobjc-missing-property-synthesis +CLANG_WARN_OBJC_ROOT_CLASS = YES // -Wobjc-root-class +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES // -Wduplicate-method-match +GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES // -Wprotocol +GCC_WARN_STRICT_SELECTOR_MATCH = YES // -Wstrict-selector-match +GCC_WARN_UNDECLARED_SELECTOR = YES // -Wundeclared-selector + +// Apple Clang - Warnings - Objective-C and ARC + +CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES // -Wexplicit-ownership-type +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES // -Wimplicit-retain-self +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES // -Warc-repeated-use-of-weak -Wno-arc-maybe-repeated-use-of-weak +CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES // -Warc-bridge-casts-disallowed-in-nonarc + +// Warning flags that have no dedicated Xcode build settings + +WARNING_CFLAGS = -Wcast-qual -Wconditional-uninitialized -Wcustom-atomic-properties -Wdirect-ivar-access -Wdocumentation-unknown-command -Wformat-nonliteral -Widiomatic-parentheses -Wimplicit-int-float-conversion -Wimport-preprocessor-directive-pedantic -Wincomplete-implementation -Wmissing-variable-declarations -Wno-unknown-warning-option -Wnonportable-include-path -Wnullable-to-nonnull-conversion -Woverriding-method-mismatch -Wpointer-sign -Wswitch-enum -Wunused-macros + +// Some flags that were considered and rejected: +// +// -Wcstring-format-directive warns when a %s format string is used to construct a CF/NSString, despite them being supported. +// -Wpadded warns when struct padding is added by the compiler, a common occurrence and not a programming error. +// diff --git a/Bugsnag.xcodeproj/project.pbxproj b/Bugsnag.xcodeproj/project.pbxproj index 4d14f9cfd..b9d43a430 100644 --- a/Bugsnag.xcodeproj/project.pbxproj +++ b/Bugsnag.xcodeproj/project.pbxproj @@ -679,6 +679,16 @@ 01840B7325DC26E200F95648 /* BSGEventUploader.m in Sources */ = {isa = PBXBuildFile; fileRef = 01840B6E25DC26E200F95648 /* BSGEventUploader.m */; }; 01840B7425DC26E200F95648 /* BSGEventUploader.m in Sources */ = {isa = PBXBuildFile; fileRef = 01840B6E25DC26E200F95648 /* BSGEventUploader.m */; }; 01840B7525DC26E200F95648 /* BSGEventUploader.m in Sources */ = {isa = PBXBuildFile; fileRef = 01840B6E25DC26E200F95648 /* BSGEventUploader.m */; }; + 01847D962644140F00ADA4C7 /* BSGInternalErrorReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 01847D942644140F00ADA4C7 /* BSGInternalErrorReporter.h */; }; + 01847D972644140F00ADA4C7 /* BSGInternalErrorReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 01847D942644140F00ADA4C7 /* BSGInternalErrorReporter.h */; }; + 01847D982644140F00ADA4C7 /* BSGInternalErrorReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 01847D942644140F00ADA4C7 /* BSGInternalErrorReporter.h */; }; + 01847D992644140F00ADA4C7 /* BSGInternalErrorReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 01847D952644140F00ADA4C7 /* BSGInternalErrorReporter.m */; }; + 01847D9A2644140F00ADA4C7 /* BSGInternalErrorReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 01847D952644140F00ADA4C7 /* BSGInternalErrorReporter.m */; }; + 01847D9B2644140F00ADA4C7 /* BSGInternalErrorReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 01847D952644140F00ADA4C7 /* BSGInternalErrorReporter.m */; }; + 01847D9C2644140F00ADA4C7 /* BSGInternalErrorReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 01847D952644140F00ADA4C7 /* BSGInternalErrorReporter.m */; }; + 01847DAC26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01847DAB26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m */; }; + 01847DAD26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01847DAB26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m */; }; + 01847DAE26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01847DAB26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m */; }; 0187D464255BD7B800C503D9 /* BugsnagApiClientTest.m in Sources */ = {isa = PBXBuildFile; fileRef = CB9103632502320A00E9D1E2 /* BugsnagApiClientTest.m */; }; 019480D42625F3EB00E833ED /* BSGAppKitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 019480D32625F3EB00E833ED /* BSGAppKitTests.m */; }; 01B14C56251CE55F00118748 /* report-react-native-promise-rejection.json in Resources */ = {isa = PBXBuildFile; fileRef = 01B14C55251CE55F00118748 /* report-react-native-promise-rejection.json */; }; @@ -1321,6 +1331,9 @@ 017824BD262D65A000D18AFA /* Bugsnag.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Bugsnag.xcconfig; sourceTree = ""; }; 01840B6D25DC26E200F95648 /* BSGEventUploader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BSGEventUploader.h; sourceTree = ""; }; 01840B6E25DC26E200F95648 /* BSGEventUploader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BSGEventUploader.m; sourceTree = ""; }; + 01847D942644140F00ADA4C7 /* BSGInternalErrorReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSGInternalErrorReporter.h; sourceTree = ""; }; + 01847D952644140F00ADA4C7 /* BSGInternalErrorReporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSGInternalErrorReporter.m; sourceTree = ""; }; + 01847DAB26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BSGInternalErrorReporterTests.m; sourceTree = ""; }; 01937CF9257A7B4C00F2DE31 /* Bugsnag+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Bugsnag+Private.h"; sourceTree = ""; }; 01937D09257A7ED000F2DE31 /* BugsnagSessionTracker+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BugsnagSessionTracker+Private.h"; sourceTree = ""; }; 01937D11257A814D00F2DE31 /* BugsnagMetadata+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BugsnagMetadata+Private.h"; sourceTree = ""; }; @@ -1708,6 +1721,7 @@ 00896A3F2486DBDD00DC48C2 /* BSGConfigurationBuilderTests.m */, 008966C62486D43600DC48C2 /* BSGConnectivityTest.m */, 01BDB1CE25DEBF4600A91FAF /* BSGEventUploadKSCrashReportOperationTests.m */, + 01847DAB26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m */, CBCF77AA250142E0004AF22A /* BSGJSONSerializationTests.m */, 008966C82486D43600DC48C2 /* BSGOutOfMemoryTests.m */, CB6419AA25A73E8C00613D25 /* BSGStorageMigratorTests.m */, @@ -1838,6 +1852,8 @@ 010FF28225ED2A8D00E4F2B0 /* BSGAppHangDetector.h */, 010FF28325ED2A8D00E4F2B0 /* BSGAppHangDetector.m */, 019480C42625EE9800E833ED /* BSGAppKit.h */, + 01847D942644140F00ADA4C7 /* BSGInternalErrorReporter.h */, + 01847D952644140F00ADA4C7 /* BSGInternalErrorReporter.m */, CBCF77A125010648004AF22A /* BSGJSONSerialization.h */, CBCF77A225010648004AF22A /* BSGJSONSerialization.m */, 008968112486DA5600DC48C2 /* BSGSerialization.h */, @@ -2022,6 +2038,7 @@ 0126F7AB25DD5118008483C2 /* BSGEventUploadFileOperation.h in Headers */, 3A700A9A24A63AC60068CD1B /* BSG_KSCrashReportWriter.h in Headers */, 3A700A9B24A63AC60068CD1B /* BugsnagErrorTypes.h in Headers */, + 01847D962644140F00ADA4C7 /* BSGInternalErrorReporter.h in Headers */, 01840B6F25DC26E200F95648 /* BSGEventUploader.h in Headers */, 3A700A9C24A63AC60068CD1B /* BugsnagEvent.h in Headers */, 3A700A9D24A63AC60068CD1B /* BugsnagClient.h in Headers */, @@ -2125,6 +2142,7 @@ 0126F7AC25DD5118008483C2 /* BSGEventUploadFileOperation.h in Headers */, 3A700AAE24A63CFD0068CD1B /* BSG_KSCrashReportWriter.h in Headers */, 3A700AAF24A63CFD0068CD1B /* BugsnagErrorTypes.h in Headers */, + 01847D972644140F00ADA4C7 /* BSGInternalErrorReporter.h in Headers */, 01840B7025DC26E200F95648 /* BSGEventUploader.h in Headers */, 3A700AB024A63CFD0068CD1B /* BugsnagEvent.h in Headers */, 3A700AB124A63CFD0068CD1B /* BugsnagClient.h in Headers */, @@ -2228,6 +2246,7 @@ 0126F7AD25DD5118008483C2 /* BSGEventUploadFileOperation.h in Headers */, 3A700AC224A63D110068CD1B /* BSG_KSCrashReportWriter.h in Headers */, 3A700AC324A63D110068CD1B /* BugsnagErrorTypes.h in Headers */, + 01847D982644140F00ADA4C7 /* BSGInternalErrorReporter.h in Headers */, 01840B7125DC26E200F95648 /* BSGEventUploader.h in Headers */, 3A700AC424A63D110068CD1B /* BugsnagEvent.h in Headers */, 3A700AC524A63D110068CD1B /* BugsnagClient.h in Headers */, @@ -2624,6 +2643,7 @@ 0126F79E25DD510E008483C2 /* BSGEventUploadObjectOperation.m in Sources */, 0089682B2486DA5600DC48C2 /* BSGSerialization.m in Sources */, 011ADCE626049A3600B20D72 /* BugsnagClient+OutOfMemory.m in Sources */, + 01847D992644140F00ADA4C7 /* BSGInternalErrorReporter.m in Sources */, 008968E92486DAB800DC48C2 /* BugsnagSessionFileStore.m in Sources */, 00896A172486DAD100DC48C2 /* BSG_KSCrashSentry_CPPException.mm in Sources */, 008969CF2486DAD100DC48C2 /* BSG_KSCrashState.m in Sources */, @@ -2715,6 +2735,7 @@ 01E8765E256684E700F4B70A /* URLSessionMock.m in Sources */, 008967AB2486D43700DC48C2 /* KSMach_Tests.m in Sources */, 0089672A2486D43700DC48C2 /* BugsnagStacktraceTest.m in Sources */, + 01847DAC26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m in Sources */, 0163BF5925823D8D008DC28B /* NotificationBreadcrumbTests.m in Sources */, 008967392486D43700DC48C2 /* BugsnagEventFromKSCrashReportTest.m in Sources */, 008967182486D43700DC48C2 /* BugsnagErrorTest.m in Sources */, @@ -2794,6 +2815,7 @@ 0126F79F25DD510E008483C2 /* BSGEventUploadObjectOperation.m in Sources */, 0089682C2486DA5600DC48C2 /* BSGSerialization.m in Sources */, 011ADCE726049A3600B20D72 /* BugsnagClient+OutOfMemory.m in Sources */, + 01847D9A2644140F00ADA4C7 /* BSGInternalErrorReporter.m in Sources */, 008968EA2486DAB800DC48C2 /* BugsnagSessionFileStore.m in Sources */, 00896A182486DAD100DC48C2 /* BSG_KSCrashSentry_CPPException.mm in Sources */, 008969D02486DAD100DC48C2 /* BSG_KSCrashState.m in Sources */, @@ -2857,6 +2879,7 @@ 008967792486D43700DC48C2 /* KSMachHeader_Tests.m in Sources */, 0089675E2486D43700DC48C2 /* BugsnagSessionTrackingPayloadTest.m in Sources */, 008967A92486D43700DC48C2 /* KSCrashIdentifierTests.m in Sources */, + 01847DAD26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m in Sources */, 0089672B2486D43700DC48C2 /* BugsnagStacktraceTest.m in Sources */, 008966F22486D43700DC48C2 /* BugsnagMetadataRedactionTest.m in Sources */, CBDD6D0725AC3EFF00A2E12B /* BSGStorageMigratorTests.m in Sources */, @@ -2963,6 +2986,7 @@ 0126F7A025DD510E008483C2 /* BSGEventUploadObjectOperation.m in Sources */, 0089682D2486DA5600DC48C2 /* BSGSerialization.m in Sources */, 011ADCE826049A3600B20D72 /* BugsnagClient+OutOfMemory.m in Sources */, + 01847D9B2644140F00ADA4C7 /* BSGInternalErrorReporter.m in Sources */, 008968EB2486DAB800DC48C2 /* BugsnagSessionFileStore.m in Sources */, 00896A192486DAD100DC48C2 /* BSG_KSCrashSentry_CPPException.mm in Sources */, 008969D12486DAD100DC48C2 /* BSG_KSCrashState.m in Sources */, @@ -3058,6 +3082,7 @@ 008967772486D43700DC48C2 /* XCTestCase+KSCrash.m in Sources */, 008967322486D43700DC48C2 /* BugsnagStateEventTest.m in Sources */, CBA2249D251E429C00B87416 /* TestSupport.m in Sources */, + 01847DAE26441A5E00ADA4C7 /* BSGInternalErrorReporterTests.m in Sources */, 004E35372487AFF2007FBAE4 /* BugsnagHandledStateTest.m in Sources */, 016875C8258D003200DFFF69 /* NSUserDefaultsStub.m in Sources */, 01C17AE92542ED7F00C102C9 /* KSCrashReportWriterTests.m in Sources */, @@ -3147,6 +3172,7 @@ 0126F79125DD508C008483C2 /* BSGEventUploadOperation.m in Sources */, 008967EB2486DA2D00DC48C2 /* BugsnagErrorTypes.m in Sources */, 008967D62486DA2D00DC48C2 /* BugsnagEndpointConfiguration.m in Sources */, + 01847D9C2644140F00ADA4C7 /* BSGInternalErrorReporter.m in Sources */, 00AD1F262486A17900A27979 /* Bugsnag.m in Sources */, 0127149825F6171000D3500A /* BugsnagClient+AppHangs.m in Sources */, 008968CE2486DA9600DC48C2 /* BugsnagThread.m in Sources */, @@ -3185,7 +3211,6 @@ /* Begin XCBuildConfiguration section */ 00AD1C8424869B0E00A27979 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 017824BD262D65A000D18AFA /* Bugsnag.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; APPLICATION_EXTENSION_API_ONLY = YES; @@ -3196,28 +3221,6 @@ CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; @@ -3232,13 +3235,6 @@ "DEBUG=1", "$(inherited)", ); - GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = ./Framework/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.4; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; @@ -3260,7 +3256,6 @@ }; 00AD1C8524869B0E00A27979 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 017824BD262D65A000D18AFA /* Bugsnag.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; APPLICATION_EXTENSION_API_ONLY = YES; @@ -3271,28 +3266,6 @@ CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; @@ -3301,13 +3274,6 @@ ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; - GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = ./Framework/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.4; MTL_ENABLE_DEBUG_INFO = NO; @@ -3329,6 +3295,7 @@ }; 00AD1C8724869B0E00A27979 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 017824BD262D65A000D18AFA /* Bugsnag.xcconfig */; buildSettings = { CLANG_MODULES_AUTOLINK = NO; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; @@ -3352,6 +3319,7 @@ }; 00AD1C8824869B0E00A27979 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 017824BD262D65A000D18AFA /* Bugsnag.xcconfig */; buildSettings = { CLANG_MODULES_AUTOLINK = NO; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; @@ -3377,7 +3345,6 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; INFOPLIST_FILE = ./Tests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.3; LD_RUNPATH_SEARCH_PATHS = ( @@ -3397,7 +3364,6 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; INFOPLIST_FILE = ./Tests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.3; LD_RUNPATH_SEARCH_PATHS = ( @@ -3415,6 +3381,7 @@ }; 00AD1CBF24869C1200A27979 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 017824BD262D65A000D18AFA /* Bugsnag.xcconfig */; buildSettings = { CLANG_MODULES_AUTOLINK = NO; CODE_SIGN_STYLE = Automatic; @@ -3438,6 +3405,7 @@ }; 00AD1CC024869C1200A27979 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 017824BD262D65A000D18AFA /* Bugsnag.xcconfig */; buildSettings = { CLANG_MODULES_AUTOLINK = NO; CODE_SIGN_STYLE = Automatic; @@ -3464,7 +3432,6 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; INFOPLIST_FILE = ./Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -3485,7 +3452,6 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; INFOPLIST_FILE = ./Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -3503,6 +3469,7 @@ }; 00AD1CDB24869C2400A27979 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 017824BD262D65A000D18AFA /* Bugsnag.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; @@ -3525,6 +3492,7 @@ }; 00AD1CDC24869C2400A27979 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 017824BD262D65A000D18AFA /* Bugsnag.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; @@ -3549,7 +3517,6 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; INFOPLIST_FILE = ./Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -3570,7 +3537,6 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; INFOPLIST_FILE = ./Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -3589,6 +3555,7 @@ }; 00AD1CEB24869C6D00A27979 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 017824BD262D65A000D18AFA /* Bugsnag.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; IPHONEOS_DEPLOYMENT_TARGET = 9.3; @@ -3600,6 +3567,7 @@ }; 00AD1CEC24869C6D00A27979 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 017824BD262D65A000D18AFA /* Bugsnag.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; IPHONEOS_DEPLOYMENT_TARGET = 9.3; diff --git a/Bugsnag/Breadcrumbs/BSGNotificationBreadcrumbs.m b/Bugsnag/Breadcrumbs/BSGNotificationBreadcrumbs.m index 87c1f8c0d..57065f8ce 100644 --- a/Bugsnag/Breadcrumbs/BSGNotificationBreadcrumbs.m +++ b/Bugsnag/Breadcrumbs/BSGNotificationBreadcrumbs.m @@ -205,7 +205,7 @@ - (void)addBreadcrumbWithType:(BSGBreadcrumbType)type forNotificationName:(NSNot - (void)start { // State events - if ([_configuration shouldRecordBreadcrumbType:BSGBreadcrumbTypeState]) { + if ([self.configuration shouldRecordBreadcrumbType:BSGBreadcrumbTypeState]) { // Generic state events for (NSNotificationName name in [self automaticBreadcrumbStateEvents]) { [self startListeningForStateChangeNotification:name]; @@ -214,7 +214,7 @@ - (void)start { #if TARGET_OS_OSX // Workspace-specific events - macOS only for (NSNotificationName name in [self workspaceBreadcrumbStateEvents]) { - [_workspaceNotificationCenter addObserver:self + [self.workspaceNotificationCenter addObserver:self selector:@selector(addBreadcrumbForNotification:) name:name object:nil]; @@ -222,7 +222,7 @@ - (void)start { // NSMenu events (macOS only) for (NSNotificationName name in [self automaticBreadcrumbMenuItemEvents]) { - [_notificationCenter addObserver:self + [self.notificationCenter addObserver:self selector:@selector(addBreadcrumbForMenuItemNotification:) name:name object:nil]; @@ -231,10 +231,10 @@ - (void)start { } // Navigation events - if ([_configuration shouldRecordBreadcrumbType:BSGBreadcrumbTypeNavigation]) { + if ([self.configuration shouldRecordBreadcrumbType:BSGBreadcrumbTypeNavigation]) { // UI/NSTableView events for (NSNotificationName name in [self automaticBreadcrumbTableItemEvents]) { - [_notificationCenter addObserver:self + [self.notificationCenter addObserver:self selector:@selector(addBreadcrumbForTableViewNotification:) name:name object:nil]; @@ -242,10 +242,10 @@ - (void)start { } // User events - if ([_configuration shouldRecordBreadcrumbType:BSGBreadcrumbTypeUser]) { + if ([self.configuration shouldRecordBreadcrumbType:BSGBreadcrumbTypeUser]) { // UITextField/NSControl events (text editing) for (NSNotificationName name in [self automaticBreadcrumbControlEvents]) { - [_notificationCenter addObserver:self + [self.notificationCenter addObserver:self selector:@selector(addBreadcrumbForControlNotification:) name:name object:nil]; @@ -254,7 +254,7 @@ - (void)start { } - (void)startListeningForStateChangeNotification:(NSNotificationName)notificationName { - [_notificationCenter addObserver:self selector:@selector(addBreadcrumbForNotification:) name:notificationName object:nil]; + [self.notificationCenter addObserver:self selector:@selector(addBreadcrumbForNotification:) name:notificationName object:nil]; } - (void)addBreadcrumbForNotification:(NSNotification *)notification { diff --git a/Bugsnag/Breadcrumbs/BugsnagBreadcrumbs.h b/Bugsnag/Breadcrumbs/BugsnagBreadcrumbs.h index 6b0c748d0..5f1cf41d8 100644 --- a/Bugsnag/Breadcrumbs/BugsnagBreadcrumbs.h +++ b/Bugsnag/Breadcrumbs/BugsnagBreadcrumbs.h @@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN /** * The current breadcrumbs, loaded from disk. */ -@property (readonly) NSArray *breadcrumbs; +@property (readonly, nonatomic) NSArray *breadcrumbs; /** * Store a new breadcrumb with a provided message. diff --git a/Bugsnag/Bugsnag+Private.h b/Bugsnag/Bugsnag+Private.h index 97d02cc9e..3d0329252 100644 --- a/Bugsnag/Bugsnag+Private.h +++ b/Bugsnag/Bugsnag+Private.h @@ -14,12 +14,12 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark Properties -@property (class, readonly) BOOL bugsnagStarted; +@property (class, readonly, nonatomic) BOOL bugsnagStarted; -@property (class, readonly) BugsnagClient *client; +@property (class, readonly, nonatomic) BugsnagClient *client; /// Will be nil until +startWithApiKey: or +startWithConfiguration: has been called. -@property (class, readonly, nullable) BugsnagConfiguration *configuration; +@property (class, readonly, nullable, nonatomic) BugsnagConfiguration *configuration; #pragma mark Methods diff --git a/Bugsnag/BugsnagCrashSentry.h b/Bugsnag/BugsnagCrashSentry.h index e138f36b3..2365dc6d5 100644 --- a/Bugsnag/BugsnagCrashSentry.h +++ b/Bugsnag/BugsnagCrashSentry.h @@ -10,7 +10,9 @@ #import "BSG_KSCrashReportWriter.h" #import "BSG_KSCrashType.h" -#import "BugsnagConfiguration.h" + +@class BugsnagConfiguration; +@class BugsnagErrorTypes; @interface BugsnagCrashSentry : NSObject diff --git a/Bugsnag/BugsnagCrashSentry.m b/Bugsnag/BugsnagCrashSentry.m index be960b4bb..c3170a77f 100644 --- a/Bugsnag/BugsnagCrashSentry.m +++ b/Bugsnag/BugsnagCrashSentry.m @@ -11,8 +11,6 @@ #import "BSGFileLocations.h" #import "BSG_KSCrashAdvanced.h" -#import "BSG_KSCrashC.h" -#import "Bugsnag.h" #import "BugsnagConfiguration.h" #import "BugsnagErrorTypes.h" #import "BugsnagLogger.h" @@ -30,19 +28,11 @@ - (void)install:(BugsnagConfiguration *)config onCrash:(BSGReportCallback)onCras // applies to unhandled errors ksCrash.threadTracingEnabled = config.sendThreads != BSGThreadSendPolicyNever; - // User reported events do not go through KSCrash - BSG_KSCrashType crashTypes = 0; - - // If Bugsnag is autodetecting errors then the types of event detected is configurable - // (otherwise it's just the user reported events) - if (config.autoDetectErrors) { - // Translate the relevant BSGErrorTypes bitfield into the equivalent BSG_KSCrashType one - crashTypes = crashTypes | [self mapKSToBSGCrashTypes:config.enabledErrorTypes]; - } - - bsg_kscrash_setHandlingCrashTypes(crashTypes); - - if ((![ksCrash install:[BSGFileLocations current].kscrashReports])) { + BSG_KSCrashType crashTypes = config.autoDetectErrors ? [self mapKSToBSGCrashTypes:config.enabledErrorTypes] : 0; + + // In addition to installing crash handlers, -[BSG_KSCrash install:] initializes various + // subsystems that Bugsnag relies on, so needs to be called even if autoDetectErrors is disabled. + if ((![ksCrash install:crashTypes directory:[BSGFileLocations current].kscrashReports] && crashTypes)) { bsg_log_err(@"Failed to install crash handler. No exceptions will be reported!"); } } diff --git a/Bugsnag/BugsnagLastRunInfo.m b/Bugsnag/BugsnagLastRunInfo.m index 8ceb8d864..49f5bc50e 100644 --- a/Bugsnag/BugsnagLastRunInfo.m +++ b/Bugsnag/BugsnagLastRunInfo.m @@ -13,7 +13,7 @@ @implementation BugsnagLastRunInfo - (instancetype)initWithConsecutiveLaunchCrashes:(NSUInteger)consecutiveLaunchCrashes crashed:(BOOL)crashed crashedDuringLaunch:(BOOL)crashedDuringLaunch { - if (self = [super init]) { + if ((self = [super init])) { _consecutiveLaunchCrashes = consecutiveLaunchCrashes; _crashed = crashed; _crashedDuringLaunch = crashedDuringLaunch; diff --git a/Bugsnag/BugsnagSessionTracker.m b/Bugsnag/BugsnagSessionTracker.m index 28feab0d7..9d2cf2ea0 100644 --- a/Bugsnag/BugsnagSessionTracker.m +++ b/Bugsnag/BugsnagSessionTracker.m @@ -24,7 +24,7 @@ /** Number of seconds in background required to make a new session */ -NSTimeInterval const BSGNewSessionBackgroundDuration = 30; +static NSTimeInterval const BSGNewSessionBackgroundDuration = 30; NSString *const BSGSessionUpdateNotification = @"BugsnagSessionChanged"; @@ -48,7 +48,7 @@ @implementation BugsnagSessionTracker - (instancetype)initWithConfig:(BugsnagConfiguration *)config client:(BugsnagClient *)client postRecordCallback:(void(^)(BugsnagSession *))callback { - if (self = [super init]) { + if ((self = [super init])) { _config = config; _client = client; _apiClient = [[BugsnagSessionTrackingApiClient alloc] initWithConfig:config queueName:@"Session API queue" notifier:client.notifier]; @@ -62,7 +62,7 @@ - (instancetype)initWithConfig:(BugsnagConfiguration *)config - (void)setCodeBundleId:(NSString *)codeBundleId { _codeBundleId = codeBundleId; - _apiClient.codeBundleId = codeBundleId; + self.apiClient.codeBundleId = codeBundleId; } #pragma mark - Creating and sending a new session diff --git a/Bugsnag/BugsnagSystemState.m b/Bugsnag/BugsnagSystemState.m index d4ce2b1e8..18792e601 100644 --- a/Bugsnag/BugsnagSystemState.m +++ b/Bugsnag/BugsnagSystemState.m @@ -159,7 +159,7 @@ @interface BugsnagSystemState () @implementation BugsnagSystemState - (instancetype)initWithConfiguration:(BugsnagConfiguration *)config { - if (self = [super init]) { + if ((self = [super init])) { _kvStore = [BugsnagKVStore new]; _persistenceFilePath = [BSGFileLocations current].systemState; _lastLaunchState = loadPreviousState(_kvStore, _persistenceFilePath); diff --git a/Bugsnag/Client/BugsnagClient+AppHangs.h b/Bugsnag/Client/BugsnagClient+AppHangs.h index 56a4ef49e..40d540781 100644 --- a/Bugsnag/Client/BugsnagClient+AppHangs.h +++ b/Bugsnag/Client/BugsnagClient+AppHangs.h @@ -14,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN @interface BugsnagClient (AppHangs) -/// @Returns A `BugsnagEvent` if the last run ended with a fatal app hang, `nil` otherwise. +/// @return A `BugsnagEvent` if the last run ended with a fatal app hang, `nil` otherwise. - (nullable BugsnagEvent *)loadFatalAppHangEvent; - (void)startAppHangDetector; diff --git a/Bugsnag/Client/BugsnagClient+Private.h b/Bugsnag/Client/BugsnagClient+Private.h index 63e9d1630..61b950055 100644 --- a/Bugsnag/Client/BugsnagClient+Private.h +++ b/Bugsnag/Client/BugsnagClient+Private.h @@ -70,7 +70,7 @@ NS_ASSUME_NONNULL_BEGIN @property (strong, nonatomic) BugsnagSessionTracker *sessionTracker; // Used in BugsnagReactNative -@property (readonly, nonatomic) BOOL started; +@property (nonatomic) BOOL started; /// State related metadata /// diff --git a/Bugsnag/Client/BugsnagClient.m b/Bugsnag/Client/BugsnagClient.m index 98102d376..6d0edf2c4 100644 --- a/Bugsnag/Client/BugsnagClient.m +++ b/Bugsnag/Client/BugsnagClient.m @@ -31,6 +31,7 @@ #import "BSGConnectivity.h" #import "BSGEventUploader.h" #import "BSGFileLocations.h" +#import "BSGInternalErrorReporter.h" #import "BSGJSONSerialization.h" #import "BSGNotificationBreadcrumbs.h" #import "BSGSerialization.h" @@ -85,9 +86,9 @@ #import "BSGAppKit.h" #endif -NSString *const BSTabCrash = @"crash"; -NSString *const BSAttributeDepth = @"depth"; -NSString *const BSEventLowMemoryWarning = @"lowMemoryWarning"; +static NSString *const BSTabCrash = @"crash"; +static NSString *const BSAttributeDepth = @"depth"; +static NSString *const BSEventLowMemoryWarning = @"lowMemoryWarning"; static struct { // Contains the state of the event (handled/unhandled) @@ -165,30 +166,23 @@ void BSSerializeDataCrashHandler(const BSG_KSCrashReportWriter *writer, __attrib #if BSG_PLATFORM_IOS NSString *BSGOrientationNameFromEnum(UIDeviceOrientation deviceOrientation) { - NSString *orientation; switch (deviceOrientation) { - case UIDeviceOrientationPortraitUpsideDown: - orientation = @"portraitupsidedown"; - break; - case UIDeviceOrientationPortrait: - orientation = @"portrait"; - break; - case UIDeviceOrientationLandscapeRight: - orientation = @"landscaperight"; - break; - case UIDeviceOrientationLandscapeLeft: - orientation = @"landscapeleft"; - break; - case UIDeviceOrientationFaceUp: - orientation = @"faceup"; - break; - case UIDeviceOrientationFaceDown: - orientation = @"facedown"; - break; - default: - return nil; // always ignore unknown breadcrumbs + case UIDeviceOrientationPortraitUpsideDown: + return @"portraitupsidedown"; + case UIDeviceOrientationPortrait: + return @"portrait"; + case UIDeviceOrientationLandscapeRight: + return @"landscaperight"; + case UIDeviceOrientationLandscapeLeft: + return @"landscapeleft"; + case UIDeviceOrientationFaceUp: + return @"faceup"; + case UIDeviceOrientationFaceDown: + return @"facedown"; + case UIDeviceOrientationUnknown: + break; } - return orientation; + return nil; } #endif @@ -216,29 +210,28 @@ void BSGWriteSessionCrashData(BugsnagSession *session) { } // ============================================================================= -// MARK: - BugsnagClient -// ============================================================================= -@interface BugsnagClient () +// MARK: - + +@interface BugsnagClient () @property (nonatomic) BSGNotificationBreadcrumbs *notificationBreadcrumbs; @property (weak, nonatomic) NSTimer *appLaunchTimer; +@property (readwrite, nullable, nonatomic) BugsnagLastRunInfo *lastRunInfo; + @end +// MARK: - + #if __clang_major__ >= 11 // Xcode 10 does not like the following attribute __attribute__((annotate("oclint:suppress[long class]"))) __attribute__((annotate("oclint:suppress[too many methods]"))) #endif @implementation BugsnagClient -/** - * Storage for the device orientation. It is "last" whenever an orientation change is received - */ -NSString *_lastOrientation = nil; - @dynamic user; // This computed property should not have a backing ivar - (instancetype)initWithConfiguration:(BugsnagConfiguration *)configuration { @@ -318,6 +311,8 @@ - (instancetype)initWithConfiguration:(BugsnagConfiguration *)configuration { if (self.user.id == nil) { // populate with an autogenerated ID if no value set [self setUser:[BSG_KSSystemInfo deviceAndAppHash] withEmail:configuration.user.email andName:configuration.user.name]; } + + BSGInternalErrorReporter.sharedInstance = [[BSGInternalErrorReporter alloc] initWithDataSource:self]; } return self; } @@ -605,14 +600,6 @@ - (void)setCodeBundleId:(NSString *)codeBundleId { self.sessionTracker.codeBundleId = codeBundleId; } -- (void)setLastRunInfo:(BugsnagLastRunInfo *)lastRunInfo { - _lastRunInfo = lastRunInfo; -} - -- (void)setStarted:(BOOL)started { - _started = started; -} - /** * Removes observers and listeners to prevent allocations when the app is terminated */ @@ -1041,7 +1028,7 @@ - (void)orientationChanged:(NSNotification *)notification { // Short-circuit the exit if we don't have enough info to record a full breadcrumb // or the orientation hasn't changed (false positive). - if (!_lastOrientation || [orientation isEqualToString:_lastOrientation]) { + if (!self.lastOrientation || [orientation isEqualToString:self.lastOrientation]) { self.lastOrientation = orientation; return; } @@ -1052,7 +1039,7 @@ - (void)orientationChanged:(NSNotification *)notification { [self addAutoBreadcrumbOfType:BSGBreadcrumbTypeState withMessage:[self.notificationBreadcrumbs messageForNotificationName:notification.name] andMetadata:@{ - @"from" : _lastOrientation, + @"from" : self.lastOrientation, @"to" : orientation }]; @@ -1141,7 +1128,9 @@ - (BugsnagDeviceWithState *)generateDeviceWithState:(NSDictionary *)systemInfo { BugsnagDeviceWithState *device = [BugsnagDeviceWithState deviceWithKSCrashReport:@{@"system": systemInfo}]; device.time = [NSDate date]; // default to current time for handled errors [device appendRuntimeInfo:self.extraRuntimeInfo]; - device.orientation = _lastOrientation; +#if TARGET_OS_IOS + device.orientation = self.lastOrientation; +#endif return device; } diff --git a/Bugsnag/Configuration/BugsnagConfiguration+Private.h b/Bugsnag/Configuration/BugsnagConfiguration+Private.h index 4ecd91d96..6158e07e5 100644 --- a/Bugsnag/Configuration/BugsnagConfiguration+Private.h +++ b/Bugsnag/Configuration/BugsnagConfiguration+Private.h @@ -21,9 +21,9 @@ NS_ASSUME_NONNULL_BEGIN /// The user defaults database to use for persistence of user information. @property (class, nonatomic) NSUserDefaults *userDefaults; -@property (readonly) NSDictionary *dictionaryRepresentation; +@property (readonly, nonatomic) NSDictionary *dictionaryRepresentation; -@property (readonly, copy, nonatomic) BugsnagMetadata *metadata; +@property (copy, nonatomic) BugsnagMetadata *metadata; @property (readonly, nullable, nonatomic) NSURL *notifyURL; @@ -36,9 +36,9 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) NSMutableSet *plugins; -@property (readonly) BOOL shouldSendReports; +@property (readonly, nonatomic) BOOL shouldSendReports; -@property (readonly) NSDictionary *sessionApiHeaders; +@property (readonly, nonatomic) NSDictionary *sessionApiHeaders; @property (readonly, nullable, nonatomic) NSURL *sessionURL; diff --git a/Bugsnag/Configuration/BugsnagConfiguration.m b/Bugsnag/Configuration/BugsnagConfiguration.m index ab9601d85..30d428ed8 100644 --- a/Bugsnag/Configuration/BugsnagConfiguration.m +++ b/Bugsnag/Configuration/BugsnagConfiguration.m @@ -43,9 +43,9 @@ static const int BSGApiKeyLength = 32; // User info persistence keys -NSString * const kBugsnagUserEmailAddress = @"BugsnagUserEmailAddress"; -NSString * const kBugsnagUserName = @"BugsnagUserName"; -NSString * const kBugsnagUserUserId = @"BugsnagUserUserId"; +static NSString * const kBugsnagUserEmailAddress = @"BugsnagUserEmailAddress"; +static NSString * const kBugsnagUserName = @"BugsnagUserName"; +static NSString * const kBugsnagUserUserId = @"BugsnagUserUserId"; // ============================================================================= // MARK: - BugsnagConfiguration @@ -169,10 +169,8 @@ - (instancetype)initWithApiKey:(NSString *)apiKey { } _metadata = [[BugsnagMetadata alloc] init]; _endpoints = [BugsnagEndpointConfiguration new]; - _sessionURL = [NSURL URLWithString:@"https://sessions.bugsnag.com"]; _autoDetectErrors = YES; _appHangThresholdMillis = BugsnagAppHangThresholdFatalOnly; - _notifyURL = [NSURL URLWithString:BSGDefaultNotifyUrl]; _onSendBlocks = [NSMutableArray new]; _onSessionBlocks = [NSMutableArray new]; _onBreadcrumbBlocks = [NSMutableArray new]; @@ -338,19 +336,23 @@ - (NSDictionary *)sessionApiHeaders { } - (void)setEndpoints:(BugsnagEndpointConfiguration *)endpoints { - _endpoints = endpoints; - self.notifyURL = [NSURL URLWithString:endpoints.notify]; - self.sessionURL = [NSURL URLWithString:endpoints.sessions]; - - // This causes a crash under DEBUG but is ignored in production - NSAssert([self isValidUrl:_notifyURL], @"Invalid URL supplied for notify endpoint"); - - if (![self isValidUrl:_sessionURL]) { - self.sessionURL = nil; + if ([self isValidURLString:endpoints.notify]) { + _endpoints.notify = [endpoints.notify copy]; + } else { + // This causes a crash under DEBUG but is ignored in production + NSAssert(NO, @"Invalid URL supplied for notify endpoint"); + _endpoints.notify = @""; + } + if ([self isValidURLString:endpoints.sessions]) { + _endpoints.sessions = [endpoints.sessions copy]; + } else { + bsg_log_err(@"Invalid URL supplied for session endpoint"); + _endpoints.sessions = @""; } } -- (BOOL)isValidUrl:(NSURL *)url { +- (BOOL)isValidURLString:(NSString *)URLString { + NSURL *url = [NSURL URLWithString:URLString]; return url != nil && url.scheme != nil && url.host != nil; } @@ -399,26 +401,26 @@ - (BugsnagUser *)getPersistedUserData { */ - (void)persistUserData { @synchronized(self) { - if (_user) { + if (self.user) { // Email - if (_user.email) { - [userDefaults setObject:_user.email forKey:kBugsnagUserEmailAddress]; + if (self.user.email) { + [userDefaults setObject:self.user.email forKey:kBugsnagUserEmailAddress]; } else { [userDefaults removeObjectForKey:kBugsnagUserEmailAddress]; } // Name - if (_user.name) { - [userDefaults setObject:_user.name forKey:kBugsnagUserName]; + if (self.user.name) { + [userDefaults setObject:self.user.name forKey:kBugsnagUserName]; } else { [userDefaults removeObjectForKey:kBugsnagUserName]; } // UserId - if (_user.id) { - [userDefaults setObject:_user.id forKey:kBugsnagUserUserId]; + if (self.user.id) { + [userDefaults setObject:self.user.id forKey:kBugsnagUserUserId]; } else { [userDefaults removeObjectForKey:kBugsnagUserUserId]; @@ -496,16 +498,12 @@ - (void)setMaxBreadcrumbs:(NSUInteger)maxBreadcrumbs { } } -- (void)setMetadata:(BugsnagMetadata *)metadata { - _metadata = [metadata deepCopy]; -} - -- (void)setNotifyURL:(NSURL *)notifyURL { - _notifyURL = notifyURL; +- (NSURL *)notifyURL { + return self.endpoints.notify.length ? [NSURL URLWithString:self.endpoints.notify] : nil; } -- (void)setSessionURL:(NSURL *)sessionURL { - _sessionURL = sessionURL; +- (NSURL *)sessionURL { + return self.endpoints.sessions.length ? [NSURL URLWithString:self.endpoints.sessions] : nil; } - (BOOL)shouldDiscardErrorClass:(NSString *)errorClass { @@ -589,7 +587,7 @@ - (void)validate { // MARK: - - (void)addPlugin:(id _Nonnull)plugin { - [_plugins addObject:plugin]; + [self.plugins addObject:plugin]; } // MARK: - @@ -613,7 +611,7 @@ - (id _Nullable)getMetadataFromSection:(NSString *_Nonnull)sectionName return [self.metadata getMetadataFromSection:sectionName withKey:key]; } -- (NSDictionary *_Nullable)getMetadataFromSection:(NSString *_Nonnull)sectionName +- (NSMutableDictionary *)getMetadataFromSection:(NSString *_Nonnull)sectionName { return [self.metadata getMetadataFromSection:sectionName]; } diff --git a/Bugsnag/Configuration/BugsnagEndpointConfiguration.m b/Bugsnag/Configuration/BugsnagEndpointConfiguration.m index a0300115e..870199b47 100644 --- a/Bugsnag/Configuration/BugsnagEndpointConfiguration.m +++ b/Bugsnag/Configuration/BugsnagEndpointConfiguration.m @@ -11,7 +11,7 @@ @implementation BugsnagEndpointConfiguration - (instancetype)init { - if (self = [super init]) { + if ((self = [super init])) { _notify = @"https://notify.bugsnag.com"; _sessions = @"https://sessions.bugsnag.com"; } @@ -19,7 +19,7 @@ - (instancetype)init { } - (instancetype)initWithNotify:(NSString *)notify sessions:(NSString *)sessions { - if (self = [super init]) { + if ((self = [super init])) { _notify = notify; _sessions = sessions; } diff --git a/Bugsnag/Configuration/BugsnagErrorTypes.m b/Bugsnag/Configuration/BugsnagErrorTypes.m index 51bddb5bd..00d4da7a0 100644 --- a/Bugsnag/Configuration/BugsnagErrorTypes.m +++ b/Bugsnag/Configuration/BugsnagErrorTypes.m @@ -11,7 +11,7 @@ @implementation BugsnagErrorTypes - (instancetype)init { - if (self = [super init]) { + if ((self = [super init])) { _appHangs = YES; _unhandledExceptions = YES; _signals = YES; diff --git a/Bugsnag/Delivery/BSGConnectivity.m b/Bugsnag/Delivery/BSGConnectivity.m index cf8a08e3e..1a405a0c5 100644 --- a/Bugsnag/Delivery/BSGConnectivity.m +++ b/Bugsnag/Delivery/BSGConnectivity.m @@ -32,12 +32,12 @@ static const SCNetworkReachabilityFlags kSCNetworkReachabilityFlagsUninitialized = UINT32_MAX; static SCNetworkReachabilityRef bsg_reachability_ref; -BSGConnectivityChangeBlock bsg_reachability_change_block; +static BSGConnectivityChangeBlock bsg_reachability_change_block; static SCNetworkReachabilityFlags bsg_current_reachability_state = kSCNetworkReachabilityFlagsUninitialized; -NSString *const BSGConnectivityCellular = @"cellular"; -NSString *const BSGConnectivityWiFi = @"wifi"; -NSString *const BSGConnectivityNone = @"none"; +static NSString *const BSGConnectivityCellular = @"cellular"; +static NSString *const BSGConnectivityWiFi = @"wifi"; +static NSString *const BSGConnectivityNone = @"none"; /** * Check whether the connectivity change should be noted or ignored. diff --git a/Bugsnag/Delivery/BSGEventUploadFileOperation.m b/Bugsnag/Delivery/BSGEventUploadFileOperation.m index 8a9a6fb3d..8cd99cd9f 100644 --- a/Bugsnag/Delivery/BSGEventUploadFileOperation.m +++ b/Bugsnag/Delivery/BSGEventUploadFileOperation.m @@ -17,7 +17,7 @@ @implementation BSGEventUploadFileOperation - (instancetype)initWithFile:(NSString *)file delegate:(id)delegate { - if (self = [super initWithDelegate:delegate]) { + if ((self = [super initWithDelegate:delegate])) { _file = [file copy]; } return self; diff --git a/Bugsnag/Delivery/BSGEventUploadKSCrashReportOperation.m b/Bugsnag/Delivery/BSGEventUploadKSCrashReportOperation.m index 493f76c84..7028778de 100644 --- a/Bugsnag/Delivery/BSGEventUploadKSCrashReportOperation.m +++ b/Bugsnag/Delivery/BSGEventUploadKSCrashReportOperation.m @@ -8,6 +8,7 @@ #import "BSGEventUploadKSCrashReportOperation.h" +#import "BSGInternalErrorReporter.h" #import "BSGJSONSerialization.h" #import "BSG_KSCrashDoctor.h" #import "BSG_KSCrashReportFields.h" @@ -22,17 +23,41 @@ @implementation BSGEventUploadKSCrashReportOperation - (BugsnagEvent *)loadEventAndReturnError:(NSError * __autoreleasing *)errorPtr { - id json = [BSGJSONSerialization JSONObjectWithContentsOfFile:self.file options:0 error:errorPtr]; - if (!json) { + NSError *error = nil; + + NSData *data = [NSData dataWithContentsOfFile:self.file options:0 error:&error]; + if (!data) { + [BSGInternalErrorReporter.sharedInstance reportErrorWithClass:@"File reading error" + message:BSGErrorDescription(error) + diagnostics:error.userInfo]; + if (errorPtr) { + *errorPtr = error; + } return nil; } - json = [self fixupCrashReport:json]; + id json = [BSGJSONSerialization JSONObjectWithData:data options:0 error:&error]; if (!json) { + NSMutableDictionary *diagnostics = [NSMutableDictionary dictionary]; + diagnostics[@"data"] = [data base64EncodedStringWithOptions:0]; + [BSGInternalErrorReporter.sharedInstance reportErrorWithClass:@"JSON parsing error" + message:BSGErrorDescription(error) + diagnostics:diagnostics]; + if (errorPtr) { + *errorPtr = error; + } + return nil; + } + + NSDictionary *crashReport = [self fixupCrashReport:json]; + if (!crashReport) { + [BSGInternalErrorReporter.sharedInstance reportErrorWithClass:@"Unexpected JSON payload" + message:@"-fixupCrashReport: returned nil" + diagnostics:@{@"json": json}]; return nil; } - BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:json]; + BugsnagEvent *event = [[BugsnagEvent alloc] initWithKSReport:crashReport]; if (!event.app.type) { // Use current value for crashes from older notifier versions that didn't persist config.appType diff --git a/Bugsnag/Delivery/BSGEventUploadObjectOperation.m b/Bugsnag/Delivery/BSGEventUploadObjectOperation.m index 579b16e79..04cbb010a 100644 --- a/Bugsnag/Delivery/BSGEventUploadObjectOperation.m +++ b/Bugsnag/Delivery/BSGEventUploadObjectOperation.m @@ -14,7 +14,7 @@ @implementation BSGEventUploadObjectOperation - (instancetype)initWithEvent:(BugsnagEvent *)event delegate:(id)delegate { - if (self = [super initWithDelegate:delegate]) { + if ((self = [super initWithDelegate:delegate])) { _event = event; } return self; diff --git a/Bugsnag/Delivery/BSGEventUploadOperation.m b/Bugsnag/Delivery/BSGEventUploadOperation.m index eabf68445..c73589ecf 100644 --- a/Bugsnag/Delivery/BSGEventUploadOperation.m +++ b/Bugsnag/Delivery/BSGEventUploadOperation.m @@ -38,7 +38,7 @@ @interface BSGEventUploadOperation () @implementation BSGEventUploadOperation - (instancetype)initWithDelegate:(id)delegate { - if (self = [super init]) { + if ((self = [super init])) { _delegate = delegate; } return self; diff --git a/Bugsnag/Delivery/BSGEventUploader.m b/Bugsnag/Delivery/BSGEventUploader.m index ec9161242..ddeb3015f 100644 --- a/Bugsnag/Delivery/BSGEventUploader.m +++ b/Bugsnag/Delivery/BSGEventUploader.m @@ -39,7 +39,7 @@ @implementation BSGEventUploader @synthesize notifier = _notifier; - (instancetype)initWithConfiguration:(BugsnagConfiguration *)configuration notifier:(BugsnagNotifier *)notifier { - if (self = [super init]) { + if ((self = [super init])) { _apiClient = [[BugsnagApiClient alloc] initWithSession:configuration.session queueName:@""]; _configuration = configuration; _eventsDirectory = [BSGFileLocations current].events; diff --git a/Bugsnag/Delivery/BugsnagApiClient.h b/Bugsnag/Delivery/BugsnagApiClient.h index b487b48a1..05016f72f 100644 --- a/Bugsnag/Delivery/BugsnagApiClient.h +++ b/Bugsnag/Delivery/BugsnagApiClient.h @@ -40,7 +40,7 @@ typedef NS_ENUM(NSInteger, BugsnagApiClientDeliveryStatus) { toURL:(NSURL *)url completionHandler:(void (^)(BugsnagApiClientDeliveryStatus status, NSError * _Nullable error))completionHandler; -- (NSString *)SHA1HashStringWithData:(NSData *)data; ++ (NSString *)SHA1HashStringWithData:(NSData *)data; @property (readonly, nonatomic) NSOperationQueue *sendQueue; diff --git a/Bugsnag/Delivery/BugsnagApiClient.m b/Bugsnag/Delivery/BugsnagApiClient.m index e3ede19bb..3a17ec2d4 100644 --- a/Bugsnag/Delivery/BugsnagApiClient.m +++ b/Bugsnag/Delivery/BugsnagApiClient.m @@ -43,7 +43,7 @@ @interface BugsnagApiClient() @implementation BugsnagApiClient - (instancetype)initWithSession:(nullable NSURLSession *)session queueName:(NSString *)queueName { - if (self = [super init]) { + if ((self = [super init])) { _sendQueue = [NSOperationQueue new]; _sendQueue.maxConcurrentOperationCount = 1; if ([_sendQueue respondsToSelector:@selector(qualityOfService)]) { @@ -90,7 +90,7 @@ - (void)sendJSONPayload:(NSDictionary *)payload } NSMutableDictionary *mutableHeaders = [headers mutableCopy]; - mutableHeaders[BugsnagHTTPHeaderNameIntegrity] = [NSString stringWithFormat:@"sha1 %@", [self SHA1HashStringWithData:data]]; + mutableHeaders[BugsnagHTTPHeaderNameIntegrity] = [NSString stringWithFormat:@"sha1 %@", [BugsnagApiClient SHA1HashStringWithData:data]]; NSMutableURLRequest *request = [self prepareRequest:url headers:mutableHeaders]; bsg_log_debug(@"Sending %lu byte payload to %@", (unsigned long)data.length, url); @@ -120,7 +120,7 @@ - (void)sendJSONPayload:(NSDictionary *)payload NSURLErrorFailingURLErrorKey: url }]; bsg_log_debug(@"Response headers: %@", ((NSHTTPURLResponse *)response).allHeaderFields); - bsg_log_debug(@"Response body: %.*s", (int)data.length, data.bytes); + bsg_log_debug(@"Response body: %.*s", (int)data.length, (const char *)data.bytes); if (statusCode / 100 == 4 && statusCode != HTTPStatusCodePaymentRequired && @@ -150,7 +150,7 @@ - (NSMutableURLRequest *)prepareRequest:(NSURL *)url return request; } -- (NSString *)SHA1HashStringWithData:(NSData *)data { ++ (NSString *)SHA1HashStringWithData:(NSData *)data { if (!data) { return nil; } diff --git a/Bugsnag/Helpers/BSGAppHangDetector.m b/Bugsnag/Helpers/BSGAppHangDetector.m index c05652bf9..2898de6cb 100644 --- a/Bugsnag/Helpers/BSGAppHangDetector.m +++ b/Bugsnag/Helpers/BSGAppHangDetector.m @@ -36,7 +36,7 @@ @implementation BSGAppHangDetector #if TARGET_OS_IOS - (instancetype)init { - if (self = [super init]) { + if ((self = [super init])) { [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(applicationDidEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil]; diff --git a/Bugsnag/Helpers/BSGInternalErrorReporter.h b/Bugsnag/Helpers/BSGInternalErrorReporter.h new file mode 100644 index 000000000..881640bcc --- /dev/null +++ b/Bugsnag/Helpers/BSGInternalErrorReporter.h @@ -0,0 +1,66 @@ +// +// BSGInternalErrorReporter.h +// Bugsnag +// +// Created by Nick Dowell on 06/05/2021. +// Copyright © 2021 Bugsnag Inc. All rights reserved. +// + +#import + +@class BugsnagAppWithState; +@class BugsnagConfiguration; +@class BugsnagDeviceWithState; +@class BugsnagEvent; +@class BugsnagNotifier; + +NS_ASSUME_NONNULL_BEGIN + +/// Returns a concise desription of the error including its domain, code, and debug description or localizedDescription. +FOUNDATION_EXPORT NSString *BSGErrorDescription(NSError *error); + +// MARK: - + +@protocol BSGInternalErrorReporterDataSource + +@property (readonly, nonatomic) BugsnagConfiguration *configuration; + +@property (readonly, nonatomic) BugsnagNotifier *notifier; + +- (BugsnagAppWithState *)generateAppWithState:(NSDictionary *)systemInfo; + +- (BugsnagDeviceWithState *)generateDeviceWithState:(NSDictionary *)systemInfo; + +@end + +// MARK: - + +@interface BSGInternalErrorReporter : NSObject + +@property (class, nonatomic) BSGInternalErrorReporter *sharedInstance; + +- (instancetype)initWithDataSource:(id)dataSource NS_DESIGNATED_INITIALIZER; + +- (instancetype)init UNAVAILABLE_ATTRIBUTE; + +/// Reports an error to Bugsnag's internal bugsnag-cocoa project dashboard. +/// @param errorClass The class of error which occurred. This field is used to group the errors together so should not contain any contextual +/// information that would prevent correct grouping. This would ordinarily be the Exception name when dealing with an exception. +/// @param message The error message associated with the error. Usually this will contain some information about this specific instance of the error +/// and is not used to group the errors. +/// @param diagnostics JSON compatible information to include in the `BugsnagDiagnostics` metadata section. +- (void)reportErrorWithClass:(NSString *)errorClass + message:(nullable NSString *)message + diagnostics:(nullable NSDictionary *)diagnostics; + +// Private + +- (nullable BugsnagEvent *)eventWithErrorClass:(NSString *)errorClass + message:(nullable NSString *)message + diagnostics:(nullable NSDictionary *)diagnostics; + +- (nullable NSURLRequest *)requestForEvent:(BugsnagEvent *)event error:(NSError * __autoreleasing *)errorPtr; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Bugsnag/Helpers/BSGInternalErrorReporter.m b/Bugsnag/Helpers/BSGInternalErrorReporter.m new file mode 100644 index 000000000..c07037ea3 --- /dev/null +++ b/Bugsnag/Helpers/BSGInternalErrorReporter.m @@ -0,0 +1,177 @@ +// +// BSGInternalErrorReporter.m +// Bugsnag +// +// Created by Nick Dowell on 06/05/2021. +// Copyright © 2021 Bugsnag Inc. All rights reserved. +// + +#import "BSGInternalErrorReporter.h" + +#import "BSG_KSSystemInfo.h" +#import "BSG_RFC3339DateTool.h" +#import "BugsnagApiClient.h" +#import "BugsnagAppWithState+Private.h" +#import "BugsnagCollections.h" +#import "BugsnagConfiguration+Private.h" +#import "BugsnagDeviceWithState+Private.h" +#import "BugsnagError+Private.h" +#import "BugsnagEvent+Private.h" +#import "BugsnagHandledState.h" +#import "BugsnagKeys.h" +#import "BugsnagLogger.h" +#import "BugsnagMetadata+Private.h" +#import "BugsnagNotifier.h" +#import "BugsnagStackframe+Private.h" +#import "BugsnagUser+Private.h" + +static NSString * const EventPayloadVersion = @"4.0"; + +static NSString * const BugsnagDiagnosticsKey = @"BugsnagDiagnostics"; + +static BugsnagHTTPHeaderName const BugsnagHTTPHeaderNameInternalError = @"Bugsnag-Internal-Error"; + + +NSString *BSGErrorDescription(NSError *error) { + return [NSString stringWithFormat:@"%@ %ld: %@", error.domain, (long)error.code, + error.userInfo[NSDebugDescriptionErrorKey] ?: error.localizedDescription]; +} + + +// MARK: - + +@interface BSGInternalErrorReporter () + +@property (weak, nullable, nonatomic) id dataSource; +@property (nonatomic) NSURLSession *session; + +@end + + +@implementation BSGInternalErrorReporter + +static BSGInternalErrorReporter *sharedInstance_; + ++ (BSGInternalErrorReporter *)sharedInstance { + return sharedInstance_; +} + ++ (void)setSharedInstance:(BSGInternalErrorReporter *)sharedInstance { + sharedInstance_ = sharedInstance; +} + +- (instancetype)initWithDataSource:(id)dataSource { + if ((self = [super init])) { + _dataSource = dataSource; + _session = [NSURLSession sessionWithConfiguration:NSURLSessionConfiguration.ephemeralSessionConfiguration]; + } + return self; +} + +// MARK: Public API + +- (void)reportErrorWithClass:(NSString *)errorClass + message:(nullable NSString *)message + diagnostics:(nullable NSDictionary *)diagnostics { + @try { + BugsnagEvent *event = [self eventWithErrorClass:errorClass message:message diagnostics:diagnostics]; + if (event) { + [self sendEvent:event]; + } + } @catch (NSException *exception) { + bsg_log_err(@"%@", exception); + } +} + +// MARK: Private API + +- (nullable BugsnagEvent *)eventWithErrorClass:(NSString *)errorClass + message:(nullable NSString *)message + diagnostics:(nullable NSDictionary *)diagnostics { + id dataSource = self.dataSource; + if (!dataSource) { + return nil; + } + + BugsnagMetadata *metadata = [[BugsnagMetadata alloc] init]; + if (diagnostics) { + [metadata addMetadata:(NSDictionary * _Nonnull)diagnostics toSection:BugsnagDiagnosticsKey]; + } + [metadata addMetadata:dataSource.configuration.apiKey withKey:BSGKeyApiKey toSection:BugsnagDiagnosticsKey]; + + NSArray *stacktrace = [BugsnagStackframe stackframesWithCallStackReturnAddresses: + BSGArraySubarrayFromIndex(NSThread.callStackReturnAddresses, 2)]; + + BugsnagError *error = + [[BugsnagError alloc] initWithErrorClass:errorClass + errorMessage:message + errorType:BSGErrorTypeCocoa + stacktrace:stacktrace]; + + NSDictionary *systemInfo = [BSG_KSSystemInfo systemInfo]; + + BugsnagEvent *event = + [[BugsnagEvent alloc] initWithApp:[dataSource generateAppWithState:systemInfo] + device:[dataSource generateDeviceWithState:systemInfo] + handledState:[BugsnagHandledState handledStateWithSeverityReason:HandledError] + user:[[BugsnagUser alloc] init] + metadata:metadata + breadcrumbs:@[] + errors:@[error] + threads:@[] + session:nil]; + + return event; +} + +- (NSURLRequest *)requestForEvent:(nonnull BugsnagEvent *)event error:(NSError * __autoreleasing *)errorPtr { + id dataSource = self.dataSource; + if (!dataSource) { + return nil; + } + + NSURL *url = dataSource.configuration.notifyURL; + if (!url) { + if (errorPtr) { + *errorPtr = [NSError errorWithDomain:@"BugsnagConfigurationErrorDomain" code:0 + userInfo:@{NSLocalizedDescriptionKey: @"Missing notify URL"}]; + } + return nil; + } + + NSMutableDictionary *requestPayload = [NSMutableDictionary dictionary]; + requestPayload[BSGKeyEvents] = @[[event toJsonWithRedactedKeys:nil]]; + requestPayload[BSGKeyNotifier] = [dataSource.notifier toDict]; + requestPayload[BSGKeyPayloadVersion] = EventPayloadVersion; + + NSData *data = [NSJSONSerialization dataWithJSONObject:requestPayload options:0 error:errorPtr]; + if (!data) { + return nil; + } + + NSMutableDictionary *headers = [NSMutableDictionary dictionary]; + headers[@"Content-Type"] = @"application/json"; + headers[BugsnagHTTPHeaderNameIntegrity] = [NSString stringWithFormat:@"sha1 %@", [BugsnagApiClient SHA1HashStringWithData:data]]; + headers[BugsnagHTTPHeaderNameInternalError] = @"bugsnag-cocoa"; + headers[BugsnagHTTPHeaderNamePayloadVersion] = EventPayloadVersion; + headers[BugsnagHTTPHeaderNameSentAt] = [BSG_RFC3339DateTool stringFromDate:[NSDate date]]; + + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + request.allHTTPHeaderFields = headers; + request.HTTPBody = data; + request.HTTPMethod = @"POST"; + + return request; +} + +- (void)sendEvent:(nonnull BugsnagEvent *)event { + NSError *error = nil; + NSURLRequest *request = [self requestForEvent:event error:&error]; + if (!request) { + bsg_log_err(@"%@", error); + return; + } + [[self.session dataTaskWithRequest:request] resume]; +} + +@end diff --git a/Bugsnag/Helpers/BugsnagKVStoreObjC.m b/Bugsnag/Helpers/BugsnagKVStoreObjC.m index f5a1c69ef..80f1da594 100644 --- a/Bugsnag/Helpers/BugsnagKVStoreObjC.m +++ b/Bugsnag/Helpers/BugsnagKVStoreObjC.m @@ -11,8 +11,6 @@ #import "BSGFileLocations.h" #import "BugsnagLogger.h" -#define KV_DIR @"bsg_kvstore" - static void bsgkv_init() { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ diff --git a/Bugsnag/Helpers/BugsnagKeys.h b/Bugsnag/Helpers/BugsnagKeys.h index e7e6b4f9e..8c03d6e6d 100644 --- a/Bugsnag/Helpers/BugsnagKeys.h +++ b/Bugsnag/Helpers/BugsnagKeys.h @@ -6,12 +6,8 @@ // Copyright © 2017 Bugsnag. All rights reserved. // -#ifndef BugsnagKeys_h -#define BugsnagKeys_h - #import -extern NSString *const BSGDefaultNotifyUrl; extern NSString *const BSGKeyAction; extern NSString *const BSGKeyApiKey; extern NSString *const BSGKeyApp; @@ -44,7 +40,6 @@ extern NSString *const BSGKeyExceptions; extern NSString *const BSGKeyExecutableName; extern NSString *const BSGKeyExtraRuntimeInfo; extern NSString *const BSGKeyFrameAddress; -extern NSString *const BSGKeyFrameAddrFormat; extern NSString *const BSGKeyGroupingHash; extern NSString *const BSGKeyId; extern NSString *const BSGKeyImageAddress; @@ -107,5 +102,3 @@ extern NSString *const BSGKeyWarning; #define BSGKeyHwCputype "hw.cputype" #define BSGKeyHwCpusubtype "hw.cpusubtype" #define BSGKeyDefaultMacName "en0" - -#endif /* BugsnagKeys_h */ diff --git a/Bugsnag/Helpers/BugsnagKeys.m b/Bugsnag/Helpers/BugsnagKeys.m index f74ec3319..1cdcb8d71 100644 --- a/Bugsnag/Helpers/BugsnagKeys.m +++ b/Bugsnag/Helpers/BugsnagKeys.m @@ -5,9 +5,8 @@ // Created by Robin Macharg on 22/05/2020. // -#import +#import "BugsnagKeys.h" -NSString *const BSGDefaultNotifyUrl = @"https://notify.bugsnag.com/"; NSString *const BSGKeyAction = @"action"; NSString *const BSGKeyApiKey = @"apiKey"; NSString *const BSGKeyApp = @"app"; @@ -40,7 +39,6 @@ NSString *const BSGKeyExecutableName = @"CFBundleExecutable"; NSString *const BSGKeyExtraRuntimeInfo = @"extraRuntimeInfo"; NSString *const BSGKeyFrameAddress = @"frameAddress"; -NSString *const BSGKeyFrameAddrFormat = @"0x%lx"; NSString *const BSGKeyGroupingHash = @"groupingHash"; NSString *const BSGKeyId = @"id"; NSString *const BSGKeyImageAddress = @"image_addr"; diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.h index 022f089c9..bc2ee5da7 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.h @@ -44,12 +44,6 @@ */ @property(nonatomic, readwrite, retain) NSDictionary *userInfo; -/** The crash types that are being handled. - * Note: This value may change once BSG_KSCrash is installed if some handlers - * fail to install. - */ -@property(nonatomic, readwrite, assign) BSG_KSCrashType handlingCrashTypes; - /** If YES, introspect memory contents during a crash. * Any Objective-C objects or C strings near the stack pointer or referenced by * cpu registers or exceptions will be recorded in the crash report, along with @@ -63,13 +57,13 @@ */ + (BSG_KSCrash *)sharedInstance; -/** Install the crash reporter. - * The reporter will record crashes, but will not send any crash reports unless - * sink is set. +/** + * Install the crash reporter. * - * @return YES if the reporter successfully installed. + * @return The crash types that are now behing handled, representing the crash + * sentries that were successfully installed. */ -- (BOOL)install:(NSString *)directory; +- (BSG_KSCrashType)install:(BSG_KSCrashType)crashTypes directory:(NSString *)directory; /** * Collects information about the application's foreground state (duration in foreground/background) diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m index 348ff54a8..0908452c8 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m @@ -50,19 +50,10 @@ #import "BSGAppKit.h" #endif -// ============================================================================ -#pragma mark - Default Constants - -// ============================================================================ - -#ifndef BSG_INITIAL_MACH_BINARY_IMAGE_ARRAY_SIZE -#define BSG_INITIAL_MACH_BINARY_IMAGE_ARRAY_SIZE 400 -#endif - // ============================================================================ #pragma mark - Constants - // ============================================================================ -#define BSG_kCrashLogFilenameSuffix "-CrashLog.txt" #define BSG_kCrashStateFilenameSuffix "-CrashState.json" // ============================================================================ @@ -89,7 +80,6 @@ @implementation BSG_KSCrash // ============================================================================ @synthesize userInfo = _userInfo; -@synthesize handlingCrashTypes = _handlingCrashTypes; @synthesize printTraceToStdout = _printTraceToStdout; @synthesize onCrash = _onCrash; @synthesize bundleName = _bundleName; @@ -146,10 +136,6 @@ - (void)setUserInfo:(NSDictionary *)userInfo { bsg_kscrash_setUserInfoJSON([userInfoJSON bytes]); } -- (void)setHandlingCrashTypes:(BSG_KSCrashType)handlingCrashTypes { - _handlingCrashTypes = bsg_kscrash_setHandlingCrashTypes(handlingCrashTypes); -} - - (void)setPrintTraceToStdout:(bool)printTraceToStdout { _printTraceToStdout = printTraceToStdout; bsg_kscrash_setPrintTraceToStdout(printTraceToStdout); @@ -175,22 +161,24 @@ - (void)setThreadTracingEnabled:(BOOL)threadTracingEnabled { bsg_kscrash_setThreadTracingEnabled(threadTracingEnabled); } -- (BOOL)install:(NSString *)directory { +- (BSG_KSCrashType)install:(BSG_KSCrashType)crashTypes directory:(NSString *)directory { bsg_kscrash_generate_report_initialize(directory.fileSystemRepresentation, self.bundleName.UTF8String); - char *crashReportPath = (char *)bsg_kscrash_generate_report_path(self.nextCrashID.UTF8String, false); - char *recrashReportPath = (char *)bsg_kscrash_generate_report_path(self.nextCrashID.UTF8String, true); + char *crashReportPath = bsg_kscrash_generate_report_path(self.nextCrashID.UTF8String, false); + char *recrashReportPath = bsg_kscrash_generate_report_path(self.nextCrashID.UTF8String, true); NSString *stateFilePath = [directory stringByAppendingPathComponent: [self.bundleName stringByAppendingString:@BSG_kCrashStateFilenameSuffix]]; - self.handlingCrashTypes = bsg_kscrash_install( + bsg_kscrash_setHandlingCrashTypes(crashTypes); + + BSG_KSCrashType installedCrashTypes = bsg_kscrash_install( crashReportPath, recrashReportPath, [stateFilePath UTF8String], [self.nextCrashID UTF8String]); free(crashReportPath); free(recrashReportPath); - if (self.handlingCrashTypes == 0) { - return false; + if (!installedCrashTypes) { + return 0; } NSNotificationCenter *nCenter = [NSNotificationCenter defaultCenter]; @@ -231,7 +219,7 @@ - (BOOL)install:(NSString *)directory { object:nil]; #endif - return true; + return installedCrashTypes; } - (NSDictionary *)captureAppStats { diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.c b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.c index 047305b9f..7b3a4f0ba 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.c +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.c @@ -137,12 +137,12 @@ void bsg_kscrash_reinstall(const char *const crashReportFilePath, BSG_KSLOG_TRACE("stateFilePath = %s", stateFilePath); BSG_KSLOG_TRACE("crashID = %s", crashID); - bsg_ksstring_replace((const char **)&bsg_g_stateFilePath, stateFilePath); + bsg_ksstring_replace(&bsg_g_stateFilePath, stateFilePath); BSG_KSCrash_Context *context = crashContext(); - bsg_ksstring_replace((const char **)&context->config.crashReportFilePath, + bsg_ksstring_replace(&context->config.crashReportFilePath, crashReportFilePath); - bsg_ksstring_replace((const char **)&context->config.recrashReportFilePath, + bsg_ksstring_replace(&context->config.recrashReportFilePath, recrashReportFilePath); bsg_ksstring_replace(&context->config.crashID, crashID); diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashContext.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashContext.h index 704f03665..321af1061 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashContext.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashContext.h @@ -52,16 +52,16 @@ typedef struct { typedef struct { /** A unique identifier (UUID). */ - const char *crashID; + char *crashID; /** Name of this process. */ - const char *processName; + char *processName; /** System information in JSON format (to be written to the report). */ - const char *systemInfoJSON; + char *systemInfoJSON; /** User information in JSON format (to be written to the report). */ - const char *userInfoJSON; + char *userInfoJSON; /** When writing the crash report, print a stack trace to STDOUT as well. */ bool printTraceToStdout; @@ -80,12 +80,12 @@ typedef struct { /** * File path to write the crash report */ - const char *crashReportFilePath; + char *crashReportFilePath; /** * File path to write the recrash report, if the crash reporter crashes */ - const char *recrashReportFilePath; + char *recrashReportFilePath; } BSG_KSCrash_Configuration; /** Contextual data used by the crash report writer. diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashDoctor.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashDoctor.m index 9068abe91..28a016a1e 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashDoctor.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashDoctor.m @@ -10,8 +10,6 @@ #import "BSG_KSCrashReportFields.h" #import "BSG_KSSystemInfo.h" -#define BSG_kUserCrashHandler "kscrw_i_callUserCrashHandler" - typedef NS_ENUM(NSUInteger, BSG_CPUFamily) { BSG_CPUFamilyUnknown, BSG_CPUFamilyArm, diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashIdentifier.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashIdentifier.h index 5db0c7606..f023d3c34 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashIdentifier.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashIdentifier.h @@ -12,13 +12,12 @@ void bsg_kscrash_generate_report_initialize(const char *directory, const char *b * Generates a new UUID. Not async signal safe. Caller responsible for * freeing allocated string. */ -const char *bsg_kscrash_generate_report_identifier(void); +char *bsg_kscrash_generate_report_identifier(void); /** * Generates a new path string. Not async signal safe. Caller responsible * for freeing allocated string. */ -const char *bsg_kscrash_generate_report_path(const char *identifier, - bool is_recrash_report); +char *bsg_kscrash_generate_report_path(const char *identifier, bool is_recrash_report); #ifdef __cplusplus } diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashIdentifier.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashIdentifier.m index 0de0172fd..851741c51 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashIdentifier.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashIdentifier.m @@ -15,12 +15,11 @@ void bsg_kscrash_generate_report_initialize(const char *directory, const char *b bundle_name = bundleName ? strdup(bundleName) : NULL; } -const char *bsg_kscrash_generate_report_identifier(void) { +char *bsg_kscrash_generate_report_identifier(void) { return strdup([[[NSUUID UUID] UUIDString] UTF8String]); } -const char *bsg_kscrash_generate_report_path(const char *identifier, - bool is_recrash_report) { +char *bsg_kscrash_generate_report_path(const char *identifier, bool is_recrash_report) { if (identifier == NULL) { return NULL; } diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c index ed6ab2d21..3aa1b7222 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c @@ -80,13 +80,6 @@ typedef ucontext_t SignalUserContext; /** The minimum length for a valid string. */ #define BSG_kMinStringLength 4 -// ============================================================================ -#pragma mark - Thread Data Buffer - -// ============================================================================ - -#define BSG_THREAD_DATA_SIZE_INITIAL 128 * 1024 -#define BSG_THREAD_DATA_SIZE_INCREMENT 8 * 1024 - typedef struct { char *data; size_t allocated_size; @@ -329,7 +322,7 @@ int bsg_kscrw_i_addJSONData(const char *const data, const size_t length, * @return true if the address points to a string. */ bool bsg_kscrw_i_isValidString(const void *const address) { - if ((void *)address == NULL) { + if (!address) { return false; } @@ -386,7 +379,7 @@ BSG_STRUCT_MCONTEXT_L *bsg_kscrw_i_getMachineContext( BSG_STRUCT_MCONTEXT_L *const machineContextBuffer) { if (thread == crash->offendingThread) { if (crash->crashType == BSG_KSCrashTypeSignal) { - return ((SignalUserContext *)crash->signal.userContext) + return ((const SignalUserContext *)crash->signal.userContext) ->BSG_UC_MCONTEXT; } } @@ -498,7 +491,7 @@ void bsg_kscrw_i_logCrashType( bsg_ksmachexceptionName(machExceptionType); const char *machCodeName = machCode == 0 ? NULL : bsg_ksmachkernelReturnCodeName(machCode); - BSG_KSLOGBASIC_INFO("App crashed due to mach exception: [%s: %s] at %p", + BSG_KSLOGBASIC_INFO("App crashed due to mach exception: [%s: %s] at %lu", machExceptionName, machCodeName, sentryContext->faultAddress); break; @@ -520,7 +513,7 @@ void bsg_kscrw_i_logCrashType( int sigCode = sentryContext->signal.signalInfo->si_code; const char *sigName = bsg_kssignal_signalName(sigNum); const char *sigCodeName = bsg_kssignal_signalCodeName(sigNum, sigCode); - BSG_KSLOGBASIC_INFO("App crashed due to signal: [%s, %s] at %08x", + BSG_KSLOGBASIC_INFO("App crashed due to signal: [%s, %s] at %08lx", sigName, sigCodeName, sentryContext->faultAddress); break; } @@ -1430,7 +1423,7 @@ void bsg_kscrw_i_writeReportInfo(const BSG_KSCrashReportWriter *const writer, /** Prepare a report writer for use. * - * @oaram writer The writer to prepare. + * @param writer The writer to prepare. * * @param context JSON writer contextual information. */ diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m index 2709c1d9c..72a52578c 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m @@ -57,7 +57,6 @@ "backgroundDurationSinceLastCrash" #define BSG_kKeyLaunchesSinceLastCrash "launchesSinceLastCrash" #define BSG_kKeySessionsSinceLastCrash "sessionsSinceLastCrash" -#define BSG_kKeySessionsSinceLaunch "sessionsSinceLaunch" // ============================================================================ #pragma mark - Globals - diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m index 65c1ad156..a1e22e026 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfo.m @@ -190,7 +190,7 @@ + (NSDate *)dateSysctl:(NSString *)name { */ + (NSString *)uuidBytesToString:(const uint8_t *)uuidBytes { CFUUIDRef uuidRef = - CFUUIDCreateFromUUIDBytes(NULL, *((CFUUIDBytes *)uuidBytes)); + CFUUIDCreateFromUUIDBytes(NULL, *((const CFUUIDBytes *)uuidBytes)); NSString *str = (__bridge_transfer NSString *)CFUUIDCreateString(NULL, uuidRef); CFRelease(uuidRef); @@ -614,7 +614,7 @@ + (BOOL)isInForeground:(UIApplicationState)state { @end -const char *bsg_kssysteminfo_toJSON(void) { +char *bsg_kssysteminfo_toJSON(void) { NSError *error; NSMutableDictionary *systemInfo = [[BSG_KSSystemInfo systemInfo] mutableCopy]; diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfoC.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfoC.h index 9607142f8..9940cbbd2 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfoC.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/BSG_KSSystemInfoC.h @@ -38,7 +38,7 @@ extern "C" { * * @return System info as JSON. Caller is responsible for calling free(). */ -const char *bsg_kssysteminfo_toJSON(void); +char *bsg_kssysteminfo_toJSON(void); /** Create a copy of the current process name. * diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_CPPException.mm b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_CPPException.mm index 1b1b6daca..c6ff49e2d 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_CPPException.mm +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_CPPException.mm @@ -42,7 +42,6 @@ #define DESCRIPTION_BUFFER_LENGTH 1000 // Compiler hints for "if" statements -#define likely_if(x) if (__builtin_expect(x, 1)) #define unlikely_if(x) if (__builtin_expect(x, 0)) #ifdef __cplusplus diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSBacktrace.c b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSBacktrace.c index dae15bfcc..8b0bce89f 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSBacktrace.c +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSBacktrace.c @@ -34,7 +34,9 @@ * devices. Example usage, assuming the usage is guarded for __arm64__: * uintptr_t ptr_address = ptr & BSG_PACStrippingMaskArm64e; */ +#if defined(__arm64__) #define BSG_PACStrippingMaskArm64e 0x0000000fffffffff +#endif /** Remove any pointer tagging from an instruction address * On armv7 the least significant bit of the pointer distinguishes diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSDynamicLinker.c b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSDynamicLinker.c index d31812ac5..672157054 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSDynamicLinker.c +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSDynamicLinker.c @@ -74,7 +74,8 @@ bool bsg_ksdldladdr(const uintptr_t address, Dl_info *const info) { } info->dli_fname = image->name; - info->dli_fbase = (void *)image->header; + // Cast away constness because dli_fbase is not :'( + info->dli_fbase = (void *)(uintptr_t)image->header; // Find symbol tables and get whichever symbol is closest to the address. const BSG_STRUCT_NLIST *bestMatch = NULL; diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSJSONCodec.c b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSJSONCodec.c index e5059ce6f..ebaca0ead 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSJSONCodec.c +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSJSONCodec.c @@ -552,7 +552,7 @@ int bsg_ksjsonaddJSONElement(BSG_KSJSONEncodeContext *const context, case '9': break; default: - BSG_KSLOG_ERROR("Invalid character '%c' in: ", element[idx], element); + BSG_KSLOG_ERROR("Invalid character '%c' in: ", element[idx]); return BSG_KSJSON_ERROR_INVALID_DATA; } @@ -619,8 +619,8 @@ int bsg_ksjsonbeginDataElement(BSG_KSJSONEncodeContext *const context, int bsg_ksjsonappendDataElement(BSG_KSJSONEncodeContext *const context, const char *const value, size_t length) { - unsigned char *currentByte = (unsigned char *)value; - unsigned char *end = currentByte + length; + const unsigned char *currentByte = (const unsigned char *)value; + const unsigned char *end = currentByte + length; char chars[2]; int result = BSG_KSJSON_OK; while (currentByte < end) { diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSJSONCodecObjC.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSJSONCodecObjC.m index f114df980..94ca1eb21 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSJSONCodecObjC.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSJSONCodecObjC.m @@ -232,7 +232,7 @@ - (void)dealloc { int bsg_ksjsoncodecobjc_i_onElement(BSG_KSJSONCodec *codec, NSString *name, id element) { - id currentContainer = codec->_currentContainer; + id currentContainer = codec.currentContainer; if (!currentContainer) { codec.error = [NSError bsg_errorWithDomain:@"KSJSONCodecObjC" @@ -252,16 +252,16 @@ int bsg_ksjsoncodecobjc_i_onElement(BSG_KSJSONCodec *codec, NSString *name, int bsg_ksjsoncodecobjc_i_onBeginContainer(BSG_KSJSONCodec *codec, NSString *name, id container) { - if (codec->_topLevelContainer == nil) { - codec->_topLevelContainer = container; + if (codec.topLevelContainer == nil) { + codec.topLevelContainer = container; } else { int result = bsg_ksjsoncodecobjc_i_onElement(codec, name, container); if (result != BSG_KSJSON_OK) { return result; } } - codec->_currentContainer = container; - [codec->_containerStack addObject:container]; + codec.currentContainer = container; + [codec.containerStack addObject:container]; return BSG_KSJSON_OK; } @@ -297,10 +297,10 @@ int bsg_ksjsoncodecobjc_i_onNullElement(const char *const cName, NSString *name = stringFromCString(cName); BSG_KSJSONCodec *codec = (__bridge BSG_KSJSONCodec *)userData; - id currentContainer = codec->_currentContainer; - if ((codec->_ignoreNullsInArrays && + id currentContainer = codec.currentContainer; + if ((codec.ignoreNullsInArrays && [currentContainer isKindOfClass:[NSArray class]]) || - (codec->_ignoreNullsInObjects && + (codec.ignoreNullsInObjects && [currentContainer isKindOfClass:[NSDictionary class]])) { return BSG_KSJSON_OK; } @@ -337,7 +337,7 @@ int bsg_ksjsoncodecobjc_i_onBeginArray(const char *const cName, int bsg_ksjsoncodecobjc_i_onEndContainer(void *const userData) { BSG_KSJSONCodec *codec = (__bridge BSG_KSJSONCodec *)userData; - if ([codec->_containerStack count] == 0) { + if ([codec.containerStack count] == 0) { codec.error = [NSError bsg_errorWithDomain:@"KSJSONCodecObjC" code:0 @@ -345,13 +345,13 @@ int bsg_ksjsoncodecobjc_i_onEndContainer(void *const userData) { @"Already at the top level; no container left to end"]; return BSG_KSJSON_ERROR_INVALID_DATA; } - [codec->_containerStack removeLastObject]; - NSUInteger count = [codec->_containerStack count]; + [codec.containerStack removeLastObject]; + NSUInteger count = [codec.containerStack count]; if (count > 0) { - codec->_currentContainer = - codec->_containerStack[count - 1]; + codec.currentContainer = + codec.containerStack[count - 1]; } else { - codec->_currentContainer = nil; + codec.currentContainer = nil; } return BSG_KSJSON_OK; } @@ -398,7 +398,16 @@ int bsg_ksjsoncodecobjc_i_encodeObject(BSG_KSJSONCodec *codec, id object, case kCFNumberCharType: return bsg_ksjsonaddBooleanElement(context, cName, [object boolValue]); - default: + case kCFNumberSInt8Type: + case kCFNumberSInt16Type: + case kCFNumberSInt32Type: + case kCFNumberSInt64Type: + case kCFNumberShortType: + case kCFNumberIntType: + case kCFNumberLongType: + case kCFNumberLongLongType: + case kCFNumberCFIndexType: + case kCFNumberNSIntegerType: return bsg_ksjsonaddIntegerElement(context, cName, [object longLongValue]); } @@ -408,7 +417,7 @@ int bsg_ksjsoncodecobjc_i_encodeObject(BSG_KSJSONCodec *codec, id object, if ((result = bsg_ksjsonbeginArray(context, cName)) != BSG_KSJSON_OK) { return result; } - if (codec->_sorted) { + if (codec.sorted) { object = [object sortedArrayUsingComparator:^NSComparisonResult( id obj1, id obj2) { Class cls1 = [obj1 class]; @@ -445,7 +454,7 @@ int bsg_ksjsoncodecobjc_i_encodeObject(BSG_KSJSONCodec *codec, id object, return result; } NSArray *keys = [object allKeys]; - if (codec->_sorted) { + if (codec.sorted) { keys = [keys sortedArrayUsingSelector:@selector(compare:)]; } for (id key in keys) { @@ -507,7 +516,7 @@ + (NSData *)encode:(id)object } @catch (NSException *exception) { BSG_KSLOG_ERROR(@"Could not encode JSON object: %@", exception.description); if (error != nil) { - *error = [NSError bsg_errorWithDomain:@"KSJSONCodecObjC" code:0 description:exception.description]; + *error = [NSError bsg_errorWithDomain:@"KSJSONCodecObjC" code:0 description:@"%@", exception.description]; } return nil; } @@ -522,7 +531,7 @@ + (id)decode:(NSData *)JSONData } @catch (NSException *exception) { BSG_KSLOG_ERROR(@"Could not decode JSON object: %@", exception.description); if (error != nil) { - *error = [NSError bsg_errorWithDomain:@"KSJSONCodecObjC" code:0 description:exception.description]; + *error = [NSError bsg_errorWithDomain:@"KSJSONCodecObjC" code:0 description:@"%@", exception.description]; } result = @{}; } diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSLogger.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSLogger.h index 470026060..34cde2525 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSLogger.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSLogger.h @@ -24,7 +24,7 @@ // THE SOFTWARE. // -#import "BugsnagLogger.h" +#include "BugsnagLogger.h" /** * BSG_KSLogger @@ -159,9 +159,10 @@ extern "C" { #import void bsg_i_kslog_logObjC(const char *level, const char *file, int line, - const char *function, NSString *fmt, ...); + const char *function, NSString *fmt, ...) + NS_FORMAT_FUNCTION(5, 6); -void bsg_i_kslog_logObjCBasic(NSString *fmt, ...); +void bsg_i_kslog_logObjCBasic(NSString *fmt, ...) NS_FORMAT_FUNCTION(1, 2); #define i_KSLOG_FULL bsg_i_kslog_logObjC #define i_KSLOG_BASIC bsg_i_kslog_logObjCBasic @@ -169,9 +170,10 @@ void bsg_i_kslog_logObjCBasic(NSString *fmt, ...); #else // __OBJC__ void bsg_i_kslog_logC(const char *level, const char *file, int line, - const char *function, const char *fmt, ...); + const char *function, const char *fmt, ...) + __printflike(5, 6); -void bsg_i_kslog_logCBasic(const char *fmt, ...); +void bsg_i_kslog_logCBasic(const char *fmt, ...) __printflike(1, 2); #define i_KSLOG_FULL bsg_i_kslog_logC #define i_KSLOG_BASIC bsg_i_kslog_logCBasic diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSLogger.m b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSLogger.m index 979dc8cbe..d39e0aa5e 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSLogger.m +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSLogger.m @@ -31,7 +31,6 @@ // =========================================================================== // Compiler hints for "if" statements -#define likely_if(x) if (__builtin_expect(x, 1)) #define unlikely_if(x) if (__builtin_expect(x, 0)) /** The buffer size to use when writing log entries. @@ -66,7 +65,7 @@ * * @param fmt The format string, followed by its arguments. */ -static void writeFmtToLog(const char *fmt, ...); +static void writeFmtToLog(const char *fmt, ...) __printflike(1, 2); /** Write a formatted string to the log using a vararg list. * @@ -74,7 +73,7 @@ * * @param args The variable arguments. */ -static void writeFmtArgsToLog(const char *fmt, va_list args); +static void writeFmtArgsToLog(const char *fmt, va_list args) __printflike(1, 0); /** Flush the log stream. */ @@ -203,6 +202,7 @@ bool bsg_kslog_setLogFilename(const char *filename, bool overwrite) { #pragma mark - C - // =========================================================================== +__printflike(1, 2) void bsg_i_kslog_logCBasic(const char *const fmt, ...) { va_list args; va_start(args, fmt); @@ -212,6 +212,7 @@ void bsg_i_kslog_logCBasic(const char *const fmt, ...) { flushLog(); } +__printflike(5, 6) void bsg_i_kslog_logC(const char *const level, const char *const file, const int line, const char *const function, const char *const fmt, ...) { diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMach.c b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMach.c index a850b56e6..330662986 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMach.c +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMach.c @@ -24,7 +24,7 @@ // THE SOFTWARE. // -#import "BugsnagPlatformConditional.h" +#include "BugsnagPlatformConditional.h" #include "BSG_KSMach.h" @@ -457,8 +457,8 @@ kern_return_t bsg_ksmachcopyMem(const void *const src, void *const dst, size_t bsg_ksmachcopyMaxPossibleMem(const void *const src, void *const dst, const size_t numBytes) { const uint8_t *pSrc = src; - const uint8_t *pSrcMax = (uint8_t *)src + numBytes; - const uint8_t *pSrcEnd = (uint8_t *)src + numBytes; + const uint8_t *pSrcMax = (const uint8_t *)src + numBytes; + const uint8_t *pSrcEnd = (const uint8_t *)src + numBytes; uint8_t *pDst = dst; size_t bytesCopied = 0; diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMach.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMach.h index d93a8889c..b28f0e4bf 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMach.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMach.h @@ -245,7 +245,7 @@ int bsg_ksmachstackGrowDirection(void); * * @param thread The thread whose name to get. * - * @oaram buffer Buffer to hold the name. + * @param buffer Buffer to hold the name. * * @param bufLength The length of the buffer. * @@ -259,7 +259,7 @@ bool bsg_ksmachgetThreadName(const thread_t thread, char *const buffer, * * @param thread The thread whose queue name to get. * - * @oaram buffer Buffer to hold the name. + * @param buffer Buffer to hold the name. * * @param bufLength The length of the buffer. * diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.c b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.c index 1a8f9f472..fe0a57fe4 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.c +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.c @@ -245,7 +245,7 @@ uintptr_t bsg_mach_headers_first_cmd_after_header(const struct mach_header *cons return (uintptr_t)(header + 1); case MH_MAGIC_64: case MH_CIGAM_64: - return (uintptr_t)(((struct mach_header_64 *)header) + 1); + return (uintptr_t)(((const struct mach_header_64 *)header) + 1); default: // Header is corrupt return 0; diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.h index 376aad0e0..e3b3622cf 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.h @@ -9,9 +9,9 @@ #ifndef BSG_KSMachHeaders_h #define BSG_KSMachHeaders_h -#import -#import -#import +#include +#include +#include /* Maintaining our own list of framework Mach headers means that we avoid potential * deadlock situations where we try and suspend lock-holding threads prior to diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSObjC.c b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSObjC.c index c4af05f9f..71a320bdb 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSObjC.c +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSObjC.c @@ -33,16 +33,6 @@ #include #include -#define kMaxNameLength 128 - -//====================================================================== -#pragma mark - Macros - -//====================================================================== - -// Compiler hints for "if" statements -#define likely_if(x) if (__builtin_expect(x, 1)) -#define unlikely_if(x) if (__builtin_expect(x, 0)) - //====================================================================== #pragma mark - Utility - //====================================================================== diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSString.c b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSString.c index 88b36756c..49815b2e7 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSString.c +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSString.c @@ -29,7 +29,6 @@ #include // Compiler hints for "if" statements -#define likely_if(x) if (__builtin_expect(x, 1)) #define unlikely_if(x) if (__builtin_expect(x, 0)) static const int bsg_g_printableControlChars[0x20] = { @@ -123,14 +122,14 @@ bool bsg_ksstring_extractHexValue(const char *string, size_t stringLength, value += 2; // Must have at least one valid digit after "0x". - unlikely_if (bsg_g_hexConversion[*(uint8_t *)value] == INV) { + unlikely_if (bsg_g_hexConversion[*(const uint8_t *)value] == INV) { return false; } uint64_t accum = 0; unsigned int nybble = 0; while (value < string + stringLength) { - nybble = bsg_g_hexConversion[*(uint8_t *)value++]; + nybble = bsg_g_hexConversion[*(const uint8_t *)value++]; unlikely_if (nybble == INV) { break; } @@ -141,9 +140,9 @@ bool bsg_ksstring_extractHexValue(const char *string, size_t stringLength, return true; } -void bsg_ksstring_replace(const char **dest, const char *replacement) { +void bsg_ksstring_replace(char **dest, const char *replacement) { if (*dest != NULL) { - free((void *)*dest); + free(*dest); } if (replacement == NULL) { *dest = NULL; diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSString.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSString.h index de5dd93c3..994c83069 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSString.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSString.h @@ -69,7 +69,7 @@ bool bsg_ksstring_extractHexValue(const char *string, size_t stringLength, * * @param replacement The string to replace with. */ -void bsg_ksstring_replace(const char **dest, const char *replacement); +void bsg_ksstring_replace(char **dest, const char *replacement); #ifdef __cplusplus } diff --git a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/NSError+BSG_SimpleConstructor.h b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/NSError+BSG_SimpleConstructor.h index b4b296fca..3508215e7 100644 --- a/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/NSError+BSG_SimpleConstructor.h +++ b/Bugsnag/KSCrash/Source/KSCrash/Recording/Tools/NSError+BSG_SimpleConstructor.h @@ -40,8 +40,8 @@ * key NSLocalizedDescriptionKey). */ + (NSError *)bsg_errorWithDomain:(NSString *)domain - code:(NSInteger)code - description:(NSString *)fmt, ...; + code:(NSInteger)code + description:(NSString *)fmt, ... NS_FORMAT_FUNCTION(3, 4); /** Fill an error pointer with an NSError object if it's not nil. * @@ -55,6 +55,6 @@ + (BOOL)bsg_fillError:(NSError **)error withDomain:(NSString *)domain code:(NSInteger)code - description:(NSString *)fmt, ...; + description:(NSString *)fmt, ... NS_FORMAT_FUNCTION(4, 5); @end diff --git a/Bugsnag/Metadata/BugsnagMetadata.m b/Bugsnag/Metadata/BugsnagMetadata.m index c379cce4c..62d201d95 100644 --- a/Bugsnag/Metadata/BugsnagMetadata.m +++ b/Bugsnag/Metadata/BugsnagMetadata.m @@ -42,7 +42,7 @@ - (instancetype)init { } - (instancetype)initWithDictionary:(NSDictionary *)dict { - if (self = [super init]) { + if ((self = [super init])) { // Ensure that the instantiating dictionary is mutable. // Saves checks later. _dictionary = [self sanitizeDictionary:dict]; @@ -115,6 +115,12 @@ - (void)removeObserverWithBlock:(BugsnagObserverBlock _Nonnull)block { self.stateEventBlocks = newStateEventBlocks; } +// MARK: - + +- (id)copyWithZone:(__attribute__((unused)) NSZone *)zone { + return [self deepCopy]; +} + // MARK: - - (instancetype)mutableCopyWithZone:(__attribute__((unused)) NSZone *)zone { diff --git a/Bugsnag/Payload/BugsnagBreadcrumb+Private.h b/Bugsnag/Payload/BugsnagBreadcrumb+Private.h index 230705598..ed22c5200 100644 --- a/Bugsnag/Payload/BugsnagBreadcrumb+Private.h +++ b/Bugsnag/Payload/BugsnagBreadcrumb+Private.h @@ -20,4 +20,7 @@ NS_ASSUME_NONNULL_BEGIN @end +FOUNDATION_EXPORT NSString *BSGBreadcrumbTypeValue(BSGBreadcrumbType type); +FOUNDATION_EXPORT BSGBreadcrumbType BSGBreadcrumbTypeFromString( NSString * _Nullable value); + NS_ASSUME_NONNULL_END diff --git a/Bugsnag/Payload/BugsnagBreadcrumb.m b/Bugsnag/Payload/BugsnagBreadcrumb.m index d0b82435c..d42bd7e4f 100644 --- a/Bugsnag/Payload/BugsnagBreadcrumb.m +++ b/Bugsnag/Payload/BugsnagBreadcrumb.m @@ -77,6 +77,8 @@ BSGBreadcrumbType BSGBreadcrumbTypeFromString(NSString *value) { @interface BugsnagBreadcrumb () +@property (readwrite, nullable, nonatomic) NSDate *timestamp; + /// String representation of `timestamp` used to avoid unnecessary date <--> string conversions @property (copy, nonatomic) NSString *timestampString; @@ -86,7 +88,7 @@ @interface BugsnagBreadcrumb () @implementation BugsnagBreadcrumb - (instancetype)init { - if (self = [super init]) { + if ((self = [super init])) { _timestamp = [NSDate date]; _type = BSGBreadcrumbTypeManual; _metadata = @{}; @@ -101,17 +103,17 @@ - (BOOL)isValid { - (NSDictionary *)objectValue { @synchronized (self) { NSString *timestamp = self.timestampString ?: [BSG_RFC3339DateTool stringFromDate:self.timestamp]; - if (timestamp && _message.length > 0) { + if (timestamp && self.message.length > 0) { NSMutableDictionary *metadata = [NSMutableDictionary new]; - for (NSString *key in _metadata) { - metadata[[key copy]] = [_metadata[key] copy]; + for (NSString *key in self.metadata) { + metadata[[key copy]] = [self.metadata[key] copy]; } return @{ // Note: The Bugsnag Error Reporting API specifies that the breadcrumb "message" // field should be delivered in as a "name" field. This comment notes that variance. - BSGKeyName : [_message copy], + BSGKeyName : [self.message copy], BSGKeyTimestamp : timestamp, - BSGKeyType : BSGBreadcrumbTypeValue(_type), + BSGKeyType : BSGBreadcrumbTypeValue(self.type), BSGKeyMetadata : metadata }; } @@ -119,8 +121,6 @@ - (NSDictionary *)objectValue { } } -@synthesize timestamp = _timestamp; - // The timestamp is lazily computed from the timestampString to avoid unnecessary // calls to -dateFromString: (which is expensive) when loading breadcrumbs from disk. @@ -138,7 +138,7 @@ - (NSDate *)timestamp { - (void)setTimestampString:(NSString *)timestampString { @synchronized (self) { _timestampString = [timestampString copy]; - _timestamp = nil; //!OCLint + self.timestamp = nil; } } diff --git a/Bugsnag/Payload/BugsnagError+Private.h b/Bugsnag/Payload/BugsnagError+Private.h index a9ec9ebf5..1aba3cb7f 100644 --- a/Bugsnag/Payload/BugsnagError+Private.h +++ b/Bugsnag/Payload/BugsnagError+Private.h @@ -17,7 +17,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithKSCrashReport:(NSDictionary *)event stacktrace:(NSArray *)stacktrace; - (instancetype)initWithErrorClass:(NSString *)errorClass - errorMessage:(NSString *)errorMessage + errorMessage:(nullable NSString *)errorMessage errorType:(BSGErrorType)errorType stacktrace:(nullable NSArray *)stacktrace; diff --git a/Bugsnag/Payload/BugsnagError.m b/Bugsnag/Payload/BugsnagError.m index 4b7858e54..9e49653f7 100644 --- a/Bugsnag/Payload/BugsnagError.m +++ b/Bugsnag/Payload/BugsnagError.m @@ -19,9 +19,9 @@ typedef NSString * BSGErrorTypeString NS_TYPED_ENUM; -BSGErrorTypeString const BSGErrorTypeStringCocoa = @"cocoa"; -BSGErrorTypeString const BSGErrorTypeStringC = @"c"; -BSGErrorTypeString const BSGErrorTypeStringReactNativeJs = @"reactnativejs"; +static BSGErrorTypeString const BSGErrorTypeStringCocoa = @"cocoa"; +static BSGErrorTypeString const BSGErrorTypeStringC = @"c"; +static BSGErrorTypeString const BSGErrorTypeStringReactNativeJs = @"reactnativejs"; NSString *_Nonnull BSGSerializeErrorType(BSGErrorType errorType) { @@ -84,7 +84,7 @@ @implementation BugsnagError @dynamic type; - (instancetype)initWithKSCrashReport:(NSDictionary *)event stacktrace:(NSArray *)stacktrace { - if (self = [super init]) { + if ((self = [super init])) { NSDictionary *error = [event valueForKeyPath:@"crash.error"]; NSString *errorType = error[BSGKeyType]; _errorClass = BSGParseErrorClass(error, errorType); @@ -102,7 +102,7 @@ - (instancetype)initWithErrorClass:(NSString *)errorClass errorMessage:(NSString *)errorMessage errorType:(BSGErrorType)errorType stacktrace:(NSArray *)stacktrace { - if (self = [super init]) { + if ((self = [super init])) { _errorClass = errorClass; _errorMessage = errorMessage; _typeString = BSGSerializeErrorType(errorType); diff --git a/Bugsnag/Payload/BugsnagEvent.m b/Bugsnag/Payload/BugsnagEvent.m index 9076d5599..51d79999b 100644 --- a/Bugsnag/Payload/BugsnagEvent.m +++ b/Bugsnag/Payload/BugsnagEvent.m @@ -163,7 +163,7 @@ - (instancetype)initWithApp:(BugsnagAppWithState *)app errors:(NSArray *)errors threads:(NSArray *)threads session:(BugsnagSession *)session { - if (self = [super init]) { + if ((self = [super init])) { _app = app; _device = device; _handledState = handledState; @@ -181,7 +181,7 @@ - (instancetype)initWithApp:(BugsnagAppWithState *)app } - (instancetype)initWithJson:(NSDictionary *)json { - if (self = [super init]) { + if ((self = [super init])) { _app = BSGDeserializeObject(json[BSGKeyApp], ^id _Nullable(NSDictionary * _Nonnull dict) { return [BugsnagAppWithState appFromJson:dict]; }) ?: [[BugsnagAppWithState alloc] init]; @@ -474,13 +474,13 @@ - (void)attachCustomStacktrace:(NSArray *)frames withType:(NSString *)type { - (BSGSeverity)severity { @synchronized (self) { - return _handledState.currentSeverity; + return self.handledState.currentSeverity; } } - (void)setSeverity:(BSGSeverity)severity { @synchronized (self) { - _handledState.currentSeverity = severity; + self.handledState.currentSeverity = severity; } } diff --git a/Bugsnag/Payload/BugsnagHandledState.m b/Bugsnag/Payload/BugsnagHandledState.m index aaa2b0cc4..c4b600f16 100644 --- a/Bugsnag/Payload/BugsnagHandledState.m +++ b/Bugsnag/Payload/BugsnagHandledState.m @@ -125,7 +125,7 @@ - (instancetype)initWithSeverityReason:(SeverityReasonType)severityReason unhandled:(BOOL)unhandled unhandledOverridden:(BOOL)unhandledOverridden attrValue:(NSString *)attrValue { - if (self = [super init]) { + if ((self = [super init])) { _severityReasonType = severityReason; _currentSeverity = severity; _originalSeverity = severity; @@ -144,7 +144,7 @@ - (instancetype)initWithSeverityReason:(SeverityReasonType)severityReason } - (instancetype)initWithDictionary:(NSDictionary *)dict { - if (self = [super init]) { + if ((self = [super init])) { _unhandled = [dict[kUnhandled] boolValue]; _severityReasonType = [BugsnagHandledState severityReasonFromString:dict[kSeverityReasonType]]; @@ -157,7 +157,7 @@ - (instancetype)initWithDictionary:(NSDictionary *)dict { } - (SeverityReasonType)calculateSeverityReasonType { - return _originalSeverity == _currentSeverity ? _severityReasonType + return self.originalSeverity == self.currentSeverity ? self.severityReasonType : UserCallbackSetSeverity; } diff --git a/Bugsnag/Payload/BugsnagNotifier.m b/Bugsnag/Payload/BugsnagNotifier.m index 0a3f8ac0e..3ef475f8d 100644 --- a/Bugsnag/Payload/BugsnagNotifier.m +++ b/Bugsnag/Payload/BugsnagNotifier.m @@ -13,7 +13,7 @@ @implementation BugsnagNotifier - (instancetype)init { - if (self = [super init]) { + if ((self = [super init])) { #if BSG_PLATFORM_TVOS self.name = @"tvOS Bugsnag Notifier"; #elif BSG_PLATFORM_IOS @@ -23,7 +23,7 @@ - (instancetype)init { #else self.name = @"Bugsnag Objective-C"; #endif - self.version = @"6.9.1"; + self.version = @"6.9.2"; self.url = @"https://github.com/bugsnag/bugsnag-cocoa"; self.dependencies = [NSMutableArray new]; } diff --git a/Bugsnag/Payload/BugsnagSession.m b/Bugsnag/Payload/BugsnagSession.m index 08bc860b7..90b23f781 100644 --- a/Bugsnag/Payload/BugsnagSession.m +++ b/Bugsnag/Payload/BugsnagSession.m @@ -29,7 +29,7 @@ - (instancetype)initWithId:(NSString *)sessionId autoCaptured:(BOOL)autoCaptured app:(BugsnagApp *)app device:(BugsnagDevice *)device { - if (self = [super init]) { + if ((self = [super init])) { _id = sessionId; _startedAt = [startDate copy]; _user = user; @@ -63,7 +63,7 @@ - (nullable instancetype)initWithDictionary:(NSDictionary *)dict { if (!sessionId) { return nil; } - if (self = [super init]) { + if ((self = [super init])) { _id = sessionId; _unhandledCount = [dict[kBugsnagUnhandledCount] unsignedIntegerValue]; _handledCount = [dict[kBugsnagHandledCount] unsignedIntegerValue]; @@ -92,7 +92,7 @@ - (_Nonnull instancetype)initWithId:(NSString *)sessionId unhandledCount:(NSUInteger)unhandledCount app:(BugsnagApp *)app device:(BugsnagDevice *)device { - if (self = [super init]) { + if ((self = [super init])) { _id = sessionId; _startedAt = startDate; _unhandledCount = unhandledCount; diff --git a/Bugsnag/Payload/BugsnagSessionTrackingPayload.m b/Bugsnag/Payload/BugsnagSessionTrackingPayload.m index 5e6c43011..8afa62a53 100644 --- a/Bugsnag/Payload/BugsnagSessionTrackingPayload.m +++ b/Bugsnag/Payload/BugsnagSessionTrackingPayload.m @@ -33,7 +33,7 @@ - (instancetype)initWithSessions:(NSArray *)sessions codeBundleId:(NSString *)codeBundleId notifier:(BugsnagNotifier *)notifier { - if (self = [super init]) { + if ((self = [super init])) { _sessions = sessions; _config = config; _codeBundleId = codeBundleId; diff --git a/Bugsnag/Payload/BugsnagStackframe.m b/Bugsnag/Payload/BugsnagStackframe.m index b877df3f3..158a2e6cc 100644 --- a/Bugsnag/Payload/BugsnagStackframe.m +++ b/Bugsnag/Payload/BugsnagStackframe.m @@ -17,6 +17,11 @@ BugsnagStackframeType const BugsnagStackframeTypeCocoa = @"cocoa"; +static NSString * _Nullable FormatMemoryAddress(NSNumber * _Nullable address) { + return address == nil ? nil : [NSString stringWithFormat:@"0x%" PRIxPTR, address.unsignedLongValue]; +} + + // MARK: - Properties not used for Cocoa stack frames, but used by React Native and Unity. @interface BugsnagStackframe () @@ -226,23 +231,10 @@ - (NSDictionary *)toDictionary { dict[BSGKeyMachoFile] = self.machoFile; dict[BSGKeyMethod] = self.method; dict[BSGKeyMachoUUID] = self.machoUuid; - - if (self.frameAddress != nil) { - NSString *frameAddr = [NSString stringWithFormat:BSGKeyFrameAddrFormat, [self.frameAddress unsignedLongValue]]; - dict[BSGKeyFrameAddress] = frameAddr; - } - if (self.symbolAddress != nil) { - NSString *symbolAddr = [NSString stringWithFormat:BSGKeyFrameAddrFormat, [self.symbolAddress unsignedLongValue]]; - dict[BSGKeySymbolAddr] = symbolAddr; - } - if (self.machoLoadAddress != nil) { - NSString *imageAddr = [NSString stringWithFormat:BSGKeyFrameAddrFormat, [self.machoLoadAddress unsignedLongValue]]; - dict[BSGKeyMachoLoadAddr] = imageAddr; - } - if (self.machoVmAddress != nil) { - NSString *vmAddr = [NSString stringWithFormat:BSGKeyFrameAddrFormat, [self.machoVmAddress unsignedLongValue]]; - dict[BSGKeyMachoVMAddress] = vmAddr; - } + dict[BSGKeyFrameAddress] = FormatMemoryAddress(self.frameAddress); + dict[BSGKeySymbolAddr] = FormatMemoryAddress(self.symbolAddress); + dict[BSGKeyMachoLoadAddr] = FormatMemoryAddress(self.machoLoadAddress); + dict[BSGKeyMachoVMAddress] = FormatMemoryAddress(self.machoVmAddress); if (self.isPc) { dict[BSGKeyIsPC] = @(self.isPc); } diff --git a/Bugsnag/Payload/BugsnagStacktrace.m b/Bugsnag/Payload/BugsnagStacktrace.m index 7c9d37c49..7c2e11737 100644 --- a/Bugsnag/Payload/BugsnagStacktrace.m +++ b/Bugsnag/Payload/BugsnagStacktrace.m @@ -32,7 +32,7 @@ + (instancetype)stacktraceFromJson:(NSArray *)json { - (instancetype)initWithTrace:(NSArray *)trace binaryImages:(NSArray *)binaryImages { - if (self = [super init]) { + if ((self = [super init])) { _trace = [NSMutableArray new]; for (NSDictionary *obj in trace) { diff --git a/Bugsnag/Payload/BugsnagStateEvent.m b/Bugsnag/Payload/BugsnagStateEvent.m index 2d659d85a..6ebc23360 100644 --- a/Bugsnag/Payload/BugsnagStateEvent.m +++ b/Bugsnag/Payload/BugsnagStateEvent.m @@ -13,7 +13,7 @@ @implementation BugsnagStateEvent - (instancetype)initWithName:(NSString *)name data:(id)data { - if (self = [super init]) { + if ((self = [super init])) { self.type = name; self.data = data; } diff --git a/Bugsnag/Payload/BugsnagThread.m b/Bugsnag/Payload/BugsnagThread.m index 11d32079b..d190ee5d7 100644 --- a/Bugsnag/Payload/BugsnagThread.m +++ b/Bugsnag/Payload/BugsnagThread.m @@ -45,7 +45,7 @@ - (instancetype)initWithId:(NSString *)id errorReportingThread:(BOOL)errorReportingThread type:(BSGThreadType)type stacktrace:(NSArray *)stacktrace { - if (self = [super init]) { + if ((self = [super init])) { _id = id; _name = name; _errorReportingThread = errorReportingThread; @@ -56,7 +56,7 @@ - (instancetype)initWithId:(NSString *)id } - (instancetype)initWithThread:(NSDictionary *)thread binaryImages:(NSArray *)binaryImages { - if (self = [super init]) { + if ((self = [super init])) { _errorReportingThread = [thread[@BSG_KSCrashField_Crashed] boolValue]; _id = [thread[@BSG_KSCrashField_Index] stringValue]; _type = BSGThreadTypeCocoa; diff --git a/Bugsnag/Payload/BugsnagUser.m b/Bugsnag/Payload/BugsnagUser.m index 33688b184..6ed0f6e00 100644 --- a/Bugsnag/Payload/BugsnagUser.m +++ b/Bugsnag/Payload/BugsnagUser.m @@ -13,7 +13,7 @@ @implementation BugsnagUser - (instancetype)initWithDictionary:(NSDictionary *)dict { - if (self = [super init]) { + if ((self = [super init])) { _id = dict[@"id"]; _email = dict[@"email"]; _name = dict[@"name"]; diff --git a/Bugsnag/Plugins/BugsnagPluginClient.m b/Bugsnag/Plugins/BugsnagPluginClient.m index e14597678..008d52213 100644 --- a/Bugsnag/Plugins/BugsnagPluginClient.m +++ b/Bugsnag/Plugins/BugsnagPluginClient.m @@ -22,7 +22,7 @@ @implementation BugsnagPluginClient - (instancetype _Nonnull)initWithPlugins:(NSMutableSet> *_Nonnull)plugins client:(BugsnagClient *)client { - if (self = [super init]) { + if ((self = [super init])) { NSMutableSet *instantiatedPlugins = [plugins mutableCopy]; id rnPlugin = [self instantiateBugsnagPlugin:kPluginReactNative]; diff --git a/Bugsnag/Storage/BSGFileLocations.m b/Bugsnag/Storage/BSGFileLocations.m index 68693a66d..14eadf9bf 100644 --- a/Bugsnag/Storage/BSGFileLocations.m +++ b/Bugsnag/Storage/BSGFileLocations.m @@ -80,7 +80,7 @@ + (instancetype) v1 { } - (instancetype)initWithVersion1 { - if (self = [super init]) { + if ((self = [super init])) { NSString *root = rootDirectory(@"v1"); _events = getAndCreateSubdir(root, @"events"); _sessions = getAndCreateSubdir(root, @"sessions"); diff --git a/Bugsnag/Storage/BugsnagFileStore.m b/Bugsnag/Storage/BugsnagFileStore.m index 0909e65f5..2db670c65 100644 --- a/Bugsnag/Storage/BugsnagFileStore.m +++ b/Bugsnag/Storage/BugsnagFileStore.m @@ -51,7 +51,7 @@ - (instancetype)initWithId:(NSString *)fileId creationDate:(NSDate *)creationDat } - (NSComparisonResult)compare:(BSGFileStoreInfo *)other { - return [_creationDate compare:other->_creationDate]; + return [self.creationDate compare:other.creationDate]; } @end diff --git a/Bugsnag/include/Bugsnag/BSG_KSCrashReportWriter.h b/Bugsnag/include/Bugsnag/BSG_KSCrashReportWriter.h index cae6f6ab8..08b26e1ca 100644 --- a/Bugsnag/include/Bugsnag/BSG_KSCrashReportWriter.h +++ b/Bugsnag/include/Bugsnag/BSG_KSCrashReportWriter.h @@ -136,7 +136,7 @@ typedef struct BSG_KSCrashReportWriter { * * @param value A pointer to the binary data. * - * @paramn length The length of the data. + * @param length The length of the data. */ void (*addDataElement)(const struct BSG_KSCrashReportWriter *writer, const char *name, const char *value, @@ -159,7 +159,7 @@ typedef struct BSG_KSCrashReportWriter { * * @param value A pointer to the binary data. * - * @paramn length The length of the data. + * @param length The length of the data. */ void (*appendDataElement)(const struct BSG_KSCrashReportWriter *writer, const char *value, const size_t length); diff --git a/Bugsnag/include/Bugsnag/Bugsnag.h b/Bugsnag/include/Bugsnag/Bugsnag.h index 8e993d606..3b6205ecc 100644 --- a/Bugsnag/include/Bugsnag/Bugsnag.h +++ b/Bugsnag/include/Bugsnag/Bugsnag.h @@ -107,7 +107,7 @@ /** * Information about the last run of the app, and whether it crashed. */ -@property (class, readonly, nullable) BugsnagLastRunInfo *lastRunInfo; +@property (class, readonly, nullable, nonatomic) BugsnagLastRunInfo *lastRunInfo; /** * Tells Bugsnag that your app has finished launching. diff --git a/Bugsnag/include/Bugsnag/BugsnagClient.h b/Bugsnag/include/Bugsnag/BugsnagClient.h index be2e55c17..2845b8a78 100644 --- a/Bugsnag/include/Bugsnag/BugsnagClient.h +++ b/Bugsnag/include/Bugsnag/BugsnagClient.h @@ -205,7 +205,7 @@ NS_SWIFT_NAME(leaveBreadcrumb(_:metadata:type:)); /** * Retrieves the context - a general summary of what was happening in the application */ - @property (copy, nullable) NSString *context; + @property (copy, nullable, atomic) NSString *context; /** * @return YES if Bugsnag has been started and the previous launch crashed diff --git a/Bugsnag/include/Bugsnag/BugsnagConfiguration.h b/Bugsnag/include/Bugsnag/BugsnagConfiguration.h index f2bb2bef0..bda89ff92 100644 --- a/Bugsnag/include/Bugsnag/BugsnagConfiguration.h +++ b/Bugsnag/include/Bugsnag/BugsnagConfiguration.h @@ -311,7 +311,7 @@ typedef BOOL (^BugsnagOnSessionBlock)(BugsnagSession *_Nonnull session); * missing, an assertion will be thrown. If the session endpoint is missing, a warning will be * logged and sessions will not be sent automatically. */ -@property (strong, nonatomic) BugsnagEndpointConfiguration *endpoints; +@property (copy, nonatomic) BugsnagEndpointConfiguration *endpoints; // ============================================================================= // MARK: - User diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ddd2517c..ae994864b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,19 @@ Changelog ========= +## 6.9.2 (2021-05-19) + +### Enhancements + +* Add a mechanism for reporting errors that occur within the notifier. + [#1089](https://github.com/bugsnag/bugsnag-cocoa/pull/1089) + +### Bug fixes + +* Fix compiler warnings when additional warning flags are enabled. + [#1092](https://github.com/bugsnag/bugsnag-cocoa/pull/1092) + [#1094](https://github.com/bugsnag/bugsnag-cocoa/pull/1094) + ## 6.9.1 (2021-04-28) ### Bug fixes diff --git a/Framework/Info.plist b/Framework/Info.plist index 05db8be35..ff4b0eb74 100644 --- a/Framework/Info.plist +++ b/Framework/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 6.9.1 + 6.9.2 CFBundleVersion 1 diff --git a/Gemfile b/Gemfile index d32da79bf..65a4493ec 100644 --- a/Gemfile +++ b/Gemfile @@ -7,7 +7,7 @@ gem 'xcpretty' # A reference to Maze Runner is only needed for running tests locally and if committed it must be # portable for CI, e.g. a specific release. However, leaving it commented out would mean quicker CI. -gem 'bugsnag-maze-runner', git: 'https://github.com/bugsnag/maze-runner', tag: 'v4.13.0' +gem 'bugsnag-maze-runner', git: 'https://github.com/bugsnag/maze-runner', tag: 'v5.1.0' # Locally, you can run against Maze Runner branches and uncommitted changes: # gem 'bugsnag-maze-runner', path: '../maze-runner' diff --git a/Gemfile.lock b/Gemfile.lock index 54ae93bc9..320694678 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,11 +1,10 @@ GIT remote: https://github.com/bugsnag/maze-runner - revision: 3161e2a7115a2642a1929aa5c037ead65d4ebfba - tag: v4.13.0 + revision: 5e6c9624177f6087a75f5099130e24fb51036bb2 + branch: local-appium-server-logs specs: - bugsnag-maze-runner (4.13.0) + bugsnag-maze-runner (5.0.2) appium_lib (~> 11.2.0) - boring (~> 0.1.0) cucumber (~> 3.1.2) cucumber-expressions (~> 6.0.0) curb (~> 0.9.6) @@ -39,8 +38,7 @@ GEM faye-websocket (~> 0.11.0) selenium-webdriver (~> 3.14, >= 3.14.1) atomos (0.1.3) - backports (3.20.2) - boring (0.1.0) + backports (3.21.0) builder (3.2.4) childprocess (3.0.0) claide (1.0.3) @@ -170,7 +168,7 @@ GEM nap (1.1.0) netrc (0.11.0) no_proxy_fix (0.1.2) - nokogiri (1.11.2) + nokogiri (1.11.3) mini_portile2 (~> 2.5.0) racc (~> 1.4) octokit (4.20.0) diff --git a/Tests/BSGInternalErrorReporterTests.m b/Tests/BSGInternalErrorReporterTests.m new file mode 100644 index 000000000..bcd5e6351 --- /dev/null +++ b/Tests/BSGInternalErrorReporterTests.m @@ -0,0 +1,79 @@ +// +// BSGInternalErrorReporterTests.m +// Bugsnag +// +// Created by Nick Dowell on 06/05/2021. +// Copyright © 2021 Bugsnag Inc. All rights reserved. +// + +#import + +#import + +#import "BSGInternalErrorReporter.h" +#import "BugsnagEvent+Private.h" +#import "BugsnagNotifier.h" + +@interface BSGInternalErrorReporterTests : XCTestCase + +@property (nonatomic) BugsnagConfiguration *configuration; +@property (nonatomic) BugsnagNotifier *notifier; + +@end + +@implementation BSGInternalErrorReporterTests + +- (void)setUp { + self.configuration = [[BugsnagConfiguration alloc] initWithApiKey:@"0192837465afbecd0192837465afbecd"]; + self.notifier = [[BugsnagNotifier alloc] init]; +} + +- (void)testEventForError { + BugsnagConfiguration *configuration = [[BugsnagConfiguration alloc] initWithApiKey:@"0192837465afbecd0192837465afbecd"]; + BSGInternalErrorReporter *reporter = [[BSGInternalErrorReporter alloc] initWithDataSource:self]; + + BugsnagEvent *event = [reporter eventWithErrorClass:@"Internal error" message:@"Something went wrong" diagnostics:@{}]; + XCTAssertEqualObjects(event.errors[0].errorClass, @"Internal error"); + XCTAssertEqualObjects(event.errors[0].errorMessage, @"Something went wrong"); + XCTAssertNil(event.apiKey); + + NSDictionary *diagnostics = [event.metadata getMetadataFromSection:@"BugsnagDiagnostics"]; + XCTAssertEqualObjects(diagnostics[@"apiKey"], configuration.apiKey); +} + +- (void)testRequestForEvent { + self.configuration.endpoints.notify = @"https://notify.example.com"; + + BugsnagNotifier *notifier = [[BugsnagNotifier alloc] init]; + BSGInternalErrorReporter *reporter = [[BSGInternalErrorReporter alloc] initWithDataSource:self]; + + BugsnagEvent *event = [[BugsnagEvent alloc] init]; + + NSURLRequest *request = [reporter requestForEvent:event error:NULL]; + XCTAssertEqualObjects(request.URL, [NSURL URLWithString:self.configuration.endpoints.notify]); + XCTAssertEqualObjects(request.HTTPMethod, @"POST"); + + XCTAssertEqualObjects([request valueForHTTPHeaderField:@"Bugsnag-Internal-Error"], @"bugsnag-cocoa"); + XCTAssertNil([request valueForHTTPHeaderField:@"Bugsnag-Api-Key"]); + XCTAssertNil([request valueForHTTPHeaderField:@"Bugsnag-Stacktrace-Types"]); + XCTAssertNotNil([request valueForHTTPHeaderField:@"Bugsnag-Integrity"]); + XCTAssertNotNil([request valueForHTTPHeaderField:@"Bugsnag-Sent-At"]); + + NSDictionary *payload = [NSJSONSerialization JSONObjectWithData:(NSData * _Nonnull)request.HTTPBody options:0 error:NULL]; + XCTAssertEqualObjects(payload[@"events"], @[[event toJsonWithRedactedKeys:nil]]); + XCTAssertEqualObjects(payload[@"notifier"], [notifier toDict]); + XCTAssertEqualObjects(payload[@"payloadVersion"], @"4.0"); + XCTAssertNil(payload[@"apiKey"]); +} + +// MARK: - BSGInternalErrorReporterDataSource + +- (BugsnagAppWithState *)generateAppWithState:(nonnull NSDictionary *)systemInfo { + return [[BugsnagAppWithState alloc] init]; +} + +- (BugsnagDeviceWithState *)generateDeviceWithState:(nonnull NSDictionary *)systemInfo { + return [[BugsnagDeviceWithState alloc] init]; +} + +@end diff --git a/Tests/BugsnagApiClientTest.m b/Tests/BugsnagApiClientTest.m index c5e8a7ab2..38b7c8f75 100644 --- a/Tests/BugsnagApiClientTest.m +++ b/Tests/BugsnagApiClientTest.m @@ -81,12 +81,11 @@ - (void)testNotConnectedToInternetError { } - (void)testSHA1HashStringWithData { - BugsnagApiClient *client = [[BugsnagApiClient alloc] init]; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wnonnull" - XCTAssertNil([client SHA1HashStringWithData:nil]); + XCTAssertNil([BugsnagApiClient SHA1HashStringWithData:nil]); #pragma clang diagnostic pop - XCTAssertEqualObjects([client SHA1HashStringWithData:[@"{\"foo\":\"bar\"}" dataUsingEncoding:NSUTF8StringEncoding]], @"a5e744d0164540d33b1d7ea616c28f2fa97e754a"); + XCTAssertEqualObjects([BugsnagApiClient SHA1HashStringWithData:[@"{\"foo\":\"bar\"}" dataUsingEncoding:NSUTF8StringEncoding]], @"a5e744d0164540d33b1d7ea616c28f2fa97e754a"); } @end diff --git a/Tests/BugsnagConfigurationTests.m b/Tests/BugsnagConfigurationTests.m index 26fe90392..218f2baff 100644 --- a/Tests/BugsnagConfigurationTests.m +++ b/Tests/BugsnagConfigurationTests.m @@ -284,7 +284,7 @@ - (void)testEnabledReleaseStagesExcludedSkipsSending { - (void)testNotifyEndpoint { BugsnagConfiguration *config = [[BugsnagConfiguration alloc] initWithApiKey:DUMMY_APIKEY_32CHAR_1]; - XCTAssertEqualObjects([NSURL URLWithString:@"https://notify.bugsnag.com/"], config.notifyURL); + XCTAssertEqualObjects([NSURL URLWithString:@"https://notify.bugsnag.com"], config.notifyURL); // Test overriding the notify endpoint (use dummy endpoints to avoid hitting production) config.endpoints = [[BugsnagEndpointConfiguration alloc] initWithNotify:@"http://localhost:1234" diff --git a/Tests/Info.plist b/Tests/Info.plist index a4ceaaecf..8c9f92881 100644 --- a/Tests/Info.plist +++ b/Tests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 6.9.1 + 6.9.2 CFBundleVersion 1 diff --git a/VERSION b/VERSION index dc3829f5e..6b9255cf0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.9.1 +6.9.2 diff --git a/docker-compose.yml b/docker-compose.yml index bca9b2c74..4afe115b2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,14 +1,14 @@ version: '3.6' services: cocoa-maze-runner: - image: 855461928731.dkr.ecr.us-west-1.amazonaws.com/maze-runner-releases:latest-v4-cli + image: 855461928731.dkr.ecr.us-west-1.amazonaws.com/maze-runner-releases:latest-v5-cli environment: DEBUG: VERBOSE: BUILDKITE: BUILDKITE_PIPELINE_NAME: - MAZE_DEVICE_FARM_USERNAME: - MAZE_DEVICE_FARM_ACCESS_KEY: + BROWSER_STACK_USERNAME: + BROWSER_STACK_ACCESS_KEY: volumes: - ./features/fixtures/ios-swift-cocoapods/output:/app/build - ./features/:/app/features/ diff --git a/features/fixtures/ios-swift-cocoapods/Podfile b/features/fixtures/ios-swift-cocoapods/Podfile index df3263070..3e0c08deb 100644 --- a/features/fixtures/ios-swift-cocoapods/Podfile +++ b/features/fixtures/ios-swift-cocoapods/Podfile @@ -18,6 +18,12 @@ post_install do |installer| target.build_configurations.each do |config| config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)', 'BSG_LOG_LEVEL=BSG_LOGLEVEL_DEBUG'] config.build_settings['GCC_TREAT_WARNINGS_AS_ERRORS'] = 'YES' + + # Include all our build warning settings without needing to duplicate them here + xcconfig = "Pods/Target Support Files/#{target.name}/#{target.name}.#{config.name.downcase}.xcconfig" + File.open(xcconfig, 'a') do |file| + file << '#include "../../../../../../Bugsnag.xcconfig"' + end end end end diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp.xcodeproj/project.pbxproj b/features/fixtures/ios-swift-cocoapods/iOSTestApp.xcodeproj/project.pbxproj index 4db5b2f2c..d24a12507 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp.xcodeproj/project.pbxproj +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp.xcodeproj/project.pbxproj @@ -19,6 +19,7 @@ 01018BA025E40ADD000312C6 /* AsyncSafeMallocScenario.m in Sources */ = {isa = PBXBuildFile; fileRef = 01018B9F25E40ADD000312C6 /* AsyncSafeMallocScenario.m */; }; 0104085F258CA0A100933C60 /* DispatchCrashScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0104085E258CA0A100933C60 /* DispatchCrashScenario.swift */; }; 0163BFA72583B3CF008DC28B /* DiscardClassesScenarios.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0163BFA62583B3CF008DC28B /* DiscardClassesScenarios.swift */; }; + 01847DD626453D4E00ADA4C7 /* InternalErrorReportingScenarios.m in Sources */ = {isa = PBXBuildFile; fileRef = 01847DD526453D4E00ADA4C7 /* InternalErrorReportingScenarios.m */; }; 01AF6A53258A112F00FFC803 /* BareboneTestScenarios.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01AF6A52258A112F00FFC803 /* BareboneTestScenarios.swift */; }; 01B6BB7525D5748800FC4DE6 /* LastRunInfoScenarios.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01B6BB7425D5748800FC4DE6 /* LastRunInfoScenarios.swift */; }; 01B6BBB625DA82B800FC4DE6 /* SendLaunchCrashesSynchronouslyScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01B6BBB525DA82B700FC4DE6 /* SendLaunchCrashesSynchronouslyScenario.swift */; }; @@ -171,6 +172,7 @@ 01018B9F25E40ADD000312C6 /* AsyncSafeMallocScenario.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AsyncSafeMallocScenario.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 = ""; }; + 01847DD526453D4E00ADA4C7 /* InternalErrorReportingScenarios.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InternalErrorReportingScenarios.m; sourceTree = ""; }; 01AF6A52258A112F00FFC803 /* BareboneTestScenarios.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BareboneTestScenarios.swift; sourceTree = ""; }; 01B6BB7425D5748800FC4DE6 /* LastRunInfoScenarios.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LastRunInfoScenarios.swift; sourceTree = ""; }; 01B6BBB525DA82B700FC4DE6 /* SendLaunchCrashesSynchronouslyScenario.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SendLaunchCrashesSynchronouslyScenario.swift; sourceTree = ""; }; @@ -572,6 +574,7 @@ 01F1474325F282E600C2DC65 /* AppHangScenarios.swift */, 01AF6A52258A112F00FFC803 /* BareboneTestScenarios.swift */, 0163BFA62583B3CF008DC28B /* DiscardClassesScenarios.swift */, + 01847DD526453D4E00ADA4C7 /* InternalErrorReportingScenarios.m */, 01E5EAD025B713990066EA8A /* OOMScenario.h */, 01E5EAD125B713990066EA8A /* OOMScenario.m */, 8AB1081823301FE600672818 /* ReleaseStageScenarios.swift */, @@ -964,6 +967,7 @@ A1117E552535A59100014FDA /* OOMLoadScenario.swift in Sources */, 8A840FBA21AF5C450041DBFA /* SwiftAssertion.swift in Sources */, E753F24824927412001FB671 /* OnSendErrorCallbackCrashScenario.swift in Sources */, + 01847DD626453D4E00ADA4C7 /* InternalErrorReportingScenarios.m in Sources */, 001E5502243B8FDA0009E31D /* AutoCaptureRunScenario.m in Sources */, 0104085F258CA0A100933C60 /* DispatchCrashScenario.swift in Sources */, E700EE55247D3204008CFFB6 /* OnSendOverwriteScenario.swift in Sources */, diff --git a/features/fixtures/macos-stress-test/BugsnagStressTest.xcodeproj/project.pbxproj b/features/fixtures/macos-stress-test/BugsnagStressTest.xcodeproj/project.pbxproj index 086659a2b..0262721da 100644 --- a/features/fixtures/macos-stress-test/BugsnagStressTest.xcodeproj/project.pbxproj +++ b/features/fixtures/macos-stress-test/BugsnagStressTest.xcodeproj/project.pbxproj @@ -231,6 +231,7 @@ MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; + STRIP_INSTALLED_PRODUCT = NO; }; name = Debug; }; @@ -283,6 +284,7 @@ MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = macosx; + STRIP_INSTALLED_PRODUCT = NO; }; name = Release; }; diff --git a/features/fixtures/macos-stress-test/Makefile b/features/fixtures/macos-stress-test/Makefile index 927e03959..91f881255 100644 --- a/features/fixtures/macos-stress-test/Makefile +++ b/features/fixtures/macos-stress-test/Makefile @@ -1,4 +1,4 @@ -.PHONY: all build clean run +.PHONY: all build clean all: build @@ -14,8 +14,3 @@ build: clean: rm -rf build Pods *.log - -run: - QUIET=true /usr/bin/time -l ./build/usr/local/bin/BugsnagStressTest - rm -rf $(HOME)/Library/Application\ Support/com.bugsnag.Bugsnag - @echo "macOS stress-test complete" diff --git a/features/fixtures/macos-stress-test/run.sh b/features/fixtures/macos-stress-test/run.sh new file mode 100755 index 000000000..81ddcc599 --- /dev/null +++ b/features/fixtures/macos-stress-test/run.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +cd "$(dirname "$0")" + +QUIET=true ./build/usr/local/bin/BugsnagStressTest +RESULT=$? + +rm -rf ~/Library/Application\ Support/com.bugsnag.Bugsnag + +if [ "$RESULT" -ne "0" ]; then + # Wait for the crash reporter to write a crash report + sleep 5 + + find ~/Library/Logs/DiagnosticReports \ + -name 'BugsnagStressTest_*.crash' \ + -newer build/usr/local/bin/BugsnagStressTest \ + -exec mv {} . \; +fi + +echo "BugsnagStressTest exited with $RESULT" + +exit $RESULT diff --git a/features/fixtures/macos/macOSTestApp.xcodeproj/project.pbxproj b/features/fixtures/macos/macOSTestApp.xcodeproj/project.pbxproj index 370960ce4..394a3aef8 100644 --- a/features/fixtures/macos/macOSTestApp.xcodeproj/project.pbxproj +++ b/features/fixtures/macos/macOSTestApp.xcodeproj/project.pbxproj @@ -17,6 +17,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 */; }; + 01847DCD26443DF000ADA4C7 /* InternalErrorReportingScenarios.m in Sources */ = {isa = PBXBuildFile; fileRef = 01847DCC26443DF000ADA4C7 /* InternalErrorReportingScenarios.m */; }; 01AF6A50258A00DE00FFC803 /* BareboneTestScenarios.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01AF6A4F258A00DE00FFC803 /* BareboneTestScenarios.swift */; }; 01AF6A84258BB38A00FFC803 /* DispatchCrashScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01AF6A83258BB38A00FFC803 /* DispatchCrashScenario.swift */; }; 01B6BB7225D56CBF00FC4DE6 /* LastRunInfoScenarios.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01B6BB7125D56CBF00FC4DE6 /* LastRunInfoScenarios.swift */; }; @@ -168,6 +169,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 = ""; }; + 01847DCC26443DF000ADA4C7 /* InternalErrorReportingScenarios.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InternalErrorReportingScenarios.m; sourceTree = ""; }; 01AF6A4F258A00DE00FFC803 /* BareboneTestScenarios.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BareboneTestScenarios.swift; sourceTree = ""; }; 01AF6A83258BB38A00FFC803 /* DispatchCrashScenario.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DispatchCrashScenario.swift; sourceTree = ""; }; 01B6BB7125D56CBF00FC4DE6 /* LastRunInfoScenarios.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LastRunInfoScenarios.swift; sourceTree = ""; }; @@ -417,6 +419,7 @@ 01F47C4E254B1B2D00B184AD /* HandledErrorScenario.swift */, 01F47C28254B1B2C00B184AD /* HandledExceptionScenario.swift */, 01F47C55254B1B2E00B184AD /* HandledInternalNotifyScenario.swift */, + 01847DCC26443DF000ADA4C7 /* InternalErrorReportingScenarios.m */, 01B6BB7125D56CBF00FC4DE6 /* LastRunInfoScenarios.swift */, 01F47C23254B1B2C00B184AD /* LoadConfigFromFileAutoScenario.swift */, 01F47C94254B1B2F00B184AD /* LoadConfigFromFileScenario.swift */, @@ -679,6 +682,7 @@ 01F47CE9254B1B3100B184AD /* SIGTRAPScenario.m in Sources */, 01F47CC8254B1B3100B184AD /* AutoSessionScenario.m in Sources */, 01E0DB0625E8E95700A740ED /* AppDurationScenario.swift in Sources */, + 01847DCD26443DF000ADA4C7 /* InternalErrorReportingScenarios.m in Sources */, 01F47D2D254B1B3100B184AD /* OnErrorOverwriteScenario.swift in Sources */, 01F47CC7254B1B3100B184AD /* MetadataRedactionDefaultScenario.swift in Sources */, 01F47CEC254B1B3100B184AD /* SessionCallbackCrashScenario.swift in Sources */, diff --git a/features/fixtures/shared/scenarios/BareboneTestScenarios.swift b/features/fixtures/shared/scenarios/BareboneTestScenarios.swift index aaab20c21..07a114cde 100644 --- a/features/fixtures/shared/scenarios/BareboneTestScenarios.swift +++ b/features/fixtures/shared/scenarios/BareboneTestScenarios.swift @@ -38,6 +38,7 @@ class BareboneTestHandledScenario: Scenario { return true } config.enabledBreadcrumbTypes = [.error] + config.autoDetectErrors = false config.addMetadata(["Testing": true], section: "Flags") config.addMetadata(["password": "123456"], section: "Other") config.launchDurationMillis = 0 diff --git a/features/fixtures/shared/scenarios/InternalErrorReportingScenarios.m b/features/fixtures/shared/scenarios/InternalErrorReportingScenarios.m new file mode 100644 index 000000000..a95922bb0 --- /dev/null +++ b/features/fixtures/shared/scenarios/InternalErrorReportingScenarios.m @@ -0,0 +1,34 @@ +// +// InternalErrorReportingScenarios.m +// macOSTestApp +// +// Created by Nick Dowell on 07/05/2021. +// Copyright © 2021 Bugsnag Inc. All rights reserved. +// + +#import "Scenario.h" + +@interface InternalErrorReportingScenarios_KSCrashReport : Scenario + +@end + +static void InternalErrorReportingScenarios_KSCrashReport_CrashHandler() { + // Terminate the process without running atexit handlers. This should leave + // a partically written KSCrashReport which will fail to parse as JSON. + _exit(0); +} + +@implementation InternalErrorReportingScenarios_KSCrashReport + +- (void)startBugsnag { + self.config.autoTrackSessions = NO; + self.config.onCrashHandler = InternalErrorReportingScenarios_KSCrashReport_CrashHandler; + + [super startBugsnag]; +} + +- (void)run { + __builtin_trap(); +} + +@end diff --git a/features/internal_error_reporting.feature b/features/internal_error_reporting.feature new file mode 100644 index 000000000..d4ac51fb1 --- /dev/null +++ b/features/internal_error_reporting.feature @@ -0,0 +1,18 @@ +Feature: Internal error reporting + + Background: + Given I clear all persistent data + + Scenario: An internal error report is sent for invalid KSCrashReport files + When I run "InternalErrorReportingScenarios_KSCrashReport" and relaunch the app + And I configure Bugsnag for "InternalErrorReportingScenarios_KSCrashReport" + And I wait to receive an error + And the error "Bugsnag-Api-Key" header is null + And the error "Bugsnag-Internal-Error" header equals "bugsnag-cocoa" + And the error payload field "events.0.threads" is an array with 0 elements + And the event "apiKey" is null + And the event "metaData.BugsnagDiagnostics.apiKey" equals "12312312312312312312312312312312" + And the event "metaData.BugsnagDiagnostics.data" is not null + And the event "unhandled" is false + And the exception "errorClass" equals "JSON parsing error" + And the exception "message" equals "NSCocoaErrorDomain 3840: Unexpected end of file while parsing object." diff --git a/features/steps/header_steps.rb b/features/steps/header_steps.rb new file mode 100644 index 000000000..2761177e5 --- /dev/null +++ b/features/steps/header_steps.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# @!group Header steps + +Then('the {word} {string} header is null') do |request_type, header_name| + assert_nil(Maze::Server.list_for(request_type).current[:request][header_name], + "The #{request_type} '#{header_name}' header should be null") +end diff --git a/features/stress_test.feature b/features/stress_test.feature index 6126964df..fe9a873ad 100644 --- a/features/stress_test.feature +++ b/features/stress_test.feature @@ -3,10 +3,9 @@ Feature: Stress test Scenario: Triggering error notifications continuously When I start a new shell - And I input "cd features/fixtures/macos-stress-test" interactively - And I input "make build run" interactively - And I wait for the shell to output "macOS stress-test complete" to stdout - Then the last interactive command exited successfully + And I input "./features/fixtures/macos-stress-test/run.sh" interactively + And I wait for the shell to output a match for the regex "BugsnagStressTest exited with " to stdout + And the shell has output "BugsnagStressTest exited with 0" to stdout # This is low, but due to network congestion all we can guarantee in the course of a normal test And I have received at least 1 error