Native Plugin(C++) calling C# method gets crashed when accessing C# object

I have a C# callback for C++ to invoke as follows:
[MonoPInvokeCallback(typeof(Trace))]
void __internal_trace(IntPtr in_buffer, IntPtr in_length) {

this.gameObject.transform.position = XXX;

}

But it always crashes on my iphone with an error about l2CppWrapperException. When I remove the line containing “this”, everything goes well. So I think it is a bug. Any ideas?

What exactly is XXX? It could be the part causing the crash, not the “this” itself.

actually I did:

int length = in_length.ToInt32();
float[ ] buffer = new float[length];
Marshal.Copy(in_buffer, buffer, 0, length * sizeof(float));
Debug.Log(“transferred” + length * sizeof(float) + “bytesintoC#as” + buffer);

Vector4 center = new Vector4(buffer[0], buffer[1], buffer[2], 1.0f);
this.gameObject.transform.position = center;

Another thing is that when I debug with a single line in my C# callback, with “Debug.Log(this.GetHashcode());”, it’ll crash too, so I think it has something to do with the communication issues between C# and C++

Why would you use a Vector4 and not a Vector3 if you’re just setting the position? That’s not the problem, it just seems a little odd.

I’m guessing parts of your code gets optimized away when you’re not assigning the center to anything.

The 4th argument to Marshal.Copy should be the length of the array in elements, and not bytes, if I’m not mistaken (Marshal.Copy Method (System.Runtime.InteropServices) | Microsoft Learn), so just length and not length*sizeof(float). This might be the issue.

If you show me the real C function, the real c# method, all calls involved, then I can see what’s wrong. I do LOTS of calling from c# → C and C → C# and never get any issues, BUT you have to be very sure you’re marshalling the data correctly or you’re going to get lots of runtime problems.

Edit: But right off the bat this line looks wrong:

int length = in_length.ToInt32();

Since in_length is specified as an IntPtr, should that not be a Int32 or UInt32?

But it’s hard to know without seeing how you’re calling this from C.

I test a naive callback as follows:
C#:

private delegate void TraceBegin ();

[DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
private static extern void RegisterCallbacks(TraceBegin traceBegin);

[MonoPInvokeCallback(typeof(TraceBegin))]
void __internal_trace_begin() {
      Debug.Log ("tracebegin");
      this.gameObject.transform.position = new Vector4 (0, 0, 0, 0);
}

C++:

typedef void (*TRACE_BEGIN) ();

class UnityInterface
{
public:
  UnityInterface();
  ~UnityInterface();

  static std::vector<TRACE_BEGIN> begin_callbacks;
};

void RegisterCallbacks(TRACE_BEGIN traceBegin) {
  UnityInterface::begin_callbacks.push_back(traceBegin);
}

And I call it with
UnityInterface::begin_callbacksidx;

If I insert “this.gameObject.transform.position = new Vector4 (0, 0, 0, 0);”, it’ll crash, otherwise not. It’s really strange. Do you develop the code on iOS?

The log showed in last several lines is:
trace begin

(Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineDebugBindings.gen.cpp Line: 37)

libc++abi.dylib: terminating with uncaught exception of type Il2CppExceptionWrapper

Thanks for your help, but the issue still exists:(

What does the extern “C” function look like? (I’m pretty sure you have to have an extern “C” interface to your c++ code.)

I use MonoPInvokeCallbackAttribute rather than MonoPInvokeCallback, not sure if that’ll make any difference.

What thread are you calling the callback on? Are you calling from your own thread in the C/C++ runtime?

  #ifdef __cplusplus
  extern "C" {
  #endif
   
    void RegisterCallbacks(TRACE_BEGIN traceBegin);

  #ifdef __cplusplus
  }
  #endif

I called the C# method in a different thread started in C++.

Could it be that because the callback doesn’t happen on the main thread, it crashes because you try to set the position of a gameobject outside the main thread?

That’s not a good idea and is likely your issue.

You should fire events via the Update() thread or you need to keep the state on the C# side and read/update the Unity state on the Update thread (using appropriate synchronization/locking/etc).

Firing events via the Update thread in Unity is (IMO) the simpler solution.

C#

void Update()
{
   MyNativeBindings.update(); //call the native code to update our state.
}

C

extern "C" void update()
{
  //
  // Do work that'll invoke the c# callbacks.
  //
}

But fiddling Unity state on another thread is not going to work.

I’ll try it, thanks.

Thanks for your help! I’ll try it.