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

Model try-with-resources semantics during CFG construction #6273

Merged
merged 65 commits into from
Nov 29, 2023

Conversation

msridhar
Copy link
Contributor

@msridhar msridhar commented Oct 29, 2023

Fixes #6037

We modify CFG construction to inject calls to close() at the appropriate place for all resource variables declared or used in a try-with-resources tree. Our modeling is based on the desugaring given in JLS 14.20.3.1:

https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.20.3.1

Essentially, the closing of each resource is modeled using a nested try-finally block, where the finally block includes the close() call. We currently elide the null checks and tracking of the primary exception from the JLS desugaring.

This explicit modeling in the CFG enables deletion of a good amount of custom code related to resource variables in the Must Call Checker and the Resource Leak Checker, while also enabling those checkers to handle more cases.

@msridhar
Copy link
Contributor Author

@mernst I didn't request a review on this one since I wasn't sure whether you or @smillst would be best to review the dataflow changes

@mernst
Copy link
Member

mernst commented Oct 29, 2023

@msridhar Ordinarily me, but I am overwhelmed at the moment, so I will ask Suzanne to take a look.

Copy link
Member

@smillst smillst left a comment

Choose a reason for hiding this comment

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

I just had a few minor comments.


/**
* This represents a resource declaration in a try-with-resources tree. A resource declaration can
* be either a variable declaration or just a final (or effectively final) local variable.
Copy link
Member

Choose a reason for hiding this comment

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

I would change just a to a use of a.


@Override
public Collection<Node> getOperands() {
// TODO what is the right answer here?
Copy link
Member

Choose a reason for hiding this comment

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

This should return a singleton of assignOrLocalVarNode.

@@ -1241,6 +1242,28 @@ private void updateObligationsForAssignment(
}
}

/**
* Updates a set of obligations to account for a resource declaration in a try-with-resources
* tree. If the resource is a local variable (<em>not</em> a variable declaration), remove all
Copy link
Member

Choose a reason for hiding this comment

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

I would change the resource is a local variable (<em>not</em> a variable declaration) to the resource is a use of a local variable.

* @param p the argument for the operation implemented by this visitor
* @return the return value of the operation implemented by this visitor
*/
R visitResource(ResourceNode n, P p);
Copy link
Member

@smillst smillst Oct 30, 2023

Choose a reason for hiding this comment

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

Please add a change log entry for the new node subclass.

@smillst smillst assigned msridhar and unassigned smillst Oct 30, 2023
@msridhar
Copy link
Contributor Author

I realized that in Java 9 and after try-with-resources can also be used to close a final field. Will need to rework this PR a bit to handle that. Will address comments also and then re-request a review.

@msridhar msridhar marked this pull request as draft October 30, 2023 16:38
@msridhar
Copy link
Contributor Author

msridhar commented Nov 3, 2023

@smillst @kelloggm @mernst I'm thinking about re-working the approach here and would like your feedback. Right now, this PR adds ResourceNodes (modeling the declaration of a resource in a try-with-resources) at the same point in the CFG where the resource is declared. The problem is that this is not the program point where the resource is actually closed. So, in the presence of @CreatesMustCallFor, we can get false positives, e.g., here. (That false positive is reset.not.owning but I think we'd also get a false positive that the resource is not closed.)

Here is my alternative proposal. Instead of putting the ResourceNodes where resources are declared, we would place them in all copies of the finally block if it exists, and just after the doneLabel for the try if there is no finally block. Then, a ResourceNode would represent the logic to close a reference to a resource if it is not null, catching any relevant exceptions from the close() call, etc. With this representation, we could simply model a ResourceNode as a call to close() in CalledMethodsTransfer (or ResourceLeakTransfer if we don't want this for the Called Methods Checker). I think that would be all we need to model try-with-resources semantics for the RLC, so we could get rid of some code we have now in MustCallConsistencyAnalyzer and elsewhere that special-cases resource variables.

Let me know your thoughts on the above; thanks!

@kelloggm
Copy link
Contributor

kelloggm commented Nov 6, 2023

Here is my alternative proposal

I think this alternative proposal is sensible. I would consider changing the name from ResourceNode to something that specifically calls out the fact that the node represents the close logic, though, if we do this--for example, ResourceCloseNode or something like that---because I suspect that otherwise the presence of "ResourceNode"s near the end of try-with-resources (rather than the beginning) will be unintuitive.

@smillst
Copy link
Member

smillst commented Nov 6, 2023

This sounds good to me. I also agree with Martin's naming suggestion, too.

mernst
mernst previously approved these changes Nov 27, 2023
Copy link
Member

@mernst mernst left a comment

Choose a reason for hiding this comment

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

Thanks for all these improvements. I have a few questions/comments.

@msridhar msridhar assigned mernst and unassigned msridhar Nov 28, 2023
@msridhar msridhar requested a review from mernst November 28, 2023 04:55
mernst
mernst previously approved these changes Nov 28, 2023
@mernst mernst assigned smillst and unassigned mernst Nov 28, 2023
Copy link
Member

@smillst smillst left a comment

Choose a reason for hiding this comment

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

LGTM. I didn't merge because I'm not sure if I'm the last to review it.

@smillst smillst assigned msridhar and unassigned smillst Nov 29, 2023
@mernst
Copy link
Member

mernst commented Nov 29, 2023

@msridhar I think this can be merged. Thank you!

@msridhar msridhar merged commit c54834b into typetools:master Nov 29, 2023
29 checks passed
@msridhar msridhar deleted the resource-node branch November 29, 2023 16:50
wmdietl pushed a commit to eisop/checker-framework that referenced this pull request Dec 5, 2023
…#6273)

Co-authored-by: Michael Ernst <mernst@cs.washington.edu>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Resource leak checker does not seem to honor try-with-resources in some cases
4 participants