IL2CPP: Class object interop marshalling fails

We’re upgrading a game that is currently live on PS4/5 and XB1/Scarlett from Unity 2020.3.35f1 to Unity 2022.3.14f1 and it started crashing when marshalling a class object from C# code into one of our C++ libraries as it attempts to do a memset on a nullptr (which wasn’t a nullptr before, as it was being marshalled correctly)

struct LPacket {
};

extern "C" __declspec(dllexport) void __cdecl GetPacket(LPacket *const dst, const int idx)
[StructLayout(LayoutKind.Sequential)]
public class LPacket {
}
[DllImport("xxxx")]
    public static extern void GetPacket([Out] LPacket dst, int idx);

Something changed with IL2CPP and we’re not sure what. We know this because when building with the Mono backend our PC version works fine, the moment we switch to IL2CPP it starts crashing when calling the above method.
We’re in the process of narrowing down which Unity version started having this problem. In the meantime, any suggestion is welcome.

Edit: We’ve narrowed it down to this Editor version: Unity 2021.3.28
And this change in particular: IL2CPP: When P/Invoking with a blittable class parameter, pass a pinned pointer to the managed class to native. (UUM-33942)
We’re currently looking for a fix.

Thank you!

Edit2: We now know for sure that that is the fix that is causing our problems. Unity 2022.2.20f1 works correctly, meanwhle the subsequent version where the aforementioned issue was also fixed, 2022.2.21f1, also crashes in the same spot.

More evidence is in the il2cppOutput:

IL2CPP_EXTERN_C IL2CPP_METHOD_ATTR void XxxxDLL_GetPacket_m22748FF55FCB0E0EB59FB14005A23886C635B1E5 (LPacket_t49FC97AA2190BA893E8B524362C6068543588B9E* ___0_dst, int32_t ___1_idx, const RuntimeMethod* method) 
{

    typedef void (DEFAULT_CALL *PInvokeFunc) (LPacket_t49FC97AA2190BA893E8B524362C6068543588B9E_marshaled_pinvoke*, int32_t);
    #if !FORCE_PINVOKE_INTERNAL && !FORCE_PINVOKE_xxxx_INTERNAL
    static PInvokeFunc il2cppPInvokeFunc;
    if (il2cppPInvokeFunc == NULL)
    {
        int parameterSize = sizeof(void*) + sizeof(int32_t);
        il2cppPInvokeFunc = il2cpp_codegen_resolve_pinvoke<PInvokeFunc>(IL2CPP_NATIVE_STRING("xxxx"), "GetPacket", IL2CPP_CALL_DEFAULT, CHARSET_NOT_SPECIFIED, parameterSize, false);
        IL2CPP_ASSERT(il2cppPInvokeFunc != NULL);
    }
    #endif

    LPacket_t49FC97AA2190BA893E8B524362C6068543588B9E_marshaled_pinvoke ____0_dst_marshaled = {};

    #if FORCE_PINVOKE_INTERNAL || FORCE_PINVOKE_xxxx_INTERNAL
    reinterpret_cast<PInvokeFunc>(GetPacket)(___0_dst != NULL ? (&____0_dst_marshaled) : NULL, ___1_idx);
    #else
    il2cppPInvokeFunc(___0_dst != NULL ? (&____0_dst_marshaled) : NULL, ___1_idx);
    #endif

    if (___0_dst != NULL)
    {
        LPacket__ctor_mDC58D8B268C89FF8BEE55953B5D550F431C5383E(___0_dst, NULL);
        LPacket_t49FC97AA2190BA893E8B524362C6068543588B9E_marshal_pinvoke_back(____0_dst_marshaled, *___0_dst);
    }

    if ((&____0_dst_marshaled) != NULL)
    {
        LPacket_t49FC97AA2190BA893E8B524362C6068543588B9E_marshal_pinvoke_cleanup(____0_dst_marshaled);
    }

}
IL2CPP_EXTERN_C IL2CPP_METHOD_ATTR void XxxxDLL_GetPacket_m22748FF55FCB0E0EB59FB14005A23886C635B1E5 (LPacket_t49FC97AA2190BA893E8B524362C6068543588B9E* ___0_dst, int32_t ___1_idx, const RuntimeMethod* method) 
{


    typedef void (DEFAULT_CALL *PInvokeFunc) (void*, int32_t);
    #if !FORCE_PINVOKE_INTERNAL && !FORCE_PINVOKE_xxxx_INTERNAL
    static PInvokeFunc il2cppPInvokeFunc;
    if (il2cppPInvokeFunc == NULL)
    {
        int parameterSize = sizeof(void*) + sizeof(int32_t);
        il2cppPInvokeFunc = il2cpp_codegen_resolve_pinvoke<PInvokeFunc>(IL2CPP_NATIVE_STRING("xxxx"), "GetPacket", IL2CPP_CALL_DEFAULT, CHARSET_NOT_SPECIFIED, parameterSize, false);
        IL2CPP_ASSERT(il2cppPInvokeFunc != NULL);
    }
    #endif

    void* ____0_dst_marshaled = NULL;

    #if FORCE_PINVOKE_INTERNAL || FORCE_PINVOKE_xxxx_INTERNAL
    reinterpret_cast<PInvokeFunc>(GetPacket)(____0_dst_marshaled, ___1_idx);
    #else
    il2cppPInvokeFunc(____0_dst_marshaled, ___1_idx);
    #endif

}

The line in particular that draws the attention is this void* ____0_dst_marshaled = NULL;

2 Likes

Thanks for finding this! Can you by any chance file a bug report through the editor? Via the Help → Report a Bug button. That way we can be sure we fix the issue affecting your code (as we’ll be able to test it after the fix) and we’ll be able to notify you when the fix goes out.