📄 findopenstream.java
字号:
* ---------------------------------------------------------------------- */ private List<PotentialOpenStream> potentialOpenStreamList; /* ---------------------------------------------------------------------- * Implementation * ---------------------------------------------------------------------- */ public FindOpenStream(BugReporter bugReporter) { super(bugReporter); this.potentialOpenStreamList = new LinkedList<PotentialOpenStream>(); } public boolean prescreen(ClassContext classContext, Method method) { BitSet bytecodeSet = classContext.getBytecodeSet(method); return bytecodeSet.get(Constants.NEW) || bytecodeSet.get(Constants.INVOKEINTERFACE) || bytecodeSet.get(Constants.INVOKESPECIAL) || bytecodeSet.get(Constants.INVOKESTATIC) || bytecodeSet.get(Constants.INVOKEVIRTUAL); } public StreamResourceTracker getResourceTracker(ClassContext classContext, Method method) { return new StreamResourceTracker(streamFactoryList, bugReporter); } public static boolean isMainMethod(Method method) { return method.isStatic() && method.getName().equals("main") && method.getSignature().equals("([Ljava/lang/String;)V"); } public void analyzeMethod(ClassContext classContext, Method method, StreamResourceTracker resourceTracker, ResourceCollection<Stream> resourceCollection) throws CFGBuilderException, DataflowAnalysisException { if (isMainMethod(method)) return; potentialOpenStreamList.clear(); JavaClass javaClass = classContext.getJavaClass(); MethodGen methodGen = classContext.getMethodGen(method); CFG cfg = classContext.getCFG(method); // Add Streams passed into the method as parameters. // These are uninteresting, and should poison // any streams which wrap them. try { Type[] parameterTypeList = Type.getArgumentTypes(methodGen.getSignature()); Location firstLocation = new Location(cfg.getEntry().getFirstInstruction(), cfg.getEntry()); int local = methodGen.isStatic() ? 0 : 1; for (int i = 0; i < parameterTypeList.length; ++i) { Type type = parameterTypeList[i]; if (type instanceof ObjectType) { ObjectType objectType = (ObjectType) type; for (int j = 0; j < streamBaseList.length; ++j) { ObjectType streamBase = streamBaseList[j]; if (Hierarchy.isSubtype(objectType, streamBase)) { // OK, found a parameter that is a resource. // Create a Stream object to represent it. // The Stream will be uninteresting, so it will // inhibit reporting for any stream that wraps it. Stream paramStream = new Stream(firstLocation, objectType.getClassName(), streamBase.getClassName()); paramStream.setIsOpenOnCreation(true); paramStream.setOpenLocation(firstLocation); paramStream.setInstanceParam(local); resourceCollection.addPreexistingResource(paramStream); break; } } } switch (type.getType()) { case Constants.T_LONG: case Constants.T_DOUBLE: local += 2; break; default: local += 1; break; } } } catch (ClassNotFoundException e) { bugReporter.reportMissingClass(e); } // Set precomputed map of Locations to Stream creation points. // That way, the StreamResourceTracker won't have to // repeatedly try to figure out where Streams are created. resourceTracker.setResourceCollection(resourceCollection); super.analyzeMethod(classContext, method, resourceTracker, resourceCollection); // Compute streams that escape into other streams: // this takes wrapper streams into account. // This will also compute equivalence classes of streams, // so that if one stream in a class is closed, // they are all considered closed. // (FIXME: this is too simplistic, especially if buffering // is involved. Sometime we should really think harder // about how this should work.) resourceTracker.markTransitiveUninterestingStreamEscapes(); // For each stream closed on all paths, mark its equivalence // class as being closed. for (Iterator<Stream> i = resourceCollection.resourceIterator(); i.hasNext();) { Stream stream = i.next(); StreamEquivalenceClass equivalenceClass = resourceTracker.getStreamEquivalenceClass(stream); if (stream.isClosed()) equivalenceClass.setClosed(); } // Iterate through potential open streams, reporting warnings // for the "interesting" streams that haven't been closed // (and aren't in an equivalence class with another stream // that was closed). for (Iterator<PotentialOpenStream> i = potentialOpenStreamList.iterator(); i.hasNext();) { PotentialOpenStream pos = i.next(); Stream stream = pos.stream; if (stream.isClosed()) // Stream was in an equivalence class with another // stream that was properly closed. continue; if (stream.isUninteresting()) continue; Location openLocation = stream.getOpenLocation(); if (openLocation == null) continue; if (IGNORE_WRAPPED_UNINTERESTING_STREAMS && resourceTracker.isUninterestingStreamEscape(stream)) continue; String sourceFile = javaClass.getSourceFileName(); bugReporter.reportBug(new BugInstance(this, pos.bugType, pos.priority) .addClassAndMethod(methodGen, sourceFile) .addSourceLine(methodGen, sourceFile, stream.getLocation().getHandle())); } } public void inspectResult(JavaClass javaClass, MethodGen methodGen, CFG cfg, Dataflow<ResourceValueFrame, ResourceValueAnalysis<Stream>> dataflow, Stream stream) { ResourceValueFrame exitFrame = dataflow.getResultFact(cfg.getExit()); int exitStatus = exitFrame.getStatus(); if (exitStatus == ResourceValueFrame.OPEN || exitStatus == ResourceValueFrame.OPEN_ON_EXCEPTION_PATH) { // FIXME: Stream object should be queried for the // priority. String bugType = stream.getBugType(); int priority = NORMAL_PRIORITY; if (exitStatus == ResourceValueFrame.OPEN_ON_EXCEPTION_PATH) { bugType += "_EXCEPTION_PATH"; priority = LOW_PRIORITY; } potentialOpenStreamList.add(new PotentialOpenStream(bugType, priority, stream)); } else if (exitStatus == ResourceValueFrame.CLOSED) { // Remember that this stream was closed on all paths. // Later, we will mark all of the streams in its equivalence class // as having been closed. stream.setClosed(); } } public static void main(String[] argv) throws Exception { if (argv.length != 3) { System.err.println("Usage: " + FindOpenStream.class.getName() + " <class file> <method name> <bytecode offset>"); System.exit(1); } String classFile = argv[0]; String methodName = argv[1]; int offset = Integer.parseInt(argv[2]); ResourceValueAnalysisTestDriver<Stream, StreamResourceTracker> driver = new ResourceValueAnalysisTestDriver<Stream, StreamResourceTracker>() { public StreamResourceTracker createResourceTracker(ClassContext classContext, Method method) { return new StreamResourceTracker(streamFactoryList, classContext.getLookupFailureCallback()); } }; driver.execute(classFile, methodName, offset); }}// vim:ts=3
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -