[GH-ISSUE #6513] [Bug] Managed member comparison ignores a change in locals-signature presence #3905

Closed
opened 2026-10-31 00:45:07 +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/6513

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: compare_managed_members can classify a method as unchanged when one inspected fat method header has no local-variable signature (local_var_sig_token: null) and the other has a local-variable signature. The producer retains this difference, but the comparison checks only max_stack and init_locals among header fields. Neither CIL digest includes the header or locals, so equal instruction bytes do not expose the change through another dimension.

No REA runtime reproduction was performed. This report describes the current source path, not measured CLR behavior.

Reproduction

Actually performed: inspected the producer, comparison, status selection, and documented digest boundaries at the source revision below.

Proposed integration case, not run:

  1. Create two valid PE/CLI fixtures with the same declared method signature, flags, max_stack, init_locals, and CIL ret instruction. Use a fat header with LocalVarSigTok zero on the left and a valid StandAloneSig for one unused local on the right.
  2. Inspect both with inspect_managed_members and compare them with compare_managed_members.
  3. Check the retained body.local_var_sig_token and the comparison method's status and dimensions.

NOT_ENOUGH_INFO: runtime output and reproduction frequency were not collected.

Expected behavior

An observed transition between no locals signature and a declared locals signature should remain visible as a static metadata difference, rather than yielding an unqualified unchanged method. This does not require comparing build-local token numbers across builds or claiming a runtime behavior change. If locals are intentionally outside comparison, explicitly report that coverage limitation.

The method metadata comparison contract says identical instructions do not establish unchanged method metadata. The digest boundary table expressly excludes headers and locals from the CIL hashes.

Impact and scope

The source-derived scope is a locals-signature presence change in an otherwise matching, completely decoded method. The comparison can hide an independently retained static difference. No runtime consequences or real-world frequency were measured.

Manual comparison of the two inspections' local_var_sig_token values can reveal presence versus absence; token-number differences alone are not cross-build identity evidence. This workaround is source-derived and was not executed.

REA version

Main source revision 49c9c9d4a14cc7d5509ec28a304dab48f85cb045 (package metadata says 6.7.0). The omission also exists in the source of latest published tag rea-agents-6.7.0; the packaged runtime was not executed.

Runtime and platform

Source review on Linux x64 with Node.js v26.12.1. No .NET runtime or external provider was used. Runtime platform reach is untested.

Target and artifact context

PE/CLI managed methods with valid fat method headers; the proposed pair differs in locals-signature presence and retains equal raw CIL bytes.

Interface

Other

Shared comparison logic used by CLI and MCP; neither adapter was executed for this report.

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

Source evidence only:

The relevant omission is:

const headerFields = ["max_stack", "init_locals"] as const;

NOT_ENOUGH_INFO: no executed comparison JSON is available.

Additional context

Related closed report #3348 addressed init_locals and max_stack; current main compares both. This report concerns the still-omitted presence of a local-variable signature, not a claim those fixed fields remain broken. Open and closed searches for local_var_sig_token, local signature, and managed locals found no matching report.

Triage assessment

  • Impact level: P2
  • Assessment status: provisional
  • Impact basis: The comparison source can suppress an observed locals-signature presence difference and report an unchanged method; runtime occurrence and frequency were not measured.
  • Workaround status: unverified
  • Workaround basis: The inspection producer retains null versus a token, allowing manual comparison of signature presence, but that workflow was not executed in this audit.
Originally created by @coygeek on GitHub (Oct 23, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6513 ### 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: `compare_managed_members` can classify a method as `unchanged` when one inspected fat method header has no local-variable signature (`local_var_sig_token: null`) and the other has a local-variable signature. The producer retains this difference, but the comparison checks only `max_stack` and `init_locals` among header fields. Neither CIL digest includes the header or locals, so equal instruction bytes do not expose the change through another dimension. No REA runtime reproduction was performed. This report describes the current source path, not measured CLR behavior. ### Reproduction Actually performed: inspected the producer, comparison, status selection, and documented digest boundaries at the source revision below. Proposed integration case, not run: 1. Create two valid PE/CLI fixtures with the same declared method signature, flags, `max_stack`, `init_locals`, and CIL `ret` instruction. Use a fat header with LocalVarSigTok zero on the left and a valid StandAloneSig for one unused local on the right. 2. Inspect both with `inspect_managed_members` and compare them with `compare_managed_members`. 3. Check the retained `body.local_var_sig_token` and the comparison method's status and dimensions. `NOT_ENOUGH_INFO`: runtime output and reproduction frequency were not collected. ### Expected behavior An observed transition between no locals signature and a declared locals signature should remain visible as a static metadata difference, rather than yielding an unqualified unchanged method. This does not require comparing build-local token numbers across builds or claiming a runtime behavior change. If locals are intentionally outside comparison, explicitly report that coverage limitation. The [method metadata comparison contract](https://github.com/morluto/rea/blob/49c9c9d4a14cc7d5509ec28a304dab48f85cb045/docs/managed-code-analysis.md#method-metadata-during-build-comparison) says identical instructions do not establish unchanged method metadata. The [digest boundary table](https://github.com/morluto/rea/blob/49c9c9d4a14cc7d5509ec28a304dab48f85cb045/docs/managed-code-analysis.md#decoded-cil-fingerprint) expressly excludes headers and locals from the CIL hashes. ### Impact and scope The source-derived scope is a locals-signature presence change in an otherwise matching, completely decoded method. The comparison can hide an independently retained static difference. No runtime consequences or real-world frequency were measured. Manual comparison of the two inspections' `local_var_sig_token` values can reveal presence versus absence; token-number differences alone are not cross-build identity evidence. This workaround is source-derived and was not executed. ### REA version Main source revision `49c9c9d4a14cc7d5509ec28a304dab48f85cb045` (package metadata says 6.7.0). The omission also exists in the source of latest published tag `rea-agents-6.7.0`; the packaged runtime was not executed. ### Runtime and platform Source review on Linux x64 with Node.js v26.12.1. No .NET runtime or external provider was used. Runtime platform reach is untested. ### Target and artifact context PE/CLI managed methods with valid fat method headers; the proposed pair differs in locals-signature presence and retains equal raw CIL bytes. ### Interface Other Shared comparison logic used by CLI and MCP; neither adapter was executed for this report. ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence Source evidence only: - [Producer retains LocalVarSigTok as null or a token](https://github.com/morluto/rea/blob/49c9c9d4a14cc7d5509ec28a304dab48f85cb045/src/dotnet/ManagedMethodBodyReader.ts#L162-L176). - [Comparison enumerates only max_stack and init_locals, then checks instruction and exception facets](https://github.com/morluto/rea/blob/49c9c9d4a14cc7d5509ec28a304dab48f85cb045/src/domain/managed/managedMemberComparisonItems.ts#L61-L123). - [No observed dimension and no unknown flag becomes unchanged](https://github.com/morluto/rea/blob/49c9c9d4a14cc7d5509ec28a304dab48f85cb045/src/domain/managed/managedMemberComparisonItems.ts#L446-L463). - [Existing comparison limitations name excluded literals and exported types but omit locals](https://github.com/morluto/rea/blob/49c9c9d4a14cc7d5509ec28a304dab48f85cb045/src/domain/managed/managedMemberComparisonCoverage.ts#L151-L165). The relevant omission is: ```ts const headerFields = ["max_stack", "init_locals"] as const; ``` `NOT_ENOUGH_INFO`: no executed comparison JSON is available. ### Additional context Related closed report [#3348](https://github.com/morluto/rea/issues/3348) addressed `init_locals` and `max_stack`; current main compares both. This report concerns the still-omitted presence of a local-variable signature, not a claim those fixed fields remain broken. Open and closed searches for `local_var_sig_token`, `local signature`, and managed locals found no matching report. ## Triage assessment - Impact level: P2 - Assessment status: provisional - Impact basis: The comparison source can suppress an observed locals-signature presence difference and report an unchanged method; runtime occurrence and frequency were not measured. - Workaround status: unverified - Workaround basis: The inspection producer retains null versus a token, allowing manual comparison of signature presence, but that workflow was not executed in this audit.
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#3905
No description provided.