-
-
Notifications
You must be signed in to change notification settings - Fork 408
KSCrash: install crash handler #8469
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Open
Changes from 27 commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
2b5250f
feat: install KSCrash with production-safe monitors in SentryKSCrashI…
NinjaLikesCheez 8e2c53e
fix: remove KSCrashInstallations import from test target to break dep…
NinjaLikesCheez 1d24690
fix: treat KSCrash alreadyInstalled error as success
NinjaLikesCheez 84b4353
chore: abstract KSCrash to protocols so testutils doesn't need to imp…
NinjaLikesCheez 9b22e6d
ref: rework the API to nest related types
NinjaLikesCheez 59a2762
test: update to use swift testing because the future is now
NinjaLikesCheez f41cd5b
changelog: add changelog for feature
NinjaLikesCheez 24c7263
chore: correctly disable arm64e for mac catalyst builds
NinjaLikesCheez 4ca43bd
build: bump macOS deployment target to 10.15 for test targets only
NinjaLikesCheez f739144
test(kscrash): revert Swift Testing conversion back to XCTest
NinjaLikesCheez fec5a4d
test(kscrash): rename tests to follow project naming convention
NinjaLikesCheez 130cfe3
fix(kscrash): expose productionSafeMonitors as UInt to fix test build
NinjaLikesCheez 220f37c
chore: remove unused membership exception
NinjaLikesCheez 731abd1
chore: mirror SentryCrash install path configuration
NinjaLikesCheez fbc56d5
chore: wire into SentrySDK's crash status reporting
NinjaLikesCheez 3640f20
fix: use CFBundleName instead of CFBundleIdentifier
NinjaLikesCheez 940d2e7
feat: separate 'fatalDetected' into 'crashHandlerDetectedCrash'
NinjaLikesCheez 440b482
chore: sanitize file path in same way as SentryCrash (also fix name i…
NinjaLikesCheez a394bc2
test: reset state after tests
NinjaLikesCheez 57c91fa
lint: appease the linting god for the rules hath changed under me
NinjaLikesCheez 207f6c1
lint: disable the rule (fixed in a follow up PR) as the semantics of …
NinjaLikesCheez d975839
chore: extract install path to helper function to centralize path bui…
NinjaLikesCheez 0c228c3
ref: extract installer to local variable
NinjaLikesCheez a23914d
test: don't clear test state on setup & tear down
NinjaLikesCheez 2290319
chore: track installed status at the crash subsystem level
NinjaLikesCheez f37a279
feat: Add SentryKSCrash+Query to expose crash handler state (swift) t…
NinjaLikesCheez eb0fd17
test: update tests to use new SentryKSCrash & SDKInternal API
NinjaLikesCheez 0c27969
test: add test to cover setting fatalDetected
NinjaLikesCheez File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
Sources/Swift/Integrations/KSCrash/SentryKSCrash+Installer.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| #if ENABLE_KSCRASH | ||
| // swiftlint:disable:next no_implementation_only_import | ||
| @_implementationOnly import KSCrashInstallations | ||
|
|
||
| extension SentryKSCrash { | ||
| protocol Installing { | ||
| /// Install the crash handler. | ||
| /// - Parameters: | ||
| /// - installPath: The base directory for crash report storage. | ||
| /// - monitors: Monitor types to enable. | ||
| /// - enableSwapCxaThrow: Whether to swap `__cxa_throw` for better C++ stacks. | ||
| /// - Throws: Any error from `KSCrash.installWithConfiguration(_:error:)`. | ||
| func install(installPath: String, monitors: UInt, enableSwapCxaThrow: Bool) throws | ||
|
|
||
| /// Whether the previous run crashed. | ||
| var crashedLastLaunch: Bool { get } | ||
|
|
||
| var installed: Bool { get } | ||
| } | ||
|
|
||
| /// Configures and installs a crash handler | ||
| struct Installer: SentryKSCrash.Installing { | ||
| func install(installPath: String, monitors: UInt, enableSwapCxaThrow: Bool) throws { | ||
| let config = KSCrashConfiguration() | ||
| config.installPath = installPath | ||
| config.monitors = MonitorType(rawValue: monitors) | ||
| config.enableSwapCxaThrow = enableSwapCxaThrow | ||
| do { | ||
| try KSCrash.shared.install(with: config) | ||
| } catch let error as NSError | ||
| where error.domain == "KSCrashErrorDomain" && error.code == 1 /* KSCrashInstallErrorAlreadyInstalled */ { | ||
| // KSCrash holds a process-lifetime C flag, so install() fails on every | ||
| // subsequent call within the same process (common during tests and SDK re-init). | ||
| // The crash handler is already running — treat this as success. | ||
| SentrySDKLog.debug("KSCrash already installed; continuing.") | ||
| } | ||
| } | ||
|
|
||
| var crashedLastLaunch: Bool { KSCrash.shared.crashedLastLaunch } | ||
|
|
||
| var installed: Bool { | ||
| // From KSCrash docs: 'If the crash reporter is not installed, this will be `nil`' | ||
| KSCrash.shared.reportStore != nil | ||
| } | ||
| } | ||
| } | ||
| #endif |
76 changes: 76 additions & 0 deletions
76
Sources/Swift/Integrations/KSCrash/SentryKSCrash+Integration.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| #if ENABLE_KSCRASH | ||
| // swiftlint:disable:next no_implementation_only_import | ||
| @_implementationOnly import KSCrashInstallations | ||
| internal import _SentryPrivate | ||
| import Foundation | ||
|
|
||
| // MARK: - Integration | ||
| extension SentryKSCrash { | ||
| typealias DependencyProvider = SentryKSCrash.InstallerProvider | ||
|
|
||
| /// Crash detectors matching SentryCrash's production monitor set: | ||
| /// Mach exceptions, signals, C++ exceptions, and NSExceptions. | ||
| /// KSCrash unconditionally adds its Required monitors (System, AppState, | ||
| /// UserInfo, Resource) on top of whatever is passed here. | ||
| static let productionSafeMonitors: UInt = MonitorType([ | ||
| .machException, | ||
| .signal, | ||
| .cppException, | ||
| .nsException | ||
| ]).rawValue | ||
|
|
||
| final class Integration<Dependencies: DependencyProvider>: NSObject, SwiftIntegration { | ||
| private weak var options: Options? | ||
|
|
||
| // MARK: - Initialization | ||
|
|
||
| init?(with options: Options, dependencies: Dependencies) { | ||
| guard options.enableCrashHandler else { | ||
| SentrySDKLog.debug("Not going to enable \(Self.name) because enableCrashHandler is disabled.") | ||
| return nil | ||
| } | ||
|
|
||
| self.options = options | ||
| super.init() | ||
|
|
||
| let installer = dependencies.getKSCrashInstaller() | ||
|
|
||
| // To match KSCrash & SentryCrash, we need to add 'KSCrash/<bundlename>' to the cacheDirectoryPath | ||
| let installPath = Self.installPath(for: options.cacheDirectoryPath, bundleInfo: Bundle.main.infoDictionary) | ||
|
|
||
| do { | ||
| try installer.install( | ||
| installPath: installPath.path, | ||
| monitors: productionSafeMonitors, | ||
| enableSwapCxaThrow: options.experimental.enableUnhandledCPPExceptionsV2 | ||
| ) | ||
|
cursor[bot] marked this conversation as resolved.
|
||
| } catch { | ||
| SentrySDKLog.error("KSCrash install failed: \(error)") | ||
| return nil | ||
| } | ||
|
|
||
| if installer.crashedLastLaunch { | ||
| SentrySDKInternal.fatalDetected = true | ||
| } | ||
|
cursor[bot] marked this conversation as resolved.
|
||
| } | ||
|
|
||
| // MARK: - SwiftIntegration | ||
| static var name: String { | ||
| "SentryKSCrashIntegration" | ||
| } | ||
|
|
||
| func uninstall() {} | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| // MARK: - Helpers | ||
| /// Get the install path for the crash reporter | ||
| /// This method exists to centralize path building to save rebuilding it manually in tests | ||
| static func installPath(for cacheDirectoryPath: String, bundleInfo: [String: Any]?) -> URL { | ||
| let bundleName = bundleInfo?["CFBundleName"] as? String ?? "Unknown" | ||
| return URL(fileURLWithPath: cacheDirectoryPath) | ||
| .appendingPathComponent("KSCrash") | ||
| .appendingPathComponent(bundleName.replacingOccurrences(of: "/", with: "-")) | ||
| .absoluteURL | ||
| } | ||
| } | ||
| } | ||
| #endif | ||
46 changes: 46 additions & 0 deletions
46
Sources/Swift/Integrations/KSCrash/SentryKSCrash+Query.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| #if ENABLE_KSCRASH | ||
| // swiftlint:disable:next no_implementation_only_import | ||
| @_implementationOnly import KSCrashInstallations | ||
| internal import _SentryPrivate | ||
|
|
||
| extension SentryKSCrash { | ||
| protocol QueryProvider { | ||
| associatedtype Querying: SentryKSCrash.Querying | ||
|
|
||
| var kscrashQuery: Querying { get } | ||
| } | ||
| } | ||
|
|
||
| extension SentryKSCrash { | ||
| /// Allows querying the state of the crash reporter | ||
| @objc(SentryKSCrashQuerying) | ||
| public protocol Querying: NSObjectProtocol { | ||
| /// Whether KSCrash has been successfully installed this session. | ||
| @objc var installed: Bool { get } | ||
| /// Whether KSCrash crashed on the previous launch. | ||
| @objc var crashedLastLaunch: Bool { get } | ||
| } | ||
| } | ||
|
|
||
| extension SentryKSCrash { | ||
| /// An ObjC-accessible class that surfaces live KSCrash crash state to ObjC callers | ||
| /// without adding `@objc` to `SentryKSCrash.Installer`. | ||
| @_spi(Private) | ||
| @objc(SentryKSCrashQuery) | ||
| final public class Query: NSObject, Querying { | ||
| private let installer: any Installing | ||
|
|
||
| init(installer: some Installing) { | ||
| self.installer = installer | ||
| } | ||
|
|
||
| // swiftlint:disable missing_docs | ||
| @objc | ||
| public var installed: Bool { installer.installed } | ||
|
|
||
| @objc | ||
| public var crashedLastLaunch: Bool { installer.crashedLastLaunch } | ||
| //swiftlint:enable missing_docs | ||
| } | ||
| } | ||
| #endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| #if ENABLE_KSCRASH | ||
| /// All types related to KSCrash should live under this type | ||
| @_spi(Private) public enum SentryKSCrash { | ||
| /// Provides a `KSCrashInstalling` instance for dependency injection. | ||
| protocol InstallerProvider { | ||
| /// The installer used to set up KSCrash crash reporting. | ||
| associatedtype Installing: SentryKSCrash.Installing | ||
|
|
||
| func getKSCrashInstaller() -> Installing | ||
| } | ||
| } | ||
| #endif |
38 changes: 0 additions & 38 deletions
38
Sources/Swift/Integrations/KSCrash/SentryKSCrashIntegration.swift
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: When
ENABLE_KSCRASHis active,crashedLastRunincorrectly reads from the disabledSentryCrashreporter, always returningfalseeven after a crash.Severity: MEDIUM
Suggested Fix
Use an
#if ENABLE_KSCRASHpreprocessor directive for thecrashedLastRunproperty. When the flag is active, the property should get its value fromSentryDependencyContainer.sharedInstance.kscrashQuery.crashedLastLaunch. Otherwise, it should use the existingSentryDependencyContainer.sharedInstance.crashReporter.crashedLastLaunch.Prompt for AI Agent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i guess this is because
+(BOOL) crashedLastRunis just above this, but it's compiled out in SDK_V10 mode (which ENABLE_KSCRASH includes).