Skip to content

Commit

Permalink
[mono] Fix min alignment of structures with explicit layout. (dotnet#…
Browse files Browse the repository at this point in the history
  • Loading branch information
vargaz authored Aug 16, 2023
1 parent 227e882 commit a39262b
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 6 deletions.
9 changes: 3 additions & 6 deletions src/mono/mono/metadata/marshal.c
Original file line number Diff line number Diff line change
Expand Up @@ -5764,21 +5764,18 @@ mono_marshal_load_type_info (MonoClass* klass)
if (m_class_get_byval_arg (klass)->type == MONO_TYPE_PTR)
info->native_size = TARGET_SIZEOF_VOID_P;

gboolean align_size = TRUE;
if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT) {
info->native_size = MAX (native_size, info->native_size);
/*
* If the provided Size is equal or larger than the calculated size, and there
* was no Pack attribute, we set min_align to 1 to avoid native_size being increased
*/
if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
if (native_size && native_size == info->native_size && m_class_get_packing_size (klass) == 0)
min_align = 1;
align_size = FALSE;
else
min_align = MIN (min_align, packing);
}
}

if (info->native_size & (min_align - 1)) {
if (info->native_size & (min_align - 1) && align_size) {
info->native_size += min_align - 1;
info->native_size &= ~(min_align - 1);
}
Expand Down
120 changes: 120 additions & 0 deletions src/tests/JIT/Regression/JitBlue/Runtime_90531/Runtime_90531.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// 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 Xunit;

public class Runtime_90531
{
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct StructA
{
[FieldOffset(0)]
public long Field0;
}

public struct StructB
{
public int Field0;
// padded 4
public StructA Field1;
// no padding
public int Field2;
}

// Size should be 16 in both 32 and 64 bits win/linux
// Size should be 12 on 32bits OSX size alignment of long is 4
[StructLayout (LayoutKind.Explicit)]
struct TestStruct8 {
[FieldOffset (0)]
public int a;
[FieldOffset (4)]
public ulong b;
}

// Size should be 12 in both 32 and 64 bits
[StructLayout (LayoutKind.Explicit, Size=12)]
struct TestStruct9 {
[FieldOffset (0)]
public int a;
[FieldOffset (4)]
public ulong b;
}

// Size should be 16 in both 32 and 64 bits
// Size should be 12 on 32bits OSX size alignment of long is 4
[StructLayout (LayoutKind.Explicit)]
struct TestStruct10 {
[FieldOffset (0)]
public int a;
[FieldOffset (3)]
public ulong b;
}

// Size should be 11 in both 32 and 64 bits
[StructLayout (LayoutKind.Explicit, Size=11)]
struct TestStruct11 {
[FieldOffset (0)]
public int a;
[FieldOffset (3)]
public ulong b;
}

[StructLayout (LayoutKind.Explicit, Pack=1)]
struct TestStruct12 {
[FieldOffset (0)]
public short a;
[FieldOffset (2)]
public int b;
}

// Size should always be 12, since pack = 0, size = 0 and min alignment = 4
//When pack is not set, we default to 8, so min (8, min alignment) -> 4
[StructLayout (LayoutKind.Explicit)]
struct TestStruct13 {
[FieldOffset(0)]
int one;
[FieldOffset(4)]
int two;
[FieldOffset(8)]
int three;
}

// Size should always be 12, since pack = 8, size = 0 and min alignment = 4
//It's aligned to min (pack, min alignment) -> 4
[StructLayout (LayoutKind.Explicit)]
struct TestStruct14 {
[FieldOffset(0)]
int one;
[FieldOffset(4)]
int two;
[FieldOffset(8)]
int three;
}

[Fact]
public unsafe static int EntryPoint()
{
void* mem = stackalloc byte[24];
Marshal.WriteInt32((IntPtr)mem, 0, 1);
Marshal.WriteInt64((IntPtr)mem, 8, 2);
Marshal.WriteInt32((IntPtr)mem, 16, 3);

var s = Marshal.PtrToStructure<StructB>((IntPtr)mem);

if (s.Field1.Field0 != 2)
return 101;
if(Marshal.SizeOf(typeof(TestStruct8)) != 16)
return 102;
if(Marshal.SizeOf(typeof(TestStruct9)) != 12)
return 103;
if(Marshal.SizeOf(typeof(TestStruct10)) != 16)
return 104;
if(Marshal.SizeOf(typeof(TestStruct11)) != 11)
return 105;
if(Marshal.SizeOf(typeof(TestStruct12)) != 6)
return 106;
return 100;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Optimize>True</Optimize>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
</ItemGroup>
</Project>

0 comments on commit a39262b

Please sign in to comment.