You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On wasm (CoreCLR interpreter + R2R, FEATURE_PORTABLE_ENTRYPOINTS), reflection-invoking a generic method instantiated over a reference type (a shared __Canon instantiation) crashes. The same generic method instantiated over a value type (an exact instantiation) works.
This is the root cause of several of the "silent" browser-lane crashes seen when enabling R2R for browser/wasm CoreCLR (#129634) — assemblies that abort during xUnit test execution with WASM EXIT 1 and no [FAIL] (e.g. System.IO.Compression.Tests, System.IO.Compression.ZipFile.Tests, System.Text.RegularExpressions.Tests, Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests). xUnit invokes every test method via reflection, so a shared-generic test method (or shared-generic xUnit machinery) trips this.
Repro
Minimal repro in src/mono/sample/wasm/console-node (the sample assembly is R2R-compiled via <WasmReadyToRunAssembly Include="$(AssemblyName)"/>):
Output (the process aborts at the reference-type instantiation; run node main.mjs directly on the bundle for per-line output, since the abort drops buffered stdout):
Hello World!
VALUE:
n:Int32
REF:
The discriminator is purely the generic argument: value type (exact) passes, reference type (shared __Canon) crashes — same method, same call site.
It is not virtual-specific: a generic virtual method (GVM) shows the same pattern (VirtGen<int> ok, VirtGen<string> / VirtGen<Tuple<decimal,string>> crash).
Observed failure
Two manifestations of the same corruption were observed (Debug runtime):
Compression test (Chrome console) — a MethodTableSanityCheck assert during generic-virtual dispatch reached from reflection invoke:
Sample probe (Node) — a NullReferenceException inside the invoke machinery:
Unhandled exception. System.NullReferenceException
at System.Runtime.CompilerServices.RuntimeHelpers.GetMethodTable(Object obj)
at <reflection invoke>
Both point at a corrupt / null MethodTable (or generic context) being produced when reflection resolves a shared-generic (__Canon) method instantiation under R2R.
In Release (CI) there is no SanityCheck assert, so the corrupt MethodTable proceeds and eventually causes a hard wasm abort — surfacing as the opaque WASM EXIT 1 with no [FAIL]. (The dotnet console redirect / helix wasm-console.log does not capture the wasm error; only the browser's JS error console does.)
Why this is R2R-related
On main (CoreCLR + browser + interpreter, no R2R) the full library test suite is green (CI build 1478862: totalTests=78361, failedTests=0), and shared-generic reflection invoke is pervasive in xUnit. R2R is the delta in #129634. Likely tied to the generic-dictionary / generic-context R2R area on wasm (see #129821).
Related: #129766, #129808 (reflection invoke of R2R methods), #129821 (generic-lookup null function), #129857 (UnmanagedCallersOnly function pointers). Discovered while bringing up R2R for browser/wasm CoreCLR (#129634).
Note
This issue was authored with the assistance of GitHub Copilot.
Summary
On wasm (CoreCLR interpreter + R2R,
FEATURE_PORTABLE_ENTRYPOINTS), reflection-invoking a generic method instantiated over a reference type (a shared__Canoninstantiation) crashes. The same generic method instantiated over a value type (an exact instantiation) works.This is the root cause of several of the "silent" browser-lane crashes seen when enabling R2R for browser/wasm CoreCLR (#129634) — assemblies that abort during xUnit test execution with
WASM EXIT 1and no[FAIL](e.g.System.IO.Compression.Tests,System.IO.Compression.ZipFile.Tests,System.Text.RegularExpressions.Tests,Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests). xUnit invokes every test method via reflection, so a shared-generic test method (or shared-generic xUnit machinery) trips this.Repro
Minimal repro in
src/mono/sample/wasm/console-node(the sample assembly is R2R-compiled via<WasmReadyToRunAssembly Include="$(AssemblyName)"/>):Build & run:
Output (the process aborts at the reference-type instantiation; run
node main.mjsdirectly on the bundle for per-line output, since the abort drops buffered stdout):The discriminator is purely the generic argument: value type (exact) passes, reference type (shared
__Canon) crashes — same method, same call site.It is not virtual-specific: a generic virtual method (GVM) shows the same pattern (
VirtGen<int>ok,VirtGen<string>/VirtGen<Tuple<decimal,string>>crash).Observed failure
Two manifestations of the same corruption were observed (Debug runtime):
Compression test (Chrome console) — a
MethodTableSanityCheckassert during generic-virtual dispatch reached from reflection invoke:Sample probe (Node) — a
NullReferenceExceptioninside the invoke machinery:Both point at a corrupt / null
MethodTable(or generic context) being produced when reflection resolves a shared-generic (__Canon) method instantiation under R2R.In Release (CI) there is no
SanityCheckassert, so the corruptMethodTableproceeds and eventually causes a hard wasm abort — surfacing as the opaqueWASM EXIT 1with no[FAIL]. (The dotnet console redirect / helixwasm-console.logdoes not capture the wasm error; only the browser's JS error console does.)Why this is R2R-related
On
main(CoreCLR + browser + interpreter, no R2R) the full library test suite is green (CI build 1478862:totalTests=78361, failedTests=0), and shared-generic reflection invoke is pervasive in xUnit. R2R is the delta in #129634. Likely tied to the generic-dictionary / generic-context R2R area on wasm (see #129821).Environment
dotnet/runtimePR [browser][coreCLR] browserhost to load R2R #129634 branch, commit93ef88f0137fec51588fa891bd0e13b0bf1f70f0browser-wasm, CoreCLR interpreter + R2R,FEATURE_PORTABLE_ENTRYPOINTSRelated: #129766, #129808 (reflection invoke of R2R methods), #129821 (generic-lookup
null function), #129857 (UnmanagedCallersOnly function pointers). Discovered while bringing up R2R for browser/wasm CoreCLR (#129634).Note
This issue was authored with the assistance of GitHub Copilot.