开发者

C#/.NET Generics and Cdecl Varargs Bug?

开发者 https://www.devze.com 2023-03-02 02:06 出处:网络
Why does Foo() succeed but Bar() throws a BadImageFormatException? using System.Runtime.InteropServices;

Why does Foo() succeed but Bar() throws a BadImageFormatException?

using System.Runtime.InteropServices;
using System.Text;

static class Program
{
    [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern int sprintf([Out] StringBuilder buf, string format, __ar开发者_C百科glist);

    static void Main(string[] args)
    {
        Foo<int>(2); //Runs fine
        Bar<int>(2); //Error: "The signature is incorrect"
    }

 static void Foo<T>(int a) { sprintf(new StringBuilder(8), "%d", __arglist(a)); }
 static void Bar<T>(T   a) { sprintf(new StringBuilder(8), "%d", __arglist(a)); }
}


Try like this:

using System;
using System.Runtime.InteropServices;
using System.Text;

static class Program
{
    [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern int sprintf([Out] StringBuilder buf, string format, params object[] args);

    static void Main(string[] args)
    {
        Foo(2);
        Bar<int>(2);
    }

    static void Foo(int a) { sprintf(new StringBuilder(8), "%d", a); }
    static void Bar<T>(T a){ sprintf(new StringBuilder(8), "%d", a); }
}


You are asking why an undocumented (_arglist,_makeref,_reftype,_refvalue) keyword does not work.

Well you should ask Microsoft :D

If you really want to know my take on this, it could be because generics don't know the type of T at compile time, and yet they are compiled to classes. What does __arglist take at compilation time there is a mystery. Since in the line where you declare the generic don't specify the kind of parameter to __arglist.

But all of this is as much obscure as using sprintf from C#... at least if it were _snwprintf_s or similar :D


As shown in the following code, the exception is thrown before running the method when it is compiled into native code:

var t = typeof(Program);
var m = t.GetMethod("Bar", BindingFlags.NonPublic | BindingFlags.Static);
m = m.MakeGenericMethod(typeof(int));
System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(m.MethodHandle); //error

Also it is complaining about wrong type passed to SizeOf. I guess it might be a bug in the CLR that causes it to pass the internal handle to the generic type parameter instead of the handle of the real type passed to the method.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号