Skip to content

fix: Record cached dyld images async#7269

Open
noahsmartin wants to merge 2 commits intomainfrom
imageCacheAsync
Open

fix: Record cached dyld images async#7269
noahsmartin wants to merge 2 commits intomainfrom
imageCacheAsync

Conversation

@noahsmartin
Copy link
Contributor

@noahsmartin noahsmartin commented Jan 23, 2026

Resolves #4618 by moving the crash reporting tracking of dyld images to a background thread. Also fixes existing race conditions in that image tracker. Synchronization is now done with atomics so the crash handler can read from the added images.

VC swizzling is updated to iterate dyld loaded images directly, rather than getting them from the cache. VC tracking still does some work on the main thread, but less than the cache was doing previously. This makes it possible to disable all dyld work on the main thread if you turn off VC swizzling. There is no need for VC swizzling to use the image cache IMO since the purpose of the image cache is to provide a re-entrant API for crash reporting

#skip-changelog

@github-actions
Copy link
Contributor

github-actions bot commented Jan 23, 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).


This PR will not appear in the changelog.


🤖 This preview updates automatically when you update the PR.

@codecov
Copy link

codecov bot commented Jan 23, 2026

Codecov Report

❌ Patch coverage is 90.80460% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.289%. Comparing base (3a42337) to head (c2e30bf).
⚠️ Report is 12 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...entryCrash/Recording/SentryCrashBinaryImageCache.c 88.235% 5 Missing and 3 partials ⚠️
Additional details and impacted files

Impacted file tree graph

@@              Coverage Diff              @@
##              main     #7269       +/-   ##
=============================================
- Coverage   85.308%   85.289%   -0.020%     
=============================================
  Files          480       480               
  Lines        28622     28605       -17     
  Branches     12378     12398       +20     
=============================================
- Hits         24417     24397       -20     
- Misses        4157      4159        +2     
- Partials        48        49        +1     
Files with missing lines Coverage Δ
...ces/Swift/Core/Helper/SentryBinaryImageCache.swift 95.789% <100.000%> (-0.365%) ⬇️
.../Performance/SentryUIViewControllerSwizzling.swift 83.870% <100.000%> (-1.750%) ⬇️
...s/Swift/SentryCrash/SentryDebugImageProvider.swift 100.000% <ø> (ø)
Sources/Swift/SentryDependencyContainer.swift 97.156% <ø> (-0.014%) ⬇️
...entryCrash/Recording/SentryCrashBinaryImageCache.c 89.534% <88.235%> (-6.210%) ⬇️

... and 6 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 3a42337...c2e30bf. Read the comment docs.

@noahsmartin noahsmartin added the ready-to-merge Use this label to trigger all PR workflows label Jan 23, 2026
@philipphofmann
Copy link
Member

@noahsmartin, I didn't check the code yet, as this is still a draft. Please be aware that they also need the loaded binary image in the UIViewControllerSwizzling, as pointed out here #4618 (comment). If the proposal respects this, then excellent.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 26, 2026

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 1196.08 ms 1214.86 ms 18.78 ms
Size 24.14 KiB 1.11 MiB 1.08 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
5a4353f 1208.10 ms 1240.50 ms 32.40 ms
92e1256 1218.58 ms 1250.63 ms 32.04 ms
a424cf3 1231.36 ms 1259.62 ms 28.25 ms
2d59844 1208.98 ms 1245.25 ms 36.27 ms
d4dd2bd 1218.59 ms 1255.21 ms 36.61 ms
09a80f2 1214.78 ms 1237.85 ms 23.07 ms
ee272e8 1210.98 ms 1245.10 ms 34.12 ms
feceb0d 1214.55 ms 1237.04 ms 22.50 ms
1d0feed 1213.31 ms 1247.44 ms 34.14 ms
aa58669 1218.51 ms 1258.55 ms 40.04 ms

App size

