/* * 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 map = new HashMap<>(); SomeResource res = new SomeResource(); Integer key = 42; map.put(key, res); return map; } void createsLocalMapContainingResourcesOk() { HashMap map = new HashMap<>(); SomeResource res = new SomeResource(); Integer key = 42; map.put(key, res); map.clear(); } HashMap 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 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); } } } }