I played with the code from this dotnet hosting example and ran into some problems.
This is how I get a function pointer:
component_entry_point_fn function = nullptr;
int rc = functionPointer(
dllPath.c_str(),
dotnetType.c_str(),
methodName.c_str(),
nullptr,
nullptr,
(void**)&function);
And then I called it:
struct test {
const char* str = "from host!";
int i = 1;
} testArgs;
function(&testArgs, sizeof(testArgs));
And it works fine. Output:
Hello, world! from Lib [count: 1]
-- message: from host!
-- number: 1
Hello again, world! from Lib [count: 2]
-- message: from host!
-- number: 1
But when I try to pass the arguments as a tuple:
std::tuple<FunctionArgs...> argsTuple = std::make_tuple(args...);
function(&argsTuple, sizeof(argsTuple));
I got it:
Hello, world! from Lib [count: 1]
Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at System.SpanHelpers.IndexOfNullByte(Byte*)
at System.Runtime.InteropServices.Marshal.PtrToStringUTF8(IntPtr)
at Scripts.Lib.PrintLibArgs(LibArgs)
at Scripts.Lib.HelloAgain(IntPtr, Int32)
The code from the C# side is the same as in the example in the link above. Another important fact is that everything works without errors on Arm MacOS. The error appears on Linux x86_64. The compiler is the same everywhere: clang.
sizeof for structure and tuple is the same - 16 bytes. Tried adding alignment:
alignas(16) std::tuple<FunctionArgs...>
argsTuple = std::make_tuple(args...);
all of MSVC and gcc and clang on x64 architecture seem to swap the order of the tuple elements in memory https://godbolt.org/z/PW55PfGGE, but this is an implementation detail and not something you can rely on in your code.
you shouldn't be passing C++ tuples to a C interface, they don't have any layout requirements.