Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
neuecc opened this issue Nov 27, 2022 · 4 comments
Closed

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

neuecc opened this issue Nov 27, 2022 · 4 comments

Comments

@neuecc
Copy link

neuecc commented Nov 27, 2022

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

@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@ghost
Copy link

ghost commented Nov 27, 2022

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Issue Details

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

Author: neuecc
Assignees: -
Labels:

untriaged, area-NativeAOT-coreclr

Milestone: -

@MichalStrehovsky
Copy link
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.

@MichalStrehovsky MichalStrehovsky closed this as not planned Won't fix, can't repro, duplicate, stale Nov 28, 2022
@ghost ghost removed the untriaged New issue has not been triaged by the area owner label Nov 28, 2022
@neuecc
Copy link
Author

neuecc commented Nov 28, 2022

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

@ghost ghost locked as resolved and limited conversation to collaborators Dec 28, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants