[r8-obfuscation] Add PE metadata rebuild substrate - #12629
Conversation
e83dcaa to
58ac474
Compare
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
fdb7393 to
311a3bf
Compare
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Use the executing runtime version in metadata fixtures so rebuilt images load across target frameworks. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
311a3bf to
cc7f216
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
MetadataEncoding.ReadCompressedInteger does not guard against negative offsets, causing unintended IndexOutOfRangeException instead of a controlled rewrite failure.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review tier: Lite
Findings: 1
New issues introduced by this change (2)
| Severity | Finding |
|---|---|
src/Xamarin.Android.Build.Tasks/Utilities/JniRemapping/MetadataEncoding.cs — ❌ error Bug — ReadCompressedInteger allows a negative offset, which will throw… |
|
src/Xamarin.Android.Build.Tasks/Utilities/JniRemapping/AssemblyRebuilder.cs — 💡 suggestion Formatting / Conventions — Prefer [] over Array.Empty<T>() in this repo to… |
What changed in this PR
Adds the internal PE + ECMA-335 metadata rebuild substrate under Xamarin.Android.Build.Tasks to support later R8/JNI name-rewriting layers, while keeping this layer behaviorally inert (no build integration yet). The new utilities focus on rebuilding managed assemblies without moving metadata tokens, while re-emitting method bodies, resources, debug directory data, native resources, and FieldRVA mapped data, plus adding targeted validation against malformed inputs.
Changes:
- Introduces
AssemblyRebuilderand supporting primitives for token-preserving PE/metadata reconstruction, IL scanning, and selective heap/value rewrites. - Adds low-level helpers for raw metadata column access, compressed integer encoding/decoding,
FieldRVAdecoding/relayout, and Win32 resource section relocation. - Adds focused NUnit coverage with a fixture generator to validate native resources,
FieldRVAbehaviors, IL scanning validation, and strong-name signature handling.
| File | Description |
|---|---|
| src/Xamarin.Android.Build.Tasks/Utilities/JniRemapping/AssemblyRebuilder.cs | Core token-preserving managed PE rebuild implementation (IL, resources, debug/native resources, FieldRVA). |
| src/Xamarin.Android.Build.Tasks/Utilities/JniRemapping/FieldRvaTable.cs | Reads and interprets FieldRVA rows and mapped data, including typemap-style UTF-8 payload detection. |
| src/Xamarin.Android.Build.Tasks/Utilities/JniRemapping/NativeResourceSectionCopier.cs | Copies and relocates .rsrc directory data for rebuilt PEs with validation. |
| src/Xamarin.Android.Build.Tasks/Utilities/JniRemapping/MetadataRawColumns.cs | Reads metadata table columns not exposed by MetadataReader (e.g., ImplMap.MemberForwarded). |
| src/Xamarin.Android.Build.Tasks/Utilities/JniRemapping/MetadataEncoding.cs | ECMA-335 compressed integer encode/decode helper used for manual blob rewriting. |
| src/Xamarin.Android.Build.Tasks/Utilities/JniRemapping/JniRewritePlan.cs | Holds per-use-site rewrite decisions for attributes, ldstr, and UTF-8 FieldRVA data. |
| src/Xamarin.Android.Build.Tasks/Utilities/JniRemapping/JniRewriteException.cs | Dedicated exception type for rewrite failures and validation errors. |
| src/Xamarin.Android.Build.Tasks/Utilities/JniRemapping/IlOpcodeTable.cs | Minimal operand-size table enabling IL walks without a full IL parser. |
| src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/JniRemapping/AssemblyRebuilderTests.cs | End-to-end tests for rebuild invariants (FieldRVA/resources, IL, strong-name space, validation). |
| src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/JniRemapping/NativeResourceSectionCopierTests.cs | Validates .rsrc copying/relocation and malformed directory rejection. |
| src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/JniRemapping/JniFixtureBuilder.cs | Produces minimal managed PE fixtures to exercise the rebuilder without external binaries. |
Detach rewritten mapped fields from overlapping source storage so shorter replacements cannot corrupt aliased fields. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Validate negative compressed-integer offsets and use the repository empty-array convention when rebuilding method bodies. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Validate malformed resource and strong-name directory values through the rewrite error contract, and emit MethodSemantics rows in HasSemantics coded-index order. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
/review |
|
✅ Android PR Reviewer completed successfully!
|
There was a problem hiding this comment.
The table-by-table token preservation and malformed-metadata coverage are strong, and all 44 CI checks are green. Before merge, the rebuild needs to reject or preserve non-MethodDef entry points; I also called out two validation gaps that can silently produce altered or inconsistent output for malformed metadata.
Generated by Android PR Reviewer for #12629 · gpt56 · 227.7 AIC · ⌖ 9.02 AIC · ⊞ 25.7K
Comment /review to run again
Validate colliding synthetic UTF-8 types before reuse and reject half-populated native resource directories. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |


Summary
This is layer 2 of 6 in the replacement stack for PR #12575. It adds the internal PE and metadata reconstruction substrate required by later JNI name-rewriting layers, without enabling any build behavior.
FieldRVAmapped data, including ranges from different PE sections.FieldRVAbacking data by relocating rewritten fields instead of modifying shared storage.HasSemanticscoded-index order.ImplMaprows instead of silently dropping metadata.FieldRVAreplacements, aliased mapped fields, event/property accessor preservation, per-use#USsplitting, and strong-name signature preservation directly throughAssemblyRebuilder.Scope
This layer intentionally does not add JNI-specific planning or attribute/
ldstrorchestration, the assembly-rewriter facade, theRewriteJniNamesForR8MSBuild task, typemap rewrite behavior, CoreCLR/NativeAOT target integration, or documentation. Those surfaces belong to later stack layers.Validation
./dotnet-local.sh build src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj -c Debug -v:minimal --no-restore./dotnet-local.sh test bin/TestDebug/net10.0/Xamarin.Android.Build.Tests.dll --filter 'FullyQualifiedName~NativeResourceSectionCopierTests|FullyQualifiedName~AssemblyRebuilderTests'RewrittenAssemblyLoadsAndRunsInTheRuntimeresult: 1 passed, 0 failed.Related to #12535
Depends on #12628