This simple test code:
[Test] public static unsafe void does_ConvertExistingDataToNativeArray_work()
{
var array = new int[]{ 1 , 2 , 3 , 4 };
void* ptr = UnsafeUtility.PinGCArrayAndGetDataAddress(array, out ulong gcHandle);
var nativeArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<byte>(ptr, array.Length, Allocator.None);
for (int i = 0; i < array.Length; i++)
Assert.AreEqual(array[i], actual:nativeArray[i]);
UnsafeUtility.ReleaseGCObject(gcHandle);
}
Results in a NullReferenceException message:
System.NullReferenceException : Object reference not set to an instance of an object
at Unity.Collections.NativeArray1[T].CheckElementReadAccess (System.Int32 index) [0x00033] in <ca42919df2b74e53b11002749c8755af>:0 at Unity.Collections.NativeArray
1[T].get_Item (System.Int32 index) [0x00001] in :0
at NativeArrayExtensionMethodsTests.does_ConvertExistingDataToNativeArray_work () [0x0002c] in D:_WORKSHOP!PROJECTS_other\daggerfall-unity\Assets\Scripts\Utility\Editor\NativeArrayExtensionMethodsTests.cs:248
at (wrapper managed-to-native) System.Reflection.MonoMethod.InternalInvoke(System.Reflection.MonoMethod,object,object[ ],System.Exception&)
at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[ ] parameters, System.Globalization.CultureInfo culture) [0x00032] in :0
But why?
andrew-lukasik:
This simple test code:
[Test] public static unsafe void does_ConvertExistingDataToNativeArray_work()
{
var array = new int[]{ 1 , 2 , 3 , 4 };
void* ptr = UnsafeUtility.PinGCArrayAndGetDataAddress(array, out ulong gcHandle);
var nativeArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<byte>(ptr, array.Length, Allocator.None);
for (int i = 0; i < array.Length; i++)
Assert.AreEqual(array[i], actual:nativeArray[i]);
UnsafeUtility.ReleaseGCObject(gcHandle);
}
Results in a NullReferenceException message:
But why?
It’s safety system complains. You need to properly initialize safety handle (how to get second argument depends on data source you converts to native array from):
var nativeArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<byte>(ptr, array.Length, Allocator.None);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref nativeArray, AtomicSafetyHandle.GetTempMemoryHandle());
#endif
Otherwise here you’ll have null m_Safety
1 Like
Thank you @eizenhorn for this very helpful answer! That was exactly what I was missing here
This unit test still fails, but for a baffling reason:
[Test] public static unsafe void does_ConvertExistingDataToNativeArray_work()
{
var array = new int[]{ 1 , 2 , 3 , 4 };
void* ptr = UnsafeUtility.PinGCArrayAndGetDataAddress(array, out ulong gcHandle);
var nativeArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<byte>(ptr, array.Length, Allocator.None);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref nativeArray, AtomicSafetyHandle.GetTempMemoryHandle());
#endif
//Debug.Log($"array:\t\t{array.ToReadableString()}");
//Debug.Log($"nativeArray:\t{nativeArray.ToReadableString()}");
Assert.AreEqual(expected:array.Length, actual:nativeArray.Length);
for (int i = 0; i < array.Length; i++)
Assert.AreEqual(expected:array[i], actual:nativeArray[i]);
UnsafeUtility.ReleaseGCObject(gcHandle);
}
Message:
and the logs tell me that this is what those 2 arrays looks like:
array: (1,2,3,4)
nativeArray: (1,0,0,0)
Why on earth does the first dword matches but the others does not?
That’s completely expected. You “reinterpret” int
array to byte
array. Types size not match as result these arrays memory layout cannot be aliased. As result in your case you see “invalid” values for your reinterpreted array. If you look at NativeArrayExtensions.Reinterpret
you’ll see they have size check, which prevents you from doing that. If you change ConvertExistingDataToNativeArray<byte>
to ConvertExistingDataToNativeArray<int>
everything will match.
1 Like
Of course! I’m such a fool today, didn’t catch that. Thank you again!