Skip to content
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

Avoid assuming containing assembly is from source in DefiniteAssignment #59069

Merged
merged 7 commits into from
Jan 27, 2022

Conversation

cston
Copy link
Member

@cston cston commented Jan 26, 2022

Fixes #57428

@@ -160,7 +156,7 @@ internal partial class DefiniteAssignmentPass : LocalDataFlowPass<
trackUnassignments)
{
this.initiallyAssignedVariables = null;
_sourceAssembly = ((object)member == null) ? null : (SourceAssemblySymbol)member.ContainingAssembly;
_sourceAssembly = member?.ContainingAssembly as SourceAssemblySymbol;
Copy link
Member

@333fred 333fred Jan 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is member in this case? And why is its assembly not from source? #Resolved

Copy link
Member Author

@cston cston Jan 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The failure case is an expression within a lambda used as an attribute argument. The member in that case is the attribute (obtained from SyntaxTreeSemanticModel.GetMemberModel(expression)) where the attribute type is from metadata.

Copy link
Member

@333fred 333fred Jan 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fascinating. Can we add an assert that it's basically either this case, or from source (or the member is null altogether)? It feels like this could potentially hide a bug later on if another case slipped in here.

@@ -160,7 +156,7 @@ internal partial class DefiniteAssignmentPass : LocalDataFlowPass<
trackUnassignments)
{
this.initiallyAssignedVariables = null;
_sourceAssembly = ((object)member == null) ? null : (SourceAssemblySymbol)member.ContainingAssembly;
_sourceAssembly = member?.ContainingAssembly as SourceAssemblySymbol;
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

member?.ContainingAssembly as SourceAssemblySymbol

It feels like we might want to strengthen the logic here to get ContainingAssembly only from a symbol that is actually a member or belongs to a member. Otherwise, we might still get a SourceAssemblySymbol that doesn't match the context and start changing its state based on the analysis that we perform. #Closed

@AlekseyTs
Copy link
Contributor

Done with review pass (commit 1)

(type.IsErrorType() || compilation.IsAttributeType(type)));
return null;
}
Debug.Assert(member.ContainingAssembly is SourceAssemblySymbol);
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug.Assert(member.ContainingAssembly is SourceAssemblySymbol);

Consider if we can make this assert stronger. Something like:

Debug.Assert((object)member.ContainingAssembly == compilation.SourceAssembly); 
``` #Resolved

Copy link
Contributor

@AlekseyTs AlekseyTs Jan 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, if we always have compilation, why not simply always grab its SourceAssembly regardless of the node and member?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverting to use member.ContainingAssembly as SourceAssemblySymbol rather than compilation.SourceAssembly since compilation may be null in the EE. (It doesn't seem like we have any tests that hit this case currently, but it seems safer to allow that.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since compilation may be null in the EE.

This doesn't match the nullable annotations on the parameters. Also, we store compilation in a protected field in the base class and it doesn't look like we protect against null value in it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are cases where AbstractFlowPass<,>.compilation is null - see #59093.

Logged #59111 to ensure callers pass a non-null CSharpCompilation.

Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (commit 4)

AlekseyTs
AlekseyTs previously approved these changes Jan 26, 2022
Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (commit 6)

@AlekseyTs AlekseyTs dismissed their stale review January 26, 2022 22:10

Obsolete

Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (commit 7), assuming that we will open an issue to ensure that flow analysis is never passed a null compilation.

@cston cston merged commit 1037b82 into dotnet:main Jan 27, 2022
@cston cston deleted the 57428 branch January 27, 2022 16:47
@ghost ghost added this to the Next milestone Jan 27, 2022
@RikkiGibson RikkiGibson modified the milestones: Next, 17.2.P1 Feb 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

InvalidCastException from DefiniteAssignmentPass during extract method analysis
4 participants