Skip to content

feat: Support reading .NET 11 Android assembly stores - #5577

Open
jamescrosswell wants to merge 30 commits into
version7from
feat/assemblystore-index-sizing
Open

jamescrosswell wants to merge 30 commits into
version7from
feat/assemblystore-index-sizing

Conversation

@jamescrosswell

@jamescrosswell jamescrosswell commented Sep 14, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #5575 (itself stacked on #5574) — this PR's diff is only the index-entry sizing change. Together the three PRs make .NET 11 Android APKs readable for symbolication.

Closes #5454

Summary

  • StoreReader.Prepare() inferred the index entry layout from the ABI bitness (64-bit hash on 64-bit ABIs), plus a compile-time #if NET10_0_OR_GREATER for the ignore byte. But upstream's generator picks the hash width by runtime: CoreCLR writes 32-bit CRC32 name hashes on every ABI, MonoVM writes xxHash sized by bitness (AssemblyStoreGenerator.cs). A .NET 11 x86_64 store has 60 entries in 540 bytes — 9 bytes each — so we read past the index and Prepare() threw EndOfStreamException.
  • The entry size is now index_size / index_entry_count, as upstream does. Only the two v3/v4 layouts (9 and 13 bytes) are accepted; anything else, or a size that doesn't divide evenly, throws as a corrupt index. Upstream's v2 layouts are intentionally not ported (v2 support was dropped in feat: add support for .NET 11 preview 7 #5529).
  • The dead #if NET10_0_OR_GREATER branch is gone.
  • Debug images on CoreCLR. Reading the store isn't enough on its own: on .NET 11 Module.FullyQualifiedName is <Unknown> for assemblies loaded from the store, so DebugStackTrace returned before ever calling the assembly reader and events had no debug_meta. When an assembly reader is configured it now falls back to Module.ScopeName (the file name the store is indexed by). Modules that do have a location still pass FullyQualifiedName, so Mono behaviour is unchanged.
  • ATTRIBUTION.txt now records the v3 and v4 upstream sync points, not just the original baseline.

Tests

  • The net11.0 APK tests in AndroidAssemblyReaderTests are re-enabled — 29 run on net11.0 (previously 9); the 8 still skipped are the Mono AOT permutations .NET 11 can't produce.
  • CreatesCorrectArchiveReader now expects an AndroidAssemblyStoreReader on .NET 11: the AndroidUseAssemblyStore=false APK contains only libassembly-store.so, because the CoreCLR host has no non-store fallback since dotnet/android#12033.
  • StoreReaderTests gains a CoreCLR-style v4 64-bit store with 32-bit hashes, plus corrupt-index cases (the 12-byte v2 layout and a non-divisible index size).

Example

Symbolicated stack trace from a .NET 11 app

image

Notes

  • Carries two small follow-ups to review comments on the merged feat: Support Zstandard-compressed assemblies on Android (.NET 11) #5575: ArchiveUtils no longer allocates the output buffer before failing on a Zstandard payload it can't decompress, and the tests share ArchiveUtils' magic constants.
  • Verified end to end with Sentry.Samples.Android (Release, net11.0-android37.0, arm64 emulator, API 37): the SDK reads the app assembly from the Zstandard-compressed v4 store, the captured event carries a pe_dotnet debug image with the PDB's debug ID, frames have addr_mode/function_id, and the matching PDB is uploaded by the build.
  • That only holds with the default trim mode. With AndroidLinkMode=full (which the Android sample sets) the trimmer rewrites app assemblies, and the Android SDK forces TrimmerRemoveSymbols=true in Release, so the packaged assemblies have no debug ID to report. That's independent of this PR and of .NET 11.
  • Removing the skips also re-enables these tests in the Android device test run, which reads the running app's own .NET 11 APK — that's the first on-device coverage of the whole v4 + Zstandard path.
  • The ELF _assembly_store symbol item was dropped from Port upstream AssemblyStore reader changes: v4/CoreCLR format, _assembly_store symbol, index-entry sizing (next major) #5454 as unnecessary — see this comment.

🤖 Generated with Claude Code

jamescrosswell and others added 13 commits September 14, 2026 12:42
…eader

v4 stores (CoreCLR, .NET 11) add a content_id field to the header, so the
index starts 8 bytes later. Header.NativeSize is now derived from the format
number rather than being a constant.

Refs #5454

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
.NET 11 compresses assemblies with Zstandard (XAZS) instead of LZ4 (XALZ).
The 12-byte header is unchanged, so only the magic and the codec differ.
Zstandard uses the BCL ZstandardDecoder on net11.0; the net10.0 build
throws NotSupportedException, since only .NET 11 apps produce XAZS.

Refs #5346

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The index entry layout was inferred from the ABI bitness (plus a compile-time
TFM check for the ignore flag). CoreCLR v4 stores use 32-bit CRC32 name
hashes on every ABI, so on 64-bit ABIs the reader read the index 4 bytes per
entry too far and failed in Prepare(). The entry size is now
index_size / index_entry_count, and anything other than the two v3/v4 layouts
is rejected as corrupt.

With this, .NET 11 APKs are readable, so the net11 APK tests are re-enabled.

Refs #5454

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.00000% with 5 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (version7@aa02031). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/Sentry/Internal/DebugStackTrace.cs 62.50% 2 Missing and 1 partial ⚠️
...rc/Sentry.Android.AssemblyReader/V2/StoreReader.cs 81.81% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             version7    #5577   +/-   ##
===========================================
  Coverage            ?   74.80%           
===========================================
  Files               ?      515           
  Lines               ?    18919           
  Branches            ?     3693           
===========================================
  Hits                ?    14153           
  Misses              ?     3890           
  Partials            ?      876           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

jamescrosswell and others added 2 commits September 14, 2026 18:38
Assembly.Location is empty on Android, so the static initializer threw and
every test in the class failed on the device runs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jamescrosswell
jamescrosswell added this pull request to stack #5581 September 15, 2026 03:49
jamescrosswell and others added 5 commits September 15, 2026 16:52
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
On .NET 11 (CoreCLR) Android, assemblies loaded from the assembly store report
Module.FullyQualifiedName as <Unknown>, so DebugStackTrace bailed out before
calling the assembly reader and events had no debug images. When an assembly
reader is configured, fall back to Module.ScopeName, which is the file name
the store is indexed by.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…sizing

Also trims comments.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jamescrosswell and others added 3 commits September 16, 2026 13:34
.NET 11 compresses assemblies with Zstandard (XAZS) instead of LZ4 (XALZ).
The 12-byte header is unchanged, so only the magic and the codec differ.
Zstandard uses the BCL ZstandardDecoder on net11.0; the net10.0 build
throws NotSupportedException, since only .NET 11 apps produce XAZS.

Refs #5346

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Assembly.Location is empty on Android, so the static initializer threw and
every test in the class failed on the device runs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jamescrosswell and others added 3 commits September 16, 2026 16:33
…at/assemblystore-index-sizing

# Conflicts:
#	src/Sentry.Android.AssemblyReader/V2/StoreReader.cs
#	test/Sentry.Android.AssemblyReader.Tests/StoreReaderTests.cs
Magic numbers become internal constants the tests share, and the
DecompressZstandard helper is inlined - its assemblyName parameter was
unused on .NET 11.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Base automatically changed from feat/assemblystore-zstd to version7 September 18, 2026 01:44
Comment thread test/Sentry.Android.AssemblyReader.Tests/ArchiveUtilsTests.cs Outdated
Comment thread test/Sentry.Android.AssemblyReader.Tests/StoreReaderTests.cs Outdated
Comment thread test/Sentry.Android.AssemblyReader.Tests/StoreReaderTests.cs Outdated
Comment thread test/Sentry.Android.AssemblyReader.Tests/StoreReaderTests.cs Outdated

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This condition makes it so that var outputStream = new MemoryStream(decompressedLength); on line 53 never gets used. Would be nice to not initialize on this NET10 or lower.

Comment thread src/Sentry/Internal/DebugStackTrace.cs Outdated
jamescrosswell and others added 3 commits September 24, 2026 11:07
Names the magic values in the test fixtures, shares the format number mask
with the reader, skips the output buffer allocation when a Zstandard payload
can't be decompressed, and logs why reading an assembly failed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
dotnet/android#12780 removed the opt-in decompression cache and restored
assembly store format version 3 for CoreCLR, so v4 only ever existed in
.NET 11 previews. Correct the vendored file headers and ATTRIBUTION,
which claimed v4 ships in .NET 11.

.NET 11 GA emits v3 with CoreCLR's 32-bit CRC32 name hashes on 64-bit
ABIs - a shape the synthetic store tests did not cover. Add it.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: medium PR risk score: medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants