Skip to content

Commit 7a98632

Browse files
fix: Race condition in ANRTrackerV1 (getsentry#5137)
Use an atomic_bool to fix race conditions for accessing reported in the ANRTrackerV1. Fixes getsentryGH-2508
1 parent 054f756 commit 7a98632

File tree

5 files changed

+51
-7
lines changed

5 files changed

+51
-7
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66

77
- Added ability to bring your own button for user feedback form display (#5107)
88

9+
### Fixes
10+
11+
- Race condition in ANRTrackerV1 (#5137)
12+
913
### Improvements
1014

1115
- More logging for Session Replay video info (#5132)

Sentry.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
6205CF262D549D8A001E6049 /* SentryDateCodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6205CF252D549D8A001E6049 /* SentryDateCodableTests.swift */; };
9090
621AE74B2C626C230012E730 /* SentryANRTrackerV2.h in Headers */ = {isa = PBXBuildFile; fileRef = 621AE74A2C626C230012E730 /* SentryANRTrackerV2.h */; };
9191
621AE74D2C626C510012E730 /* SentryANRTrackerV2.m in Sources */ = {isa = PBXBuildFile; fileRef = 621AE74C2C626C510012E730 /* SentryANRTrackerV2.m */; };
92+
621D22012DBB7E09006F9C48 /* SentryANRTrackerV1IntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621D22002DBB7E09006F9C48 /* SentryANRTrackerV1IntegrationTests.swift */; };
9293
621D9F2F2B9B0320003D94DE /* SentryCurrentDateProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621D9F2E2B9B0320003D94DE /* SentryCurrentDateProvider.swift */; };
9394
621F61F12BEA073A005E654F /* SentryEnabledFeaturesBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621F61F02BEA073A005E654F /* SentryEnabledFeaturesBuilder.swift */; };
9495
62212B872D520CB00062C2FA /* SentryEventCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62212B862D520CB00062C2FA /* SentryEventCodable.swift */; };
@@ -1173,6 +1174,7 @@
11731174
621AE74A2C626C230012E730 /* SentryANRTrackerV2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentryANRTrackerV2.h; path = include/SentryANRTrackerV2.h; sourceTree = "<group>"; };
11741175
621AE74C2C626C510012E730 /* SentryANRTrackerV2.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentryANRTrackerV2.m; sourceTree = "<group>"; };
11751176
621AE74E2C626CF70012E730 /* SentryANRTrackerV2Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryANRTrackerV2Tests.swift; sourceTree = "<group>"; };
1177+
621D22002DBB7E09006F9C48 /* SentryANRTrackerV1IntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryANRTrackerV1IntegrationTests.swift; sourceTree = "<group>"; };
11761178
621D9F2E2B9B0320003D94DE /* SentryCurrentDateProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryCurrentDateProvider.swift; sourceTree = "<group>"; };
11771179
621F61F02BEA073A005E654F /* SentryEnabledFeaturesBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryEnabledFeaturesBuilder.swift; sourceTree = "<group>"; };
11781180
62212B862D520CB00062C2FA /* SentryEventCodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryEventCodable.swift; sourceTree = "<group>"; };
@@ -3095,6 +3097,7 @@
30953097
isa = PBXGroup;
30963098
children = (
30973099
7B2A70D727D5F07F008B0D15 /* SentryANRTrackerV1Tests.swift */,
3100+
621D22002DBB7E09006F9C48 /* SentryANRTrackerV1IntegrationTests.swift */,
30983101
621AE74E2C626CF70012E730 /* SentryANRTrackerV2Tests.swift */,
30993102
7BFA69F527E0840400233199 /* SentryANRTrackingIntegrationTests.swift */,
31003103
623E16C22D6C57C000CF1625 /* SentryANRTypeTests.swift */,
@@ -5523,6 +5526,7 @@
55235526
84EB21962BF01CEA00EDDA28 /* SentryCrashInstallationTests.swift in Sources */,
55245527
7BFE7A0A27A1B6B000D2B66E /* SentryWatchdogTerminationsIntegrationTests.swift in Sources */,
55255528
D8292D7D2A39A027009872F7 /* UrlSanitizedTests.swift in Sources */,
5529+
621D22012DBB7E09006F9C48 /* SentryANRTrackerV1IntegrationTests.swift in Sources */,
55265530
7BA61CAF247BBF3C00C130A8 /* SentryDebugImageProviderTests.swift in Sources */,
55275531
7BB7E7C729267A28004BF96B /* EmptyIntegration.swift in Sources */,
55285532
7B965728268321CD00C66E25 /* SentryCrashScopeObserverTests.swift in Sources */,

