Skip to content

[wasm] crossgen2 crashes in getMethodNameFromMetadata for RuntimeTypeHandle.ToIntPtr(typeof(T[]).TypeHandle) in shared generic code #132505

Description

@pavelsavara

Description

When producing the browser-wasm framework ReadyToRun images, crossgen2 crashes while compiling System.Linq.Parallel. The failing method is the shared-generic instantiation:

[S.P.CoreLib]System.GC.<AllocateUninitializedArray>g__AllocateNewArrayWorker|77_0<Pair`2<float64,int64>>(int32,bool)

(and the same for Pair<int64,int64>), which come from System.Linq.Parallel.

The Exec of crossgen2 exits with -532462766 (0xE0434352, unhandled managed exception), reported as MSB3073 from Microsoft.NETCore.App.Runtime.CoreCLR.sfxproj (_CrossgenBrowserFrameworkR2R).

Exception

Unhandled exception. ILCompiler.CodeGenerationFailedException: Code generation failed for method
  '[S.P.CoreLib]System.GC.<AllocateUninitializedArray>g__AllocateNewArrayWorker|77_0<Pair`2<float64,int64>>(int32,bool)'
 ---> System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
   at Internal.JitInterface.CorInfoImpl.HandleToObject(Void* handle) in CorInfoImpl.cs:line 767
   at Internal.JitInterface.CorInfoImpl.getMethodNameFromMetadata(...) in CorInfoImpl.cs:line 3920
   --- End of inner exception stack trace ---
   at Internal.JitInterface.CorInfoImpl.CompileMethodInternal(...) in CorInfoImpl.cs:line 375
   at ILCompiler.ReadyToRunCodegenCompilation...CompileOneMethod(...)

Steps to reproduce

Build the browser-wasm CoreCLR runtime pack (Release), which runs the framework R2R crossgen step:

.\build.cmd -os browser -subset clr+libs+host -c Release /p:RuntimeFlavor=CoreCLR

The crash happens deterministically when crossgen2 compiles System.Linq.Parallel.wasm. The crossgen2 invocation is roughly:

crossgen2.exe -o:...\framework-r2r\System.Linq.Parallel.wasm
  -r:...\lib\net11.0\*.dll -r:...\System.Private.CoreLib.dll
  "--opt-cross-module:*" --targetarch:wasm --targetos:browser --obj-format:wasm
  --codegenopt:JitWasmNyiToR2RUnsupported=1 --codegenopt:JitWasmSimdNyiToR2RUnsupported=1
  -O ...\lib\net11.0\System.Linq.Parallel.dll

Root cause (confirmed via instrumentation)

The crash is in the JIT importer, not the wasm codegen backend. Compiler::lookupNamedIntrinsic (src/coreclr/jit/importercalls.cpp) is invoked with a null method handle (CORINFO_METHOD_HANDLE/gtCallMethHnd == NO_METHOD_HANDLE, e.g. an indirect call). It passes that handle straight to info.compCompHnd->getMethodNameFromMetadata(method, ...); on the crossgen2 side that does HandleToObject(ftn)_handleToObject[index] with index = ((int)ftn - handleBase) / handleMultiplier. For ftn == 0 this is a large negative index → ArgumentOutOfRangeException.

Instrumenting crossgen2's getMethodNameFromMetadata confirmed the handle value:

AGENT_DEBUG getMethodNameFromMetadata bad ftn=0x0 odd=0 idx=-540672 count=3866

Returning early from that callback then surfaced a second, identical trap on the same null handle at the lookupNamedIntrinsic fallback info.compCompHnd->getArrayIntrinsicID(method) (CorInfoImpl.cs getArrayIntrinsicID), proving the bad caller is lookupNamedIntrinsic itself.

lookupNamedIntrinsic has ~30 call sites, several of which pass call->gtCallMethHnd on arbitrary calls (including indirect calls with NO_METHOD_HANDLE, and helper calls whose handle is the odd-encoded eeFindHelper value). The wasm framework bubble compiles the shared-generic value-type instantiation AllocateUninitializedArray<Pair<double,long>> (--opt-cross-module:*) where the typeof(T[]) / array-handling tree reaches one of these sites with a null handle. The bug is latent on other targets that don't compile this exact tree shape.

Fix (validated)

Guard lookupNamedIntrinsic to return NI_Illegal for a null or helper handle (neither is ever a named intrinsic), which protects every call site:

NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
{
    if ((method == NO_METHOD_HANDLE) || (eeGetHelperNum(method) != CORINFO_HELP_UNDEF))
    {
        return NI_Illegal;
    }
    ...

Validated: with this guard in the rebuilt clrjit_universal_wasm_x64, crossgen2 compiles System.Linq.Parallel.wasm successfully (R2R image emitted, exit 0) instead of crashing.

Note

This issue text was generated with the assistance of GitHub Copilot.

Metadata

Metadata

Assignees

No one assigned

    Labels

    arch-wasmWebAssembly architecturearea-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIuntriagedNew issue has not been triaged by the area owner

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions