Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Get pointers to native container buffers using reflection

Discussion in 'Scripting' started by Djadjouka, Sep 11, 2019.

  1. Djadjouka

    Djadjouka

    Joined:
    Nov 1, 2016
    Posts:
    9
    Hi,

    I am trying to get the pointer to the internal memory buffer of a native array or a native slice for debugging purposes at runtime. I'm using this code but it doesn't give me the correct memory address somehow (it prints the log below). Am I doing something wrong or is there a bug with reflection for pointers? If there's a bug, would there be an alternative way of getting this pointer using reflection? I was also thinking maybe of reading the value using pointers but I'm not sure how I could get the memory address of a value type if it's boxed as an object.

    Code (CSharp):
    1. public class Test : MonoBehaviour
    2. {
    3.     unsafe void Start()
    4.     {
    5.         NativeArray<int> nativeArray = new NativeArray<int>(10, Allocator.Temp);
    6.         NativeSlice<int> nativeSlice = nativeArray;
    7.         Type nativeSliceType = nativeSlice.GetType();
    8.         FieldInfo bufferField = nativeSliceType.GetField("m_Buffer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
    9.         object bufferPointerBoxed = bufferField.GetValue(nativeSlice);
    10.         byte* pointer = (byte*)Pointer.Unbox(bufferPointerBoxed);
    11.         if (pointer != NativeSliceUnsafeUtility.GetUnsafePtr(nativeSlice))
    12.         {
    13.             Debug.Log("Something went wrong.");
    14.         }
    15.         nativeArray.Dispose();
    16.     }
    17. }
     
  2. Djadjouka

    Djadjouka

    Joined:
    Nov 1, 2016
    Posts:
    9
    I didn't manage to make it work with reflection but I found a workaround/hack with pointers:

    Code (CSharp):
    1. public unsafe IntPtr GetNativeArrayBufferPointer(object nativeArray)
    2.     {
    3.         ulong gcHandle;
    4.         IntPtr* nativeArrayBoxedPointer = (IntPtr*)UnsafeUtility.PinGCObjectAndGetAddress(nativeArray, out gcHandle);
    5.         IntPtr bufferPointer = *(nativeArrayBoxedPointer + 2);
    6.         UnsafeUtility.ReleaseGCObject(gcHandle);
    7.         return bufferPointer;
    8.     }
    9.  
    10.     public unsafe IntPtr GetNativeSliceBufferPointer(object nativeSlice)
    11.     {
    12.         ulong gcHandle;
    13.         IntPtr* nativeSliceBoxedPointer = (IntPtr*)UnsafeUtility.PinGCObjectAndGetAddress(nativeSlice, out gcHandle);
    14.         IntPtr bufferPointer = *(nativeSliceBoxedPointer + 2);
    15.         UnsafeUtility.ReleaseGCObject(gcHandle);
    16.         return bufferPointer;
    17.     }
    18.  
    19.     private unsafe IntPtr GetNativeListBufferPointer(object nativeList)
    20.     {
    21.         ulong gcHandle;
    22.         IntPtr* nativeListBoxedPointer = (IntPtr*)UnsafeUtility.PinGCObjectAndGetAddress(nativeList, out gcHandle);
    23.         // According to https://www.red-gate.com/simple-talk/dotnet/.net-framework/object-overhead-the-hidden-.net-memory--allocation-cost/
    24.         byte* nativeListDataPointerPointer = (byte*)(nativeListBoxedPointer + 2);
    25. #if ENABLE_UNITY_COLLECTIONS_CHECKS
    26.         nativeListDataPointerPointer += UnsafeUtility.SizeOf<AtomicSafetyHandle>();
    27.         // Dispose sentinel size
    28.         nativeListDataPointerPointer += IntPtr.Size;
    29. #endif
    30.         IntPtr nativeListDataPointer = *((IntPtr*)nativeListDataPointerPointer);
    31.         IntPtr nativeListBufferPointer = *((IntPtr*)nativeListDataPointer);
    32.         UnsafeUtility.ReleaseGCObject(gcHandle);
    33.         return nativeListBufferPointer;
    34.     }