StackOverflowException while calling native (DllImport) function

747 views Asked by At

I'm currenty doing micro-benchmarks for a better understanding of clr to native code performance. In the following example I'm getting a StackOverflowException, when compiled as release and executed without debugger attached. I don't get the exception when compiling as debug-build or when running the program with debugger attached. Furthermore I also get this error only with SuppressUnmanagedCodeSecurityAttribute-Attribute.

I built a dll using c and VS2013 (platformtoolset=v120) with one function in it:

__declspec(dllexport) int __cdecl NativeTestFunction(int a, int b, int c, int d)
{
    return a + c + b + d;
}

In my C#-program I use DllImport to call this function and do some timing-measurements:

[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());
}

If I compile this code as release and start it without debugger attached the output is:

Unsuppressed: 00:00:00.2666255

Process is terminated due to StackOverflowException.

However, executed with debugger attached or compiled as debug and launched with or without debugger attached the program succeeds:

Unsuppressed: 00:00:00.2952272
Suppressed..: 00:00:00.1278980

Is this a known Bug in .NET/CLR? What is my mistake? I think the behavior should be the same between attached and not-attached debugger.

This error happens with .NET 2.0 and .NET 4.0. My software is compiled as x86 (and therefore tested only for x86) for compatibility to the Native.dll. If you don't want to setup this scenario yourself you can download my test-projects: Sourcecode.

1

There are 1 answers

4
David Heffernan On BEST ANSWER
__declspec(dllexport) int __cdecl NativeTestFunction(int a, char* b, int c, int d)

Note the type of b. It is char*. Then in the C# code you write:

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

Here you declare b to be int. That does not match. It gets worse when you call the function.

NativeTestFunctionSuppressed(2, -1, -2, 1);

Passing -1 will, in a 32 bit process, equate to passing the address 0xffffffff. Nothing good will come of attempting to de-reference that address.

The other problem is that the calling conventions do not match. The native code uses __cdecl, but the managed code uses the default of __stdcall. Change the managed code to:

[DllImport("Native.dll", EntryPoint = "NativeTestFunction", 
    CallingConvention = CallingConvention.Cdecl), 
    SuppressUnmanagedCodeSecurityAttribute]

And likewise for the other import.