[GH-ISSUE #6534] [Bug] IL2CPP type names conflate rank-one multidimensional arrays with vectors #3927

Closed
opened 2026-10-31 00:45:18 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 23, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/6534

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Native analysis or decompilation

Observed behavior

Source-only finding; runtime not run. inspect_il2cpp_metadata with binary_path renders both a rank-one IL2CPP_TYPE_ARRAY (kind 0x14) and an IL2CPP_TYPE_SZARRAY vector (kind 0x1d) as int[] when their element type is int.

The ARRAY branch accepts rank 1 and inserts zero commas between brackets. The SZARRAY branch appends the same brackets. These are different managed array types, so the returned name loses the kind distinction while presenting a concrete type.

Reproduction

Only source inspection and issue searches were performed. The following fixture replay is proposed and unexecuted:

  1. Parse createIl2cppMetadataFixture({ version: 31 }).bytes from tests/fixtures/il2cpp/metadata.ts with readIl2cppMetadataForLinking.
  2. Create vector = createIl2cppBinaryFixture() from tests/fixtures/il2cpp/binary.ts. Set its type-0 data pointer at file offset 0x980 to FIXTURE_BINARY_BASE + 0x9b0n, the fixture's primitive int type. Its kind remains 0x1d.
  3. Copy it to multidimensional. Set the kind/attribute word at 0x988 to 0x14 << 16, and the data pointer at 0x980 to FIXTURE_BINARY_BASE + 0xb00n. At 0xb00, write the element pointer FIXTURE_BINARY_BASE + 0x9b0n; set the rank byte at 0xb08 to 1. The remaining zero-filled array fields represent unspecified bounds.
  4. Call linkIl2cppBinary(bytes, metadata, link).return_types[0] for each variant. Source-derived prediction: both return { type: 0, name: "int[]" }.
  5. For a public MCP replay, save the version-31 metadata and either binary as regular files, then request:
{
  "name": "inspect_il2cpp_metadata",
  "arguments": {
    "path": "/artifacts/global-metadata.dat",
    "binary_path": "/artifacts/array.dylib",
    "detail": "complete"
  }
}

No fixture execution, public request, test, or build was run. Runtime reproduction frequency is NOT_ENOUGH_INFO.

Expected behavior

Keep the two array kinds distinguishable, for example int[*] or int[...] for rank-one ARRAY and int[] for SZARRAY.

Microsoft's array-type contract distinguishes a rank-one multidimensional array from a vector. REA's managed signature decoder already preserves this distinction. This does not require recovering omitted numeric array bounds.

Impact and scope

Source-derived scope: native return, field, or parameter type names whose Il2CppType kind is ARRAY with rank 1. Consumers can mistake the displayed type for a vector. The original binary and native type index remain retained; artifact bytes are not changed.

Version 31 supplies a concrete admitted path. Version 27 is excluded because the linker deliberately returns null type names. Real Unity artifact prevalence and runtime behavior across the other admitted versions are NOT_ENOUGH_INFO; neither was tested.

REA version

Source package 6.7.0; baseline revision 28a33cae8f8d4de8e11f7a266ff0d756432ab092.

Runtime and platform

Linux x64 source inspection; no REA runtime execution. Node.js and deep-analysis-provider runtime versions: Not applicable to the source-only evidence.

Target and artifact context

Synthetic version-31 IL2CPP metadata with the repository's thin arm64 Mach-O registration fixture, modified only in the described native type records. No Unity application was executed.

Interface

MCP

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

Derived string trace, not captured runtime output:

SZARRAY(int)   -> "int" + "[]"                  -> "int[]"
ARRAY(int, 1)  -> "int" + "[" + ",".repeat(0) + "]" -> "int[]"

Missing evidence: NOT_ENOUGH_INFO for executed fixture output or a real-world affected Unity binary.

Typed outcome or recovery expected

Preserve the native type index and return a name that distinguishes rank-one ARRAY from SZARRAY. Restoration signal: the proposed paired fixtures yield different names, with the vector still int[]. Rank-two ARRAY should remain int[,].

Analysis or suspected cause

Source-derived cause: ARRAY rendering uses only comma count to express rank. Rank 1 contributes an empty string, so it collides with the dedicated vector suffix. The provider's stated omission of array bounds does not identify or preserve this array-kind distinction.

Additional context

Open and closed dedup searches included "IL2CPP" "array", "IL2CPP" "vector", "IL2CPP" "rank", and an open search for "Il2cppBinaryTypes"; no equivalent report was found.

Inspected related reports: open #6224 concerns name-filter rejection in retained views, while closed #5112 introduced native linking. Neither reports this rendering result.

Last known good version and regression interval: NOT_ENOUGH_INFO; this is a source-only audit, not an established regression.

Triage assessment

  • Impact level: P2
  • Assessment status: provisional
  • Impact basis: Admitted rank-one ARRAY type records produce a concrete vector name in native type evidence, misleading type interpretation. The source trace is direct, but runtime reproduction and real-world prevalence were not established; original artifacts and type indices remain available.
  • Workaround status: unverified
  • Workaround basis: Inspecting retained native type records separately may recover the array kind, but no practical REA-only workaround was demonstrated.
Originally created by @coygeek on GitHub (Oct 23, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6534 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Native analysis or decompilation ### Observed behavior Source-only finding; runtime not run. `inspect_il2cpp_metadata` with `binary_path` renders both a rank-one `IL2CPP_TYPE_ARRAY` (kind `0x14`) and an `IL2CPP_TYPE_SZARRAY` vector (kind `0x1d`) as `int[]` when their element type is `int`. The ARRAY branch accepts rank 1 and inserts zero commas between brackets. The SZARRAY branch appends the same brackets. These are different managed array types, so the returned name loses the kind distinction while presenting a concrete type. ### Reproduction Only source inspection and issue searches were performed. The following fixture replay is proposed and **unexecuted**: 1. Parse `createIl2cppMetadataFixture({ version: 31 }).bytes` from `tests/fixtures/il2cpp/metadata.ts` with `readIl2cppMetadataForLinking`. 2. Create `vector = createIl2cppBinaryFixture()` from `tests/fixtures/il2cpp/binary.ts`. Set its type-0 data pointer at file offset `0x980` to `FIXTURE_BINARY_BASE + 0x9b0n`, the fixture's primitive `int` type. Its kind remains `0x1d`. 3. Copy it to `multidimensional`. Set the kind/attribute word at `0x988` to `0x14 << 16`, and the data pointer at `0x980` to `FIXTURE_BINARY_BASE + 0xb00n`. At `0xb00`, write the element pointer `FIXTURE_BINARY_BASE + 0x9b0n`; set the rank byte at `0xb08` to 1. The remaining zero-filled array fields represent unspecified bounds. 4. Call `linkIl2cppBinary(bytes, metadata, link).return_types[0]` for each variant. Source-derived prediction: both return `{ type: 0, name: "int[]" }`. 5. For a public MCP replay, save the version-31 metadata and either binary as regular files, then request: ```json { "name": "inspect_il2cpp_metadata", "arguments": { "path": "/artifacts/global-metadata.dat", "binary_path": "/artifacts/array.dylib", "detail": "complete" } } ``` No fixture execution, public request, test, or build was run. Runtime reproduction frequency is NOT_ENOUGH_INFO. ### Expected behavior Keep the two array kinds distinguishable, for example `int[*]` or `int[...]` for rank-one ARRAY and `int[]` for SZARRAY. [Microsoft's array-type contract](https://learn.microsoft.com/en-us/dotnet/api/system.type.makearraytype?view=net-10.0#remarks) distinguishes a rank-one multidimensional array from a vector. REA's [managed signature decoder](https://github.com/morluto/rea/blob/28a33cae8f8d4de8e11f7a266ff0d756432ab092/src/dotnet/ManagedMemberInspectorCore.ts#L451-L454) already preserves this distinction. This does not require recovering omitted numeric array bounds. ### Impact and scope Source-derived scope: native return, field, or parameter type names whose Il2CppType kind is ARRAY with rank 1. Consumers can mistake the displayed type for a vector. The original binary and native type index remain retained; artifact bytes are not changed. Version 31 supplies a concrete admitted path. Version 27 is excluded because the linker deliberately returns null type names. Real Unity artifact prevalence and runtime behavior across the other admitted versions are NOT_ENOUGH_INFO; neither was tested. ### REA version Source package 6.7.0; baseline revision `28a33cae8f8d4de8e11f7a266ff0d756432ab092`. ### Runtime and platform Linux x64 source inspection; no REA runtime execution. Node.js and deep-analysis-provider runtime versions: Not applicable to the source-only evidence. ### Target and artifact context Synthetic version-31 IL2CPP metadata with the repository's thin arm64 Mach-O registration fixture, modified only in the described native type records. No Unity application was executed. ### Interface MCP ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence - [The two array-kind branches](https://github.com/morluto/rea/blob/28a33cae8f8d4de8e11f7a266ff0d756432ab092/src/il2cpp/Il2cppBinaryTypes.ts#L115-L128) produce identical brackets for SZARRAY and rank-one ARRAY. - [The linker guards and column production](https://github.com/morluto/rea/blob/28a33cae8f8d4de8e11f7a266ff0d756432ab092/src/il2cpp/Il2cppBinaryFile.ts#L155-L185) admit a valid mapped type index, skip names specifically for version 27, and call this renderer for native type rows. - [The provider projection](https://github.com/morluto/rea/blob/28a33cae8f8d4de8e11f7a266ff0d756432ab092/src/il2cpp/Il2cppMetadataProvider.ts#L220-L222) forwards these names unchanged. [The documented output](https://github.com/morluto/rea/blob/28a33cae8f8d4de8e11f7a266ff0d756432ab092/docs/il2cpp-metadata.md#L247-L254) describes names rendered from the native Il2CppType table. Derived string trace, not captured runtime output: ```text SZARRAY(int) -> "int" + "[]" -> "int[]" ARRAY(int, 1) -> "int" + "[" + ",".repeat(0) + "]" -> "int[]" ``` Missing evidence: NOT_ENOUGH_INFO for executed fixture output or a real-world affected Unity binary. ### Typed outcome or recovery expected Preserve the native type index and return a name that distinguishes rank-one ARRAY from SZARRAY. Restoration signal: the proposed paired fixtures yield different names, with the vector still `int[]`. Rank-two ARRAY should remain `int[,]`. ### Analysis or suspected cause Source-derived cause: ARRAY rendering uses only comma count to express rank. Rank 1 contributes an empty string, so it collides with the dedicated vector suffix. The provider's stated omission of array bounds does not identify or preserve this array-kind distinction. ### Additional context Open and closed dedup searches included `"IL2CPP" "array"`, `"IL2CPP" "vector"`, `"IL2CPP" "rank"`, and an open search for `"Il2cppBinaryTypes"`; no equivalent report was found. Inspected related reports: open [#6224](https://github.com/morluto/rea/issues/6224) concerns name-filter rejection in retained views, while closed [#5112](https://github.com/morluto/rea/issues/5112) introduced native linking. Neither reports this rendering result. Last known good version and regression interval: NOT_ENOUGH_INFO; this is a source-only audit, not an established regression. ## Triage assessment - Impact level: P2 - Assessment status: provisional - Impact basis: Admitted rank-one ARRAY type records produce a concrete vector name in native type evidence, misleading type interpretation. The source trace is direct, but runtime reproduction and real-world prevalence were not established; original artifacts and type indices remain available. - Workaround status: unverified - Workaround basis: Inspecting retained native type records separately may recover the array kind, but no practical REA-only workaround was demonstrated.
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#3927
No description provided.