Skip to content

Generic virtual method pointer lookup failure in .NET 7 Native AOT #78882

Closed as not planned

Description

@neuecc

Description

Following reproduction code crashes after publishing and running the AOT executable.
Code includes static abstract members, generics.

Reproduction Steps

create .NET 7 ConsoleApp project

csproj

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net7.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>

        <PublishAot>true</PublishAot>
        <SelfContained>true</SelfContained>
        <IlcOptimizationPreference>Speed</IlcOptimizationPreference>
        <IlcOptimizationPreference>Size</IlcOptimizationPreference>
        <IlcFoldIdenticalMethodBodies>true</IlcFoldIdenticalMethodBodies>
    </PropertyGroup>

</Project>

Program.cs

using System.Buffers;

// require this unused line for reproduce error?
var bufferWriter = new ArrayBufferWriter<byte>();

var mc = new MemPackObject();

var formatter = new MemoryPackableFormatter2<MemPackObject>();
formatter.Serialize<ArrayBufferWriter<byte>>(ref mc);


public interface IMemoryPackable2<T>
{
    static abstract void Serialize<TBufferWriter>(scoped ref T? value)
        where TBufferWriter : IBufferWriter<byte>;
}

public interface IMemoryPackFormatter2<T>
{
    void Serialize<TBufferWriter>(scoped ref T? value)
        where TBufferWriter : IBufferWriter<byte>;
}

public abstract class MemoryPackFormatter2<T> : IMemoryPackFormatter2<T>
{
    public abstract void Serialize<TBufferWriter>(scoped ref T? value)
        where TBufferWriter : IBufferWriter<byte>;
}

public sealed class MemoryPackableFormatter2<T> : MemoryPackFormatter2<T>
    where T : IMemoryPackable2<T>
{
    public override void Serialize<TBufferWriter>(scoped ref T? value)
    {
        Console.WriteLine("Before");
        T.Serialize<TBufferWriter>(ref value);
        Console.WriteLine("After");
    }
}

public class MemPackObject : IMemoryPackable2<MemPackObject>
{
    public static void Serialize<TBufferWriter>(scoped ref MemPackObject? value)
          where TBufferWriter : IBufferWriter<byte>
    {
        Console.WriteLine("OK");
    }
}

command

dotnet publish
execute published .exe

Expected behavior

Run successfully, console logged "OK".

Actual behavior

Process terminated. Generic virtual method pointer lookup failure.

Declaring type handle: MethodTable:0x00007FF76B94D6C8
Target type handle: MethodTable:0x00007FF76B94D720
Method name: Serialize
Instantiation:
  Argument 00000000: MethodTable:0x00007FF76B956030

image

Regression?

No response

Known Workarounds

No response

Configuration

  • .NET 7.0.100
  • Windows 10 Pro
  • x64 CPU(AMD Ryzen 5950X)

Other information

Originally, I've received from my library's issue.
Cysharp/MemoryPack#75

I've found other Generic virtual method pointer lookup failure issue in bug-report.
Therefore, I am reporting this because I think this may be a bug in native-aot.
#70878

Activity

  1. ghost added
    untriagedNew issue has not been triaged by the area owner
    on Nov 27, 2022
  2. MichalStrehovsky commented on Nov 28, 2022

    @MichalStrehovsky
    Member

    This is a duplicate of #77070.

    Unfortunately, static or instance generic virtual method dispatch (call into MemoryPackableFormatter2.Serialize) that lands in a method that does another static generic virtual method dispatch (call into IMemoryPackable2<T>.Serialize) directly or from its generic closure runs into an issue where we're not able to compute the target of the second dispatch.

    The workaround is to tell the compiler manually that the target needs to be generated. It is not pretty. Pull request #78904 adds support for at least telling what needs to be pregenerated and I'm hoping we can service that part in January for 7.0.

    It's likely the root cause of the problem will only be fixed in 8.0. Sorry, it's a very risky fix.

  3. ghost removed
    untriagedNew issue has not been triaged by the area owner
    on Nov 28, 2022
  4. neuecc commented on Nov 28, 2022

    @neuecc
    Author

    Thanks for the details!
    It seems difficult to work around in code, so I will wait for 8.0.

  5. ghost locked as resolved and limited conversation to collaborators on Dec 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions