diff --git a/src/Generator/Generators/CSharp/CSharpSources.cs b/src/Generator/Generators/CSharp/CSharpSources.cs index adfb6a3c..1277afe8 100644 --- a/src/Generator/Generators/CSharp/CSharpSources.cs +++ b/src/Generator/Generators/CSharp/CSharpSources.cs @@ -1528,6 +1528,11 @@ namespace CppSharp.Generators.CSharp NewLine(); GenerateVTableClassSetup(@class, wrappedEntries); + WriteLine("private static readonly global::System.Collections.Generic.List<" + + "global::CppSharp.Runtime.SafeUnmanagedMemoryHandle> __handleManagedVTables" + + " = new global::System.Collections.Generic.List<" + + "global::CppSharp.Runtime.SafeUnmanagedMemoryHandle>();"); + NewLine(); WriteLine("#endregion"); PopBlock(NewLineKind.BeforeNextBlock); @@ -1638,6 +1643,7 @@ namespace CppSharp.Generators.CSharp string vfptr = $"vfptr{(destructorOnly ? "_dtor" : string.Empty)}{i}"; WriteLine($@"var {vfptr} = Marshal.AllocHGlobal({size} * { Context.TargetInfo.PointerWidth / 8});"); + WriteLine($"__handleManagedVTables.Add(new global::CppSharp.Runtime.SafeUnmanagedMemoryHandle({vfptr}, true));"); WriteLine($"{managedVTables}[{i}] = {vfptr}.ToPointer();"); AllocateNewVTableEntries(vftable.Layout.Components, wrappedEntries, @@ -1655,6 +1661,7 @@ namespace CppSharp.Generators.CSharp int size = @class.Layout.Layout.Components.Count; uint pointerSize = Context.TargetInfo.PointerWidth / 8; WriteLine($"var vtptr{suffix} = Marshal.AllocHGlobal({size} * {pointerSize});"); + WriteLine($"__handleManagedVTables.Add(new global::CppSharp.Runtime.SafeUnmanagedMemoryHandle(vtptr{suffix}, true));"); WriteLine($@"var vfptr{suffix}0 = vtptr{suffix} + { VTables.ItaniumOffsetToTopAndRTTI} * {pointerSize};"); diff --git a/src/Runtime/SafeUnmanagedMemoryHandle.cs b/src/Runtime/SafeUnmanagedMemoryHandle.cs new file mode 100644 index 00000000..da651589 --- /dev/null +++ b/src/Runtime/SafeUnmanagedMemoryHandle.cs @@ -0,0 +1,28 @@ +using System; +using System.Runtime.InteropServices; +using System.Security.Permissions; +using Microsoft.Win32.SafeHandles; + +namespace CppSharp.Runtime +{ + // https://stackoverflow.com/a/17563315/ + [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)] + public sealed class SafeUnmanagedMemoryHandle : SafeHandleZeroOrMinusOneIsInvalid + { + public SafeUnmanagedMemoryHandle() : base(true) { } + + public SafeUnmanagedMemoryHandle(IntPtr preexistingHandle, bool ownsHandle) + : base(ownsHandle) => SetHandle(preexistingHandle); + + protected override bool ReleaseHandle() + { + if (handle != IntPtr.Zero) + { + Marshal.FreeHGlobal(handle); + handle = IntPtr.Zero; + return true; + } + return false; + } + } +}