diff --git a/src/Common/src/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/Common/src/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index 693d5a4a864..b1329685c0f 100644 --- a/src/Common/src/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/Common/src/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -315,7 +315,8 @@ private static ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataTy foreach (var fieldAndOffset in layoutMetadata.Offsets) { - var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldAndOffset.Field.FieldType, packingSize); + TypeDesc fieldType = fieldAndOffset.Field.FieldType; + var fieldSizeAndAlignment = ComputeFieldSizeAndAlignment(fieldType, packingSize); largestAlignmentRequired = LayoutInt.Max(fieldSizeAndAlignment.Alignment, largestAlignmentRequired); @@ -324,12 +325,13 @@ private static ComputedInstanceFieldLayout ComputeExplicitFieldLayout(MetadataTy LayoutInt computedOffset = fieldAndOffset.Offset + cumulativeInstanceFieldPos; - if (fieldAndOffset.Field.FieldType.IsGCPointer && !computedOffset.IsIndeterminate) + // GC pointers MUST be aligned. + // We treat byref-like structs as GC pointers too. + if (!computedOffset.IsIndeterminate && (fieldType.IsGCPointer || fieldType.IsByRefLike)) { int offsetModulo = computedOffset.AsInt % type.Context.Target.PointerSize; if (offsetModulo != 0) { - // GC pointers MUST be aligned. ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadExplicitLayout, type, fieldAndOffset.Offset.ToStringInvariant()); } } diff --git a/src/ILCompiler.TypeSystem/tests/CoreTestAssembly/InstanceFieldLayout.cs b/src/ILCompiler.TypeSystem/tests/CoreTestAssembly/InstanceFieldLayout.cs index da6cc41906b..188d26d8e1a 100644 --- a/src/ILCompiler.TypeSystem/tests/CoreTestAssembly/InstanceFieldLayout.cs +++ b/src/ILCompiler.TypeSystem/tests/CoreTestAssembly/InstanceFieldLayout.cs @@ -96,6 +96,24 @@ public class ExplicitEmptyClass public struct ExplicitEmptyStruct { } + + [StructLayout(LayoutKind.Explicit)] + ref struct MisalignedPointer + { + [FieldOffset(2)] + public object O; + } + + [StructLayout(LayoutKind.Explicit)] + ref struct MisalignedByRef + { + [FieldOffset(2)] + public ByRefStruct O; + } + + ref struct ByRefStruct + { + } } namespace Sequential diff --git a/src/ILCompiler.TypeSystem/tests/InstanceFieldLayoutTests.cs b/src/ILCompiler.TypeSystem/tests/InstanceFieldLayoutTests.cs index fc7b26a1770..142abfdfa84 100644 --- a/src/ILCompiler.TypeSystem/tests/InstanceFieldLayoutTests.cs +++ b/src/ILCompiler.TypeSystem/tests/InstanceFieldLayoutTests.cs @@ -112,6 +112,20 @@ public void TestExplicitTypeLayoutWithInheritance() } } + [Fact] + public void TestInvalidExplicitTypeLayout() + { + { + DefType type = _testModule.GetType("Explicit", "MisalignedPointer"); + Assert.Throws(() => type.ComputeInstanceLayout(InstanceLayoutKind.TypeAndFields)); + } + + { + DefType type = _testModule.GetType("Explicit", "MisalignedByRef"); + Assert.Throws(() => type.ComputeInstanceLayout(InstanceLayoutKind.TypeAndFields)); + } + } + [Fact] public void TestSequentialTypeLayout() {