Summary: Copying Java biabduction tests into pulse tests folder. The goal is to check how well Pulse will perform on Java. Reviewed By: jvillard Differential Revision: D25901299 fbshipit-source-id: a117b44f5master
parent
eeb34231fa
commit
9362b22317
@ -0,0 +1,270 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
public class AnalysisStops {
|
||||||
|
|
||||||
|
private native Object externalFunc();
|
||||||
|
|
||||||
|
public void skipPointerDerefMayCauseLocalFalseNegativeBad() {
|
||||||
|
Object ret = externalFunc();
|
||||||
|
ret.toString();
|
||||||
|
int i = 1 / 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object skipPointerDerefPreventsSpecInferenceRetObj() {
|
||||||
|
Object ret = externalFunc();
|
||||||
|
ret.toString();
|
||||||
|
return new Object();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void skipPointerDerefMayCauseCalleeFalsePositiveOk() {
|
||||||
|
Object o = skipPointerDerefPreventsSpecInferenceRetObj();
|
||||||
|
o.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int skipPointerDerefPreventsSpecInferenceRetZero() {
|
||||||
|
Object ret = externalFunc();
|
||||||
|
ret.toString();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void skipPointerDerefMayCauseCalleeFalseNegativeBad() {
|
||||||
|
int ret = skipPointerDerefPreventsSpecInferenceRetZero();
|
||||||
|
int i = 1 / ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void divideByParam(int i) {
|
||||||
|
int j = 1 / i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void skipPointerDerefMayCauseInterprocFalseNegativeBad() {
|
||||||
|
int i = skipPointerDerefPreventsSpecInferenceRetZero();
|
||||||
|
divideByParam(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String castExternalPreventsSpecInference() {
|
||||||
|
return (String) externalFunc();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void castFailureOnUndefinedObjMayCauseFalseNegativeBad() {
|
||||||
|
castExternalPreventsSpecInference();
|
||||||
|
int i = 1 / 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callOnCastUndefinedObjMayCauseFalseNegativeBad() {
|
||||||
|
String s = castExternalPreventsSpecInference();
|
||||||
|
s.toString();
|
||||||
|
int i = 1 / 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MyObj {
|
||||||
|
Object f;
|
||||||
|
MyObj rec;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
public int retOne() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int retZero() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private native MyObj externalFunc2();
|
||||||
|
|
||||||
|
public void callOnUndefinedObjMayCauseFalseNegativeBad() {
|
||||||
|
MyObj ret = externalFunc2();
|
||||||
|
int i = 1 / ret.retZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callOnUndefinedObjMayCauseFalsePositiveOk() {
|
||||||
|
MyObj ret = externalFunc2();
|
||||||
|
int i = 1 / ret.retOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fieldWriteOnUndefinedObjMayCauseFalseNegativeBad() {
|
||||||
|
MyObj ret = externalFunc2();
|
||||||
|
ret.f = new Object();
|
||||||
|
int i = 1 / 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fieldWriteOnUndefinedObjMayCauseFalsePositiveOk() {
|
||||||
|
MyObj ret = externalFunc2();
|
||||||
|
ret.f = new Object();
|
||||||
|
ret.f.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fieldReadOnUndefinedObjMayCauseFalseNegativeBad() {
|
||||||
|
MyObj ret = externalFunc2();
|
||||||
|
Object o = ret.f;
|
||||||
|
int i = 1 / 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fieldReadOnUndefinedObjMayCauseFalsePositiveOk() {
|
||||||
|
MyObj ret = externalFunc2();
|
||||||
|
Object o = ret.f;
|
||||||
|
o.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recursiveAngelicTypesMayCauseFalseNegativeBad() {
|
||||||
|
MyObj ret = externalFunc2();
|
||||||
|
MyObj rec1 = ret.rec;
|
||||||
|
MyObj rec2 = rec1.rec;
|
||||||
|
int i = 1 / 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recursiveAngelicTypesMayCauseFalsePositiveOk() {
|
||||||
|
MyObj ret = externalFunc2();
|
||||||
|
MyObj rec1 = ret.rec;
|
||||||
|
rec1.rec.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void infiniteMaterializationMayCauseFalseNegativeBad(boolean b) {
|
||||||
|
MyObj rec = externalFunc2();
|
||||||
|
while (b) {
|
||||||
|
rec = rec.rec;
|
||||||
|
}
|
||||||
|
int i = 1 / 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void infiniteMaterializationMayCauseFalsePositiveOk(boolean b) {
|
||||||
|
MyObj rec = externalFunc2();
|
||||||
|
while (b) {
|
||||||
|
rec = rec.rec;
|
||||||
|
}
|
||||||
|
rec.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void primitiveFieldOfAngelicObjMayCauseFalseNegativeBad() {
|
||||||
|
MyObj ret = externalFunc2();
|
||||||
|
if (ret.i == 0) {
|
||||||
|
int i = 1 / 0;
|
||||||
|
} else {
|
||||||
|
int i = 1 / 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void primitiveFieldOfAngelicObjMayCauseFalsePositiveOk() {
|
||||||
|
MyObj ret = externalFunc2();
|
||||||
|
if (ret.i != 0) {
|
||||||
|
int i = 1 / ret.i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void heapFieldOfAngelicObjMayCauseFalseNegativeBad() {
|
||||||
|
MyObj ret = externalFunc2();
|
||||||
|
Object obj = ret.f;
|
||||||
|
if (obj == ret.f) {
|
||||||
|
int i = 1 / 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void heapFieldOfAngelicObjMayCauseFalsePositiveOk() {
|
||||||
|
MyObj ret = externalFunc2();
|
||||||
|
Object obj = ret.f;
|
||||||
|
if (obj != ret.f) {
|
||||||
|
int i = 1 / 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fieldReadAferCastMayCauseFalseNegativeBad(Iterator<MyObj> iter) {
|
||||||
|
MyObj ret = iter.next();
|
||||||
|
Object obj = ret.f;
|
||||||
|
obj.toString();
|
||||||
|
int i = ret.i;
|
||||||
|
if (i == 7) {
|
||||||
|
int j = 1 / 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void derefParamOk(MyObj obj) {
|
||||||
|
Object f = obj.f;
|
||||||
|
f.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fieldReadInCalleeMayCauseFalsePositiveOk() {
|
||||||
|
MyObj ret = externalFunc2();
|
||||||
|
derefParamOk(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fieldReadInCalleeMayCauseFalseNegativeBad() {
|
||||||
|
MyObj ret = externalFunc2();
|
||||||
|
ret.f = null;
|
||||||
|
derefParamOk(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fieldReadInCalleeWithAngelicObjFieldMayCauseFalsePositiveOk() {
|
||||||
|
MyObj ret = externalFunc2();
|
||||||
|
derefParamOk(ret.rec);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fieldReadInCalleeWithAngelicObjFieldMayCauseFalseNegativeBad() {
|
||||||
|
MyObj ret = externalFunc2();
|
||||||
|
ret.rec.f = null;
|
||||||
|
derefParamOk(ret.rec);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void accessPathOnParamOk(MyObj obj) {
|
||||||
|
MyObj ret = obj.rec;
|
||||||
|
Object f = ret.f;
|
||||||
|
f.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void accessPathInCalleeMayCauseFalsePositiveOk() {
|
||||||
|
MyObj ret = externalFunc2();
|
||||||
|
accessPathOnParamOk(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void accessPathInCalleeMayCauseFalseNegativeBad() {
|
||||||
|
MyObj ret = externalFunc2();
|
||||||
|
ret.rec.f = null;
|
||||||
|
accessPathOnParamOk(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void skipFunctionInLoopMayCauseFalseNegativeBad() {
|
||||||
|
Object o = null;
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
externalFunc();
|
||||||
|
}
|
||||||
|
o.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// will fail to find error unless spec inference succeeds for all callees
|
||||||
|
public void specInferenceMayFailAndCauseFalseNegativeBad(boolean b, Iterator<MyObj> iter) {
|
||||||
|
skipPointerDerefMayCauseLocalFalseNegativeBad();
|
||||||
|
skipPointerDerefPreventsSpecInferenceRetObj();
|
||||||
|
skipPointerDerefPreventsSpecInferenceRetZero();
|
||||||
|
skipPointerDerefMayCauseCalleeFalseNegativeBad();
|
||||||
|
skipPointerDerefMayCauseInterprocFalseNegativeBad();
|
||||||
|
castFailureOnUndefinedObjMayCauseFalseNegativeBad();
|
||||||
|
callOnCastUndefinedObjMayCauseFalseNegativeBad();
|
||||||
|
callOnUndefinedObjMayCauseFalseNegativeBad();
|
||||||
|
callOnUndefinedObjMayCauseFalsePositiveOk();
|
||||||
|
fieldWriteOnUndefinedObjMayCauseFalseNegativeBad();
|
||||||
|
fieldWriteOnUndefinedObjMayCauseFalsePositiveOk();
|
||||||
|
fieldReadOnUndefinedObjMayCauseFalseNegativeBad();
|
||||||
|
fieldReadOnUndefinedObjMayCauseFalsePositiveOk();
|
||||||
|
recursiveAngelicTypesMayCauseFalseNegativeBad();
|
||||||
|
recursiveAngelicTypesMayCauseFalsePositiveOk();
|
||||||
|
infiniteMaterializationMayCauseFalseNegativeBad(b);
|
||||||
|
infiniteMaterializationMayCauseFalsePositiveOk(b);
|
||||||
|
primitiveFieldOfAngelicObjMayCauseFalsePositiveOk();
|
||||||
|
primitiveFieldOfAngelicObjMayCauseFalseNegativeBad();
|
||||||
|
heapFieldOfAngelicObjMayCauseFalsePositiveOk();
|
||||||
|
heapFieldOfAngelicObjMayCauseFalseNegativeBad();
|
||||||
|
fieldReadAferCastMayCauseFalseNegativeBad(iter);
|
||||||
|
fieldReadInCalleeMayCauseFalsePositiveOk();
|
||||||
|
fieldReadInCalleeWithAngelicObjFieldMayCauseFalsePositiveOk();
|
||||||
|
accessPathInCalleeMayCauseFalsePositiveOk();
|
||||||
|
int i = 1 / 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
public class ArrayOutOfBounds {
|
||||||
|
|
||||||
|
public int arrayOutOfBoundsBad() {
|
||||||
|
int[] arr = new int[1];
|
||||||
|
return arr[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int arrayInBoundsOk() {
|
||||||
|
int[] arr = new int[2];
|
||||||
|
return arr[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// tests below this line are turned off until array functionality improves
|
||||||
|
public void arrayLoopOutOfBoundsOk(int[] arr) {
|
||||||
|
for (int i = 0; i <= arr.length; i++) {
|
||||||
|
int j = arr[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void arrayLoopInBoundsOk(int[] arr) {
|
||||||
|
for (int i = 0; i < arr.length; i++) {
|
||||||
|
int j = arr[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void buggyIterOk(int[] arr1, int[] arr2) {
|
||||||
|
for (int i = 0; i < arr1.length; i++) {
|
||||||
|
arr2[i] = 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void switchedArrsOutOfBoundsOk() {
|
||||||
|
buggyIterOk(new int[11], new int[10]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void buggyNestedLoop1Ok(int[] arr1, int[] arr2) {
|
||||||
|
for (int i = 0; i < arr1.length; i++) {
|
||||||
|
for (int j = 0; i < arr2.length; j++) {
|
||||||
|
arr1[i] = arr1[i] + arr2[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void nestedOutOfBounds1Ok() {
|
||||||
|
buggyNestedLoop1Ok(new int[11], new int[10]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void buggyNestedLoop2Ok(int[] arr1, int[] arr2) {
|
||||||
|
for (int i = 0; i < arr1.length; i++) {
|
||||||
|
for (int j = 0; j < arr2.length; i++) {
|
||||||
|
arr1[i] = arr1[i] + arr2[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void nestedOutOfBounds2Ok() {
|
||||||
|
buggyNestedLoop2Ok(new int[11], new int[10]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void buggyNestedLoop3Ok(int[] arr1, int[] arr2) {
|
||||||
|
for (int i = 0; i < arr1.length; i++) {
|
||||||
|
for (int j = 0; j < arr2.length; j++) {
|
||||||
|
arr1[i] = 2 * arr2[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void nestedOutOfBounds3Ok() {
|
||||||
|
buggyNestedLoop3Ok(new int[11], new int[10]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void safeNestedLoopOk(int[] arr1, int[] arr2) {
|
||||||
|
for (int i = 0; i < arr1.length; i++) {
|
||||||
|
for (int j = 0; j < arr2.length; j++) {
|
||||||
|
arr1[i] = arr1[i] + arr2[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void nestedInBoundsOk() {
|
||||||
|
safeNestedLoopOk(new int[11], new int[10]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
/* @generated */
|
||||||
|
|
||||||
|
public class AutoGenerated {
|
||||||
|
|
||||||
|
void npeBad() {
|
||||||
|
String s = null;
|
||||||
|
int n = s.length();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import com.facebook.infer.builtins.InferBuiltins;
|
||||||
|
|
||||||
|
public class Builtins {
|
||||||
|
|
||||||
|
void blockErrorOk() {
|
||||||
|
Object x = null;
|
||||||
|
InferBuiltins.assume(x != null);
|
||||||
|
x.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void doNotBlockErrorBad(Object x) {
|
||||||
|
Object y = null;
|
||||||
|
InferBuiltins.assume(x != null);
|
||||||
|
y.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void blockErrorIntAssumeOk(Object x) {
|
||||||
|
Object y = null;
|
||||||
|
int i = 0;
|
||||||
|
InferBuiltins.assume(i != 0);
|
||||||
|
y.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void causeErrorBad(Object x) {
|
||||||
|
InferBuiltins.assume(x == null);
|
||||||
|
x.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
class SuperClass {}
|
||||||
|
|
||||||
|
class SubClassA extends SuperClass {}
|
||||||
|
|
||||||
|
class SubClassB extends SuperClass {}
|
||||||
|
|
||||||
|
interface MyInterface {
|
||||||
|
public int getInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
class ImplementationOfInterface implements MyInterface {
|
||||||
|
|
||||||
|
public int getInt() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AnotherImplementationOfInterface implements MyInterface {
|
||||||
|
public int getInt() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ClassCastExceptions {
|
||||||
|
|
||||||
|
public void classCastExceptionBad() {
|
||||||
|
SuperClass a = new SubClassA();
|
||||||
|
SubClassB b = (SubClassB) a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int classCastExceptionImplementsInterfaceCalleeOk(MyInterface i) {
|
||||||
|
ImplementationOfInterface impl = (ImplementationOfInterface) i;
|
||||||
|
return impl.getInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int classCastExceptionImplementsInterfaceBad() {
|
||||||
|
return classCastExceptionImplementsInterfaceCalleeOk(new AnotherImplementationOfInterface());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getURL() {
|
||||||
|
return "http://bla.com";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void openHttpURLConnectionOk() throws IOException {
|
||||||
|
URL url = new URL(getURL());
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void castingArrayOfPrimitiveTypeOk(int[] a) {
|
||||||
|
int[] b = (int[]) a;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,248 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
class LocalException extends IOException {}
|
||||||
|
|
||||||
|
class SomeResource implements Closeable {
|
||||||
|
|
||||||
|
void doSomething() throws LocalException {
|
||||||
|
if (!CloseableAsResourceExample.star()) {
|
||||||
|
throw new LocalException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {}
|
||||||
|
|
||||||
|
native void foo(int i);
|
||||||
|
|
||||||
|
static native void bar(SomeResource r);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Resource implements Closeable {
|
||||||
|
public Resource() {}
|
||||||
|
|
||||||
|
public void close() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Wrapper implements Closeable {
|
||||||
|
Resource mR;
|
||||||
|
|
||||||
|
public Wrapper(Resource r) {
|
||||||
|
mR = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
mR.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Sub extends Wrapper {
|
||||||
|
public Sub(Resource r) {
|
||||||
|
super(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ResourceWithException implements Closeable {
|
||||||
|
|
||||||
|
public void close() throws IOException {
|
||||||
|
if (CloseableAsResourceExample.star()) {
|
||||||
|
throw new IOException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ByteArrayOutputStreamWrapper extends ByteArrayOutputStream {}
|
||||||
|
|
||||||
|
class ByteArrayInputStreamWrapper extends ByteArrayInputStream {
|
||||||
|
|
||||||
|
public ByteArrayInputStreamWrapper(byte[] arr) {
|
||||||
|
super(arr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CloseableAsResourceExample {
|
||||||
|
|
||||||
|
static native boolean star();
|
||||||
|
|
||||||
|
void closingCloseable() {
|
||||||
|
SomeResource res = new SomeResource();
|
||||||
|
res.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void notClosingCloseable() {
|
||||||
|
SomeResource res = new SomeResource();
|
||||||
|
} // should report a resource leak
|
||||||
|
|
||||||
|
void tryWithResource() {
|
||||||
|
try (SomeResource res = new SomeResource()) {
|
||||||
|
try {
|
||||||
|
res.doSomething();
|
||||||
|
} catch (LocalException e) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void withExceptionBad() throws LocalException {
|
||||||
|
SomeResource res = new SomeResource();
|
||||||
|
res.doSomething();
|
||||||
|
res.close();
|
||||||
|
} // should report a resource leak
|
||||||
|
|
||||||
|
void closingWrapper() {
|
||||||
|
Resource r = new Resource();
|
||||||
|
Sub s = new Sub(r);
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void notClosingWrapper() {
|
||||||
|
Sub s = new Sub(new Resource());
|
||||||
|
s.mR.close();
|
||||||
|
} // should report a resource leak
|
||||||
|
|
||||||
|
void noNeedToCloseStringReader() {
|
||||||
|
StringReader stringReader = new StringReader("paf!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void noNeedToCloseByteArrayOutputStream() {
|
||||||
|
ByteArrayOutputStream stream = new ByteArrayOutputStream(42);
|
||||||
|
}
|
||||||
|
|
||||||
|
void noCloseByteArrayWrappersOk(byte[] array) {
|
||||||
|
ByteArrayOutputStreamWrapper stream1 = new ByteArrayOutputStreamWrapper();
|
||||||
|
ByteArrayInputStreamWrapper stream2 = new ByteArrayInputStreamWrapper(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
void noNeedToCloseByteArrayInputStream(byte[] array) {
|
||||||
|
ByteArrayInputStream stream = new ByteArrayInputStream(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
void closingWithCloseQuietly() {
|
||||||
|
SomeResource r = null;
|
||||||
|
try {
|
||||||
|
r = new SomeResource();
|
||||||
|
r.doSomething();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
Utils.closeQuietly(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void failToCloseWithCloseQuietly() {
|
||||||
|
try {
|
||||||
|
SomeResource r = new SomeResource();
|
||||||
|
r.doSomething();
|
||||||
|
Utils.closeQuietly(r);
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void noLeakwithExceptionOnClose() throws IOException {
|
||||||
|
ResourceWithException res = new ResourceWithException();
|
||||||
|
res.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void noLeakWithCloseQuietlyAndExceptionOnClose() {
|
||||||
|
ResourceWithException res = new ResourceWithException();
|
||||||
|
Utils.closeQuietly(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
static T sourceOfNullWithResourceLeak() {
|
||||||
|
SomeResource r = new SomeResource();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MyCloseable extends Closeable {}
|
||||||
|
|
||||||
|
class MyResource implements MyCloseable {
|
||||||
|
public void close() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void leakFoundWhenIndirectlyImplementingCloseable() {
|
||||||
|
MyResource res = new MyResource();
|
||||||
|
}
|
||||||
|
|
||||||
|
void skippedCallClosesResourceOnArgs() {
|
||||||
|
SomeResource res = new SomeResource();
|
||||||
|
SomeResource.bar(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void skippedVritualCallDoesNotCloseResourceOnReceiver() {
|
||||||
|
SomeResource res = new SomeResource();
|
||||||
|
res.foo(42);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map returnsLocalMapContainingResourcesOk() {
|
||||||
|
HashMap<Integer, Closeable> map = new HashMap<>();
|
||||||
|
SomeResource res = new SomeResource();
|
||||||
|
Integer key = 42;
|
||||||
|
map.put(key, res);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
void createsLocalMapContainingResourcesOk() {
|
||||||
|
HashMap<Integer, Closeable> map = new HashMap<>();
|
||||||
|
SomeResource res = new SomeResource();
|
||||||
|
Integer key = 42;
|
||||||
|
map.put(key, res);
|
||||||
|
map.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap<Integer, Closeable> resourceMap = new HashMap<>();
|
||||||
|
|
||||||
|
void fieldMapContainingResourcesOk() {
|
||||||
|
Integer key = 42;
|
||||||
|
SomeResource res = new SomeResource();
|
||||||
|
resourceMap.put(key, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this case is not supported
|
||||||
|
void FN_notClearinglocalMapContainingResourcesBad() {
|
||||||
|
HashMap<Integer, Closeable> map = new HashMap<>();
|
||||||
|
SomeResource res = new SomeResource();
|
||||||
|
Integer key = 42;
|
||||||
|
map.put(key, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void closeCloseable(Closeable closeable) {
|
||||||
|
try {
|
||||||
|
if (closeable != null) {
|
||||||
|
closeable.close();
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void finallyCloseOk(File file, String fileContent) {
|
||||||
|
if (!file.exists()) {
|
||||||
|
FileWriter writer = null;
|
||||||
|
try {
|
||||||
|
writer = new FileWriter(file);
|
||||||
|
writer.write(fileContent);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
closeCloseable(writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,244 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import android.app.DownloadManager;
|
||||||
|
import android.content.ContentProviderClient;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.CursorWrapper;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteQueryBuilder;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.provider.MediaStore;
|
||||||
|
|
||||||
|
public class CursorLeaks {
|
||||||
|
|
||||||
|
public int cursorClosed(SQLiteDatabase sqLiteDatabase) {
|
||||||
|
Cursor cursor = sqLiteDatabase.query("events", null, null, null, null, null, null);
|
||||||
|
try {
|
||||||
|
return cursor.getCount();
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object cursorClosedCheckNull(SQLiteDatabase sqLiteDatabase) {
|
||||||
|
Cursor cursor = sqLiteDatabase.query("events", null, null, null, null, null, null);
|
||||||
|
Object value = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (cursor == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = cursor.getString(0);
|
||||||
|
} finally {
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object cursorClosedCheckNullCheckClosed_FP(SQLiteDatabase sqLiteDatabase) {
|
||||||
|
Cursor cursor = sqLiteDatabase.query("events", null, null, null, null, null, null);
|
||||||
|
Object value = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (cursor == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = cursor.getString(0);
|
||||||
|
} finally {
|
||||||
|
if (cursor != null && !cursor.isClosed()) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int cursorNotClosed(SQLiteDatabase sqLiteDatabase) {
|
||||||
|
Cursor cursor = sqLiteDatabase.query("events", null, null, null, null, null, null);
|
||||||
|
return cursor.getCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
Context mContext;
|
||||||
|
ContentResolver mContentResolver;
|
||||||
|
|
||||||
|
public int getImageCountHelperNotClosed(String customClause) {
|
||||||
|
String[] projection = {"COUNT(*)"};
|
||||||
|
|
||||||
|
String selectionClause = selectionClause = customClause;
|
||||||
|
|
||||||
|
Cursor cursor =
|
||||||
|
mContext.getContentResolver().query(null, projection, selectionClause, null, null);
|
||||||
|
|
||||||
|
if (cursor != null) {
|
||||||
|
int count = cursor.getInt(0);
|
||||||
|
// cursor.close();
|
||||||
|
return count;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getImageCountHelperClosed(String customClause) {
|
||||||
|
String[] projection = {"COUNT(*)"};
|
||||||
|
|
||||||
|
String selectionClause = selectionClause = customClause;
|
||||||
|
|
||||||
|
Cursor cursor =
|
||||||
|
mContext.getContentResolver().query(null, projection, selectionClause, null, null);
|
||||||
|
|
||||||
|
if (cursor != null) {
|
||||||
|
int count = cursor.getInt(0);
|
||||||
|
cursor.close();
|
||||||
|
return count;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBucketCountNotClosed() {
|
||||||
|
Cursor cursor = MediaStore.Images.Media.query(mContentResolver, null, null, null, null, null);
|
||||||
|
if (cursor == null) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
int count = 0;
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBucketCountClosed() {
|
||||||
|
Cursor cursor = MediaStore.Images.Media.query(mContentResolver, null, null, null, null, null);
|
||||||
|
if (cursor == null) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
int count = 0;
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void queryUVMLegacyDbNotClosed() {
|
||||||
|
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
|
||||||
|
builder.setTables("");
|
||||||
|
Cursor cursor = builder.query(null, null, "", null, null, null, null);
|
||||||
|
if (cursor != null) cursor.moveToFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void queryUVMLegacyDbClosed() {
|
||||||
|
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
|
||||||
|
builder.setTables("");
|
||||||
|
Cursor cursor = builder.query(null, null, "", null, null, null, null);
|
||||||
|
if (cursor != null) cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int completeDownloadClosed(DownloadManager downloadManager) {
|
||||||
|
DownloadManager.Query query = new DownloadManager.Query();
|
||||||
|
Cursor cursor = (Cursor) null;
|
||||||
|
try {
|
||||||
|
cursor = downloadManager.query(query);
|
||||||
|
if (cursor == null) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (cursor != null) cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int completeDownloadNotClosed(DownloadManager downloadManager) {
|
||||||
|
DownloadManager.Query query = new DownloadManager.Query();
|
||||||
|
Cursor cursor = null;
|
||||||
|
try {
|
||||||
|
cursor = downloadManager.query(query);
|
||||||
|
if (cursor == null) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
// cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadPrefsFromContentProviderClosed() {
|
||||||
|
ContentProviderClient contentProviderClient = mContentResolver.acquireContentProviderClient("");
|
||||||
|
if (contentProviderClient != null) {
|
||||||
|
Cursor cursor = null;
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
cursor = contentProviderClient.query(null, null, null, null, null);
|
||||||
|
} catch (RemoteException ex) {
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadPrefsFromContentProviderNotClosed() {
|
||||||
|
ContentProviderClient contentProviderClient = mContentResolver.acquireContentProviderClient("");
|
||||||
|
if (contentProviderClient == null) return;
|
||||||
|
Cursor cursor = null;
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
cursor = contentProviderClient.query(null, null, null, null, null);
|
||||||
|
} catch (RemoteException ex) {
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (cursor != null) {
|
||||||
|
// cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NamedCursor extends CursorWrapper {
|
||||||
|
private String mName;
|
||||||
|
|
||||||
|
NamedCursor(Cursor cursor, String name) {
|
||||||
|
super(cursor);
|
||||||
|
mName = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Cursor cursorWrapperReturned(SQLiteDatabase sqLiteDatabase) {
|
||||||
|
Cursor cursor = sqLiteDatabase.query("events", null, null, null, null, null, null);
|
||||||
|
return new NamedCursor(cursor, "abc");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO (#7474990): investigate why is Infer reporting a resource leak here
|
||||||
|
// public void cursorWrapperClosed(SQLiteDatabase sqLiteDatabase) {
|
||||||
|
// Cursor cursor = sqLiteDatabase.query("events", null, null, null, null, null, null);
|
||||||
|
// Cursor c = new NamedCursor(cursor, "abc");
|
||||||
|
// c.close();
|
||||||
|
// }
|
||||||
|
|
||||||
|
native NamedCursor createWrapper(Cursor cursor);
|
||||||
|
|
||||||
|
public NamedCursor cursorAttachedTheWrapper(SQLiteDatabase sqLiteDatabase) {
|
||||||
|
Cursor cursor = sqLiteDatabase.query("events", null, null, null, null, null, null);
|
||||||
|
return createWrapper(cursor);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import android.app.DownloadManager;
|
||||||
|
import android.content.ContentProviderClient;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteQueryBuilder;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.provider.MediaStore;
|
||||||
|
|
||||||
|
public class CursorNPEs {
|
||||||
|
|
||||||
|
public int cursorNPEfromQuery(SQLiteDatabase sqLiteDatabase) {
|
||||||
|
Cursor cursor = sqLiteDatabase.query("events", null, null, null, null, null, null);
|
||||||
|
try {
|
||||||
|
return cursor.getCount();
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Context mContext;
|
||||||
|
ContentResolver mContentResolver;
|
||||||
|
|
||||||
|
public void cursorFromContentResolverNPE(String customClause) {
|
||||||
|
String[] projection = {"COUNT(*)"};
|
||||||
|
|
||||||
|
String selectionClause = selectionClause = customClause;
|
||||||
|
|
||||||
|
Cursor cursor =
|
||||||
|
mContext.getContentResolver().query(null, projection, selectionClause, null, null);
|
||||||
|
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cursorFromMediaNPE() {
|
||||||
|
Cursor cursor = MediaStore.Images.Media.query(mContentResolver, null, null, null, null, null);
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cursorFromSQLiteQueryBuilderNPE() {
|
||||||
|
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
|
||||||
|
builder.setTables("");
|
||||||
|
Cursor cursor = builder.query(null, null, "", null, null, null, null);
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int cursorFromDownloadManagerNPE(DownloadManager downloadManager) {
|
||||||
|
DownloadManager.Query query = new DownloadManager.Query();
|
||||||
|
Cursor cursor = null;
|
||||||
|
try {
|
||||||
|
cursor = downloadManager.query(query);
|
||||||
|
return cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
|
||||||
|
} finally {
|
||||||
|
if (cursor != null) cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cursorFromContentProviderClient() {
|
||||||
|
ContentProviderClient contentProviderClient = mContentResolver.acquireContentProviderClient("");
|
||||||
|
if (contentProviderClient != null) {
|
||||||
|
Cursor cursor = null;
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
cursor = contentProviderClient.query(null, null, null, null, null);
|
||||||
|
cursor.moveToFirst();
|
||||||
|
} catch (RemoteException ex) {
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
public class DivideByZero {
|
||||||
|
|
||||||
|
public int divByZeroLocal(String s) {
|
||||||
|
int denominator = 0;
|
||||||
|
int nominator = 10;
|
||||||
|
int result = nominator / denominator;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int divideByZeroInterProc(int denominator) {
|
||||||
|
return 10 / denominator;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DO NOT MOVE, test relies on line number
|
||||||
|
public int callDivideByZeroInterProc() {
|
||||||
|
return divideByZeroInterProc(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// divide by zero with static fields
|
||||||
|
private static int x;
|
||||||
|
|
||||||
|
public void setXToZero() {
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int divideByZeroWithStaticField() {
|
||||||
|
setXToZero();
|
||||||
|
return divideByZeroInterProc(x);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class DoubleExample {
|
||||||
|
|
||||||
|
@Nullable Double x;
|
||||||
|
|
||||||
|
private Double testAssignNonNullOk() {
|
||||||
|
x = 1.0;
|
||||||
|
return x + 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Double testdReadNullableBad() {
|
||||||
|
return x + 1.0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,261 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.security.DigestInputStream;
|
||||||
|
import java.util.zip.CheckedInputStream;
|
||||||
|
import java.util.zip.DeflaterInputStream;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
import java.util.zip.InflaterInputStream;
|
||||||
|
import javax.crypto.CipherInputStream;
|
||||||
|
|
||||||
|
public class FilterInputStreamLeaks {
|
||||||
|
|
||||||
|
// BufferedInputStream tests
|
||||||
|
|
||||||
|
public void bufferedInputStreamNotClosedAfterRead() {
|
||||||
|
FileInputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
BufferedInputStream bis = new BufferedInputStream(fis);
|
||||||
|
bis.read();
|
||||||
|
bis.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bufferedInputStreamClosedAfterReset() throws IOException {
|
||||||
|
FileInputStream fis;
|
||||||
|
BufferedInputStream bis = null;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
bis = new BufferedInputStream(fis);
|
||||||
|
bis.reset();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (bis != null) bis.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckedInputStream tests
|
||||||
|
|
||||||
|
public void checkedInputStreamNotClosedAfterRead() {
|
||||||
|
FileInputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
CheckedInputStream chis = new CheckedInputStream(fis, null);
|
||||||
|
chis.read();
|
||||||
|
chis.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkedInputStreamClosedAfterSkip() throws IOException {
|
||||||
|
FileInputStream fis;
|
||||||
|
CheckedInputStream chis = null;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
chis = new CheckedInputStream(fis, null);
|
||||||
|
chis.skip(5);
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (chis != null) chis.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CipherInputStream tests
|
||||||
|
|
||||||
|
public void cipherInputStreamNotClosedAfterSkip() {
|
||||||
|
FileInputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
CipherInputStream cis = new CipherInputStream(fis, null);
|
||||||
|
cis.skip(8);
|
||||||
|
cis.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cipherInputStreamClosedAfterRead() throws IOException {
|
||||||
|
FileInputStream fis;
|
||||||
|
CipherInputStream cis = null;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
cis = new CipherInputStream(fis, null);
|
||||||
|
cis.read();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (cis != null) cis.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataInputStream tests
|
||||||
|
|
||||||
|
public void dataInputStreamNotClosedAfterRead() {
|
||||||
|
byte[] arr = new byte[10];
|
||||||
|
FileInputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
DataInputStream dis = new DataInputStream(fis);
|
||||||
|
dis.read(arr);
|
||||||
|
dis.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dataInputStreamClosedAfterReadBoolean() throws IOException {
|
||||||
|
FileInputStream fis;
|
||||||
|
DataInputStream dis = null;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
dis = new DataInputStream(fis);
|
||||||
|
dis.readBoolean();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (dis != null) dis.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeflaterInputStream tests
|
||||||
|
|
||||||
|
public void deflaterInputStreamNotClosedAfterRead() {
|
||||||
|
FileInputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
DeflaterInputStream dis = new DeflaterInputStream(fis, null);
|
||||||
|
dis.read();
|
||||||
|
dis.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deflaterInputStreamClosedAfterReset() throws IOException {
|
||||||
|
FileInputStream fis;
|
||||||
|
DeflaterInputStream dis = null;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
dis = new DeflaterInputStream(fis, null);
|
||||||
|
dis.reset();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (dis != null) dis.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GZipInputStream tests
|
||||||
|
|
||||||
|
public void gzipInputStreamNotClosedAfterRead() {
|
||||||
|
FileInputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
GZIPInputStream gzipInputStream = new GZIPInputStream(fis);
|
||||||
|
gzipInputStream.read();
|
||||||
|
gzipInputStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void gzipInputStreamClosedAfterRead() throws IOException {
|
||||||
|
FileInputStream fis = null;
|
||||||
|
GZIPInputStream gzipInputStream = null;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
gzipInputStream = new GZIPInputStream(fis);
|
||||||
|
gzipInputStream.read();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (gzipInputStream != null) gzipInputStream.close();
|
||||||
|
else if (fis != null) fis.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DigestInputStream tests
|
||||||
|
|
||||||
|
public void digestInputStreamNotClosedAfterRead() {
|
||||||
|
byte[] arr = new byte[10];
|
||||||
|
FileInputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
DigestInputStream dis = new DigestInputStream(fis, null);
|
||||||
|
dis.read(arr);
|
||||||
|
dis.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void digestInputStreamClosedAfterRead() throws IOException {
|
||||||
|
FileInputStream fis;
|
||||||
|
DigestInputStream dis = null;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
dis = new DigestInputStream(fis, null);
|
||||||
|
dis.read();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (dis != null) dis.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// InflaterInputStream tests
|
||||||
|
|
||||||
|
public void inflaterInputStreamNotClosedAfterRead() {
|
||||||
|
FileInputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
InflaterInputStream iis = new InflaterInputStream(fis, null);
|
||||||
|
iis.read();
|
||||||
|
iis.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inflaterInputStreamClosedAfterAvailable() throws IOException {
|
||||||
|
FileInputStream fis;
|
||||||
|
InflaterInputStream iis = null;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
iis = new InflaterInputStream(fis, null);
|
||||||
|
iis.available();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (iis != null) iis.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushbackInputStream tests
|
||||||
|
|
||||||
|
public void pushbackInputStreamNotClosedAfterRead() {
|
||||||
|
FileInputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
PushbackInputStream pms = new PushbackInputStream(fis);
|
||||||
|
pms.read();
|
||||||
|
pms.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pushbackInputStreamClosedAfterReset() throws IOException {
|
||||||
|
FileInputStream fis;
|
||||||
|
PushbackInputStream pms = null;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
pms = new PushbackInputStream(fis);
|
||||||
|
pms.reset();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (pms != null) pms.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void twoLevelWrapperNoLeak(File file) throws IOException {
|
||||||
|
DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,302 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.FilterOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.DigestOutputStream;
|
||||||
|
import java.util.zip.CheckedOutputStream;
|
||||||
|
import java.util.zip.DeflaterOutputStream;
|
||||||
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
import java.util.zip.InflaterOutputStream;
|
||||||
|
import javax.crypto.CipherOutputStream;
|
||||||
|
|
||||||
|
public class FilterOutputStreamLeaks {
|
||||||
|
|
||||||
|
// FilterOutputStream tests
|
||||||
|
|
||||||
|
public void filterOutputStreamNotClosedAfterWrite() {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
FilterOutputStream fos = new FilterOutputStream(fis);
|
||||||
|
fos.write(arr);
|
||||||
|
fos.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void filterOutputStreamClosedAfterWrite() throws IOException {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis;
|
||||||
|
FilterOutputStream fos = null;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
fos = new FilterOutputStream(fis);
|
||||||
|
fos.write(arr);
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (fos != null) fos.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataOutputStream tests
|
||||||
|
|
||||||
|
public void dataOutputStreamNotClosedAfterWrite() {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
DataOutputStream dos = new DataOutputStream(fis);
|
||||||
|
dos.write(arr);
|
||||||
|
dos.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dataOutputStreamClosedAfterWrite() throws IOException {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis;
|
||||||
|
DataOutputStream dos = null;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
dos = new DataOutputStream(fis);
|
||||||
|
dos.write(arr);
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (dos != null) dos.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BufferedOutputStream tests
|
||||||
|
|
||||||
|
public void bufferedOutputStreamNotClosedAfterWrite() {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis = null;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
BufferedOutputStream bos = new BufferedOutputStream(fis);
|
||||||
|
bos.write(arr);
|
||||||
|
bos.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bufferedOutputStreamClosedAfterWrite() throws IOException {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis;
|
||||||
|
BufferedOutputStream bos = null;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
bos = new BufferedOutputStream(fis);
|
||||||
|
bos.write(arr);
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (bos != null) bos.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckedOutputStream tests
|
||||||
|
|
||||||
|
public void checkedOutputStreamNotClosedAfterWrite() {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
CheckedOutputStream chos = new CheckedOutputStream(fis, null);
|
||||||
|
chos.write(arr);
|
||||||
|
chos.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkedOutputStreamClosedAfterWrite() throws IOException {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis;
|
||||||
|
CheckedOutputStream chos = null;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
chos = new CheckedOutputStream(fis, null);
|
||||||
|
chos.write(arr);
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (chos != null) chos.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CipherOutputStream tests
|
||||||
|
|
||||||
|
public void cipherOutputStreamNotClosedAfterWrite() {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
CipherOutputStream cos = new CipherOutputStream(fis, null);
|
||||||
|
cos.write(arr);
|
||||||
|
cos.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cipherOutputStreamClosedAfterWrite() throws IOException {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis;
|
||||||
|
CipherOutputStream cos = null;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
cos = new CipherOutputStream(fis, null);
|
||||||
|
cos.write(arr);
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (cos != null) cos.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeflaterOutputStream tests
|
||||||
|
|
||||||
|
public void deflaterOutputStreamNotClosedAfterWrite() {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
DeflaterOutputStream dos = new DeflaterOutputStream(fis, null);
|
||||||
|
dos.write(arr);
|
||||||
|
dos.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deflaterOutputStreamClosedAfterWrite() throws IOException {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis;
|
||||||
|
DeflaterOutputStream dos = null;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
dos = new DeflaterOutputStream(fis, null);
|
||||||
|
dos.write(arr);
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (dos != null) dos.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DigestOutputStream tests
|
||||||
|
|
||||||
|
public void digestOutputStreamNotClosedAfterWrite() {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
DigestOutputStream dos = new DigestOutputStream(fis, null);
|
||||||
|
dos.write(arr);
|
||||||
|
dos.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void digestOutputStreamClosedAfterWrite() throws IOException {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis;
|
||||||
|
DigestOutputStream dos = null;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
dos = new DigestOutputStream(fis, null);
|
||||||
|
dos.write(arr);
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (dos != null) dos.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// InflaterOutputStream tests
|
||||||
|
|
||||||
|
public void inflaterOutputStreamNotClosedAfterWrite() {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
InflaterOutputStream ios = new InflaterOutputStream(fis, null);
|
||||||
|
ios.write(arr);
|
||||||
|
ios.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inflaterOutputStreamClosedAfterWrite() throws IOException {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis;
|
||||||
|
InflaterOutputStream ios = null;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
ios = new InflaterOutputStream(fis, null);
|
||||||
|
ios.write(arr);
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (ios != null) ios.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GZipOutputStream tests
|
||||||
|
|
||||||
|
public void gzipOutputStreamNotClosedAfterFlush() {
|
||||||
|
FileOutputStream fos;
|
||||||
|
try {
|
||||||
|
fos = new FileOutputStream("file.txt");
|
||||||
|
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(fos);
|
||||||
|
gzipOutputStream.flush();
|
||||||
|
gzipOutputStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void gzipOutputStreamClosedAfterWrite() throws IOException {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fos = null;
|
||||||
|
GZIPOutputStream gzipOutputStream = null;
|
||||||
|
try {
|
||||||
|
fos = new FileOutputStream("file.txt");
|
||||||
|
gzipOutputStream = new GZIPOutputStream(fos);
|
||||||
|
gzipOutputStream.write(arr);
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (gzipOutputStream != null) gzipOutputStream.close();
|
||||||
|
else if (fos != null) fos.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrintStream tests
|
||||||
|
|
||||||
|
public void printStreamNotClosedAfterWrite() {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
InflaterOutputStream printer = new InflaterOutputStream(fis, null);
|
||||||
|
printer.write(arr);
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printStreamClosedAfterWrite() throws IOException {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis;
|
||||||
|
InflaterOutputStream printer = null;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
printer = new InflaterOutputStream(fis, null);
|
||||||
|
printer.write(arr);
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (printer != null) printer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,576 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
|
|
||||||
|
public class GuardedByExample {
|
||||||
|
|
||||||
|
static class AutoCloseableReadWriteUpdateLock implements Closeable {
|
||||||
|
@Override
|
||||||
|
public void close() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object mLock = new Object();
|
||||||
|
|
||||||
|
private Object mOtherLock = new Object();
|
||||||
|
|
||||||
|
private AutoCloseableReadWriteUpdateLock mReadWriteLock = new AutoCloseableReadWriteUpdateLock();
|
||||||
|
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
private Object f = new Object();
|
||||||
|
|
||||||
|
@GuardedBy("this")
|
||||||
|
Object g = new Object();
|
||||||
|
|
||||||
|
Object mCopyOfG;
|
||||||
|
|
||||||
|
@GuardedBy("SomeLockThatDoesntExist")
|
||||||
|
Object h = new Object();
|
||||||
|
|
||||||
|
@GuardedBy("mReadWriteLock")
|
||||||
|
Object i = new Object();
|
||||||
|
|
||||||
|
private static Object sLock = new Object();
|
||||||
|
|
||||||
|
@GuardedBy("sLock")
|
||||||
|
static Object sFld;
|
||||||
|
|
||||||
|
@GuardedBy("GuardedByExample.class")
|
||||||
|
static Object sGuardedByClass;
|
||||||
|
|
||||||
|
static {
|
||||||
|
// don't warn on class initializer
|
||||||
|
sFld = new Object();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GuardedByExample() {
|
||||||
|
// don't warn on reads or writes of Guarded fields in constructor
|
||||||
|
f.toString();
|
||||||
|
g = new Object();
|
||||||
|
}
|
||||||
|
|
||||||
|
void readFBad() {
|
||||||
|
this.f.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("InvalidAccessToGuardedField")
|
||||||
|
void readFBadButSuppressed() {
|
||||||
|
this.f.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SomeOtherWarning")
|
||||||
|
void readFBadButSuppressedOther() {
|
||||||
|
this.f.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeFBad() {
|
||||||
|
this.f = new Object();
|
||||||
|
}
|
||||||
|
|
||||||
|
void readFBadWrongLock() {
|
||||||
|
synchronized (mOtherLock) {
|
||||||
|
this.f.toString(); // f is supposed to be protected by mLock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeFBadWrongLock() {
|
||||||
|
synchronized (mOtherLock) {
|
||||||
|
this.f = new Object(); // f is supposed to be protected by mLock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void readFAfterBlockBad() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
}
|
||||||
|
this.f.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeFAfterBlockBad() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
}
|
||||||
|
this.f = new Object();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mOtherLock")
|
||||||
|
void readFBadWrongAnnotation() {
|
||||||
|
this.f.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
void readFOkMethodAnnotated() {
|
||||||
|
this.f.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void synchronizedMethodReadOk() {
|
||||||
|
this.g.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void synchronizedMethodWriteOk() {
|
||||||
|
this.g = new Object();
|
||||||
|
}
|
||||||
|
|
||||||
|
void readFOkSynchronized() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
this.f.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeFOkSynchronized() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
this.f = new Object();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void synchronizedMethodReadBad() {
|
||||||
|
this.f.toString(); // f is supposed to be protected by mLock, not this
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void synchronizedMethodWriteBad() {
|
||||||
|
this.f = new Object(); // f is supposed to be protected by mLock, not this
|
||||||
|
}
|
||||||
|
|
||||||
|
void reassignCopyOk() {
|
||||||
|
synchronized (this) {
|
||||||
|
mCopyOfG = g; // these are ok: access of g guarded by this
|
||||||
|
}
|
||||||
|
mCopyOfG = new Object(); // ok; this doesn't change the value of g
|
||||||
|
}
|
||||||
|
|
||||||
|
void readHBad() {
|
||||||
|
synchronized (mLock) { // h is not protected by mLock
|
||||||
|
this.h.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void readHBadSynchronizedMethodShouldntHelp() {
|
||||||
|
this.h.toString(); // h is not protected by this
|
||||||
|
}
|
||||||
|
|
||||||
|
private void privateUnguardedAccess() {
|
||||||
|
// not protected, but safe if all call sites guard the access to f
|
||||||
|
this.g.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void guardedCallSite1() {
|
||||||
|
synchronized (this) {
|
||||||
|
privateUnguardedAccess(); // should not warn; lock is held
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void guardedCallSite2() {
|
||||||
|
privateUnguardedAccess(); // should not warn; lock is held
|
||||||
|
}
|
||||||
|
|
||||||
|
private void wrapper() {
|
||||||
|
privateUnguardedAccess(); // should not warn, just propagate the proof obl
|
||||||
|
}
|
||||||
|
|
||||||
|
public void guardedCallSite3() {
|
||||||
|
synchronized (this) {
|
||||||
|
wrapper(); // should not warn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void readWriteLockOk() {
|
||||||
|
try (AutoCloseableReadWriteUpdateLock lock = mReadWriteLock) {
|
||||||
|
this.i.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static synchronized void staticSynchronizedOk() {
|
||||||
|
sGuardedByClass.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void synchronizeOnClassOk1() {
|
||||||
|
synchronized (GuardedByExample.class) {
|
||||||
|
sGuardedByClass.toString(); // should not warn here
|
||||||
|
sGuardedByClass = new Object(); // or here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void synchronizedOnThisBad() {
|
||||||
|
sGuardedByClass.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
Object dontReportOnCompilerGenerated() {
|
||||||
|
return new Object() {
|
||||||
|
public void accessInAnonClassOk() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
f.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Object readFromInnerClassOkOuter() {
|
||||||
|
return new Object() {
|
||||||
|
public String readFromInnerClassOk() {
|
||||||
|
synchronized (GuardedByExample.this) {
|
||||||
|
return g.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Object readFromInnerClassBad1Outer() {
|
||||||
|
return new Object() {
|
||||||
|
public String readFromInnerClassBad1() {
|
||||||
|
synchronized (this) {
|
||||||
|
return g.toString(); // g is guarded by the outer class this, not this$0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Object readFromInnerClassBad2Outer() {
|
||||||
|
return new Object() {
|
||||||
|
public synchronized String readFromInnerClassBad2() {
|
||||||
|
return g.toString(); // g is guarded by the outer class this, not this$0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public void visibleForTestingOk1() {
|
||||||
|
f.toString(); // should push proof obl to caller
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void visibleForTestingOk2() {
|
||||||
|
f.toString(); // should push proof obl to caller
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized Object returnPtG() {
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
|
||||||
|
// note: this test should raise an error under "by value" GuardedBy semantics, but not under
|
||||||
|
// "by reference" GuardedBy semantics
|
||||||
|
void readGFromCopyOk() {
|
||||||
|
synchronized (this) {
|
||||||
|
mCopyOfG = g; // these are ok: access of g guarded by this
|
||||||
|
g.toString();
|
||||||
|
}
|
||||||
|
mCopyOfG.toString(); // should be an error; unprotected access to pt(g)
|
||||||
|
}
|
||||||
|
|
||||||
|
// another "by reference" vs "by value" test. buggy in "by value", but safe in "by reference"
|
||||||
|
void usePtG() {
|
||||||
|
Object ptG = returnPtG();
|
||||||
|
ptG.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
Object byRefTrickyBad() {
|
||||||
|
Object local = null;
|
||||||
|
synchronized (this) {
|
||||||
|
local = g; // we have a local pointer... to pt(G)
|
||||||
|
}
|
||||||
|
g.toString(); // ...but unsafe access is through g!
|
||||||
|
return local;
|
||||||
|
}
|
||||||
|
|
||||||
|
void byRefTrickyOk() {
|
||||||
|
Object local = null;
|
||||||
|
synchronized (this) {
|
||||||
|
local = g; // we have a local pointer... to pt(G)
|
||||||
|
}
|
||||||
|
local.toString(); // ...but unsafe access is through g!
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuardedBy("ui_thread")
|
||||||
|
Object uiThread1;
|
||||||
|
|
||||||
|
@GuardedBy("ui-thread")
|
||||||
|
Object uiThread2;
|
||||||
|
|
||||||
|
@GuardedBy("uithread")
|
||||||
|
Object uiThread3;
|
||||||
|
|
||||||
|
@GuardedBy("something that's clearly not an expression")
|
||||||
|
Object nonExpression;
|
||||||
|
|
||||||
|
// tests for not reporting false alarms on unrecognized GuardedBy strings
|
||||||
|
void accessUnrecognizedGuardedByFieldsOk() {
|
||||||
|
uiThread1 = new Object();
|
||||||
|
uiThread1.toString();
|
||||||
|
uiThread2 = new Object();
|
||||||
|
uiThread2.toString();
|
||||||
|
uiThread3 = new Object();
|
||||||
|
uiThread3.toString();
|
||||||
|
nonExpression = new Object();
|
||||||
|
nonExpression.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// outer class this tests
|
||||||
|
@GuardedBy("GuardedByExample.this")
|
||||||
|
Object guardedByOuterThis;
|
||||||
|
|
||||||
|
synchronized void okOuterAccess() {
|
||||||
|
guardedByOuterThis = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// inner class this tests
|
||||||
|
private class Inner {
|
||||||
|
@GuardedBy("this")
|
||||||
|
Object guardedByInnerThis1;
|
||||||
|
|
||||||
|
@GuardedBy("Inner.this")
|
||||||
|
Object guardedByInnerThis2;
|
||||||
|
|
||||||
|
@GuardedBy("GuardedByExample$Inner.this")
|
||||||
|
Object guardedByInnerThis3;
|
||||||
|
|
||||||
|
@GuardedBy("Inner.class")
|
||||||
|
Object guardedByInnerClass1;
|
||||||
|
|
||||||
|
@GuardedBy("GuardedByExample.Inner.class")
|
||||||
|
Object guardedByInnerClass2;
|
||||||
|
|
||||||
|
@GuardedBy("GuardedByExample$Inner.class")
|
||||||
|
Object guardedByInnerClass3;
|
||||||
|
|
||||||
|
synchronized void okAccess1() {
|
||||||
|
guardedByInnerThis1 = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void okAccess2() {
|
||||||
|
guardedByInnerThis2 = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void okAccess3() {
|
||||||
|
guardedByInnerThis3 = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void okInnerClassGuard1() {
|
||||||
|
synchronized (Inner.class) {
|
||||||
|
guardedByInnerClass1 = new Object();
|
||||||
|
guardedByInnerClass2 = new Object();
|
||||||
|
guardedByInnerClass3 = new Object();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void okInnerClassGuard2() {
|
||||||
|
synchronized (GuardedByExample.Inner.class) {
|
||||||
|
guardedByInnerClass1 = new Object();
|
||||||
|
guardedByInnerClass2 = new Object();
|
||||||
|
guardedByInnerClass3 = new Object();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: report on these cases
|
||||||
|
/*
|
||||||
|
public void unguardedCallSiteBad1() {
|
||||||
|
privateUnguardedAccess(); // should warn; lock is not held
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void unguardedCallSiteBad2() {
|
||||||
|
privateUnguardedAccess(); // should warn; lock is not held
|
||||||
|
}
|
||||||
|
|
||||||
|
void unguardedCallSiteBad3() {
|
||||||
|
privateUnguardedAccess(); // should warn; lock is not held
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
int n;
|
||||||
|
|
||||||
|
public void withloop2() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
for (int i = 0; i <= n; i++) {
|
||||||
|
f = 42;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void withoutloop2() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
f = 42;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuardedBy("self_reference")
|
||||||
|
Object self_reference;
|
||||||
|
|
||||||
|
void guardedBySelfReferenceOK() {
|
||||||
|
synchronized (self_reference) {
|
||||||
|
this.self_reference.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: report on this case, or at least a version which writes
|
||||||
|
/*
|
||||||
|
void guardedBySelfReferenceBad() {
|
||||||
|
this.self_reference.toString();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
@GuardedBy("itself")
|
||||||
|
Object itself_fld;
|
||||||
|
|
||||||
|
void itselfOK() {
|
||||||
|
synchronized (itself_fld) {
|
||||||
|
this.itself_fld.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: report on this case, or at least a version which writes
|
||||||
|
/*
|
||||||
|
void itselfBad() {
|
||||||
|
this.itself_fld.toString();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
ReadWriteLock mRWL;
|
||||||
|
|
||||||
|
@GuardedBy("mRWL")
|
||||||
|
Integer guardedbymRWL;
|
||||||
|
|
||||||
|
Integer someOtherInt;
|
||||||
|
|
||||||
|
void readLockOK() {
|
||||||
|
mRWL.readLock().lock();
|
||||||
|
someOtherInt = guardedbymRWL;
|
||||||
|
mRWL.readLock().unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeLockOK() {
|
||||||
|
mRWL.writeLock().lock();
|
||||||
|
guardedbymRWL = 55;
|
||||||
|
mRWL.writeLock().unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReentrantReadWriteLock mRRWL;
|
||||||
|
|
||||||
|
@GuardedBy("mRRWL")
|
||||||
|
Integer guardedbymRRWL;
|
||||||
|
|
||||||
|
void reentrantReadLockOK() {
|
||||||
|
mRRWL.readLock().lock();
|
||||||
|
someOtherInt = guardedbymRRWL;
|
||||||
|
mRRWL.readLock().unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reentrantWriteLockOK() {
|
||||||
|
mRRWL.writeLock().lock();
|
||||||
|
guardedbymRRWL = 55;
|
||||||
|
mRRWL.writeLock().unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: warn on misuse of read/write locks.
|
||||||
|
|
||||||
|
@GuardedBy("this")
|
||||||
|
Integer xForSub;
|
||||||
|
|
||||||
|
static class Sub extends GuardedByExample {
|
||||||
|
|
||||||
|
void goodSub1() {
|
||||||
|
synchronized (this) {
|
||||||
|
xForSub = 22;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void goodSub2() {
|
||||||
|
xForSub = 22;
|
||||||
|
}
|
||||||
|
|
||||||
|
void badSub() {
|
||||||
|
xForSub = 22;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Lock normallock;
|
||||||
|
|
||||||
|
@GuardedBy("normallock")
|
||||||
|
Integer guardedbynl;
|
||||||
|
|
||||||
|
ReentrantLock reentrantlock;
|
||||||
|
|
||||||
|
@GuardedBy("reentrantlock")
|
||||||
|
Integer guardedbyrel;
|
||||||
|
|
||||||
|
void goodGuardedByNormalLock() {
|
||||||
|
normallock.lock();
|
||||||
|
guardedbynl = 22;
|
||||||
|
normallock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void goodTryLockGuardedByNormalLock() {
|
||||||
|
if (normallock.tryLock()) {
|
||||||
|
guardedbynl = 22;
|
||||||
|
normallock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void goodTryLockGuardedByReentrantLock() {
|
||||||
|
if (reentrantlock.tryLock()) {
|
||||||
|
guardedbyrel = 44;
|
||||||
|
reentrantlock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void badGuardedByNormalLock() {
|
||||||
|
guardedbynl = 22;
|
||||||
|
}
|
||||||
|
|
||||||
|
void badGuardedByReentrantLock() {
|
||||||
|
guardedbyrel = 44;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class OtherClassWithLock {
|
||||||
|
ReentrantLock lock;
|
||||||
|
|
||||||
|
@GuardedBy("lock")
|
||||||
|
Object guardedByLock;
|
||||||
|
|
||||||
|
Object otherClassObject;
|
||||||
|
|
||||||
|
void guardedInSameClassOk() {
|
||||||
|
lock.lock();
|
||||||
|
guardedByLock = new Object();
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GuardedBy("OtherClassWithLock.lock")
|
||||||
|
Object guardedByLock1;
|
||||||
|
|
||||||
|
@GuardedBy("codetoanalyze.java.infer.GuardedByExample$OtherClassWithLock.lock")
|
||||||
|
Object guardedByLock2;
|
||||||
|
|
||||||
|
@GuardedBy("OtherClassWithLock.otherClassObject")
|
||||||
|
Object guardedByLock3;
|
||||||
|
|
||||||
|
OtherClassWithLock otherClass;
|
||||||
|
|
||||||
|
void guardedByTypeSyntaxOk1() {
|
||||||
|
otherClass.lock.lock();
|
||||||
|
guardedByLock1 = true;
|
||||||
|
guardedByLock2 = true;
|
||||||
|
otherClass.lock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void guardedByTypeSyntaxOk2() {
|
||||||
|
synchronized (otherClass.otherClassObject) {
|
||||||
|
guardedByLock3 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void guardedByTypeSyntaxBad() {
|
||||||
|
guardedByLock1 = true;
|
||||||
|
guardedByLock2 = true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class HashMapExample {
|
||||||
|
|
||||||
|
public static void putIntegerTwiceThenGetTwice(HashMap<Integer, Integer> hashMap) {
|
||||||
|
Integer i32 = new Integer(32);
|
||||||
|
Integer i52 = new Integer(52);
|
||||||
|
|
||||||
|
hashMap.put(i32, i32);
|
||||||
|
hashMap.put(i52, i52);
|
||||||
|
|
||||||
|
Integer a = hashMap.get(i32);
|
||||||
|
Integer b = hashMap.get(i52);
|
||||||
|
|
||||||
|
a.intValue();
|
||||||
|
b.intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void containsIntegerTwiceThenGetTwice(HashMap<Integer, Integer> hashMap) {
|
||||||
|
Integer i32 = new Integer(32);
|
||||||
|
Integer i52 = new Integer(52);
|
||||||
|
|
||||||
|
if (hashMap.containsKey(i32) && hashMap.containsKey(i52)) {
|
||||||
|
Integer a = hashMap.get(i32);
|
||||||
|
Integer b = hashMap.get(i52);
|
||||||
|
a.intValue();
|
||||||
|
b.intValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getOneIntegerWithoutCheck() {
|
||||||
|
HashMap<Integer, Integer> hashMap = new HashMap<>();
|
||||||
|
Integer i32 = new Integer(32);
|
||||||
|
|
||||||
|
Integer a = hashMap.get(i32);
|
||||||
|
|
||||||
|
return a.intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void getTwoIntegersWithOneCheck(Integer i, Integer j) {
|
||||||
|
HashMap<Integer, Integer> hashMap = new HashMap<>();
|
||||||
|
|
||||||
|
if (hashMap.containsKey(i) && !i.equals(j)) {
|
||||||
|
Integer a = hashMap.get(i);
|
||||||
|
Integer b = hashMap.get(j);
|
||||||
|
|
||||||
|
a.intValue();
|
||||||
|
b.intValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer getOrCreateInteger(final HashMap<Integer, Integer> map, final int id) {
|
||||||
|
Integer x = null;
|
||||||
|
if (map.containsKey(id)) {
|
||||||
|
x = map.get(id);
|
||||||
|
} else {
|
||||||
|
x = new Integer(0);
|
||||||
|
map.put(id, x);
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void getOrCreateIntegerThenDeref(final HashMap<Integer, Integer> map) {
|
||||||
|
Integer x = getOrCreateInteger(map, 42);
|
||||||
|
// dereference x
|
||||||
|
x.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void getAfterRemovingTheKeyBad() {
|
||||||
|
HashMap<Integer, Object> map = new HashMap();
|
||||||
|
Integer key = 42;
|
||||||
|
map.put(key, new Object());
|
||||||
|
map.remove(key);
|
||||||
|
map.get(key).toString(); // NPE here
|
||||||
|
}
|
||||||
|
|
||||||
|
void getAfterRemovingAnotherKeyOk() {
|
||||||
|
HashMap<Integer, Object> map = new HashMap();
|
||||||
|
Integer key = 42;
|
||||||
|
map.put(key, new Object());
|
||||||
|
map.remove(0);
|
||||||
|
map.get(key).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void getAfterClearBad() {
|
||||||
|
HashMap<Integer, Object> map = new HashMap();
|
||||||
|
Integer key = 42;
|
||||||
|
map.put(key, new Object());
|
||||||
|
map.clear();
|
||||||
|
map.get(key).toString(); // NPE here
|
||||||
|
}
|
||||||
|
|
||||||
|
void getFromKeySetGood_FP(HashMap<String, String> map) {
|
||||||
|
for (String key : map.keySet()) {
|
||||||
|
String s = map.get(key);
|
||||||
|
if (s.equals("foo")) {
|
||||||
|
System.out.println("true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
public class IntegerExample {
|
||||||
|
|
||||||
|
private static void testIntegerEqualsGood() {
|
||||||
|
Integer a = new Integer(42);
|
||||||
|
Integer b = new Integer(42);
|
||||||
|
Integer c = null;
|
||||||
|
|
||||||
|
if (!a.equals(b)) {
|
||||||
|
c.intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a != 42) {
|
||||||
|
c.intValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testIntegerEqualsBad() {
|
||||||
|
Integer a = new Integer(42);
|
||||||
|
Integer b = new Integer(42);
|
||||||
|
Integer c = null;
|
||||||
|
|
||||||
|
if (a.equals(b)) {
|
||||||
|
c.intValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testIntegerEqualsFN() {
|
||||||
|
Integer a = new Integer(42);
|
||||||
|
Integer b = new Integer(42);
|
||||||
|
Integer c = null;
|
||||||
|
|
||||||
|
if (a == b) {
|
||||||
|
c.intValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class InvokeDynamic {
|
||||||
|
|
||||||
|
void invokeDynamicThenNpeBad(List<String> list) {
|
||||||
|
Object o = null;
|
||||||
|
Collections.sort(
|
||||||
|
list,
|
||||||
|
(String a, String b) -> {
|
||||||
|
return b.compareTo(a);
|
||||||
|
});
|
||||||
|
o.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void npeInLambdaBad(List<String> list) {
|
||||||
|
Collections.sort(
|
||||||
|
list,
|
||||||
|
(String a, String b) -> {
|
||||||
|
Object o = null;
|
||||||
|
o.toString();
|
||||||
|
return b.compareTo(a);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// we still don't get this one (even with Javalib lambda rewriting)
|
||||||
|
// because Collections.sort is skipped
|
||||||
|
void FN_npeViaCaptureBad(List<String> list) {
|
||||||
|
String s = null;
|
||||||
|
Collections.sort(
|
||||||
|
list,
|
||||||
|
(String a, String b) -> {
|
||||||
|
return s.compareTo(a);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer npeViaSimpleCapture() {
|
||||||
|
String s = null;
|
||||||
|
Function<String, Integer> f = (s1) -> s.length();
|
||||||
|
return f.apply(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer npeViaSimpleParamPassing() {
|
||||||
|
Function<String, Integer> f = (s) -> s.length();
|
||||||
|
return f.apply(null);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class JunitAssertion {
|
||||||
|
class A {
|
||||||
|
public void f() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void consistentAssertion(A a) {
|
||||||
|
assertTrue(a != null);
|
||||||
|
a.f();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inconsistentAssertion(A a) {
|
||||||
|
assertFalse("Should not happen!", a != null);
|
||||||
|
a.f();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class Lists {
|
||||||
|
|
||||||
|
void emptyRemembersOk(List l) {
|
||||||
|
boolean empty = l.isEmpty();
|
||||||
|
Object o = null;
|
||||||
|
if (empty != l.isEmpty()) {
|
||||||
|
o.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeInvalidatesNonEmptinessNPE(List l, int i) {
|
||||||
|
if (!l.isEmpty()) {
|
||||||
|
l.remove(i);
|
||||||
|
Object o = null;
|
||||||
|
if (l.isEmpty()) {
|
||||||
|
o.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearCausesEmptinessNPE(List l, int i) {
|
||||||
|
if (!l.isEmpty()) {
|
||||||
|
l.clear();
|
||||||
|
Object o = null;
|
||||||
|
if (l.isEmpty()) {
|
||||||
|
o.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// it would be too noisy to report here
|
||||||
|
void plainGetOk(List l, int i) {
|
||||||
|
l.get(i).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
Object getElement(List l) {
|
||||||
|
return l.isEmpty() ? null : l.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getElementOk(List l) {
|
||||||
|
if (l.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getElement(l).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void getElementNPE(List l) {
|
||||||
|
if (!l.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getElement(l).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't fully understand why we don't get this one; model should allow it
|
||||||
|
void FN_addInvalidatesEmptinessNPE(List l) {
|
||||||
|
if (l.isEmpty()) {
|
||||||
|
l.add(0, new Object());
|
||||||
|
Object o = null;
|
||||||
|
if (!l.isEmpty()) {
|
||||||
|
o.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// _AUTOMATICALLY_GENERATED_
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class NeverNullSource {
|
||||||
|
|
||||||
|
@Nullable T t;
|
||||||
|
|
||||||
|
T get() {
|
||||||
|
return t == null ? null : t;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
// Command: infer -g --biabduction-only
|
||||||
|
class T {
|
||||||
|
static int q;
|
||||||
|
|
||||||
|
static void f() {
|
||||||
|
if (q == 0) {
|
||||||
|
q = 1;
|
||||||
|
} else if (q == 1) {
|
||||||
|
while (true) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void h() {
|
||||||
|
// Important to have 2 branches, and one of them is (q==1).
|
||||||
|
if (q == 1) {
|
||||||
|
} else if (q == 2) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void go() {
|
||||||
|
q = 0;
|
||||||
|
f();
|
||||||
|
h(); // warning disappears if the NOP function h() is called here
|
||||||
|
f(); // should warn of PRECONDITION_NOT_MET here
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,637 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import com.facebook.infer.annotation.Assertions;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.channels.FileLock;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class NullPointerExceptions {
|
||||||
|
|
||||||
|
class A {
|
||||||
|
int x;
|
||||||
|
|
||||||
|
public void method() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// npe local with field
|
||||||
|
public int nullPointerException() {
|
||||||
|
A a = null;
|
||||||
|
return a.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public A canReturnNullObject(boolean ok) {
|
||||||
|
A a = new A();
|
||||||
|
if (ok) return a;
|
||||||
|
else return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void expectNotNullObjectParameter(A a) {
|
||||||
|
a.method();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void expectNotNullArrayParameter(A[] array) {
|
||||||
|
array.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
// npe with branching, interprocedural
|
||||||
|
public int nullPointerExceptionInterProc() {
|
||||||
|
A a = canReturnNullObject(false);
|
||||||
|
return a.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// npe with exception handling
|
||||||
|
public int nullPointerExceptionWithExceptionHandling(boolean ok) {
|
||||||
|
A a = null;
|
||||||
|
try {
|
||||||
|
throw new Exception();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return a.x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {
|
||||||
|
A a;
|
||||||
|
|
||||||
|
void test() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int nullPointerExceptionWithArray() {
|
||||||
|
A[] array = new A[] {null};
|
||||||
|
A t = array[0];
|
||||||
|
return t.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// npe with a chain of fields
|
||||||
|
class C {
|
||||||
|
B b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int nullPointerExceptionWithAChainOfFields(C c) {
|
||||||
|
c.b = new B();
|
||||||
|
return c.b.a.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// npe with a null object parameter
|
||||||
|
public static void nullPointerExceptionWithNullObjectParameter() {
|
||||||
|
expectNotNullObjectParameter(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// npe with a null array parameter
|
||||||
|
public static void nullPointerExceptionWithNullArrayParameter() {
|
||||||
|
expectNotNullArrayParameter(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void nullPointerExceptionFromFaillingResourceConstructor() throws IOException {
|
||||||
|
FileInputStream fis = null;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream(new File("whatever.txt"));
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
fis.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void nullPointerExceptionFromFailingFileOutputStreamConstructor()
|
||||||
|
throws IOException {
|
||||||
|
FileOutputStream fos = null;
|
||||||
|
try {
|
||||||
|
fos = new FileOutputStream(new File("whatever.txt"));
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
fos.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int x;
|
||||||
|
|
||||||
|
public void nullPointerExceptionFromNotKnowingThatThisIsNotNull() {
|
||||||
|
if (this == null) {}
|
||||||
|
this.x = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T id_generics(T o) {
|
||||||
|
o.toString();
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
public A frame(A x) {
|
||||||
|
return id_generics(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void nullPointerExceptionUnlessFrameFails() {
|
||||||
|
String s = null;
|
||||||
|
Object a = frame(new A());
|
||||||
|
if (a instanceof A) {
|
||||||
|
s.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class D {
|
||||||
|
int x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int preconditionCheckStateTest(D d) {
|
||||||
|
Preconditions.checkState(d != null);
|
||||||
|
return d.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void genericMethodSomewhereCheckingForNull(String s) {
|
||||||
|
if (s == null) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FP_noNullPointerExceptionAfterSkipFunction() {
|
||||||
|
String t = new String("Hello!");
|
||||||
|
String s = t.toString();
|
||||||
|
genericMethodSomewhereCheckingForNull(s);
|
||||||
|
s.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
String hashmapNPE(HashMap h, Object o) {
|
||||||
|
return (h.get(o).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
String NPEhashmapProtectedByContainsKey(HashMap h, Object o) {
|
||||||
|
if (h.containsKey(o)) {
|
||||||
|
return (h.get(o).toString());
|
||||||
|
}
|
||||||
|
return "aa";
|
||||||
|
}
|
||||||
|
|
||||||
|
int NPEvalueOfFromHashmapBad(HashMap<Integer, Integer> h, int position) {
|
||||||
|
return h.get(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer NPEvalueOfFromHashmapGood(HashMap<Integer, Integer> h, int position) {
|
||||||
|
return h.get(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nullPointerExceptionInArrayLengthLoop(Object[] arr) {
|
||||||
|
for (int i = 0; i < arr.length; i++) {
|
||||||
|
Object x = null;
|
||||||
|
x.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Context mContext;
|
||||||
|
ContentResolver mContentResolver;
|
||||||
|
|
||||||
|
public void cursorFromContentResolverNPE(String customClause) {
|
||||||
|
String[] projection = {"COUNT(*)"};
|
||||||
|
String selectionClause = selectionClause = customClause;
|
||||||
|
Cursor cursor =
|
||||||
|
mContext.getContentResolver().query(null, projection, selectionClause, null, null);
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int cursorQueryShouldNotReturnNull(SQLiteDatabase sqLiteDatabase) {
|
||||||
|
Cursor cursor = sqLiteDatabase.query("events", null, null, null, null, null, null);
|
||||||
|
try {
|
||||||
|
return cursor.getCount();
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object[] arr = new Object[1];
|
||||||
|
|
||||||
|
Object arrayReadShouldNotCauseSymexMemoryError(int i) {
|
||||||
|
arr[i].toString();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nullPointerExceptionCallArrayReadMethod() {
|
||||||
|
arr[0] = new Object();
|
||||||
|
arrayReadShouldNotCauseSymexMemoryError(0).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sinkWithNeverNullSource() {
|
||||||
|
NeverNullSource source = new NeverNullSource();
|
||||||
|
T t = source.get();
|
||||||
|
t.f();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void otherSinkWithNeverNullSource() {
|
||||||
|
SomeLibrary source = new SomeLibrary();
|
||||||
|
T t = source.get();
|
||||||
|
t.f();
|
||||||
|
}
|
||||||
|
|
||||||
|
private @Nullable Object mFld;
|
||||||
|
|
||||||
|
void nullableFieldNPE() {
|
||||||
|
mFld.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void guardedNullableFieldDeref() {
|
||||||
|
if (mFld != null) mFld.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void allocNullableFieldDeref() {
|
||||||
|
mFld = new Object();
|
||||||
|
mFld.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void nullableParamNPE(@Nullable Object param) {
|
||||||
|
param.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void guardedNullableParamDeref(@Nullable Object param) {
|
||||||
|
if (param != null) param.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void allocNullableParamDeref(@Nullable Object param) {
|
||||||
|
param = new Object();
|
||||||
|
param.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
native boolean test();
|
||||||
|
|
||||||
|
Object getObj() {
|
||||||
|
if (test()) {
|
||||||
|
return new Object();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Boolean getBool() {
|
||||||
|
if (test()) {
|
||||||
|
return new Boolean(true);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void derefGetterAfterCheckShouldNotCauseNPE() {
|
||||||
|
if (getObj() != null) {
|
||||||
|
getObj().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void derefBoxedGetterAfterCheckShouldNotCauseNPE() {
|
||||||
|
boolean b = getBool() != null && getBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void derefNonThisGetterAfterCheckShouldNotCauseNPE() {
|
||||||
|
NullPointerExceptions c = new NullPointerExceptions();
|
||||||
|
if (c.getObj() != null) {
|
||||||
|
c.getObj().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void badCheckShouldCauseNPE() {
|
||||||
|
if (getBool() != null) getObj().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void nullPointerExceptionArrayLength() {
|
||||||
|
Object[] arr = null;
|
||||||
|
int i = arr.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
class $$Class$Name$With$Dollars {
|
||||||
|
void npeWithDollars() {
|
||||||
|
String s = null;
|
||||||
|
int n = s.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nullableNonNullStringAfterTextUtilsIsEmptyCheckShouldNotCauseNPE(@Nullable String str) {
|
||||||
|
if (!TextUtils.isEmpty(str)) {
|
||||||
|
str.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void someNPEAfterResourceLeak() {
|
||||||
|
T t = CloseableAsResourceExample.sourceOfNullWithResourceLeak();
|
||||||
|
t.f();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object mOkObj = new Object();
|
||||||
|
|
||||||
|
public void nullableParamReassign1(@Nullable Object o) {
|
||||||
|
if (o == null) {
|
||||||
|
o = mOkObj;
|
||||||
|
}
|
||||||
|
o.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void nullableParamReassign2(@Nullable Object o, Object okObj) {
|
||||||
|
if (o == null) {
|
||||||
|
o = okObj;
|
||||||
|
}
|
||||||
|
o.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private @Nullable Object mNullableField;
|
||||||
|
|
||||||
|
public void nullableFieldReassign1() {
|
||||||
|
if (mNullableField == null) {
|
||||||
|
mNullableField = mOkObj;
|
||||||
|
}
|
||||||
|
mNullableField.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void nullableFieldReassign2(Object okObj) {
|
||||||
|
if (mNullableField == null) {
|
||||||
|
mNullableField = okObj;
|
||||||
|
}
|
||||||
|
mNullableField.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void nullableFieldReassign3(Object param) {
|
||||||
|
mNullableField = param;
|
||||||
|
mNullableField.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object nullableGetter() {
|
||||||
|
return mNullableField;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void derefNullableGetter() {
|
||||||
|
Object o = nullableGetter();
|
||||||
|
o.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Object nullableRet(boolean b) {
|
||||||
|
if (b) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new Object();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void derefNullableRet(boolean b) {
|
||||||
|
Object ret = nullableRet(b);
|
||||||
|
ret.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void derefNullableRetOK(boolean b) {
|
||||||
|
Object ret = nullableRet(b);
|
||||||
|
if (ret != null) {
|
||||||
|
ret.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public native @Nullable Object undefNullableRet();
|
||||||
|
|
||||||
|
public void derefUndefNullableRet() {
|
||||||
|
Object ret = undefNullableRet();
|
||||||
|
ret.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void derefUndefNullableRetOK() {
|
||||||
|
Object ret = undefNullableRet();
|
||||||
|
if (ret != null) {
|
||||||
|
ret.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void assumeUndefNullableIdempotentOk() {
|
||||||
|
if (undefNullableRet() != null) {
|
||||||
|
undefNullableRet().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object undefNullableWrapper() {
|
||||||
|
return undefNullableRet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void derefUndefNullableRetWrapper() {
|
||||||
|
undefNullableWrapper().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int returnsThreeOnlyIfRetNotNull(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNullablePrecision() {
|
||||||
|
Object ret = undefNullableRet();
|
||||||
|
if (returnsThreeOnlyIfRetNotNull(ret) == 3) {
|
||||||
|
ret.toString(); // shouldn't warn here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable String testSystemGetPropertyArgument() {
|
||||||
|
String s = System.getProperty(null);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSystemGetPropertyReturn() {
|
||||||
|
String s = System.getProperty("");
|
||||||
|
int n = s.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
Object retUndefined() {
|
||||||
|
return "".toString(); // toString is a skip function
|
||||||
|
}
|
||||||
|
|
||||||
|
Object derefUndefinedCallee() {
|
||||||
|
// if retUndefined() is handled incorrectly, we get a symexec_memory_error here
|
||||||
|
retUndefined().toString();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void derefNull() {
|
||||||
|
// should be NPE, but will not be reported if we handled retUndefined() incorrectly
|
||||||
|
derefUndefinedCallee().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NULL_DEREFERENCE")
|
||||||
|
void shouldNotReportNPE() {
|
||||||
|
Object o = null;
|
||||||
|
o.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void shouldNotReportOnSkippedSource() {
|
||||||
|
Object o = SkippedSourceFile.createdBySkippedFile();
|
||||||
|
o.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
int nullListFiles(String pathname) {
|
||||||
|
File dir = new File(pathname);
|
||||||
|
File[] files = dir.listFiles();
|
||||||
|
return files.length; // expect possible NullPointerException as files == null is possible
|
||||||
|
}
|
||||||
|
|
||||||
|
native Object unknownFunc();
|
||||||
|
|
||||||
|
void nullDerefernceReturnOfSkippedFunctionBad() {
|
||||||
|
Object object = unknownFunc();
|
||||||
|
if (object == null) {
|
||||||
|
object.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
native @Nonnull Object doesNotReturnNull();
|
||||||
|
|
||||||
|
void noNPEWhenCallingSkippedNonnullAnnotatedMethodGood() {
|
||||||
|
Object object = doesNotReturnNull();
|
||||||
|
if (object == null) {
|
||||||
|
object.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object callUnknownFunc() {
|
||||||
|
return unknownFunc();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dontReportOnNullableDirectReassignmentToUnknown(@Nullable Object o) {
|
||||||
|
o = unknownFunc();
|
||||||
|
o.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dontReportOnNullableIndirectReassignmentToUnknown(@Nullable Object o) {
|
||||||
|
o = callUnknownFunc();
|
||||||
|
o.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
Object wrapUnknownFuncWithNullable() {
|
||||||
|
return unknownFunc();
|
||||||
|
}
|
||||||
|
|
||||||
|
void deferenceNullableMethodCallingSkippedMethodBad() {
|
||||||
|
wrapUnknownFuncWithNullable().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
String nullTryLock(FileChannel chan) throws IOException {
|
||||||
|
FileLock lock = chan.tryLock();
|
||||||
|
return lock.toString(); // expect possible NullPointerException as lock == null is possible
|
||||||
|
}
|
||||||
|
|
||||||
|
String tryLockThrows(FileChannel chan) {
|
||||||
|
try {
|
||||||
|
FileLock lock = chan.tryLock();
|
||||||
|
return (lock != null ? lock.toString() : "");
|
||||||
|
} catch (IOException e) {
|
||||||
|
Object o = null;
|
||||||
|
return o.toString(); // expect NullPointerException as tryLock can throw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class L {
|
||||||
|
L next;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object returnsNullAfterLoopOnList(L l) {
|
||||||
|
while (l != null) {
|
||||||
|
l = l.next;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dereferenceAfterLoopOnList(L l) {
|
||||||
|
Object obj = returnsNullAfterLoopOnList(l);
|
||||||
|
obj.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dereferenceAfterUnlock1(Lock l) {
|
||||||
|
l.unlock();
|
||||||
|
String s = l.toString();
|
||||||
|
s = null;
|
||||||
|
s.toString(); // Expect NPE here
|
||||||
|
}
|
||||||
|
|
||||||
|
void dereferenceAfterUnlock2(Lock l) {
|
||||||
|
synchronized (l) {
|
||||||
|
String b = null;
|
||||||
|
}
|
||||||
|
String s = l.toString();
|
||||||
|
s = null;
|
||||||
|
s.toString(); // Expect NPE here
|
||||||
|
}
|
||||||
|
|
||||||
|
void optionalNPE(Optional<Object> o) {
|
||||||
|
o.orNull().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void stringConstantEqualsTrueNotNPE() {
|
||||||
|
final String c1 = "Test string!";
|
||||||
|
final String c2 = "Test string!";
|
||||||
|
String s = null;
|
||||||
|
if (c1.equals(c1)) {
|
||||||
|
s = "safe";
|
||||||
|
}
|
||||||
|
s.toString(); // No NPE
|
||||||
|
s = null;
|
||||||
|
if (c1.equals(c2)) {
|
||||||
|
s = "safe";
|
||||||
|
}
|
||||||
|
s.toString(); // No NPE
|
||||||
|
}
|
||||||
|
|
||||||
|
void stringConstantEqualsFalseNotNPE_FP() {
|
||||||
|
// This won't actually cause an NPE, but our current model for String.equals
|
||||||
|
// returns boolean_undefined for all cases other than String constant
|
||||||
|
// equality. Consider handling constant inequality in the future.
|
||||||
|
final String c1 = "Test string 1";
|
||||||
|
final String c2 = "Test string 2";
|
||||||
|
String s = null;
|
||||||
|
if (!c1.equals(c2)) {
|
||||||
|
s = "safe";
|
||||||
|
}
|
||||||
|
s.toString(); // No NPE
|
||||||
|
}
|
||||||
|
|
||||||
|
String getString2() {
|
||||||
|
return "string 2";
|
||||||
|
}
|
||||||
|
|
||||||
|
void stringVarEqualsFalseNPE() {
|
||||||
|
final String c1 = "Test string 1";
|
||||||
|
String c2 = "Test " + getString2();
|
||||||
|
String s = null;
|
||||||
|
if (!c1.equals(c2)) {
|
||||||
|
s.toString(); // NPE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String assertParameterNotNullableOk(@Nullable Object object) {
|
||||||
|
return Assertions.assertNotNull(object).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface I {
|
||||||
|
@Nullable Object mObject = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
class E implements I {
|
||||||
|
|
||||||
|
void dereferenceNullableInterfaceFieldBad() {
|
||||||
|
mObject.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object getObject() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addNullToImmutableListBuilderBad() {
|
||||||
|
ImmutableList.Builder<Object> listBuilder = ImmutableList.builder();
|
||||||
|
listBuilder.add(getObject());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,206 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.PipedReader;
|
||||||
|
import java.io.PipedWriter;
|
||||||
|
import java.io.PushbackReader;
|
||||||
|
import java.io.Reader;
|
||||||
|
|
||||||
|
public class ReaderLeaks {
|
||||||
|
|
||||||
|
private void ignore(Object o) {}
|
||||||
|
|
||||||
|
// Reader tests
|
||||||
|
|
||||||
|
public void readerNotClosedAfterRead() {
|
||||||
|
Reader r;
|
||||||
|
try {
|
||||||
|
r = new FileReader("testing.txt");
|
||||||
|
r.read();
|
||||||
|
r.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* This test seems to be flaky in the CI at the moment.
|
||||||
|
We guess it's because of timeouts in the analysis.
|
||||||
|
public void readerClosedOk() throws IOException {
|
||||||
|
Reader r = null;
|
||||||
|
try {
|
||||||
|
r = new FileReader("testing.txt");
|
||||||
|
boolean ready = r.ready();
|
||||||
|
r.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (r != null) r.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// BufferedReader tests
|
||||||
|
|
||||||
|
public void bufferedReaderNotClosedAfterRead() {
|
||||||
|
BufferedReader reader;
|
||||||
|
try {
|
||||||
|
reader = new BufferedReader(new FileReader("testing.txt"));
|
||||||
|
ignore(reader.read());
|
||||||
|
reader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bufferedReaderClosed() throws IOException {
|
||||||
|
BufferedReader reader = null;
|
||||||
|
try {
|
||||||
|
reader = new BufferedReader(new FileReader("testing.txt"));
|
||||||
|
ignore(reader.read());
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (reader != null) reader.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void noNeedToCloseBufferReaderWrapperOk(File file) throws IOException {
|
||||||
|
try (InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(file))) {
|
||||||
|
BufferedReader reader = new BufferedReader(inputStreamReader);
|
||||||
|
ignore(reader.readLine());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// InputStreamReader tests
|
||||||
|
|
||||||
|
public void inputStreamReaderNotClosedAfterRead() {
|
||||||
|
InputStreamReader reader;
|
||||||
|
try {
|
||||||
|
reader = new InputStreamReader(new FileInputStream("testing.txt"));
|
||||||
|
reader.read();
|
||||||
|
reader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inputStreamReaderClosed() throws IOException {
|
||||||
|
InputStreamReader reader = null;
|
||||||
|
try {
|
||||||
|
reader = new InputStreamReader(new FileInputStream("testing.txt"));
|
||||||
|
ignore(reader.read());
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (reader != null) reader.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileReader tests
|
||||||
|
|
||||||
|
public void fileReaderNotClosedAfterRead() {
|
||||||
|
FileReader reader;
|
||||||
|
try {
|
||||||
|
reader = new FileReader("testing.txt");
|
||||||
|
reader.read();
|
||||||
|
reader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fileReaderClosed() throws IOException {
|
||||||
|
FileReader reader = null;
|
||||||
|
try {
|
||||||
|
reader = new FileReader("testing.txt");
|
||||||
|
reader.read();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (reader != null) reader.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushbackReader tests
|
||||||
|
|
||||||
|
public void pushbackReaderNotClosedAfterRead() {
|
||||||
|
PushbackReader reader;
|
||||||
|
try {
|
||||||
|
reader = new PushbackReader(new InputStreamReader(new FileInputStream("testing.txt")));
|
||||||
|
reader.read();
|
||||||
|
reader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pushbackReaderClosed() throws IOException {
|
||||||
|
PushbackReader reader = null;
|
||||||
|
try {
|
||||||
|
reader = new PushbackReader(new InputStreamReader(new FileInputStream("testing.txt")));
|
||||||
|
reader.read();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (reader != null) reader.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PipedReader tests
|
||||||
|
|
||||||
|
public void pipedReaderNotClosedAfterConstructedWithWriter() {
|
||||||
|
PipedReader reader;
|
||||||
|
PipedWriter writer;
|
||||||
|
try {
|
||||||
|
writer = new PipedWriter();
|
||||||
|
reader = new PipedReader(writer);
|
||||||
|
reader.read();
|
||||||
|
reader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pipedReaderNotClosedAfterConnect(PipedWriter writer) {
|
||||||
|
PipedReader reader;
|
||||||
|
try {
|
||||||
|
reader = new PipedReader();
|
||||||
|
reader.connect(writer);
|
||||||
|
reader.read();
|
||||||
|
reader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pipedReaderNotConnected() {
|
||||||
|
PipedReader reader;
|
||||||
|
try {
|
||||||
|
reader = new PipedReader();
|
||||||
|
reader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pipedReaderClosed(PipedWriter writer) throws IOException {
|
||||||
|
PipedReader reader = null;
|
||||||
|
try {
|
||||||
|
reader = new PipedReader();
|
||||||
|
reader.connect(writer);
|
||||||
|
reader.read();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (reader != null) reader.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pipedReaderFalsePositive() throws IOException {
|
||||||
|
PipedReader reader;
|
||||||
|
PipedWriter writer = null;
|
||||||
|
try {
|
||||||
|
reader = new PipedReader(writer);
|
||||||
|
reader.read();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (writer != null) writer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,950 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
|
import com.fasterxml.jackson.core.JsonFactory;
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.core.json.UTF8StreamJsonParser;
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.common.io.Closeables;
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PipedInputStream;
|
||||||
|
import java.io.PipedOutputStream;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.util.Scanner;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
import java.util.jar.JarInputStream;
|
||||||
|
import java.util.jar.JarOutputStream;
|
||||||
|
import java.util.zip.Deflater;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
import java.util.zip.Inflater;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
|
||||||
|
public class ResourceLeaks {
|
||||||
|
|
||||||
|
// FileOutputStream tests
|
||||||
|
|
||||||
|
public void fileOutputStreamNotClosed() throws IOException {
|
||||||
|
FileOutputStream fis = new FileOutputStream("file.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fileOutputStreamNotClosedAfterWrite() {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis = null;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
fis.write(arr);
|
||||||
|
fis.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fileOutputStreamClosed() throws IOException {
|
||||||
|
FileOutputStream fis = new FileOutputStream("file.txt");
|
||||||
|
fis.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fileOutputStreamOneLeak() throws IOException {
|
||||||
|
FileOutputStream fis = new FileOutputStream("file.txt");
|
||||||
|
if (fis != null) {
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int fileOutputStreamTwoLeaks1(boolean ok) throws IOException {
|
||||||
|
FileOutputStream fis = new FileOutputStream("file.txt");
|
||||||
|
if (ok) {
|
||||||
|
fis.write(1);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
fis.write(2);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fileOutputStreamTwoLeaks2() throws IOException {
|
||||||
|
FileOutputStream fis = new FileOutputStream("file.txt");
|
||||||
|
if (fis != null) {
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
fis = new FileOutputStream("x");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TwoResources tests
|
||||||
|
|
||||||
|
public static void twoResources() throws IOException {
|
||||||
|
FileInputStream fis = null;
|
||||||
|
FileOutputStream fos = null;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream(new File("infile.txt"));
|
||||||
|
fos = new FileOutputStream(new File("outfile.txt"));
|
||||||
|
fos.write(fis.read());
|
||||||
|
} finally {
|
||||||
|
if (fis != null) fis.close();
|
||||||
|
if (fos != null) fos.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void twoResourcesHeliosFix() throws IOException {
|
||||||
|
FileInputStream fis = null;
|
||||||
|
FileOutputStream fos = null;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream(new File("whatever.txt"));
|
||||||
|
try {
|
||||||
|
fos = new FileOutputStream(new File("everwhat.txt"));
|
||||||
|
fos.write(fis.read());
|
||||||
|
} finally {
|
||||||
|
if (fos != null) fos.close();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (fis != null) fis.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void twoResourcesCommonFix() throws IOException {
|
||||||
|
FileInputStream fis = null;
|
||||||
|
FileOutputStream fos = null;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream(new File("infile.txt"));
|
||||||
|
fos = new FileOutputStream(new File("outfile.txt"));
|
||||||
|
fos.write(fis.read());
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (fis != null) fis.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (fos != null) fos.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void twoResourcesServerSocket() throws IOException {
|
||||||
|
ServerSocket a = null;
|
||||||
|
ServerSocket b = null;
|
||||||
|
try {
|
||||||
|
a = new ServerSocket();
|
||||||
|
b = new ServerSocket();
|
||||||
|
} finally {
|
||||||
|
if (a != null) a.close();
|
||||||
|
if (b != null) b.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void twoResourcesRandomAccessFile() throws IOException {
|
||||||
|
RandomAccessFile a = null;
|
||||||
|
RandomAccessFile b = null;
|
||||||
|
try {
|
||||||
|
a = new RandomAccessFile("", "rw");
|
||||||
|
b = new RandomAccessFile("", "rw");
|
||||||
|
} finally {
|
||||||
|
if (a != null) a.close();
|
||||||
|
if (b != null) b.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void twoResourcesRandomAccessFileCommonFix() throws IOException {
|
||||||
|
RandomAccessFile a = null;
|
||||||
|
RandomAccessFile b = null;
|
||||||
|
try {
|
||||||
|
a = new RandomAccessFile("", "rw");
|
||||||
|
b = new RandomAccessFile("", "rw");
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (a != null) a.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (b != null) b.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NestedResource tests
|
||||||
|
|
||||||
|
// BufferedInputStream does not throw exception, and its close
|
||||||
|
// closes the FileInputStream as well
|
||||||
|
public void nestedGood() throws IOException {
|
||||||
|
BufferedInputStream b = new BufferedInputStream(new FileInputStream("file.txt"));
|
||||||
|
b.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// GZipInputStream can throw IO Exception
|
||||||
|
// in which case the new FileInputStream will be dangling
|
||||||
|
public void nestedBad1() throws IOException {
|
||||||
|
GZIPInputStream g = new GZIPInputStream(new FileInputStream("file.txt"));
|
||||||
|
g.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void nestedBad2() throws IOException {
|
||||||
|
GZIPOutputStream g = new GZIPOutputStream(new FileOutputStream("file.txt"));
|
||||||
|
g.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fixed versions of this are below with ObjectInputStream tests */
|
||||||
|
public void objectInputStreamClosedNestedBad() throws IOException {
|
||||||
|
ObjectInputStream oin = null;
|
||||||
|
try {
|
||||||
|
oin = new ObjectInputStream(new FileInputStream("file.txt"));
|
||||||
|
int a = oin.available();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (oin != null) oin.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fixed versions of this are below with ObjectInputStream tests */
|
||||||
|
public void objectOutputStreamClosedNestedBad() throws IOException {
|
||||||
|
ObjectOutputStream oin = null;
|
||||||
|
try {
|
||||||
|
oin = new ObjectOutputStream(new FileOutputStream("file.txt"));
|
||||||
|
oin.write(3);
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (oin != null) oin.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZipFile tests (Jarfile Tests also test Zipfiles)
|
||||||
|
|
||||||
|
public static void zipFileLeakExceptionalBranch() throws IOException {
|
||||||
|
ZipFile j = null;
|
||||||
|
try {
|
||||||
|
j = new ZipFile("");
|
||||||
|
} catch (IOException e) {
|
||||||
|
FileOutputStream fis = new FileOutputStream("file.txt");
|
||||||
|
// The purpose of this is to cause a leak, from when ZipFile constructor throws
|
||||||
|
} finally {
|
||||||
|
if (j != null) j.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void zipFileNoLeak() throws IOException {
|
||||||
|
ZipFile j = null;
|
||||||
|
try {
|
||||||
|
j = new ZipFile("");
|
||||||
|
} finally {
|
||||||
|
if (j != null) j.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// JarFile tests
|
||||||
|
|
||||||
|
public boolean jarFileClosed() {
|
||||||
|
JarFile jarFile = null;
|
||||||
|
try {
|
||||||
|
jarFile = new JarFile("");
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (jarFile != null) {
|
||||||
|
jarFile.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean jarFileNotClosed() {
|
||||||
|
JarFile jarFile = null;
|
||||||
|
try {
|
||||||
|
jarFile = new JarFile("");
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileInputStream tests
|
||||||
|
|
||||||
|
public void fileInputStreamNotClosedAfterRead() {
|
||||||
|
FileInputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
fis.read();
|
||||||
|
fis.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fileInputStreamClosed() throws IOException {
|
||||||
|
FileInputStream fis = null;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream("file.txt");
|
||||||
|
fis.available();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (fis != null) fis.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PipedInputStream tests
|
||||||
|
|
||||||
|
public void pipedInputStreamNotClosedAfterRead(PipedOutputStream pout) {
|
||||||
|
PipedInputStream pin;
|
||||||
|
try {
|
||||||
|
pin = new PipedInputStream(pout);
|
||||||
|
int data = pin.read();
|
||||||
|
pin.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pipedInputStreamClosed(PipedOutputStream pout) throws IOException {
|
||||||
|
PipedInputStream pin = null;
|
||||||
|
try {
|
||||||
|
pin = new PipedInputStream(pout);
|
||||||
|
int data = pin.read();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
pin.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PipedOutputStream tests
|
||||||
|
|
||||||
|
public void pipedOutputStreamNotClosedAfterWrite() {
|
||||||
|
byte[] arr = {1, 2, 3, 4, 5};
|
||||||
|
PipedOutputStream pout;
|
||||||
|
try {
|
||||||
|
pout = new PipedOutputStream();
|
||||||
|
pout.write(arr);
|
||||||
|
pout.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pipedOutputStreamClosed(PipedInputStream pin) throws IOException {
|
||||||
|
PipedOutputStream pout = null;
|
||||||
|
try {
|
||||||
|
pout = new PipedOutputStream(pin);
|
||||||
|
pout.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
pout.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ObjectOutputStream tests
|
||||||
|
|
||||||
|
public void objectOutputStreamNotClosedAfterWrite() {
|
||||||
|
byte[] arr = {1, 2, 3, 4, 5};
|
||||||
|
ObjectOutputStream oout;
|
||||||
|
try {
|
||||||
|
oout = new ObjectOutputStream(new FileOutputStream("file.txt"));
|
||||||
|
oout.write(arr);
|
||||||
|
oout.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void objectOutputStreamClosed() throws IOException {
|
||||||
|
ObjectOutputStream oout = null;
|
||||||
|
FileOutputStream fis = new FileOutputStream("file.txt");
|
||||||
|
try {
|
||||||
|
oout = new ObjectOutputStream(fis);
|
||||||
|
oout.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
fis.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ObjectInputStream tests
|
||||||
|
|
||||||
|
public void objectInputStreamNotClosedAfterRead() {
|
||||||
|
ObjectInputStream oin;
|
||||||
|
try {
|
||||||
|
oin = new ObjectInputStream(new FileInputStream("file.txt"));
|
||||||
|
oin.read();
|
||||||
|
oin.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void objectInputStreamClosed() throws IOException {
|
||||||
|
ObjectInputStream oin = null;
|
||||||
|
FileInputStream fis = new FileInputStream("file.txt");
|
||||||
|
try {
|
||||||
|
oin = new ObjectInputStream(fis);
|
||||||
|
int a = oin.available();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (oin != null) {
|
||||||
|
oin.close();
|
||||||
|
} else {
|
||||||
|
fis.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void objectInputStreamClosed2() throws IOException {
|
||||||
|
ObjectInputStream oin = null;
|
||||||
|
FileInputStream fis = new FileInputStream("file.txt");
|
||||||
|
try {
|
||||||
|
oin = new ObjectInputStream(fis);
|
||||||
|
int a = oin.available();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
fis.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// JarInputStream tests
|
||||||
|
|
||||||
|
public static void jarInputStreamNoLeak() throws IOException {
|
||||||
|
FileInputStream fos = new FileInputStream("");
|
||||||
|
try {
|
||||||
|
JarInputStream g = new JarInputStream(fos);
|
||||||
|
g.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
fos.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void jarInputStreamLeak() throws IOException {
|
||||||
|
FileInputStream fos = new FileInputStream("");
|
||||||
|
try {
|
||||||
|
JarInputStream g = new JarInputStream(fos); // Testing exceptional condition in constructor
|
||||||
|
g.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// fos.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void nestedBadJarInputStream(File file) throws IOException {
|
||||||
|
JarInputStream g = new JarInputStream(new FileInputStream(file));
|
||||||
|
g.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// JarOutputStream tests
|
||||||
|
|
||||||
|
public static void jarOutputStreamNoLeak() throws IOException {
|
||||||
|
FileOutputStream fos = new FileOutputStream("");
|
||||||
|
try {
|
||||||
|
JarOutputStream g = new JarOutputStream(fos);
|
||||||
|
g.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
fos.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void jarOutputStreamLeak() throws IOException {
|
||||||
|
FileOutputStream fos = new FileOutputStream("");
|
||||||
|
try {
|
||||||
|
JarOutputStream g = new JarOutputStream(fos); // Testing exceptional condition in constructor
|
||||||
|
g.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// fos.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void nestedBadJarOutputStream() throws IOException {
|
||||||
|
JarOutputStream g = new JarOutputStream(new FileOutputStream("file.txt"));
|
||||||
|
g.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Socket tests
|
||||||
|
|
||||||
|
public void socketNotClosed() {
|
||||||
|
Socket socket = new Socket();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void socketClosed() throws IOException {
|
||||||
|
Socket socket = new Socket();
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Socket InputStream tests
|
||||||
|
|
||||||
|
public int socketInputStreamNotClosed(Socket socket) throws IOException {
|
||||||
|
InputStream stream = socket.getInputStream();
|
||||||
|
return stream.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void socketInputStreamClosed() throws IOException {
|
||||||
|
Socket socket = new Socket();
|
||||||
|
InputStream stream = socket.getInputStream();
|
||||||
|
try {
|
||||||
|
stream.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Socket OutputStream tests
|
||||||
|
|
||||||
|
public void socketOutputStreamNotClosed(Socket socket) throws IOException {
|
||||||
|
OutputStream stream = socket.getOutputStream();
|
||||||
|
stream.write(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void socketOutputStreamClosed() throws IOException {
|
||||||
|
Socket socket = new Socket();
|
||||||
|
OutputStream stream = socket.getOutputStream();
|
||||||
|
try {
|
||||||
|
stream.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerSocket tests
|
||||||
|
|
||||||
|
public void serverSocketNotClosed() throws IOException {
|
||||||
|
ServerSocket listener = new ServerSocket(9090);
|
||||||
|
while (true) {
|
||||||
|
Socket socket = listener.accept();
|
||||||
|
try {
|
||||||
|
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
|
||||||
|
out.println("");
|
||||||
|
} finally {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
listener.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serverSocketClosed() throws IOException {
|
||||||
|
ServerSocket socket = new ServerSocket();
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serverSocketWithSocketClosed() throws IOException {
|
||||||
|
ServerSocket listener = new ServerSocket(9090);
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
Socket socket = listener.accept();
|
||||||
|
try {
|
||||||
|
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
|
||||||
|
out.println("");
|
||||||
|
} finally {
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
listener.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HttpURLConnection
|
||||||
|
|
||||||
|
public void openHttpURLConnectionDisconnected() throws IOException {
|
||||||
|
String content = "TEXT";
|
||||||
|
DataOutputStream outputStream = null;
|
||||||
|
HttpURLConnection connection = null;
|
||||||
|
URL address = new URL("http://www.facebook.com");
|
||||||
|
connection = (HttpURLConnection) address.openConnection();
|
||||||
|
try {
|
||||||
|
outputStream = new DataOutputStream(connection.getOutputStream());
|
||||||
|
outputStream.writeBytes(content);
|
||||||
|
outputStream.flush();
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void openHttpURLConnectionNotDisconnected() throws IOException {
|
||||||
|
String content = "TEXT";
|
||||||
|
DataOutputStream outputStream = null;
|
||||||
|
HttpURLConnection connection = null;
|
||||||
|
URL address = new URL("http://www.facebook.com");
|
||||||
|
connection = (HttpURLConnection) address.openConnection();
|
||||||
|
|
||||||
|
outputStream = new DataOutputStream(connection.getOutputStream());
|
||||||
|
outputStream.writeBytes(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void openHttpsURLConnectionNotDisconnected() throws IOException {
|
||||||
|
HttpsURLConnection connection = null;
|
||||||
|
URL address = new URL("https://www.facebook.com");
|
||||||
|
connection = (HttpsURLConnection) address.openConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void openHttpsURLConnectionDisconnected() throws IOException {
|
||||||
|
HttpsURLConnection connection = null;
|
||||||
|
URL address = new URL("https://www.facebook.com");
|
||||||
|
connection = (HttpsURLConnection) address.openConnection();
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closedWithCloseables() throws IOException {
|
||||||
|
FileInputStream fs = new FileInputStream("file.txt");
|
||||||
|
try {
|
||||||
|
fs.read();
|
||||||
|
} finally {
|
||||||
|
Closeables.close(fs, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closedQuietlyWithCloseables() throws IOException {
|
||||||
|
FileInputStream fs = new FileInputStream("file.txt");
|
||||||
|
try {
|
||||||
|
fs.read();
|
||||||
|
} finally {
|
||||||
|
Closeables.closeQuietly(fs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeNullWithCloseables() throws IOException {
|
||||||
|
FileInputStream fs = null;
|
||||||
|
try {
|
||||||
|
fs = new FileInputStream("file.txt");
|
||||||
|
} finally {
|
||||||
|
Closeables.close(fs, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeNullQuietlyWithCloseables() throws IOException {
|
||||||
|
FileInputStream fs = null;
|
||||||
|
try {
|
||||||
|
fs = new FileInputStream("file.txt");
|
||||||
|
} finally {
|
||||||
|
Closeables.closeQuietly(fs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void myClose(Closeable closeable, boolean swallowIOException) throws IOException {
|
||||||
|
if (closeable == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
closeable.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (!swallowIOException) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeWithCloseablesNestedAlloc() throws IOException {
|
||||||
|
BufferedInputStream b = null;
|
||||||
|
try {
|
||||||
|
b = new BufferedInputStream(new FileInputStream("file.txt"));
|
||||||
|
} finally {
|
||||||
|
myClose(b, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// JsonParser tests
|
||||||
|
|
||||||
|
public void parseFromStringAndNotClose(JsonFactory factory) throws IOException {
|
||||||
|
UTF8StreamJsonParser parser = null;
|
||||||
|
try {
|
||||||
|
parser = (UTF8StreamJsonParser) factory.createParser(new File("[]"));
|
||||||
|
Object o = parser.readValueAs(Object.class);
|
||||||
|
ignore(o);
|
||||||
|
} catch (Exception e) {
|
||||||
|
} finally {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void parseFromInputStreamAndClose(JsonFactory factory) throws IOException {
|
||||||
|
JsonParser parser = null;
|
||||||
|
FileInputStream in = null;
|
||||||
|
try {
|
||||||
|
in = new FileInputStream("");
|
||||||
|
parser = factory.createParser(in);
|
||||||
|
Object o = parser.readValueAs(Object.class);
|
||||||
|
ignore(o);
|
||||||
|
} catch (Exception e) {
|
||||||
|
} finally {
|
||||||
|
if (in != null) in.close();
|
||||||
|
}
|
||||||
|
// parser does not own a resources which is closed externally
|
||||||
|
}
|
||||||
|
|
||||||
|
public void parseFromInputStreamAndLeak(JsonFactory factory) throws IOException {
|
||||||
|
JsonParser parser = null;
|
||||||
|
FileInputStream in = null;
|
||||||
|
try {
|
||||||
|
in = new FileInputStream("");
|
||||||
|
parser = factory.createParser(in);
|
||||||
|
Object o = parser.readValueAs(Object.class);
|
||||||
|
ignore(o);
|
||||||
|
} catch (Exception e) {
|
||||||
|
} finally {
|
||||||
|
if (parser != null) parser.close();
|
||||||
|
}
|
||||||
|
// parser does not own a resource which is leaked
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ignore(Object o) {}
|
||||||
|
|
||||||
|
// Installation.java examples. Even the fix was a fp for a while
|
||||||
|
// for several reasons, so this test is just to make sure it remains
|
||||||
|
// banished forever
|
||||||
|
|
||||||
|
private String readInstallationFileGood(File installation) throws IOException {
|
||||||
|
RandomAccessFile f = new RandomAccessFile(installation, "r");
|
||||||
|
try {
|
||||||
|
byte[] bytes = new byte[(int) f.length()];
|
||||||
|
f.readFully(bytes);
|
||||||
|
return new String(bytes);
|
||||||
|
} finally {
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readInstallationFileBad(File installation) throws IOException {
|
||||||
|
RandomAccessFile f = new RandomAccessFile(installation, "r");
|
||||||
|
byte[] bytes = new byte[(int) f.length()];
|
||||||
|
f.readFully(bytes);
|
||||||
|
f.close();
|
||||||
|
return new String(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int readConfigCloseStream(String mTurnConfigUrl) {
|
||||||
|
try {
|
||||||
|
URL url = new URL(mTurnConfigUrl);
|
||||||
|
URLConnection connection = url.openConnection();
|
||||||
|
InputStream stream = connection.getInputStream();
|
||||||
|
try {
|
||||||
|
return stream.read();
|
||||||
|
} finally {
|
||||||
|
stream.close();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int readConfigNotCloseStream(String mTurnConfigUrl) {
|
||||||
|
try {
|
||||||
|
URL url = new URL(mTurnConfigUrl);
|
||||||
|
URLConnection connection = url.openConnection();
|
||||||
|
InputStream stream = connection.getInputStream();
|
||||||
|
return stream.read();
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readConfigNotClosedOK(String mTurnConfigUrl) {
|
||||||
|
try {
|
||||||
|
URL url = new URL(mTurnConfigUrl);
|
||||||
|
URLConnection connection = url.openConnection();
|
||||||
|
ignore(connection);
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypedArray
|
||||||
|
|
||||||
|
public void themeObtainTypedArrayAndRecycle(Resources.Theme theme) {
|
||||||
|
TypedArray array = theme.obtainStyledAttributes(new int[] {});
|
||||||
|
ignore(array);
|
||||||
|
array.recycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void themeObtainTypedArrayAndLeak(Resources.Theme theme) {
|
||||||
|
TypedArray array = theme.obtainStyledAttributes(new int[] {});
|
||||||
|
ignore(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void activityObtainTypedArrayAndRecycle(Activity activity) {
|
||||||
|
TypedArray array = activity.obtainStyledAttributes(new int[] {});
|
||||||
|
ignore(array);
|
||||||
|
array.recycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void activityObtainTypedArrayAndLeak(Activity activity) {
|
||||||
|
TypedArray array = activity.obtainStyledAttributes(new int[] {});
|
||||||
|
ignore(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void contextObtainTypedArrayAndRecycle(Context context) {
|
||||||
|
TypedArray array = context.obtainStyledAttributes(new int[] {});
|
||||||
|
ignore(array);
|
||||||
|
array.recycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void contextObtainTypedArrayAndLeak(Context context) {
|
||||||
|
TypedArray array = context.obtainStyledAttributes(new int[] {});
|
||||||
|
ignore(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileChannel
|
||||||
|
|
||||||
|
void copyFileLeak(File src, File dst) throws IOException {
|
||||||
|
FileChannel inChannel = new FileInputStream(src).getChannel();
|
||||||
|
FileChannel outChannel = new FileOutputStream(dst).getChannel();
|
||||||
|
try {
|
||||||
|
inChannel.transferTo(0, inChannel.size(), outChannel);
|
||||||
|
} finally {
|
||||||
|
if (inChannel != null) inChannel.close();
|
||||||
|
if (outChannel != null) outChannel.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void copyFileClose(File src, File dst) throws IOException {
|
||||||
|
FileChannel inChannel = new FileInputStream(src).getChannel();
|
||||||
|
try {
|
||||||
|
ignore(inChannel);
|
||||||
|
} finally {
|
||||||
|
inChannel.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected long checkNotNullCauseNoLeak(URL mUrl) throws IOException {
|
||||||
|
URL url = new URL("http://www.facebook.com");
|
||||||
|
HttpURLConnection serverConnection =
|
||||||
|
(HttpURLConnection) Preconditions.checkNotNull(url.openConnection());
|
||||||
|
try {
|
||||||
|
ignore(serverConnection);
|
||||||
|
} catch (NumberFormatException nfe) {
|
||||||
|
} finally {
|
||||||
|
serverConnection.disconnect();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scannerNotClosed() throws IOException {
|
||||||
|
Scanner scanner = new Scanner(new FileInputStream("file.txt"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void scannerClosed() throws IOException {
|
||||||
|
Scanner scanner = new Scanner(new FileInputStream("file.txt"));
|
||||||
|
scanner.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void processDestroyed() {
|
||||||
|
Process process = null;
|
||||||
|
try {
|
||||||
|
process = Runtime.getRuntime().exec("");
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
process.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void processForciblyDestroyed() throws IOException {
|
||||||
|
Process process = null;
|
||||||
|
try {
|
||||||
|
process = Runtime.getRuntime().exec("");
|
||||||
|
} finally {
|
||||||
|
ignore(process.destroyForcibly());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Container {
|
||||||
|
FileInputStream inputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
native Container load(FileInputStream inputStream);
|
||||||
|
|
||||||
|
public Container resourceReturnedIndirectly() {
|
||||||
|
FileInputStream inputStream;
|
||||||
|
Container container = null;
|
||||||
|
try {
|
||||||
|
inputStream = new FileInputStream("pif.txt");
|
||||||
|
container = load(inputStream);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
native void unknownClose(Closeable c);
|
||||||
|
|
||||||
|
public void resourceClosedBySkippedMethod() {
|
||||||
|
FileInputStream inputStream = null;
|
||||||
|
try {
|
||||||
|
inputStream = new FileInputStream("pif.txt");
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
return;
|
||||||
|
} finally {
|
||||||
|
unknownClose(inputStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int tryWithResource() {
|
||||||
|
try (FileInputStream inputStream = new FileInputStream("paf.txt")) {
|
||||||
|
return inputStream.read();
|
||||||
|
} catch (IOException e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStreamReader withCharset(URLConnection urlConnection) {
|
||||||
|
InputStreamReader reader = null;
|
||||||
|
try {
|
||||||
|
reader = new InputStreamReader(urlConnection.getInputStream(), "iso-8859-1");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
if (reader != null) {
|
||||||
|
try {
|
||||||
|
reader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void withZipFile() throws IOException {
|
||||||
|
ZipFile f = new ZipFile("hi");
|
||||||
|
InputStream s = f.getInputStream(f.getEntry("there"));
|
||||||
|
if (s != null) s.toString();
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deflaterLeak() {
|
||||||
|
Deflater comp = new Deflater();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deflaternoLeak() {
|
||||||
|
Deflater comp = new Deflater();
|
||||||
|
comp.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inflaterLeak() {
|
||||||
|
Inflater decomp = new Inflater();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inflaterNoLeak() {
|
||||||
|
Inflater decomp = new Inflater();
|
||||||
|
decomp.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoResourceLeakWarningAfterCheckState(File f, int x) throws IOException {
|
||||||
|
InputStream stream = new FileInputStream(f);
|
||||||
|
Preconditions.checkState(x > 0);
|
||||||
|
stream.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
public class ReturnValueIgnored {
|
||||||
|
|
||||||
|
private int m() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void returnValueIgnored() {
|
||||||
|
m();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// _SHOULD_BE_SKIPPED_
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
public class SkippedSourceFile {
|
||||||
|
|
||||||
|
static Object createdBySkippedFile() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
public class SomeLibrary {
|
||||||
|
|
||||||
|
class $$Z {}
|
||||||
|
|
||||||
|
T t;
|
||||||
|
|
||||||
|
T get() {
|
||||||
|
return t == null ? null : t;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import com.facebook.infer.annotation.SuppressLint;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
// @SuppressLint("Suppressing all the warnings in a class is not supported yet")
|
||||||
|
class SuppressAllWarnigsInTheClass {
|
||||||
|
|
||||||
|
void shouldNotReportNPE() {
|
||||||
|
Object object = null;
|
||||||
|
object.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void shouldNotReportResourceLeak() {
|
||||||
|
try {
|
||||||
|
FileInputStream fis = new FileInputStream(new File("whatever.txt"));
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SuppressLintExample {
|
||||||
|
|
||||||
|
@SuppressLint("null-dereference")
|
||||||
|
SuppressLintExample() {
|
||||||
|
Object object = null;
|
||||||
|
object.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void shouldReportNPE() {
|
||||||
|
Object object = null;
|
||||||
|
object.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("null-dereference")
|
||||||
|
void shouldNotReportNPE() {
|
||||||
|
Object object = null;
|
||||||
|
object.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
public class T {
|
||||||
|
int x;
|
||||||
|
|
||||||
|
void f() {}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
|
||||||
|
public class Utils {
|
||||||
|
|
||||||
|
public static void closeQuietly(Closeable closeable) {
|
||||||
|
try {
|
||||||
|
if (closeable != null) {
|
||||||
|
closeable.close();
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,184 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package codetoanalyze.java.infer;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.PipedReader;
|
||||||
|
import java.io.PipedWriter;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
public class WriterLeaks {
|
||||||
|
|
||||||
|
// Writer tests
|
||||||
|
|
||||||
|
public void writerNotClosedAfterWrite() {
|
||||||
|
Writer writer;
|
||||||
|
try {
|
||||||
|
writer = new PrintWriter("file.txt");
|
||||||
|
writer.write(10);
|
||||||
|
writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writerClosed() throws IOException {
|
||||||
|
Writer writer = null;
|
||||||
|
try {
|
||||||
|
writer = new PrintWriter("file.txt");
|
||||||
|
writer.write(10);
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (writer != null) writer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrintWriter tests
|
||||||
|
|
||||||
|
public void printWriterNotClosedAfterAppend() {
|
||||||
|
PrintWriter writer;
|
||||||
|
try {
|
||||||
|
writer = new PrintWriter("file.txt");
|
||||||
|
writer = writer.append('0');
|
||||||
|
writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printWriterClosed() throws IOException {
|
||||||
|
PrintWriter writer = null;
|
||||||
|
try {
|
||||||
|
writer = new PrintWriter("file.txt");
|
||||||
|
writer = writer.append(null);
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (writer != null) writer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BufferedWriter tests
|
||||||
|
|
||||||
|
public void bufferedWriterNotClosedAfterWrite() {
|
||||||
|
BufferedWriter writer;
|
||||||
|
try {
|
||||||
|
FileWriter fw = new FileWriter("file.txt");
|
||||||
|
writer = new BufferedWriter(fw);
|
||||||
|
writer.write("word");
|
||||||
|
writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bufferedWriterClosed() throws IOException {
|
||||||
|
BufferedWriter writer = null;
|
||||||
|
try {
|
||||||
|
FileWriter fw = new FileWriter("file.txt");
|
||||||
|
writer = new BufferedWriter(fw);
|
||||||
|
writer.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (writer != null) writer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OutputStreamWriter tests
|
||||||
|
|
||||||
|
public void outputStreamWriterNotClosedAfterWrite() {
|
||||||
|
OutputStreamWriter writer;
|
||||||
|
try {
|
||||||
|
writer = new OutputStreamWriter(new FileOutputStream("file.txt"));
|
||||||
|
writer.write("word");
|
||||||
|
writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void outputStreamWriterClosed() throws IOException {
|
||||||
|
OutputStreamWriter writer = null;
|
||||||
|
try {
|
||||||
|
writer = new OutputStreamWriter(new FileOutputStream("file.txt"));
|
||||||
|
writer.write(10);
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (writer != null) writer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileWriter tests
|
||||||
|
|
||||||
|
public void fileWriterNotClosedAfterWrite() {
|
||||||
|
FileWriter writer;
|
||||||
|
try {
|
||||||
|
writer = new FileWriter("file.txt");
|
||||||
|
writer.write("word");
|
||||||
|
writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fileWriterClosed() throws IOException {
|
||||||
|
FileWriter writer = null;
|
||||||
|
try {
|
||||||
|
writer = new FileWriter("file.txt");
|
||||||
|
writer.write(10);
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (writer != null) writer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PipedWriter tests
|
||||||
|
|
||||||
|
public void pipedWriterNotClosedAfterConstructedWithReader() {
|
||||||
|
PipedWriter writer;
|
||||||
|
PipedReader reader;
|
||||||
|
try {
|
||||||
|
reader = new PipedReader();
|
||||||
|
writer = new PipedWriter(reader);
|
||||||
|
writer.write(42);
|
||||||
|
writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pipedWriterNotClosedAfterConnect(PipedReader reader) {
|
||||||
|
PipedWriter writer;
|
||||||
|
try {
|
||||||
|
writer = new PipedWriter();
|
||||||
|
writer.connect(reader);
|
||||||
|
writer.write(42);
|
||||||
|
writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pipedWriterNotConnected() {
|
||||||
|
PipedWriter writer;
|
||||||
|
try {
|
||||||
|
writer = new PipedWriter();
|
||||||
|
writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pipedWriterClosed(PipedReader reader) throws IOException {
|
||||||
|
PipedWriter writer = null;
|
||||||
|
try {
|
||||||
|
writer = new PipedWriter();
|
||||||
|
writer.connect(reader);
|
||||||
|
writer.write(42);
|
||||||
|
} catch (IOException e) {
|
||||||
|
} finally {
|
||||||
|
if (writer != null) writer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue