Skip to content

Commit

Permalink
[mono] Force Mono to respect explicit struct size when LayoutKind.Seq…
Browse files Browse the repository at this point in the history
…uential is used (dotnet#101529)

* respect explicit size with sequential layout

* test for sequential layout with explicit size
  • Loading branch information
matouskozak committed Apr 30, 2024
1 parent ee4bc7e commit 0fa267d
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/mono/mono/metadata/class-init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
7 changes: 5 additions & 2 deletions src/mono/mono/metadata/marshal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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<InnerStruct>("F0").ToInt32());
Assert.Equal(8, Marshal.OffsetOf<InnerStruct>("F1").ToInt32());

// Validate that the fields of OuterStruct are at the expected offsets
Assert.Equal(0, Marshal.OffsetOf<OuterStruct>("F0").ToInt32());
Assert.Equal(8, Marshal.OffsetOf<OuterStruct>("F1").ToInt32());
Assert.Equal(20, Marshal.OffsetOf<OuterStruct>("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, *(long*)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;
}
}

0 comments on commit 0fa267d

Please sign in to comment.