[PR #6989] [MERGED] fix(il2cpp): link arm64 builds whose registrations were inlined #7552

Closed
opened 2026-11-03 13:38:39 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/6989
Author: @8rulerstar
Created: 10/24/2026
Status: ✅ Merged
Merged: 10/24/2026
Merged by: @morluto

Base: main ← Head: fix/il2cpp-lto-registrations


📝 Commits (10+)

  • f82a79f fix(il2cpp): accept arm64 module arrays loaded through adrp/add pairs
  • abf8a86 fix(il2cpp): name the matched instruction form in inferred module-array limits
  • 24451f2 fix(il2cpp): accept type tables loaded without a static MetadataRegistration
  • 0d023ad test(il2cpp): pin adrp page deltas, register pairing and type-record shape
  • f2b027e refactor(il2cpp): share Il2CppType kind decoding and document type-table bounds
  • 00235dc chore: merge latest main into exp/il2cpp-lto-port
  • 23da1dd fix(il2cpp): refuse generic instances when the type table was inferred
  • 090ddc8 fix(il2cpp): fail closed when an inferred type table is not unique
  • a6e2c82 fix(il2cpp): keep the type-table fallback cheap and its refusals exact
  • 39480ba fix(il2cpp): judge type-table slots by their loaded value

📊 Changes

17 files changed (+1006 additions, -68 deletions)

View changed files

📝 docs/il2cpp-metadata.md (+29 -4)
📝 src/application/il2cpp/Il2cppMetadataService.test.ts (+9 -5)
📝 src/application/il2cpp/Il2cppMetadataService.ts (+2 -1)
📝 src/contracts/il2cpp/il2cppToolContracts.ts (+1 -1)
📝 src/domain/analysisView/il2cppMetadataView.test.ts (+18 -0)
📝 src/domain/analysisView/il2cppMetadataView.ts (+5 -0)
📝 src/domain/il2cpp/il2cppMetadata.ts (+6 -2)
📝 src/il2cpp/Il2cppBinaryFile.ts (+26 -3)
📝 src/il2cpp/Il2cppBinaryGenerics.ts (+7 -1)
📝 src/il2cpp/Il2cppBinaryImage.ts (+19 -34)
📝 src/il2cpp/Il2cppBinaryRegistration.ts (+249 -9)
📝 src/il2cpp/Il2cppBinaryTypes.ts (+12 -2)
📝 src/il2cpp/Il2cppMetadataProvider.ts (+12 -2)
📝 tests/boundary/il2cpp/il2cppBinaryFile.test.ts (+416 -0)
📝 tests/boundary/il2cpp/il2cppMappingOwnership.test.ts (+39 -1)
📝 tests/boundary/il2cpp/il2cppMetadataProvider.test.ts (+93 -0)
📝 tests/fixtures/il2cpp/binary.ts (+63 -3)

📄 Description

Follow-up to #5327: this extends its inlined module-array fallback to arm64 and adds a matching fallback for the type table.

Summary

A Unity IL2CPP build in the Master configuration (link-time optimisation) can inline both registration structs, so the binary keeps neither g_CodeRegistration nor g_MetadataRegistration as data. On arm64 such a build stopped at code-registration-not-found, and after that at metadata-registration-not-found. This change lets it link when exactly one module array and exactly one type table are loaded by code, marks both as inferred, and keeps the existing reasons otherwise. Builds with static registrations are unchanged. Related: #3607.

Problem and expected behavior

Trigger: a macOS arm64 IL2CPP Master build of Unity 2022.3.62f3 (metadata v31) fails with code-registration-not-found. Expected: link its methods and type rows, labelled inferred, and fail closed whenever the code-loaded candidate is not unique.

Change and scope

Both fallbacks live in src/il2cpp/Il2cppBinaryRegistration.ts and run only on x86-64 or arm64 when the static search found nothing.

  • Module array: the existing fallback also follows an aligned, adjacent adrp xd + add xd, xd, #imm12 pair (same register, not register 31). The x86-64 scan is unchanged.
  • Type table (the only MetadataRegistration field linking reads): taken from a run of pointers to Il2CppType-shaped records only if exactly one run in the image is long enough for every referenced type index, it starts and ends inside its mapping, no slot or record field the loader binds or leaves unresolved bounds it, and code loads its start. A static record whose two type-definition counts match stops the fallback even if its other fields are unusable.
  • Output: types_field becomes nullable like code_gen_modules_field; types_count is then the run length. Each fallback adds its own limitation and view unknown. --generic-instances on an inferred type table fails as generic-methods-unsupported.
  • The x86-64 type-table form is included because the reference scan is shared with the existing x86-64 module-array fallback; it is checked on fixtures only.
  • Not included: other MetadataRegistration fields, ldr/GOT or non-adjacent address forms, arm64e, chained fixups.

Follow the contribution scope. Scope decision: not applicable (static reading inside the existing IL2CPP provider; no new provider or capability).

Contract and boundary impact

  • Semantic owner and earliest changed stage: Il2cppBinaryRegistration.ts (registration search); Il2CppType kind decoding is shared from Il2cppBinaryTypes.ts.
  • Contribution scope fit and linked maintainer decision: existing IL2CPP linking; not applicable.
  • CLI and MCP/tool-catalog contract: inspect_il2cpp_metadata description names the x86-64/arm64 fallback and that generic instances need both static registrations. No new input field or failure reason; binary.types_field becomes nullable.
  • Provider, bridge, target-format, or platform compatibility: x86-64 and arm64 Mach-O, PE and ELF images; builds with static registrations take the old path.
  • Evidence, artifact, provenance, or reconstruction contract: fallback links are inferred, with separate limitations and view unknowns for the module array and the type table.
  • Target selection, authority, upstream behavior, and cleanup details (if applicable): not applicable.
  • Generated metadata (docs/public/product-catalog.json), package, or installation impact: none.

Expected effects:

  • Read existing files or captured data.
  • Launch or attach to a process.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

  • Tests added or updated: tests/boundary/il2cpp/il2cppBinaryFile.test.ts covers the arm64 module array and type table (later and earlier ADRP pages), the x86-64 type table, generic instances refused on an inferred table, the not-found messages, and fail-closed cases: interior reference, run extended before or reaching past a mapping boundary, a second long-enough run (loaded or not), a static record with matching counts but an unusable table, short and one-short runs, unassigned (0x17, 0x1a) and out-of-range kinds, a value-type definition past the metadata, mismatched or register-31 ADRP/ADD pairs, and a dyld-bound table slot or record kind word whose placeholder must not change the outcome. il2cppMetadataProvider.test.ts covers the limitation per instruction form.

  • Base reproduction or other evidence: executed. With origin/main's Il2cppBinaryRegistration.ts (ddde7276c) swapped into this branch, these two test files give 159 passed / 11 failed; the failures are exactly the positive fallback cases. Self-built samples (Unity, not redistributed), linked with origin/main and this head:

    Sample origin/main This head
    2022.3.62f3 macOS arm64 Master code-registration-not-found links
    8 builds with static registrations: 2019.4.41f2 macOS x86-64, 2020.3.49f1 / 2022.3.62f3 (two) / 6000.4.1f1 macOS arm64, 2022.3.62f3 Android arm64 (ICF, Master), 6000.4.1f1 Android arm64 links binary facts, method addresses and type rows byte-identical

    On the Master build: module array 0x7880e0 (dSYM _g_CodeGenModules); 12,514 methods whose 11,031 unique code addresses equal the dSYM's 11,031 method symbols as a set. Type table 0x7adbc8 (dSYM _g_Il2CppTypeTable, 6,576 slots to the next symbol), types_count 6,576, highest referenced type index 6,031. Return, field and parameter type rows (12,514 / 8,929 / 15,582) equal the Release build of the same project linked from the same global-metadata.dat (SHA-256 82b93b7ac9ee1038025658378f258dffe818c4c4c20f91c1024bbd516b6386a7; Master GameAssembly.dylib 3978ab4f05c937914feec8de2a04a835328101c373e15a2db6242b60c13386ad). Il2CppDumper (upstream master) and Cpp2IL b5ad444 (with and without StrippedCodeRegSupport) both stop on this build.

  • User-visible CLI/MCP output (if applicable): on the Master build, binary reports

    { "format": "macho", "architecture": "arm64", "code_gen_modules_field": null, "code_gen_modules_array": "0x7880e0", "types_field": null, "types_count": 6576 }
    

    with a limitation for each fallback, for example: "No static MetadataRegistration had the type-definition counts. The type table is inferred from executable bytes consistent with an adjacent ADRP+ADD pair referencing the one run of Il2CppType-shaped pointers long enough for every referenced type index; types_count is that run's length, at least every referenced type index but not an observed typesCount, and instruction boundaries and runtime use were not verified."

  • Remaining proof gaps: one Master build (macOS arm64) checked; the x86-64 type-table path is fixture-only. A differently scheduled build (address formed by ldr, a non-adjacent pair, or a type-shaped word right before the table) fails closed rather than linking. types_count matched the dSYM here but can differ in general. Scan cost on large shipped games is unmeasured; on synthetic images an arm64 image whose words all point into a mapping gap takes 0.48 s at 16 MiB (0.36 s when a static record ends the search) and 1.9 s at 64 MiB, and 8 MiB with 1,024 mappings about 0.1 s. No game was executed or modified.

For evidence-bearing changes:

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity, source provenance, and failed attempts remain preserved.
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

Mapping-scan review follow-up at a10fba039 (2026-10-25), Node 24.22.1 / npm 11.16.0 on macOS:

  • NativeImage owns one FileMappingIndex, built after image admission and shared by the type scan, stored-word reads, loader-aware scalar reads and mapped-span checks. The scan-local index is removed. File-backed pointer reads use the index before checking zero-fill-only ownership; unresolved ELF/Mach-O slots, aliases, gaps and zero-fill refusals retain their existing semantics. This reuse lasts only for the immutable image; no cross-file or global cache is added.
  • New regressions cover repeated loader reads without rescanning the source mappings and a real code-loaded table among one-entry runs across 64 extra mappings. The former fails on e51425fb9 with 96 mapping walks; both pass now.
  • 11 selected files / 347 tests passed, covering all IL2CPP boundaries, loader mapping parity, service/view contracts, and public CLI/stdio MCP workflows. check:fast, format:check, and docs:check passed.
  • Completed public CLI benchmark: inspect-il2cpp-metadata global-metadata.dat --binary BINARY --json, before e51425fb9 versus this change. Every response's complete canonical Evidence is identical across all before/after repetitions, including provenance, limitations and uncertainty. The fallback table remains inferred, with null types_field and four entries.
Synthetic binary / invocation Elapsed before → after CPU before → after Sampled peak process-family RSS before → after
4 KiB static Mach-O, first fresh process 0.608 → 0.668 s 0.749 → 0.805 s 380.8 → 359.8 MiB
Same, median of 3 repeat processes 0.587 → 0.531 s 0.792 → 0.714 s 359.4 → 362.4 MiB
ELF, 512 extra mappings, first fresh process 0.533 → 0.620 s 0.710 → 0.778 s 396.1 → 384.0 MiB
Same, median of 3 repeat processes 0.685 → 0.579 s 0.871 → 0.794 s 397.3 → 384.7 MiB
ELF, 1,024 extra mappings, first fresh process 1.842 → 0.652 s 1.916 → 0.799 s 395.0 → 397.3 MiB
Same, median of 3 repeat processes 1.630 → 0.622 s 1.789 → 0.790 s 397.9 → 398.1 MiB

The ELF cases use createIl2cppTypeScanFixture(512, 128) and (1024, 1024): 4,096 and 65,536 isolated one-entry runs respectively, all shorter than the metadata's required four entries. The version-31 metadata fixture has each method return index set to 3. OS caches were not cleared; each CLI invocation starts a new process. CPU comes from child-family resource usage; RSS is sampled from the process family at roughly 15 ms plus process-list overhead. No resource stop occurred. The dense fixture shows about 2.6× lower elapsed time; startup noise dominates the small fixtures, and these runs establish no shipped-game or memory improvement. Agent/model tokens were not measured, and no token savings are claimed. A first fixture preflight correctly refused a metadata fixture that referenced only type 0; that failed attempt was excluded from timings and retained locally.

Pinned synthetic input SHA-256 values: metadata a09e29d0fd562da97024f44327513abfc1b95cba471b535181e46cde864e95ad; dense ELF ed7945eb6bbeac958876c2eb90bd29c0fc85c35d5f3e859affde7e8e245c4963. The original real Unity samples were not rerun. Fresh hosted CI remains pending.

CI follow-up at e51425fb9 (2026-10-25), Node 24.22.1 / npm 11.16.0 on macOS:

  • The failed shard had 13 failures in packedBridgeVerification.test.ts and packagedWasmVerifierOwnership.test.ts: their assertions expected top-level stderr and the old package-command identity prefix after the shared verifier-command migration.
  • Merged main f196ebf80, which includes the corrected diagnostic/identity assertions from #7002 (347b6e4d9). The failing verifier suites now pass without weakening isolation, descendant ownership, or cleanup assertions. No additional IL2CPP implementation changes were needed.
  • check:fast (typecheck/lint), format:check, and docs:check: passed.
  • IL2CPP service/view source tests: 53 passed. Both verifier suites and the IL2CPP binary/provider boundary suites: 199 passed. Public IL2CPP CLI/stdio MCP acceptance and shared-suffix name checks: 20 passed.
  • Fresh GitHub CI is pending. These local checks do not establish a completed hosted run; the original real Unity samples were not rerun.

Earlier author validation:

At ad5532870:

  • npm run check: passed, 6/6 tasks, lint 0 errors.
  • npm run docs:check: passed.
  • npm run jscpd: passed.
  • npx vitest run tests/boundary/il2cpp tests/acceptance/il2cppMetadataCli.test.ts src/domain/analysisView src/il2cpp src/application/il2cpp: 39 files, 1,221 passed.
  • Nine self-built Unity samples linked with origin/main and this head: results in the table above.
  • npm test: the local run stopped when a Vitest worker exited in an unrelated JavaScript test, after failures in files that read the CLI build, which was being rebuilt during the run. Rerunning the 119 files that had failed: 74 pass, and the remaining 45 files (165 tests: client setup, doctor and version reports, inspector runtime, SQLite and a GPU codec) fail identically on origin/main ddde7276c on this machine. None touch IL2CPP; CI is the reference for the full suite.

Compatibility, safety, and release

  • Breaking changes or migration steps: none. binary.types_field may now be null on fallback links; static links still report it.
  • Real Hopper/Ghidra, browser, or OS coverage: self-built macOS and Android Unity builds (one Master); no Ghidra run.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: reads caller-selected files only; scans are bounded (64 module-array candidates, the type-table search stops at a second run, yields every 64 KiB, indexed mapping lookups); no execution or writes.

Author readiness

Human owner: @8rulerstar

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/6989 **Author:** [@8rulerstar](https://github.com/8rulerstar) **Created:** 10/24/2026 **Status:** ✅ Merged **Merged:** 10/24/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `fix/il2cpp-lto-registrations` --- ### 📝 Commits (10+) - [`f82a79f`](https://github.com/morluto/rea/commit/f82a79f3f36969dc287c9beb9bc5c9edea295457) fix(il2cpp): accept arm64 module arrays loaded through adrp/add pairs - [`abf8a86`](https://github.com/morluto/rea/commit/abf8a86067944067bc5f87640e5ad70808a5c979) fix(il2cpp): name the matched instruction form in inferred module-array limits - [`24451f2`](https://github.com/morluto/rea/commit/24451f2574cca4c75ae09d079f229ce26b4073c1) fix(il2cpp): accept type tables loaded without a static MetadataRegistration - [`0d023ad`](https://github.com/morluto/rea/commit/0d023ad2b785fbe8fccb43aaacbf72e4a003c7cc) test(il2cpp): pin adrp page deltas, register pairing and type-record shape - [`f2b027e`](https://github.com/morluto/rea/commit/f2b027e9a62385aa87aef244010f03e5f2e766d2) refactor(il2cpp): share Il2CppType kind decoding and document type-table bounds - [`00235dc`](https://github.com/morluto/rea/commit/00235dc4e27056786b894ac1e2a95e2e6ef2ab6e) chore: merge latest main into exp/il2cpp-lto-port - [`23da1dd`](https://github.com/morluto/rea/commit/23da1dd8c0fc765e2580796393401e1870da351b) fix(il2cpp): refuse generic instances when the type table was inferred - [`090ddc8`](https://github.com/morluto/rea/commit/090ddc810d04989b256bbd3f60ff384dab334b8e) fix(il2cpp): fail closed when an inferred type table is not unique - [`a6e2c82`](https://github.com/morluto/rea/commit/a6e2c825e2a018988bd289798216b41df7b611e8) fix(il2cpp): keep the type-table fallback cheap and its refusals exact - [`39480ba`](https://github.com/morluto/rea/commit/39480bacd8e1a7ea5db9697fb5bbfdd475e0c231) fix(il2cpp): judge type-table slots by their loaded value ### 📊 Changes **17 files changed** (+1006 additions, -68 deletions) <details> <summary>View changed files</summary> 📝 `docs/il2cpp-metadata.md` (+29 -4) 📝 `src/application/il2cpp/Il2cppMetadataService.test.ts` (+9 -5) 📝 `src/application/il2cpp/Il2cppMetadataService.ts` (+2 -1) 📝 `src/contracts/il2cpp/il2cppToolContracts.ts` (+1 -1) 📝 `src/domain/analysisView/il2cppMetadataView.test.ts` (+18 -0) 📝 `src/domain/analysisView/il2cppMetadataView.ts` (+5 -0) 📝 `src/domain/il2cpp/il2cppMetadata.ts` (+6 -2) 📝 `src/il2cpp/Il2cppBinaryFile.ts` (+26 -3) 📝 `src/il2cpp/Il2cppBinaryGenerics.ts` (+7 -1) 📝 `src/il2cpp/Il2cppBinaryImage.ts` (+19 -34) 📝 `src/il2cpp/Il2cppBinaryRegistration.ts` (+249 -9) 📝 `src/il2cpp/Il2cppBinaryTypes.ts` (+12 -2) 📝 `src/il2cpp/Il2cppMetadataProvider.ts` (+12 -2) 📝 `tests/boundary/il2cpp/il2cppBinaryFile.test.ts` (+416 -0) 📝 `tests/boundary/il2cpp/il2cppMappingOwnership.test.ts` (+39 -1) 📝 `tests/boundary/il2cpp/il2cppMetadataProvider.test.ts` (+93 -0) 📝 `tests/fixtures/il2cpp/binary.ts` (+63 -3) </details> ### 📄 Description Follow-up to #5327: this extends its inlined module-array fallback to arm64 and adds a matching fallback for the type table. ## Summary A Unity IL2CPP build in the Master configuration (link-time optimisation) can inline both registration structs, so the binary keeps neither `g_CodeRegistration` nor `g_MetadataRegistration` as data. On arm64 such a build stopped at `code-registration-not-found`, and after that at `metadata-registration-not-found`. This change lets it link when exactly one module array and exactly one type table are loaded by code, marks both as inferred, and keeps the existing reasons otherwise. Builds with static registrations are unchanged. Related: #3607. ## Problem and expected behavior Trigger: a macOS arm64 IL2CPP Master build of Unity 2022.3.62f3 (metadata v31) fails with `code-registration-not-found`. Expected: link its methods and type rows, labelled inferred, and fail closed whenever the code-loaded candidate is not unique. ## Change and scope Both fallbacks live in `src/il2cpp/Il2cppBinaryRegistration.ts` and run only on x86-64 or arm64 when the static search found nothing. - Module array: the existing fallback also follows an aligned, adjacent `adrp xd` + `add xd, xd, #imm12` pair (same register, not register 31). The x86-64 scan is unchanged. - Type table (the only MetadataRegistration field linking reads): taken from a run of pointers to Il2CppType-shaped records only if exactly one run in the image is long enough for every referenced type index, it starts and ends inside its mapping, no slot or record field the loader binds or leaves unresolved bounds it, and code loads its start. A static record whose two type-definition counts match stops the fallback even if its other fields are unusable. - Output: `types_field` becomes nullable like `code_gen_modules_field`; `types_count` is then the run length. Each fallback adds its own limitation and view unknown. `--generic-instances` on an inferred type table fails as `generic-methods-unsupported`. - The x86-64 type-table form is included because the reference scan is shared with the existing x86-64 module-array fallback; it is checked on fixtures only. - Not included: other MetadataRegistration fields, `ldr`/GOT or non-adjacent address forms, arm64e, chained fixups. Follow the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope). Scope decision: not applicable (static reading inside the existing IL2CPP provider; no new provider or capability). ## Contract and boundary impact - Semantic owner and earliest changed stage: `Il2cppBinaryRegistration.ts` (registration search); Il2CppType kind decoding is shared from `Il2cppBinaryTypes.ts`. - Contribution scope fit and linked maintainer decision: existing IL2CPP linking; not applicable. - CLI and MCP/tool-catalog contract: `inspect_il2cpp_metadata` description names the x86-64/arm64 fallback and that generic instances need both static registrations. No new input field or failure reason; `binary.types_field` becomes nullable. - Provider, bridge, target-format, or platform compatibility: x86-64 and arm64 Mach-O, PE and ELF images; builds with static registrations take the old path. - Evidence, artifact, provenance, or reconstruction contract: fallback links are inferred, with separate limitations and view unknowns for the module array and the type table. - Target selection, authority, upstream behavior, and cleanup details (if applicable): not applicable. - Generated metadata (`docs/public/product-catalog.json`), package, or installation impact: none. Expected effects: - [x] Read existing files or captured data. - [ ] Launch or attach to a process. - [ ] Inject instrumentation or run scripts/code. - [ ] Change process memory, registers, files, or configuration. - [ ] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. ## Evidence and regression coverage - Tests added or updated: `tests/boundary/il2cpp/il2cppBinaryFile.test.ts` covers the arm64 module array and type table (later and earlier ADRP pages), the x86-64 type table, generic instances refused on an inferred table, the not-found messages, and fail-closed cases: interior reference, run extended before or reaching past a mapping boundary, a second long-enough run (loaded or not), a static record with matching counts but an unusable table, short and one-short runs, unassigned (0x17, 0x1a) and out-of-range kinds, a value-type definition past the metadata, mismatched or register-31 ADRP/ADD pairs, and a dyld-bound table slot or record kind word whose placeholder must not change the outcome. `il2cppMetadataProvider.test.ts` covers the limitation per instruction form. - Base reproduction or other evidence: executed. With `origin/main`'s `Il2cppBinaryRegistration.ts` (`ddde7276c`) swapped into this branch, these two test files give 159 passed / 11 failed; the failures are exactly the positive fallback cases. Self-built samples (Unity, not redistributed), linked with `origin/main` and this head: | Sample | `origin/main` | This head | |---|---|---| | 2022.3.62f3 macOS arm64 Master | `code-registration-not-found` | links | | 8 builds with static registrations: 2019.4.41f2 macOS x86-64, 2020.3.49f1 / 2022.3.62f3 (two) / 6000.4.1f1 macOS arm64, 2022.3.62f3 Android arm64 (ICF, Master), 6000.4.1f1 Android arm64 | links | binary facts, method addresses and type rows byte-identical | On the Master build: module array `0x7880e0` (dSYM `_g_CodeGenModules`); 12,514 methods whose 11,031 unique code addresses equal the dSYM's 11,031 method symbols as a set. Type table `0x7adbc8` (dSYM `_g_Il2CppTypeTable`, 6,576 slots to the next symbol), `types_count` 6,576, highest referenced type index 6,031. Return, field and parameter type rows (12,514 / 8,929 / 15,582) equal the Release build of the same project linked from the same `global-metadata.dat` (SHA-256 `82b93b7ac9ee1038025658378f258dffe818c4c4c20f91c1024bbd516b6386a7`; Master `GameAssembly.dylib` `3978ab4f05c937914feec8de2a04a835328101c373e15a2db6242b60c13386ad`). Il2CppDumper (upstream master) and Cpp2IL `b5ad444` (with and without StrippedCodeRegSupport) both stop on this build. - User-visible CLI/MCP output (if applicable): on the Master build, `binary` reports ```json { "format": "macho", "architecture": "arm64", "code_gen_modules_field": null, "code_gen_modules_array": "0x7880e0", "types_field": null, "types_count": 6576 } ``` with a limitation for each fallback, for example: "No static MetadataRegistration had the type-definition counts. The type table is inferred from executable bytes consistent with an adjacent ADRP+ADD pair referencing the one run of Il2CppType-shaped pointers long enough for every referenced type index; types_count is that run's length, at least every referenced type index but not an observed typesCount, and instruction boundaries and runtime use were not verified." - Remaining proof gaps: one Master build (macOS arm64) checked; the x86-64 type-table path is fixture-only. A differently scheduled build (address formed by `ldr`, a non-adjacent pair, or a type-shaped word right before the table) fails closed rather than linking. `types_count` matched the dSYM here but can differ in general. Scan cost on large shipped games is unmeasured; on synthetic images an arm64 image whose words all point into a mapping gap takes 0.48 s at 16 MiB (0.36 s when a static record ends the search) and 1.9 s at 64 MiB, and 8 MiB with 1,024 mappings about 0.1 s. No game was executed or modified. For evidence-bearing changes: - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed Mapping-scan review follow-up at `a10fba039` (2026-10-25), Node 24.22.1 / npm 11.16.0 on macOS: - `NativeImage` owns one `FileMappingIndex`, built after image admission and shared by the type scan, stored-word reads, loader-aware scalar reads and mapped-span checks. The scan-local index is removed. File-backed pointer reads use the index before checking zero-fill-only ownership; unresolved ELF/Mach-O slots, aliases, gaps and zero-fill refusals retain their existing semantics. This reuse lasts only for the immutable image; no cross-file or global cache is added. - New regressions cover repeated loader reads without rescanning the source mappings and a real code-loaded table among one-entry runs across 64 extra mappings. The former fails on `e51425fb9` with 96 mapping walks; both pass now. - **11 selected files / 347 tests passed**, covering all IL2CPP boundaries, loader mapping parity, service/view contracts, and public CLI/stdio MCP workflows. `check:fast`, `format:check`, and `docs:check` passed. - Completed public CLI benchmark: `inspect-il2cpp-metadata global-metadata.dat --binary BINARY --json`, before `e51425fb9` versus this change. Every response's complete canonical Evidence is identical across all before/after repetitions, including provenance, limitations and uncertainty. The fallback table remains inferred, with null `types_field` and four entries. | Synthetic binary / invocation | Elapsed before → after | CPU before → after | Sampled peak process-family RSS before → after | | --- | --- | --- | --- | | 4 KiB static Mach-O, first fresh process | 0.608 → 0.668 s | 0.749 → 0.805 s | 380.8 → 359.8 MiB | | Same, median of 3 repeat processes | 0.587 → 0.531 s | 0.792 → 0.714 s | 359.4 → 362.4 MiB | | ELF, 512 extra mappings, first fresh process | 0.533 → 0.620 s | 0.710 → 0.778 s | 396.1 → 384.0 MiB | | Same, median of 3 repeat processes | 0.685 → 0.579 s | 0.871 → 0.794 s | 397.3 → 384.7 MiB | | ELF, 1,024 extra mappings, first fresh process | 1.842 → 0.652 s | 1.916 → 0.799 s | 395.0 → 397.3 MiB | | Same, median of 3 repeat processes | 1.630 → 0.622 s | 1.789 → 0.790 s | 397.9 → 398.1 MiB | The ELF cases use `createIl2cppTypeScanFixture(512, 128)` and `(1024, 1024)`: 4,096 and 65,536 isolated one-entry runs respectively, all shorter than the metadata's required four entries. The version-31 metadata fixture has each method return index set to 3. OS caches were not cleared; each CLI invocation starts a new process. CPU comes from child-family resource usage; RSS is sampled from the process family at roughly 15 ms plus process-list overhead. No resource stop occurred. The dense fixture shows about 2.6× lower elapsed time; startup noise dominates the small fixtures, and these runs establish no shipped-game or memory improvement. Agent/model tokens were not measured, and no token savings are claimed. A first fixture preflight correctly refused a metadata fixture that referenced only type 0; that failed attempt was excluded from timings and retained locally. Pinned synthetic input SHA-256 values: metadata `a09e29d0fd562da97024f44327513abfc1b95cba471b535181e46cde864e95ad`; dense ELF `ed7945eb6bbeac958876c2eb90bd29c0fc85c35d5f3e859affde7e8e245c4963`. The original real Unity samples were not rerun. Fresh hosted CI remains pending. CI follow-up at `e51425fb9` (2026-10-25), Node 24.22.1 / npm 11.16.0 on macOS: - The failed shard had 13 failures in `packedBridgeVerification.test.ts` and `packagedWasmVerifierOwnership.test.ts`: their assertions expected top-level stderr and the old package-command identity prefix after the shared verifier-command migration. - Merged main `f196ebf80`, which includes the corrected diagnostic/identity assertions from #7002 (`347b6e4d9`). The failing verifier suites now pass without weakening isolation, descendant ownership, or cleanup assertions. No additional IL2CPP implementation changes were needed. - `check:fast` (typecheck/lint), `format:check`, and `docs:check`: passed. - IL2CPP service/view source tests: **53 passed**. Both verifier suites and the IL2CPP binary/provider boundary suites: **199 passed**. Public IL2CPP CLI/stdio MCP acceptance and shared-suffix name checks: **20 passed**. - Fresh GitHub CI is pending. These local checks do not establish a completed hosted run; the original real Unity samples were not rerun. Earlier author validation: At `ad5532870`: - `npm run check`: passed, 6/6 tasks, lint 0 errors. - `npm run docs:check`: passed. - `npm run jscpd`: passed. - `npx vitest run tests/boundary/il2cpp tests/acceptance/il2cppMetadataCli.test.ts src/domain/analysisView src/il2cpp src/application/il2cpp`: 39 files, 1,221 passed. - Nine self-built Unity samples linked with `origin/main` and this head: results in the table above. - `npm test`: the local run stopped when a Vitest worker exited in an unrelated JavaScript test, after failures in files that read the CLI build, which was being rebuilt during the run. Rerunning the 119 files that had failed: 74 pass, and the remaining 45 files (165 tests: client setup, doctor and version reports, inspector runtime, SQLite and a GPU codec) fail identically on `origin/main` `ddde7276c` on this machine. None touch IL2CPP; CI is the reference for the full suite. ## Compatibility, safety, and release - Breaking changes or migration steps: none. `binary.types_field` may now be `null` on fallback links; static links still report it. - Real Hopper/Ghidra, browser, or OS coverage: self-built macOS and Android Unity builds (one Master); no Ghidra run. - Package or release metadata impact: none. - Security, privacy, process, or containment review: reads caller-selected files only; scans are bounded (64 module-array candidates, the type-table search stops at a second run, yields every 64 KiB, indexed mapping lookups); no execution or writes. ## Author readiness Human owner: @8rulerstar - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-11-03 13:38:39 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#7552
No description provided.