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