Skip to content

Review feedback

54b3d45
Select commit
Loading
Failed to load commit list.
Draft

feat: Auto-create traces for MAUI navigation events #5111

Review feedback
54b3d45
Select commit
Loading
Failed to load commit list.
@sentry/warden / warden completed Apr 7, 2026 in 13m 52s

3 issues

Medium

ChildSpanFinished may throw ObjectDisposedException due to race with Finish() - `src/Sentry/TransactionTracer.cs:336`

The ChildSpanFinished method checks _hasFinished before calling _idleTimer?.Start(), but there's a race condition: Finish() could be invoked concurrently between the check and the Start() call. Finish() disposes the timer after setting _hasFinished, so Start() would then throw ObjectDisposedException. The similar method ResetIdleTimeout (line 395-403) explicitly handles this race with a try-catch, but ChildSpanFinished does not. This could cause runtime exceptions when a span finishes while the transaction is concurrently finishing.

Race condition: _currentTransaction field accessed without synchronization in singleton service - `src/Sentry.Maui/Internal/MauiEventsBinder.cs:19`

The _currentTransaction field is added to a singleton MauiEventsBinder and accessed from multiple event handlers (OnShellOnNavigating, OnApplicationOnModalPushed, OnApplicationOnModalPopped, OnWindowOnStopped) without thread synchronization. These handlers can fire concurrently from different navigation events. The StartNavigationTransaction method has a TOCTOU race where it checks _currentTransaction is { IsFinished: false } and then conditionally finishes or resets it - another thread could modify _currentTransaction between the check and the subsequent operations.

ChildSpanFinished can throw ObjectDisposedException due to race condition with Finish - `src/Sentry/TransactionTracer.cs:336`

The new ChildSpanFinished() method checks _hasFinished and then calls _idleTimer?.Start(), but the timer can be disposed by a concurrent Finish() call between these operations. This is the same race condition that ResetIdleTimeout() handles with a try-catch block, but ChildSpanFinished() lacks this protection. When SpanTracer.Finish() calls Transaction.ChildSpanFinished(), if TransactionTracer.Finish() is called concurrently, an unhandled ObjectDisposedException will propagate up to the caller.

4 skills analyzed
Skill Findings Duration Cost
code-review 1 6m 36s $7.33
find-bugs 2 13m 41s $11.16
gha-security-review 0 7m 58s $2.03
security-review 0 2m 22s $3.02

Duration: 30m 36s · Tokens: 14.6M in / 163.7k out · Cost: $23.57 (+extraction: $0.02, +dedup: $0.01, +merge: $0.00)