fix(logging): Fix deadlock in log batcher #5684
2 issues
find-bugs: Found 2 issues (2 medium)
Medium
flush() method lacks re-entry guard, causing protection to be incorrectly reset - `sentry_sdk/_batcher.py:117-122`
The flush() method unconditionally sets self._active.flag = True and resets it to False in the finally block, without first checking if the flag was already set. If flush() is called while _flush_loop() is running on the same thread (which permanently sets _active.flag = True), the finally block will incorrectly reset the flag to False, defeating the deadlock protection. This could allow a subsequent add() call to proceed and attempt to acquire locks that are already held.
Re-entry flag not cleared on early return, permanently dropping all spans from thread - `sentry_sdk/_span_batcher.py:65-66`
When _ensure_thread() returns False or _flusher is None at lines 65-66, the method returns without clearing self._active.flag. Since the flag is set at line 63 before the try block that contains the finally to reset it, this early return path leaves the flag permanently True for the current thread. All subsequent add() calls from that thread will be silently discarded. The base class _batcher.py correctly places this check inside the try block (lines 94-96), ensuring the finally always runs.
Duration: 2m 2s · Tokens: 302.1k in / 6.4k out · Cost: $0.50 (+extraction: $0.00, +merge: $0.00, +fix_gate: $0.00)
Annotations
Check warning on line 122 in sentry_sdk/_batcher.py
sentry-warden / warden: find-bugs
flush() method lacks re-entry guard, causing protection to be incorrectly reset
The `flush()` method unconditionally sets `self._active.flag = True` and resets it to `False` in the finally block, without first checking if the flag was already set. If `flush()` is called while `_flush_loop()` is running on the same thread (which permanently sets `_active.flag = True`), the finally block will incorrectly reset the flag to `False`, defeating the deadlock protection. This could allow a subsequent `add()` call to proceed and attempt to acquire locks that are already held.
Check warning on line 66 in sentry_sdk/_span_batcher.py
sentry-warden / warden: find-bugs
Re-entry flag not cleared on early return, permanently dropping all spans from thread
When `_ensure_thread()` returns False or `_flusher is None` at lines 65-66, the method returns without clearing `self._active.flag`. Since the flag is set at line 63 **before** the `try` block that contains the `finally` to reset it, this early return path leaves the flag permanently True for the current thread. All subsequent `add()` calls from that thread will be silently discarded. The base class `_batcher.py` correctly places this check **inside** the `try` block (lines 94-96), ensuring the `finally` always runs.