Interop bug related to C++ constructors
Consider the following C++ program:
// MyStaticLib.h
struct MyStruct
{
float x;
};
namespace MyNamespace
{
MyStruct GetMyStruct();
}
// MyStaticLib.cpp
#include "MyStaticLib.h"
MyStruct StaticLib::GetMyStruct()
{
MyStruct myStruct;
myStruct.x = 123;
return myStruct;
}
I've compiled this program into a static library and used the library in Beef as shown (assume the library is included in "Additional lib paths" within the project's build settings):
using System;
namespace MyNamespace
{
static
{
[CallingConvention(.Stdcall)]
[LinkName("?GetMyStruct@MyNamespace@@YA?AUMyStruct@@XZ")]
public static extern MyStruct GetMyStruct();
public static void Main()
{
let myStruct = GetMyStruct();
Console.WriteLine(myStruct.x);
}
}
[CRepr]
public struct MyStruct : this(float x);
}
This program compiles successfully and, as expected, prints 123 when run. Next, modify the C++ program to include a constructor:
// MyStaticLib.h
struct MyStruct
{
float x;
MyStruct(float x_) : x(x_)
{
}
};
namespace MyNamespace
{
MyStruct GetMyStruct();
}
// MyStaticLib.cpp
#include "MyStaticLib.h"
MyStruct StaticLib::GetMyStruct()
{
return MyStruct(123);
}
Re-running the same Beef program now prints 0, then crashes with an access violation similar to the following:
The error occurs as the program is ending. Here's the relevant call stack, first when running in debug mode, then running in release mode.
This smells like a Beef interop bug. For such trivial C++ and Beef programs, it's hard to imagine another source of error. Tested on the most recent Beef version at time of writing (09/04/2025).