package tracematches; import java.io.*; public class ReaderMain { public static void main(String[] args) throws IOException { File f = new File("temp"); f.createNewFile(); f.deleteOnExit(); FileInputStream fsin = new FileInputStream(f); Reader in = new InputStreamReader(fsin); BufferedReader bufferedReader = new BufferedReader(in); //fsin.close(); this would not be detected //(c.f. tainted string example) //unsafe in.close(); while(true) { int content = bufferedReader.read(); if(content<0) break; } //safe FileInputStream fsin2 = new FileInputStream(f); Reader in2 = new InputStreamReader(fsin2); in2.read(); fsin2.close(); //safe flow-insensitively FileInputStream fsin3 = new FileInputStream(f); Reader in3 = new InputStreamReader(fsin3); in3.read(); fsin3.read(); } static aspect ReaderChecker { /* * This aspect contains two tracematches. * The first one checks for each reader "r" which is created for an input stream "is", that * neither "r" nor "is" are closed before one reads from "r" or "is". * * The second tracematch checks the same for a reader that is created for another reader. * * Unfortunately this does not yet capture the case where we create a reader "r1" on top of a reader * "r2", which was created on top of a stream "is" and then we close "is" and read from "r2". * (c.f. tainted string example for PQL) */ pointcut createReader(InputStream is): call(Reader+.new(InputStream+,..)) && args(is,..) ; tracematch(Reader r, InputStream is) { sym create after returning(r): createReader(is); sym closeR before: call(* close()) && target(r); sym closeI before: call(* close()) && target(is); sym readR before: (call(* read(..)) || call(* readLine(..))) && target(r); sym readI before: (call(* read(..)) || call(* readLine(..))) && target(is); create (closeR|closeI) (readR|readI) { if(System.getProperty("TMTEST_ACTIVE")!=null) { throw new IllegalStateException("stream or reader closed"); } } } pointcut createReaderFromReader(Reader r): call(Reader+.new(Reader+,..)) && args(r,..) ; tracematch(Reader r, Reader inner) { sym create after returning(r): createReaderFromReader(inner); sym closeR before: call(* close()) && target(r); sym closeI before: call(* close()) && target(inner); sym readR before: (call(* read(..)) || call(* readLine(..))) && target(r); sym readI before: (call(* read(..)) || call(* readLine(..))) && target(inner); create (closeR|closeI) (readR|readI) { if(System.getProperty("TMTEST_ACTIVE")!=null) { throw new IllegalStateException("stream or reader closed"); } } } } }