-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Resolve ILLink warnings in System.Linq.Expressions (Round 1) #47585
Resolve ILLink warnings in System.Linq.Expressions (Round 1) #47585
Conversation
Tagging subscribers to this area: @cston Issue DetailsContributes to #45623 This is just round 1. At least one more round will be made where we start annotating APIs as
|
...libraries/System.Linq.Expressions/src/System/Linq/Expressions/Interpreter/CallInstruction.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Interpreter/TypeOperations.cs
Outdated
Show resolved
Hide resolved
...ft.Extensions.DependencyInjection/src/ServiceLookup/Expressions/ExpressionResolverBuilder.cs
Outdated
Show resolved
Hide resolved
...libraries/System.Linq.Expressions/src/System/Linq/Expressions/Interpreter/CallInstruction.cs
Outdated
Show resolved
Hide resolved
...libraries/System.Linq.Expressions/src/System/Linq/Expressions/Interpreter/CallInstruction.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Interpreter/TypeOperations.cs
Outdated
Show resolved
Hide resolved
Thanks for the feedback! I believe I've addressed it, please take another look. |
private readonly Type _defaultValueType; | ||
|
||
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2074:UnrecognizedReflectionPattern", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This suppression will only be correct if we replace the Activator.CreateInstance with GetUninitializedObject. Are we sure we won't forget to revisit this if the resolution of the new bug is unexpected?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you saying it isn't correct because trimming will cause Activator.CreateInstance
to fail? Or are you saying it is incorrect based on if value types get a parameterless constructor, and the trimmer removes it, causing a behavior change between trimmed and untrimmed apps?
Either way I've called this out in #47647.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The latter. The annotation on the field is writing checks no consumer can cash (because the suppression that makes is possible is incorrect).
I would keep the suppression on the Run
method where it was before because once we swap this for GetUnitializedObject we can say something along the lines of "this is okay to suppress because trimming always considers valuetypes boxed" - which is what we need for the suppression on GetUninitializedObject
to be safe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the spirit of this comment (and remembering I made the same suppression elsewhere), I tried changing the following code from Activator.CreateInstance
to RuntimeHelpers.GetUninitializedObject
:
runtime/src/libraries/Common/src/Extensions/ParameterDefaultValue/ParameterDefaultValue.cs
Lines 42 to 50 in d1c0fa8
// Workaround for https://github.com/dotnet/runtime/issues/18599 | |
if (defaultValue == null && parameter.ParameterType.IsValueType) | |
{ | |
defaultValue = CreateValueType(parameter.ParameterType); | |
} | |
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:UnrecognizedReflectionPattern", | |
Justification = "CreateInstance is only called on a ValueType, which will always have a default constructor.")] | |
static object? CreateValueType(Type t) => Activator.CreateInstance(t); |
However, unit tests started failing. This is because RuntimeHelpers.GetUninitializedObject
using a Nullable<T>
type doesn't return null
, like Activator.CreateInstance
:
t = typeof(Nullable<int>);
Console.WriteLine($"Activator Is Null? {Activator.CreateInstance(t) == null}");
Console.WriteLine($"GetUninitializedObject Is Null? {RuntimeHelpers.GetUninitializedObject(t) == null}");
prints
Activator Is Null? True
GetUninitializedObject Is Null? False
This won't be a problem for this specific site, since you can't have a Nullable<Nullable<T>>
. But for ParameterDefaultVale (and potentially other places), these two APIs aren't interchangeable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. Something we need to keep in mind as we go fixing incorrect usages of CreateInstance.
Test failure is #47728. |
Contributes to #45623
This is just round 1. At least one more round will be made where we start annotating APIs as
RequiresUnreferencedCode
.