S2095: Exception thrown between open and close, the resource is not closed

Make sure to read this post before raising a thread here:

Then tell us:

  • What language is this for?
    java: sonar-java-plugin-7.31.0.34839.jar

  • Which rule?
    java:S2095: Resources should be closed
    java:S3546: Custom resources should be closed

  • Why do you believe it’s a false-positive/false-negative?
    false-negative
    When an exception is thrown between opening and closing the stream in the try block, it is not checked that the stream is not closed.

  • Are you using

    • SonarQube - which version?
      SonarQube Community Edition Version 9.9.4 (build 87374)
  • How can we reproduce the problem? Give us a self-contained snippet of code (formatted text, no screenshots)
    In the following code, the close function in the wrong function never runs, and there is no check

import java.io.FileOutputStream;
import java.io.OutputStream;

public class Rule {

    public void correct() {
        OutputStream stream = null;
        try {
            stream = new FileOutputStream("myfile.txt");
            stream.close();
        } catch (Exception e) {
            // ...
        } finally {
            // ...
        }
    }

    public void wrong() {
        OutputStream stream = null;
        try {
            stream = new FileOutputStream("myfile.txt");
            int i = 1 / 0; // throw
            stream.close();
        } catch (Exception e) {
            // ...
        } finally {
            // ...
        }
    }

}

Hi @644262163 ,

Thanks for the report.

You have found a particular edge-case here. The division-by-zero check (S3518) actually uses the same symbolic execution engine as S2095. When the engine finds a division by zero, it stops evaluating the remaining branches, as it is effectively dead code. This leads to S2095 not triggering anymore, as we have aborted the execution before.

In this particular example, you are right, it would still be nice to have S2095 report. However, it is a very specific example and in many more complex cases, the engine will behave differently. It is very rare (I hope!) to see a division by zero that is literally / 0, most real-world examples will have more branches that will often lead to S2095 triggering, where appropriate.

We have to make compromises in terms of detection (low number of false negatives) and accuracy (low number of false positives) and we try as much as possible to reduce the noise, i.e. avoid FPs. Sometimes, this can lead to a few FNs here and there. We believe it is ultimately more valuable, as it makes the issues that are raised more meaningful.

All that being said, we started work a little while ago on a better data-flow analysis for detecting bugs. I cannot give you an ETA, but the new engine may well be better at accurately reporting on edge-cases like this.