Sources/Sentry/SentryANRTrackerV1.m

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ - (void)detectANRs
6565
}
6666

6767
__block atomic_int ticksSinceUiUpdate = 0;
68-
__block BOOL reported = NO;
68+
__block atomic_bool reported = false;
6969

7070
NSInteger reportThreshold = 5;
7171
NSTimeInterval sleepInterval = self.timeoutInterval / reportThreshold;
@@ -88,7 +88,8 @@ - (void)detectANRs
8888
[self.dispatchQueueWrapper dispatchAsyncOnMainQueue:^{
8989
atomic_store_explicit(&ticksSinceUiUpdate, 0, memory_order_relaxed);
9090

91-
if (reported) {
91+
bool isReported = atomic_load_explicit(&reported, memory_order_relaxed);
92+
if (isReported) {
9293
SENTRY_LOG_WARN(@"ANR stopped.");
9394

9495
// The ANR stopped, don't block the main thread with calling ANRStopped listeners.
@@ -99,7 +100,7 @@ - (void)detectANRs
99100
[self.dispatchQueueWrapper dispatchAsyncWithBlock:^{ [self ANRStopped]; }];
100101
}
101102

102-
reported = NO;
103+
atomic_store_explicit(&reported, false, memory_order_relaxed);
103104
}];
104105

105106
[self.threadWrapper sleepForTimeInterval:sleepInterval];
@@ -116,9 +117,12 @@ - (void)detectANRs
116117
continue;
117118
}
118119

119-
if (atomic_load_explicit(&ticksSinceUiUpdate, memory_order_relaxed) >= reportThreshold
120-
&& !reported) {
121-
reported = YES;
120+
bool isReported = atomic_load_explicit(&reported, memory_order_relaxed);
121+
int currentTicks = atomic_load_explicit(&ticksSinceUiUpdate, memory_order_relaxed);
122+
123+
if (currentTicks >= reportThreshold && !isReported) {
124+
125+
atomic_store_explicit(&reported, true, memory_order_relaxed);
122126

123127
if (![self.crashWrapper isApplicationInForeground]) {
124128
SENTRY_LOG_DEBUG(@"Ignoring ANR because the app is in the background");
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
@testable import Sentry
2+
import XCTest
3+
4+
#if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst)
5+
6+
final class SentryANRTrackerV1IntegrationTests: XCTestCase {
7+
8+
/// This uses an actual dispatch queue and a thread wrapper so the thread sanitizer can find threading problems in the implementation.
9+
/// It has no assertions on purpose. To test the thread safety locally, enable the thread sanitizer in the test plan.
10+
func testWithActualDispatchQueueAndThreadWrapper() {
11+
let expectation = XCTestExpectation(description: "ANR Tracker")
12+
13+
let listener = SentryANRTrackerTestDelegate()
14+
15+
let anrTracker: SentryANRTracker = SentryANRTrackerV1(
16+
timeoutInterval: 0.01,
17+
crashWrapper: TestSentryCrashWrapper.sharedInstance(),
18+
dispatchQueueWrapper: SentryDispatchQueueWrapper(),
19+
threadWrapper: SentryThreadWrapper())
20+
21+
anrTracker.add(listener: listener)
22+
23+
DispatchQueue.global().asyncAfter(deadline: .now() + 2.0) {
24+
anrTracker.clear()
25+
expectation.fulfill()
26+
}
27+
28+
wait(for: [expectation], timeout: 5.0)
29+
}
30+
}
31+
32+
#endif // os(iOS) || os(tvOS) || targetEnvironment(macCatalyst)

Tests/SentryTests/Integrations/ANR/SentryANRTrackerV1Tests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ class SentryANRTrackerV1Tests: XCTestCase, SentryANRTrackerDelegate {
208208
// and finish multiple times. Most importantly, the code covers every start with one finish.
209209
XCTAssertEqual(fixture.threadWrapper.threadStartedInvocations.count, fixture.threadWrapper.threadFinishedInvocations.count, "The number of started and finished threads should be equal, otherwise the ANR tracker could run.")
210210
}
211-
211+
212212
// swiftlint:disable test_case_accessibility
213213
// Protocl implementation can't be private
214214

0 commit comments

Comments
 (0)