From 3db080c12ff2bf6fd4acc09109edeaee7c087dbb Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Wed, 27 Sep 2023 06:30:23 -0700 Subject: [PATCH] Add tests for `UnsafeAccessor` on fields on generic types (#92657) * Add tests for field access on generics The tests are currently disabled. * Fix ILC to compile UnsafeAccessorsTests UnsafeAccessorsTests passes on NAOT. --- .../Common/TypeSystem/IL/UnsafeAccessors.cs | 18 +++--- .../UnsafeAccessors/UnsafeAccessorsTests.cs | 63 ++++++++++++++++++- 2 files changed, 70 insertions(+), 11 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/UnsafeAccessors.cs b/src/coreclr/tools/Common/TypeSystem/IL/UnsafeAccessors.cs index e9c9b52621369..6338f725be223 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/UnsafeAccessors.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/UnsafeAccessors.cs @@ -71,13 +71,12 @@ public static MethodIL TryGetIL(EcmaMethod method) return GenerateAccessorBadImageFailure(method); } - const string ctorName = ".ctor"; - context.TargetType = ValidateTargetType(retType); - if (context.TargetType == null) + if (!ValidateTargetType(retType, out context.TargetType)) { return GenerateAccessorBadImageFailure(method); } + const string ctorName = ".ctor"; if (!TrySetTargetMethod(ref context, ctorName, out isAmbiguous)) { return GenerateAccessorSpecificFailure(ref context, ctorName, isAmbiguous); @@ -100,8 +99,7 @@ public static MethodIL TryGetIL(EcmaMethod method) return GenerateAccessorBadImageFailure(method); } - context.TargetType = ValidateTargetType(firstArgType); - if (context.TargetType == null) + if (!ValidateTargetType(firstArgType, out context.TargetType)) { return GenerateAccessorBadImageFailure(method); } @@ -132,8 +130,7 @@ public static MethodIL TryGetIL(EcmaMethod method) return GenerateAccessorBadImageFailure(method); } - context.TargetType = ValidateTargetType(firstArgType); - if (context.TargetType == null) + if (!ValidateTargetType(firstArgType, out context.TargetType)) { return GenerateAccessorBadImageFailure(method); } @@ -221,7 +218,7 @@ private struct GenerationContext public FieldDesc TargetField; } - private static TypeDesc ValidateTargetType(TypeDesc targetTypeMaybe) + private static bool ValidateTargetType(TypeDesc targetTypeMaybe, out TypeDesc validated) { TypeDesc targetType = targetTypeMaybe.IsByRef ? ((ParameterizedType)targetTypeMaybe).ParameterType @@ -232,10 +229,11 @@ private static TypeDesc ValidateTargetType(TypeDesc targetTypeMaybe) if ((targetType.IsParameterizedType && !targetType.IsArray) || targetType.IsFunctionPointer) { - ThrowHelper.ThrowBadImageFormatException(); + targetType = null; } - return targetType; + validated = targetType; + return validated != null; } private static bool DoesMethodMatchUnsafeAccessorDeclaration(ref GenerationContext context, MethodDesc method, bool ignoreCustomModifiers) diff --git a/src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.cs b/src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.cs index af69c37545b8f..c524802b968be 100644 --- a/src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.cs +++ b/src/tests/baseservices/compilerservices/UnsafeAccessors/UnsafeAccessorsTests.cs @@ -43,7 +43,7 @@ private static void _MVV() {} private void _mvv() {} // The "init" is important to have here - custom modifier test. - // The signature of set_Prop is + // The signature of set_Prop is // instance void modreq([System.Runtime]System.Runtime.CompilerServices.IsExternalInit) set_Prop ( string 'value') private string Prop { get; init; } @@ -85,6 +85,33 @@ struct UserDataValue public string GetFieldValue() => _f; } + class UserDataGenericClass + { + public const string StaticGenericFieldName = nameof(_GF); + public const string GenericFieldName = nameof(_gf); + public const string StaticGenericMethodName = nameof(_GM); + public const string GenericMethodName = nameof(_gm); + + public const string StaticFieldName = nameof(_F); + public const string FieldName = nameof(_f); + public const string StaticMethodName = nameof(_M); + public const string MethodName = nameof(_m); + + private static T _GF; + private T _gf; + + private static string _F = PrivateStatic; + private string _f; + + public UserDataGenericClass() { _f = Private; } + + private static string _GM(T s, ref T sr, in T si) => typeof(T).ToString(); + private string _gm(T s, ref T sr, in T si) => typeof(T).ToString(); + + private static string _M(string s, ref string sr, in string si) => s; + private string _m(string s, ref string sr, in string si) => s; + } + [UnsafeAccessor(UnsafeAccessorKind.Constructor)] extern static UserDataClass CallPrivateConstructorClass(); @@ -188,6 +215,23 @@ public static void Verify_AccessFieldClass() extern static ref string GetPrivateField(UserDataClass d); } + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/92633")] + public static void Verify_AccessStaticFieldGenericClass() + { + Console.WriteLine($"Running {nameof(Verify_AccessStaticFieldGenericClass)}"); + + Assert.Equal(PrivateStatic, GetPrivateStaticFieldInt((UserDataGenericClass)null)); + + Assert.Equal(PrivateStatic, GetPrivateStaticFieldString((UserDataGenericClass)null)); + + [UnsafeAccessor(UnsafeAccessorKind.StaticField, Name=UserDataGenericClass.StaticFieldName)] + extern static ref string GetPrivateStaticFieldInt(UserDataGenericClass d); + + [UnsafeAccessor(UnsafeAccessorKind.StaticField, Name=UserDataGenericClass.StaticFieldName)] + extern static ref string GetPrivateStaticFieldString(UserDataGenericClass d); + } + [Fact] public static void Verify_AccessStaticFieldValue() { @@ -215,6 +259,23 @@ public static void Verify_AccessFieldValue() extern static ref string GetPrivateField(ref UserDataValue d); } + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/92633")] + public static void Verify_AccessFieldGenericClass() + { + Console.WriteLine($"Running {nameof(Verify_AccessFieldGenericClass)}"); + + Assert.Equal(Private, GetPrivateFieldInt(new UserDataGenericClass())); + + Assert.Equal(Private, GetPrivateFieldString(new UserDataGenericClass())); + + [UnsafeAccessor(UnsafeAccessorKind.Field, Name=UserDataGenericClass.FieldName)] + extern static ref string GetPrivateFieldInt(UserDataGenericClass d); + + [UnsafeAccessor(UnsafeAccessorKind.Field, Name=UserDataGenericClass.FieldName)] + extern static ref string GetPrivateFieldString(UserDataGenericClass d); + } + [Fact] public static void Verify_AccessStaticMethodClass() {