Revision Plain With Sentry Diff
5a4353f 24.14 KiB 1.07 MiB 1.04 MiB
92e1256 24.14 KiB 1.11 MiB 1.09 MiB
a424cf3 24.14 KiB 1.06 MiB 1.04 MiB
2d59844 24.14 KiB 1.09 MiB 1.06 MiB
d4dd2bd 24.14 KiB 1.10 MiB 1.08 MiB
09a80f2 24.14 KiB 1.10 MiB 1.08 MiB
ee272e8 24.14 KiB 1.10 MiB 1.08 MiB
feceb0d 24.14 KiB 1.10 MiB 1.08 MiB
1d0feed 24.14 KiB 1.05 MiB 1.03 MiB
aa58669 24.14 KiB 1.10 MiB 1.07 MiB

Previous results on branch: imageCacheAsync

Startup times

Revision Plain With Sentry Diff
7847014 1222.58 ms 1241.55 ms 18.97 ms
45a6e74 1217.39 ms 1254.95 ms 37.56 ms
272a47a 1233.83 ms 1249.33 ms 15.50 ms
f02c17c 1212.57 ms 1246.06 ms 33.49 ms
6dfcb08 1209.61 ms 1251.52 ms 41.91 ms
823a3af 1206.16 ms 1222.51 ms 16.35 ms
629dd8e 1225.23 ms 1252.12 ms 26.89 ms
a93524f 1222.58 ms 1252.44 ms 29.86 ms
9cfdab1 1208.33 ms 1239.00 ms 30.67 ms
eaac74f 1220.91 ms 1251.35 ms 30.44 ms

App size

Revision Plain With Sentry Diff
7847014 24.14 KiB 1.10 MiB 1.08 MiB
45a6e74 24.14 KiB 1.10 MiB 1.08 MiB
272a47a 24.14 KiB 1.10 MiB 1.08 MiB
f02c17c 24.14 KiB 1.10 MiB 1.07 MiB
6dfcb08 24.14 KiB 1.10 MiB 1.07 MiB
823a3af 24.14 KiB 1.08 MiB 1.06 MiB
629dd8e 24.14 KiB 1.10 MiB 1.08 MiB
a93524f 24.14 KiB 1.11 MiB 1.09 MiB
9cfdab1 24.14 KiB 1.10 MiB 1.07 MiB
eaac74f 24.14 KiB 1.11 MiB 1.08 MiB

@noahsmartin noahsmartin force-pushed the imageCacheAsync branch 11 times, most recently from 6fa7332 to 20488ae Compare February 10, 2026 01:50
@noahsmartin noahsmartin marked this pull request as ready for review February 10, 2026 19:27
…nch time

sentrycrashbic_startCache now dispatches its work on a background queue
so that the expensive _dyld_register_func_for_add_image callback (which
calls dladdr for every loaded image) does not block the main thread
during SDK initialization.

Since the cache may not be populated yet when
SentryUIViewControllerSwizzling.start() runs, replace its
SentryBinaryImageCache lookup with direct synchronous iteration of
_dyld_image_count/_dyld_get_image_name. Performance-sensitive users can
disable UIViewController swizzling.

Also fix a race condition in SentryCrashBinaryImageCache where stopCache
resets g_next_index while a concurrent add_dyld_image could increment it
afterwards. Move the reset into startCacheImpl and gate
iterateOverImages/registerAddedCallback on g_started.
Copy link

@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 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

= atomic_load_explicit(&g_addedCallback, memory_order_acquire);

// ---- Publish ----
atomic_store_explicit(&entry->ready, 1, memory_order_release);
Copy link

Choose a reason for hiding this comment

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

Reused slots stay published across restarts

Medium Severity

After stop/start, g_next_index is reset but g_images[idx].ready is never cleared before slot reuse. add_dyld_image increments g_next_index before republishing, so readers can observe ready == 1 from a prior run and read stale or partially overwritten image data.

Additional Locations (1)

Fix in Cursor Fix in Web

callback(&src->image);
}
break;
return;
Copy link

Choose a reason for hiding this comment

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

Remove callbacks still run after stop

Medium Severity

dyld_remove_image_cb does not check g_started. After sentrycrashbic_stopCache, remove events can still find old entries in g_images, flip ready, and invoke g_removedCallback. This allows cache-change notifications and state mutations after the cache is supposed to be stopped.

Additional Locations (1)

Fix in Cursor Fix in Web

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

Labels

ready-to-merge Use this label to trigger all PR workflows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

App Launch Time Slow:sentrycrashdl_getBinarylmageForHeader

3 participants