fix(logcat): Add re-entrancy guard to SentryLogcatAdapter#5734
Open
sentry[bot] wants to merge 5 commits into
Open
fix(logcat): Add re-entrancy guard to SentryLogcatAdapter#5734sentry[bot] wants to merge 5 commits into
sentry[bot] wants to merge 5 commits into
Conversation
Author
📲 Install BuildsAndroid
|
Contributor
Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| d364ace | 382.77 ms | 443.21 ms | 60.44 ms |
| 4c04bb8 | 333.16 ms | 408.16 ms | 75.00 ms |
| bb0ff41 | 344.70 ms | 413.82 ms | 69.12 ms |
| 91bb874 | 314.47 ms | 440.00 ms | 125.53 ms |
| bdbe1f4 | 380.66 ms | 464.44 ms | 83.78 ms |
| 8687935 | 294.00 ms | 304.02 ms | 10.02 ms |
| eb95ded | 317.51 ms | 369.08 ms | 51.57 ms |
| b936425 | 302.69 ms | 372.86 ms | 70.17 ms |
| d15471f | 342.08 ms | 415.44 ms | 73.35 ms |
| 5b66efd | 308.67 ms | 363.85 ms | 55.18 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| d364ace | 1.58 MiB | 2.11 MiB | 539.75 KiB |
| 4c04bb8 | 0 B | 0 B | 0 B |
| bb0ff41 | 0 B | 0 B | 0 B |
| 91bb874 | 1.58 MiB | 2.13 MiB | 559.07 KiB |
| bdbe1f4 | 1.58 MiB | 2.11 MiB | 538.88 KiB |
| 8687935 | 1.58 MiB | 2.19 MiB | 619.17 KiB |
| eb95ded | 0 B | 0 B | 0 B |
| b936425 | 0 B | 0 B | 0 B |
| d15471f | 1.58 MiB | 2.13 MiB | 559.54 KiB |
| 5b66efd | 1.58 MiB | 2.13 MiB | 559.07 KiB |
Add a regression test reproducing SDK-CRASHES-JAVA-3T3H: a beforeBreadcrumb callback that logs re-enters SentryLogcatAdapter while a Logcat breadcrumb is being added, which recurses to a StackOverflowError without the guard. Also correct the guard's Javadoc. The recursion is not caused by the plugin transforming AndroidLogger inside the SDK (io.sentry.* classes are excluded from logcat instrumentation); it is caused by app code reachable during breadcrumb processing calling a rewritten Log.* method. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The guard only covered addAsBreadcrumb(). The public methods also call addAsLog() sequentially, which could recurse the same way: a beforeSendLog callback that logs re-enters SentryLogcatAdapter while a Logcat log is being sent, leading to a StackOverflowError. Share a single thread-local guard across both addAsBreadcrumb() and addAsLog() so any re-entrant capture on the same thread is a no-op, while the real Log.* call is left untouched. Add a regression test for the logs path and use Google Truth for the new assertions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jul 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📜 Description
Fixes a
StackOverflowError(SDK-CRASHES-JAVA-3T3H) caused by infinite recursion inSentryLogcatAdapterwhen the Sentry Android Gradle Plugin's logcat instrumentation is enabled.💡 Motivation and Context
The Sentry Android Gradle Plugin rewrites
android.util.Log.*calls in the app's own code toSentryLogcatAdapter.*. SDK classes underio.sentry.*are explicitly excluded from this rewrite (seeLogcat.isInstrumentable/isSentryClassin the plugin), soAndroidLoggerand the adapter itself are not transformed.The recursion instead happens when code that runs while a Logcat breadcrumb or log is being captured itself calls a rewritten
Log.*method. The most common paths are an appbeforeBreadcrumborbeforeSendLogcallback (or anything they invoke) that logs:SentryLogcatAdapter.w()→addAsBreadcrumb()/addAsLog()beforeBreadcrumb/beforeSendLogcallback runsLog.w(...), which the plugin rewrote toSentryLogcatAdapter.w(...)StackOverflowErrorSolution
A single
ThreadLocal<Boolean>re-entrancy guard (isCapturing) wraps both the breadcrumb path (addAsBreadcrumb()) and the logs path (addAsLog()). If either is re-entered on the same thread while a capture is already in progress, the nested call returns early, breaking the cycle. The realLog.*call is left outside the guard so the app's actual logcat output is preserved.This fix lives in the SDK (not the plugin) because the recursion is a runtime cycle through arbitrary app code reachable during breadcrumb/log processing — something the plugin cannot detect statically.
💚 How did you test it?
Added two regression tests (using Google Truth) that install a
beforeBreadcrumb/beforeSendLogcallback which re-entersSentryLogcatAdapter. Each was verified to fail with aStackOverflowErrorwithout its guard and pass with it, recording exactly one breadcrumb / log.Fixes SDK-CRASHES-JAVA-3T3H
JAVA-637
Triggered by @runningcode