diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 0ea8d8d65..7ad71498a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,55 +1,33 @@ ## Goal - - - + ## Design - + ## Changeset - + ## Tests - + -## Review -### Outstanding Questions - + - -- This pull request is ready for: - - [ ] Initial review of the intended approach, not yet feature complete - - [ ] Structural review of the classes, functions, and properties modified - - [ ] Final review - - - -- [ ] The correct target branch has been selected (`master` for fixes, `next` for - features) -- [ ] Consistency across platforms for structures or concepts added or modified -- [ ] Consistency between the changeset and the goal stated above -- [ ] Internal consistency with the rest of the library - is there any overlap between existing interfaces and any which have been added? -- [ ] Usage friction - is the proposed change in usage cumbersome or complicated? -- [ ] Performance and complexity - are there any cases of unexpected O(n^3) when iterating, recursing, flat mapping, etc? -- [ ] Concurrency concerns - if components are accessed asynchronously, what issues will arise -- [ ] Thoroughness of added tests and any missing edge cases -- [ ] Idiomatic use of the language diff --git a/.gitignore b/.gitignore index 9af183d69..842164202 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,5 @@ Pods Carthage *.idea features/fixtures/carthage-proj +IDEWorkspaceChecks.plist +Podfile.lock diff --git a/Bugsnag.podspec.json b/Bugsnag.podspec.json index a284a4e7e..ec670f448 100644 --- a/Bugsnag.podspec.json +++ b/Bugsnag.podspec.json @@ -1,6 +1,6 @@ { "name": "Bugsnag", - "version": "5.23.0", + "version": "5.23.5", "summary": "Cocoa notifier for SDK for bugsnag.com", "homepage": "https://bugsnag.com", "license": "MIT", @@ -9,7 +9,7 @@ }, "source": { "git": "https://github.com/bugsnag/bugsnag-cocoa.git", - "tag": "v5.23.0" + "tag": "v5.23.5" }, "frameworks": ["Foundation", "SystemConfiguration"], "libraries": [ diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c33a66c2..711d9e319 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,68 @@ Changelog ========= +## 5.23.5 (2020-07-27) + +### Bug fixes + +The following bug fixes have been applied to the v5 branch to provide a patch +for users who have not yet upgraded to v6: + +* Fix JSON serialisation of strings with control characters + [739](https://github.com/bugsnag/bugsnag-cocoa/pull/739) + +* Removed non-thread safe date formatter + [#758](https://github.com/bugsnag/bugsnag-cocoa/pull/758) + +## 5.23.4 (2020-07-06) + +### Bug Fixes + +The following bug fixes have been applied to the v5 branch to provide a patch +for users who have not yet upgraded to v6: + +* Fix incorrect string comparison of thread names in Mach exception handling + [#721](https://github.com/bugsnag/bugsnag-cocoa/pull/721) + +* Move binary images store declaration from header file + [#725](https://github.com/bugsnag/bugsnag-cocoa/pull/725) + +* Avoid dereference null pointer in JSON serialisation + [#637](https://github.com/bugsnag/bugsnag-cocoa/pull/637) + [Naugladur](https://github.com/Naugladur) + +## 5.23.3 (2020-06-05) + +### Bug Fixes + +* Fix DYLD lock mechanism preventing compilation on iOS <10. + [#675](https://github.com/bugsnag/bugsnag-cocoa/pull/675) + +## 5.23.2 (2020-05-13) + +### Bug Fixes + +* Fixed an issue where an app could deadlock during a crash if unfavourable + timing caused DYLD lock contention. + [#580](https://github.com/bugsnag/bugsnag-cocoa/pull/580) + +## 5.23.1 (2020-04-08) + +### Bug fixes + +* Fix possible report corruption when using `notify()` from multiple threads + when configured to skip capturing/reporting background thread contents + (generally only Unity games). + [#442](https://github.com/bugsnag/bugsnag-cocoa/pull/442) + +* Added several additional event fields (`codeBundleId`, `osName`, `modelNumber`, + `locale`) that were missing from the OOM reports. + [#444](https://github.com/bugsnag/bugsnag-cocoa/pull/444) + +* Bugsnag now correctly records a new session if it is returning to the foreground + after more than 60 seconds in the background. + [#529](https://github.com/bugsnag/bugsnag-cocoa/pull/529) + ## 5.23.0 (2019-12-10) This release removes support for reporting 'partial' or 'minimal' crash reports diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fd5929ff9..9e6cfbb3d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,36 +12,58 @@ Thanks for stopping by! This document should cover most topics surrounding contr ## Reporting issues -Are you having trouble getting started? Please [contact us directly](mailto:support@bugsnag.com?subject=%5BGitHub%5D%20Cocoa%20-%20having%20trouble%20getting%20started%20with%20Bugsnag&body=Description%3A%0A%0A%28Add%20a%20description%20here%2C%20and%20fill%20in%20your%20environment%20below%3A%29%0A%0A%0AEnvironment%3A%0A%0A%0APaste%20the%20output%20of%20this%20command%20into%20the%20code%20block%20below%20%28use%20%60npm%20ls%60%20instead%0Aof%20%60yarn%20list%60%20if%20you%20are%20using%20npm%29%3A%0A%0A%60%60%60%0Ayarn%20list%20cocoa%20bugsnag-cocoa%20cocoa-code-push%0A%60%60%60%0A%0A-%20cocoapods%20version%20%28if%20any%29%20%28%60pod%20-v%60%29%3A%0A-%20iOS/Android%20version%28s%29%3A%0A-%20simulator/emulator%20or%20physical%20device%3F%3A%0A-%20debug%20mode%20or%20production%3F%3A%0A%0A-%20%5B%20%5D%20%28iOS%20only%29%20%60%5BBugsnagReactNative%20start%5D%60%20is%20present%20in%20the%0A%20%20%60application%3AdidFinishLaunchingWithOptions%3A%60%20method%20in%20your%20%60AppDelegate%60%0A%20%20class%3F%0A-%20%5B%20%5D%20%28Android%20only%29%20%60BugsnagReactNative.start%28this%29%60%20is%20present%20in%20the%0A%20%20%60onCreate%60%20method%20of%20your%20%60MainApplication%60%20class%3F) for assistance with integrating Bugsnag into your application. -If you have spotted a problem with this module, feel free to open a [new issue](https://github.com/bugsnag/bugsnag-cocoa/issues/new?template=Bug_report.md). Here are a few things to check before doing so: - -* Are you using the latest version of `Bugsnag`? If not, does updating to the latest version fix your issue? -* Has somebody else [already reported](https://github.com/bugsnag/bugsnag-cocoa/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen) your issue? Feel free to add additional context to or check-in on an existing issue that matches your own. -* Is your issue caused by this module? Only things related to the `bugsnag-cocoa` module should be reported here. For anything else, please [contact us directly](mailto:support@bugsnag.com) and we'd be happy to help you out. +Are you having trouble getting started? Please [contact us directly](mailto:support@bugsnag.com?subject=%5BGitHub%5D%20Cocoa%20-%20having%20trouble%20getting%20started%20with%20Bugsnag&body=Description%3A%0A%0A%28Add%20a%20description%20here%2C%20and%20fill%20in%20your%20environment%20below%3A%29%0A%0A%0AEnvironment%3A%0A%0A%0APaste%20the%20output%20of%20this%20command%20into%20the%20code%20block%20below%20%28use%20%60npm%20ls%60%20instead%0Aof%20%60yarn%20list%60%20if%20you%20are%20using%20npm%29%3A%0A%0A%60%60%60%0Ayarn%20list%20cocoa%20bugsnag-cocoa%20cocoa-code-push%0A%60%60%60%0A%0A-%20cocoapods%20version%20%28if%20any%29%20%28%60pod%20-v%60%29%3A%0A-%20iOS/Android%20version%28s%29%3A%0A-%20simulator/emulator%20or%20physical%20device%3F%3A%0A-%20debug%20mode%20or%20production%3F%3A%0A%0A-%20%5B%20%5D%20%28iOS%20only%29%20%60%5BBugsnagReactNative%20start%5D%60%20is%20present%20in%20the%0A%20%20%60application%3AdidFinishLaunchingWithOptions%3A%60%20method%20in%20your%20%60AppDelegate%60%0A%20%20class%3F%0A-%20%5B%20%5D%20%28Android%20only%29%20%60BugsnagReactNative.start%28this%29%60%20is%20present%20in%20the%0A%20%20%60onCreate%60%20method%20of%20your%20%60MainApplication%60%20class%3F) +for assistance with integrating Bugsnag into your application. If you have +spotted a problem with this module, feel free to open a +[new issue](https://github.com/bugsnag/bugsnag-cocoa/issues/new?template=Bug_report.md). +Here are a few things to check before doing so: + +* Are you using the latest version of `Bugsnag`? If not, does updating to the + latest version fix your issue? +* Has somebody else [already reported](https://github.com/bugsnag/bugsnag-cocoa/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen) + your issue? Feel free to add additional context to or check-in on an existing + issue that matches your own. +* Is your issue caused by this module? Only things related to the + `bugsnag-cocoa` module should be reported here. For anything else, please + [contact us directly](mailto:support@bugsnag.com) and we'd be happy to help + you out. ### Fixing issues If you've identified a fix to a new or existing issue, we welcome contributions! -Here are some helpful suggestions on contributing that help us merge your PR quickly and smoothly: +Here are some helpful suggestions on contributing that help us merge your PR +quickly and smoothly: * [Fork](https://help.github.com/articles/fork-a-repo) the [library on GitHub](https://github.com/bugsnag/bugsnag-cocoa) -* Build and test your changes. We have automated tests for many scenarios but its also helpful to use `npm pack` to build the module locally and install it in a real app. +* Build and test your changes. We have automated tests for many scenarios but + its also helpful to use `npm pack` to build the module locally and install it + in a real app. * Commit and push until you are happy with your contribution * [Make a pull request](https://help.github.com/articles/using-pull-requests) -* Ensure the automated checks pass (and if it fails, please try to address the cause) +* Ensure the automated checks pass (and if it fails, please try to address the + cause) ### Adding features -Unfortunately we’re unable to accept PRs that add features or refactor the library at this time. -However, we’re very eager and welcome to hearing feedback about the library so please contact us directly to discuss your idea, or open a -[feature request](https://github.com/bugsnag/bugsnag-cocoa/issues/new?template=Feature_request.md) to help us improve the library. +Unfortunately we’re unable to accept PRs that add features or refactor the +library at this time. However, we’re very eager and welcome to hearing +feedback about the library so please contact us directly to discuss your idea, +or open a [feature request](https://github.com/bugsnag/bugsnag-cocoa/issues/new?template=Feature_request.md) +to help us improve the library. Here’s a bit about our process designing and building the Bugsnag libraries: -* We have an internal roadmap to plan out the features we build, and sometimes we will already be planning your suggested feature! -* Our open source libraries span many languages and frameworks so we strive to ensure they are idiomatic on the given platform, but also consistent in terminology between platforms. That way the core concepts are familiar whether you adopt Bugsnag for one platform or many. -* Finally, one of our goals is to ensure our libraries work reliably, even in crashy, multi-threaded environments. Oftentimes, this requires an intensive engineering design and code review process that adheres to our style and linting guidelines. +* We have an internal roadmap to plan out the features we build, and sometimes + we will already be planning your suggested feature! +* Our open source libraries span many languages and frameworks so we strive to + ensure they are idiomatic on the given platform, but also consistent in + terminology between platforms. That way the core concepts are familiar whether + you adopt Bugsnag for one platform or many. +* Finally, one of our goals is to ensure our libraries work reliably, even in + crashy, multi-threaded environments. Oftentimes, this requires an intensive + engineering design and code review process that adheres to our style and + linting guidelines. ## Building @@ -74,8 +96,11 @@ Run the integration tests using `make e2e` (end-to-end) 2. Sign in to CocoaPods trunk: ``` - pod trunk register notifiers@bugsnag.com 'Bugsnag Notifiers' --description='your name' + pod trunk register notifiers@bugsnag.com 'Bugsnag Notifiers' --description='' ``` + + (Remember to warn the platforms team to ignore the email) + 3. Click the link in the email that got sent to the platforms team ### Pre-release steps @@ -84,29 +109,60 @@ Run the integration tests using `make e2e` (end-to-end) released. If any changes on `next` should go out, check out that branch before the subsequent steps. * Add any missing entries to the CHANGELOG. Update the README.md if appropriate. -* Create a pull request for a new version by running `make VERSION=[number] prerelease`. Pull request generation depends on [`hub`](https://hub.github.com) (`brew install hub`) +* Create a pull request for a new version by running `make VERSION=[number] + prerelease`. Pull request generation depends on [`hub`](https://hub.github.com) + (`brew install hub`) * Perform preflight checks: - [ ] Have the changelog and README been updated? - - [ ] Are there pull requests for installation changes on the [dashboard](https://github.com/bugsnag/dashboard-js)? - - [ ] Are there pull requests for new features/behavior on the [docs site](https://github.com/bugsnag/docs.bugsnag.com)? + - [ ] Are there pull requests for installation changes on the + [dashboard](https://github.com/bugsnag/dashboard-js)? + - [ ] Are there pull requests for new features/behavior on the + [docs site](https://github.com/bugsnag/docs.bugsnag.com)? - [ ] Run `./Tests/prerelease/run_prerelease_checks.sh` + +* The following checks are optional. Use your judgement to decide if the scope + of the release merits performing any or all of them. + - [ ] Has all new functionality been manually tested on a release build? - - [ ] Do the installation instructions work when creating an example app from scratch? - - [ ] Does the Carthage installation instruction work? - - [ ] If a response is not received from the server, is the report queued for later? + - [ ] Do the [installation instructions](https://docs.bugsnag.com/platforms/ios/#installation) + work when creating an example app from scratch? If using Cocoapods + remember to point at the pre-release branch in the `Podfile`, e.g. + + ``` + pod 'Bugsnag', :git => 'https://github.com/bugsnag/bugsnag-cocoa', :branch => '' + ``` + + - [ ] Does the Carthage installation instruction work? + - [ ] If a response is not received from the server, is the report queued for + later? - [ ] If no network connection is available, is the report queued for later? - - [ ] On a throttled network, is the request timeout reasonable, and the main thread not blocked? + - [ ] On a throttled network, is the request timeout reasonable, and the main + thread not blocked? - [ ] Are queued reports sent asynchronously? - - [ ] On a throttled network, is the request timeout reasonable, and the main thread not blocked by any visible UI freeze? (Throttling can be achieved by setting both endpoints to "https://httpstat.us/200?sleep=5000") - - [ ] Please ensure that release builds are run on a physical device with an ad-hoc archive. (For release builds, select Edit Scheme, change the Build Configuration to Release, and uncheck Debug Executable) + - [ ] On a throttled network, is the request timeout reasonable, and the main + thread not blocked by any visible UI freeze? (Throttling can be achieved + by setting both endpoints to "https://httpstat.us/200?sleep=5000") + - [ ] Please ensure that release builds are run on a physical device with an + ad-hoc archive. (For release builds, select Edit Scheme, change the + Build Configuration to Release, and uncheck Debug Executable) ### Release steps * Once the pull request is merged, publish the release by running `make release` -* Click "Publish Release" in the freshly opened GitHub release page +* A GitHub release page will open. Fill in the release notes: `vMaj.Min.Patch` + as a title and a summary of the changes from the CHANGELOG. Look to previous + releases for style guidance; _"This release fixes a number of issues..."_ etc. +* Click "Publish Release". * Perform post-release checks: - [ ] Have all Docs and dashboard PRs been merged? - [ ] Do the installation instructions work using the released artefact? - - [ ] Can a freshly created example app send an error report from a release build, using the released artefact? - - [ ] Do the existing example apps send an error report using the released artefact? -* Make releases to downstream libraries, if appropriate (generally for bug fixes) + - [ ] Can a freshly created example app send an error report from a release + build, using the released artefact? + - [ ] Do the existing example apps send an error report using the released + artefact? +* Plan to make releases to downstream libraries once adoption of the main + library has begun, if appropriate (generally for bug fixes). These include: + * [bugsnag-react-native](https://github.com/bugsnag/bugsnag-react-native) + * [bugsnag-cocos2dx](https://github.com/bugsnag/bugsnag-cocos2dx) + * [bugsnag-unity](https://github.com/bugsnag/bugsnag-unity) + diff --git a/OSX/Bugsnag.xcodeproj/project.pbxproj b/OSX/Bugsnag.xcodeproj/project.pbxproj index f8694438f..090423db4 100644 --- a/OSX/Bugsnag.xcodeproj/project.pbxproj +++ b/OSX/Bugsnag.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 0071CB53246074BD00F562B1 /* BSG_KSMachHeaders.m in Sources */ = {isa = PBXBuildFile; fileRef = 0071CB51246074BD00F562B1 /* BSG_KSMachHeaders.m */; }; + 0071CB54246074BD00F562B1 /* BSG_KSMachHeaders.h in Headers */ = {isa = PBXBuildFile; fileRef = 0071CB52246074BD00F562B1 /* BSG_KSMachHeaders.h */; }; 4B406C1822CAD96400464D1D /* BugsnagCollectionsBSGDictMergeTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B406C1622CAD96400464D1D /* BugsnagCollectionsBSGDictMergeTest.m */; }; 4B406C1922CAD96400464D1D /* BugsnagCollectionsBSGDictSetSafeObjectTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B406C1722CAD96400464D1D /* BugsnagCollectionsBSGDictSetSafeObjectTest.m */; }; 4B775FD422CBE02F004839C5 /* BugsnagCollectionsBSGDictInsertIfNotNilTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B775FD222CBE02A004839C5 /* BugsnagCollectionsBSGDictInsertIfNotNilTest.m */; }; @@ -43,6 +45,8 @@ 8A87352C1C6D3B1600EDBD5B /* BSG_KSCrashReportWriter.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A87352B1C6D3B1600EDBD5B /* BSG_KSCrashReportWriter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8ACF0F752018136200173809 /* BugsnagCrashReportTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2C8FE11C6BC38200846019 /* BugsnagCrashReportTests.m */; }; 8AD9FA891E086351002859A7 /* BugsnagConfigurationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD9FA851E0862DC002859A7 /* BugsnagConfigurationTests.m */; }; + E694862324CB1C5F002077D1 /* BSG_RFC3339DateTool.m in Sources */ = {isa = PBXBuildFile; fileRef = E694862124CB1C5F002077D1 /* BSG_RFC3339DateTool.m */; }; + E694862424CB1C5F002077D1 /* BSG_RFC3339DateTool.h in Headers */ = {isa = PBXBuildFile; fileRef = E694862224CB1C5F002077D1 /* BSG_RFC3339DateTool.h */; }; E72352C11F55924A00436528 /* BSGConnectivity.h in Headers */ = {isa = PBXBuildFile; fileRef = E72352BF1F55924A00436528 /* BSGConnectivity.h */; }; E72352C21F55924A00436528 /* BSGConnectivity.m in Sources */ = {isa = PBXBuildFile; fileRef = E72352C01F55924A00436528 /* BSGConnectivity.m */; }; E7433AD21F4F64EF00C082D1 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 8A2C8FF11C6BC3A800846019 /* libz.tbd */; }; @@ -147,8 +151,6 @@ E79E6BD01F4E3850002B35F9 /* BSG_KSSysCtl.h in Headers */ = {isa = PBXBuildFile; fileRef = E79E6B641F4E3850002B35F9 /* BSG_KSSysCtl.h */; }; E79E6BD51F4E3850002B35F9 /* NSError+BSG_SimpleConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = E79E6B691F4E3850002B35F9 /* NSError+BSG_SimpleConstructor.h */; }; E79E6BD61F4E3850002B35F9 /* NSError+BSG_SimpleConstructor.m in Sources */ = {isa = PBXBuildFile; fileRef = E79E6B6A1F4E3850002B35F9 /* NSError+BSG_SimpleConstructor.m */; }; - E79E6BD91F4E3850002B35F9 /* BSG_RFC3339DateTool.h in Headers */ = {isa = PBXBuildFile; fileRef = E79E6B6D1F4E3850002B35F9 /* BSG_RFC3339DateTool.h */; }; - E79E6BDA1F4E3850002B35F9 /* BSG_RFC3339DateTool.m in Sources */ = {isa = PBXBuildFile; fileRef = E79E6B6E1F4E3850002B35F9 /* BSG_RFC3339DateTool.m */; }; E79E6BDB1F4E3850002B35F9 /* BSG_KSCrashReportFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = E79E6B711F4E3850002B35F9 /* BSG_KSCrashReportFilter.h */; }; E79E6BDC1F4E3850002B35F9 /* BSG_KSCrashReportFilterCompletion.h in Headers */ = {isa = PBXBuildFile; fileRef = E79E6B721F4E3850002B35F9 /* BSG_KSCrashReportFilterCompletion.h */; }; E7CE78BB1FD94E77001D07E0 /* KSCrashReportConverter_Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = E7CE78991FD94E60001D07E0 /* KSCrashReportConverter_Tests.m */; }; @@ -183,6 +185,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 0071CB51246074BD00F562B1 /* BSG_KSMachHeaders.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSG_KSMachHeaders.m; sourceTree = ""; }; + 0071CB52246074BD00F562B1 /* BSG_KSMachHeaders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSG_KSMachHeaders.h; sourceTree = ""; }; 4B406C1622CAD96400464D1D /* BugsnagCollectionsBSGDictMergeTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BugsnagCollectionsBSGDictMergeTest.m; sourceTree = ""; }; 4B406C1722CAD96400464D1D /* BugsnagCollectionsBSGDictSetSafeObjectTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BugsnagCollectionsBSGDictSetSafeObjectTest.m; sourceTree = ""; }; 4B775FD222CBE02A004839C5 /* BugsnagCollectionsBSGDictInsertIfNotNilTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BugsnagCollectionsBSGDictInsertIfNotNilTest.m; sourceTree = ""; }; @@ -227,6 +231,8 @@ 8A6C6FB02257884C00E8EF24 /* BSGOutOfMemoryWatchdog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSGOutOfMemoryWatchdog.h; path = ../Source/BSGOutOfMemoryWatchdog.h; sourceTree = ""; }; 8A87352B1C6D3B1600EDBD5B /* BSG_KSCrashReportWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSG_KSCrashReportWriter.h; path = ../Source/BSG_KSCrashReportWriter.h; sourceTree = SOURCE_ROOT; }; 8AD9FA851E0862DC002859A7 /* BugsnagConfigurationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BugsnagConfigurationTests.m; path = ../Tests/BugsnagConfigurationTests.m; sourceTree = SOURCE_ROOT; }; + E694862124CB1C5F002077D1 /* BSG_RFC3339DateTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BSG_RFC3339DateTool.m; path = ../Source/BSG_RFC3339DateTool.m; sourceTree = ""; }; + E694862224CB1C5F002077D1 /* BSG_RFC3339DateTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSG_RFC3339DateTool.h; path = ../Source/BSG_RFC3339DateTool.h; sourceTree = ""; }; E72352BF1F55924A00436528 /* BSGConnectivity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSGConnectivity.h; path = ../Source/BSGConnectivity.h; sourceTree = SOURCE_ROOT; }; E72352C01F55924A00436528 /* BSGConnectivity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BSGConnectivity.m; path = ../Source/BSGConnectivity.m; sourceTree = SOURCE_ROOT; }; E762E9F71F73F7E900E82B43 /* BugsnagHandledStateTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BugsnagHandledStateTest.m; path = ../Tests/BugsnagHandledStateTest.m; sourceTree = SOURCE_ROOT; }; @@ -331,8 +337,6 @@ E79E6B641F4E3850002B35F9 /* BSG_KSSysCtl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSG_KSSysCtl.h; path = ../Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSSysCtl.h; sourceTree = SOURCE_ROOT; }; E79E6B691F4E3850002B35F9 /* NSError+BSG_SimpleConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSError+BSG_SimpleConstructor.h"; path = "../Source/KSCrash/Source/KSCrash/Recording/Tools/NSError+BSG_SimpleConstructor.h"; sourceTree = SOURCE_ROOT; }; E79E6B6A1F4E3850002B35F9 /* NSError+BSG_SimpleConstructor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSError+BSG_SimpleConstructor.m"; path = "../Source/KSCrash/Source/KSCrash/Recording/Tools/NSError+BSG_SimpleConstructor.m"; sourceTree = SOURCE_ROOT; }; - E79E6B6D1F4E3850002B35F9 /* BSG_RFC3339DateTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSG_RFC3339DateTool.h; path = ../Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_RFC3339DateTool.h; sourceTree = SOURCE_ROOT; }; - E79E6B6E1F4E3850002B35F9 /* BSG_RFC3339DateTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BSG_RFC3339DateTool.m; path = ../Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_RFC3339DateTool.m; sourceTree = SOURCE_ROOT; }; E79E6B711F4E3850002B35F9 /* BSG_KSCrashReportFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSG_KSCrashReportFilter.h; path = ../Source/KSCrash/Source/KSCrash/Reporting/Filters/BSG_KSCrashReportFilter.h; sourceTree = SOURCE_ROOT; }; E79E6B721F4E3850002B35F9 /* BSG_KSCrashReportFilterCompletion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSG_KSCrashReportFilterCompletion.h; path = ../Source/KSCrash/Source/KSCrash/Reporting/Filters/BSG_KSCrashReportFilterCompletion.h; sourceTree = SOURCE_ROOT; }; E7CE78871FD94E5F001D07E0 /* KSMach_Tests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSMach_Tests.m; sourceTree = ""; }; @@ -405,6 +409,8 @@ 8A3C591123968B3600B344AA /* BugsnagPlugin.h */, 8A6C6FB02257884C00E8EF24 /* BSGOutOfMemoryWatchdog.h */, 8A6C6FAF2257884C00E8EF24 /* BSGOutOfMemoryWatchdog.m */, + E694862224CB1C5F002077D1 /* BSG_RFC3339DateTool.h */, + E694862124CB1C5F002077D1 /* BSG_RFC3339DateTool.m */, E791483E1FD82B35003EFEBF /* BugsnagApiClient.h */, E791483D1FD82B35003EFEBF /* BugsnagApiClient.m */, E79148401FD82B35003EFEBF /* BugsnagFileStore.h */, @@ -582,6 +588,8 @@ E79E6B411F4E3850002B35F9 /* Tools */ = { isa = PBXGroup; children = ( + 0071CB52246074BD00F562B1 /* BSG_KSMachHeaders.h */, + 0071CB51246074BD00F562B1 /* BSG_KSMachHeaders.m */, E79E6B421F4E3850002B35F9 /* BSG_KSArchSpecific.h */, E79E6B431F4E3850002B35F9 /* BSG_KSBacktrace.c */, E79E6B441F4E3850002B35F9 /* BSG_KSBacktrace.h */, @@ -617,8 +625,6 @@ E79E6B641F4E3850002B35F9 /* BSG_KSSysCtl.h */, E79E6B691F4E3850002B35F9 /* NSError+BSG_SimpleConstructor.h */, E79E6B6A1F4E3850002B35F9 /* NSError+BSG_SimpleConstructor.m */, - E79E6B6D1F4E3850002B35F9 /* BSG_RFC3339DateTool.h */, - E79E6B6E1F4E3850002B35F9 /* BSG_RFC3339DateTool.m */, ); name = Tools; path = ../Source/KSCrash/Source/KSCrash/Recording/Tools; @@ -720,6 +726,7 @@ E79E6B9C1F4E3850002B35F9 /* BSG_KSSystemInfo.h in Headers */, 8A2C8FD71C6BC2C800846019 /* BugsnagMetaData.h in Headers */, E79E6B021F4E3847002B35F9 /* BugsnagCrashSentry.h in Headers */, + 0071CB54246074BD00F562B1 /* BSG_KSMachHeaders.h in Headers */, E79E6B911F4E3850002B35F9 /* BSG_KSCrashReport.h in Headers */, 8A48EF271EAA805D00B70024 /* BugsnagLogger.h in Headers */, E79E6BCC1F4E3850002B35F9 /* BSG_KSSingleton.h in Headers */, @@ -744,8 +751,8 @@ E79E6BC61F4E3850002B35F9 /* BSG_KSObjC.h in Headers */, E79E6BCE1F4E3850002B35F9 /* BSG_KSString.h in Headers */, E79E6B921F4E3850002B35F9 /* BSG_KSCrashReportFields.h in Headers */, - E79E6BD91F4E3850002B35F9 /* BSG_RFC3339DateTool.h in Headers */, E72352C11F55924A00436528 /* BSGConnectivity.h in Headers */, + E694862424CB1C5F002077D1 /* BSG_RFC3339DateTool.h in Headers */, 8A2C8FDD1C6BC2C800846019 /* BugsnagSink.h in Headers */, 8A87352C1C6D3B1600EDBD5B /* BSG_KSCrashReportWriter.h in Headers */, E79148461FD82B36003EFEBF /* BugsnagSession.h in Headers */, @@ -853,6 +860,7 @@ files = ( E79E6BCD1F4E3850002B35F9 /* BSG_KSString.c in Sources */, E79E6BCF1F4E3850002B35F9 /* BSG_KSSysCtl.c in Sources */, + E694862324CB1C5F002077D1 /* BSG_RFC3339DateTool.m in Sources */, 8A2C8FD41C6BC2C800846019 /* BugsnagConfiguration.m in Sources */, 8A627CDA1EC3B75200F7C04E /* BSGSerialization.m in Sources */, E79E6BAA1F4E3850002B35F9 /* BSG_KSCrashSentry_Signal.c in Sources */, @@ -895,6 +903,7 @@ E79E6BA81F4E3850002B35F9 /* BSG_KSCrashSentry_NSException.m in Sources */, E79E6B901F4E3850002B35F9 /* BSG_KSCrashReport.c in Sources */, 8A2C8FD81C6BC2C800846019 /* BugsnagMetaData.m in Sources */, + 0071CB53246074BD00F562B1 /* BSG_KSMachHeaders.m in Sources */, E79E6BA51F4E3850002B35F9 /* BSG_KSCrashSentry_MachException.c in Sources */, E79E6BB41F4E3850002B35F9 /* BSG_KSDynamicLinker.c in Sources */, E79E6B031F4E3847002B35F9 /* BugsnagCrashSentry.m in Sources */, @@ -904,7 +913,6 @@ E79E6B891F4E3850002B35F9 /* BSG_KSCrash.m in Sources */, E79E6BAC1F4E3850002B35F9 /* BSG_KSCrashSentry_User.c in Sources */, E79148581FD82B36003EFEBF /* BugsnagFileStore.m in Sources */, - E79E6BDA1F4E3850002B35F9 /* BSG_RFC3339DateTool.m in Sources */, E72352C21F55924A00436528 /* BSGConnectivity.m in Sources */, 8A530CB922FDC38300F0C108 /* BSG_KSCrashIdentifier.m in Sources */, ); diff --git a/Source/BSGOutOfMemoryWatchdog.m b/Source/BSGOutOfMemoryWatchdog.m index ac71776d4..6c82a1e4e 100644 --- a/Source/BSGOutOfMemoryWatchdog.m +++ b/Source/BSGOutOfMemoryWatchdog.m @@ -13,6 +13,7 @@ #import "Bugsnag.h" #import "BugsnagKSCrashSysInfoParser.h" #import "BugsnagSessionTracker.h" +#import "BSG_RFC3339DateTool.h" @interface BSGOutOfMemoryWatchdog () @property(nonatomic, getter=isWatching) BOOL watching; @@ -144,8 +145,8 @@ - (void)handleTransitionToBackground:(NSNotification *)note { } - (void)handleLowMemoryChange:(NSNotification *)note { - self.cachedFileInfo[@"device"][@"lowMemory"] = [[Bugsnag payloadDateFormatter] - stringFromDate:[NSDate date]]; + self.cachedFileInfo[@"device"][@"lowMemory"] = + [BSG_RFC3339DateTool stringFromDate:[NSDate date]]; [self writeSentinelFile]; } @@ -243,6 +244,8 @@ - (NSMutableDictionary *)generateCacheInfoWithConfig:(BugsnagConfiguration *)con app[@"releaseStage"] = config.releaseStage; app[@"version"] = systemInfo[@BSG_KSSystemField_BundleShortVersion] ?: @""; app[@"bundleVersion"] = systemInfo[@BSG_KSSystemField_BundleVersion] ?: @""; + // 'codeBundleId' only (optionally) exists for React Native clients and defaults otherwise to nil + app[@"codeBundleId"] = [config codeBundleId]; #if BSGOOMAvailable UIApplicationState state = [BSG_KSSystemInfo currentAppState]; app[@"inForeground"] = @([BSG_KSSystemInfo isInForeground:state]); @@ -262,8 +265,12 @@ - (NSMutableDictionary *)generateCacheInfoWithConfig:(BugsnagConfiguration *)con // device[@"lowMemory"] is initially unset device[@"osBuild"] = systemInfo[@BSG_KSSystemField_OSVersion]; device[@"osVersion"] = systemInfo[@BSG_KSSystemField_SystemVersion]; + device[@"osName"] = systemInfo[@BSG_KSSystemField_SystemName]; + // Translated from 'iDeviceMaj,Min' into human-readable "iPhone X" description on the server device[@"model"] = systemInfo[@BSG_KSSystemField_Machine]; + device[@"modelNumber"] = systemInfo[@ BSG_KSSystemField_Model]; device[@"wordSize"] = @(PLATFORM_WORD_SIZE); + device[@"locale"] = [[NSLocale currentLocale] localeIdentifier]; #if TARGET_OS_SIMULATOR device[@"simulator"] = @YES; #else diff --git a/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_RFC3339DateTool.h b/Source/BSG_RFC3339DateTool.h similarity index 100% rename from Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_RFC3339DateTool.h rename to Source/BSG_RFC3339DateTool.h diff --git a/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_RFC3339DateTool.m b/Source/BSG_RFC3339DateTool.m similarity index 61% rename from Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_RFC3339DateTool.m rename to Source/BSG_RFC3339DateTool.m index 26f5e44bf..fc4054115 100644 --- a/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_RFC3339DateTool.m +++ b/Source/BSG_RFC3339DateTool.m @@ -24,13 +24,18 @@ #import "BSG_RFC3339DateTool.h" +@interface BSG_RFC3339DateTool () ++ (NSDateFormatter *)iosFormatterInstance; +@end + @implementation BSG_RFC3339DateTool -static NSString *const kDateFormatterKey = @"RfcDateFormatter"; +static NSString *const kRfcDateFormatterKey = @"RfcDateFormatter"; +static NSString *const kIsoDateFormatterKey = @"IsoDateFormatter"; + (NSDateFormatter *)sharedInstance { NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary]; - NSDateFormatter *formatter = threadDict[kDateFormatterKey]; + NSDateFormatter *formatter = threadDict[kRfcDateFormatterKey]; if (formatter == nil) { formatter = [NSDateFormatter new]; @@ -39,8 +44,30 @@ + (NSDateFormatter *)sharedInstance { [formatter setLocale:locale]; [formatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"]; [formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; - threadDict[kDateFormatterKey] = formatter; + threadDict[kRfcDateFormatterKey] = formatter; } + + formatter = threadDict[kRfcDateFormatterKey]; + return formatter; +} + +/** +Used internally to convert any dates with timezones (from older notifier versions) to Zulu time + */ ++ (NSDateFormatter *)iosFormatterInstance { + NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary]; + NSDateFormatter *formatter = threadDict[kIsoDateFormatterKey]; + if (formatter == nil) { + formatter = [NSDateFormatter new]; + NSLocale *locale = + [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; + [formatter setLocale:locale]; + [formatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssZZZ"]; + [formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; + threadDict[kIsoDateFormatterKey] = formatter; + } + + formatter = threadDict[kIsoDateFormatterKey]; return formatter; } @@ -55,7 +82,11 @@ + (NSDate *)dateFromString:(NSString *)string { if (![string isKindOfClass:[NSString class]]) { return nil; } - return [[self sharedInstance] dateFromString:string]; + NSDate *date = [[self sharedInstance] dateFromString:string]; + if (!date) { + date = [[self iosFormatterInstance] dateFromString:string]; + } + return date; } + (NSString *)stringFromUNIXTimestamp:(unsigned long long)timestamp { diff --git a/Source/Bugsnag.h b/Source/Bugsnag.h index b2688526f..97fc2caeb 100644 --- a/Source/Bugsnag.h +++ b/Source/Bugsnag.h @@ -199,8 +199,6 @@ static NSString *_Nonnull const BugsnagSeverityInfo = @"info"; */ + (void)clearBreadcrumbs; -+ (NSDateFormatter *_Nonnull)payloadDateFormatter; - + (void)setSuspendThreadsForUserReported:(BOOL)suspendThreadsForUserReported; + (void)setReportWhenDebuggerIsAttached:(BOOL)reportWhenDebuggerIsAttached; + (void)setThreadTracingEnabled:(BOOL)threadTracingEnabled; diff --git a/Source/Bugsnag.m b/Source/Bugsnag.m index 6e62ca7f2..bce8b946d 100644 --- a/Source/Bugsnag.m +++ b/Source/Bugsnag.m @@ -266,16 +266,6 @@ + (BOOL)resumeSession { } } -+ (NSDateFormatter *)payloadDateFormatter { - static NSDateFormatter *formatter; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - formatter = [NSDateFormatter new]; - formatter.dateFormat = @"yyyy'-'MM'-'dd'T'HH':'mm':'ssZZZ"; - }); - return formatter; -} - + (void)setSuspendThreadsForUserReported:(BOOL)suspendThreadsForUserReported { if ([self bugsnagStarted]) { [[BSG_KSCrash sharedInstance] diff --git a/Source/BugsnagBreadcrumb.m b/Source/BugsnagBreadcrumb.m index c524d5681..7787f1c85 100644 --- a/Source/BugsnagBreadcrumb.m +++ b/Source/BugsnagBreadcrumb.m @@ -27,6 +27,7 @@ #import "Bugsnag.h" #import "BugsnagLogger.h" #import "BugsnagKeys.h" +#import "BSG_RFC3339DateTool.h" static NSString *const BSGBreadcrumbDefaultName = @"manual"; static NSUInteger const BSGBreadcrumbMaxByteSize = 4096; @@ -82,7 +83,7 @@ - (BOOL)isValid { - (NSDictionary *)objectValue { @synchronized (self) { NSString *timestamp = - [[Bugsnag payloadDateFormatter] stringFromDate:_timestamp]; + [BSG_RFC3339DateTool stringFromDate:_timestamp]; if (timestamp && _name.length > 0) { NSMutableDictionary *metadata = [NSMutableDictionary new]; for (NSString *key in _metadata) { diff --git a/Source/BugsnagNotifier.m b/Source/BugsnagNotifier.m index af1c28aa2..039e74753 100644 --- a/Source/BugsnagNotifier.m +++ b/Source/BugsnagNotifier.m @@ -47,7 +47,7 @@ #import #endif -NSString *const NOTIFIER_VERSION = @"5.23.0"; +NSString *const NOTIFIER_VERSION = @"5.23.5"; NSString *const NOTIFIER_URL = @"https://github.com/bugsnag/bugsnag-cocoa"; NSString *const BSTabCrash = @"crash"; NSString *const BSAttributeDepth = @"depth"; @@ -471,7 +471,7 @@ - (void)watchLifecycleEvents:(NSNotificationCenter *)center { #if TARGET_OS_TV || TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE foregroundName = UIApplicationWillEnterForegroundNotification; - backgroundName = UIApplicationWillEnterForegroundNotification; + backgroundName = UIApplicationDidEnterBackgroundNotification; #elif TARGET_OS_MAC foregroundName = NSApplicationWillBecomeActiveNotification; backgroundName = NSApplicationDidFinishLaunchingNotification; @@ -802,8 +802,7 @@ - (void)orientationChanged:(NSNotification *)notif { - (void)lowMemoryWarning:(NSNotification *)notif { [[self state] addAttribute:BSEventLowMemoryWarning - withValue:[[Bugsnag payloadDateFormatter] - stringFromDate:[NSDate date]] + withValue:[BSG_RFC3339DateTool stringFromDate:[NSDate date]] toTabWithName:BSGKeyDeviceState]; if ([self.configuration automaticallyCollectBreadcrumbs]) { [self sendBreadcrumbForNotification:notif]; diff --git a/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m b/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m index c703c0c90..7ed2483f8 100644 --- a/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m +++ b/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m @@ -24,6 +24,7 @@ // THE SOFTWARE. // +#import #import "BSG_KSCrashAdvanced.h" #import "BSG_KSCrashC.h" @@ -31,6 +32,7 @@ #import "BSG_KSJSONCodecObjC.h" #import "BSG_KSSingleton.h" #import "BSG_KSSystemCapabilities.h" +#import "BSG_KSMachHeaders.h" #import "NSError+BSG_SimpleConstructor.h" //#define BSG_KSLogger_LocalLevel TRACE @@ -49,6 +51,10 @@ #define BSG_KSCRASH_DefaultReportFilesDirectory @"KSCrashReports" #endif +#ifndef BSG_INITIAL_MACH_BINARY_IMAGE_ARRAY_SIZE +#define BSG_INITIAL_MACH_BINARY_IMAGE_ARRAY_SIZE 400 +#endif + // ============================================================================ #pragma mark - Constants - // ============================================================================ @@ -219,13 +225,16 @@ - (NSString *)stateFilePath { } - (BOOL)install { + // Maintain a cache of info about dynamically loaded binary images + [self listenForLoadedBinaries]; + _handlingCrashTypes = bsg_kscrash_install( [self.crashReportPath UTF8String], [self.recrashReportPath UTF8String], [self.stateFilePath UTF8String], [self.nextCrashID UTF8String]); if (self.handlingCrashTypes == 0) { return false; } - + #if BSG_KSCRASH_HAS_UIKIT NSNotificationCenter *nCenter = [NSNotificationCenter defaultCenter]; [nCenter addObserver:self @@ -253,6 +262,21 @@ - (BOOL)install { return true; } +/** + * Set up listeners for un/loaded frameworks. 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 loading mach headers as part of our normal event handling + * behaviour. + */ +- (void)listenForLoadedBinaries { + bsg_check_unfair_lock_support(); + bsg_initialise_mach_binary_headers(BSG_INITIAL_MACH_BINARY_IMAGE_ARRAY_SIZE); + + // Note: Access to DYLD's binary image store is guarded by locks. + _dyld_register_func_for_remove_image(&bsg_mach_binary_image_removed); + _dyld_register_func_for_add_image(&bsg_mach_binary_image_added); +} + - (void)sendAllReportsWithCompletion: (BSG_KSCrashReportFilterCompletion)onCompletion { [self.crashReportStore pruneFilesLeaving:self.maxStoredReports]; diff --git a/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c b/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c index a9ea67e11..616de183b 100644 --- a/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c +++ b/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c @@ -36,6 +36,7 @@ #include "BSG_KSObjC.h" #include "BSG_KSSignalInfo.h" #include "BSG_KSString.h" +#include "BSG_KSMachHeaders.h" //#define BSG_kSLogger_LocalLevel TRACE #include "BSG_KSLogger.h" @@ -1084,70 +1085,23 @@ int bsg_kscrw_i_threadIndex(const thread_t thread) { * * @param key The object key, if needed. * - * @param index Which image to write about. + * @param index Cached info about the binary image. */ void bsg_kscrw_i_writeBinaryImage(const BSG_KSCrashReportWriter *const writer, - const char *const key, const uint32_t index) { - const struct mach_header *header = _dyld_get_image_header(index); - if (header == NULL) { - return; - } - - uintptr_t cmdPtr = bsg_ksdlfirstCmdAfterHeader(header); - if (cmdPtr == 0) { - return; - } - - // Look for the TEXT segment to get the image size. - // Also look for a UUID command. - uint64_t imageSize = 0; - uint64_t imageVmAddr = 0; - uint8_t *uuid = NULL; - - for (uint32_t iCmd = 0; iCmd < header->ncmds; iCmd++) { - struct load_command *loadCmd = (struct load_command *)cmdPtr; - switch (loadCmd->cmd) { - case LC_SEGMENT: { - struct segment_command *segCmd = (struct segment_command *)cmdPtr; - if (strcmp(segCmd->segname, SEG_TEXT) == 0) { - imageSize = segCmd->vmsize; - imageVmAddr = segCmd->vmaddr; - } - break; - } - case LC_SEGMENT_64: { - struct segment_command_64 *segCmd = - (struct segment_command_64 *)cmdPtr; - if (strcmp(segCmd->segname, SEG_TEXT) == 0) { - imageSize = segCmd->vmsize; - imageVmAddr = segCmd->vmaddr; - } - break; - } - case LC_UUID: { - struct uuid_command *uuidCmd = (struct uuid_command *)cmdPtr; - uuid = uuidCmd->uuid; - break; - } - } - cmdPtr += loadCmd->cmdsize; - } - + const char *const key, + const uint32_t index) +{ + BSG_Mach_Binary_Image_Info info = *bsg_dyld_get_image_info(index); + writer->beginObject(writer, key); { - writer->addUIntegerElement(writer, BSG_KSCrashField_ImageAddress, - (uintptr_t)header); - writer->addUIntegerElement(writer, BSG_KSCrashField_ImageVmAddress, - imageVmAddr); - writer->addUIntegerElement(writer, BSG_KSCrashField_ImageSize, - imageSize); - writer->addStringElement(writer, BSG_KSCrashField_Name, - _dyld_get_image_name(index)); - writer->addUUIDElement(writer, BSG_KSCrashField_UUID, uuid); - writer->addIntegerElement(writer, BSG_KSCrashField_CPUType, - header->cputype); - writer->addIntegerElement(writer, BSG_KSCrashField_CPUSubType, - header->cpusubtype); + writer->addUIntegerElement(writer, BSG_KSCrashField_ImageAddress, (uintptr_t)info.header); + writer->addUIntegerElement(writer, BSG_KSCrashField_ImageVmAddress, info.imageVmAddr); + writer->addUIntegerElement(writer, BSG_KSCrashField_ImageSize, info.imageSize); + writer->addStringElement(writer, BSG_KSCrashField_Name, info.name); + writer->addUUIDElement(writer, BSG_KSCrashField_UUID, info.uuid); + writer->addIntegerElement(writer, BSG_KSCrashField_CPUType, info.header->cputype); + writer->addIntegerElement(writer, BSG_KSCrashField_CPUSubType, info.header->cpusubtype); } writer->endContainer(writer); } @@ -1159,12 +1113,14 @@ void bsg_kscrw_i_writeBinaryImage(const BSG_KSCrashReportWriter *const writer, * @param key The object key, if needed. */ void bsg_kscrw_i_writeBinaryImages(const BSG_KSCrashReportWriter *const writer, - const char *const key) { - const uint32_t imageCount = _dyld_image_count(); + const char *const key) +{ + const uint32_t imageCount = bsg_dyld_image_count(); writer->beginArray(writer, key); { for (uint32_t iImg = 0; iImg < imageCount; iImg++) { + // Threads are suspended at this point; no need to synchronise/lock bsg_kscrw_i_writeBinaryImage(writer, NULL, iImg); } } @@ -1658,9 +1614,6 @@ void bsg_kscrashreport_writeStandardReport( bsg_ksjsonendEncode(bsg_getJsonContext(writer)); - if (!bsg_ksfuflushWriteBuffer(fd)) { - BSG_KSLOG_ERROR("Failed to flush write buffer"); - } close(fd); } diff --git a/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReportStore.m b/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReportStore.m index a9ca1725a..909331620 100644 --- a/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReportStore.m +++ b/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReportStore.m @@ -83,9 +83,10 @@ - (NSDictionary *)fileWithId:(NSString *)fileId { if (dict != nil) { return dict; } else { + NSError *error = nil; NSMutableDictionary *fileContents = [NSMutableDictionary new]; NSMutableDictionary *recrashReport = - [self readFile:[self pathToRecrashReportWithID:fileId] error:nil]; + [self readFile:[self pathToRecrashReportWithID:fileId] error:&error]; BSGDictInsertIfNotNil(fileContents, recrashReport, @BSG_KSCrashField_RecrashReport); return fileContents; } diff --git a/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m b/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m index 7c47457d7..d2008efaa 100644 --- a/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m +++ b/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.m @@ -263,9 +263,6 @@ bool bsg_kscrashstate_i_saveState(const BSG_KSCrash_State *const state, goto done; } result = bsg_ksjsonendEncode(&JSONContext); - if (!bsg_ksfuflushWriteBuffer(fd)) { - BSG_KSLOG_ERROR(@"Failed to flush write buffer"); - } done: close(fd); diff --git a/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_MachException.c b/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_MachException.c index 71452ab82..027e552dc 100644 --- a/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_MachException.c +++ b/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_MachException.c @@ -206,7 +206,7 @@ void *ksmachexc_i_handleExceptions(void *const userData) { const char *threadName = (const char *)userData; pthread_setname_np(threadName); - if (threadName == kThreadSecondary) { + if (strcmp(threadName, kThreadSecondary) == 0) { BSG_KSLOG_DEBUG("This is the secondary thread. Suspending."); thread_suspend(bsg_ksmachthread_self()); } diff --git a/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSDynamicLinker.c b/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSDynamicLinker.c index 7f79499a8..148647937 100644 --- a/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSDynamicLinker.c +++ b/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSDynamicLinker.c @@ -26,6 +26,7 @@ #include "BSG_KSDynamicLinker.h" #include "BSG_KSArchSpecific.h" +#include "BSG_KSMachHeaders.h" #include #include @@ -33,10 +34,10 @@ uint32_t bsg_ksdlimageNamed(const char *const imageName, bool exactMatch) { if (imageName != NULL) { - const uint32_t imageCount = _dyld_image_count(); - + const uint32_t imageCount = bsg_dyld_image_count(); + for (uint32_t iImg = 0; iImg < imageCount; iImg++) { - const char *name = _dyld_get_image_name(iImg); + const char *name = bsg_dyld_get_image_name(iImg); if (name == NULL) { continue; // name is null if the index is out of range per dyld(3) } else if (exactMatch) { @@ -57,7 +58,7 @@ const uint8_t *bsg_ksdlimageUUID(const char *const imageName, bool exactMatch) { if (imageName != NULL) { const uint32_t iImg = bsg_ksdlimageNamed(imageName, exactMatch); if (iImg != UINT32_MAX) { - const struct mach_header *header = _dyld_get_image_header(iImg); + const struct mach_header *header = bsg_dyld_get_image_header(iImg); if (header != NULL) { uintptr_t cmdPtr = bsg_ksdlfirstCmdAfterHeader(header); if (cmdPtr != 0) { @@ -96,15 +97,15 @@ uintptr_t bsg_ksdlfirstCmdAfterHeader(const struct mach_header *const header) { } uint32_t bsg_ksdlimageIndexContainingAddress(const uintptr_t address) { - const uint32_t imageCount = _dyld_image_count(); + const uint32_t imageCount = bsg_dyld_image_count(); const struct mach_header *header = 0; for (uint32_t iImg = 0; iImg < imageCount; iImg++) { - header = _dyld_get_image_header(iImg); + header = bsg_dyld_get_image_header(iImg); if (header != NULL) { // Look for a segment command with this address within its range. uintptr_t addressWSlide = - address - (uintptr_t)_dyld_get_image_vmaddr_slide(iImg); + address - bsg_dyld_get_image_vmaddr_slide(iImg); uintptr_t cmdPtr = bsg_ksdlfirstCmdAfterHeader(header); if (cmdPtr == 0) { continue; @@ -135,7 +136,7 @@ uint32_t bsg_ksdlimageIndexContainingAddress(const uintptr_t address) { } uintptr_t bsg_ksdlsegmentBaseOfImageIndex(const uint32_t idx) { - const struct mach_header *header = _dyld_get_image_header(idx); + const struct mach_header *header = bsg_dyld_get_image_header(idx); if (header == NULL) { return 0; } @@ -176,12 +177,12 @@ bool bsg_ksdldladdr(const uintptr_t address, Dl_info *const info) { if (idx == UINT_MAX) { return false; } - const struct mach_header *header = _dyld_get_image_header(idx); + const struct mach_header *header = bsg_dyld_get_image_header(idx); if (header == NULL) { return false; } const uintptr_t imageVMAddrSlide = - (uintptr_t)_dyld_get_image_vmaddr_slide(idx); + bsg_dyld_get_image_vmaddr_slide(idx); const uintptr_t addressWithSlide = address - imageVMAddrSlide; const uintptr_t segmentBase = bsg_ksdlsegmentBaseOfImageIndex(idx) + imageVMAddrSlide; @@ -189,7 +190,7 @@ bool bsg_ksdldladdr(const uintptr_t address, Dl_info *const info) { return false; } - info->dli_fname = _dyld_get_image_name(idx); + info->dli_fname = bsg_dyld_get_image_name(idx); info->dli_fbase = (void *)header; // Find symbol tables and get whichever symbol is closest to the address. @@ -244,12 +245,12 @@ bool bsg_ksdldladdr(const uintptr_t address, Dl_info *const info) { const void *bsg_ksdlgetSymbolAddrInImage(uint32_t imageIdx, const char *symbolName) { - const struct mach_header *header = _dyld_get_image_header(imageIdx); + const struct mach_header *header = bsg_dyld_get_image_header(imageIdx); if (header == NULL) { return NULL; } const uintptr_t imageVMAddrSlide = - (uintptr_t)_dyld_get_image_vmaddr_slide(imageIdx); + bsg_dyld_get_image_vmaddr_slide(imageIdx); const uintptr_t segmentBase = bsg_ksdlsegmentBaseOfImageIndex(imageIdx) + imageVMAddrSlide; if (segmentBase == 0) { @@ -290,7 +291,7 @@ const void *bsg_ksdlgetSymbolAddrInImage(uint32_t imageIdx, } const void *bsg_ksdlgetSymbolAddrInAnyImage(const char *symbolName) { - const uint32_t imageCount = _dyld_image_count(); + const uint32_t imageCount = bsg_dyld_image_count(); for (uint32_t iImg = 0; iImg < imageCount; iImg++) { const void *symbolAddr = bsg_ksdlgetSymbolAddrInImage(iImg, symbolName); diff --git a/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSFileUtils.c b/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSFileUtils.c index 029590042..fcbeec960 100644 --- a/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSFileUtils.c +++ b/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSFileUtils.c @@ -30,24 +30,9 @@ #include "BSG_KSLogger.h" #include -#include -#include #include -#include #include -/** Buffer size to use in the "writeFmt" functions. - * If the formatted output length would exceed this value, it is truncated. - */ -#ifndef BSG_KSFU_WriteFmtBufferSize -#define BSG_KSFU_WriteFmtBufferSize 1024 -#endif - -#define BUFFER_SIZE 65536 - -char charBuffer[BUFFER_SIZE]; -ssize_t bufferLen = 0; - const char *bsg_ksfulastPathEntry(const char *const path) { if (path == NULL) { return NULL; @@ -57,106 +42,42 @@ const char *bsg_ksfulastPathEntry(const char *const path) { return lastFile == NULL ? path : lastFile + 1; } -bool bsg_ksfuflushWriteBuffer(const int fd) { - const char *pos = charBuffer; - while (bufferLen > 0) { - ssize_t bytesWritten = write(fd, pos, (size_t)bufferLen); - if (bytesWritten == -1) { - BSG_KSLOG_ERROR("Could not write to fd %d: %s", fd, - strerror(errno)); - return false; - } - bufferLen -= bytesWritten; - pos += bytesWritten; - } - return true; -} - bool bsg_ksfuwriteBytesToFD(const int fd, const char *const bytes, ssize_t length) { - - for (ssize_t k = 0; k < length; k++) { - if (bufferLen >= BUFFER_SIZE) { - if (!bsg_ksfuflushWriteBuffer(fd)) { - return false; - } + ssize_t bytesRemaining = length; + ssize_t bytesWritten = 0; + const char *unwrittenBytes = (const char *)bytes; + + // write(2) attempts to write the entire length but may write less than + // that, the exact number of bytes are specified in the return value. In + // the (unlikely) event that the bytes written are less than length, this + // function retries with the remaining bytes until all bytes are written, + // handling potential error cases as needed. + while (bytesRemaining > 0) { + bytesWritten = write(fd, unwrittenBytes, bytesRemaining); + if (bytesWritten == -1) { + // Retry as-is if a signal interrupt occurred, as its a recoverable + // error. Otherwise exit early as the file descriptor cannot be written + // (due to lack of disk space, invalid fd, invalid file offset etc). + // + // write(2): Upon successful completion the number of bytes which were + // written is returned. Otherwise, a -1 is returned and the global + // variable errno is set to indicate the error. + // + // ERRORS + // The write(), writev(), and pwrite() system calls will fail and + // the file pointer will remain unchanged if: + // + // ... + // [EINTR] A signal interrupts the write before it could be completed. + if (errno != EINTR) { + return false; // Unrecoverable } - charBuffer[bufferLen] = bytes[k]; - bufferLen++; + } else { + bytesRemaining -= bytesWritten; + unwrittenBytes += bytesWritten; + } } - return true; -} -bool bsg_ksfureadBytesFromFD(const int fd, char *const bytes, ssize_t length) { - char *pos = bytes; - while (length > 0) { - ssize_t bytesRead = read(fd, pos, (size_t)length); - if (bytesRead == -1) { - BSG_KSLOG_ERROR("Could not write to fd %d: %s", fd, - strerror(errno)); - return false; - } - length -= bytesRead; - pos += bytesRead; - } return true; } - -bool bsg_ksfuwriteStringToFD(const int fd, const char *const string) { - if (*string != 0) { - size_t bytesToWrite = strlen(string); - const char *pos = string; - while (bytesToWrite > 0) { - ssize_t bytesWritten = write(fd, pos, bytesToWrite); - if (bytesWritten == -1) { - BSG_KSLOG_ERROR("Could not write to fd %d: %s", fd, - strerror(errno)); - return false; - } - bytesToWrite -= (size_t)bytesWritten; - pos += bytesWritten; - } - return true; - } - return false; -} - -bool bsg_ksfuwriteFmtToFD(const int fd, const char *const fmt, ...) { - if (*fmt != 0) { - va_list args; - va_start(args, fmt); - bool result = bsg_ksfuwriteFmtArgsToFD(fd, fmt, args); - va_end(args); - return result; - } - return false; -} - -bool bsg_ksfuwriteFmtArgsToFD(const int fd, const char *const fmt, - va_list args) { - if (*fmt != 0) { - char buffer[BSG_KSFU_WriteFmtBufferSize]; - vsnprintf(buffer, sizeof(buffer), fmt, args); - return bsg_ksfuwriteStringToFD(fd, buffer); - } - return false; -} - -ssize_t bsg_ksfureadLineFromFD(const int fd, char *const buffer, - const int maxLength) { - char *end = buffer + maxLength - 1; - *end = 0; - char *ch; - for (ch = buffer; ch < end; ch++) { - ssize_t bytesRead = read(fd, ch, 1); - if (bytesRead < 0) { - BSG_KSLOG_ERROR("Could not read from fd %d: %s", fd, - strerror(errno)); - return -1; - } else if (bytesRead == 0 || *ch == '\n') { - break; - } - } - *ch = 0; - return ch - buffer; -} diff --git a/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSFileUtils.h b/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSFileUtils.h index 7b89277ef..2c64c0a35 100644 --- a/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSFileUtils.h +++ b/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSFileUtils.h @@ -34,9 +34,7 @@ extern "C" { #endif -#include #include -#include #include /** Get the last entry in a file path. Assumes UNIX style separators. @@ -66,62 +64,6 @@ bool bsg_ksfuwriteBytesToFD(const int fd, const char *bytes, ssize_t length); */ bool bsg_ksfuflushWriteBuffer(const int fd); -/** Read bytes from a file descriptor. - * - * @param fd The file descriptor. - * - * @param bytes Buffer to store the bytes in. - * - * @param length The number of bytes to read. - * - * @return true if the operation was successful. - */ -bool bsg_ksfureadBytesFromFD(const int fd, char *bytes, ssize_t length); - -/** Write a string to a file. - * - * @param fd The file descriptor. - * - * @param string The string to write. - * - * @return true if successful. - */ -bool bsg_ksfuwriteStringToFD(const int fd, const char *string); - -/** Write a formatted string to a file. - * - * @param fd The file descriptor. - * - * @param fmt The format specifier, followed by its arguments. - * - * @return true if successful. - */ -bool bsg_ksfuwriteFmtToFD(const int fd, const char *fmt, ...); - -/** Write a formatted string to a file. - * - * @param fd The file descriptor. - * - * @param fmt The format specifier. - * - * @param args The arguments list. - * - * @return true if successful. - */ -bool bsg_ksfuwriteFmtArgsToFD(const int fd, const char *fmt, va_list args); - -/** Read a single line from a file. - * - * @param fd The file descriptor. - * - * @param buffer The buffer to read into. - * - * @param maxLength The maximum length to read. - * - * @return The number of bytes read. - */ -ssize_t bsg_ksfureadLineFromFD(const int fd, char *buffer, int maxLength); - #ifdef __cplusplus } #endif diff --git a/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSJSONCodec.c b/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSJSONCodec.c index a2426af91..914f64b5e 100644 --- a/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSJSONCodec.c +++ b/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSJSONCodec.c @@ -127,7 +127,20 @@ int bsg_ksjsoncodec_i_appendEscapedString( } // Deal with complicated case (if any) + int result; for (; src < srcEnd; src++) { + + // If we add an escaped control character this may exceed the buffer by up to + // 6 characters: add this chunk now, reset the buffer and carry on + if (dst + 6 > workBuffer + BSG_KSJSONCODEC_WorkBufferSize) { + size_t encLength = (size_t)(dst - workBuffer); + unlikely_if((result = addJSONData(context, dst - encLength, encLength)) != + BSG_KSJSON_OK) { + return result; + } + dst = workBuffer; + } + switch (*src) { case '\\': case '\"': @@ -175,8 +188,7 @@ int bsg_ksjsoncodec_i_appendEscapedString( } } size_t encLength = (size_t)(dst - workBuffer); - dst -= encLength; - return addJSONData(context, dst, encLength); + return addJSONData(context, dst - encLength, encLength); } /** Escape a string for use with JSON and send to data handler. @@ -198,8 +210,8 @@ int bsg_ksjsoncodec_i_addEscapedString(BSG_KSJSONEncodeContext *const context, size_t offset = 0; while (offset < length) { size_t toAdd = length - offset; - unlikely_if(toAdd > BSG_KSJSONCODEC_WorkBufferSize / 2) { - toAdd = BSG_KSJSONCODEC_WorkBufferSize / 2; + unlikely_if(toAdd > BSG_KSJSONCODEC_WorkBufferSize) { + toAdd = BSG_KSJSONCODEC_WorkBufferSize; } result = bsg_ksjsoncodec_i_appendEscapedString(context, string + offset, toAdd); diff --git a/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.h b/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.h new file mode 100644 index 000000000..99cf90f7f --- /dev/null +++ b/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.h @@ -0,0 +1,109 @@ +// +// BSG_KSMachHeaders.h +// Bugsnag +// +// Created by Robin Macharg on 04/05/2020. +// Copyright © 2020 Bugsnag. All rights reserved. +// + +#ifndef BSG_KSMachHeaders_h +#define BSG_KSMachHeaders_h + +#import +#import +#import + +/** + * An encapsulation of the Mach header - either 64 or 32 bit, along with some additional information required for + * detailing a crash report's binary images. + */ +typedef struct { + const struct mach_header *header; /* The mach_header - 32 or 64 bit */ + uint64_t imageVmAddr; + uint64_t imageSize; + uint8_t *uuid; + const char* name; + intptr_t slide; +} BSG_Mach_Binary_Image_Info; + +/** + * MARK: - A Dynamic array container + * See: https://stackoverflow.com/a/3536261/2431627 + */ +typedef struct { + uint32_t used; + uint32_t size; + BSG_Mach_Binary_Image_Info *contents; +} BSG_Mach_Binary_Images; + + +// MARK: - Locking + +/** + * An OS-version-specific lock, used to synchronise access to the array of binary image info. A combination of + * compile-time determination of the OS and and run-time determination of the OS version is used to ensure that + * the correct lock mechanism is used. + * + * os_unfair_lock is available from specific OS versions onwards: + * https://developer.apple.com/documentation/os/os_unfair_lock + * + * It deprecates OSSpinLock: + * https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/spinlock.3.html + * + * The imported headers have specific version info: and + */ + +void bsg_spin_lock(void); +void bsg_spin_unlock(void); +void bsg_unfair_lock(void); +void bsg_unfair_unlock(void); +void bsg_dyld_cache_lock(void); +void bsg_dyld_cache_unlock(void); + +// MARK: - Replicate the DYLD API + +/** + * Returns the current number of images mapped in by dyld + */ +uint32_t bsg_dyld_image_count(void); + +/** + * Returns a pointer to the mach header of the image indexed by image_index. If imageIndex + * is out of range, NULL is returned. + */ +const struct mach_header* bsg_dyld_get_image_header(uint32_t imageIndex); + +/** + * Returns the virtural memory address slide amount of the image indexed by imageIndex. + * If image_index is out of range zero is returned. + */ +intptr_t bsg_dyld_get_image_vmaddr_slide(uint32_t imageIndex); + +/** + * Returns the name of the image indexed by imageIndex. + */ +const char* bsg_dyld_get_image_name(uint32_t imageIndex); + +BSG_Mach_Binary_Image_Info *bsg_dyld_get_image_info(uint32_t imageIndex); // An additional convenience function + +/** + * Called when a binary image is loaded. + */ +void bsg_mach_binary_image_added(const struct mach_header *mh, intptr_t slide); + +/** + * Called when a binary image is unloaded. + */ +void bsg_mach_binary_image_removed(const struct mach_header *mh, intptr_t slide); + +/** + * Create an empty array with initial capacity to hold Mach header info. + */ +BSG_Mach_Binary_Images *bsg_initialise_mach_binary_headers(uint32_t initialSize); + +/** + * Determines whether the OS supports unfair locks or not. + */ +void bsg_check_unfair_lock_support(void); + +#endif /* BSG_KSMachHeaders_h */ diff --git a/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.m b/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.m new file mode 100644 index 000000000..812a1dc63 --- /dev/null +++ b/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachHeaders.m @@ -0,0 +1,307 @@ +// +// BSG_KSMachHeaders.m +// Bugsnag +// +// Created by Robin Macharg on 04/05/2020. +// Copyright © 2020 Bugsnag. All rights reserved. +// + +#import +#import +#import +#import "BSG_KSDynamicLinker.h" +#import "BSG_KSMachHeaders.h" + +// MARK: - Locking + +static BSG_Mach_Binary_Images bsg_mach_binary_images; + +// Pragma's hide unavoidable (and expected) deprecation/unavailable warnings +_Pragma("clang diagnostic push") +_Pragma("clang diagnostic ignored \"-Wunguarded-availability\"") +static os_unfair_lock bsg_mach_binary_images_access_lock_unfair = OS_UNFAIR_LOCK_INIT; +_Pragma("clang diagnostic pop") + +_Pragma("clang diagnostic push") +_Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +static OSSpinLock bsg_mach_binary_images_access_lock_spin = OS_SPINLOCK_INIT; +_Pragma("clang diagnostic pop") + +static BOOL bsg_unfair_lock_supported; + +// Lock helpers. These use bulky Pragmas to hide warnings so are in their own functions for clarity. + +void bsg_spin_lock() { + _Pragma("clang diagnostic push") + _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") + OSSpinLockLock(&bsg_mach_binary_images_access_lock_spin); + _Pragma("clang diagnostic pop") +} + +void bsg_spin_unlock() { + _Pragma("clang diagnostic push") + _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") + OSSpinLockUnlock(&bsg_mach_binary_images_access_lock_spin); + _Pragma("clang diagnostic pop") +} + +void bsg_unfair_lock() { + _Pragma("clang diagnostic push") + _Pragma("clang diagnostic ignored \"-Wunguarded-availability\"") + os_unfair_lock_lock(&bsg_mach_binary_images_access_lock_unfair); + _Pragma("clang diagnostic pop") +} + +void bsg_unfair_unlock() { + _Pragma("clang diagnostic push") + _Pragma("clang diagnostic ignored \"-Wunguarded-availability\"") + os_unfair_lock_unlock(&bsg_mach_binary_images_access_lock_unfair); + _Pragma("clang diagnostic pop") +} + +// Lock and unlock sections of code + +void bsg_dyld_cache_lock() { + if (bsg_unfair_lock_supported) { + bsg_unfair_lock(); + } else { + bsg_spin_lock(); + } +} + +void bsg_dyld_cache_unlock() { + if (bsg_unfair_lock_supported) { + bsg_unfair_unlock(); + } else { + bsg_spin_unlock(); + } +} + +BOOL BSGIsUnfairLockSupported(NSProcessInfo *processInfo) { + NSOperatingSystemVersion minSdk = {0,0,0}; +#if TARGET_OS_IOS + minSdk.majorVersion = 10; +#elif TARGET_OS_OSX + minSdk.majorVersion = 10; + minSdk.minorVersion = 12; +#elif TARGET_OS_TV + minSdk.majorVersion = 10; +#elif TARGET_OS_WATCH + minSdk.majorVersion = 3; +#endif + return [processInfo isOperatingSystemAtLeastVersion:minSdk]; +} + +void bsg_check_unfair_lock_support() { + bsg_unfair_lock_supported = BSGIsUnfairLockSupported([NSProcessInfo processInfo]); +} + +// MARK: - Replicate the DYLD API + +uint32_t bsg_dyld_image_count(void) { + return bsg_mach_binary_images.used; +} + +const struct mach_header* bsg_dyld_get_image_header(uint32_t imageIndex) { + if (imageIndex < bsg_mach_binary_images.used) { + return bsg_mach_binary_images.contents[imageIndex].header; + } + return NULL; +} + +intptr_t bsg_dyld_get_image_vmaddr_slide(uint32_t imageIndex) { + if (imageIndex < bsg_mach_binary_images.used) { + return bsg_mach_binary_images.contents[imageIndex].slide; + } + return 0; +} + +const char* bsg_dyld_get_image_name(uint32_t imageIndex) { + if (imageIndex < bsg_mach_binary_images.used) { + return bsg_mach_binary_images.contents[imageIndex].name; + } + return NULL; +} + +BSG_Mach_Binary_Image_Info *bsg_dyld_get_image_info(uint32_t imageIndex) { + if (imageIndex < bsg_mach_binary_images.used) { + return &bsg_mach_binary_images.contents[imageIndex]; + } + return NULL; +} + +/** + * Store a Mach binary image-excapsulating struct in a dynamic array. + * The array doubles on filling-up. Typical sizes is expected to be in < 1000 (i.e. 2-3 doublings, at app start-up) + * This should be called in a threadsafe way; we lock against a simultaneous add and remove. + */ +void bsg_add_mach_binary_image(BSG_Mach_Binary_Image_Info element) { + + bsg_dyld_cache_lock(); + + // Expand array if necessary. We're slightly paranoid here. An OOM is likely to be indicative of bigger problems + // but we should still do *our* best not to crash the app. + if (bsg_mach_binary_images.used == bsg_mach_binary_images.size) { + uint32_t newSize = bsg_mach_binary_images.size *= 2; + uint32_t newAllocationSize = newSize * sizeof(BSG_Mach_Binary_Image_Info); + errno = 0; + BSG_Mach_Binary_Image_Info *newAllocation = (BSG_Mach_Binary_Image_Info *)realloc(bsg_mach_binary_images.contents, newAllocationSize); + + if (newAllocation != NULL && errno != ENOMEM) { + bsg_mach_binary_images.size = newSize; + bsg_mach_binary_images.contents = newAllocation; + } + else { + // Exit early, don't expand the array, don't store the header info and unlock + bsg_dyld_cache_unlock(); + return; + } + } + + // Store the value, increment the number of used elements + bsg_mach_binary_images.contents[bsg_mach_binary_images.used++] = element; + + bsg_dyld_cache_unlock(); +} + +/** + * Binary images can only be loaded at most once. We can use the VMAddress as a key, without needing to compare the + * other fields. Element order is not important; deletion is accomplished by copying the last item into the deleted + * position. + */ +void bsg_remove_mach_binary_image(uint64_t imageVmAddr) { + + bsg_dyld_cache_lock(); + + for (uint32_t i=0; ilast. + if (bsg_mach_binary_images.used >= 2) { + bsg_mach_binary_images.contents[i] = bsg_mach_binary_images.contents[--bsg_mach_binary_images.used]; + } + else { + bsg_mach_binary_images.used = 0; + } + break; // an image can only be loaded singularly; exit loop once found + } + } + + bsg_dyld_cache_unlock(); +} + +/** + * Create an empty array with initial capacity to hold Mach header info. + * + * @param initialSize The initial array capacity + * + * @returns A struct for holding Mach binary image info +*/ +BSG_Mach_Binary_Images *bsg_initialise_mach_binary_headers(uint32_t initialSize) { + bsg_mach_binary_images.contents = (BSG_Mach_Binary_Image_Info *)malloc(initialSize * sizeof(BSG_Mach_Binary_Image_Info)); + bsg_mach_binary_images.used = 0; + bsg_mach_binary_images.size = initialSize; + return &bsg_mach_binary_images; +} + +/** + * Populate a Mach binary image info structure + * + * @param header The Mach binary image header + * + * @param info Encapsulated Binary Image info + * + * @returns a boolean indicating success + */ +bool bsg_populate_mach_image_info(const struct mach_header *header, intptr_t slide, BSG_Mach_Binary_Image_Info *info) { + + // Early exit conditions; this is not a valid/useful binary image + // 1. We can't find a sensible Mach command + uintptr_t cmdPtr = bsg_ksdlfirstCmdAfterHeader(header); + if (cmdPtr == 0) { + return false; + } + + // 2. The image doesn't have a name. Note: running with a debugger attached causes this condition to match. + Dl_info DlInfo = (const Dl_info) { 0 }; + dladdr(header, &DlInfo); + const char *imageName = DlInfo.dli_fname; + if (!imageName) { + return false; + } + + // Look for the TEXT segment to get the image size. + // Also look for a UUID command. + uint64_t imageSize = 0; + uint64_t imageVmAddr = 0; + uint8_t *uuid = NULL; + + for (uint32_t iCmd = 0; iCmd < header->ncmds; iCmd++) { + struct load_command *loadCmd = (struct load_command *)cmdPtr; + switch (loadCmd->cmd) { + case LC_SEGMENT: { + struct segment_command *segCmd = (struct segment_command *)cmdPtr; + if (strcmp(segCmd->segname, SEG_TEXT) == 0) { + imageSize = segCmd->vmsize; + imageVmAddr = segCmd->vmaddr; + } + break; + } + case LC_SEGMENT_64: { + struct segment_command_64 *segCmd = + (struct segment_command_64 *)cmdPtr; + if (strcmp(segCmd->segname, SEG_TEXT) == 0) { + imageSize = segCmd->vmsize; + imageVmAddr = segCmd->vmaddr; + } + break; + } + case LC_UUID: { + struct uuid_command *uuidCmd = (struct uuid_command *)cmdPtr; + uuid = uuidCmd->uuid; + break; + } + } + cmdPtr += loadCmd->cmdsize; + } + + // Save these values + info->header = header; + info->imageSize = imageSize; + info->imageVmAddr = imageVmAddr; + info->uuid = uuid; + info->name = imageName; + info->slide = slide; + + return true; +} + +/** + * A callback invoked when dyld loads binary images. It stores enough relevant info about the + * image to populate a crash report later. + * + * @param header A mach_header structure + * + * @param slide A virtual memory slide amount. The virtual memory slide amount specifies the difference between the + * address at which the image was linked and the address at which the image is loaded. + */ +void bsg_mach_binary_image_added(const struct mach_header *header, intptr_t slide) +{ + BSG_Mach_Binary_Image_Info info = { 0 }; + if (bsg_populate_mach_image_info(header, slide, &info)) { + bsg_add_mach_binary_image(info); + } +} + +/** + * Called when a binary image is unloaded. + */ +void bsg_mach_binary_image_removed(const struct mach_header *header, intptr_t slide) +{ + // Convert header into an info struct + BSG_Mach_Binary_Image_Info info = { 0 }; + if (bsg_populate_mach_image_info(header, slide, &info)) { + bsg_remove_mach_binary_image(info.imageVmAddr); + } +} diff --git a/Tests/KSCrash/KSFileUtils_Tests.m b/Tests/KSCrash/KSFileUtils_Tests.m index 85e2f1d9a..3801deb0c 100755 --- a/Tests/KSCrash/KSFileUtils_Tests.m +++ b/Tests/KSCrash/KSFileUtils_Tests.m @@ -55,169 +55,9 @@ - (void) testWriteBytesToFD XCTAssertTrue(fd >= 0, @""); bool result = bsg_ksfuwriteBytesToFD(fd, [expected cStringUsingEncoding:NSUTF8StringEncoding], stringLength); XCTAssertTrue(result, @""); - bsg_ksfuflushWriteBuffer(fd); NSString* actual = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; XCTAssertNil(error, @""); XCTAssertEqualObjects(actual, expected, @""); } -//- (void) testWriteBytesToFDBig -//{ -// NSError* error = nil; -// NSString* path = [self.tempPath stringByAppendingPathComponent:@"test.txt"]; -// int length = 1000000; -// NSMutableData* expected = [NSMutableData dataWithCapacity:(NSUInteger)length]; -// for(int i = 0; i < length; i++) -// { -// unsigned char byte = (unsigned char)i; -// [expected appendBytes:&byte length:1]; -// } -// -// int fd = open([path UTF8String], O_RDWR | O_CREAT | O_EXCL, 0644); -// XCTAssertTrue(fd >= 0, @""); -// bool result = bsg_ksfuwriteBytesToFD(fd, [expected bytes], length); -// XCTAssertTrue(result, @""); -// NSMutableData* actual = [NSMutableData dataWithContentsOfFile:path options:0 error:&error]; -// XCTAssertNil(error, @""); -// XCTAssertEqualObjects(actual, expected, @""); -//} - -- (void) testReadBytesFromFD -{ - NSError* error = nil; - NSString* path = [self.tempPath stringByAppendingPathComponent:@"test.txt"]; - NSString* expected = @"testing a bunch of stuff.\nOh look, a newline!"; - int stringLength = (int)[expected length]; - [expected writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&error]; - XCTAssertNil(error, @""); - - int fd = open([path UTF8String], O_RDONLY); - XCTAssertTrue(fd >= 0, @""); - NSMutableData* data = [NSMutableData dataWithLength:(NSUInteger)stringLength]; - bool result = bsg_ksfureadBytesFromFD(fd, [data mutableBytes], stringLength); - XCTAssertTrue(result, @""); - NSString* actual = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - XCTAssertNil(error, @""); - XCTAssertEqualObjects(actual, expected, @""); -} - -//- (void) testReadBytesFromFDBig -//{ -// NSError* error = nil; -// NSString* path = [self.tempPath stringByAppendingPathComponent:@"test.txt"]; -// int length = 1000000; -// NSMutableData* expected = [NSMutableData dataWithCapacity:(NSUInteger)length]; -// for(int i = 0; i < length; i++) -// { -// unsigned char byte = (unsigned char)i; -// [expected appendBytes:&byte length:1]; -// } -// [expected writeToFile:path options:0 error:&error]; -// XCTAssertNil(error, @""); -// -// int fd = open([path UTF8String], O_RDONLY); -// XCTAssertTrue(fd >= 0, @""); -// NSMutableData* actual = [NSMutableData dataWithLength:(NSUInteger)length]; -// bool result = bsg_ksfureadBytesFromFD(fd, [actual mutableBytes], length); -// XCTAssertTrue(result, @""); -// XCTAssertEqualObjects(actual, expected, @""); -//} - -- (void) testWriteStringToFD -{ - NSError* error = nil; - NSString* path = [self.tempPath stringByAppendingPathComponent:@"test.txt"]; - NSString* expected = @"testing a bunch of stuff.\nOh look, a newline!"; - - int fd = open([path UTF8String], O_RDWR | O_CREAT | O_EXCL, 0644); - XCTAssertTrue(fd >= 0, @""); - bool result = bsg_ksfuwriteStringToFD(fd, [expected cStringUsingEncoding:NSUTF8StringEncoding]); - XCTAssertTrue(result, @""); - NSString* actual = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; - XCTAssertNil(error, @""); - XCTAssertEqualObjects(actual, expected, @""); -} - -- (void) testWriteFmtToFD -{ - NSError* error = nil; - NSString* path = [self.tempPath stringByAppendingPathComponent:@"test.txt"]; - NSString* expected = @"test test testing 1 2.0 3"; - - int fd = open([path UTF8String], O_RDWR | O_CREAT | O_EXCL, 0644); - XCTAssertTrue(fd >= 0, @""); - bool result = bsg_ksfuwriteFmtToFD(fd, "test test testing %d %.1f %s", 1, 2.0f, "3"); - XCTAssertTrue(result, @""); - NSString* actual = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; - XCTAssertNil(error, @""); - XCTAssertEqualObjects(actual, expected, @""); -} - -- (bool) writeToFD:(int) fd fmt:(char*) fmt, ... -{ - va_list args; - va_start(args, fmt); - bool result = bsg_ksfuwriteFmtArgsToFD(fd, fmt, args); - va_end(args); - return result; -} - -- (void) testWriteFmtArgsToFD -{ - NSError* error = nil; - NSString* path = [self.tempPath stringByAppendingPathComponent:@"test.txt"]; - NSString* expected = @"test test testing 1 2.0 3"; - - int fd = open([path UTF8String], O_RDWR | O_CREAT | O_EXCL, 0644); - XCTAssertTrue(fd >= 0, @""); - bool result = [self writeToFD:fd fmt: "test test testing %d %.1f %s", 1, 2.0f, "3"]; - XCTAssertTrue(result, @""); - NSString* actual = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; - XCTAssertNil(error, @""); - XCTAssertEqualObjects(actual, expected, @""); -} - -- (void) testReadLineFromFD -{ - NSError* error = nil; - NSString* path = [self.tempPath stringByAppendingPathComponent:@"test.txt"]; - NSString* source = @"line 1\nline 2\nline 3"; - NSString* expected1 = @"line 1"; - NSString* expected2 = @"line 2"; - NSString* expected3 = @"line 3"; - [source writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&error]; - XCTAssertNil(error, @""); - - int fd = open([path UTF8String], O_RDONLY); - XCTAssertTrue(fd >= 0, @""); - NSMutableData* data = [NSMutableData dataWithLength:100]; - ssize_t bytesRead; - NSString* actual; - - bytesRead = bsg_ksfureadLineFromFD(fd, [data mutableBytes], 100); - XCTAssertTrue(bytesRead > 0, @""); - actual = [[NSString alloc] initWithBytes:[data bytes] - length:(NSUInteger)bytesRead - encoding:NSUTF8StringEncoding]; - XCTAssertEqualObjects(actual, expected1, @""); - - bytesRead = bsg_ksfureadLineFromFD(fd, [data mutableBytes], 100); - XCTAssertTrue(bytesRead > 0, @""); - actual = [[NSString alloc] initWithBytes:[data bytes] - length:(NSUInteger)bytesRead - encoding:NSUTF8StringEncoding]; - XCTAssertEqualObjects(actual, expected2, @""); - - bytesRead = bsg_ksfureadLineFromFD(fd, [data mutableBytes], 100); - XCTAssertTrue(bytesRead > 0, @""); - actual = [[NSString alloc] initWithBytes:[data bytes] - length:(NSUInteger)bytesRead - encoding:NSUTF8StringEncoding]; - XCTAssertEqualObjects(actual, expected3, @""); - - bytesRead = bsg_ksfureadLineFromFD(fd, [data mutableBytes], 100); - XCTAssertTrue(bytesRead == 0, @""); -} - @end - diff --git a/Tests/KSCrash/KSJSONCodec_Tests.m b/Tests/KSCrash/KSJSONCodec_Tests.m index 340681c60..2f28fd17c 100755 --- a/Tests/KSCrash/KSJSONCodec_Tests.m +++ b/Tests/KSCrash/KSJSONCodec_Tests.m @@ -1140,6 +1140,88 @@ - (void) testSerializeArrayBadCharacter XCTAssertNil(error, @""); } +- (void) testSerializeLongString +{ + NSError* error = (NSError*)self; + // Long string with a leading escaped character to ensure it exceeds the length + // of the buffer in one iteration + id source = @"\"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890"; + NSString* result = toString([BSG_KSJSONCodec encode:source + options:BSG_KSJSONEncodeOptionSorted + error:&error]); + XCTAssertEqualObjects(result, @"\"" + @"\\\"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + @"12345678901234567890123456789012345678901234567890" + "\""); + XCTAssertNil(error, @""); +} + +- (void) testSerializeEscapeLongString +{ + NSError* error = (NSError*)self; + id source = @"\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + @"\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + @"\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + @"\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + @"\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + @"\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + @"\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + @"\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + @"\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + @"\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"; + NSString* result = toString([BSG_KSJSONCodec encode:source + options:BSG_KSJSONEncodeOptionSorted + error:&error]); + XCTAssertEqualObjects(result, @"\"\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001" + @"\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001" + @"\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001" + @"\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001" + @"\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001" + @"\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001" + @"\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001" + @"\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001" + @"\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001" + @"\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\\u0001\""); + XCTAssertNil(error, @""); +} + - (void)testDeserializeArrayInvalidUnicodeSequence { NSError* error = (NSError*)self; diff --git a/Tests/KSCrash/KSMachHeader_Tests.m b/Tests/KSCrash/KSMachHeader_Tests.m new file mode 100644 index 000000000..d4d355332 --- /dev/null +++ b/Tests/KSCrash/KSMachHeader_Tests.m @@ -0,0 +1,173 @@ +// +// KSMachHeader_Tests.m +// Tests +// +// Created by Robin Macharg on 04/05/2020. +// Copyright © 2020 Bugsnag. All rights reserved. +// + +#import +#import "BSG_KSMachHeaders.h" +#import + +// Private methods +void bsg_add_mach_binary_image(BSG_Mach_Binary_Image_Info element); +void bsg_remove_mach_binary_image(uint64_t imageVmAddr); + +const struct mach_header mh = { + .magic = 1, + .cputype = 42, + .cpusubtype = 27, + .filetype = 1, + .ncmds = 1, + .sizeofcmds = 1, + .flags = 1 +}; + +const BSG_Mach_Binary_Image_Info info1 = {.header = &mh, .imageVmAddr = 12345, .imageSize = 6789, .uuid = (uint8_t *)123, .name = "header the first", .slide = 123 }; +const BSG_Mach_Binary_Image_Info info2 = {.header = &mh, .imageVmAddr = 23456, .imageSize = 6789, .uuid = (uint8_t *)123, .name = "header the second", .slide = 1234 }; +const BSG_Mach_Binary_Image_Info info3 = {.header = &mh, .imageVmAddr = 34567, .imageSize = 6789, .uuid = (uint8_t *)123, .name = "header the third", .slide = 12345 }; +const BSG_Mach_Binary_Image_Info info4 = {.header = &mh, .imageVmAddr = 45678, .imageSize = 6789, .uuid = (uint8_t *)123, .name = "header the fourth", .slide = 123456 }; + +@interface KSMachHeader_Tests : XCTestCase +@end + +@implementation KSMachHeader_Tests + +- (void)testDynamicArray { + + BSG_Mach_Binary_Images *images = bsg_initialise_mach_binary_headers(2); + XCTAssertEqual(images->size, 2); + XCTAssertEqual(bsg_dyld_image_count(), 0); + + // Add + bsg_add_mach_binary_image(info1); + XCTAssertEqual(images->size, 2); + XCTAssertEqual(bsg_dyld_image_count(), 1); + + bsg_add_mach_binary_image(info2); + XCTAssertEqual(images->size, 2); + XCTAssertEqual(bsg_dyld_image_count(), 2); + + // Expand - double size + bsg_add_mach_binary_image(info3); + XCTAssertEqual(images->size, 4); + XCTAssertEqual(bsg_dyld_image_count(), 3); + + // Delete - third will be copied + bsg_remove_mach_binary_image(12345); + XCTAssertEqual(images->size, 4); + XCTAssertEqual(bsg_dyld_image_count(), 2); + + XCTAssertEqual(strcmp(bsg_dyld_get_image_name(0), "header the third"), 0); + XCTAssertEqual(strcmp(bsg_dyld_get_image_name(1), "header the second"), 0); + XCTAssertEqual(images->size, 4); + + // Nothing happens + bsg_remove_mach_binary_image(12345); + XCTAssertEqual(images->size, 4); + XCTAssertEqual(bsg_dyld_image_count(), 2); + + bsg_remove_mach_binary_image(23456); + XCTAssertEqual(images->size, 4); + XCTAssertEqual(bsg_dyld_image_count(), 1); + XCTAssertEqual(strcmp(bsg_dyld_get_image_name(0), "header the third"), 0); + + bsg_remove_mach_binary_image(34567); + XCTAssertEqual(images->size, 4); + XCTAssertEqual(bsg_dyld_image_count(), 0); + + bsg_remove_mach_binary_image(34567); + XCTAssertEqual(images->size, 4); + XCTAssertEqual(bsg_dyld_image_count(), 0); + + // Readd + bsg_add_mach_binary_image(info1); + XCTAssertEqual(images->size, 4); + XCTAssertEqual(bsg_dyld_image_count(), 1); +} + +- (void)testRemoveLast1 { + BSG_Mach_Binary_Images *images = bsg_initialise_mach_binary_headers(2); + bsg_add_mach_binary_image(info1); + XCTAssertEqual(images->size, 2); + XCTAssertEqual(bsg_dyld_image_count(), 1); + + bsg_remove_mach_binary_image(12345); + XCTAssertEqual(images->size, 2); + XCTAssertEqual(bsg_dyld_image_count(), 0); +} + +- (void)testRemoveLast2 { + BSG_Mach_Binary_Images *images = bsg_initialise_mach_binary_headers(2); + bsg_add_mach_binary_image(info1); + bsg_add_mach_binary_image(info2); + XCTAssertEqual(images->size, 2); + XCTAssertEqual(bsg_dyld_image_count(), 2); + + bsg_remove_mach_binary_image(23456); + XCTAssertEqual(images->size, 2); + XCTAssertEqual(bsg_dyld_image_count(), 1); + + bsg_remove_mach_binary_image(12345); + XCTAssertEqual(images->size, 2); + XCTAssertEqual(bsg_dyld_image_count(), 0); +} + +- (void)testRemoveLast3 { + BSG_Mach_Binary_Images *images = bsg_initialise_mach_binary_headers(2); + + bsg_add_mach_binary_image(info1); + bsg_add_mach_binary_image(info2); + bsg_add_mach_binary_image(info3); + bsg_add_mach_binary_image(info4); + XCTAssertEqual(images->size, 4); + XCTAssertEqual(bsg_dyld_image_count(), 4); + + bsg_remove_mach_binary_image(45678); + XCTAssertEqual(images->size, 4); + XCTAssertEqual(bsg_dyld_image_count(), 3); + + bsg_remove_mach_binary_image(12345); + XCTAssertEqual(images->size, 4); + XCTAssertEqual(bsg_dyld_image_count(), 2); + + bsg_remove_mach_binary_image(12345); + XCTAssertEqual(images->size, 4); + XCTAssertEqual(bsg_dyld_image_count(), 2); + + bsg_remove_mach_binary_image(34567); + XCTAssertEqual(images->size, 4); + XCTAssertEqual(bsg_dyld_image_count(), 1); +} + +// Test out-of-bounds behaviour of the replicated dyld API +- (void)testBSGDYLDAPI { + BSG_Mach_Binary_Images *images = bsg_initialise_mach_binary_headers(2); + + bsg_add_mach_binary_image(info1); + bsg_add_mach_binary_image(info2); + XCTAssertEqual(images->size, 2); + XCTAssertEqual(bsg_dyld_image_count(), 2); + + XCTAssertEqual(bsg_dyld_get_image_vmaddr_slide(0), 123); + XCTAssertEqual(bsg_dyld_get_image_vmaddr_slide(1), 1234); + XCTAssertEqual(bsg_dyld_get_image_vmaddr_slide(2), 0); + XCTAssertEqual(bsg_dyld_get_image_vmaddr_slide(999), 0); + + XCTAssertEqualObjects([NSString stringWithUTF8String:bsg_dyld_get_image_name(0)], @"header the first"); + XCTAssertEqualObjects([NSString stringWithUTF8String:bsg_dyld_get_image_name(1)], @"header the second"); + XCTAssertTrue(bsg_dyld_get_image_name(2) == NULL); + XCTAssertTrue(bsg_dyld_get_image_name(999) == NULL); + + XCTAssertEqual(bsg_dyld_get_image_header(0)->filetype, 1); + XCTAssertEqual(bsg_dyld_get_image_header(1)->filetype, 1); + XCTAssertTrue(bsg_dyld_get_image_header(2) == NULL); + XCTAssertTrue(bsg_dyld_get_image_header(999) == NULL); + + XCTAssertEqualObjects([NSString stringWithUTF8String:bsg_dyld_get_image_info(0)->name], @"header the first"); + XCTAssertEqualObjects([NSString stringWithUTF8String:bsg_dyld_get_image_info(1)->name], @"header the second"); + XCTAssertTrue(bsg_dyld_get_image_info(999) == NULL); +} + +@end diff --git a/Tests/KSCrash/RFC3339DateTool_Tests.m b/Tests/KSCrash/RFC3339DateTool_Tests.m index bd2b9791a..523283d8a 100755 --- a/Tests/KSCrash/RFC3339DateTool_Tests.m +++ b/Tests/KSCrash/RFC3339DateTool_Tests.m @@ -68,6 +68,25 @@ - (void) testDateFromString XCTAssertEqualObjects(actual, expected, @""); } +- (void) testDateFromStringWithTimezone +{ + NSDate* expected = [self gmtDateWithYear:2000 month:1 day:2 hour:3 minute:4 second:5]; + NSDate* actual = [BSG_RFC3339DateTool dateFromString:@"2000-01-02T03:04:05+0000"]; + + XCTAssertEqualObjects(actual, expected, @""); +} + +- (void) testDateFromStringWithTimezonePlus2 +{ + NSDate* expected = [self gmtDateWithYear:2000 month:1 day:2 hour:1 minute:4 second:5]; + NSDate* actual = [BSG_RFC3339DateTool dateFromString:@"2000-01-02T03:04:05+0200"]; + + XCTAssertEqualObjects(actual, expected, @""); + + // Convert back again to verify overall effect + XCTAssertEqualObjects([BSG_RFC3339DateTool stringFromDate:actual], @"2000-01-02T01:04:05Z"); +} + - (void) testStringFromUnixTimestamp { NSDate* date = [self gmtDateWithYear:2000 month:1 day:2 hour:3 minute:4 second:5]; diff --git a/VERSION b/VERSION index e7acdaa93..4d15632e6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.23.0 +5.23.5 diff --git a/examples/objective-c-ios/Bugsnag Test App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/examples/objective-c-ios/Bugsnag Test App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/examples/objective-c-ios/Bugsnag Test App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/examples/objective-c-ios/Podfile.lock b/examples/objective-c-ios/Podfile.lock deleted file mode 100644 index 0301232af..000000000 --- a/examples/objective-c-ios/Podfile.lock +++ /dev/null @@ -1,16 +0,0 @@ -PODS: - - Bugsnag (5.17.3) - -DEPENDENCIES: - - Bugsnag (from `../..`) - -EXTERNAL SOURCES: - Bugsnag: - :path: "../.." - -SPEC CHECKSUMS: - Bugsnag: 45ee8446ac012adc1fb24224839cd4d941b09448 - -PODFILE CHECKSUM: 4c48f26cc704429f747c4af7a40e026b20fdc83e - -COCOAPODS: 1.5.3 diff --git a/examples/objective-c-osx/Podfile.lock b/examples/objective-c-osx/Podfile.lock deleted file mode 100644 index af86bb73b..000000000 --- a/examples/objective-c-osx/Podfile.lock +++ /dev/null @@ -1,16 +0,0 @@ -PODS: - - Bugsnag (5.17.3) - -DEPENDENCIES: - - Bugsnag (from `../..`) - -EXTERNAL SOURCES: - Bugsnag: - :path: "../.." - -SPEC CHECKSUMS: - Bugsnag: 45ee8446ac012adc1fb24224839cd4d941b09448 - -PODFILE CHECKSUM: df3de31179198c85e1d68a7930eb894bbeb22744 - -COCOAPODS: 1.5.3 diff --git a/examples/objective-c-osx/objective-c-osx.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/examples/objective-c-osx/objective-c-osx.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/examples/objective-c-osx/objective-c-osx.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/examples/swift-ios/Podfile.lock b/examples/swift-ios/Podfile.lock deleted file mode 100644 index fd2c55f9f..000000000 --- a/examples/swift-ios/Podfile.lock +++ /dev/null @@ -1,16 +0,0 @@ -PODS: - - Bugsnag (5.17.3) - -DEPENDENCIES: - - Bugsnag (from `../..`) - -EXTERNAL SOURCES: - Bugsnag: - :path: "../.." - -SPEC CHECKSUMS: - Bugsnag: 45ee8446ac012adc1fb24224839cd4d941b09448 - -PODFILE CHECKSUM: 2107babfbfdb18f0288407b9d9ebd48cbee8661c - -COCOAPODS: 1.5.3 diff --git a/examples/swift-ios/bugsnag-example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/examples/swift-ios/bugsnag-example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/examples/swift-ios/bugsnag-example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/features/fixtures/ios-swift-cocoapods/Podfile.lock b/features/fixtures/ios-swift-cocoapods/Podfile.lock deleted file mode 100644 index 47eac62d1..000000000 --- a/features/fixtures/ios-swift-cocoapods/Podfile.lock +++ /dev/null @@ -1,16 +0,0 @@ -PODS: - - Bugsnag (5.22.1) - -DEPENDENCIES: - - Bugsnag (from `../../..`) - -EXTERNAL SOURCES: - Bugsnag: - :path: "../../.." - -SPEC CHECKSUMS: - Bugsnag: 2f44880d3f61a629adfb846baa86da18e8ab4721 - -PODFILE CHECKSUM: 4d026fb83571f098c9fb4fa71c1564c72c55ab1a - -COCOAPODS: 1.5.3 diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp.xcodeproj/project.pbxproj b/features/fixtures/ios-swift-cocoapods/iOSTestApp.xcodeproj/project.pbxproj index 8444df44d..06cbadbae 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp.xcodeproj/project.pbxproj +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 001E5502243B8FDA0009E31D /* AutoCaptureRunScenario.m in Sources */ = {isa = PBXBuildFile; fileRef = 001E5501243B8FDA0009E31D /* AutoCaptureRunScenario.m */; }; 8A14F0F52282D4AE00337B05 /* ReportBackgroundOOMsEnabledScenario.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A14F0F02282D4AD00337B05 /* ReportBackgroundOOMsEnabledScenario.m */; }; 8A14F0F62282D4AE00337B05 /* ReportOOMsDisabledScenario.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A14F0F22282D4AD00337B05 /* ReportOOMsDisabledScenario.m */; }; 8A14F0F72282D4AE00337B05 /* ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A14F0F32282D4AE00337B05 /* ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.m */; }; @@ -17,6 +18,7 @@ 8A72A0382396574F00328051 /* CustomPluginNotifierDescriptionScenario.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A72A0372396574F00328051 /* CustomPluginNotifierDescriptionScenario.m */; }; 8A840FBA21AF5C450041DBFA /* SwiftAssertion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A840FB921AF5C450041DBFA /* SwiftAssertion.swift */; }; 8A98400320FD11BF0023ECD1 /* AutoSessionCustomVersionScenario.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A98400220FD11BF0023ECD1 /* AutoSessionCustomVersionScenario.m */; }; + 8AA05A2F23BE700C00C7AD00 /* ManyConcurrentNotifyNoBackgroundThreads.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AA05A2E23BE700C00C7AD00 /* ManyConcurrentNotifyNoBackgroundThreads.m */; }; 8AA7C2D72327DD3D002255B2 /* ConfigChangesAfterStartScenarios.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AA7C2D52327DD3D002255B2 /* ConfigChangesAfterStartScenarios.m */; }; 8AB1081923301FE600672818 /* ReleaseStageScenarios.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AB1081823301FE600672818 /* ReleaseStageScenarios.swift */; }; 8AB8866420404DD30003E444 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AB8866320404DD30003E444 /* AppDelegate.swift */; }; @@ -69,6 +71,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 001E5500243B7D290009E31D /* AutoCaptureRunScenario.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AutoCaptureRunScenario.h; sourceTree = ""; }; + 001E5501243B8FDA0009E31D /* AutoCaptureRunScenario.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AutoCaptureRunScenario.m; sourceTree = ""; }; 4994F05E0421A0B037DD2CC5 /* Pods_iOSTestApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iOSTestApp.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8A14F0EF2282D4AD00337B05 /* ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.h; sourceTree = ""; }; 8A14F0F02282D4AD00337B05 /* ReportBackgroundOOMsEnabledScenario.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReportBackgroundOOMsEnabledScenario.m; sourceTree = ""; }; @@ -92,6 +96,8 @@ 8A840FB921AF5C450041DBFA /* SwiftAssertion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftAssertion.swift; sourceTree = ""; }; 8A98400120FD11BF0023ECD1 /* AutoSessionCustomVersionScenario.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AutoSessionCustomVersionScenario.h; sourceTree = ""; }; 8A98400220FD11BF0023ECD1 /* AutoSessionCustomVersionScenario.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AutoSessionCustomVersionScenario.m; sourceTree = ""; }; + 8AA05A2D23BE700C00C7AD00 /* ManyConcurrentNotifyNoBackgroundThreads.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ManyConcurrentNotifyNoBackgroundThreads.h; sourceTree = ""; }; + 8AA05A2E23BE700C00C7AD00 /* ManyConcurrentNotifyNoBackgroundThreads.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ManyConcurrentNotifyNoBackgroundThreads.m; sourceTree = ""; }; 8AA7C2D52327DD3D002255B2 /* ConfigChangesAfterStartScenarios.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConfigChangesAfterStartScenarios.m; sourceTree = ""; }; 8AA7C2D62327DD3D002255B2 /* ConfigChangesAfterStartScenarios.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConfigChangesAfterStartScenarios.h; sourceTree = ""; }; 8AB1081823301FE600672818 /* ReleaseStageScenarios.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReleaseStageScenarios.swift; sourceTree = ""; }; @@ -333,6 +339,10 @@ 8AF8FCAD22BD23BA00A967CA /* HandledInternalNotifyScenario.swift */, 8A72A0362396574F00328051 /* CustomPluginNotifierDescriptionScenario.h */, 8A72A0372396574F00328051 /* CustomPluginNotifierDescriptionScenario.m */, + 8AA05A2D23BE700C00C7AD00 /* ManyConcurrentNotifyNoBackgroundThreads.h */, + 8AA05A2E23BE700C00C7AD00 /* ManyConcurrentNotifyNoBackgroundThreads.m */, + 001E5501243B8FDA0009E31D /* AutoCaptureRunScenario.m */, + 001E5500243B7D290009E31D /* AutoCaptureRunScenario.h */, ); path = scenarios; sourceTree = ""; @@ -456,6 +466,7 @@ F429561C9CFE8750B030F369 /* NSExceptionScenario.swift in Sources */, 8A98400320FD11BF0023ECD1 /* AutoSessionCustomVersionScenario.m in Sources */, F42955E0916B8851F074D9B3 /* UserEmailScenario.swift in Sources */, + 8AA05A2F23BE700C00C7AD00 /* ManyConcurrentNotifyNoBackgroundThreads.m in Sources */, F4295968571A4118D6A4606A /* UserEnabledScenario.swift in Sources */, F4295A036B228AF608641699 /* UserDisabledScenario.swift in Sources */, 8A14F0F62282D4AE00337B05 /* ReportOOMsDisabledScenario.m in Sources */, @@ -482,6 +493,7 @@ 8A22FC66225B598500CA8895 /* OOMScenario.m in Sources */, F42953498545B853CC0B635E /* NullPointerScenario.m in Sources */, 8A840FBA21AF5C450041DBFA /* SwiftAssertion.swift in Sources */, + 001E5502243B8FDA0009E31D /* AutoCaptureRunScenario.m in Sources */, F429538D8941382EC2C857CE /* AsyncSafeThreadScenario.m in Sources */, F42955869D33EE0E510B9651 /* ReadGarbagePointerScenario.m in Sources */, 8AEFC73420F8D1BB00A78779 /* ManualSessionWithUserScenario.m in Sources */, diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/features/fixtures/ios-swift-cocoapods/iOSTestApp.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AbortScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AbortScenario.m index 0a595ae22..046501d36 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AbortScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AbortScenario.m @@ -29,7 +29,7 @@ @implementation AbortScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AccessNonObjectScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AccessNonObjectScenario.m index 5bafeab27..0c23ad4a1 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AccessNonObjectScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AccessNonObjectScenario.m @@ -32,7 +32,7 @@ @implementation AccessNonObjectScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AsyncSafeThreadScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AsyncSafeThreadScenario.m index 84bf94d53..a5e19044a 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AsyncSafeThreadScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AsyncSafeThreadScenario.m @@ -34,7 +34,7 @@ @implementation AsyncSafeThreadScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AutoCaptureRunScenario.h b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AutoCaptureRunScenario.h new file mode 100644 index 000000000..2f7221656 --- /dev/null +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AutoCaptureRunScenario.h @@ -0,0 +1,18 @@ +// +// AutoCaptureRunScenario.h +// iOSTestApp +// +// Created by Robin Macharg on 06/04/2020. +// Copyright © 2020 Bugsnag. All rights reserved. +// + +#ifndef AutoCaptureRunScenario_h +#define AutoCaptureRunScenario_h + +#import "Scenario.h" + +@interface AutoCaptureRunScenario : Scenario + +@end + +#endif /* AutoCaptureRunScenario_h */ diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AutoCaptureRunScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AutoCaptureRunScenario.m new file mode 100644 index 000000000..f7078b9cf --- /dev/null +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AutoCaptureRunScenario.m @@ -0,0 +1,20 @@ +// +// AutoCaptureRunScenario.m +// iOSTestApp +// +// Created by Robin Macharg on 06/04/2020. +// Copyright © 2020 Bugsnag. All rights reserved. +// + +#import "AutoCaptureRunScenario.h" + +@implementation AutoCaptureRunScenario + +- (void)startBugsnag { + self.config.autoTrackSessions = YES; + [super startBugsnag]; +} + +- (void)run {} + +@end diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AutoSessionUnhandledScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AutoSessionUnhandledScenario.m index 6e119eacf..a3431593d 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AutoSessionUnhandledScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/AutoSessionUnhandledScenario.m @@ -12,9 +12,9 @@ @implementation AutoSessionUnhandledScenario - (void)startBugsnag { if ([self.eventMode isEqualToString:@"noevent"]) - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; else - self.config.shouldAutoCaptureSessions = YES; + self.config.autoTrackSessions = YES; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/BuiltinTrapScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/BuiltinTrapScenario.m index ac24057ca..9c0e5fa5c 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/BuiltinTrapScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/BuiltinTrapScenario.m @@ -11,7 +11,7 @@ @implementation BuiltinTrapScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ConfigChangesAfterStartScenarios.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ConfigChangesAfterStartScenarios.m index 995c5c885..e72d7e72d 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ConfigChangesAfterStartScenarios.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ConfigChangesAfterStartScenarios.m @@ -3,7 +3,7 @@ @implementation TurnOnCrashDetectionAfterStartScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; self.config.autoDetectErrors = NO; [super startBugsnag]; } @@ -18,7 +18,7 @@ - (void)run { @implementation TurnOffCrashDetectionAfterStartScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/CustomPluginNotifierDescriptionScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/CustomPluginNotifierDescriptionScenario.m index 6daef25f1..ca5204507 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/CustomPluginNotifierDescriptionScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/CustomPluginNotifierDescriptionScenario.m @@ -35,7 +35,7 @@ @implementation CustomPluginNotifierDescriptionScenario - (void)startBugsnag { [Bugsnag registerPlugin:[DescriptionPlugin new]]; - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/CxxExceptionScenario.mm b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/CxxExceptionScenario.mm index 1dcb77113..bb4cfcea0 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/CxxExceptionScenario.mm +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/CxxExceptionScenario.mm @@ -42,7 +42,7 @@ @implementation CxxExceptionScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/DisabledSessionTrackingScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/DisabledSessionTrackingScenario.m index c902d40f1..b5f01a6b3 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/DisabledSessionTrackingScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/DisabledSessionTrackingScenario.m @@ -9,7 +9,7 @@ @implementation DisabledSessionTrackingScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/HandledErrorOverrideScenario.swift b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/HandledErrorOverrideScenario.swift index 7a48f0ea7..87b681470 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/HandledErrorOverrideScenario.swift +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/HandledErrorOverrideScenario.swift @@ -14,7 +14,7 @@ import Bugsnag class HandledErrorOverrideScenario: Scenario { override func startBugsnag() { - self.config.shouldAutoCaptureSessions = false; + self.config.autoTrackSessions = false; super.startBugsnag() } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/HandledErrorScenario.swift b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/HandledErrorScenario.swift index 067ed9dca..64825b0c3 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/HandledErrorScenario.swift +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/HandledErrorScenario.swift @@ -12,7 +12,7 @@ import Bugsnag class HandledErrorScenario: Scenario { override func startBugsnag() { - self.config.shouldAutoCaptureSessions = false; + self.config.autoTrackSessions = false; super.startBugsnag() } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/HandledExceptionScenario.swift b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/HandledExceptionScenario.swift index 7cab06718..96a541cf9 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/HandledExceptionScenario.swift +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/HandledExceptionScenario.swift @@ -12,7 +12,7 @@ import Bugsnag class HandledExceptionScenario: Scenario { override func startBugsnag() { - self.config.shouldAutoCaptureSessions = false; + self.config.autoTrackSessions = false; super.startBugsnag() } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ManualSessionScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ManualSessionScenario.m index b436b024d..28fe6249e 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ManualSessionScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ManualSessionScenario.m @@ -9,7 +9,7 @@ @implementation ManualSessionScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ManualSessionWithUserScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ManualSessionWithUserScenario.m index 049f48e0e..b5a34b752 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ManualSessionWithUserScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ManualSessionWithUserScenario.m @@ -12,7 +12,7 @@ @implementation ManualSessionWithUserScenario - (void)startBugsnag { [self.config setUser:@"123" withName:@"Joe Bloggs" andEmail:@"joe@example.com"]; - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ManyConcurrentNotifyNoBackgroundThreads.h b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ManyConcurrentNotifyNoBackgroundThreads.h new file mode 100644 index 000000000..b41a0b7c0 --- /dev/null +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ManyConcurrentNotifyNoBackgroundThreads.h @@ -0,0 +1,5 @@ +#import "Scenario.h" + +@interface ManyConcurrentNotifyNoBackgroundThreads : Scenario + +@end diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ManyConcurrentNotifyNoBackgroundThreads.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ManyConcurrentNotifyNoBackgroundThreads.m new file mode 100644 index 000000000..6eefd97ca --- /dev/null +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ManyConcurrentNotifyNoBackgroundThreads.m @@ -0,0 +1,46 @@ +#import "ManyConcurrentNotifyNoBackgroundThreads.h" + +@interface ManyConcurrentNotifyNoBackgroundThreads () +@property (nonatomic) dispatch_queue_t queue1; +@property (nonatomic) dispatch_queue_t queue2; +@end + +@interface BarError : NSError +@end +@implementation BarError +@end + +@implementation ManyConcurrentNotifyNoBackgroundThreads + +- (instancetype)initWithConfig:(BugsnagConfiguration *)config { + if (self = [super initWithConfig:config]) { + _queue1 = dispatch_queue_create("Log Queue 1", DISPATCH_QUEUE_CONCURRENT); + _queue2 = dispatch_queue_create("Log Queue 2", DISPATCH_QUEUE_CONCURRENT); + } + return self; +} + +- (void)run { + for (int i = 0; i < 4; i++) { + NSString *message = [NSString stringWithFormat:@"Err %ld", (long)i]; + [self logError:[BarError errorWithDomain:@"com.example" + code:401 + i + userInfo:@{NSLocalizedDescriptionKey: message}]]; + } +} + +- (void)logError:(NSError *)error { + dispatch_async(self.queue1, ^{ + [Bugsnag notifyError:error]; + }); + dispatch_async(self.queue2, ^{ + [Bugsnag notifyError:error]; + }); +} + +- (void)startBugsnag { + self.config.autoTrackSessions = NO; + [super startBugsnag]; + [Bugsnag setSuspendThreadsForUserReported:NO]; +} +@end diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ManyConcurrentNotifyScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ManyConcurrentNotifyScenario.m index 51bc3e141..9f81876ed 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ManyConcurrentNotifyScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ManyConcurrentNotifyScenario.m @@ -40,7 +40,7 @@ - (void)logError:(NSError *)error { } - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NSExceptionShiftScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NSExceptionShiftScenario.m index 1943127b3..daee2cb88 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NSExceptionShiftScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NSExceptionShiftScenario.m @@ -4,7 +4,7 @@ @implementation NSExceptionShiftScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NewSessionScenario.swift b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NewSessionScenario.swift index 660e7a29d..cae501764 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NewSessionScenario.swift +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NewSessionScenario.swift @@ -11,7 +11,7 @@ import Bugsnag internal class NewSessionScenario: Scenario { override func startBugsnag() { - self.config.shouldAutoCaptureSessions = false; + self.config.autoTrackSessions = false; super.startBugsnag() } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NonExistentMethodScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NonExistentMethodScenario.m index 1af5959c8..1d8d7fa68 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NonExistentMethodScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NonExistentMethodScenario.m @@ -9,7 +9,7 @@ @implementation NonExistentMethodScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NullPointerScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NullPointerScenario.m index 917980cfd..16febf9d8 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NullPointerScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NullPointerScenario.m @@ -31,7 +31,7 @@ @implementation NullPointerScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/OOMScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/OOMScenario.m index 6678272d5..f757f4347 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/OOMScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/OOMScenario.m @@ -5,7 +5,7 @@ @implementation OOMScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; self.config.releaseStage = @"alpha"; [self.config addBeforeSendBlock:^bool(NSDictionary * _Nonnull rawEventData, BugsnagCrashReport * _Nonnull report) { NSMutableDictionary *metadata = [report.metaData mutableCopy]; diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/OOMWillTerminateScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/OOMWillTerminateScenario.m index 13b201217..5360c0301 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/OOMWillTerminateScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/OOMWillTerminateScenario.m @@ -6,7 +6,7 @@ @implementation OOMWillTerminateScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ObjCExceptionScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ObjCExceptionScenario.m index 8cf91258a..7bfdc9cb1 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ObjCExceptionScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ObjCExceptionScenario.m @@ -34,7 +34,7 @@ @implementation ObjCExceptionScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ObjCMsgSendScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ObjCMsgSendScenario.m index 56533bcd4..06860bea8 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ObjCMsgSendScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ObjCMsgSendScenario.m @@ -33,7 +33,7 @@ @implementation ObjCMsgSendScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/OverwriteLinkRegisterScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/OverwriteLinkRegisterScenario.m index 9217379c8..5603b36ba 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/OverwriteLinkRegisterScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/OverwriteLinkRegisterScenario.m @@ -38,7 +38,7 @@ - (NSString *)desc { } - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/PrivilegedInstructionScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/PrivilegedInstructionScenario.m index 7e04d80b2..18399f33c 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/PrivilegedInstructionScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/PrivilegedInstructionScenario.m @@ -32,7 +32,7 @@ @implementation PrivilegedInstructionScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReadGarbagePointerScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReadGarbagePointerScenario.m index 5b9c25f1a..4a7b0a7bc 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReadGarbagePointerScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReadGarbagePointerScenario.m @@ -33,7 +33,7 @@ @implementation ReadGarbagePointerScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReadOnlyPageScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReadOnlyPageScenario.m index e2e102632..d9654d950 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReadOnlyPageScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReadOnlyPageScenario.m @@ -32,7 +32,7 @@ @implementation ReadOnlyPageScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReleaseStageScenarios.swift b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReleaseStageScenarios.swift index 36a729f57..21b34f6ef 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReleaseStageScenarios.swift +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReleaseStageScenarios.swift @@ -5,7 +5,7 @@ class MagicError : NSError {} class NotifyWhenReleaseStageInNotifyReleaseStages : Scenario { override func startBugsnag() { - self.config.shouldAutoCaptureSessions = false; + self.config.autoTrackSessions = false; self.config.releaseStage = "prod" self.config.notifyReleaseStages = ["dev", "prod"] super.startBugsnag() @@ -21,7 +21,7 @@ class NotifyWhenReleaseStageInNotifyReleaseStages : Scenario { class CrashWhenReleaseStageInNotifyReleaseStages : Scenario { override func startBugsnag() { - self.config.shouldAutoCaptureSessions = false; + self.config.autoTrackSessions = false; self.config.releaseStage = "prod" self.config.notifyReleaseStages = ["dev", "prod"] super.startBugsnag() @@ -35,7 +35,7 @@ class CrashWhenReleaseStageInNotifyReleaseStages : Scenario { class CrashWhenReleaseStageInNotifyReleaseStagesChanges : Scenario { override func startBugsnag() { - self.config.shouldAutoCaptureSessions = false; + self.config.autoTrackSessions = false; if (self.eventMode == "noevent") { // The event is evaluated whether to be sent self.config.releaseStage = "test" @@ -55,7 +55,7 @@ class CrashWhenReleaseStageInNotifyReleaseStagesChanges : Scenario { class CrashWhenReleaseStageNotInNotifyReleaseStagesChanges : Scenario { override func startBugsnag() { - self.config.shouldAutoCaptureSessions = false; + self.config.autoTrackSessions = false; if (self.eventMode == "noevent") { // The event is evaluated whether to be sent self.config.releaseStage = "prod" @@ -75,7 +75,7 @@ class CrashWhenReleaseStageNotInNotifyReleaseStagesChanges : Scenario { class NotifyWhenReleaseStageNotInNotifyReleaseStages : Scenario { override func startBugsnag() { - self.config.shouldAutoCaptureSessions = false; + self.config.autoTrackSessions = false; self.config.releaseStage = "dev" self.config.notifyReleaseStages = ["prod"] super.startBugsnag() @@ -91,7 +91,7 @@ class NotifyWhenReleaseStageNotInNotifyReleaseStages : Scenario { class CrashWhenReleaseStageNotInNotifyReleaseStages : Scenario { override func startBugsnag() { - self.config.shouldAutoCaptureSessions = false; + self.config.autoTrackSessions = false; self.config.releaseStage = "dev" self.config.notifyReleaseStages = ["prod"] super.startBugsnag() diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReleasedObjectScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReleasedObjectScenario.m index 0275729de..0f5dc1433 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReleasedObjectScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReleasedObjectScenario.m @@ -36,7 +36,7 @@ - (NSString *)category { return @"Objective-C"; } - (NSString *)title { return @"Message a released object"; } - (NSString *)desc { return @""; } - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportBackgroundOOMsEnabledScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportBackgroundOOMsEnabledScenario.m index ca3540b87..043722c60 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportBackgroundOOMsEnabledScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportBackgroundOOMsEnabledScenario.m @@ -4,7 +4,7 @@ @implementation ReportBackgroundOOMsEnabledScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; self.config.reportBackgroundOOMs = YES; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportDidCrashScenario.swift b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportDidCrashScenario.swift index d9668c8a8..339268687 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportDidCrashScenario.swift +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportDidCrashScenario.swift @@ -5,7 +5,7 @@ import Bugsnag @objc class ReportDidCrashScenario: Scenario { override func startBugsnag() { - self.config.shouldAutoCaptureSessions = false; + self.config.autoTrackSessions = false; super.startBugsnag() } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.m index 3bf864838..d9117d6e8 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledReportBackgroundOOMsEnabledScenario.m @@ -4,7 +4,7 @@ @implementation ReportOOMsDisabledReportBackgroundOOMsEnabledScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; self.config.reportOOMs = NO; self.config.reportBackgroundOOMs = YES; [super startBugsnag]; diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledScenario.m index 11acfa202..47e7a5c52 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ReportOOMsDisabledScenario.m @@ -5,7 +5,7 @@ @implementation ReportOOMsDisabledScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; self.config.reportOOMs = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ResumeSessionOOMScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ResumeSessionOOMScenario.m index 4aa92ad9c..e66aa023d 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ResumeSessionOOMScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ResumeSessionOOMScenario.m @@ -3,7 +3,7 @@ @implementation ResumeSessionOOMScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ResumedSessionScenario.swift b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ResumedSessionScenario.swift index 834fab381..6cf9a89c1 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ResumedSessionScenario.swift +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ResumedSessionScenario.swift @@ -11,7 +11,7 @@ import Bugsnag internal class ResumedSessionScenario: Scenario { override func startBugsnag() { - self.config.shouldAutoCaptureSessions = false; + self.config.autoTrackSessions = false; super.startBugsnag() } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/SessionOOMScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/SessionOOMScenario.m index c03b7f242..f28686e3c 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/SessionOOMScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/SessionOOMScenario.m @@ -4,7 +4,7 @@ @implementation SessionOOMScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StackOverflowScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StackOverflowScenario.m index 66cbc6b92..22942d0ab 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StackOverflowScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StackOverflowScenario.m @@ -33,7 +33,7 @@ @implementation StackOverflowScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StopSessionOOMScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StopSessionOOMScenario.m index cfc4dc1da..a17700541 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StopSessionOOMScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StopSessionOOMScenario.m @@ -3,7 +3,7 @@ @implementation StopSessionOOMScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StoppedSessionScenario.swift b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StoppedSessionScenario.swift index 07a1c9abf..6db3e10c3 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StoppedSessionScenario.swift +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StoppedSessionScenario.swift @@ -11,7 +11,7 @@ import Bugsnag internal class StoppedSessionScenario: Scenario { override func startBugsnag() { - self.config.shouldAutoCaptureSessions = false; + self.config.autoTrackSessions = false; super.startBugsnag() } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/SwiftAssertion.swift b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/SwiftAssertion.swift index c5078aa4a..c6fef0716 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/SwiftAssertion.swift +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/SwiftAssertion.swift @@ -2,7 +2,7 @@ import Foundation class SwiftAssertion: Scenario { override func startBugsnag() { - self.config.shouldAutoCaptureSessions = false; + self.config.autoTrackSessions = false; super.startBugsnag() } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/SwiftCrash.swift b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/SwiftCrash.swift index 04d191836..f1872e202 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/SwiftCrash.swift +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/SwiftCrash.swift @@ -31,7 +31,7 @@ import Foundation */ class SwiftCrash: Scenario { override func startBugsnag() { - self.config.shouldAutoCaptureSessions = false; + self.config.autoTrackSessions = false; super.startBugsnag() } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UndefinedInstructionScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UndefinedInstructionScenario.m index 8734474a6..e5508643f 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UndefinedInstructionScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UndefinedInstructionScenario.m @@ -32,7 +32,7 @@ @implementation UndefinedInstructionScenario - (void)startBugsnag { - self.config.shouldAutoCaptureSessions = NO; + self.config.autoTrackSessions = NO; [super startBugsnag]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UserDisabledScenario.swift b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UserDisabledScenario.swift index eafadf954..b96a6a9e2 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UserDisabledScenario.swift +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UserDisabledScenario.swift @@ -11,7 +11,7 @@ import Bugsnag */ internal class UserDisabledScenario: Scenario { override func startBugsnag() { - self.config.shouldAutoCaptureSessions = false; + self.config.autoTrackSessions = false; super.startBugsnag() } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UserEmailScenario.swift b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UserEmailScenario.swift index 303ef7dbe..ed0584eea 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UserEmailScenario.swift +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UserEmailScenario.swift @@ -11,7 +11,7 @@ import Bugsnag */ internal class UserEmailScenario: Scenario { override func startBugsnag() { - self.config.shouldAutoCaptureSessions = false; + self.config.autoTrackSessions = false; super.startBugsnag() } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UserEnabledScenario.swift b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UserEnabledScenario.swift index 70ce67cd6..41537058d 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UserEnabledScenario.swift +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UserEnabledScenario.swift @@ -12,7 +12,7 @@ import Bugsnag internal class UserEnabledScenario: Scenario { override func startBugsnag() { - self.config.shouldAutoCaptureSessions = false; + self.config.autoTrackSessions = false; super.startBugsnag() } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UserIdScenario.swift b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UserIdScenario.swift index e350889e0..a213f5250 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UserIdScenario.swift +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/UserIdScenario.swift @@ -12,7 +12,7 @@ import Bugsnag internal class UserIdScenario: Scenario { override func startBugsnag() { - self.config.shouldAutoCaptureSessions = false; + self.config.autoTrackSessions = false; super.startBugsnag() } diff --git a/features/handled_errors.feature b/features/handled_errors.feature index 37bea9e73..c7c2c51b4 100644 --- a/features/handled_errors.feature +++ b/features/handled_errors.feature @@ -67,3 +67,17 @@ Scenario: Reporting handled errors concurrently | FooError | Err 1 | | FooError | Err 2 | | FooError | Err 3 | + +Scenario: Reporting handled errors concurrently in an environment without background thread reporting + When I run "ManyConcurrentNotifyNoBackgroundThreads" + And I wait for a request + Then the request is valid for the error reporting API + And the "Bugsnag-API-Key" header equals "a35a2a72bd230ac0aa0f52715bbdc6aa" + And the payload field "notifier.name" equals "iOS Bugsnag Notifier" + And the payload field "events" is an array with 8 elements + And each event in the payload matches one of: + | exceptions.0.errorClass | exceptions.0.message | + | BarError | Err 0 | + | BarError | Err 1 | + | BarError | Err 2 | + | BarError | Err 3 | diff --git a/features/scripts/foreground_ios_app.sh b/features/scripts/foreground_ios_app.sh new file mode 100755 index 000000000..5f59136e8 --- /dev/null +++ b/features/scripts/foreground_ios_app.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +# Bring a previously running app to the foreground + +xcrun simctl launch "$iOS_Simulator" com.bugsnag.iOSTestApp \ + "EVENT_TYPE=AutoCaptureRunScenario" \ + "BUGSNAG_API_KEY=$BUGSNAG_API_KEY" \ + "MOCK_API_PATH=http://localhost:$MOCK_API_PORT" diff --git a/features/session_tracking.feature b/features/session_tracking.feature index decc520b0..4c1678753 100644 --- a/features/session_tracking.feature +++ b/features/session_tracking.feature @@ -146,3 +146,20 @@ Scenario: Encountering handled and unhandled events during a session And the payload field "events.2.session.id" of request 2 equals the payload field "sessions.0.id" of request 0 And the payload field "events.0.session.id" of request 2 does not equal the payload field "sessions.1.id" of request 0 +Scenario: Backgrounding an app for more than a minute causes a new session to start on re-foregrounding it + Given I set environment variable "BUGSNAG_API_KEY" to "a35a2a72bd230ac0aa0f52715bbdc6aa" + When I run "AutoCaptureRunScenario" + And I wait for 1 request + Then request 0 is valid for the session tracking API + And the payload field "sessions" is an array with 1 element for request 0 + + Then I put the app in the background + And I wait for 70 seconds + + Then I bring the app to the foreground + # cummulative + And I wait for 2 requests + Then request 1 is valid for the session tracking API + And the payload field "sessions" is an array with 1 element for request 1 + And the payload field "sessions.0.id" of request 0 does not equal the payload field "sessions.0.id" of request 1 + \ No newline at end of file diff --git a/features/steps/ios_steps.rb b/features/steps/ios_steps.rb index 237eb564d..ca69c3541 100644 --- a/features/steps/ios_steps.rb +++ b/features/steps/ios_steps.rb @@ -51,6 +51,12 @@ } end +When("I bring the app to the foreground") do + steps %Q{ + When I run the script "features/scripts/foreground_ios_app.sh" synchronously + } +end + Then("each event in the payload for request {int} matches one of:") do |request_index, table| # Checks string equality of event fields against values events = read_key_path(find_request(request_index)[:body], "events") diff --git a/iOS/Bugsnag.xcodeproj/project.pbxproj b/iOS/Bugsnag.xcodeproj/project.pbxproj index 014d1dcb6..01ce07797 100644 --- a/iOS/Bugsnag.xcodeproj/project.pbxproj +++ b/iOS/Bugsnag.xcodeproj/project.pbxproj @@ -7,6 +7,11 @@ objects = { /* Begin PBXBuildFile section */ + 0003F3C52461B29A00AE0C93 /* BSG_KSMachHeaders.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0071CB4D2460216200F562B1 /* BSG_KSMachHeaders.h */; }; + 0071CB4B2460213200F562B1 /* BSG_KSMachHeaders.m in Sources */ = {isa = PBXBuildFile; fileRef = 0071CB4A2460213200F562B1 /* BSG_KSMachHeaders.m */; }; + 0071CB4C2460213200F562B1 /* BSG_KSMachHeaders.m in Sources */ = {isa = PBXBuildFile; fileRef = 0071CB4A2460213200F562B1 /* BSG_KSMachHeaders.m */; }; + 0071CB4F246025AF00F562B1 /* KSMachHeader_Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0071CB4E246025AF00F562B1 /* KSMachHeader_Tests.m */; }; + 0071CB502460705D00F562B1 /* BSG_KSMachHeaders.h in Headers */ = {isa = PBXBuildFile; fileRef = 0071CB4D2460216200F562B1 /* BSG_KSMachHeaders.h */; }; 4B47970A22A9AE1F00FF9C2E /* BugsnagCrashReportFromKSCrashReportTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B47970922A9AE1F00FF9C2E /* BugsnagCrashReportFromKSCrashReportTest.m */; }; 4B775FCF22CBDEB4004839C5 /* BugsnagCollectionsBSGDictInsertIfNotNilTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B775FCE22CBDEB4004839C5 /* BugsnagCollectionsBSGDictInsertIfNotNilTest.m */; }; 4BE6C42622CAD61A0056305D /* BugsnagCollectionsBSGDictMergeTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BE6C42522CAD61A0056305D /* BugsnagCollectionsBSGDictMergeTest.m */; }; @@ -44,6 +49,8 @@ 8A70D9CD2253C484006B696F /* BSGOutOfMemoryWatchdogTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A70D9CC2253C484006B696F /* BSGOutOfMemoryWatchdogTests.m */; }; 8A72A0392396590300328051 /* BugsnagPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A72A0352396535000328051 /* BugsnagPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8AF1748E23070F0300902CC2 /* BSG_KSCrashIdentifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A530CBF22FDC3AE00F0C108 /* BSG_KSCrashIdentifier.m */; }; + E694862724CB1C7F002077D1 /* BSG_RFC3339DateTool.h in Headers */ = {isa = PBXBuildFile; fileRef = E694862524CB1C7F002077D1 /* BSG_RFC3339DateTool.h */; }; + E694862824CB1C7F002077D1 /* BSG_RFC3339DateTool.m in Sources */ = {isa = PBXBuildFile; fileRef = E694862624CB1C7F002077D1 /* BSG_RFC3339DateTool.m */; }; E70E52152216E41C00A590AB /* BugsnagSessionTrackerStopTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E70E52142216E41C00A590AB /* BugsnagSessionTrackerStopTest.m */; }; E70EE0781FD7039E00FA745C /* RFC3339DateTool_Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = E70EE0771FD7039D00FA745C /* RFC3339DateTool_Tests.m */; }; E70EE07E1FD703D600FA745C /* NSError+SimpleConstructor_Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = E70EE07A1FD703D500FA745C /* NSError+SimpleConstructor_Tests.m */; }; @@ -124,8 +131,6 @@ E7107C7B1F4C97F100BB3F98 /* BSG_KSSysCtl.h in Headers */ = {isa = PBXBuildFile; fileRef = E7107C0F1F4C97F100BB3F98 /* BSG_KSSysCtl.h */; }; E7107C801F4C97F100BB3F98 /* NSError+BSG_SimpleConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = E7107C141F4C97F100BB3F98 /* NSError+BSG_SimpleConstructor.h */; }; E7107C811F4C97F100BB3F98 /* NSError+BSG_SimpleConstructor.m in Sources */ = {isa = PBXBuildFile; fileRef = E7107C151F4C97F100BB3F98 /* NSError+BSG_SimpleConstructor.m */; }; - E7107C841F4C97F100BB3F98 /* BSG_RFC3339DateTool.h in Headers */ = {isa = PBXBuildFile; fileRef = E7107C181F4C97F100BB3F98 /* BSG_RFC3339DateTool.h */; }; - E7107C851F4C97F100BB3F98 /* BSG_RFC3339DateTool.m in Sources */ = {isa = PBXBuildFile; fileRef = E7107C191F4C97F100BB3F98 /* BSG_RFC3339DateTool.m */; }; E7107C861F4C97F100BB3F98 /* BSG_KSCrashReportFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = E7107C1C1F4C97F100BB3F98 /* BSG_KSCrashReportFilter.h */; }; E7107C871F4C97F100BB3F98 /* BSG_KSCrashReportFilterCompletion.h in Headers */ = {isa = PBXBuildFile; fileRef = E7107C1D1F4C97F100BB3F98 /* BSG_KSCrashReportFilterCompletion.h */; }; E71FF7591FD55CE50099C9DD /* BugsnagApiClient.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = F42950F4A741305B77E95389 /* BugsnagApiClient.h */; }; @@ -164,7 +169,6 @@ E7397E1E1F83BC2A0034242A /* BSG_KSJSONCodecObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = E7107BFA1F4C97F100BB3F98 /* BSG_KSJSONCodecObjC.m */; }; E7397E1F1F83BC2A0034242A /* BSG_KSLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = E7107BFC1F4C97F100BB3F98 /* BSG_KSLogger.m */; }; E7397E221F83BC2A0034242A /* NSError+BSG_SimpleConstructor.m in Sources */ = {isa = PBXBuildFile; fileRef = E7107C151F4C97F100BB3F98 /* NSError+BSG_SimpleConstructor.m */; }; - E7397E231F83BC2A0034242A /* BSG_RFC3339DateTool.m in Sources */ = {isa = PBXBuildFile; fileRef = E7107C191F4C97F100BB3F98 /* BSG_RFC3339DateTool.m */; }; E7397E241F83BC2A0034242A /* BugsnagCrashSentry.m in Sources */ = {isa = PBXBuildFile; fileRef = E72962D11F4BBA8A00CEA15D /* BugsnagCrashSentry.m */; }; E7397E251F83BC2A0034242A /* BugsnagErrorReportApiClient.m in Sources */ = {isa = PBXBuildFile; fileRef = E72962D31F4BBA8B00CEA15D /* BugsnagErrorReportApiClient.m */; }; E7397E271F83BC2A0034242A /* BSGConnectivity.m in Sources */ = {isa = PBXBuildFile; fileRef = E72352B51F55718E00436528 /* BSGConnectivity.m */; }; @@ -239,7 +243,6 @@ E7397ED81F83CFC20034242A /* BSG_KSString.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = E7107C0D1F4C97F100BB3F98 /* BSG_KSString.h */; }; E7397ED91F83CFC20034242A /* BSG_KSSysCtl.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = E7107C0F1F4C97F100BB3F98 /* BSG_KSSysCtl.h */; }; E7397EDC1F83CFC20034242A /* NSError+BSG_SimpleConstructor.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = E7107C141F4C97F100BB3F98 /* NSError+BSG_SimpleConstructor.h */; }; - E7397EDD1F83CFC20034242A /* BSG_RFC3339DateTool.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = E7107C181F4C97F100BB3F98 /* BSG_RFC3339DateTool.h */; }; E7397EDE1F83CFC20034242A /* BSG_KSCrashReportFilter.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = E7107C1C1F4C97F100BB3F98 /* BSG_KSCrashReportFilter.h */; }; E7397EDF1F83CFC20034242A /* BSG_KSCrashReportFilterCompletion.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = E7107C1D1F4C97F100BB3F98 /* BSG_KSCrashReportFilterCompletion.h */; }; E7397EE01F83CFC20034242A /* BugsnagCrashSentry.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = E72962D01F4BBA8A00CEA15D /* BugsnagCrashSentry.h */; }; @@ -323,6 +326,7 @@ dstPath = "include/${PRODUCT_NAME}"; dstSubfolderSpec = 16; files = ( + 0003F3C52461B29A00AE0C93 /* BSG_KSMachHeaders.h in CopyFiles */, 8A3C590923965D9400B344AA /* BugsnagPlugin.h in CopyFiles */, E79148251FD828E6003EFEBF /* BugsnagKeys.h in CopyFiles */, E79148261FD828E6003EFEBF /* BugsnagSessionTracker.h in CopyFiles */, @@ -374,7 +378,6 @@ E7397ED81F83CFC20034242A /* BSG_KSString.h in CopyFiles */, E7397ED91F83CFC20034242A /* BSG_KSSysCtl.h in CopyFiles */, E7397EDC1F83CFC20034242A /* NSError+BSG_SimpleConstructor.h in CopyFiles */, - E7397EDD1F83CFC20034242A /* BSG_RFC3339DateTool.h in CopyFiles */, E7397EDE1F83CFC20034242A /* BSG_KSCrashReportFilter.h in CopyFiles */, E7397EDF1F83CFC20034242A /* BSG_KSCrashReportFilterCompletion.h in CopyFiles */, E7397EE01F83CFC20034242A /* BugsnagCrashSentry.h in CopyFiles */, @@ -397,6 +400,9 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0071CB4A2460213200F562B1 /* BSG_KSMachHeaders.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BSG_KSMachHeaders.m; sourceTree = ""; }; + 0071CB4D2460216200F562B1 /* BSG_KSMachHeaders.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BSG_KSMachHeaders.h; sourceTree = ""; }; + 0071CB4E246025AF00F562B1 /* KSMachHeader_Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KSMachHeader_Tests.m; sourceTree = ""; }; 4B3B193422CA7B0900475354 /* BugsnagCollectionsBSGDictSetSafeObjectTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = BugsnagCollectionsBSGDictSetSafeObjectTest.m; path = ../../Tests/BugsnagCollectionsBSGDictSetSafeObjectTest.m; sourceTree = ""; }; 4B47970922A9AE1F00FF9C2E /* BugsnagCrashReportFromKSCrashReportTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BugsnagCrashReportFromKSCrashReportTest.m; sourceTree = ""; }; 4B775FCE22CBDEB4004839C5 /* BugsnagCollectionsBSGDictInsertIfNotNilTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = BugsnagCollectionsBSGDictInsertIfNotNilTest.m; path = ../../Tests/BugsnagCollectionsBSGDictInsertIfNotNilTest.m; sourceTree = ""; }; @@ -443,6 +449,8 @@ 8A70D9CC2253C484006B696F /* BSGOutOfMemoryWatchdogTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BSGOutOfMemoryWatchdogTests.m; sourceTree = ""; }; 8A72A0352396535000328051 /* BugsnagPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BugsnagPlugin.h; path = ../Source/BugsnagPlugin.h; sourceTree = ""; }; 8AF2894923339CCA00E8EB27 /* Config.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Config.xcconfig; path = ../Configurations/Config.xcconfig; sourceTree = ""; }; + E694862524CB1C7F002077D1 /* BSG_RFC3339DateTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSG_RFC3339DateTool.h; path = ../Source/BSG_RFC3339DateTool.h; sourceTree = ""; }; + E694862624CB1C7F002077D1 /* BSG_RFC3339DateTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BSG_RFC3339DateTool.m; path = ../Source/BSG_RFC3339DateTool.m; sourceTree = ""; }; E70E52142216E41C00A590AB /* BugsnagSessionTrackerStopTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = BugsnagSessionTrackerStopTest.m; path = ../../Tests/BugsnagSessionTrackerStopTest.m; sourceTree = ""; }; E70EE0771FD7039D00FA745C /* RFC3339DateTool_Tests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RFC3339DateTool_Tests.m; path = ../Tests/KSCrash/RFC3339DateTool_Tests.m; sourceTree = SOURCE_ROOT; }; E70EE07A1FD703D500FA745C /* NSError+SimpleConstructor_Tests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSError+SimpleConstructor_Tests.m"; path = "../Tests/KSCrash/NSError+SimpleConstructor_Tests.m"; sourceTree = SOURCE_ROOT; }; @@ -526,8 +534,6 @@ E7107C0F1F4C97F100BB3F98 /* BSG_KSSysCtl.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; name = BSG_KSSysCtl.h; path = ../Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSSysCtl.h; sourceTree = SOURCE_ROOT; }; E7107C141F4C97F100BB3F98 /* NSError+BSG_SimpleConstructor.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; name = "NSError+BSG_SimpleConstructor.h"; path = "../Source/KSCrash/Source/KSCrash/Recording/Tools/NSError+BSG_SimpleConstructor.h"; sourceTree = SOURCE_ROOT; }; E7107C151F4C97F100BB3F98 /* NSError+BSG_SimpleConstructor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSError+BSG_SimpleConstructor.m"; path = "../Source/KSCrash/Source/KSCrash/Recording/Tools/NSError+BSG_SimpleConstructor.m"; sourceTree = SOURCE_ROOT; }; - E7107C181F4C97F100BB3F98 /* BSG_RFC3339DateTool.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; name = BSG_RFC3339DateTool.h; path = ../Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_RFC3339DateTool.h; sourceTree = SOURCE_ROOT; }; - E7107C191F4C97F100BB3F98 /* BSG_RFC3339DateTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BSG_RFC3339DateTool.m; path = ../Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_RFC3339DateTool.m; sourceTree = SOURCE_ROOT; }; E7107C1C1F4C97F100BB3F98 /* BSG_KSCrashReportFilter.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; name = BSG_KSCrashReportFilter.h; path = ../Source/KSCrash/Source/KSCrash/Reporting/Filters/BSG_KSCrashReportFilter.h; sourceTree = SOURCE_ROOT; }; E7107C1D1F4C97F100BB3F98 /* BSG_KSCrashReportFilterCompletion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSG_KSCrashReportFilterCompletion.h; path = ../Source/KSCrash/Source/KSCrash/Reporting/Filters/BSG_KSCrashReportFilterCompletion.h; sourceTree = SOURCE_ROOT; }; E72352B41F55718E00436528 /* BSGConnectivity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSGConnectivity.h; path = ../Source/BSGConnectivity.h; sourceTree = SOURCE_ROOT; }; @@ -643,6 +649,8 @@ 8A2C8F1A1C6BBD2300846019 /* Bugsnag */ = { isa = PBXGroup; children = ( + E694862524CB1C7F002077D1 /* BSG_RFC3339DateTool.h */, + E694862624CB1C7F002077D1 /* BSG_RFC3339DateTool.m */, E7107BD31F4C97F100BB3F98 /* BSG_KSCrashReportWriter.h */, E72352B41F55718E00436528 /* BSGConnectivity.h */, E72352B51F55718E00436528 /* BSGConnectivity.m */, @@ -771,6 +779,7 @@ E7B970321FD7031500590C27 /* XCTestCase+KSCrash.h */, E7B970331FD7031500590C27 /* XCTestCase+KSCrash.m */, E7B970301FD702DA00590C27 /* KSLogger_Tests.m */, + 0071CB4E246025AF00F562B1 /* KSMachHeader_Tests.m */, ); name = KSCrash; path = ../../Tests/KSCrash; @@ -883,6 +892,8 @@ E7107C011F4C97F100BB3F98 /* BSG_KSMach_x86_32.c */, E7107C021F4C97F100BB3F98 /* BSG_KSMach_x86_64.c */, E7107C031F4C97F100BB3F98 /* BSG_KSMachApple.h */, + 0071CB4A2460213200F562B1 /* BSG_KSMachHeaders.m */, + 0071CB4D2460216200F562B1 /* BSG_KSMachHeaders.h */, E7107C041F4C97F100BB3F98 /* BSG_KSObjC.c */, E7107C051F4C97F100BB3F98 /* BSG_KSObjC.h */, E7107C061F4C97F100BB3F98 /* BSG_KSObjCApple.h */, @@ -895,8 +906,6 @@ E7107C0F1F4C97F100BB3F98 /* BSG_KSSysCtl.h */, E7107C141F4C97F100BB3F98 /* NSError+BSG_SimpleConstructor.h */, E7107C151F4C97F100BB3F98 /* NSError+BSG_SimpleConstructor.m */, - E7107C181F4C97F100BB3F98 /* BSG_RFC3339DateTool.h */, - E7107C191F4C97F100BB3F98 /* BSG_RFC3339DateTool.m */, ); path = Tools; sourceTree = ""; @@ -965,6 +974,7 @@ E7107C451F4C97F100BB3F98 /* BSG_KSCrashType.h in Headers */, E7107C431F4C97F100BB3F98 /* BSG_KSCrashState.h in Headers */, E7107C471F4C97F100BB3F98 /* BSG_KSSystemInfo.h in Headers */, + 0071CB502460705D00F562B1 /* BSG_KSMachHeaders.h in Headers */, E72962D61F4BBA8B00CEA15D /* BugsnagCrashSentry.h in Headers */, E7107C3C1F4C97F100BB3F98 /* BSG_KSCrashReport.h in Headers */, 8A381D4B1EAA49A700AF8429 /* BugsnagLogger.h in Headers */, @@ -986,11 +996,11 @@ E7107C351F4C97F100BB3F98 /* BSG_KSCrashAdvanced.h in Headers */, E7107C711F4C97F100BB3F98 /* BSG_KSObjC.h in Headers */, E7107C3D1F4C97F100BB3F98 /* BSG_KSCrashReportFields.h in Headers */, - E7107C841F4C97F100BB3F98 /* BSG_RFC3339DateTool.h in Headers */, E7DC009B1FC5C4F6004AB8DF /* BugsnagCollections.h in Headers */, 8A2C8F5F1C6BBE3C00846019 /* BugsnagSink.h in Headers */, E794E8031F9F743D00A67EE7 /* BugsnagKeys.h in Headers */, E72352B61F55718E00436528 /* BSGConnectivity.h in Headers */, + E694862724CB1C7F002077D1 /* BSG_RFC3339DateTool.h in Headers */, F4295932E7EC58D1CB806EC9 /* BugsnagFileStore.h in Headers */, F4295C14DCDDF541188CDE66 /* BugsnagSessionFileStore.h in Headers */, F429561943952286B690CFB1 /* BugsnagSessionTrackingApiClient.h in Headers */, @@ -1128,6 +1138,7 @@ files = ( E7107C781F4C97F100BB3F98 /* BSG_KSString.c in Sources */, E7107C7A1F4C97F100BB3F98 /* BSG_KSSysCtl.c in Sources */, + E694862824CB1C7F002077D1 /* BSG_RFC3339DateTool.m in Sources */, 8A2C8F561C6BBE3C00846019 /* BugsnagConfiguration.m in Sources */, 8A627CD21EC2A62900F7C04E /* BSGSerialization.m in Sources */, E72BF7761FC867E4004BE82F /* BugsnagSessionTracker.m in Sources */, @@ -1170,13 +1181,13 @@ E72BF7801FC86A7A004BE82F /* BugsnagUser.m in Sources */, 8A2C8F541C6BBE3C00846019 /* BugsnagCollections.m in Sources */, E7107C501F4C97F100BB3F98 /* BSG_KSCrashSentry_MachException.c in Sources */, + 0071CB4B2460213200F562B1 /* BSG_KSMachHeaders.m in Sources */, E7107C5F1F4C97F100BB3F98 /* BSG_KSDynamicLinker.c in Sources */, E737DEA31F73AD7400BC7C80 /* BugsnagHandledState.m in Sources */, E72962D71F4BBA8B00CEA15D /* BugsnagCrashSentry.m in Sources */, 8A2C8F581C6BBE3C00846019 /* BugsnagCrashReport.m in Sources */, E7107C341F4C97F100BB3F98 /* BSG_KSCrash.m in Sources */, E7107C571F4C97F100BB3F98 /* BSG_KSCrashSentry_User.c in Sources */, - E7107C851F4C97F100BB3F98 /* BSG_RFC3339DateTool.m in Sources */, F42953297D561ACAB878DEB8 /* BugsnagFileStore.m in Sources */, F4295B2AC95281CBA3A42DCA /* BugsnagSessionFileStore.m in Sources */, F4295C52A30DC98515F2FF02 /* BugsnagSessionTrackingApiClient.m in Sources */, @@ -1218,6 +1229,7 @@ E784D25A1FD70C25004B01E1 /* KSJSONCodec_Tests.m in Sources */, E70EE0881FD7047800FA745C /* KSSystemInfo_Tests.m in Sources */, 4BE6C42622CAD61A0056305D /* BugsnagCollectionsBSGDictMergeTest.m in Sources */, + 0071CB4F246025AF00F562B1 /* KSMachHeader_Tests.m in Sources */, E70EE0871FD7047800FA745C /* KSSysCtl_Tests.m in Sources */, E78C1EF31FCC615400B976D3 /* BugsnagSessionTrackingPayloadTest.m in Sources */, E78C1EF11FCC2F1700B976D3 /* BugsnagSessionTrackerTest.m in Sources */, @@ -1269,7 +1281,6 @@ E7397E1F1F83BC2A0034242A /* BSG_KSLogger.m in Sources */, E7397E221F83BC2A0034242A /* NSError+BSG_SimpleConstructor.m in Sources */, E7EB06761FCDAF2000C076A6 /* BugsnagKSCrashSysInfoParser.m in Sources */, - E7397E231F83BC2A0034242A /* BSG_RFC3339DateTool.m in Sources */, E7397E241F83BC2A0034242A /* BugsnagCrashSentry.m in Sources */, E7397E251F83BC2A0034242A /* BugsnagErrorReportApiClient.m in Sources */, E7397E271F83BC2A0034242A /* BSGConnectivity.m in Sources */, @@ -1277,6 +1288,7 @@ E72BF7811FC86A7A004BE82F /* BugsnagUser.m in Sources */, E7397E291F83BC2A0034242A /* Bugsnag.m in Sources */, E7397E2A1F83BC2A0034242A /* BugsnagBreadcrumb.m in Sources */, + 0071CB4C2460213200F562B1 /* BSG_KSMachHeaders.m in Sources */, E7397E2B1F83BC2A0034242A /* BugsnagCollections.m in Sources */, E7397E2C1F83BC2A0034242A /* BugsnagConfiguration.m in Sources */, E7397E2D1F83BC2A0034242A /* BugsnagCrashReport.m in Sources */, diff --git a/iOS/Bugsnag.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/iOS/Bugsnag.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/iOS/Bugsnag.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/iOS/BugsnagTests/BSGOutOfMemoryWatchdogTests.m b/iOS/BugsnagTests/BSGOutOfMemoryWatchdogTests.m index 7f4784bea..4136f493f 100644 --- a/iOS/BugsnagTests/BSGOutOfMemoryWatchdogTests.m +++ b/iOS/BugsnagTests/BSGOutOfMemoryWatchdogTests.m @@ -1,19 +1,73 @@ - +#import #import "BSGOutOfMemoryWatchdog.h" #import "BSG_KSSystemInfo.h" #import "BugsnagConfiguration.h" -#import +#import "Bugsnag.h" +#import "BugsnagNotifier.h" -@interface BSGOutOfMemoryWatchdogTests : XCTestCase +// Expose private identifiers for testing + +@interface Bugsnag (Testing) ++ (BugsnagNotifier *)notifier; +@end + +@interface BugsnagNotifier (Testing) +@property (nonatomic, strong) BSGOutOfMemoryWatchdog *oomWatchdog; +@end +@interface BSGOutOfMemoryWatchdog (Testing) +- (NSMutableDictionary *)generateCacheInfoWithConfig:(BugsnagConfiguration *)config; +@property(nonatomic, strong, readwrite) NSMutableDictionary *cachedFileInfo; +@end + +@interface BSGOutOfMemoryWatchdogTests : XCTestCase @end @implementation BSGOutOfMemoryWatchdogTests +- (void)setUp { + [super setUp]; + BugsnagConfiguration *config = [BugsnagConfiguration new]; + config.autoDetectErrors = NO; + config.apiKey = @"apiKeyHere"; + config.codeBundleId = @"codeBundleIdHere"; + config.releaseStage = @"MagicalTestingTime"; + + [Bugsnag startBugsnagWithConfiguration:config]; +} + - (void)testNilPathDoesNotCreateWatchdog { XCTAssertNil([[BSGOutOfMemoryWatchdog alloc] init]); XCTAssertNil([[BSGOutOfMemoryWatchdog alloc] initWithSentinelPath:nil configuration:nil]); } +/** + * Test that the generated OOM report values exist and are correct (where that can be tested) + */ +- (void)testOOMFieldsSetCorrectly { + NSMutableDictionary *cachedFileInfo = [[[Bugsnag notifier] oomWatchdog] cachedFileInfo]; + XCTAssertNotNil([cachedFileInfo objectForKey:@"app"]); + XCTAssertNotNil([cachedFileInfo objectForKey:@"device"]); + + NSMutableDictionary *app = [cachedFileInfo objectForKey:@"app"]; + XCTAssertNotNil([app objectForKey:@"bundleVersion"]); + XCTAssertNotNil([app objectForKey:@"id"]); + XCTAssertNotNil([app objectForKey:@"inForeground"]); + XCTAssertNotNil([app objectForKey:@"version"]); + XCTAssertNotNil([app objectForKey:@"name"]); + XCTAssertEqual([app valueForKey:@"codeBundleId"], @"codeBundleIdHere"); + XCTAssertEqual([app valueForKey:@"releaseStage"], @"MagicalTestingTime"); + + NSMutableDictionary *device = [cachedFileInfo objectForKey:@"device"]; + XCTAssertNotNil([device objectForKey:@"osName"]); + XCTAssertNotNil([device objectForKey:@"osBuild"]); + XCTAssertNotNil([device objectForKey:@"osVersion"]); + XCTAssertNotNil([device objectForKey:@"id"]); + XCTAssertNotNil([device objectForKey:@"model"]); + XCTAssertNotNil([device objectForKey:@"simulator"]); + XCTAssertNotNil([device objectForKey:@"wordSize"]); + XCTAssertEqual([device valueForKey:@"locale"], [[NSLocale currentLocale] localeIdentifier]); +} + @end diff --git a/tvOS/Bugsnag.xcodeproj/project.pbxproj b/tvOS/Bugsnag.xcodeproj/project.pbxproj index 491b46e3c..3abbd4840 100644 --- a/tvOS/Bugsnag.xcodeproj/project.pbxproj +++ b/tvOS/Bugsnag.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 0071CB572460755500F562B1 /* BSG_KSMachHeaders.m in Sources */ = {isa = PBXBuildFile; fileRef = 0071CB552460755500F562B1 /* BSG_KSMachHeaders.m */; }; + 0071CB582460755500F562B1 /* BSG_KSMachHeaders.h in Headers */ = {isa = PBXBuildFile; fileRef = 0071CB562460755500F562B1 /* BSG_KSMachHeaders.h */; }; 4B3CD2B622C5625800DBFF33 /* BugsnagKSCrashSysInfoParserTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B3CD2B522C5625800DBFF33 /* BugsnagKSCrashSysInfoParserTest.m */; }; 4B3CD2BB22C5676800DBFF33 /* BSGOutOfMemoryWatchdogTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B3CD2B722C5676700DBFF33 /* BSGOutOfMemoryWatchdogTests.m */; }; 4B3CD2BC22C5676800DBFF33 /* BugsnagCrashReportFromKSCrashReportTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B3CD2B822C5676700DBFF33 /* BugsnagCrashReportFromKSCrashReportTest.m */; }; @@ -15,7 +17,6 @@ 4B406C1422CAD94100464D1D /* BugsnagCollectionsBSGDictSetSafeObjectTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B406C1222CAD94100464D1D /* BugsnagCollectionsBSGDictSetSafeObjectTest.m */; }; 4B406C1522CAD94100464D1D /* BugsnagCollectionsBSGDictMergeTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B406C1322CAD94100464D1D /* BugsnagCollectionsBSGDictMergeTest.m */; }; 4B775FD122CBE01F004839C5 /* BugsnagCollectionsBSGDictInsertIfNotNilTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B775FD022CBE01F004839C5 /* BugsnagCollectionsBSGDictInsertIfNotNilTest.m */; }; - 8A12006E221C51550008C9C3 /* BSGFilepathTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A12006D221C51550008C9C3 /* BSGFilepathTests.m */; }; 8A3C591023968B2000B344AA /* BugsnagPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A3C590F23968B2000B344AA /* BugsnagPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8A48EF291EAA824100B70024 /* BugsnagLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A48EF281EAA824100B70024 /* BugsnagLogger.h */; }; 8A530CBC22FDC39300F0C108 /* BSG_KSCrashIdentifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A530CBA22FDC39300F0C108 /* BSG_KSCrashIdentifier.m */; }; @@ -48,6 +49,8 @@ 8AD9A5041D42EEB0004E1CC5 /* BugsnagSink.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB151351D41366400C9B218 /* BugsnagSink.m */; }; 8AD9A5051D42EEE9004E1CC5 /* BSG_KSCrashReportWriter.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AB151251D41366400C9B218 /* BSG_KSCrashReportWriter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8AD9FA8D1E0863A1002859A7 /* BugsnagConfigurationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AD9FA8B1E0863A1002859A7 /* BugsnagConfigurationTests.m */; }; + E694862B24CB1CB6002077D1 /* BSG_RFC3339DateTool.h in Headers */ = {isa = PBXBuildFile; fileRef = E694862924CB1CB5002077D1 /* BSG_RFC3339DateTool.h */; }; + E694862C24CB1CB6002077D1 /* BSG_RFC3339DateTool.m in Sources */ = {isa = PBXBuildFile; fileRef = E694862A24CB1CB5002077D1 /* BSG_RFC3339DateTool.m */; }; E72352BA1F55922F00436528 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E72352B91F55922F00436528 /* SystemConfiguration.framework */; }; E72352BD1F55923700436528 /* BSGConnectivity.h in Headers */ = {isa = PBXBuildFile; fileRef = E72352BB1F55923700436528 /* BSGConnectivity.h */; }; E72352BE1F55923700436528 /* BSGConnectivity.m in Sources */ = {isa = PBXBuildFile; fileRef = E72352BC1F55923700436528 /* BSGConnectivity.m */; }; @@ -130,8 +133,6 @@ E76617C51F4E459C0094CECF /* BSG_KSSysCtl.h in Headers */ = {isa = PBXBuildFile; fileRef = E76617591F4E459C0094CECF /* BSG_KSSysCtl.h */; }; E76617CA1F4E459C0094CECF /* NSError+BSG_SimpleConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = E766175E1F4E459C0094CECF /* NSError+BSG_SimpleConstructor.h */; }; E76617CB1F4E459C0094CECF /* NSError+BSG_SimpleConstructor.m in Sources */ = {isa = PBXBuildFile; fileRef = E766175F1F4E459C0094CECF /* NSError+BSG_SimpleConstructor.m */; }; - E76617CE1F4E459C0094CECF /* BSG_RFC3339DateTool.h in Headers */ = {isa = PBXBuildFile; fileRef = E76617621F4E459C0094CECF /* BSG_RFC3339DateTool.h */; }; - E76617CF1F4E459C0094CECF /* BSG_RFC3339DateTool.m in Sources */ = {isa = PBXBuildFile; fileRef = E76617631F4E459C0094CECF /* BSG_RFC3339DateTool.m */; }; E76617D01F4E459C0094CECF /* BSG_KSCrashReportFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = E76617661F4E459C0094CECF /* BSG_KSCrashReportFilter.h */; }; E76617D11F4E459C0094CECF /* BSG_KSCrashReportFilterCompletion.h in Headers */ = {isa = PBXBuildFile; fileRef = E76617671F4E459C0094CECF /* BSG_KSCrashReportFilterCompletion.h */; }; E79148771FD82E6D003EFEBF /* BugsnagSession.h in Headers */ = {isa = PBXBuildFile; fileRef = E79148641FD82E6A003EFEBF /* BugsnagSession.h */; }; @@ -189,6 +190,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 0071CB552460755500F562B1 /* BSG_KSMachHeaders.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSG_KSMachHeaders.m; sourceTree = ""; }; + 0071CB562460755500F562B1 /* BSG_KSMachHeaders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BSG_KSMachHeaders.h; sourceTree = ""; }; 4B3CD2B522C5625800DBFF33 /* BugsnagKSCrashSysInfoParserTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BugsnagKSCrashSysInfoParserTest.m; path = ../../iOS/BugsnagTests/BugsnagKSCrashSysInfoParserTest.m; sourceTree = ""; }; 4B3CD2B722C5676700DBFF33 /* BSGOutOfMemoryWatchdogTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BSGOutOfMemoryWatchdogTests.m; path = ../../iOS/BugsnagTests/BSGOutOfMemoryWatchdogTests.m; sourceTree = ""; }; 4B3CD2B822C5676700DBFF33 /* BugsnagCrashReportFromKSCrashReportTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BugsnagCrashReportFromKSCrashReportTest.m; path = ../../iOS/BugsnagTests/BugsnagCrashReportFromKSCrashReportTest.m; sourceTree = ""; }; @@ -197,7 +200,6 @@ 4B406C1222CAD94100464D1D /* BugsnagCollectionsBSGDictSetSafeObjectTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BugsnagCollectionsBSGDictSetSafeObjectTest.m; path = ../../Tests/BugsnagCollectionsBSGDictSetSafeObjectTest.m; sourceTree = ""; }; 4B406C1322CAD94100464D1D /* BugsnagCollectionsBSGDictMergeTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BugsnagCollectionsBSGDictMergeTest.m; path = ../../Tests/BugsnagCollectionsBSGDictMergeTest.m; sourceTree = ""; }; 4B775FD022CBE01F004839C5 /* BugsnagCollectionsBSGDictInsertIfNotNilTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BugsnagCollectionsBSGDictInsertIfNotNilTest.m; path = ../../Tests/BugsnagCollectionsBSGDictInsertIfNotNilTest.m; sourceTree = ""; }; - 8A12006D221C51550008C9C3 /* BSGFilepathTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BSGFilepathTests.m; path = ../../Tests/BSGFilepathTests.m; sourceTree = ""; }; 8A3C590F23968B2000B344AA /* BugsnagPlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BugsnagPlugin.h; path = ../Source/BugsnagPlugin.h; sourceTree = ""; }; 8A48EF281EAA824100B70024 /* BugsnagLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BugsnagLogger.h; path = ../Source/BugsnagLogger.h; sourceTree = ""; }; 8A530CBA22FDC39300F0C108 /* BSG_KSCrashIdentifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BSG_KSCrashIdentifier.m; sourceTree = ""; }; @@ -233,6 +235,8 @@ 8AB151341D41366400C9B218 /* BugsnagSink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BugsnagSink.h; path = ../Source/BugsnagSink.h; sourceTree = ""; }; 8AB151351D41366400C9B218 /* BugsnagSink.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BugsnagSink.m; path = ../Source/BugsnagSink.m; sourceTree = ""; }; 8AD9FA8B1E0863A1002859A7 /* BugsnagConfigurationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BugsnagConfigurationTests.m; path = ../Tests/BugsnagConfigurationTests.m; sourceTree = SOURCE_ROOT; }; + E694862924CB1CB5002077D1 /* BSG_RFC3339DateTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSG_RFC3339DateTool.h; path = ../Source/BSG_RFC3339DateTool.h; sourceTree = ""; }; + E694862A24CB1CB5002077D1 /* BSG_RFC3339DateTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BSG_RFC3339DateTool.m; path = ../Source/BSG_RFC3339DateTool.m; sourceTree = ""; }; E72352B91F55922F00436528 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; E72352BB1F55923700436528 /* BSGConnectivity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSGConnectivity.h; path = ../Source/BSGConnectivity.h; sourceTree = ""; }; E72352BC1F55923700436528 /* BSGConnectivity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BSGConnectivity.m; path = ../Source/BSGConnectivity.m; sourceTree = ""; }; @@ -317,8 +321,6 @@ E76617591F4E459C0094CECF /* BSG_KSSysCtl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSG_KSSysCtl.h; path = ../Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSSysCtl.h; sourceTree = SOURCE_ROOT; }; E766175E1F4E459C0094CECF /* NSError+BSG_SimpleConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSError+BSG_SimpleConstructor.h"; path = "../Source/KSCrash/Source/KSCrash/Recording/Tools/NSError+BSG_SimpleConstructor.h"; sourceTree = SOURCE_ROOT; }; E766175F1F4E459C0094CECF /* NSError+BSG_SimpleConstructor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSError+BSG_SimpleConstructor.m"; path = "../Source/KSCrash/Source/KSCrash/Recording/Tools/NSError+BSG_SimpleConstructor.m"; sourceTree = SOURCE_ROOT; }; - E76617621F4E459C0094CECF /* BSG_RFC3339DateTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSG_RFC3339DateTool.h; path = ../Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_RFC3339DateTool.h; sourceTree = SOURCE_ROOT; }; - E76617631F4E459C0094CECF /* BSG_RFC3339DateTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BSG_RFC3339DateTool.m; path = ../Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_RFC3339DateTool.m; sourceTree = SOURCE_ROOT; }; E76617661F4E459C0094CECF /* BSG_KSCrashReportFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSG_KSCrashReportFilter.h; path = ../Source/KSCrash/Source/KSCrash/Reporting/Filters/BSG_KSCrashReportFilter.h; sourceTree = SOURCE_ROOT; }; E76617671F4E459C0094CECF /* BSG_KSCrashReportFilterCompletion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSG_KSCrashReportFilterCompletion.h; path = ../Source/KSCrash/Source/KSCrash/Reporting/Filters/BSG_KSCrashReportFilterCompletion.h; sourceTree = SOURCE_ROOT; }; E79148641FD82E6A003EFEBF /* BugsnagSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BugsnagSession.h; path = ../Source/BugsnagSession.h; sourceTree = ""; }; @@ -412,6 +414,8 @@ 8A8D51261D41343500D33797 /* tvOS */ = { isa = PBXGroup; children = ( + E694862924CB1CB5002077D1 /* BSG_RFC3339DateTool.h */, + E694862A24CB1CB5002077D1 /* BSG_RFC3339DateTool.m */, 8A3C590F23968B2000B344AA /* BugsnagPlugin.h */, 8A6C6FAC2257882400E8EF24 /* BSGOutOfMemoryWatchdog.h */, 8A6C6FAB2257882400E8EF24 /* BSGOutOfMemoryWatchdog.m */, @@ -598,6 +602,8 @@ E76617361F4E459C0094CECF /* Tools */ = { isa = PBXGroup; children = ( + 0071CB562460755500F562B1 /* BSG_KSMachHeaders.h */, + 0071CB552460755500F562B1 /* BSG_KSMachHeaders.m */, E76617371F4E459C0094CECF /* BSG_KSArchSpecific.h */, E76617381F4E459C0094CECF /* BSG_KSBacktrace.c */, E76617391F4E459C0094CECF /* BSG_KSBacktrace.h */, @@ -633,8 +639,6 @@ E76617591F4E459C0094CECF /* BSG_KSSysCtl.h */, E766175E1F4E459C0094CECF /* NSError+BSG_SimpleConstructor.h */, E766175F1F4E459C0094CECF /* NSError+BSG_SimpleConstructor.m */, - E76617621F4E459C0094CECF /* BSG_RFC3339DateTool.h */, - E76617631F4E459C0094CECF /* BSG_RFC3339DateTool.m */, ); name = Tools; path = ../Source/KSCrash/Source/KSCrash/Recording/Tools; @@ -736,6 +740,7 @@ E76617911F4E459C0094CECF /* BSG_KSSystemInfo.h in Headers */, 8AD9A4FA1D42EE96004E1CC5 /* BugsnagMetaData.h in Headers */, E76616F71F4E45950094CECF /* BugsnagCrashSentry.h in Headers */, + 0071CB582460755500F562B1 /* BSG_KSMachHeaders.h in Headers */, E76617861F4E459C0094CECF /* BSG_KSCrashReport.h in Headers */, 8A48EF291EAA824100B70024 /* BugsnagLogger.h in Headers */, E76617C11F4E459C0094CECF /* BSG_KSSingleton.h in Headers */, @@ -760,8 +765,8 @@ E76617BB1F4E459C0094CECF /* BSG_KSObjC.h in Headers */, E76617C31F4E459C0094CECF /* BSG_KSString.h in Headers */, E76617871F4E459C0094CECF /* BSG_KSCrashReportFields.h in Headers */, - E76617CE1F4E459C0094CECF /* BSG_RFC3339DateTool.h in Headers */, E72352BD1F55923700436528 /* BSGConnectivity.h in Headers */, + E694862B24CB1CB6002077D1 /* BSG_RFC3339DateTool.h in Headers */, 8AD9A4F71D42EE90004E1CC5 /* BugsnagCollections.h in Headers */, 8AD9A4FB1D42EE96004E1CC5 /* BugsnagNotifier.h in Headers */, E79148771FD82E6D003EFEBF /* BugsnagSession.h in Headers */, @@ -869,6 +874,7 @@ files = ( E76617C21F4E459C0094CECF /* BSG_KSString.c in Sources */, E79148871FD82E6D003EFEBF /* BugsnagSessionTracker.m in Sources */, + E694862C24CB1CB6002077D1 /* BSG_RFC3339DateTool.m in Sources */, E76617C41F4E459C0094CECF /* BSG_KSSysCtl.c in Sources */, 8AD9A5001D42EEA9004E1CC5 /* BugsnagConfiguration.m in Sources */, 8A627CD61EC3B69300F7C04E /* BSGSerialization.m in Sources */, @@ -911,6 +917,7 @@ E76616FA1F4E45950094CECF /* BugsnagErrorReportApiClient.m in Sources */, E76617AD1F4E459C0094CECF /* BSG_KSJSONCodec.c in Sources */, E766179D1F4E459C0094CECF /* BSG_KSCrashSentry_NSException.m in Sources */, + 0071CB572460755500F562B1 /* BSG_KSMachHeaders.m in Sources */, E76617851F4E459C0094CECF /* BSG_KSCrashReport.c in Sources */, 8AD9A5021D42EEB0004E1CC5 /* BugsnagMetaData.m in Sources */, E766179A1F4E459C0094CECF /* BSG_KSCrashSentry_MachException.c in Sources */, @@ -920,7 +927,6 @@ 8AD9A4FD1D42EE99004E1CC5 /* Bugsnag.m in Sources */, E766177E1F4E459C0094CECF /* BSG_KSCrash.m in Sources */, E76617A11F4E459C0094CECF /* BSG_KSCrashSentry_User.c in Sources */, - E76617CF1F4E459C0094CECF /* BSG_RFC3339DateTool.m in Sources */, E72352BE1F55923700436528 /* BSGConnectivity.m in Sources */, 8A530CBC22FDC39300F0C108 /* BSG_KSCrashIdentifier.m in Sources */, );