-
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
Fix analyzer treatment of flow captures of arrays #93420
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
01dc9b7
Fix analyzer treatment of flow captures of arrays
sbomer daca428
Add back comment
sbomer 3627e69
Fix expected warning
sbomer c5c4aeb
Add interpolated string handler test, fix asserts
sbomer f0726d2
Keep disabled assert as comment, add assert location
sbomer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,8 @@ | |
|
||
using System; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Runtime.CompilerServices; | ||
using System.Runtime.InteropServices; | ||
using Mono.Linker.Tests.Cases.Expectations.Assertions; | ||
using Mono.Linker.Tests.Cases.Expectations.Helpers; | ||
|
||
|
@@ -30,6 +32,7 @@ public static void Main () | |
TestArraySetElementAndInitializerMultipleElementsMix<TestType> (typeof (TestType)); | ||
|
||
TestGetElementAtUnknownIndex (); | ||
TestGetMergedArrayElement (); | ||
TestMergedArrayElementWithUnknownIndex (0); | ||
|
||
// Array reset - certain operations on array are not tracked fully (or impossible due to unknown inputs) | ||
|
@@ -47,6 +50,8 @@ public static void Main () | |
|
||
WriteCapturedArrayElement.Test (); | ||
|
||
WriteElementOfCapturedArray.Test (); | ||
|
||
ConstantFieldValuesAsIndex.Test (); | ||
|
||
HoistedArrayMutation.Test (); | ||
|
@@ -205,6 +210,23 @@ static void TestGetElementAtUnknownIndex (int i = 0) | |
arr[i].RequiresPublicFields (); | ||
} | ||
|
||
// https://github.com/dotnet/runtime/issues/93416 tracks the discrepancy between | ||
// the analyzer and ILLink/ILCompiler. | ||
[ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), | ||
ProducedBy = Tool.Trimmer | Tool.NativeAot)] | ||
[ExpectedWarning ("IL2072", nameof (GetMethods), nameof (DataFlowTypeExtensions.RequiresAll), | ||
ProducedBy = Tool.Analyzer)] | ||
[ExpectedWarning ("IL2072", nameof (GetFields), nameof (DataFlowTypeExtensions.RequiresAll), | ||
ProducedBy = Tool.Analyzer)] | ||
static void TestGetMergedArrayElement (bool b = true) | ||
{ | ||
Type[] arr = new Type[] { GetMethods () }; | ||
Type[] arr2 = new Type[] { GetFields () }; | ||
if (b) | ||
arr = arr2; | ||
arr[0].RequiresAll (); | ||
} | ||
|
||
// Trimmer code doesnt handle locals from different branches separetely, therefore merges incorrectly GetMethods with Unknown producing both warnings | ||
[ExpectedWarning ("IL2072", nameof (ArrayDataFlow.GetMethods), ProducedBy = Tool.Trimmer | Tool.NativeAot)] | ||
[ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll))] | ||
|
@@ -614,6 +636,102 @@ public static void Test () | |
} | ||
} | ||
|
||
class WriteElementOfCapturedArray | ||
{ | ||
[Kept] | ||
[ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (DataFlowTypeExtensions.RequiresAll))] | ||
[ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), nameof (DataFlowTypeExtensions.RequiresAll))] | ||
// Analysis hole: https://github.com/dotnet/runtime/issues/90335 | ||
// The array element assignment assigns to a temp array created as a copy of | ||
// arr1 or arr2, and writes to it aren't reflected back in arr1/arr2. | ||
static void TestArrayElementAssignment (bool b = true) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Test moved from ByRefDataflow. Note this introduces a behavior change: analyzer no longer produces warnings for the |
||
{ | ||
var arr1 = new Type[] { GetUnknownType () }; | ||
var arr2 = new Type[] { GetTypeWithPublicConstructors () }; | ||
(b ? arr1 : arr2)[0] = GetWithPublicMethods (); | ||
arr1[0].RequiresAll (); | ||
arr2[0].RequiresAll (); | ||
} | ||
|
||
[Kept] | ||
[KeptAttributeAttribute (typeof (InlineArrayAttribute))] | ||
[InlineArray (8)] | ||
public struct InlineTypeArray | ||
{ | ||
[Kept] | ||
public Type t; | ||
} | ||
|
||
[Kept] | ||
[ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll))] | ||
[ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll))] | ||
static void TestInlineArrayElementReferenceAssignment (bool b = true) | ||
{ | ||
var arr1 = new InlineTypeArray (); | ||
arr1[0] = GetUnknownType (); | ||
var arr2 = new InlineTypeArray (); | ||
arr2[0] = GetTypeWithPublicConstructors (); | ||
(b ? ref arr1[0] : ref arr2[0]) = GetTypeWithPublicConstructors (); | ||
arr1[0].RequiresAll (); | ||
arr2[0].RequiresAll (); | ||
} | ||
|
||
// Inline array references are not allowed in conditionals, unlike array references. | ||
// static void TestInlineArrayElementAssignment (bool b = true) | ||
// { | ||
// var arr1 = new InlineTypeArray (); | ||
// arr1[0] = GetUnknownType (); | ||
// var arr2 = new InlineTypeArray (); | ||
// arr2[0] = GetTypeWithPublicConstructors (); | ||
// (b ? arr1 : arr2)[0] = GetWithPublicMethods (); | ||
// arr1[0].RequiresAll (); | ||
// arr2[0].RequiresAll (); | ||
// } | ||
|
||
[ExpectedWarning ("IL2087", nameof (T), nameof (DataFlowTypeExtensions.RequiresAll))] | ||
[ExpectedWarning ("IL2087", nameof (U), nameof (DataFlowTypeExtensions.RequiresPublicFields))] | ||
// Missing warnings for 'V' possibly assigned to arr or arr2 because write to temp | ||
// array isn't reflected back in the local variables. https://github.com/dotnet/linker/issues/2158 | ||
static void TestNullCoalesce<T, U, V> (bool b = false) | ||
{ | ||
Type[]? arr = new Type[1] { typeof (T) }; | ||
Type[] arr2 = new Type[1] { typeof (U) }; | ||
|
||
(arr ?? arr2)[0] = typeof (V); | ||
arr[0].RequiresAll (); | ||
arr2[0].RequiresPublicFields (); | ||
} | ||
|
||
[ExpectedWarning ("IL2087", nameof (T), nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Analyzer)] | ||
[ExpectedWarning ("IL2087", nameof (U), nameof (DataFlowTypeExtensions.RequiresPublicFields))] | ||
// Missing warnings for 'V' possibly assigned to arr or arr2 because write to temp | ||
// array isn't reflected back in the local variables. https://github.com/dotnet/linker/issues/2158 | ||
// This also causes an extra analyzer warning for 'U' in 'arr', because the analyzer models the | ||
// possible assignment of arr2 to arr, without overwriting index '0'. And it produces a warning | ||
// for each possible value, unlike ILLink/ILCompiler, which produce an unknown value for a merged | ||
// array value: https://github.com/dotnet/runtime/issues/93416 | ||
[ExpectedWarning ("IL2087", nameof (U), nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Analyzer)] | ||
[ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] | ||
static void TestNullCoalescingAssignment<T, U, V> (bool b = true) | ||
{ | ||
Type[]? arr = new Type[1] { typeof (T) }; | ||
Type[] arr2 = new Type[1] { typeof (U) }; | ||
|
||
(arr ??= arr2)[0] = typeof (V); | ||
arr[0].RequiresAll (); | ||
arr2[0].RequiresPublicFields (); | ||
} | ||
|
||
public static void Test () | ||
{ | ||
TestArrayElementAssignment (); | ||
TestInlineArrayElementReferenceAssignment (); | ||
// TestInlineArrayElementAssignment (); | ||
TestNullCoalesce<int, int, int> (); | ||
TestNullCoalescingAssignment<int, int, int> (); | ||
} | ||
} | ||
|
||
class ConstantFieldValuesAsIndex | ||
{ | ||
private const sbyte ConstSByte = 1; | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 logic is no longer needed now that the array reference should never be an l-value capture. If the array reference is a flow capture, it should be an r-value capture, handled in the normal visitor logic.
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.
By this you mean, that the array (LHS) part of the ArrayReference should be an rvalue, right? Not the thing as a whole?
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.
Exactly - the
(arr ?? arr2)
temp should be an r-value, while(arr ?? arr2)[0]
should be an l-value. At least that's how I think it should work after pondering this for a while, and is the behavior in the PR. ;)