diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index 82499f314e4f3d..19a63dd9255443 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -8391,7 +8391,6 @@ MethodTableBuilder::HandleExplicitLayout( { STANDARD_VM_CONTRACT; - // Instance slice size is the total size of an instance, and is calculated as // the field whose offset and size add to the greatest number. UINT instanceSliceSize = 0; @@ -8426,13 +8425,13 @@ MethodTableBuilder::HandleExplicitLayout( pFieldLayout[i] = empty; } - // go through each field and look for invalid layout + // Go through each field and look for invalid layout. // (note that we are more permissive than what Ecma allows. We only disallow the minimum set necessary to // close security holes.) // - // This is what we implment: + // This is what we implement: // - // 1. Verify that every OREF is on a valid alignment + // 1. Verify that every OREF or BYREF is on a valid alignment. // 2. Verify that OREFs only overlap with other OREFs. // 3. If an OREF does overlap with another OREF, the class is marked unverifiable. // 4. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()). @@ -8445,7 +8444,6 @@ MethodTableBuilder::HandleExplicitLayout( isObject[i] = oref; } - ExplicitClassTrust explicitClassTrust; UINT valueClassCacheIndex = ((UINT)(-1)); @@ -8481,7 +8479,8 @@ MethodTableBuilder::HandleExplicitLayout( // "i" indexes all fields, valueClassCacheIndex indexes non-static fields only. Don't get them confused! valueClassCacheIndex++; - if (CorTypeInfo::IsObjRef(pFD->GetFieldType())) + CorElementType type = pFD->GetFieldType(); + if (CorTypeInfo::IsObjRef(type) || CorTypeInfo::IsByRef(type)) { // Check that the ref offset is pointer aligned if ((pFD->GetOffset_NoLogging() & ((ULONG)TARGET_POINTER_SIZE - 1)) != 0) @@ -8489,9 +8488,13 @@ MethodTableBuilder::HandleExplicitLayout( badOffset = pFD->GetOffset_NoLogging(); fieldTrust.SetTrust(ExplicitFieldTrust::kNone); - // If we got here, OREF field was not pointer aligned. THROW. + // If we got here, OREF or BYREF field was not pointer aligned. THROW. break; } + } + + if (CorTypeInfo::IsObjRef(type)) + { // check if overlaps another object if (memcmp((void *)&pFieldLayout[pFD->GetOffset_NoLogging()], (void *)isObject, sizeof(isObject)) == 0) { diff --git a/src/mono/mono/metadata/class-init.c b/src/mono/mono/metadata/class-init.c index 00ab30ffbd76f2..36fdd82960f83b 100644 --- a/src/mono/mono/metadata/class-init.c +++ b/src/mono/mono/metadata/class-init.c @@ -346,6 +346,10 @@ mono_class_setup_fields (MonoClass *klass) mono_class_set_type_load_failure (klass, "Missing field layout info for %s", field->name); break; } + if (m_type_is_byref (field->type) && (offset % MONO_ABI_ALIGNOF (gpointer) != 0)) { + mono_class_set_type_load_failure (klass, "Field '%s' has an invalid offset", field->name); + break; + } if (offset < -1) { /*-1 is used to encode special static fields */ mono_class_set_type_load_failure (klass, "Field '%s' has a negative offset %d", field->name, offset); break; diff --git a/src/tests/Loader/classloader/RefFields/InvalidCSharp.il b/src/tests/Loader/classloader/RefFields/InvalidCSharp.il index cb012cf23b7ecb..768f603f22d55c 100644 --- a/src/tests/Loader/classloader/RefFields/InvalidCSharp.il +++ b/src/tests/Loader/classloader/RefFields/InvalidCSharp.il @@ -5,26 +5,46 @@ .assembly InvalidCSharp { } -.class public auto ansi sealed beforefieldinit InvalidCSharp.InvalidStructWithRefField +.class public sequential ansi sealed beforefieldinit InvalidCSharp.InvalidStructWithRefField extends [System.Runtime]System.ValueType { // Type requires IsByRefLikeAttribute to be valid. - .field public string& invalid + .field public string& Invalid +} + +.class public explicit ansi sealed beforefieldinit InvalidCSharp.InvalidRefFieldAlignment + extends [System.Runtime]System.ValueType +{ + .custom instance void [System.Runtime]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = ( + 01 00 00 00 + ) + .field [0] public int16 Field + .field [2] public int32& Invalid +} + +.class public explicit ansi sealed beforefieldinit InvalidCSharp.InvalidObjectRefRefFieldOverlap + extends [System.Runtime]System.ValueType +{ + .custom instance void [System.Runtime]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = ( + 01 00 00 00 + ) + .field [0] public object Field + .field [0] public int32& Invalid } // This is invalid metadata and is unable to be loaded. // - [field sig] (0x80131815 (VER_E_FIELD_SIG)) // -// .class public auto ansi sealed beforefieldinit InvalidCSharp.InvalidStructWithStaticRefField +// .class public sequential ansi sealed beforefieldinit InvalidCSharp.InvalidStructWithStaticRefField // extends [System.Runtime]System.ValueType // { // .custom instance void [System.Runtime]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = ( // 01 00 00 00 // ) -// .field public static string& invalid +// .field public static string& Invalid // } -.class public auto ansi sealed beforefieldinit InvalidCSharp.WithRefField +.class public sequential ansi sealed beforefieldinit InvalidCSharp.WithRefField extends [System.Runtime]System.ValueType { .custom instance void [System.Runtime]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = ( @@ -57,7 +77,7 @@ } } -.class public auto ansi sealed beforefieldinit InvalidCSharp.WithRefStructField +.class public sequential ansi sealed beforefieldinit InvalidCSharp.WithRefStructField extends [System.Runtime]System.ValueType { .custom instance void [System.Runtime]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = ( @@ -91,7 +111,7 @@ } } -.class public auto ansi sealed beforefieldinit InvalidCSharp.WithTypedReferenceField`1 +.class public sequential ansi sealed beforefieldinit InvalidCSharp.WithTypedReferenceField`1 extends [System.Runtime]System.ValueType { .custom instance void [System.Runtime]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = ( diff --git a/src/tests/Loader/classloader/RefFields/Validate.cs b/src/tests/Loader/classloader/RefFields/Validate.cs index 3e8d3b76d23d00..b286d51f2f6aae 100644 --- a/src/tests/Loader/classloader/RefFields/Validate.cs +++ b/src/tests/Loader/classloader/RefFields/Validate.cs @@ -15,6 +15,8 @@ public static void Validate_Invalid_RefField_Fails() { Console.WriteLine($"{nameof(Validate_Invalid_RefField_Fails)}..."); Assert.Throws(() => { var t = typeof(InvalidStructWithRefField); }); + Assert.Throws(() => { var t = typeof(InvalidRefFieldAlignment); }); + Assert.Throws(() => { var t = typeof(InvalidObjectRefRefFieldOverlap); }); } [Fact]