Skip to content

Suppresses RLC non-final field overwrite warning for safe constructor field initialization #7050

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

Open
wants to merge 18 commits into
base: master
Choose a base branch
from

Conversation

iamsanjaymalakar
Copy link
Member

@iamsanjaymalakar iamsanjaymalakar commented Apr 18, 2025

No description provided.

@iamsanjaymalakar iamsanjaymalakar self-assigned this Apr 18, 2025
Copy link
Contributor

@kelloggm kelloggm left a comment

Choose a reason for hiding this comment

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

Overall looks good, just a few minor comments. I'd like to take one more look before we merge, though.

private @Owning FileInputStream s;

public ConstructorChainingLeak() throws Exception {
this(42);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a test like this one but where the this(42) call is replaced by a call to a super constructor? I'd like to at least codify the behavior in that scenario (I think it would be safe not to warn in that constructor, but it's okay if there's an FP now).

Copy link
Member Author

Choose a reason for hiding this comment

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

Added a test case for a constructor that calls super().
The suppression logic already handles super constructor calls correctly, so no false positive is reported solely due to the super() call.

* Determines whether the given assignment is the first write to a private field during a
* potential non-final owning field overwrite. This is used to suppress false positive resource
* leak warnings when it is safe to assume that a constructor initializes the field for the first
* time. This method returns {@code true} if: - the field is private, - it has no non-null inline
Copy link
Contributor

Choose a reason for hiding this comment

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

This Javadoc should be more clear that this method conservatively returns false unless it can prove that this is the first reassignment to a field.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've updated the Javadoc.

if (member instanceof BlockTree) {
BlockTree block = (BlockTree) member;
if (block.isStatic()) continue;
boolean[] found = {false};
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is found an array? Why not just a boolean?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch — I used the array to work around Java's requirement that variables accessed from within inner classes be effectively final. I've updated the code to use AtomicBoolean instead, which takes care of the issue. Thanks!

@mernst mernst changed the title Suppresses RLC non-final field overwrite warning for safe constructor… #7049 Suppresses RLC non-final field overwrite warning for safe constructor field initialization Apr 18, 2025
@mernst
Copy link
Member

mernst commented Apr 18, 2025

@iamsanjaymalakar The typecheck job is not passing.

kelloggm
kelloggm previously approved these changes Jun 6, 2025
Copy link
Contributor

@kelloggm kelloggm 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 don't need to review again. Please address these comments and then request a review from Mike.

@mernst
Copy link
Member

mernst commented Jul 10, 2025

@iamsanjaymalakar Martin asked you to assign me when you had addressed his comments. Have you addressed them?

@iamsanjaymalakar iamsanjaymalakar assigned mernst and unassigned kelloggm Jul 14, 2025
@iamsanjaymalakar
Copy link
Member Author

@iamsanjaymalakar Martin asked you to assign me when you had addressed his comments. Have you addressed them?

Yes, I have. You can take a look.

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.

Please clarify some documentation, and update the code if necessary. (I didn't read the code because there is no point in doing so until the documentation is clear.)

@mernst mernst assigned iamsanjaymalakar and unassigned mernst Jul 14, 2025
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

The PR introduces a targeted suppression of RLC (Resource Leak Checker) warnings for safe first-time field initializations within constructors. The main purpose is to prevent false positive warnings when a private field is being initialized for the first time in a constructor, while still catching actual resource leaks in other scenarios.

  • Adds logic to detect and suppress warnings for first-time private field assignments in constructors
  • Implements comprehensive validation checks including constructor chaining, initializer blocks, and method calls
  • Includes extensive test coverage for various initialization patterns and edge cases

Reviewed Changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
MustCallConsistencyAnalyzer.java Implements the core suppression logic with field analysis and validation methods
ResourceLeakFirstInitConstructorTest.java Adds JUnit test class for the new functionality
FirstAssignmentInConstructor.java Test case for basic safe first assignment scenario
ExplicitNullInitializer.java Test case for fields explicitly initialized to null
SuperCallFromConstructor.java Test case for constructors that call super()
ConstructorChainingLeak.java Test case for constructor chaining with this() calls
MethodCallBeforeAssignment.java Test case for method calls before field assignment
PrivateMethodAssignmentLeak.java Test case for field assignment within private methods
InstanceInitializerBlockLeak.java Test case for instance initializer block assignments
InlineInitializerLeak.java Test case for inline field initializers
PublicFieldLeak.java Test case for public field assignments
ProtectedFieldLeak.java Test case for protected field assignments
PackagePrivateFieldLeak.java Test case for package-private field assignments
Comments suppressed due to low confidence (2)

checker/src/main/java/org/checkerframework/checker/resourceleak/MustCallConsistencyAnalyzer.java:1683

  • [nitpick] The parameter name 'currentAssignment' is misleading since it represents the assignment tree being analyzed, not necessarily the current one in a sequence. Consider renaming to 'assignmentTree' or 'targetAssignment' for clarity.
      VariableElement field, MethodTree constructor, @FindDistinct Tree currentAssignment) {

checker/tests/resourceleak-firstinitconstructor/InlineInitializerLeak.java:10

  • This line will throw an IOException that is not handled in the field initializer. This could cause compilation issues or unexpected behavior during testing. Consider wrapping in a try-catch or using a mock/stub.
  private @Owning FileInputStream s = new FileInputStream("test.txt");

if (member instanceof BlockTree) {
BlockTree block = (BlockTree) member;
if (block.isStatic()) continue;
// The variables accessed from within the inner class need to be effectively final, so
Copy link
Preview

Copilot AI Jul 18, 2025

Choose a reason for hiding this comment

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

The comment mentions 'inner class' but the code uses an anonymous class (TreeScanner). Consider updating the comment to be more precise: 'The variables accessed from within the anonymous class need to be effectively final'.

Suggested change
// The variables accessed from within the inner class need to be effectively final, so
// The variables accessed from within the anonymous class need to be effectively final, so

Copilot uses AI. Check for mistakes.

Element receiverElement = TypesUtils.getTypeElement(receiver.getType());
if (Objects.equals(enclosingClassElement, receiverElement)) {
VariableElement lhsElement = lhs.getElement();
if (lhsElement.getModifiers().contains(Modifier.PRIVATE)
Copy link
Member

Choose a reason for hiding this comment

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

Method isFirstAssignmentToField is document to do this test, so move it into the method.

// (later writes/calls are checked at their own CFG points).
Element enclosingClassElement =
TreeUtils.elementFromDeclaration(enclosingMethodTree).getEnclosingElement();
if (ElementUtils.isTypeElement(enclosingClassElement)) {
Copy link
Member

Choose a reason for hiding this comment

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

How can this test fail? If it does, should an exception be thrown?

}

// (3) Disallow assignment in instance initializer blocks
for (Tree member : classTree.getMembers()) {
Copy link
Member

Choose a reason for hiding this comment

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

For efficiency, merge this into the above loop, like (5) and (6) are handled by a single loop.

if (expr == currentAssignment) {
break;
}
// (5) Prior assignment to the same field
Copy link
Member

Choose a reason for hiding this comment

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

I think this (or possibly some other bit of similar code) causes errors to be issued at the wrong location. See added test, which fails.

@mernst mernst removed their assignment Jul 20, 2025
@mernst
Copy link
Member

mernst commented Jul 20, 2025

@iamsanjaymalakar Please take a look at my review comments.

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.

3 participants