From 072ebe7c115e80bf2555bb5f02049379e6bf9722 Mon Sep 17 00:00:00 2001 From: Vitek Karas <10670590+vitek-karas@users.noreply.github.com> Date: Thu, 14 Jul 2022 12:38:12 -0700 Subject: Fix a bug with null value passed to annotated parameter on attribute (#2894) This also makes small tweaks to help with linker->AOT sync. --- src/linker/Linker.Dataflow/AttributeDataFlow.cs | 5 ++++- .../Linker.Dataflow/CompilerGeneratedCallGraph.cs | 10 ++++----- .../Linker.Dataflow/CompilerGeneratedState.cs | 12 ++++++----- .../DataFlow/AttributeConstructorDataflow.cs | 19 ++++++++++++++++ .../DataFlow/AttributeFieldDataflow.cs | 23 ++++++++++++++++++++ .../DataFlow/AttributePropertyDataflow.cs | 25 ++++++++++++++++++++++ 6 files changed, 83 insertions(+), 11 deletions(-) diff --git a/src/linker/Linker.Dataflow/AttributeDataFlow.cs b/src/linker/Linker.Dataflow/AttributeDataFlow.cs index 357803a76..3ed11d392 100644 --- a/src/linker/Linker.Dataflow/AttributeDataFlow.cs +++ b/src/linker/Linker.Dataflow/AttributeDataFlow.cs @@ -50,6 +50,9 @@ namespace Mono.Linker.Dataflow MultiValue GetValueForCustomAttributeArgument (CustomAttributeArgument argument) { if (argument.Type.Name == "Type") { + if (argument.Value is null) + return NullValue.Instance; + TypeDefinition? referencedType = ((TypeReference) argument.Value).ResolveToTypeDefinition (_context); return referencedType == null ? UnknownValue.Instance @@ -57,7 +60,7 @@ namespace Mono.Linker.Dataflow } if (argument.Type.MetadataType == MetadataType.String) - return new KnownStringValue ((string) argument.Value); + return argument.Value is null ? NullValue.Instance : new KnownStringValue ((string) argument.Value); // We shouldn't have gotten a non-null annotation for this from GetParameterAnnotation throw new InvalidOperationException (); diff --git a/src/linker/Linker.Dataflow/CompilerGeneratedCallGraph.cs b/src/linker/Linker.Dataflow/CompilerGeneratedCallGraph.cs index 551ff51e5..1cfbc8770 100644 --- a/src/linker/Linker.Dataflow/CompilerGeneratedCallGraph.cs +++ b/src/linker/Linker.Dataflow/CompilerGeneratedCallGraph.cs @@ -9,15 +9,15 @@ namespace Mono.Linker.Dataflow { sealed class CompilerGeneratedCallGraph { - readonly Dictionary> callGraph; + readonly Dictionary> _callGraph; - public CompilerGeneratedCallGraph () => callGraph = new Dictionary> (); + public CompilerGeneratedCallGraph () => _callGraph = new Dictionary> (); void TrackCallInternal (IMemberDefinition fromMember, IMemberDefinition toMember) { - if (!callGraph.TryGetValue (fromMember, out HashSet? toMembers)) { + if (!_callGraph.TryGetValue (fromMember, out HashSet? toMembers)) { toMembers = new HashSet (); - callGraph.Add (fromMember, toMembers); + _callGraph.Add (fromMember, toMembers); } toMembers.Add (toMember); } @@ -48,7 +48,7 @@ namespace Mono.Linker.Dataflow visited.Add (start); queue.Enqueue (start); while (queue.TryDequeue (out IMemberDefinition? method)) { - if (!callGraph.TryGetValue (method, out HashSet? callees)) + if (!_callGraph.TryGetValue (method, out HashSet? callees)) continue; foreach (var callee in callees) { diff --git a/src/linker/Linker.Dataflow/CompilerGeneratedState.cs b/src/linker/Linker.Dataflow/CompilerGeneratedState.cs index 2802e6703..c99968f1d 100644 --- a/src/linker/Linker.Dataflow/CompilerGeneratedState.cs +++ b/src/linker/Linker.Dataflow/CompilerGeneratedState.cs @@ -102,7 +102,7 @@ namespace Mono.Linker.Dataflow /// up and find the nearest containing user type. Returns the nearest user type, /// or null if none was found. /// - TypeDefinition? PopulateCacheForType (TypeDefinition type) + TypeDefinition? GetCompilerGeneratedStateForType (TypeDefinition type) { // Look in the declaring type if this is a compiler-generated type (state machine or display class). // State machines can be emitted into display classes, so we may also need to go one more level up. @@ -183,7 +183,7 @@ namespace Mono.Linker.Dataflow } // Already warned above if multiple methods map to the same type // Fill in null for argument providers now, the real providers will be filled in later - _ = _generatedTypeToTypeArgumentInfo.TryAdd (stateMachineType, new TypeArgumentInfo (method, null)); + _generatedTypeToTypeArgumentInfo[stateMachineType] = new TypeArgumentInfo (method, null); } } @@ -292,6 +292,7 @@ namespace Mono.Linker.Dataflow if (typeRef is null) { return; } + for (int i = 0; i < typeRef.GenericArguments.Count; i++) { var typeArg = typeRef.GenericArguments[i]; // Start with the existing parameters, in case we can't find the mapped one @@ -321,6 +322,7 @@ namespace Mono.Linker.Dataflow typeArgs[i] = userAttrs; } + _generatedTypeToTypeArgumentInfo[generatedType] = typeInfo with { OriginalAttributes = typeArgs }; } } @@ -356,7 +358,7 @@ namespace Mono.Linker.Dataflow if (IsNestedFunctionOrStateMachineMember (method)) return false; - var typeToCache = PopulateCacheForType (method.DeclaringType); + var typeToCache = GetCompilerGeneratedStateForType (method.DeclaringType); if (typeToCache is null) return false; @@ -371,7 +373,7 @@ namespace Mono.Linker.Dataflow { Debug.Assert (CompilerGeneratedNames.IsGeneratedType (generatedType.Name)); - var typeToCache = PopulateCacheForType (generatedType); + var typeToCache = GetCompilerGeneratedStateForType (generatedType); if (typeToCache is null) return null; @@ -407,7 +409,7 @@ namespace Mono.Linker.Dataflow // sourceType is a state machine type, or the type containing a lambda or local function. // Search all methods to find the one which points to the type as its // state machine implementation. - var typeToCache = PopulateCacheForType (sourceType); + var typeToCache = GetCompilerGeneratedStateForType (sourceType); if (typeToCache is null) return false; diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs index 46120679c..f6747be82 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs @@ -16,9 +16,11 @@ namespace Mono.Linker.Tests.Cases.DataFlow { [KeptAttributeAttribute (typeof (KeepsPublicConstructorAttribute))] [KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))] + [KeptAttributeAttribute (typeof (KeepsPublicFieldsAttribute))] [KeptAttributeAttribute (typeof (TypeArrayAttribute))] [KeepsPublicConstructor (typeof (ClassWithKeptPublicConstructor))] [KeepsPublicMethods ("Mono.Linker.Tests.Cases.DataFlow.AttributeConstructorDataflow+ClassWithKeptPublicMethods")] + [KeepsPublicFields (null, null)] [TypeArray (new Type[] { typeof (AttributeConstructorDataflow) })] // Trimmer only for now - https://github.com/dotnet/linker/issues/2273 [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", ProducedBy = ProducedBy.Trimmer)] @@ -55,6 +57,23 @@ namespace Mono.Linker.Tests.Cases.DataFlow } } + // Used to test null parameter values + [Kept] + [KeptBaseType (typeof (Attribute))] + class KeepsPublicFieldsAttribute : Attribute + { + [Kept] + public KeepsPublicFieldsAttribute ( + [KeptAttributeAttribute(typeof(DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] + Type type, + [KeptAttributeAttribute(typeof(DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] + string typeName) + { + } + } + [Kept] class ClassWithKeptPublicConstructor { diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/AttributeFieldDataflow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/AttributeFieldDataflow.cs index 2cac037c5..01fa19c20 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/AttributeFieldDataflow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/AttributeFieldDataflow.cs @@ -16,9 +16,11 @@ namespace Mono.Linker.Tests.Cases.DataFlow { [KeptAttributeAttribute (typeof (KeepsPublicConstructorsAttribute))] [KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))] + [KeptAttributeAttribute (typeof (KeepsPublicFieldsAttribute))] [KeptAttributeAttribute (typeof (TypeArrayAttribute))] [KeepsPublicConstructors (Type = typeof (ClassWithKeptPublicConstructor))] [KeepsPublicMethods (Type = "Mono.Linker.Tests.Cases.DataFlow.AttributeFieldDataflow+ClassWithKeptPublicMethods")] + [KeepsPublicFields (Type = null, TypeName = null)] [TypeArray (Types = new Type[] { typeof (AttributeFieldDataflow) })] // Trimmer only for now - https://github.com/dotnet/linker/issues/2273 [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", ProducedBy = ProducedBy.Trimmer)] @@ -58,6 +60,27 @@ namespace Mono.Linker.Tests.Cases.DataFlow public string Type; } + // Use to test null values + [Kept] + [KeptBaseType (typeof (Attribute))] + class KeepsPublicFieldsAttribute : Attribute + { + [Kept] + public KeepsPublicFieldsAttribute () + { + } + + [Kept] + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] + public Type Type; + + [Kept] + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] + public string TypeName; + } + [Kept] class ClassWithKeptPublicConstructor { diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs index 1b10390ea..a944bb742 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs @@ -16,9 +16,11 @@ namespace Mono.Linker.Tests.Cases.DataFlow { [KeptAttributeAttribute (typeof (KeepsPublicConstructorsAttribute))] [KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))] + [KeptAttributeAttribute (typeof (KeepsPublicFieldsAttribute))] [KeptAttributeAttribute (typeof (TypeArrayAttribute))] [KeepsPublicConstructors (Type = typeof (ClassWithKeptPublicConstructor))] [KeepsPublicMethods (Type = "Mono.Linker.Tests.Cases.DataFlow.AttributePropertyDataflow+ClassWithKeptPublicMethods")] + [KeepsPublicFields (Type = null, TypeName = null)] [TypeArray (Types = new Type[] { typeof (AttributePropertyDataflow) })] // Trimmer only for now - https://github.com/dotnet/linker/issues/2273 [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", ProducedBy = ProducedBy.Trimmer)] @@ -60,6 +62,29 @@ namespace Mono.Linker.Tests.Cases.DataFlow public string Type { get; [Kept] set; } } + // Used to test null values + [Kept] + [KeptBaseType (typeof (Attribute))] + class KeepsPublicFieldsAttribute : Attribute + { + [Kept] + public KeepsPublicFieldsAttribute () + { + } + + [field: Kept] + [Kept] + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] + public Type Type { get; [Kept] set; } + + [field: Kept] + [Kept] + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] + public string TypeName { get; [Kept] set; } + } + [Kept] class ClassWithKeptPublicConstructor { -- cgit v1.2.3