From 210c8e8fe4c3fa152a2a06c6129ab90861538dc1 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 4 Apr 2025 00:36:35 +0200 Subject: [PATCH] Fix incorrect result array memory copy from native to managed code --- Source/Engine/Engine/NativeInterop.Marshallers.cs | 14 ++++++++++++-- .../Flax.Build/Bindings/BindingsGenerator.Cpp.cs | 11 +++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Engine/NativeInterop.Marshallers.cs b/Source/Engine/Engine/NativeInterop.Marshallers.cs index 63c0f7bc8..4dd4de919 100644 --- a/Source/Engine/Engine/NativeInterop.Marshallers.cs +++ b/Source/Engine/Engine/NativeInterop.Marshallers.cs @@ -563,7 +563,7 @@ namespace FlaxEngine.Interop { T[] sourceArray; ManagedArray managedArray; - ManagedHandle handle; + ManagedHandle handle; // Valid only for pooled array public void FromManaged(T[] managed) { @@ -588,7 +588,13 @@ namespace FlaxEngine.Interop { ManagedArray arr = Unsafe.As(ManagedHandle.FromIntPtr(new IntPtr(unmanaged)).Target); if (sourceArray == null || sourceArray.Length != arr.Length) + { + // Array was resized when returned from native code (as ref parameter) + managedArray.FreePooled(); sourceArray = new T[arr.Length]; + managedArray = arr; + handle = new ManagedHandle(); // Invalidate as it's not pooled array anymore + } } public ReadOnlySpan GetUnmanagedValuesSource(int numElements) @@ -602,7 +608,11 @@ namespace FlaxEngine.Interop public T[] ToManaged() => sourceArray; - public void Free() => managedArray.FreePooled(); + public void Free() + { + if (handle.IsAllocated) + managedArray.FreePooled(); + } } public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[] managed, out int numElements) diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs index d36fb706d..558510bae 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs @@ -1207,6 +1207,7 @@ namespace Flax.Build.Bindings string callReturnCount = ""; if (returnTypeIsContainer) { + // Array marshallers need to know amount of items written in the buffer callReturnCount = indent; if (returnType.Type == "Span" || returnType.Type == "BytesContainer") callReturnCount += "*__returnCount = {0}.Length();"; @@ -1349,6 +1350,7 @@ namespace Flax.Build.Bindings #if USE_NETCORE if (parameterInfo.Type.Type == "Array") { + // Array marshallers need to know amount of items written in the buffer contents.Append(indent).AppendFormat("*__{0}Count = {1}.Count();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine(); } #endif @@ -1368,6 +1370,8 @@ namespace Flax.Build.Bindings if (parameterInfo.Type.Type == "BytesContainer" && parameterInfo.Type.GenericArgs == null) { contents.Append(indent).AppendFormat("MCore::GC::WriteRef({0}, (MObject*){1});", parameterInfo.Name, value).AppendLine(); + + // Array marshallers need to know amount of items written in the buffer contents.Append(indent).AppendFormat("*__{0}Count = {1}.Length();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine(); continue; } @@ -1376,6 +1380,13 @@ namespace Flax.Build.Bindings } } contents.Append(indent).AppendFormat("*{0} = {1};", parameterInfo.Name, value).AppendLine(); +#if USE_NETCORE + if (parameterInfo.Type.Type == "Array") + { + // Array marshallers need to know amount of items written in the buffer + contents.Append(indent).AppendFormat("*__{0}Count = {1}.Count();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine(); + } +#endif } } }