Fix crash when boxing native non-POD structure into managed data
This commit is contained in:
@@ -55,6 +55,9 @@ namespace FlaxEngine.Interop
|
|||||||
private static Dictionary<Assembly, string> assemblyOwnedNativeLibraries = new();
|
private static Dictionary<Assembly, string> assemblyOwnedNativeLibraries = new();
|
||||||
internal static AssemblyLoadContext scriptingAssemblyLoadContext;
|
internal static AssemblyLoadContext scriptingAssemblyLoadContext;
|
||||||
|
|
||||||
|
private delegate TInternal ToNativeDelegate<T, TInternal>(T value);
|
||||||
|
private delegate T ToManagedDelegate<T, TInternal>(TInternal value);
|
||||||
|
|
||||||
[System.Diagnostics.DebuggerStepThrough]
|
[System.Diagnostics.DebuggerStepThrough]
|
||||||
private static IntPtr NativeLibraryImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? dllImportSearchPath)
|
private static IntPtr NativeLibraryImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? dllImportSearchPath)
|
||||||
{
|
{
|
||||||
@@ -490,6 +493,7 @@ namespace FlaxEngine.Interop
|
|||||||
internal delegate void MarshalFieldTypedDelegate(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize);
|
internal delegate void MarshalFieldTypedDelegate(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize);
|
||||||
internal delegate void* GetBasePointer(ref T fieldOwner);
|
internal delegate void* GetBasePointer(ref T fieldOwner);
|
||||||
|
|
||||||
|
internal static Delegate toManagedDelegate;
|
||||||
internal static FieldInfo[] marshallableFields;
|
internal static FieldInfo[] marshallableFields;
|
||||||
internal static int[] marshallableFieldOffsets;
|
internal static int[] marshallableFieldOffsets;
|
||||||
internal static MarshalFieldTypedDelegate[] toManagedFieldMarshallers;
|
internal static MarshalFieldTypedDelegate[] toManagedFieldMarshallers;
|
||||||
@@ -611,6 +615,21 @@ namespace FlaxEngine.Interop
|
|||||||
// Setup marshallers for managed and native directions
|
// Setup marshallers for managed and native directions
|
||||||
MethodInfo toManagedMethod;
|
MethodInfo toManagedMethod;
|
||||||
if (type.IsValueType)
|
if (type.IsValueType)
|
||||||
|
{
|
||||||
|
// Non-POD structures use internal layout (eg. SpriteHandleManaged in C++ with SpriteHandleMarshaller.SpriteHandleInternal in C#) so convert C++ data into C# data
|
||||||
|
var attr = type.GetCustomAttribute<System.Runtime.InteropServices.Marshalling.NativeMarshallingAttribute>();
|
||||||
|
toManagedMethod = attr?.NativeType.GetMethod("ToManaged", BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
if (toManagedMethod != null)
|
||||||
|
{
|
||||||
|
// TODO: optimize via delegate call rather than method invoke
|
||||||
|
var internalType = toManagedMethod.GetParameters()[0].ParameterType;
|
||||||
|
var types = new Type[] { type, internalType };
|
||||||
|
toManagedDelegate = toManagedMethod.CreateDelegate(typeof(ToManagedDelegate<,>).MakeGenericType(types));
|
||||||
|
//toManagedDelegate = toManagedMethod.CreateDelegate();//.CreateDelegate(typeof(ToManagedDelegate<,>).MakeGenericType(type, toManagedMethod.GetParameters()[0].ParameterType));
|
||||||
|
string methodName = nameof(MarshalInternalHelper<ValueTypePlaceholder, ValueTypePlaceholder>.ToManagedMarshaller);
|
||||||
|
toManagedMethod = typeof(MarshalInternalHelper<,>).MakeGenericType(types).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
string methodName;
|
string methodName;
|
||||||
if (type == typeof(IntPtr))
|
if (type == typeof(IntPtr))
|
||||||
@@ -623,6 +642,7 @@ namespace FlaxEngine.Interop
|
|||||||
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManaged);
|
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManaged);
|
||||||
toManagedMethod = typeof(MarshalHelperValueType<>).MakeGenericType(type).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
|
toManagedMethod = typeof(MarshalHelperValueType<>).MakeGenericType(type).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (type.IsArray)
|
else if (type.IsArray)
|
||||||
{
|
{
|
||||||
Type elementType = type.GetElementType();
|
Type elementType = type.GetElementType();
|
||||||
@@ -1065,6 +1085,17 @@ namespace FlaxEngine.Interop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static class MarshalInternalHelper<T, TInternal> where T : struct
|
||||||
|
where TInternal : struct
|
||||||
|
{
|
||||||
|
internal static void ToManagedMarshaller(ref T managedValue, IntPtr nativePtr, bool byRef)
|
||||||
|
{
|
||||||
|
ToManagedDelegate<T, TInternal> toManaged = Unsafe.As<ToManagedDelegate<T, TInternal>>(MarshalHelper<T>.toManagedDelegate);
|
||||||
|
TInternal intern = Unsafe.Read<TInternal>(nativePtr.ToPointer());
|
||||||
|
managedValue = toManaged(Unsafe.Read<TInternal>(nativePtr.ToPointer()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal static class MarshalHelperValueType<T> where T : struct
|
internal static class MarshalHelperValueType<T> where T : struct
|
||||||
{
|
{
|
||||||
internal static void ToNativeWrapper(object managedObject, IntPtr nativePtr)
|
internal static void ToNativeWrapper(object managedObject, IntPtr nativePtr)
|
||||||
@@ -1504,8 +1535,6 @@ namespace FlaxEngine.Interop
|
|||||||
private static (IntPtr ptr, int size)[] pinnedAllocations = new (IntPtr ptr, int size)[256];
|
private static (IntPtr ptr, int size)[] pinnedAllocations = new (IntPtr ptr, int size)[256];
|
||||||
private static uint pinnedAllocationsPointer = 0;
|
private static uint pinnedAllocationsPointer = 0;
|
||||||
|
|
||||||
private delegate TInternal ToNativeDelegate<T, TInternal>(T value);
|
|
||||||
|
|
||||||
private delegate IntPtr UnboxerDelegate(object value, object converter);
|
private delegate IntPtr UnboxerDelegate(object value, object converter);
|
||||||
|
|
||||||
private static ConcurrentDictionary<Type, (UnboxerDelegate deleg, object toNativeDeleg)> unboxers = new(1, 3);
|
private static ConcurrentDictionary<Type, (UnboxerDelegate deleg, object toNativeDeleg)> unboxers = new(1, 3);
|
||||||
@@ -1683,6 +1712,7 @@ namespace FlaxEngine.Interop
|
|||||||
internal static class TypeHelpers<T>
|
internal static class TypeHelpers<T>
|
||||||
{
|
{
|
||||||
public static readonly int MarshalSize;
|
public static readonly int MarshalSize;
|
||||||
|
|
||||||
static TypeHelpers()
|
static TypeHelpers()
|
||||||
{
|
{
|
||||||
Type type = typeof(T);
|
Type type = typeof(T);
|
||||||
|
|||||||
@@ -1855,7 +1855,6 @@ namespace Flax.Build.Bindings
|
|||||||
{{structureInfo.Name}}Internal unmanaged;
|
{{structureInfo.Name}}Internal unmanaged;
|
||||||
public void FromManaged({{structureInfo.Name}} managed) => this.managed = managed;
|
public void FromManaged({{structureInfo.Name}} managed) => this.managed = managed;
|
||||||
public {{structureInfo.Name}}Internal ToUnmanaged() { unmanaged = {{marshallerFullName}}.ToNative(managed); return unmanaged; }
|
public {{structureInfo.Name}}Internal ToUnmanaged() { unmanaged = {{marshallerFullName}}.ToNative(managed); return unmanaged; }
|
||||||
//public void FromUnmanaged({{structureInfo.Name}}Internal unmanaged) { {{marshallerFullName}}.Free(this.unmanaged.Value); this.unmanaged = unmanaged; }
|
|
||||||
public void FromUnmanaged({{structureInfo.Name}}Internal unmanaged) => this.unmanaged = unmanaged;
|
public void FromUnmanaged({{structureInfo.Name}}Internal unmanaged) => this.unmanaged = unmanaged;
|
||||||
public {{structureInfo.Name}} ToManaged() { managed = {{marshallerFullName}}.ToManaged(unmanaged); return managed; }
|
public {{structureInfo.Name}} ToManaged() { managed = {{marshallerFullName}}.ToManaged(unmanaged); return managed; }
|
||||||
public void Free() => NativeToManaged.Free(unmanaged);
|
public void Free() => NativeToManaged.Free(unmanaged);
|
||||||
|
|||||||
Reference in New Issue
Block a user