Skip to content

Commit

Permalink
fix: App hang with race condition for tick counter (#3290)
Browse files Browse the repository at this point in the history
Thread sanitizer was complaining about a race condition in the ANR tracker.
Added atomic operations to avoid the race condition
  • Loading branch information
brustolin authored Oct 4, 2023
1 parent f1a6589 commit 3f6c30b
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Fixes

- App hang with race condition for tick counter (#3290)
- Remove "duplicate library" warning (#3312)

## 8.13.0
Expand Down
10 changes: 6 additions & 4 deletions Sources/Sentry/SentryANRTracker.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#import "SentryDispatchQueueWrapper.h"
#import "SentryLog.h"
#import "SentryThreadWrapper.h"
#import <stdatomic.h>

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -64,7 +65,7 @@ - (void)detectANRs
state = kSentryANRTrackerRunning;
}

__block NSInteger ticksSinceUiUpdate = 0;
__block atomic_int ticksSinceUiUpdate = 0;
__block BOOL reported = NO;

NSInteger reportThreshold = 5;
Expand All @@ -81,10 +82,10 @@ - (void)detectANRs
NSDate *blockDeadline = [[SentryDependencyContainer.sharedInstance.dateProvider date]
dateByAddingTimeInterval:self.timeoutInterval];

ticksSinceUiUpdate++;
atomic_fetch_add_explicit(&ticksSinceUiUpdate, 1, memory_order_relaxed);

[self.dispatchQueueWrapper dispatchAsyncOnMainQueue:^{
ticksSinceUiUpdate = 0;
atomic_store_explicit(&ticksSinceUiUpdate, 0, memory_order_relaxed);

if (reported) {
SENTRY_LOG_WARN(@"ANR stopped.");
Expand Down Expand Up @@ -115,7 +116,8 @@ - (void)detectANRs
continue;
}

if (ticksSinceUiUpdate >= reportThreshold && !reported) {
if (atomic_load_explicit(&ticksSinceUiUpdate, memory_order_relaxed) >= reportThreshold
&& !reported) {
reported = YES;

if (![self.crashWrapper isApplicationInForeground]) {
Expand Down
4 changes: 2 additions & 2 deletions Tests/SentryTests/PrivateSentrySDKOnlyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class PrivateSentrySDKOnlyTests: XCTestCase {
/**
* Smoke Tests profiling via PrivateSentrySDKOnly. Actual profiling unit tests are done elsewhere.
*/
func testProfilingStartAndCollect() {
func testProfilingStartAndCollect() throws {
let options = Options()
options.dsn = TestConstants.dsnAsString(username: "SentryFramesTrackingIntegrationTests")
let client = TestClient(options: options)
Expand All @@ -148,7 +148,7 @@ class PrivateSentrySDKOnlyTests: XCTestCase {
XCTAssertNotNil(profile?["frames"])
let transactionInfo = payload?["transaction"] as? NSDictionary
XCTAssertNotNil(transactionInfo)
XCTAssertGreaterThan(transactionInfo?["active_thread_id"] as! Int64, 0)
XCTAssertGreaterThan(try XCTUnwrap(transactionInfo?["active_thread_id"] as? Int64), 0)
}

func testProfilingDiscard() {
Expand Down

0 comments on commit 3f6c30b

Please sign in to comment.