Skip to content

fix(macos): Don't overwrite exception value with notable addresses for AppKit _crashOnException crashes#7734

Open
denrase wants to merge 9 commits intomainfrom
fix/better-cpp-exception-value
Open

fix(macos): Don't overwrite exception value with notable addresses for AppKit _crashOnException crashes#7734
denrase wants to merge 9 commits intomainfrom
fix/better-cpp-exception-value

Conversation

@denrase
Copy link
Copy Markdown
Collaborator

@denrase denrase commented Mar 24, 2026

📜 Description

When an NSException on macOS falls through to the mach exception monitor (via AppKit's _crashOnException:), enhanceValueFromNotableAddresses overwrites the exception value with "garbage" strings from registers/stack memory (e.g., 0x000000019de89d54 start + 7184). This happens for macOS apps that don't use SentryCrashExceptionApplication or have enableUncaughtNSExceptionReporting disabled.

The fix detects this specific crash pattern (EXC_BREAKPOINT with a crashed-thread frame inside AppKit) and skips the notable address enhancement, preserving the original mach exception description.

💡 Motivation and Context

Relates to #1562

💚 How did you test it?

Unit test. Tested with sample app.

📝 Checklist

You have to check all boxes before merging:

  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.

denrase added 2 commits March 24, 2026 16:29
…r AppKit _crashOnException crashes

When an NSException on macOS falls through to the mach exception monitor (via AppKit's _crashOnException:), enhanceValueFromNotableAddresses overwrites the exception value with garbage strings from registers/stack memory (e.g., 0x000000019de89d54 start + 7184). This happens for macOS apps that don't use SentryCrashExceptionApplication or have enableUncaughtNSExceptionReporting disabled.

The fix detects this specific crash pattern (EXC_BREAKPOINT with a crashed-thread frame inside AppKit) and skips the notable address enhancement, preserving the original mach exception description.

Relates to #1562
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 24, 2026

Semver Impact of This PR

🟢 Patch (bug fixes)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


Bug Fixes 🐛

  • (macos) Don't overwrite exception value with notable addresses for AppKit _crashOnException crashes by denrase in #7734
  • Per-instance unmaskView propagates to child views by denrase in #7733

Documentation 📚

  • Add SentryCrash analysis and improvement plan document by itaybre in #7528

Internal Changes 🔧

Deps

  • Bump ruby/setup-ruby from 1.295.0 to 1.298.0 by dependabot in #7751
  • Bump codecov/codecov-action from 5.5.3 to 6.0.0 by dependabot in #7749
  • Bump getsentry/craft from 2.25.0 to 2.25.2 by dependabot in #7748
  • Bump fastlane-plugin-sentry from 2.4.0 to 2.5.0 by dependabot in #7746
  • Bump actions/deploy-pages from 4.0.5 to 5.0.0 by dependabot in #7747
  • Update clang-format version by sentry-mobile-updater in #7755
  • Bump getsentry/craft/.github/workflows/changelog-preview.yml from 2.25.0 to 2.25.2 by dependabot in #7750
  • Bump activesupport from 7.2.3 to 7.2.3.1 by dependabot in #7732
  • Bump fastlane-plugin-sentry from 2.3.0 to 2.4.0 by dependabot in #7724
  • Bump ruby/setup-ruby from 1.292.0 to 1.295.0 by dependabot in #7728
  • Bump getsentry/craft from 2.24.1 to 2.25.0 by dependabot in #7729
  • Bump codecov/codecov-action from 5.5.2 to 5.5.3 by dependabot in #7725
  • Bump actions/create-github-app-token from 2.2.1 to 3.0.0 by dependabot in #7726
  • Bump getsentry/craft/.github/workflows/changelog-preview.yml from 2.24.1 to 2.25.0 by dependabot in #7727
  • Bump json from 2.18.1 to 2.19.2 by dependabot in #7709

Other

  • Pin GitHub Actions to full-length commit SHAs by joshuarli in #7730

🤖 This preview updates automatically when you update the PR.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 24, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.102%. Comparing base (1d8568d) to head (cba7a89).
⚠️ Report is 7 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files

Impacted file tree graph

@@              Coverage Diff              @@
##              main     #7734       +/-   ##
=============================================
- Coverage   85.366%   85.102%   -0.265%     
=============================================
  Files          487       487               
  Lines        28996     29012       +16     
  Branches     12553     12556        +3     
=============================================
- Hits         24753     24690       -63     
- Misses        4195      4274       +79     
  Partials        48        48               
Files with missing lines Coverage Δ
Sources/Sentry/SentryCrashReportConverter.m 96.418% <100.000%> (+0.165%) ⬆️

... and 11 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1d8568d...cba7a89. Read the comment docs.

@denrase denrase marked this pull request as ready for review March 27, 2026 13:41
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Nil image name falsely matches AppKit substring check
    • The AppKit frame check now first assigns and validates imageName as non-nil before calling rangeOfString:, preventing nil receivers from falsely matching.

Create PR

Or push these changes by commenting:

@cursor push f56fc09dda
Preview (f56fc09dda)
diff --git a/Sources/Sentry/SentryCrashReportConverter.m b/Sources/Sentry/SentryCrashReportConverter.m
--- a/Sources/Sentry/SentryCrashReportConverter.m
+++ b/Sources/Sentry/SentryCrashReportConverter.m
@@ -543,7 +543,8 @@
     for (NSUInteger i = 0; i < limit; i++) {
         uintptr_t addr = (uintptr_t)[frames[i][@"instruction_addr"] unsignedLongLongValue];
         NSDictionary *image = [self binaryImageForAddress:addr];
-        if (image != nil && [image[@"name"] rangeOfString:@"AppKit"].location != NSNotFound) {
+        NSString *imageName = image[@"name"];
+        if (imageName != nil && [imageName rangeOfString:@"AppKit"].location != NSNotFound) {
             return YES;
         }
     }

This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

for (NSUInteger i = 0; i < limit; i++) {
uintptr_t addr = (uintptr_t)[frames[i][@"instruction_addr"] unsignedLongLongValue];
NSDictionary *image = [self binaryImageForAddress:addr];
if (image != nil && [image[@"name"] rangeOfString:@"AppKit"].location != NSNotFound) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nil image name falsely matches AppKit substring check

Low Severity

If image[@"name"] is nil, [nil rangeOfString:@"AppKit"] returns a zero-filled NSRange with location = 0. Since NSNotFound is NSIntegerMax, the comparison .location != NSNotFound evaluates to YES, causing a binary image with no name to be falsely identified as AppKit. This would make isMachExceptionFromAppKitCrashOnException return YES incorrectly, suppressing the notable address enhancement for crashes that aren't _crashOnException:.

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there are images with no names, but we should cover ourselves just in case

Copy link
Copy Markdown
Contributor

@itaybre itaybre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly looks good, I am just worried about this logic including other exceptions too

for (NSUInteger i = 0; i < limit; i++) {
uintptr_t addr = (uintptr_t)[frames[i][@"instruction_addr"] unsignedLongLongValue];
NSDictionary *image = [self binaryImageForAddress:addr];
if (image != nil && [image[@"name"] rangeOfString:@"AppKit"].location != NSNotFound) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there are images with no names, but we should cover ourselves just in case

for (NSUInteger i = 0; i < limit; i++) {
uintptr_t addr = (uintptr_t)[frames[i][@"instruction_addr"] unsignedLongLongValue];
NSDictionary *image = [self binaryImageForAddress:addr];
if (image != nil && [image[@"name"] rangeOfString:@"AppKit"].location != NSNotFound) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: Are we 100% that both conditions are enough (exception type and appkit present)?
We already removed _crashOnException from the stacktrace, right? If not adding that could help

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point, will check if we have better heuristics for this so we only filter out unusual messages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants