You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Update — control experiment reframes this issue (read first)
The original framing ("native crashes lose symbolication and ProGuard deobfuscation") was too strong. A control experiment shows native symbolication and the uploaded symbols/sources were never broken:
I changed the sample's Native Crash to a genuine null-pointer deref inside a named C function (trigger_null_deref() in native-sample.cpp) instead of raise(SIGSEGV).
Onmain(no fix) the crash symbolicates fine: trigger_null_deref (native-sample.cpp:13) incl. the source line.
With the fix it also symbolicates. Same issue, same frame.
So the original "unsymbolicated/obfuscated native crash" was an artifact of the sample's raise(SIGSEGV)-from-JNI crash — a managed-origin crash whose tombstone stack is the ART/OAT managed chain with no app-native frame — not a symbolication or symbol-source failure.
What the merge actually does (genuine native crash, both TombstoneMerged, both symbolicate)
main: keeps the tombstone's full mixed stack — the symbolicated native crash frame plus the (obfuscated) managed call chain that led into native code.
⇒ For a real native crash the current PR is neutral-to-worse (loses call-chain context), not the clear win originally claimed. Recommend holding PR #5771 and reframing toward the deobfuscation gap below.
The real readability gap
Managed frames in a TombstoneMerged native event are not ProGuard-deobfuscated, because the event platform == "native". This affects:
Managed-origin crashes (e.g. raise() from JNI): the whole crashing stack is obfuscated ART/OAT frames — unreadable.
Genuine native crashes: the native crash frame resolves, but the surrounding managed call chain (d3.v.a … g6.f.a) stays obfuscated.
If those java-classifiable frames were deobfuscated (they carry the correct ProGuard image, e.g. c44ea147-…), the mixed stack would be the best of both worlds.
Mechanism (still accurate)
sentry-android-core/.../TombstoneIntegration.java, mergeNativeCrashes (~L287–320) overwrites the Native SDK event's exceptions/threads/debugMeta with the tombstone's. This is the "discards the NDK crashing thread" behavior — real, but per the control experiment it is not what makes native crashes unreadable.
raise()-from-JNI (the original repro): main → obfuscated managed stack; fix → degenerate native stack (raise + garbage). Neither useful — a synthetic-crash artifact.
Options
Deobfuscate managed frames in the merged native event (preferred) — makes main's mixed stack fully readable; strictly better than either current behavior.
Sample (sentry-samples-android), release + SAGP (-PuseSagp, uploadNativeSymbols=true, includeProguardMapping=true), io.sentry.tombstone.enable=true. Compare a raise(SIGSEGV) crash vs a real in-.so null-deref.
Not a server bug
sentry and symbolicator behave correctly (verified from raw event JSON).
Update — control experiment reframes this issue (read first)
The original framing ("native crashes lose symbolication and ProGuard deobfuscation") was too strong. A control experiment shows native symbolication and the uploaded symbols/sources were never broken:
trigger_null_deref()innative-sample.cpp) instead ofraise(SIGSEGV).main(no fix) the crash symbolicates fine:trigger_null_deref (native-sample.cpp:13)incl. the source line.So the original "unsymbolicated/obfuscated native crash" was an artifact of the sample's
raise(SIGSEGV)-from-JNI crash — a managed-origin crash whose tombstone stack is the ART/OAT managed chain with no app-native frame — not a symbolication or symbol-source failure.What the merge actually does (genuine native crash, both TombstoneMerged, both symbolicate)
⇒ For a real native crash the current PR is neutral-to-worse (loses call-chain context), not the clear win originally claimed. Recommend holding PR #5771 and reframing toward the deobfuscation gap below.
The real readability gap
Managed frames in a
TombstoneMergednative event are not ProGuard-deobfuscated, because the eventplatform == "native". This affects:raise()from JNI): the whole crashing stack is obfuscated ART/OAT frames — unreadable.d3.v.a…g6.f.a) stays obfuscated.If those java-classifiable frames were deobfuscated (they carry the correct ProGuard image, e.g.
c44ea147-…), the mixed stack would be the best of both worlds.Mechanism (still accurate)
sentry-android-core/.../TombstoneIntegration.java,mergeNativeCrashes(~L287–320) overwrites the Native SDK event'sexceptions/threads/debugMetawith the tombstone's. This is the "discards the NDK crashing thread" behavior — real, but per the control experiment it is not what makes native crashes unreadable.Evidence
Genuine null-deref (
trigger_null_deref), Pixel 10 / Android 17,TombstoneMerged:906e4e40…: Most-relevant frametrigger_null_deref (native-sample.cpp:13); full stack = obfuscated managed chain →trigger_null_deref.99a2e924…:<unknown>→<unknown>→trigger_null_deref (native-sample.cpp:13).raise()-from-JNI (the original repro): main → obfuscated managed stack; fix → degenerate native stack (raise+ garbage). Neither useful — a synthetic-crash artifact.Options
raise()-from-JNI case, and drops context for real native crashes.Repro
Sample (
sentry-samples-android), release + SAGP (-PuseSagp,uploadNativeSymbols=true,includeProguardMapping=true),io.sentry.tombstone.enable=true. Compare araise(SIGSEGV)crash vs a real in-.sonull-deref.Not a server bug
sentryandsymbolicatorbehave correctly (verified from raw event JSON).