checker-framework icon indicating copy to clipboard operation
checker-framework copied to clipboard

RLC inference with a private finalizer method

Open iamsanjaymalakar opened this issue 10 months ago • 1 comments

When using Resource Leak Checker (RLC) inference, private finalizer methods that are invoked internally can lead to incorrect or incomplete inference results. Specifically, the inference mechanism does not annotate the enclosing class with @InheritableMustCall because the finalizer method is private, causing CF RLC to emit warnings like:

The enclosing element _ has an empty @MustCall annotation.

Consider this minimal example:

class Foo implements Runnable {

    @Owning
    private final FileWriter fileWriter;

    public Foo(File file) throws IOException {
        this.fileWriter = new FileWriter(file);
    }

    @EnsuresCalledMethods(value = { "this.fileWriter" }, methods = { "close" })
    private void close() {
        try {
            fileWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void run() {
        close();
    }
}

Here, the inference algorithm correctly identifies the finalizer method (close) as releasing fileWriter. But it does not infer an @InheritableMustCall annotation on Foo due to the close method's visibility (private). This results in the mentioned warning, and a missing resource-management specification.

To handle this case the possible correct behaviors I can think of:

  1. Inferring the necessary @EnsuresCalledMethods annotation on the caller method (run() in this example). But as the close method does take an @Owning paramter as an input, this is not happenning currently.
@EnsuresCalledMethods(value = { "this.fileWriter" }, methods = { "close" })
public void run() {
    close();
}
  1. Not inferring ownership annotations (@EnsuresCalledMethods) on private finalizer methods without parameters that are not exposed externally.

iamsanjaymalakar avatar Mar 13 '25 02:03 iamsanjaymalakar

I think the best way to address this would be to somehow enhance inference to infer the @EnsuresCalledMethods annotation on run() and then make run the must-call method for Foo. I don't think there is anything wrong with the annotations inference is adding right now; it's just incomplete.

msridhar avatar Mar 13 '25 16:03 msridhar