调用native(DllImport)函数时发生StackOverflowException

Mat*_*ias 2 .net c# stack-overflow dllimport

我目前正在进行微基准测试,以便更好地理解clr到本机代码的性能.在下面的例子中,我得到一个StackOverflowException,当编译为release并执行时没有连接调试器.编译为debug-build或运行附带调试器的程序时,我没有得到异常.此外,我也只使用SuppressUnmanagedCodeSecurityAttribute-Attribute 获得此错误.

我使用c和VS2013(platformtoolset = v120)构建了一个dll,其中包含一个函数:

__declspec(dllexport) int __cdecl NativeTestFunction(int a, int b, int c, int d)
{
    return a + c + b + d;
}
Run Code Online (Sandbox Code Playgroud)

在我的C#程序中,我DllImport用来调用这个函数并进行一些时序测量:

[DllImport("Native.dll", EntryPoint = "NativeTestFunction")]
static extern int NativeTestFunction(int a, int b, int c, int d);

[DllImport("Native.dll", EntryPoint = "NativeTestFunction"), SuppressUnmanagedCodeSecurityAttribute]
static extern int NativeTestFunctionSuppressed(int a, int b, int c, int d);

static void Main(string[] args)
{
    byte[] data = new byte[64];
    int c = 0;

    Stopwatch sw = Stopwatch.StartNew();

    for (int i = 0; i < 10000000; i++)
        c += NativeTestFunction(2, -1, -2, 1);

    Console.WriteLine("Unsuppressed: " + sw.Elapsed.ToString());
    sw = Stopwatch.StartNew();

    for (int i = 0; i < 10000000; i++)
        c += NativeTestFunctionSuppressed(2, -1, -2, 1);

    Console.WriteLine("Suppressed..: " + sw.Elapsed.ToString());
}
Run Code Online (Sandbox Code Playgroud)

如果我将此代码编译为release并在没有附加调试器的情况下启动它,则输出为:

Unsuppressed: 00:00:00.2666255

Process is terminated due to StackOverflowException.
Run Code Online (Sandbox Code Playgroud)

但是,在调试器附加或编译为调试的情况下执行,并且无论是否附带调试器启动,程序都会成功:

Unsuppressed: 00:00:00.2952272
Suppressed..: 00:00:00.1278980
Run Code Online (Sandbox Code Playgroud)

这是.NET/CLR中的已知错误吗?我的错是什么?我认为附加和未附加的调试器之间的行为应该是相同的.

.NET 2.0和.NET 4.0发生此错误.我的软件编译为x86(因此仅针对x86进行测试)以兼容Native.dll.如果您不想自己设置此方案,可以下载我的测试项目:源代码.

Dav*_*nan 5

__declspec(dllexport) int __cdecl NativeTestFunction(int a, char* b, int c, int d)
Run Code Online (Sandbox Code Playgroud)

注意类型b.是的char*.然后在你编写的C#代码中:

[DllImport("Native.dll", EntryPoint = "NativeTestFunction"), 
    SuppressUnmanagedCodeSecurityAttribute]
static extern int NativeTestFunctionSuppressed(int a, int b, int c, int d);
Run Code Online (Sandbox Code Playgroud)

在这里你声明bint.那不匹配.调用该函数时会变得更糟.

NativeTestFunctionSuppressed(2, -1, -2, 1);
Run Code Online (Sandbox Code Playgroud)

-1在32位进程中传递将等同于传递地址0xffffffff.尝试取消引用该地址没有任何好处.

另一个问题是调用约定不匹配.本机代码使用__cdecl,但托管代码使用默认值__stdcall.将托管代码更改为:

[DllImport("Native.dll", EntryPoint = "NativeTestFunction", 
    CallingConvention = CallingConvention.Cdecl), 
    SuppressUnmanagedCodeSecurityAttribute]
Run Code Online (Sandbox Code Playgroud)

同样对于其他进口.