typetools / typetools/checker-framework

Resource Leak Checker: false positives when a resource is allocated and closed in the same expression

Open
#6,270 7 comments 0 reactions 1 assignee View on GitHub

@kelloggm is already working on this.

Since Dec 14, 2023.

ResourceLeakChecker
Dominant language
Java
Stars
1.1k
Forks
440
Avg merge
1d 12h
Merged PRs (30d)
134

Description

The Resource Leak Checker does not accept this code:

  static void method() {
    // error: [required.method.not.called] @MustCall method close may not have been invoked on new Resource()
    close(new Resource());
  }

  @EnsuresCalledMethods(value = "#1", methods = "close")
  static void close(Resource r) {
    r.close();
  }

this very similar code works:

  static void method() {
    Resource r = new Resource();
    close(r);
  }

However, that refactoring is not possible when

  • method is a constructor
  • close is a call to super(...) or this(...)

For example:

class TestCase {
  @EnsuresCalledMethods(value = "#1", methods = "close")
  TestCase(Resource r) {
    r.close();
  }

  TestCase() {
    // error: [required.method.not.called] @MustCall method close may not have been invoked on new Resource()
    this(new Resource());
  }
}

Below is a more complete set of tests that exercise a few variants of that pattern. The RLC reports false positives for test cases 3-7.

import java.io.*;
import org.checkerframework.checker.calledmethods.qual.*;

class AllocResourceInExpression {

  static void testCase1() {
    new Resource().close();
  }

  static void testCase2() {
    alloc().close();
  }

  static void testCase3() {
    new Resource().free();
  }

  static void testCase4() {
    alloc().free();
  }

  static void testCase5() {
    close(new Resource());
  }

  static void testCase6() {
    close(alloc());
  }

  class TestCase7 {
    @EnsuresCalledMethods(value = "#1", methods = "close")
    TestCase7(Resource r) {
      r.close();
    }

    TestCase7() {
      this(new Resource());
    }
  }

  static class Resource implements Closeable {
    @Override
    public void close() {}

    @EnsuresCalledMethods(value = "this", methods = "close")
    public void free() {
      close();
    }
  }

  static Resource alloc() {
    return new Resource();
  }

  @EnsuresCalledMethods(value = "#1", methods = "close")
  static void close(Resource r) {
    r.close();
  }

}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.