[PR #6877] [CLOSED] fix(managed): derive P/Invoke suffix candidates for default and Auto charsets #7429

Closed
opened 2026-11-01 21:47:48 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/6877
Author: @AmmarJamil23
Created: 10/23/2026
Status: ❌ Closed

Base: main ← Head: fix/pinvoke-charset-candidates


📝 Commits (1)

  • 3d1a2cd fix(managed): derive P/Invoke suffix candidates for default and Auto charsets

📊 Changes

3 files changed (+85 additions, -6 deletions)

View changed files

📝 docs/managed-code-analysis.md (+8 -0)
📝 src/domain/managed/managedNativeVerificationMatch.ts (+22 -4)
📝 tests/conformance/providers/managed/managedNativeVerification.test.ts (+55 -2)

📄 Description

Summary

Fixes #6857.

verify-managed-native-boundaries added the A/W entry-point suffix candidate only for an explicit ansi or unicode charset. A default (not-specified) P/Invoke declaration behaves as ANSI, and Auto means Unicode on Windows, so their conventional decorated exports (ExampleA, ExampleW) were dropped and verification reported unresolved / no-native-candidate. They are now retained as inferred / decorated-name-candidate, the same as the explicit-charset controls.

Problem and expected behavior

Smallest trigger: a P/Invoke Example in example.dll with mapping flags 0x0200 (charset unspecified, ExactSpelling false) and supplied PE function Evidence named ExampleA. Before: unresolved, no-native-candidate, no candidates; explicit ANSI (0x0202) returned inferred with ExampleA. Same pattern for Auto (0x0206) with ExampleW versus explicit Unicode.

Expected (per the issue and Microsoft's Charsets and marshalling / Specifying a character set): the default charset probes the A name, Auto probes W on Windows, and ExactSpelling suppresses suffixes. This stays a static candidate inference, not proof of binding.

Change and scope

The charset parser already preserved not-specified and auto correctly; the gap was in candidate enumeration (candidateNames in src/domain/managed/managedNativeVerificationMatch.ts). It now resolves an effective charset per native module:

  • not-specified → ANSI (adds A) for every module format;
  • auto → Unicode (adds W) when the supplied native Evidence's module format is pe, and unknown (no suffix candidate) for other formats, because Auto means UTF-8 off Windows and the supplied Evidence does not establish suffix probing there;
  • ansi/unicode and ExactSpelling (no_mangle) behave exactly as before.

Candidates are computed per native symbol, since only the symbol's Evidence knows its module format; the existing moduleFormatsByEvidenceId map already carried that fact. docs/managed-code-analysis.md now states the entry-point rule next to the existing module-name rules.

Not changed: stdcall _Name@N decorations, module matching, and verification status semantics.

Contribution scope: ordinary correctness fix within the existing static-verification boundary; no scope decision needed.

Contract and boundary impact

  • Semantic owner and earliest changed stage: P/Invoke candidate enumeration in managedNativeVerificationMatch.ts.
  • Contribution scope fit and linked maintainer decision: not applicable.
  • CLI and MCP/tool-catalog contract: no schema change; affected declarations now return the existing inferred / decorated-name-candidate state.
  • Provider, bridge, target-format, or platform compatibility: the Auto suffix applies only to PE modules; ELF, Mach-O and unknown formats get no Auto suffix candidate.
  • Evidence, artifact, provenance, or reconstruction contract: unchanged; matches remain inferences with the supplied native Evidence retained.
  • Target selection, authority, upstream behavior, and cleanup details: not applicable.
  • Generated metadata, package, or installation impact: none; npm run docs:check passed with no generated changes.

Evidence and regression coverage

  • Tests added or updated: tests/conformance/providers/managed/managedNativeVerification.test.ts, with 10 table cases covering default/ANSI/Unicode/Auto on PE and ELF, wrong-suffix controls, and ExactSpelling suppression. The nativeFunctionEvidence helper takes a function name, and inputWithImportScope takes a charset/ExactSpelling override.
  • Base reproduction: with the src/ change stashed, exactly the 3 bug cases fail (default→A on PE, default→A on ELF, Auto→W on PE); the 7 controls pass on both revisions.
  • Public CLI: the issue's six-case verify-managed-native-boundaries script (adapted for a Windows host), run with the fix: default-ansi-suffix and auto-unicode-suffix now return inferred / decorated-name-candidate with ExampleA / ExampleW; explicit controls unchanged; auto-exact-control stays verified / exact-function-name; exactspelling-control stays unresolved / no-native-candidate.
  • Real Windows binding behavior (supports the rule; not committed). The issue notes it did not run a live Windows binding test, so I ran DllImport probes on Windows 11 x64 (.NET Framework 4.8 via PowerShell Add-Type) against system DLLs:
    • shell32!CommandLineToArgv, which is exported only as CommandLineToArgvW: Auto and Unicode bind; default, Ansi, and Auto + ExactSpelling throw EntryPointNotFoundException.
    • kernel32!GetModuleHandle, which is exported only as GetModuleHandleA / GetModuleHandleW: the default charset binds (so it resolves GetModuleHandleA, since the default never probed W above); default + ExactSpelling throws EntryPointNotFoundException.
  • Remaining proof gaps: modern .NET (Core) on Windows was not probed live (Microsoft documents the same name matching); non-Windows Auto behavior is deliberately left unknown rather than asserted.

Validation performed

Windows 11 x64, Node.js 24.22.1 (pinned), locked dependencies.

  • npm run test:focused -- tests/conformance/providers/managed/managedNativeVerification.test.ts — 30/30 passed; with src/ stashed, 3 failed / 27 passed (the three bug cases).
  • npm run test:focused -- tests/boundary/mcp/managedNativeVerificationAdapters.test.ts tests/boundary/mcp/outputSchemaSemanticConstraints.test.ts — 4/4 passed.
  • npm run build:cached then the issue's CLI reproduction — results above.
  • npm run check:fast — passed.
  • npm run docs:check — passed; no generated changes.

Compatibility, safety, and release

  • Breaking changes or migration steps: none. Some declarations that previously reported unresolved / no-native-candidate now report inferred / decorated-name-candidate.
  • Real Hopper/Ghidra, browser, or OS coverage: Windows binding probes only (above); no native analysis engine involved.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: static metadata comparison only; no target is loaded or executed.

Author readiness

Human owner: @AmmarJamil23

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • 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.

🤖 Generated with Claude Code


🔄 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/6877 **Author:** [@AmmarJamil23](https://github.com/AmmarJamil23) **Created:** 10/23/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/pinvoke-charset-candidates` --- ### 📝 Commits (1) - [`3d1a2cd`](https://github.com/morluto/rea/commit/3d1a2cd39ed021e26cd4401c82d4f5602b923281) fix(managed): derive P/Invoke suffix candidates for default and Auto charsets ### 📊 Changes **3 files changed** (+85 additions, -6 deletions) <details> <summary>View changed files</summary> 📝 `docs/managed-code-analysis.md` (+8 -0) 📝 `src/domain/managed/managedNativeVerificationMatch.ts` (+22 -4) 📝 `tests/conformance/providers/managed/managedNativeVerification.test.ts` (+55 -2) </details> ### 📄 Description ## Summary Fixes #6857. `verify-managed-native-boundaries` added the `A`/`W` entry-point suffix candidate only for an explicit `ansi` or `unicode` charset. A default (`not-specified`) P/Invoke declaration behaves as ANSI, and `Auto` means Unicode on Windows, so their conventional decorated exports (`ExampleA`, `ExampleW`) were dropped and verification reported `unresolved / no-native-candidate`. They are now retained as `inferred / decorated-name-candidate`, the same as the explicit-charset controls. ## Problem and expected behavior Smallest trigger: a P/Invoke `Example` in `example.dll` with mapping flags `0x0200` (charset unspecified, ExactSpelling false) and supplied PE function Evidence named `ExampleA`. Before: `unresolved`, `no-native-candidate`, no candidates; explicit ANSI (`0x0202`) returned `inferred` with `ExampleA`. Same pattern for `Auto` (`0x0206`) with `ExampleW` versus explicit Unicode. Expected (per the issue and Microsoft's [Charsets and marshalling](https://learn.microsoft.com/en-us/dotnet/standard/native-interop/charset) / [Specifying a character set](https://learn.microsoft.com/en-us/dotnet/standard/native-interop/specifying-a-character-set)): the default charset probes the `A` name, `Auto` probes `W` on Windows, and ExactSpelling suppresses suffixes. This stays a static candidate inference, not proof of binding. ## Change and scope The charset parser already preserved `not-specified` and `auto` correctly; the gap was in candidate enumeration (`candidateNames` in `src/domain/managed/managedNativeVerificationMatch.ts`). It now resolves an effective charset per native module: - `not-specified` → ANSI (adds `A`) for every module format; - `auto` → Unicode (adds `W`) when the supplied native Evidence's module format is `pe`, and `unknown` (no suffix candidate) for other formats, because `Auto` means UTF-8 off Windows and the supplied Evidence does not establish suffix probing there; - `ansi`/`unicode` and ExactSpelling (`no_mangle`) behave exactly as before. Candidates are computed per native symbol, since only the symbol's Evidence knows its module format; the existing `moduleFormatsByEvidenceId` map already carried that fact. `docs/managed-code-analysis.md` now states the entry-point rule next to the existing module-name rules. Not changed: stdcall `_Name@N` decorations, module matching, and verification status semantics. Contribution scope: ordinary correctness fix within the existing static-verification boundary; no scope decision needed. ## Contract and boundary impact - Semantic owner and earliest changed stage: P/Invoke candidate enumeration in `managedNativeVerificationMatch.ts`. - Contribution scope fit and linked maintainer decision: not applicable. - CLI and MCP/tool-catalog contract: no schema change; affected declarations now return the existing `inferred / decorated-name-candidate` state. - Provider, bridge, target-format, or platform compatibility: the `Auto` suffix applies only to PE modules; ELF, Mach-O and unknown formats get no `Auto` suffix candidate. - Evidence, artifact, provenance, or reconstruction contract: unchanged; matches remain inferences with the supplied native Evidence retained. - Target selection, authority, upstream behavior, and cleanup details: not applicable. - Generated metadata, package, or installation impact: none; `npm run docs:check` passed with no generated changes. ## Evidence and regression coverage - Tests added or updated: `tests/conformance/providers/managed/managedNativeVerification.test.ts`, with 10 table cases covering default/ANSI/Unicode/Auto on PE and ELF, wrong-suffix controls, and ExactSpelling suppression. The `nativeFunctionEvidence` helper takes a function name, and `inputWithImportScope` takes a charset/ExactSpelling override. - Base reproduction: with the `src/` change stashed, exactly the 3 bug cases fail (default→`A` on PE, default→`A` on ELF, Auto→`W` on PE); the 7 controls pass on both revisions. - Public CLI: the issue's six-case `verify-managed-native-boundaries` script (adapted for a Windows host), run with the fix: `default-ansi-suffix` and `auto-unicode-suffix` now return `inferred / decorated-name-candidate` with `ExampleA` / `ExampleW`; explicit controls unchanged; `auto-exact-control` stays `verified / exact-function-name`; `exactspelling-control` stays `unresolved / no-native-candidate`. - Real Windows binding behavior (supports the rule; not committed). The issue notes it did not run a live Windows binding test, so I ran `DllImport` probes on Windows 11 x64 (.NET Framework 4.8 via PowerShell `Add-Type`) against system DLLs: - `shell32!CommandLineToArgv`, which is exported only as `CommandLineToArgvW`: `Auto` and `Unicode` bind; default, `Ansi`, and `Auto` + ExactSpelling throw `EntryPointNotFoundException`. - `kernel32!GetModuleHandle`, which is exported only as `GetModuleHandleA` / `GetModuleHandleW`: the default charset binds (so it resolves `GetModuleHandleA`, since the default never probed `W` above); default + ExactSpelling throws `EntryPointNotFoundException`. - Remaining proof gaps: modern .NET (Core) on Windows was not probed live (Microsoft documents the same name matching); non-Windows `Auto` behavior is deliberately left unknown rather than asserted. ## Validation performed Windows 11 x64, Node.js 24.22.1 (pinned), locked dependencies. - `npm run test:focused -- tests/conformance/providers/managed/managedNativeVerification.test.ts` — 30/30 passed; with `src/` stashed, 3 failed / 27 passed (the three bug cases). - `npm run test:focused -- tests/boundary/mcp/managedNativeVerificationAdapters.test.ts tests/boundary/mcp/outputSchemaSemanticConstraints.test.ts` — 4/4 passed. - `npm run build:cached` then the issue's CLI reproduction — results above. - `npm run check:fast` — passed. - `npm run docs:check` — passed; no generated changes. ## Compatibility, safety, and release - Breaking changes or migration steps: none. Some declarations that previously reported `unresolved / no-native-candidate` now report `inferred / decorated-name-candidate`. - Real Hopper/Ghidra, browser, or OS coverage: Windows binding probes only (above); no native analysis engine involved. - Package or release metadata impact: none. - Security, privacy, process, or containment review: static metadata comparison only; no target is loaded or executed. ## Author readiness Human owner: @AmmarJamil23 - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [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. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-11-01 21:47:48 +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#7429
No description provided.