Skip to content

fix: resolve EXC_BAD_ACCESS in SentryTracer/SentryNetworkTracker span lifecycle#8058

Draft
itaybre wants to merge 2 commits into
mainfrom
fix/exc-bad-access-tracer-network-span-lifecycle
Draft

fix: resolve EXC_BAD_ACCESS in SentryTracer/SentryNetworkTracker span lifecycle#8058
itaybre wants to merge 2 commits into
mainfrom
fix/exc-bad-access-tracer-network-span-lifecycle

Conversation

@itaybre

@itaybre itaybre commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Description

Fix two crash paths in the SentryTracerSentryNetworkTracker call chain that cause EXC_BAD_ACCESS crashes. This is the most frequent crash pattern in SDK-CRASHES-COCOA-5 (43/100 sampled events), affecting 7 customer projects across SDK versions 8.36.0–9.9.0 with ~140K events in the last 90 days.

Root causes and fixes

1. TOCTOU race in SentryTracer.canBeFinishedhasUnfinishedChildSpansToWaitFor was evaluated outside @synchronized(self), so two concurrent threads could both observe "no unfinished children" and race into finishInternal, operating on deallocated state. Moved the check inside the synchronized block.

2. Volatile currentRequest re-readsSentryTracePropagation.addBaggageHeader: and SentryNetworkTracker.urlSessionTaskResume: accessed sessionTask.currentRequest multiple times without retaining. The property can return a freed object if the task completes on another thread between reads (CFURLRequestSetHTTPRequestBody crash). Both methods now snapshot the request once into a local variable.

3. Weak span dangling refs in TTD callbackSentryTimeToDisplayTracker's finishCallback accessed weak initialDisplaySpan/fullDisplaySpan properties repeatedly without strongifying. The spans could be zeroed mid-callback if the tracer's children are released concurrently. Now strongified into locals at callback entry with nil guards.

How tested

  • make format — clean
  • make analyze — clean
  • make build-ios — succeeds
  • make test-ios ONLY_TESTING=SentryTests/SentryTracerTests — 86 tests pass
  • make test-ios ONLY_TESTING=SentryTests/SentryTracePropagationTests,SentryTests/SentryNetworkTrackerTests,SentryTests/SentryTimeToDisplayTrackerTest — 100 tests pass

Closes #8012

… lifecycle

Fix two crash paths in the SentryTracer → SentryNetworkTracker call chain
that cause use-after-free crashes (SDK-CRASHES-COCOA-5, ~140K events/90d):

1. TOCTOU race in canBeFinished: hasUnfinishedChildSpansToWaitFor was
   checked outside @synchronized(self), allowing concurrent threads to
   both see "no unfinished children" and call finishInternal. Moved the
   check inside the synchronized block.

2. Volatile currentRequest re-reads: SentryTracePropagation and
   SentryNetworkTracker accessed sessionTask.currentRequest multiple
   times without retaining. The property can return a freed object if
   the task completes on another thread between reads. Snapshot the
   request once into a local variable in both methods.

3. Weak span dangling refs in TTD callback: SentryTimeToDisplayTracker's
   finishCallback accessed weak initialDisplaySpan/fullDisplaySpan
   properties repeatedly. Strongify into locals at callback entry with
   nil guards.

Closes #8012
@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor
Fails
🚫 Please consider adding a changelog entry for the next release.

Instructions and example for changelog

Please add an entry to CHANGELOG.md to the "Unreleased" section. Make sure the entry includes this PR's number.

Example:

## Unreleased

### Fixes

- resolve EXC_BAD_ACCESS in SentryTracer/SentryNetworkTracker span lifecycle ([#8058](https://github.com/getsentry/sentry-cocoa/pull/8058))

If none of the above apply, you can opt out of this check by adding #skip-changelog to the PR description or adding a skip-changelog label.

Generated by 🚫 dangerJS against ad1d81a

@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.22222% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 87.203%. Comparing base (11b0eef) to head (ad1d81a).
⚠️ Report is 4 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
Sources/Sentry/SentryTracePropagation.m 92.307% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@              Coverage Diff              @@
##              main     #8058       +/-   ##
=============================================
- Coverage   87.306%   87.203%   -0.104%     
=============================================
  Files          554       559        +5     
  Lines        31986     32172      +186     
  Branches     13139     13146        +7     
=============================================
+ Hits         27926     28055      +129     
- Misses        4012      4069       +57     
  Partials        48        48               
Files with missing lines Coverage Δ
Sources/Sentry/SentryNetworkTracker.m 97.759% <100.000%> (ø)
Sources/Sentry/SentryTimeToDisplayTracker.m 98.979% <100.000%> (+0.032%) ⬆️
Sources/Sentry/SentryTracer.m 99.297% <100.000%> (+1.639%) ⬆️
Sources/Sentry/SentryTracePropagation.m 75.862% <92.307%> (-5.957%) ⬇️

... and 21 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

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

Cover the three crash paths fixed in the previous commit:

- SentryTracerTests: concurrent child span finish racing with
  tracer.finish() to verify canBeFinished atomicity
- SentryNetworkTrackerTests: concurrent resume + setState on the
  same task, and resume after task already completed
- SentryTimeToDisplayTrackerTest: concurrent tracer finish with
  child span operations, and finish with no full display span
- SentryTracePropagationTests: addBaggageHeader with nil
  currentRequest (task with no request set)
@github-actions

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code can easily blow up and is hard to test. We had severe bugs in the past. Be extra careful when changing these files, and have an extra careful look at these:

  • Sources/Sentry/SentryNetworkTracker.m

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.

EXC_BAD_ACCESS in SentryTracer/SentryNetworkTracker span lifecycle

1 participant