[GH-ISSUE #3877] [Bug] Wrong-kind managed member signatures are reported decoded with complete coverage #1497

Closed
opened 2026-10-16 21:06:11 +00:00 by bsakaguchi · 0 comments
Owner

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

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

rea inspect-managed-members accepts a field signature in a MethodDef row and a method signature in a Field row as decoded, with complete coverage and no issues. The MethodDef is reported as signature.kind: "field" and the Field as signature.kind: "method". rea compare-managed-members then treats the malformed method as an exact, unchanged match.

All commands exit 0. For field-in-method.dll, the MethodDef 0x06000001 reports kind: "field", status: "decoded", return_type: null, field_type: "i4". For method-in-field.dll, the Field 0x04000001 reports kind: "method", status: "decoded", return_type: "void". Both results report metadata.status: "complete" and coverage: {"state":"complete","issues":[]}. The self-comparison reports the method unchanged with an exact-il-signature match, confidence: "exact", no limitations, and complete-within-inputs coverage.

Reproduction

  1. From the root of a REA source checkout (the fixture builder src/dotnet/ManagedPe.fixture.ts is source-only), set WORK to an empty directory outside the checkout and build three single-method assemblies: a valid control, a MethodDef whose signature is the field signature 06 08 (i4), and a Field whose signature is the method signature 00 00 01 (zero-parameter method returning void).
export REA_REPO="$PWD" WORK
node --input-type=module - <<'NODE'
import fs from 'node:fs';
import path from 'node:path';
import {stripTypeScriptTypes} from 'node:module';
import {pathToFileURL} from 'node:url';
const repo = process.env.REA_REPO;
const work = process.env.WORK;
const source = fs.readFileSync(path.join(repo, 'src/dotnet/ManagedPe.fixture.ts'), 'utf8');
const fixtureModule = path.join(work, 'fixture.mjs');
fs.writeFileSync(fixtureModule, stripTypeScriptTypes(source));
const {buildManagedPeFixture} = await import(pathToFileURL(fixtureModule).href);
const body = Buffer.from([0x06, 0x2a]); // Tiny method header, then ret.
for (const [name, options] of [
  ['control', {}],
  ['field-in-method', {methodSignature: Buffer.from([0x06, 0x08])}],
  ['method-in-field', {fieldSignature: Buffer.from([0x00, 0x00, 0x01])}],
]) fs.writeFileSync(path.join(work, name + '.dll'), buildManagedPeFixture({ilBody: body, ...options}));
NODE
  1. Inspect each assembly and compare the malformed MethodDef fixture with itself.
node scripts/rea.mjs inspect-managed-members "$WORK/control.dll" --json > "$WORK/control.json"
node scripts/rea.mjs inspect-managed-members "$WORK/field-in-method.dll" --json > "$WORK/field-in-method.json"
node scripts/rea.mjs inspect-managed-members "$WORK/method-in-field.dll" --json > "$WORK/method-in-field.json"
node scripts/rea.mjs compare-managed-members "$WORK/field-in-method.dll" "$WORK/field-in-method.dll" --json > "$WORK/comparison.json"
  1. Read each member's signature.kind, signature.parse_status, and the result coverage.

Expected behavior

A MethodDef whose signature blob is a FIELD signature, and a Field whose blob is a method signature, are malformed. Each keeps a non-decoded (malformed) signature status, member coverage becomes partial with an issue, and comparison does not report an exact unchanged match for that method. docs/managed-code-analysis.md says malformed facts remain explicit in coverage and per-member status, and the decoder's own comment states that FIELD headers are never method signatures.

Impact and scope

Malformed or damaged managed assemblies receive contradictory decoded member facts with complete coverage, and comparison propagates them as exact unchanged matches; the reach is bounded to inputs with a wrong-kind signature blob.

Workaround: available. The observed outputs retain the mismatch, so a consumer can check that each MethodDef's signature.kind is method and each Field's is field; no CLI option makes REA enforce this.

Reporter's impact estimate: P2 (supported).

REA version

6.5.0, built from source at main commit 034342ba28 (latest npm release is 6.5.0)

Runtime and platform

Node.js v26.10.0; macOS 27.0.1 arm64

Target and artifact context

Synthetic .NET PE assembly with a malformed member signature blob

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

  • Expected source: docs/managed-code-analysis.md:396-398 (malformed facts remain explicit in coverage and per-member status); src/dotnet/ManagedMemberInspectorCore.ts:363-368 (a header that is not a method signature in a MethodDef context is malformed; FIELD headers are never method signatures)
  • Failure source: observed inspect-managed-members and compare-managed-members JSON for the fixtures above
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

Selected inspection values:

{"fixture":"control","coverage":{"state":"complete","issues":[]},"method":{"token":"0x06000001","kind":"method","status":"decoded","return_type":"void","field_type":null},"field":{"token":"0x04000001","kind":"field","status":"decoded","return_type":null,"field_type":"i4"}}
{"fixture":"field-in-method","coverage":{"state":"complete","issues":[]},"method":{"token":"0x06000001","kind":"field","status":"decoded","return_type":null,"field_type":"i4"},"field":{"token":"0x04000001","kind":"field","status":"decoded","return_type":null,"field_type":"i4"}}
{"fixture":"method-in-field","coverage":{"state":"complete","issues":[]},"method":{"token":"0x06000001","kind":"method","status":"decoded","return_type":"void","field_type":null},"field":{"token":"0x04000001","kind":"method","status":"decoded","return_type":"void","field_type":null}}

Selected comparison values:

{"method_status":"unchanged","method_dimensions":[],"method_match":{"status":"matched","basis":"exact-il-signature","confidence":"exact","candidate_left_tokens":[],"candidate_right_tokens":[]},"method_limitations":[],"coverage":{"status":"complete-within-inputs","left_status":"complete","right_status":"complete"}}

Source-derived reasoning: parseFields (src/dotnet/ManagedMemberRows.ts:96-109) and parseMethods (lines 343-350, stored at line 372) pass the blob to the shared budgetedSignature decoder without an expected kind. The decoder chooses field versus method from the blob header alone (src/dotnet/ManagedMemberInspectorCore.ts:753-771), so a FIELD header bypasses the MethodDef guard. Coverage checks only parse_status !== "decoded" (src/dotnet/ManagedMemberInspector.ts:255-263) and reports complete at lines 317-322.

Typed outcome or recovery expected

A MethodDef with a FIELD signature or a Field with a method signature should carry a malformed signature status and partial member coverage, and comparison should not report an exact unchanged match for it.

Restoration check:

For field-in-method.dll, the MethodDef currently reports kind: "field", status: "decoded", and coverage complete with no issues; after a fix it reports a malformed (non-decoded) signature status and partial coverage with an issue, and the self-comparison no longer reports an exact unchanged method match. method-in-field.dll changes the same way for the Field row. Control: control.dll continues to report a decoded method signature for the MethodDef, a decoded field signature for the Field, and complete coverage.

Analysis or suspected cause

Source-derived: src/dotnet/ManagedMemberRows.ts:96-109 and 343-350 call budgetedSignature without an expected kind; src/dotnet/ManagedMemberInspectorCore.ts:753-771 selects field or method from the blob header; src/dotnet/ManagedMemberInspector.ts:255-263 checks only parse_status.

Additional context

This report came from AI-assisted source review with local reproduction where stated above; the evidence labels distinguish observed runs from source-only reasoning.

Originally created by @coygeek on GitHub (Oct 15, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3877 ### 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 `rea inspect-managed-members` accepts a field signature in a MethodDef row and a method signature in a Field row as `decoded`, with `complete` coverage and no issues. The MethodDef is reported as `signature.kind: "field"` and the Field as `signature.kind: "method"`. `rea compare-managed-members` then treats the malformed method as an exact, unchanged match. All commands exit 0. For `field-in-method.dll`, the MethodDef `0x06000001` reports `kind: "field"`, `status: "decoded"`, `return_type: null`, `field_type: "i4"`. For `method-in-field.dll`, the Field `0x04000001` reports `kind: "method"`, `status: "decoded"`, `return_type: "void"`. Both results report `metadata.status: "complete"` and `coverage: {"state":"complete","issues":[]}`. The self-comparison reports the method `unchanged` with an `exact-il-signature` match, `confidence: "exact"`, no limitations, and `complete-within-inputs` coverage. ### Reproduction 1. From the root of a REA source checkout (the fixture builder `src/dotnet/ManagedPe.fixture.ts` is source-only), set `WORK` to an empty directory outside the checkout and build three single-method assemblies: a valid control, a MethodDef whose signature is the field signature `06 08` (`i4`), and a Field whose signature is the method signature `00 00 01` (zero-parameter method returning void). ```sh export REA_REPO="$PWD" WORK node --input-type=module - <<'NODE' import fs from 'node:fs'; import path from 'node:path'; import {stripTypeScriptTypes} from 'node:module'; import {pathToFileURL} from 'node:url'; const repo = process.env.REA_REPO; const work = process.env.WORK; const source = fs.readFileSync(path.join(repo, 'src/dotnet/ManagedPe.fixture.ts'), 'utf8'); const fixtureModule = path.join(work, 'fixture.mjs'); fs.writeFileSync(fixtureModule, stripTypeScriptTypes(source)); const {buildManagedPeFixture} = await import(pathToFileURL(fixtureModule).href); const body = Buffer.from([0x06, 0x2a]); // Tiny method header, then ret. for (const [name, options] of [ ['control', {}], ['field-in-method', {methodSignature: Buffer.from([0x06, 0x08])}], ['method-in-field', {fieldSignature: Buffer.from([0x00, 0x00, 0x01])}], ]) fs.writeFileSync(path.join(work, name + '.dll'), buildManagedPeFixture({ilBody: body, ...options})); NODE ``` 2. Inspect each assembly and compare the malformed MethodDef fixture with itself. ```sh node scripts/rea.mjs inspect-managed-members "$WORK/control.dll" --json > "$WORK/control.json" node scripts/rea.mjs inspect-managed-members "$WORK/field-in-method.dll" --json > "$WORK/field-in-method.json" node scripts/rea.mjs inspect-managed-members "$WORK/method-in-field.dll" --json > "$WORK/method-in-field.json" node scripts/rea.mjs compare-managed-members "$WORK/field-in-method.dll" "$WORK/field-in-method.dll" --json > "$WORK/comparison.json" ``` 3. Read each member's `signature.kind`, `signature.parse_status`, and the result coverage. ### Expected behavior A MethodDef whose signature blob is a FIELD signature, and a Field whose blob is a method signature, are malformed. Each keeps a non-decoded (malformed) signature status, member coverage becomes partial with an issue, and comparison does not report an exact unchanged match for that method. `docs/managed-code-analysis.md` says malformed facts remain explicit in coverage and per-member status, and the decoder's own comment states that FIELD headers are never method signatures. ### Impact and scope Malformed or damaged managed assemblies receive contradictory decoded member facts with complete coverage, and comparison propagates them as exact unchanged matches; the reach is bounded to inputs with a wrong-kind signature blob. Workaround: available. The observed outputs retain the mismatch, so a consumer can check that each MethodDef's `signature.kind` is `method` and each Field's is `field`; no CLI option makes REA enforce this. Reporter's impact estimate: P2 (supported). ### REA version 6.5.0, built from source at main commit 034342ba28c8e56c3746be92b78aa7299afa02bd (latest npm release is 6.5.0) ### Runtime and platform Node.js v26.10.0; macOS 27.0.1 arm64 ### Target and artifact context Synthetic .NET PE assembly with a malformed member signature blob ### Interface CLI ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence - Expected source: docs/managed-code-analysis.md:396-398 (malformed facts remain explicit in coverage and per-member status); src/dotnet/ManagedMemberInspectorCore.ts:363-368 (a header that is not a method signature in a MethodDef context is malformed; FIELD headers are never method signatures) - Failure source: observed `inspect-managed-members` and `compare-managed-members` JSON for the fixtures above - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete Selected inspection values: ```json {"fixture":"control","coverage":{"state":"complete","issues":[]},"method":{"token":"0x06000001","kind":"method","status":"decoded","return_type":"void","field_type":null},"field":{"token":"0x04000001","kind":"field","status":"decoded","return_type":null,"field_type":"i4"}} {"fixture":"field-in-method","coverage":{"state":"complete","issues":[]},"method":{"token":"0x06000001","kind":"field","status":"decoded","return_type":null,"field_type":"i4"},"field":{"token":"0x04000001","kind":"field","status":"decoded","return_type":null,"field_type":"i4"}} {"fixture":"method-in-field","coverage":{"state":"complete","issues":[]},"method":{"token":"0x06000001","kind":"method","status":"decoded","return_type":"void","field_type":null},"field":{"token":"0x04000001","kind":"method","status":"decoded","return_type":"void","field_type":null}} ``` Selected comparison values: ```json {"method_status":"unchanged","method_dimensions":[],"method_match":{"status":"matched","basis":"exact-il-signature","confidence":"exact","candidate_left_tokens":[],"candidate_right_tokens":[]},"method_limitations":[],"coverage":{"status":"complete-within-inputs","left_status":"complete","right_status":"complete"}} ``` Source-derived reasoning: `parseFields` (`src/dotnet/ManagedMemberRows.ts:96-109`) and `parseMethods` (lines 343-350, stored at line 372) pass the blob to the shared `budgetedSignature` decoder without an expected kind. The decoder chooses field versus method from the blob header alone (`src/dotnet/ManagedMemberInspectorCore.ts:753-771`), so a FIELD header bypasses the MethodDef guard. Coverage checks only `parse_status !== "decoded"` (`src/dotnet/ManagedMemberInspector.ts:255-263`) and reports complete at lines 317-322. ### Typed outcome or recovery expected A MethodDef with a FIELD signature or a Field with a method signature should carry a malformed signature status and partial member coverage, and comparison should not report an exact unchanged match for it. Restoration check: For `field-in-method.dll`, the MethodDef currently reports `kind: "field"`, `status: "decoded"`, and coverage `complete` with no issues; after a fix it reports a malformed (non-decoded) signature status and partial coverage with an issue, and the self-comparison no longer reports an exact unchanged method match. `method-in-field.dll` changes the same way for the Field row. Control: `control.dll` continues to report a decoded `method` signature for the MethodDef, a decoded `field` signature for the Field, and complete coverage. ### Analysis or suspected cause Source-derived: src/dotnet/ManagedMemberRows.ts:96-109 and 343-350 call budgetedSignature without an expected kind; src/dotnet/ManagedMemberInspectorCore.ts:753-771 selects field or method from the blob header; src/dotnet/ManagedMemberInspector.ts:255-263 checks only parse_status. ### Additional context This report came from AI-assisted source review with local reproduction where stated above; the evidence labels distinguish observed runs from source-only reasoning.
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#1497
No description provided.