Ross
Ross

Reputation: 617

Stackoverflow on calling native c++ from c#

I am trying to call native C++ code from C# project. To do that I followed the steps from this post.

But I get a stackoverflow exception when I create a huge array in the C++ file. Here is the code:

//CSharpTest.h

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSharpTest
{
    class Program
    {
        static void Main(string[] args)
        {
            CpTest.Class1 instance = new CpTest.Class1();
            Console.WriteLine(instance.DoSomething());
            Console.ReadKey();
        }
    }
}

And the c++ file

// CpTest.h

#pragma once

using namespace System;

namespace CpTest {

    public ref class Class1
    {
    public:
        int DoSomething(){
            int arr[640 * 480];
            return 123;
        }
        // TODO: Add your methods for this class here.
    };
}

The array declaration is causing the stackoverflow exception.

Earlier when I was running only the native C++ code I increased the stack size by increasing the 'Stack Reserve Size' from the project properties.

But for this case I don't know what to do.

Upvotes: 0

Views: 420

Answers (1)

Hans Passant
Hans Passant

Reputation: 941218

  int arr[640 * 480];

This array is stored on the stack in a C or C++ program. The equivalent of stackalloc in a C# program. It requires 640 x 480 x 4 = 1,228,800 bytes of storage. That is too much, the default size of the stack is one megabyte. You overflowed the stack, the exception tells you about it.

This is a flaw in the native code, it should never rely on such big allocations to pan out at runtime and should use the free store instead. Operator new in a C++ program, malloc in a C program.

And preferrably array<int>^ in a C++/CLI program, that's a managed array that is stored on the GC heap, just like a C# array. You'd use pin_ptr<> to allow native code to party on the array.

Technically it is fixable in a C# project, you have to ask for a bigger stack for the startup thread, the one that the operating system creates and calls your Main() method. You automatically get one when you target x64, the default is 4 megabytes. But that's not generally an option if you have to interop with existing native code. You can run Editbin.exe with the /STACK option to patch the EXE file header and ask for a bigger stack. The post-build event in your C# project can look like this:

  set path=%path%;$(DevEnvDir);$(DevEnvDir)..\..\vc\bin
  editbin.exe /STACK:2097152 "$(TargetPath)"

Or run the native code from a thread you create yourself, use one of the Thread constructors that lets you specify the stack size.

Upvotes: 5

Related Questions