Search code examples
c#c++x86-64host

C++/C# HostFXR passing arguments via std::tuple


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

Solution

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