From eb0d4c15f1975299ad306e3d8f23eabc91542577 Mon Sep 17 00:00:00 2001 From: Joe Hull Date: Wed, 7 Apr 2021 09:12:51 -0700 Subject: [PATCH] bug fix: When generating the get accessor for a field composed of an embedded array of structs use __GetOrCreateInstance to initialize the managed array wrapper rather than __CreateInstance so that __Instance holds a pointer to the memory allocated for the array in the outer struct rather than an independent copy of that memory. Added a test. TODO: once allocated, we may want to cache the managed array. Does this issue exist in other generators as well? --- src/Generator/Generators/CSharp/CSharpMarshal.cs | 4 ++-- src/Generator/Generators/CodeGenerator.cs | 1 + tests/CSharp/CSharp.Tests.cs | 16 ++++++++++++++++ tests/CSharp/CSharp.h | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/Generator/Generators/CSharp/CSharpMarshal.cs b/src/Generator/Generators/CSharp/CSharpMarshal.cs index b1f5274a..cbca5f0c 100644 --- a/src/Generator/Generators/CSharp/CSharpMarshal.cs +++ b/src/Generator/Generators/CSharp/CSharpMarshal.cs @@ -91,8 +91,8 @@ namespace CppSharp.Generators.CSharp { if (arrayType == finalArrayType) supportBefore.WriteLineIndent( - "{0}[i] = {1}.{2}(*(({1}.{3}*)&({4}[i * sizeof({1}.{3})])));", - value, array.Type, Helpers.CreateInstanceIdentifier, + "{0}[i] = {1}.{2}((IntPtr)(({1}.{3}*)&({4}[i * sizeof({1}.{3})])), true, true);", + value, array.Type, Helpers.GetOrCreateInstanceIdentifier, Helpers.InternalStruct, Context.ReturnVarName); else supportBefore.WriteLineIndent( diff --git a/src/Generator/Generators/CodeGenerator.cs b/src/Generator/Generators/CodeGenerator.cs index e7348261..1178f180 100644 --- a/src/Generator/Generators/CodeGenerator.cs +++ b/src/Generator/Generators/CodeGenerator.cs @@ -1301,6 +1301,7 @@ namespace CppSharp.Generators public static readonly string OwnsNativeInstanceIdentifier = Generator.GeneratedIdentifier("ownsNativeInstance"); public static readonly string CreateInstanceIdentifier = Generator.GeneratedIdentifier("CreateInstance"); + public static readonly string GetOrCreateInstanceIdentifier = Generator.GeneratedIdentifier("GetOrCreateInstance"); public static string GetSuffixForInternal(DeclarationContext @class) { diff --git a/tests/CSharp/CSharp.Tests.cs b/tests/CSharp/CSharp.Tests.cs index e101983a..b3ac1184 100644 --- a/tests/CSharp/CSharp.Tests.cs +++ b/tests/CSharp/CSharp.Tests.cs @@ -767,6 +767,22 @@ public unsafe class CSharpTests } } + [Test] + public void TestEmbeddedArrayOfStructAccessor() + { + const ulong firstLong = 0xC92EEDE87AAB4FECul; + const ulong secondLong = 0xAD5FB16491935522ul; + + var testStruct = new StructWithEmbeddedArrayOfStructObjectAlignment(); + testStruct.EmbeddedStruct[0].Ui64 = firstLong; + testStruct.EmbeddedStruct[1].Ui64 = secondLong; + + // Since the memory allocated for EmbeddedStruct is generally uninintialized, I suppose it _could_ + // just happen to match, but it seems very unlikely. + Assert.That(firstLong, Is.EqualTo(testStruct.EmbeddedStruct[0].Ui64)); + Assert.That(secondLong, Is.EqualTo(testStruct.EmbeddedStruct[1].Ui64)); + } + public void TestClassSize() { Assert.That(Marshal.SizeOf, Is.EqualTo(Marshal.SizeOf() * 2)); diff --git a/tests/CSharp/CSharp.h b/tests/CSharp/CSharp.h index be6a1cbc..f8b898e2 100644 --- a/tests/CSharp/CSharp.h +++ b/tests/CSharp/CSharp.h @@ -1504,7 +1504,7 @@ struct DLL_API ClassMicrosoftObjectAlignment : ClassMicrosoftObjectAlignmentBase struct DLL_API EmbeddedStruct { - int64_t i64; + uint64_t ui64; }; struct DLL_API StructWithEmbeddedArrayOfStructObjectAlignment {