Skip to content
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

fix: Remove dispatch queue metadata collection to fix crash #3522

Merged
merged 7 commits into from
Jan 9, 2024

Conversation

indragiek
Copy link
Member

📜 Description

This PR removes the collection of dispatch queue metadata when profiling, and uses main as the hard-coded thread name for the main thread (in place of the queue name com.apple.main-thread) for consistency with other platforms.

💡 Motivation and Context

We have crashes in production from trying to read ThreadHandle::dispatchQueueAddress when profiling: #3503

This appears to be a race condition with queue lifetime that is not possible to fully fix. There are similar problems encountered by other projects trying to use the same API:

💚 How did you test it?

Updated the tests, checked that the hardcoded main thread name is set.

📝 Checklist

You have to check all boxes before merging:

  • I reviewed the submitted code.
  • 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.
  • 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.

🔮 Next steps

Copy link

codecov bot commented Dec 30, 2023

Codecov Report

All modified and coverable lines are covered by tests ✅

Comparison is base (1734d1b) 89.241% compared to head (ff52c12) 89.258%.

Additional details and impacted files

Impacted file tree graph

@@              Coverage Diff              @@
##              main     #3522       +/-   ##
=============================================
+ Coverage   89.241%   89.258%   +0.016%     
=============================================
  Files          529       529               
  Lines        57780     57718       -62     
  Branches     20687     20659       -28     
=============================================
- Hits         51564     51518       -46     
+ Misses        5300      5288       -12     
+ Partials       916       912        -4     
Files Coverage Δ
SentryTestUtils/SentryProfilerMocks.mm 100.000% <ø> (ø)
...tryTestUtils/SentryProfilerMocksSwiftCompatible.mm 100.000% <100.000%> (ø)
Sources/Sentry/Profiling/SentryProfilerState.mm 98.373% <100.000%> (-0.052%) ⬇️
Sources/Sentry/SentryBacktrace.cpp 88.172% <100.000%> (+1.564%) ⬆️
Sources/Sentry/SentryThreadHandle.cpp 70.121% <ø> (+0.891%) ⬆️
Sources/Sentry/SentryThreadMetadataCache.cpp 87.096% <ø> (-4.208%) ⬇️
...urces/Sentry/include/SentryThreadMetadataCache.hpp 100.000% <ø> (ø)
...SentryProfilerTests/SentryProfilerSwiftTests.swift 97.739% <100.000%> (-0.033%) ⬇️
Tests/SentryProfilerTests/SentryProfilerTests.mm 98.159% <100.000%> (-0.045%) ⬇️
...tryProfilerTests/SentryThreadMetadataCacheTests.mm 93.939% <ø> (-1.061%) ⬇️

... and 9 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 1734d1b...ff52c12. Read the comment docs.

Copy link

github-actions bot commented Dec 30, 2023

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 1234.96 ms 1248.09 ms 13.13 ms
Size 21.58 KiB 417.86 KiB 396.28 KiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
c0ff306 1219.24 ms 1243.96 ms 24.72 ms
9883c0f 1207.59 ms 1223.14 ms 15.55 ms
313b1d9 1240.18 ms 1258.44 ms 18.26 ms
034be1c 1222.67 ms 1236.22 ms 13.55 ms
156e771 1228.06 ms 1242.64 ms 14.58 ms
e2abb0d 1235.08 ms 1257.00 ms 21.92 ms
216bdf9 1199.84 ms 1209.53 ms 9.69 ms
b9a9ffd 1221.18 ms 1235.37 ms 14.19 ms
a9103fe 1221.49 ms 1243.33 ms 21.84 ms
3f6c30b 1252.98 ms 1266.22 ms 13.24 ms

App size

Revision Plain With Sentry Diff
c0ff306 20.76 KiB 434.65 KiB 413.89 KiB
9883c0f 22.85 KiB 405.47 KiB 382.62 KiB
313b1d9 22.85 KiB 414.11 KiB 391.26 KiB
034be1c 20.76 KiB 436.66 KiB 415.90 KiB
156e771 20.76 KiB 419.70 KiB 398.94 KiB
e2abb0d 20.76 KiB 434.72 KiB 413.96 KiB
216bdf9 21.58 KiB 418.13 KiB 396.54 KiB
b9a9ffd 21.58 KiB 418.43 KiB 396.85 KiB
a9103fe 20.76 KiB 426.95 KiB 406.19 KiB
3f6c30b 22.85 KiB 408.88 KiB 386.03 KiB

Previous results on branch: indragiek/remove-queue-metadata

Startup times

Revision Plain With Sentry Diff
5e6b38e 1194.29 ms 1209.20 ms 14.92 ms

App size

Revision Plain With Sentry Diff
5e6b38e 21.58 KiB 417.17 KiB 395.58 KiB

Copy link
Member

@philipphofmann philipphofmann left a comment

Choose a reason for hiding this comment

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

Good catch, thanks @indragiek 👍

if (!backtrace.threadMetadata.name.empty() && metadata[@"name"] == nil) {
metadata[@"name"] =
[NSString stringWithUTF8String:backtrace.threadMetadata.name.c_str()];
if (metadata[@"name"] == nil) {
Copy link
Member

Choose a reason for hiding this comment

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

m: I think we shoud first check if backtrace.threadMetadata.threadID == self->_mainThreadID. Otherwise, the main thread could have different names depending on the platform. Or is this the desired behavior?

Copy link
Member

Choose a reason for hiding this comment

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

This looks like it's checking if it's already been set previously, as we reuse the metadata dictionary. The check you mention does happen before we actually go to set the value on line 107 below in this hunk.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah @armcknight is right, that was the intent here

Copy link
Member

@armcknight armcknight left a comment

Choose a reason for hiding this comment

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

LGTM

Comment on lines 66 to 70
if ([NSThread isMainThread]) {
[self cacheMainThreadID];
} else {
dispatch_async(dispatch_get_main_queue(), ^{ [self cacheMainThreadID]; });
}
Copy link
Member

@armcknight armcknight Jan 8, 2024

Choose a reason for hiding this comment

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

We have a wrapper for this, i pushed commit 9fbdeb6 to use it

}
} else {
XCTAssertFalse(try XCTUnwrap(try XCTUnwrap(queueMetadata.first?.value)["label"] as? String).isEmpty)
XCTAssertFalse(try threadMetadata.values.compactMap { $0["name"] }.filter { try XCTUnwrap($0 as? String) == "main" }.isEmpty)
Copy link
Member

Choose a reason for hiding this comment

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

Nice, this probably should have been there before, but thanks for adding it 👍🏻

@armcknight
Copy link
Member

I logged the thread sanitizer warning in a new issue, I don't think it's related.

@indragiek indragiek merged commit 94d8eb3 into main Jan 9, 2024
69 of 70 checks passed
@indragiek indragiek deleted the indragiek/remove-queue-metadata branch January 9, 2024 02:04
philipphofmann pushed a commit that referenced this pull request Jan 10, 2024
* Remove dispatch queue metadata collection

* Hardcode "main" as the name of the main thread

* Format code

* Update CHANGELOG.md

* use thread wrapper main thread dispatch

---------

Co-authored-by: Sentry Github Bot <[email protected]>
Co-authored-by: Andrew McKnight <[email protected]>
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.

4 participants