Skip to content

[mono] gshared calls to non-generic static virtual interface method throw BadImageFormatException: Method has no body #65384

@lambdageek

Description

@lambdageek

Build and run this sample with mono (for example in src/mono/sample/HelloWorld/Program.cs):

using System;
using System.IO;
using CancellationToken = System.Threading.CancellationToken;
using System.Threading.Tasks;

namespace NetStuff
{
    public interface IReadWriteAdapter {
	static abstract ValueTask<int> ReadAsync(Stream stream, Memory<byte> buffer, CancellationToken cancellationToken);
	static abstract void WriteAsync(Stream stream, byte[] buffer, int offset, int count);
    }

    public struct Message {
	public byte[] Payload {get; init;}
	public int Size => Payload.Length;
    }

    public class P {
	public void ForceAuthenticationAsync<TIOAdapter>(Stream innerStream, in Message message)
	    where TIOAdapter : IReadWriteAdapter
	{
	    TIOAdapter.WriteAsync (innerStream, message.Payload, 0, message.Size);
	}
    }

    public class AsyncReadWriteAdapter : IReadWriteAdapter {
	public static ValueTask<int> ReadAsync (Stream stream, Memory<byte> buffer, CancellationToken cancellationToken) => stream.ReadAsync(buffer, cancellationToken);

	// doesn't work
	public static void WriteAsync (Stream stream, byte[] buffer, int offset, int count) {
	    stream.WriteAsync(new ReadOnlyMemory<byte>(buffer, offset, count), default).AsTask().Wait();
	}

    }
}

namespace HelloWorld
{
    internal class Program
    {
        private static void Main(string[] args)
        {
	    var s = new MemoryStream(capacity: 1024);
	    var buf = new byte[] {0x01, 0x02, 0x03};
	    var message = new NetStuff.Message { Payload = buf };

	    var p  = new NetStuff.P ();
	    p.ForceAuthenticationAsync<NetStuff.AsyncReadWriteAdapter>(s, message);

	    s.Seek (0, SeekOrigin.Begin);
	    var res = new byte[buf.Length];
	    s.Read (new (res));
	    for (int i = 0; i < buf.Length; ++i)
		if (res[i] != buf[i])
		    throw new Exception ($"result differs at index {i}, expected {buf[i]}, got {res[i]}");
	    Console.WriteLine ("done");
        }
    }
}

Expected result:

done

Actual result:

Unhandled Exception:
System.BadImageFormatException: Method has no body
File name: 'HelloWorld'
   at NetStuff.P.ForceAuthenticationAsync[AsyncReadWriteAdapter](Stream innerStream, Message& message) in /Users/alklig/work/dotnet-runtime/runtime-bugs/src/mono/sample/HelloWorld/Program.cs:line 25
   at HelloWorld.Program.Main(String[] args) in /Users/alklig/work/dotnet-runtime/runtime-bugs/src/mono/sample/HelloWorld/Program.cs:line 51
[ERROR] FATAL UNHANDLED EXCEPTION: System.BadImageFormatException: Method has no body
File name: 'HelloWorld'
   at NetStuff.P.ForceAuthenticationAsync[AsyncReadWriteAdapter](Stream innerStream, Message& message) in /Users/alklig/work/dotnet-runtime/runtime-bugs/src/mono/sample/HelloWorld/Program.cs:line 25
   at HelloWorld.Program.Main(String[] args) in /Users/alklig/work/dotnet-runtime/runtime-bugs/src/mono/sample/HelloWorld/Program.cs:line 51

Note:

changing the sample to interface IReadWriteAdapter<T> where T: IReadWriteAdapter<T> { ... } (and updating the use sites) makes the sample work.

Note 2:

MONO_ENV_OPTIONS=--interp or MONO_ENV_OPTIONS=--optimize=-gshared makes the repro work.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions