Skip to content

Commit db44883

Browse files
vargazUnityAlex
authored andcommitted
[mono] Fix min alignment of structures with explicit layout. (#90632)
Fixes dotnet/runtime#90531.
1 parent f68166e commit db44883

File tree

3 files changed

+132
-6
lines changed

3 files changed

+132
-6
lines changed

mono/metadata/marshal.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5879,21 +5879,18 @@ mono_marshal_load_type_info (MonoClass* klass)
58795879
if (m_class_get_byval_arg (klass)->type == MONO_TYPE_PTR)
58805880
info->native_size = TARGET_SIZEOF_VOID_P;
58815881

5882+
gboolean align_size = TRUE;
58825883
if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT) {
58835884
info->native_size = MAX (native_size, info->native_size);
5884-
/*
5885-
* If the provided Size is equal or larger than the calculated size, and there
5886-
* was no Pack attribute, we set min_align to 1 to avoid native_size being increased
5887-
*/
58885885
if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
58895886
if (native_size && native_size == info->native_size && m_class_get_packing_size (klass) == 0)
5890-
min_align = 1;
5887+
align_size = FALSE;
58915888
else
58925889
min_align = MIN (min_align, packing);
58935890
}
58945891
}
58955892

5896-
if (info->native_size & (min_align - 1)) {
5893+
if (info->native_size & (min_align - 1) && align_size) {
58975894
info->native_size += min_align - 1;
58985895
info->native_size &= ~(min_align - 1);
58995896
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Runtime.InteropServices;
6+
using Xunit;
7+
8+
public class Runtime_90531
9+
{
10+
[StructLayout(LayoutKind.Explicit, Size = 8)]
11+
public struct StructA
12+
{
13+
[FieldOffset(0)]
14+
public long Field0;
15+
}
16+
17+
public struct StructB
18+
{
19+
public int Field0;
20+
// padded 4
21+
public StructA Field1;
22+
// no padding
23+
public int Field2;
24+
}
25+
26+
// Size should be 16 in both 32 and 64 bits win/linux
27+
// Size should be 12 on 32bits OSX size alignment of long is 4
28+
[StructLayout (LayoutKind.Explicit)]
29+
struct TestStruct8 {
30+
[FieldOffset (0)]
31+
public int a;
32+
[FieldOffset (4)]
33+
public ulong b;
34+
}
35+
36+
// Size should be 12 in both 32 and 64 bits
37+
[StructLayout (LayoutKind.Explicit, Size=12)]
38+
struct TestStruct9 {
39+
[FieldOffset (0)]
40+
public int a;
41+
[FieldOffset (4)]
42+
public ulong b;
43+
}
44+
45+
// Size should be 16 in both 32 and 64 bits
46+
// Size should be 12 on 32bits OSX size alignment of long is 4
47+
[StructLayout (LayoutKind.Explicit)]
48+
struct TestStruct10 {
49+
[FieldOffset (0)]
50+
public int a;
51+
[FieldOffset (3)]
52+
public ulong b;
53+
}
54+
55+
// Size should be 11 in both 32 and 64 bits
56+
[StructLayout (LayoutKind.Explicit, Size=11)]
57+
struct TestStruct11 {
58+
[FieldOffset (0)]
59+
public int a;
60+
[FieldOffset (3)]
61+
public ulong b;
62+
}
63+
64+
[StructLayout (LayoutKind.Explicit, Pack=1)]
65+
struct TestStruct12 {
66+
[FieldOffset (0)]
67+
public short a;
68+
[FieldOffset (2)]
69+
public int b;
70+
}
71+
72+
// Size should always be 12, since pack = 0, size = 0 and min alignment = 4
73+
//When pack is not set, we default to 8, so min (8, min alignment) -> 4
74+
[StructLayout (LayoutKind.Explicit)]
75+
struct TestStruct13 {
76+
[FieldOffset(0)]
77+
int one;
78+
[FieldOffset(4)]
79+
int two;
80+
[FieldOffset(8)]
81+
int three;
82+
}
83+
84+
// Size should always be 12, since pack = 8, size = 0 and min alignment = 4
85+
//It's aligned to min (pack, min alignment) -> 4
86+
[StructLayout (LayoutKind.Explicit)]
87+
struct TestStruct14 {
88+
[FieldOffset(0)]
89+
int one;
90+
[FieldOffset(4)]
91+
int two;
92+
[FieldOffset(8)]
93+
int three;
94+
}
95+
96+
[Fact]
97+
public unsafe static int EntryPoint()
98+
{
99+
void* mem = stackalloc byte[24];
100+
Marshal.WriteInt32((IntPtr)mem, 0, 1);
101+
Marshal.WriteInt64((IntPtr)mem, 8, 2);
102+
Marshal.WriteInt32((IntPtr)mem, 16, 3);
103+
104+
var s = Marshal.PtrToStructure<StructB>((IntPtr)mem);
105+
106+
if (s.Field1.Field0 != 2)
107+
return 101;
108+
if(Marshal.SizeOf(typeof(TestStruct8)) != 16)
109+
return 102;
110+
if(Marshal.SizeOf(typeof(TestStruct9)) != 12)
111+
return 103;
112+
if(Marshal.SizeOf(typeof(TestStruct10)) != 16)
113+
return 104;
114+
if(Marshal.SizeOf(typeof(TestStruct11)) != 11)
115+
return 105;
116+
if(Marshal.SizeOf(typeof(TestStruct12)) != 6)
117+
return 106;
118+
return 100;
119+
}
120+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<Optimize>True</Optimize>
4+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<Compile Include="$(MSBuildProjectName).cs" />
8+
</ItemGroup>
9+
</Project>

0 commit comments

Comments
 (0)