From 66272bb332bbbcb49a8769f10801840937cb7f6c Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Thu, 25 Apr 2024 09:46:00 +0200 Subject: [PATCH 1/3] respect explicit size with sequential layout --- src/mono/mono/metadata/class-init.c | 2 +- src/mono/mono/metadata/marshal.c | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/metadata/class-init.c b/src/mono/mono/metadata/class-init.c index 13cf1fa612b35..8608dc30bfc63 100644 --- a/src/mono/mono/metadata/class-init.c +++ b/src/mono/mono/metadata/class-init.c @@ -2331,7 +2331,7 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ instance_size = MAX (real_size, instance_size); - if (instance_size & (min_align - 1)) { + if (instance_size & (min_align - 1) && !explicit_size) { instance_size += min_align - 1; instance_size &= ~(min_align - 1); } diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index 09fddd573c0fd..aad740a31d90e 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -5749,7 +5749,7 @@ MonoMarshalType * mono_marshal_load_type_info (MonoClass* klass) { int j, count = 0; - guint32 native_size = 0, min_align = 1, packing; + guint32 native_size = 0, min_align = 1, packing, explicit_size = 0; MonoMarshalType *info; MonoClassField* field; gpointer iter; @@ -5793,7 +5793,7 @@ mono_marshal_load_type_info (MonoClass* klass) info->num_fields = count; /* Try to find a size for this type in metadata */ - mono_metadata_packing_from_typedef (m_class_get_image (klass), m_class_get_type_token (klass), NULL, &native_size); + explicit_size = mono_metadata_packing_from_typedef (m_class_get_image (klass), m_class_get_type_token (klass), NULL, &native_size); if (m_class_get_parent (klass)) { int parent_size = mono_class_native_size (m_class_get_parent (klass), NULL); @@ -5879,6 +5879,9 @@ mono_marshal_load_type_info (MonoClass* klass) align_size = FALSE; else min_align = MIN (min_align, packing); + } else if (layout == TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT) { + if (explicit_size && native_size == info->native_size) + align_size = FALSE; } } From a555074d31cbae3771cee25aa1c88de4209d7b22 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Fri, 26 Apr 2024 19:13:50 +0200 Subject: [PATCH 2/3] test for sequential layout with explicit size --- .../MarshalUnalignedStructArray.cs | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/tests/Interop/ArrayMarshalling/UnalignedStructArray/MarshalUnalignedStructArray.cs diff --git a/src/tests/Interop/ArrayMarshalling/UnalignedStructArray/MarshalUnalignedStructArray.cs b/src/tests/Interop/ArrayMarshalling/UnalignedStructArray/MarshalUnalignedStructArray.cs new file mode 100644 index 0000000000000..1ee3e7d5b4b13 --- /dev/null +++ b/src/tests/Interop/ArrayMarshalling/UnalignedStructArray/MarshalUnalignedStructArray.cs @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.Runtime.InteropServices; +using TestLibrary; +using Xunit; + +public static unsafe class MarshalUnalignedStructArrayTest +{ + [Fact] + public static void TestEntryPoint() + { + /* + * This test validates that the size and offsets of InnerStruct and OuterStruct are as expected. + * It also demonstrates accessing unaligned data in an array. + */ + // Validate that both InnerStruct and OuterStruct have the correct size + Assert.Equal(12, sizeof(InnerStruct)); + Assert.Equal(24, sizeof(OuterStruct)); + + // Validate that the fields of InnerStruct are at the expected offsets + Assert.Equal(0, Marshal.OffsetOf("F0").ToInt32()); + Assert.Equal(8, Marshal.OffsetOf("F1").ToInt32()); + + // Validate that the fields of OuterStruct are at the expected offsets + Assert.Equal(0, Marshal.OffsetOf("F0").ToInt32()); + Assert.Equal(8, Marshal.OffsetOf("F1").ToInt32()); + Assert.Equal(20, Marshal.OffsetOf("F2").ToInt32()); + + // Validate that we are able to access unaligned in an array + InnerStruct[] arrStructs = new InnerStruct[] + { + new InnerStruct(1, 2), + new InnerStruct(3, 4), + new InnerStruct(5, 6), + }; + + fixed (InnerStruct* pStruct = &arrStructs[0]) + { + byte* ptr = (byte*)pStruct; + ptr += 12; + Assert.Equal(3, *(int*)ptr); + Assert.Equal(4, *(int*)(ptr + 8)); + } + + } +} + +[StructLayout(LayoutKind.Sequential, Size = 12)] +struct InnerStruct +{ + public long F0; + public uint F1; + + public InnerStruct(long f0, uint f1) + { + F0 = f0; + F1 = f1; + } +} + +[StructLayout(LayoutKind.Sequential, Size = 24)] +struct OuterStruct +{ + public sbyte F0; + public InnerStruct F1; + public uint F2; + + public OuterStruct(sbyte f0, InnerStruct f1, uint f2) + { + F0 = f0; + F1 = f1; + F2 = f2; + } +} From 2c8125fd5e3e0921a10732155e6128caf2dc5315 Mon Sep 17 00:00:00 2001 From: Matous Kozak Date: Mon, 29 Apr 2024 17:25:16 +0200 Subject: [PATCH 3/3] fix cast --- .../UnalignedStructArray/MarshalUnalignedStructArray.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Interop/ArrayMarshalling/UnalignedStructArray/MarshalUnalignedStructArray.cs b/src/tests/Interop/ArrayMarshalling/UnalignedStructArray/MarshalUnalignedStructArray.cs index 1ee3e7d5b4b13..266a5dbf28d83 100644 --- a/src/tests/Interop/ArrayMarshalling/UnalignedStructArray/MarshalUnalignedStructArray.cs +++ b/src/tests/Interop/ArrayMarshalling/UnalignedStructArray/MarshalUnalignedStructArray.cs @@ -39,7 +39,7 @@ public static void TestEntryPoint() { byte* ptr = (byte*)pStruct; ptr += 12; - Assert.Equal(3, *(int*)ptr); + Assert.Equal(3, *(long*)ptr); Assert.Equal(4, *(int*)(ptr + 8)); }