[wasm] reverse P/Invoke thunk key drops enclosing type for nested [UnmanagedCallersOnly] methods
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
## Summary
The CoreCLR wasm reverse-P/Invoke thunk table is keyed by
`{MethodName}#{argCount}:{AssemblyName}:{Namespace}:{TypeName}`. The key is produced on two sides that must agree:
- **Generator** — `src/tasks/WasmAppBuilder/coreclr/PInvokeCollector.cs`
- **Runtime lookup** — `src/coreclr/vm/wasm/helpers.cpp` (`GetHashCode` → `MethodTable::GetFullyQualifiedNameInfo` → `GetNameOfTypeDef`), which reads the namespace straight from ECMA-335 metadata.
For a **nested** type the metadata namespace is empty, and the key uses only the **simple** nested type name (the enclosing type chain is dropped on both sides). So two genuinely-distinct nested `[UnmanagedCallersOnly]` callbacks that share the same simple type name, method name, argument count, and assembly — but differ only by enclosing type/namespace — collapse to the **same key**, e.g.:
```
A.Outer+Callback.M -> M#0:MyAsm::Callback
B.Outer+Callback.M -> M#0:MyAsm::Callback // collides
```
## Current mitigation
The generator detects duplicate keys and fails the build loudly
(`PInvokeTableGenerator.cs`: *"Two callbacks with the same Name and number of arguments … are not supported"*), so this is a **build-time error, never a silent mis-dispatch**.
A recent fix (matching the generator's namespace to the runtime's metadata truth — empty namespace for nested types) made the nested-type key agree with the runtime lookup so nested `[UnmanagedCallersOnly]` callbacks resolve at all; before that they silently missed the lookup and asserted at `precode_portable.cpp:35`. See the CoreCLR-WASI library-test bring-up (#130129).
## Why this is acceptable for now
This name-hash reverse-thunk table is a wasm-interpreter bring-up mechanism and is expected to be **replaced once R2R can generate the reverse thunks directly**. Until then, the build-time collision error is sufficient — a program hitting it is rare and gets a clear diagnostic rather than incorrect behavior.
## Possible robust fix (if the generator persists)
Include the full enclosing-type chain in the key on **both** sides (generator + runtime `GetHashCode`) so nested types are fully disambiguated, and add a CoreCLR nested-type `[UnmanagedCallersOnly]` test (there is currently no nested-type coverage; `UnmanagedCallbackNamespaced` covers only top-level types on the Mono path).
> [!NOTE]
> This issue was filed with the assistance of GitHub Copilot.
Contributor guide
Assessment
This issue has not been assessed yet.