Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[mono] Force Mono to respect explicit struct size when LayoutKind.Sequential is used #101529

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}
}
Loading