Beef icon indicating copy to clipboard operation
Beef copied to clipboard

Interop bug related to C++ constructors

Open Grimelios opened this issue 3 months ago • 1 comments

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:

Image

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.

Image Image

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).

Grimelios avatar Sep 06 '25 01:09 Grimelios