[PR #1837] [CLOSED] fix(managed): decode common ECMA-335 member signature element types #4849

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

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1837
Author: @JasonBuildAI
Created: 10/11/2026
Status: ❌ Closed

Base: main ← Head: fix/managed-signature-element-types-c7d2


📝 Commits (2)

  • feed63f fix(managed): decode common ECMA-335 member signature element types
  • b8a23d7 fix(managed): decode array shapes with signed bounds and bounded allocation

📊 Changes

5 files changed (+577 additions, -44 deletions)

View changed files

📝 src/dotnet/ManagedDecodeBudget.ts (+3 -0)
📝 src/dotnet/ManagedMemberInspector.test.ts (+243 -11)
📝 src/dotnet/ManagedMemberInspectorCore.ts (+325 -31)
📝 src/dotnet/ManagedMemberRows.ts (+5 -1)
📝 tests/boundary/providers/managed/managedMemberComparisonFromMetadata.test.ts (+1 -1)

📄 Description

Summary

Analysts running inspect-managed-members (CLI) or inspect_managed_members (MCP) on ordinary .NET and Unity assemblies now get decoded member types for generics, multidimensional arrays, function pointers, custom modifiers, and typedbyref: 6,383 methods and 2,755 fields were blocked by ELEMENT_TYPE_GENERICINST alone across a 187-assembly sweep, and affected artifacts reported coverage.state: "partial" with null return_type/parameter_types/field_type values. Fixes #1832.

Problem and expected behavior

Smallest trigger: inspect-managed-members on System.Runtime.Caching.dll (in-box .NET Framework 4). Method 0x06000001 has the well-formed signature 20 00 15 12 71 01 0e (class:113<string> return type) and is reported as parse_status: "unsupported", issue: "unsupported element type 0x15"; 19 of 493 methods and 12 of 403 fields are unsupported and coverage.state drops to partial.

Violated invariant: an admitted, well-formed signature blob that REA can fully parse should decode, and unsupported should be reserved for element types the metadata format does not assign. The base revision treated every element type outside a small fixed subset as unsupported; an existing unit test recorded ELEMENT_TYPE_ARRAY (0x14) as "valid, but not decoded here".

Expected: those signatures decode into the existing type-string form while raw_length/raw_sha256 pairing stays unchanged; the sample reports 493/493 methods, 403/403 fields, and coverage.state: "complete".

Change and scope

  • src/dotnet/ManagedMemberInspectorCore.ts: readTypeSignature becomes an iterative frame-stack decoder (no recursion; ECMA-335 permits arbitrary nesting, and an existing test requires 8,000-deep pointer signatures to parse without recursion) that decodes:
    • ELEMENT_TYPE_GENERICINST (0x15) -> class:113<string>, valuetype:10<var:0,mvar:1>, and class:5<> for empty argument lists
    • ELEMENT_TYPE_ARRAY (0x14) with rank, sizes, and lower bounds -> i4[2...5], i4[0...]
    • ELEMENT_TYPE_FNPTR (0x1b) -> fnptr(valuetype:152,native-int,native-int), fnptr[cc](...) when a calling convention is present
    • ELEMENT_TYPE_CMOD_REQD/CMOD_OPT (0x1f/0x20) -> modreq:317(bool), modopt:317(i4)
    • ELEMENT_TYPE_TYPEDBYREF (0x16) -> typedbyref
  • Malformed boundaries stay typed: GENERICINST not followed by CLASS/VALUETYPE, array rank 0, and truncated blobs report malformed with a specific issue, and unsupported element types keep the unsupported element type 0xNN contract.
  • Intentionally not included: no change to raw signature digests, cross-version matching keys, CIL decoding, metadata rows, or CLI/MCP schemas.

Contract and boundary impact

  • Semantic owner and earliest changed stage: readTypeSignature in src/dotnet/ManagedMemberInspectorCore.ts; the change is first observable in methods[].signature / fields[].signature of inspect-managed-members output.
  • CLI and MCP/tool-catalog contract: no schema change; members that carried null type fields and parse_status: "unsupported" now carry decoded strings with parse_status: "decoded" and issue: null.
  • Provider, bridge, target-format, or platform compatibility: none; pure metadata parsing, no provider or OS dependency.
  • Evidence, artifact, provenance, or reconstruction contract: raw_length/raw_sha256 and member identity are unchanged; only the decoded projection of the same blob changes.
  • Process execution, authorization, cleanup, or containment impact: none; no target code is loaded or executed.
  • Generated metadata (docs/public/product-catalog.json), package, or installation impact: none. No doc or contract enumerates the signature element-type vocabulary (checked docs/, tool contracts, and workflow examples), so no authored docs needed changes; runtime builds and source checking do not consume the scratch oracle.

Evidence and regression coverage

  • Tests added or updated: src/dotnet/ManagedMemberInspector.test.ts gains a decode table for ten field shapes, three malformed cases, and method-level tests (generic instantiation return type, function-pointer parameter from the .NET 7 System.Diagnostics.Process assembly, a generic argument following a sibling argument from System.Collections.Immutable 0x06000020, and 8,000-deep nesting). The test that codified ARRAY as unimplemented was replaced by its decode assertion.
  • Base reproduction or other evidence: before/after on the base revision and the patched revision (raw output shown below), plus a cross-check against Microsoft System.Reflection.Metadata: an independent oracle decoded the same signature blobs from 187 assemblies (.NET 7 shared framework 7.0.20 + in-box .NET Framework GAC) and compared rendered strings token-by-token. Result: 55,242 methods and 34,887 fields compared, 0 mismatches, 0 members non-decoded; the only 6 oracle failures are native DLLs without managed metadata (clrgc.dll, clretwrc.dll, hostpolicy.dll, mscorrc.dll, msquic.dll, System.IO.Compression.Native.dll). This oracle is scratch tooling, not part of the PR.
  • User-visible CLI/MCP output (if applicable): shown below.
  • Remaining proof gaps: the oracle corpus is Windows .NET Framework/GAC plus .NET 7; non-Windows runtime assemblies and stripped/obfuscated metadata were not part of the sweep. Element types still unassigned by ECMA-335 continue to report unsupported, unchanged.

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.

Reproduction output

Base revision (43dafb5a), node scripts/rea.mjs inspect-managed-members <System.Runtime.Caching.dll> --format json:

methods: 474/493 decoded (19 unsupported)
fields:  391/403 decoded (12 unsupported)
coverage: { "state": "partial", "issues": [] }
method 0x06000001: { "parse_status": "unsupported", "issue": "unsupported element type 0x15" }

Patched revision (feed63f6), same command:

methods: 493/493 decoded
fields:  403/403 decoded
coverage: { "state": "complete", "issues": [] }
method 0x06000001: {
  "raw_length": 7,
  "raw_sha256": "817f96629f84125e02fc3ea714e382f5705d5ba99997952293aad26a72fd6363",
  "parse_status": "decoded",
  "return_type": "class:113<string>",
  "parameter_types": [],
  "issue": null
}

Cross-assembly measurement before the change: 6,383 methods + 2,755 fields blocked by 0x15, 36 + 243 by 0x1f, 9 + 33 by 0x1b, 2 + 9 by 0x14, 2 by 0x16 (9,472 members total). After the change: 0 non-decoded members out of 55,242 methods and 34,887 fields compared against the oracle.

Validation performed

  • npm run test:local -- src/dotnet/ManagedMemberInspector.test.ts — 41 passed (41)
  • npm run test:local -- src/dotnet/ManagedArtifactFailures.test.ts src/dotnet/ManagedArtifactInspector.test.ts src/dotnet/ManagedCilDecoding.test.ts src/dotnet/ManagedDecodeBudget.test.ts src/dotnet/ManagedMemberInspector.test.ts src/dotnet/ManagedMemberInspectorCore.test.ts src/dotnet/ManagedMetadataHeaps.test.ts src/dotnet/ManagedNativeBoundaryInspector.test.ts — 109 passed (109)
  • npm run check:fast — typecheck and lint successful (turbo: 2 successful, 2 total)
  • npm run compile — clean TypeScript build
  • npx oxlint src/dotnet/ManagedMemberInspectorCore.ts src/dotnet/ManagedMemberInspector.test.ts — no errors; only the pre-existing file-length warning for ManagedMemberInspectorCore.ts (already over the 500-line advisory at the base revision)
  • System.Reflection.Metadata oracle sweep (scratch, described above) — 0 mismatches, 0 non-decoded members

Compatibility, safety, and release

  • Breaking changes or migration steps: none. This is a behavior improvement: members whose signatures previously reported parse_status: "unsupported" now report "decoded" with populated type fields. Callers that branched on unsupported for these element types will observe decoded instead.
  • Real Hopper/Ghidra, browser, or OS coverage: not applicable; no provider or OS-specific path is involved.
  • Package or release metadata impact: none; no dependency, package, or generated catalog changes.
  • Security, privacy, process, or containment review: none; the change only parses already-retained signature bytes and adds no execution, allocation beyond the retained blob, or external access.

AI disclosure: this change was drafted with AI assistance at my request, under my direction and review.

Review checklist

  • This PR addresses a concrete problem or an agreed enhancement.
  • 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/1837 **Author:** [@JasonBuildAI](https://github.com/JasonBuildAI) **Created:** 10/11/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/managed-signature-element-types-c7d2` --- ### 📝 Commits (2) - [`feed63f`](https://github.com/morluto/rea/commit/feed63f683f4967122c261618e8dfc14fb5c9889) fix(managed): decode common ECMA-335 member signature element types - [`b8a23d7`](https://github.com/morluto/rea/commit/b8a23d77ac3b3999221da515254f74e249bfdf5c) fix(managed): decode array shapes with signed bounds and bounded allocation ### 📊 Changes **5 files changed** (+577 additions, -44 deletions) <details> <summary>View changed files</summary> 📝 `src/dotnet/ManagedDecodeBudget.ts` (+3 -0) 📝 `src/dotnet/ManagedMemberInspector.test.ts` (+243 -11) 📝 `src/dotnet/ManagedMemberInspectorCore.ts` (+325 -31) 📝 `src/dotnet/ManagedMemberRows.ts` (+5 -1) 📝 `tests/boundary/providers/managed/managedMemberComparisonFromMetadata.test.ts` (+1 -1) </details> ### 📄 Description <!-- PR title: type(optional-scope): imperative outcome The title becomes the squash-merge commit subject and generated changelog entry. --> ## Summary Analysts running `inspect-managed-members` (CLI) or `inspect_managed_members` (MCP) on ordinary .NET and Unity assemblies now get decoded member types for generics, multidimensional arrays, function pointers, custom modifiers, and typedbyref: 6,383 methods and 2,755 fields were blocked by `ELEMENT_TYPE_GENERICINST` alone across a 187-assembly sweep, and affected artifacts reported `coverage.state: "partial"` with null `return_type`/`parameter_types`/`field_type` values. Fixes #1832. ## Problem and expected behavior Smallest trigger: `inspect-managed-members` on `System.Runtime.Caching.dll` (in-box .NET Framework 4). Method `0x06000001` has the well-formed signature `20 00 15 12 71 01 0e` (`class:113<string>` return type) and is reported as `parse_status: "unsupported"`, `issue: "unsupported element type 0x15"`; 19 of 493 methods and 12 of 403 fields are unsupported and `coverage.state` drops to `partial`. Violated invariant: an admitted, well-formed signature blob that REA can fully parse should decode, and `unsupported` should be reserved for element types the metadata format does not assign. The base revision treated every element type outside a small fixed subset as unsupported; an existing unit test recorded `ELEMENT_TYPE_ARRAY` (0x14) as "valid, but not decoded here". Expected: those signatures decode into the existing type-string form while `raw_length`/`raw_sha256` pairing stays unchanged; the sample reports 493/493 methods, 403/403 fields, and `coverage.state: "complete"`. ## Change and scope - `src/dotnet/ManagedMemberInspectorCore.ts`: `readTypeSignature` becomes an iterative frame-stack decoder (no recursion; ECMA-335 permits arbitrary nesting, and an existing test requires 8,000-deep pointer signatures to parse without recursion) that decodes: - `ELEMENT_TYPE_GENERICINST` (0x15) -> `class:113<string>`, `valuetype:10<var:0,mvar:1>`, and `class:5<>` for empty argument lists - `ELEMENT_TYPE_ARRAY` (0x14) with rank, sizes, and lower bounds -> `i4[2...5]`, `i4[0...]` - `ELEMENT_TYPE_FNPTR` (0x1b) -> `fnptr(valuetype:152,native-int,native-int)`, `fnptr[cc](...)` when a calling convention is present - `ELEMENT_TYPE_CMOD_REQD`/`CMOD_OPT` (0x1f/0x20) -> `modreq:317(bool)`, `modopt:317(i4)` - `ELEMENT_TYPE_TYPEDBYREF` (0x16) -> `typedbyref` - Malformed boundaries stay typed: GENERICINST not followed by CLASS/VALUETYPE, array rank 0, and truncated blobs report `malformed` with a specific `issue`, and unsupported element types keep the `unsupported element type 0xNN` contract. - Intentionally not included: no change to raw signature digests, cross-version matching keys, CIL decoding, metadata rows, or CLI/MCP schemas. ## Contract and boundary impact - Semantic owner and earliest changed stage: `readTypeSignature` in `src/dotnet/ManagedMemberInspectorCore.ts`; the change is first observable in `methods[].signature` / `fields[].signature` of `inspect-managed-members` output. - CLI and MCP/tool-catalog contract: no schema change; members that carried null type fields and `parse_status: "unsupported"` now carry decoded strings with `parse_status: "decoded"` and `issue: null`. - Provider, bridge, target-format, or platform compatibility: none; pure metadata parsing, no provider or OS dependency. - Evidence, artifact, provenance, or reconstruction contract: `raw_length`/`raw_sha256` and member identity are unchanged; only the decoded projection of the same blob changes. - Process execution, authorization, cleanup, or containment impact: none; no target code is loaded or executed. - Generated metadata (`docs/public/product-catalog.json`), package, or installation impact: none. No doc or contract enumerates the signature element-type vocabulary (checked `docs/`, tool contracts, and workflow examples), so no authored docs needed changes; runtime builds and source checking do not consume the scratch oracle. ## Evidence and regression coverage - Tests added or updated: `src/dotnet/ManagedMemberInspector.test.ts` gains a decode table for ten field shapes, three malformed cases, and method-level tests (generic instantiation return type, function-pointer parameter from the .NET 7 `System.Diagnostics.Process` assembly, a generic argument following a sibling argument from `System.Collections.Immutable` `0x06000020`, and 8,000-deep nesting). The test that codified ARRAY as unimplemented was replaced by its decode assertion. - Base reproduction or other evidence: before/after on the base revision and the patched revision (raw output shown below), plus a cross-check against Microsoft `System.Reflection.Metadata`: an independent oracle decoded the same signature blobs from 187 assemblies (.NET 7 shared framework 7.0.20 + in-box .NET Framework GAC) and compared rendered strings token-by-token. Result: 55,242 methods and 34,887 fields compared, 0 mismatches, 0 members non-decoded; the only 6 oracle failures are native DLLs without managed metadata (`clrgc.dll`, `clretwrc.dll`, `hostpolicy.dll`, `mscorrc.dll`, `msquic.dll`, `System.IO.Compression.Native.dll`). This oracle is scratch tooling, not part of the PR. - User-visible CLI/MCP output (if applicable): shown below. - Remaining proof gaps: the oracle corpus is Windows .NET Framework/GAC plus .NET 7; non-Windows runtime assemblies and stripped/obfuscated metadata were not part of the sweep. Element types still unassigned by ECMA-335 continue to report `unsupported`, unchanged. 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. ### Reproduction output Base revision (`43dafb5a`), `node scripts/rea.mjs inspect-managed-members <System.Runtime.Caching.dll> --format json`: ``` methods: 474/493 decoded (19 unsupported) fields: 391/403 decoded (12 unsupported) coverage: { "state": "partial", "issues": [] } method 0x06000001: { "parse_status": "unsupported", "issue": "unsupported element type 0x15" } ``` Patched revision (`feed63f6`), same command: ``` methods: 493/493 decoded fields: 403/403 decoded coverage: { "state": "complete", "issues": [] } method 0x06000001: { "raw_length": 7, "raw_sha256": "817f96629f84125e02fc3ea714e382f5705d5ba99997952293aad26a72fd6363", "parse_status": "decoded", "return_type": "class:113<string>", "parameter_types": [], "issue": null } ``` Cross-assembly measurement before the change: 6,383 methods + 2,755 fields blocked by 0x15, 36 + 243 by 0x1f, 9 + 33 by 0x1b, 2 + 9 by 0x14, 2 by 0x16 (9,472 members total). After the change: 0 non-decoded members out of 55,242 methods and 34,887 fields compared against the oracle. ## Validation performed - `npm run test:local -- src/dotnet/ManagedMemberInspector.test.ts` — 41 passed (41) - `npm run test:local -- src/dotnet/ManagedArtifactFailures.test.ts src/dotnet/ManagedArtifactInspector.test.ts src/dotnet/ManagedCilDecoding.test.ts src/dotnet/ManagedDecodeBudget.test.ts src/dotnet/ManagedMemberInspector.test.ts src/dotnet/ManagedMemberInspectorCore.test.ts src/dotnet/ManagedMetadataHeaps.test.ts src/dotnet/ManagedNativeBoundaryInspector.test.ts` — 109 passed (109) - `npm run check:fast` — typecheck and lint successful (turbo: 2 successful, 2 total) - `npm run compile` — clean TypeScript build - `npx oxlint src/dotnet/ManagedMemberInspectorCore.ts src/dotnet/ManagedMemberInspector.test.ts` — no errors; only the pre-existing file-length warning for `ManagedMemberInspectorCore.ts` (already over the 500-line advisory at the base revision) - System.Reflection.Metadata oracle sweep (scratch, described above) — 0 mismatches, 0 non-decoded members ## Compatibility, safety, and release - Breaking changes or migration steps: none. This is a behavior improvement: members whose signatures previously reported `parse_status: "unsupported"` now report `"decoded"` with populated type fields. Callers that branched on `unsupported` for these element types will observe `decoded` instead. - Real Hopper/Ghidra, browser, or OS coverage: not applicable; no provider or OS-specific path is involved. - Package or release metadata impact: none; no dependency, package, or generated catalog changes. - Security, privacy, process, or containment review: none; the change only parses already-retained signature bytes and adds no execution, allocation beyond the retained blob, or external access. AI disclosure: this change was drafted with AI assistance at my request, under my direction and review. ## Review checklist - [x] This PR addresses a concrete problem or an agreed enhancement. - [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-10-31 00:56:00 +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#4849
No description provided.