[GH-ISSUE #5102] [Bug] Managed member inspection labels truncated compressed parameter counts as reserved #3141

Closed
opened 2026-10-31 00:37:06 +00:00 by bsakaguchi · 2 comments
Owner

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

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

The production managed-only inspect_managed_members workflow reports signature.issue: "reserved compressed integer" when a MethodDef signature ends inside a two- or four-byte compressed parameter count. The prefixes in these cases are assigned integer widths, rather than reserved prefixes.

Reproduced with synthetic PE/CLI files through runManagedProviderExecution, using the real rea-dotnet-static provider. The affected signatures still have parse_status: "malformed", and coverage remains partial. CLI and MCP transports were not launched.

Reproduction

From the stated source checkout with its locked dependencies already installed, run this source-workflow probe. The fixture builder is source-only. It writes and deletes a synthetic file inside an isolated directory; no target code is executed.

WORK=$(mktemp -d)
mkdir -p "$WORK/home" "$WORK/tmp"
env -u REA_CONFIG_PATH -u REA_HOME -u XDG_CONFIG_HOME -u XDG_DATA_HOME -u XDG_CACHE_HOME HOME="$WORK/home" TMPDIR="$WORK/tmp" WORK="$WORK" node --import tsx --input-type=module <<'JS'
import assert from 'node:assert/strict';
import { writeFile, unlink } from 'node:fs/promises';
import { join } from 'node:path';
import { buildManagedPeFixture } from './src/dotnet/ManagedPe.fixture.ts';
import { runManagedProviderExecution } from './src/composition/directAnalysis.ts';
for (const [hex, expected] of [
  ['000001', null],
  ['00', 'truncated compressed integer'],
  ['0080', 'reserved compressed integer'],
  ['00c00000', 'reserved compressed integer'],
  ['00e0', 'reserved compressed integer'],
]) {
  const file = join(process.env.WORK, 'fixture.dll');
  await writeFile(file, buildManagedPeFixture({
    methodSignature: Buffer.from(hex, 'hex'),
  }));
  try {
    const execution = await runManagedProviderExecution(file, 'inspect_managed_members');
    assert.equal(execution.ok, true);
    const result = execution.value.result;
    const signature = result.methods[0].signature;
    assert.equal(signature.issue, expected);
    assert.equal(signature.parse_status, expected === null ? 'decoded' : 'malformed');
    console.log(JSON.stringify({hex, provider: execution.value.provider.id,
      status: signature.parse_status, issue: signature.issue,
      coverage: result.coverage.state}));
  } finally {
    await unlink(file);
  }
}
JS

Both truncated cases reproduced in the run; the assertions above record current behavior. After correction, those two cases should report truncation instead.

Expected behavior

Report a truncated compressed integer for prefixes 80 and c0 without all continuation bytes. Keep the malformed status and partial coverage. Preserve the reserved diagnostic for a genuinely reserved prefix such as e0.

The decoder's width masks and missing-byte diagnostic establish the distinction: 80 declares two bytes and c0 declares four. The heap-prefix decoder also distinguishes missing declared bytes from reserved prefixes. This expectation concerns accurate diagnostic wording, with no change to rejection semantics.

Impact and scope

P3: misleading wording for malformed metadata. A caller investigating damaged signatures cannot distinguish missing continuation bytes from a reserved prefix using this diagnostic. The verified scope is MethodDef parameter counts in two small synthetic files. No incorrect decoded value, acceptance of malformed input, data loss, or target mutation was observed. Frequency in real assemblies is NOT_ENOUGH_INFO. No workaround is needed to retain correct rejection; no option producing corrected wording was established.

REA version

Package version 6.7.0, source main at 3537e58c1ab29309f06eabf50bc52adba9817a0c.

Runtime and platform

Node.js v26.12.0; macOS 27.0.1; darwin arm64; repository-locked tsx 4.23.15. No external analysis engine was used. The exact repository-pinned Node.js 24.18.0 runtime was not exercised.

Target and artifact context

Source-owned synthetic PE/CLI fixture with a well-bounded blob heap item containing an internally truncated MethodDef signature. The hex strings in the reproduction are the entire method signatures. 00 is the default calling-convention header, followed by a compressed parameter count when present.

Interface

Other

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

Observed output from the production workflow probe, which exited 0:

{"hex":"000001","provider":"rea-dotnet-static","status":"decoded","issue":null,"coverage":"complete"}
{"hex":"00","provider":"rea-dotnet-static","status":"malformed","issue":"truncated compressed integer","coverage":"partial"}
{"hex":"0080","provider":"rea-dotnet-static","status":"malformed","issue":"reserved compressed integer","coverage":"partial"}
{"hex":"00c00000","provider":"rea-dotnet-static","status":"malformed","issue":"reserved compressed integer","coverage":"partial"}
{"hex":"00e0","provider":"rea-dotnet-static","status":"malformed","issue":"reserved compressed integer","coverage":"partial"}

Source-derived path: the method row reader obtains the bounded blob and retains its decoded signature. The method-header reader consumes the compressed count; the signature catch preserves the failure detail in the returned string field.

Typed outcome or recovery expected

Keep signature.parse_status: "malformed" and partial coverage, but return signature.issue: "truncated compressed integer" for 0080 and 00c00000. The valid 000001 control should remain decoded, and 00e0 should retain the reserved-prefix diagnostic.

Analysis or suspected cause

Source-derived: the two- and four-byte branches require every continuation byte to exist. If the prefix declares one of those widths but bytes are missing, both branches fail and reach the shared reserved compressed integer throw. There is no separate truncation guard for those widths. The outer blob-length guard succeeds because the fixture's heap item itself is complete.

Additional context

The two decoder files have no diff between stable tag rea-agents-6.7.0 and the tested main revision. Stable runtime reproduction is NOT_ENOUGH_INFO; source equality alone does not establish a tested release result. Other consumers of the integer helper were not separately exercised. No implementation or publication was performed.

Originally created by @coygeek on GitHub (Oct 18, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5102 ## 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 The production managed-only `inspect_managed_members` workflow reports `signature.issue: "reserved compressed integer"` when a MethodDef signature ends inside a two- or four-byte compressed parameter count. The prefixes in these cases are assigned integer widths, rather than reserved prefixes. Reproduced with synthetic PE/CLI files through `runManagedProviderExecution`, using the real `rea-dotnet-static` provider. The affected signatures still have `parse_status: "malformed"`, and coverage remains `partial`. CLI and MCP transports were not launched. ## Reproduction From the stated source checkout with its locked dependencies already installed, run this source-workflow probe. The fixture builder is source-only. It writes and deletes a synthetic file inside an isolated directory; no target code is executed. ```sh WORK=$(mktemp -d) mkdir -p "$WORK/home" "$WORK/tmp" env -u REA_CONFIG_PATH -u REA_HOME -u XDG_CONFIG_HOME -u XDG_DATA_HOME -u XDG_CACHE_HOME HOME="$WORK/home" TMPDIR="$WORK/tmp" WORK="$WORK" node --import tsx --input-type=module <<'JS' import assert from 'node:assert/strict'; import { writeFile, unlink } from 'node:fs/promises'; import { join } from 'node:path'; import { buildManagedPeFixture } from './src/dotnet/ManagedPe.fixture.ts'; import { runManagedProviderExecution } from './src/composition/directAnalysis.ts'; for (const [hex, expected] of [ ['000001', null], ['00', 'truncated compressed integer'], ['0080', 'reserved compressed integer'], ['00c00000', 'reserved compressed integer'], ['00e0', 'reserved compressed integer'], ]) { const file = join(process.env.WORK, 'fixture.dll'); await writeFile(file, buildManagedPeFixture({ methodSignature: Buffer.from(hex, 'hex'), })); try { const execution = await runManagedProviderExecution(file, 'inspect_managed_members'); assert.equal(execution.ok, true); const result = execution.value.result; const signature = result.methods[0].signature; assert.equal(signature.issue, expected); assert.equal(signature.parse_status, expected === null ? 'decoded' : 'malformed'); console.log(JSON.stringify({hex, provider: execution.value.provider.id, status: signature.parse_status, issue: signature.issue, coverage: result.coverage.state})); } finally { await unlink(file); } } JS ``` Both truncated cases reproduced in the run; the assertions above record current behavior. After correction, those two cases should report truncation instead. ## Expected behavior Report a truncated compressed integer for prefixes `80` and `c0` without all continuation bytes. Keep the malformed status and partial coverage. Preserve the reserved diagnostic for a genuinely reserved prefix such as `e0`. The [decoder's width masks and missing-byte diagnostic](https://github.com/morluto/rea/blob/3537e58c1ab29309f06eabf50bc52adba9817a0c/src/dotnet/ManagedMemberInspectorCore.ts#L256-L291) establish the distinction: `80` declares two bytes and `c0` declares four. The [heap-prefix decoder](https://github.com/morluto/rea/blob/3537e58c1ab29309f06eabf50bc52adba9817a0c/src/dotnet/ManagedMetadataHeaps.ts#L64-L108) also distinguishes missing declared bytes from reserved prefixes. This expectation concerns accurate diagnostic wording, with no change to rejection semantics. ## Impact and scope P3: misleading wording for malformed metadata. A caller investigating damaged signatures cannot distinguish missing continuation bytes from a reserved prefix using this diagnostic. The verified scope is MethodDef parameter counts in two small synthetic files. No incorrect decoded value, acceptance of malformed input, data loss, or target mutation was observed. Frequency in real assemblies is NOT_ENOUGH_INFO. No workaround is needed to retain correct rejection; no option producing corrected wording was established. ## REA version Package version 6.7.0, source main at `3537e58c1ab29309f06eabf50bc52adba9817a0c`. ## Runtime and platform Node.js v26.12.0; macOS 27.0.1; darwin arm64; repository-locked tsx 4.23.15. No external analysis engine was used. The exact repository-pinned Node.js 24.18.0 runtime was not exercised. ## Target and artifact context Source-owned synthetic PE/CLI fixture with a well-bounded blob heap item containing an internally truncated MethodDef signature. The hex strings in the reproduction are the entire method signatures. `00` is the default calling-convention header, followed by a compressed parameter count when present. ## Interface Other ## Earliest failure stage Native analysis or reconstruction ## Relevant output or evidence Observed output from the production workflow probe, which exited 0: ```json {"hex":"000001","provider":"rea-dotnet-static","status":"decoded","issue":null,"coverage":"complete"} {"hex":"00","provider":"rea-dotnet-static","status":"malformed","issue":"truncated compressed integer","coverage":"partial"} {"hex":"0080","provider":"rea-dotnet-static","status":"malformed","issue":"reserved compressed integer","coverage":"partial"} {"hex":"00c00000","provider":"rea-dotnet-static","status":"malformed","issue":"reserved compressed integer","coverage":"partial"} {"hex":"00e0","provider":"rea-dotnet-static","status":"malformed","issue":"reserved compressed integer","coverage":"partial"} ``` Source-derived path: the [method row reader](https://github.com/morluto/rea/blob/3537e58c1ab29309f06eabf50bc52adba9817a0c/src/dotnet/ManagedMemberRows.ts#L343-L372) obtains the bounded blob and retains its decoded signature. The [method-header reader](https://github.com/morluto/rea/blob/3537e58c1ab29309f06eabf50bc52adba9817a0c/src/dotnet/ManagedMemberInspectorCore.ts#L387-L400) consumes the compressed count; the [signature catch](https://github.com/morluto/rea/blob/3537e58c1ab29309f06eabf50bc52adba9817a0c/src/dotnet/ManagedMemberInspectorCore.ts#L795-L815) preserves the failure detail in the returned string field. ## Typed outcome or recovery expected Keep `signature.parse_status: "malformed"` and partial coverage, but return `signature.issue: "truncated compressed integer"` for `0080` and `00c00000`. The valid `000001` control should remain decoded, and `00e0` should retain the reserved-prefix diagnostic. ## Analysis or suspected cause Source-derived: the two- and four-byte branches require every continuation byte to exist. If the prefix declares one of those widths but bytes are missing, both branches fail and reach the shared `reserved compressed integer` throw. There is no separate truncation guard for those widths. The outer blob-length guard succeeds because the fixture's heap item itself is complete. ## Additional context The two decoder files have no diff between stable tag `rea-agents-6.7.0` and the tested main revision. Stable runtime reproduction is NOT_ENOUGH_INFO; source equality alone does not establish a tested release result. Other consumers of the integer helper were not separately exercised. No implementation or publication was performed.
Author
Owner

@XinwangTao commented on GitHub (Oct 19, 2026):

Confirmed — when a MethodDef signature ends inside a compressed parameter count, the truncated prefix is being typed as an integer-width prefix instead of reported as reserved/truncated, which makes the diagnostic misleading even though parse_status stays malformed.

Agree with #5133's direction of distinguishing truncated compressed signature integers. One suggestion: keep the malformed parse_status but make the issue message say "truncated compressed integer" explicitly rather than "reserved" — that way consumers can tell the signature was cut off mid-count instead of hitting an actually-reserved prefix, and coverage reporting can stay accurate.

<!-- gh-comment-id:6260282976 --> @XinwangTao commented on GitHub (Oct 19, 2026): Confirmed — when a MethodDef signature ends inside a compressed parameter count, the truncated prefix is being typed as an integer-width prefix instead of reported as reserved/truncated, which makes the diagnostic misleading even though parse_status stays malformed. Agree with #5133's direction of distinguishing truncated compressed signature integers. One suggestion: keep the malformed parse_status but make the issue message say "truncated compressed integer" explicitly rather than "reserved" — that way consumers can tell the signature was cut off mid-count instead of hitting an actually-reserved prefix, and coverage reporting can stay accurate.
Author
Owner

@morluto commented on GitHub (Oct 23, 2026):

Fixed in github.com/morluto/rea@db923eba44. The shared signature decoder preserves truncated versus reserved compressed-integer reasons. The executed managed compressed integer framing controls cover incomplete 80/c0 widths, complete widths, and reserved e0. This validates the reported diagnostic boundary; no new CLI/MCP run is claimed.

<!-- gh-comment-id:6376098327 --> @morluto commented on GitHub (Oct 23, 2026): Fixed in https://github.com/morluto/rea/commit/db923eba44f8703708c380966f3a7498db6fdd69. The shared signature decoder preserves truncated versus reserved compressed-integer reasons. The executed `managed compressed integer framing` controls cover incomplete 80/c0 widths, complete widths, and reserved e0. This validates the reported diagnostic boundary; no new CLI/MCP run is claimed.
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#3141
No description provided.