Skip to content

JIT: Illegal reordering of null check with argument evaluation for GVMs #121711

@jakobbotsch

Description

@jakobbotsch

The following program should print "Printed!", then throw NRE. However it does not print anything.

using System;
using System.Runtime.CompilerServices;

public class Program
{
    public static void Main()
    {
        Test(null);
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    private static void Test(Base b)
    {
        b.Foo<string>(Bar());
    }

    private static int Bar()
    {
        Console.WriteLine("Printed!");
        return 42;
    }
}

public abstract class Base
{
    public abstract void Foo<T>(int x);
}

public class Derived : Base
{
    public override void Foo<T>(int x)
    {
    }
}

The cause is the following code that spills the function pointer after having popped the arguments into the call:

// Now make an indirect call through the function pointer
unsigned lclNum = lvaGrabTemp(true DEBUGARG("VirtualCall through function pointer"));
impStoreToTemp(lclNum, fptr, CHECK_SPILL_ALL);
fptr = gtNewLclvNode(lclNum, TYP_I_IMPL);

This reorders the evaluation of the function pointer with the arguments. Evaluating the function pointer for GVMs results in a null check.

Metadata

Metadata

Assignees

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions