Skip to content

Commit d361ff8

Browse files
authored
Add -AresourceLeakIgnoredExceptions option (#6242)
1 parent d282234 commit d361ff8

File tree

11 files changed

+488
-84
lines changed

11 files changed

+488
-84
lines changed

checker/src/main/java/org/checkerframework/checker/calledmethods/CalledMethodsAnalysis.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
import com.google.common.collect.ImmutableSet;
44
import com.sun.tools.javac.code.Type;
5-
import java.util.HashSet;
65
import java.util.Set;
76
import javax.lang.model.type.TypeMirror;
7+
import org.checkerframework.checker.signature.qual.CanonicalName;
88
import org.checkerframework.common.accumulation.AccumulationAnalysis;
99
import org.checkerframework.common.basetype.BaseTypeChecker;
1010

@@ -18,17 +18,16 @@ public class CalledMethodsAnalysis extends AccumulationAnalysis {
1818
* The fully-qualified names of the exception types that are ignored by this checker when
1919
* computing dataflow stores.
2020
*/
21-
protected static final Set<String> ignoredExceptionTypes =
22-
new HashSet<>(
23-
ImmutableSet.of(
24-
// Use the Nullness Checker instead.
25-
NullPointerException.class.getCanonicalName(),
26-
// Ignore run-time errors, which cannot be predicted statically. Doing
27-
// so is unsound in the sense that they could still occur - e.g., the
28-
// program could run out of memory - but if they did, the checker's
29-
// results would be useless anyway.
30-
Error.class.getCanonicalName(),
31-
RuntimeException.class.getCanonicalName()));
21+
protected static final Set<@CanonicalName String> ignoredExceptionTypes =
22+
ImmutableSet.of(
23+
// Use the Nullness Checker instead.
24+
NullPointerException.class.getCanonicalName(),
25+
// Ignore run-time errors, which cannot be predicted statically. Doing
26+
// so is unsound in the sense that they could still occur - e.g., the
27+
// program could run out of memory - but if they did, the checker's
28+
// results would be useless anyway.
29+
Error.class.getCanonicalName(),
30+
RuntimeException.class.getCanonicalName());
3231

3332
/**
3433
* Creates a new {@code CalledMethodsAnalysis}.

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

Lines changed: 5 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
import com.sun.source.tree.Tree;
1111
import com.sun.source.tree.VariableTree;
1212
import com.sun.source.util.TreePath;
13-
import com.sun.tools.javac.code.Type;
14-
import java.io.UnsupportedEncodingException;
1513
import java.util.ArrayDeque;
1614
import java.util.ArrayList;
1715
import java.util.Collection;
@@ -34,7 +32,6 @@
3432
import javax.lang.model.element.Element;
3533
import javax.lang.model.element.ElementKind;
3634
import javax.lang.model.element.ExecutableElement;
37-
import javax.lang.model.element.Name;
3835
import javax.lang.model.element.TypeElement;
3936
import javax.lang.model.element.VariableElement;
4037
import javax.lang.model.type.TypeKind;
@@ -48,8 +45,6 @@
4845
import org.checkerframework.checker.mustcall.qual.NotOwning;
4946
import org.checkerframework.checker.mustcall.qual.Owning;
5047
import org.checkerframework.checker.nullness.qual.Nullable;
51-
import org.checkerframework.checker.signature.qual.FullyQualifiedName;
52-
import org.checkerframework.common.accumulation.AccumulationAnalysis;
5348
import org.checkerframework.common.accumulation.AccumulationStore;
5449
import org.checkerframework.common.accumulation.AccumulationValue;
5550
import org.checkerframework.dataflow.cfg.ControlFlowGraph;
@@ -182,7 +177,7 @@ class MustCallConsistencyAnalyzer {
182177
private final ResourceLeakChecker checker;
183178

184179
/** The analysis from the Resource Leak Checker, used to get input stores based on CFG blocks. */
185-
private final AccumulationAnalysis analysis;
180+
private final ResourceLeakAnalysis analysis;
186181

187182
/** True if -AnoLightweightOwnership was passed on the command line. */
188183
private final boolean noLightweightOwnership;
@@ -561,7 +556,7 @@ public String stringForErrorMessage() {
561556
* so this constructor cannot get it directly.
562557
*/
563558
/*package-private*/ MustCallConsistencyAnalyzer(
564-
ResourceLeakAnnotatedTypeFactory typeFactory, AccumulationAnalysis analysis) {
559+
ResourceLeakAnnotatedTypeFactory typeFactory, ResourceLeakAnalysis analysis) {
565560
this.typeFactory = typeFactory;
566561
this.checker = (ResourceLeakChecker) typeFactory.getChecker();
567562
this.analysis = analysis;
@@ -1906,8 +1901,8 @@ private boolean shouldTrackReturnType(MethodInvocationNode node) {
19061901

19071902
/**
19081903
* Get all successor blocks for some block, except for those corresponding to ignored exception
1909-
* types. See {@link #ignoredExceptionTypes}. Each exceptional successor is paired with the type
1910-
* of exception that leads to it, for use in error messages.
1904+
* types. See {@link ResourceLeakAnalysis#isIgnoredExceptionType(TypeMirror)}. Each exceptional
1905+
* successor is paired with the type of exception that leads to it, for use in error messages.
19111906
*
19121907
* @param block input block
19131908
* @return set of pairs (b, t), where b is a successor block, and t is the type of exception for
@@ -1927,7 +1922,7 @@ private boolean shouldTrackReturnType(MethodInvocationNode node) {
19271922
Map<TypeMirror, Set<Block>> exceptionalSuccessors = excBlock.getExceptionalSuccessors();
19281923
for (Map.Entry<TypeMirror, Set<Block>> entry : exceptionalSuccessors.entrySet()) {
19291924
TypeMirror exceptionType = entry.getKey();
1930-
if (!isIgnoredExceptionType(((Type) exceptionType).tsym.getQualifiedName())) {
1925+
if (!analysis.isIgnoredExceptionType(exceptionType)) {
19311926
for (Block exSucc : entry.getValue()) {
19321927
result.add(IPair.of(exSucc, exceptionType));
19331928
}
@@ -2477,58 +2472,6 @@ private void incrementMustCallImpl(TypeMirror type) {
24772472
.isSubtypeQualifiersOnly(cmAnno, cmAnnoForMustCallMethods);
24782473
}
24792474

2480-
/**
2481-
* The exception types in this set are ignored in the CFG when determining if a resource leaks
2482-
* along an exceptional path. These kinds of errors fall into a few categories: runtime errors,
2483-
* errors that the JVM can issue on any statement, and errors that can be prevented by running
2484-
* some other CF checker.
2485-
*
2486-
* <p>Package-private to permit access from {@link ResourceLeakAnalysis}.
2487-
*/
2488-
/*package-private*/ static final Set<String> ignoredExceptionTypes =
2489-
new HashSet<>(
2490-
ImmutableSet.of(
2491-
// Any method call has a CFG edge for Throwable/RuntimeException/Error
2492-
// to represent run-time misbehavior. Ignore it.
2493-
Throwable.class.getCanonicalName(),
2494-
Error.class.getCanonicalName(),
2495-
RuntimeException.class.getCanonicalName(),
2496-
// Use the Nullness Checker to prove this won't happen.
2497-
NullPointerException.class.getCanonicalName(),
2498-
// These errors can't be predicted statically, so ignore them and assume
2499-
// they won't happen.
2500-
ClassCircularityError.class.getCanonicalName(),
2501-
ClassFormatError.class.getCanonicalName(),
2502-
NoClassDefFoundError.class.getCanonicalName(),
2503-
OutOfMemoryError.class.getCanonicalName(),
2504-
// It's not our problem if the Java type system is wrong.
2505-
ClassCastException.class.getCanonicalName(),
2506-
// It's not our problem if the code is going to divide by zero.
2507-
ArithmeticException.class.getCanonicalName(),
2508-
// Use the Index Checker to prevent these errors.
2509-
ArrayIndexOutOfBoundsException.class.getCanonicalName(),
2510-
NegativeArraySizeException.class.getCanonicalName(),
2511-
// Most of the time, this exception is infeasible, as the charset used
2512-
// is guaranteed to be present by the Java spec (e.g., "UTF-8").
2513-
// Eventually, this exclusion could be refined by looking at the charset
2514-
// being requested.
2515-
UnsupportedEncodingException.class.getCanonicalName()));
2516-
2517-
/**
2518-
* Is {@code exceptionClassName} an exception type the checker ignores, to avoid excessive false
2519-
* positives? For now the checker ignores most runtime exceptions (especially the runtime
2520-
* exceptions that can occur at any point during the program due to something going wrong in the
2521-
* JVM, like OutOfMemoryError and ClassCircularityError) and exceptions that can be proved to
2522-
* never occur by another Checker Framework built-in checker, such as null-pointer dereferences
2523-
* (the Nullness Checker) and out-of-bounds array indexing (the Index Checker).
2524-
*
2525-
* @param exceptionClassName the fully-qualified name of the exception
2526-
* @return true if the given exception class should be ignored
2527-
*/
2528-
private static boolean isIgnoredExceptionType(@FullyQualifiedName Name exceptionClassName) {
2529-
return ignoredExceptionTypes.contains(exceptionClassName.toString());
2530-
}
2531-
25322475
/**
25332476
* If the input {@code state} has not been visited yet, add it to {@code visited} and {@code
25342477
* worklist}.
Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,36 @@
11
package org.checkerframework.checker.resourceleak;
22

3+
import javax.lang.model.type.TypeMirror;
34
import org.checkerframework.checker.calledmethods.CalledMethodsAnalysis;
45
import org.checkerframework.checker.calledmethods.CalledMethodsAnnotatedTypeFactory;
5-
import org.checkerframework.common.basetype.BaseTypeChecker;
66

77
/**
8-
* This variant of CFAnalysis extends the set of ignored exception types to include all those
9-
* ignored by the {@link MustCallConsistencyAnalyzer}. See {@link
10-
* MustCallConsistencyAnalyzer#ignoredExceptionTypes}.
8+
* This variant of CFAnalysis extends the set of ignored exception types.
9+
*
10+
* @see ResourceLeakChecker#getIgnoredExceptions()
1111
*/
1212
public class ResourceLeakAnalysis extends CalledMethodsAnalysis {
13+
14+
/**
15+
* The set of exceptions to ignore, cached from {@link
16+
* ResourceLeakChecker#getIgnoredExceptions()}.
17+
*/
18+
private final SetOfTypes ignoredExceptions;
19+
1320
/**
1421
* Creates a new {@code CalledMethodsAnalysis}.
1522
*
1623
* @param checker the checker
1724
* @param factory the factory
1825
*/
1926
protected ResourceLeakAnalysis(
20-
BaseTypeChecker checker, CalledMethodsAnnotatedTypeFactory factory) {
27+
ResourceLeakChecker checker, CalledMethodsAnnotatedTypeFactory factory) {
2128
super(checker, factory);
22-
ignoredExceptionTypes.addAll(MustCallConsistencyAnalyzer.ignoredExceptionTypes);
29+
this.ignoredExceptions = checker.getIgnoredExceptions();
30+
}
31+
32+
@Override
33+
public boolean isIgnoredExceptionType(TypeMirror exceptionType) {
34+
return ignoredExceptions.contains(getTypes(), exceptionType);
2335
}
2436
}

checker/src/main/java/org/checkerframework/checker/resourceleak/ResourceLeakAnnotatedTypeFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ public AnnotationMirror createCalledMethods(String... val) {
131131
@Override
132132
public void postAnalyze(ControlFlowGraph cfg) {
133133
MustCallConsistencyAnalyzer mustCallConsistencyAnalyzer =
134-
new MustCallConsistencyAnalyzer(this, this.analysis);
134+
new MustCallConsistencyAnalyzer(this, (ResourceLeakAnalysis) this.analysis);
135135
mustCallConsistencyAnalyzer.analyze(cfg);
136136

137137
// Inferring owning annotations for @Owning fields/parameters, @EnsuresCalledMethods for
@@ -148,7 +148,7 @@ public void postAnalyze(ControlFlowGraph cfg) {
148148

149149
@Override
150150
protected ResourceLeakAnalysis createFlowAnalysis() {
151-
return new ResourceLeakAnalysis(checker, this);
151+
return new ResourceLeakAnalysis((ResourceLeakChecker) checker, this);
152152
}
153153

154154
/**

0 commit comments

Comments
 (0)