Burst throws an uninformative error when casting to a function pointer

In my existing code, I have a raw chunk of memory containing a function pointer, and Burst for some reason throws an error when performing that cast.

For a sample code, think of something like this:

using Unity.Burst;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;

namespace UnityEngine.Internal
{
    public delegate float SomeDelegate(float a, float b);
    
    [BurstCompile]
    public static class FnLib
    {
        [BurstCompile, AOT.MonoPInvokeCallback(typeof(SomeDelegate))]
        public static float DoSomething(float a, float b) => a + b;
    }
    
    public class FunctionPointerCastTest : MonoBehaviour
    {
        private FunctionPointer<SomeDelegate> _fnPtr = default;
        private void Awake()
        {
            _fnPtr = BurstCompiler.CompileFunctionPointer<SomeDelegate>(FnLib.DoSomething);
        }

        [InspectorButton(nameof(Test))] [SerializeField] private Stub s = default; // <-- ignore this, just draws a button on inspector.
        public unsafe void Test()
        {
            var na = new NativeArray<byte>(sizeof(FunctionPointer<SomeDelegate>), Allocator.TempJob);
            var ptr = na.GetUnsafePtr();
            (*(FunctionPointer<SomeDelegate>*) ptr) = _fnPtr;
            new SomeJob {Data = (byte*) na.GetUnsafeReadOnlyPtr()}.Schedule().Complete();
            na.Dispose();
        }
    }

    [BurstCompile] // <-- comment/uncomment this
    public unsafe struct SomeJob : IJob
    {
        [NativeDisableUnsafePtrRestriction] public byte* Data;
        
        public void Execute()
        {
            (*(FunctionPointer<SomeDelegate>*) Data).Invoke(34, 56);
        }
    }
}

Obviously, my actual code doesn’t ignore the result of a pure method but just bear with me for the sake of an example, please.

If the job is not burst compiled, it works just fine, no issues, but if it is, then it spits out the following error:

A majority of what I am working on is actually dependent on being able to cast raw memory into a function pointer. Can someone please help me out with this?

I researched a bit more over this and seems like it is because FunctionPointer is a generic type, and Burst breaks when it tries to interpret it.

As a workaround, currently, I am using a switch and const ushort identifiers, directly burst compiled, but it’s quite a bit of boilerplate every time. How I wish C# had preprocessor macros, or that Unity had some C++ API.

There’s a major problem with this though, I need to update the registry EVERY time I need to add a new function, throwing the modularity of the code out the window.

Okay, finally found a solution, you can use UnsafeUtility.As<U, T>(ref U value) to reinterpret cast like it were C++.

1 Like