📄 findopenstream.java
字号:
/* (non-Javadoc) * @see edu.umd.cs.findbugs.Detector#visitClassContext(edu.umd.cs.findbugs.ba.ClassContext) */ @Override public void visitClassContext(ClassContext classContext) { JavaClass jclass = classContext.getJavaClass(); // Check to see if the class references any other classes // which could be resources we want to track. // If we don't find any such classes, we skip analyzing // the class. (Note: could do this by method.) boolean sawResourceClass = false; for (int i = 0; i < jclass.getConstantPool().getLength(); ++i) { Constant constant = jclass.getConstantPool().getConstant(i); String className = null; if (constant instanceof ConstantMethodref) { ConstantMethodref cmr = (ConstantMethodref) constant; int classIndex = cmr.getClassIndex(); className = jclass.getConstantPool().getConstantString( classIndex, Constants.CONSTANT_Class); } else if (constant instanceof ConstantInterfaceMethodref) { ConstantInterfaceMethodref cmr = (ConstantInterfaceMethodref) constant; int classIndex = cmr.getClassIndex(); className = jclass.getConstantPool().getConstantString( classIndex, Constants.CONSTANT_Class); } if (className != null) { if (DEBUG) System.out.println("FindOpenStream: saw class " + className); for (String aPRESCREEN_CLASS_LIST : PRESCREEN_CLASS_LIST) { if (className.indexOf(aPRESCREEN_CLASS_LIST) >= 0) { sawResourceClass = true; break; } } } } if (sawResourceClass) { super.visitClassContext(classContext); } } @Override public boolean prescreen(ClassContext classContext, Method method) { BitSet bytecodeSet = classContext.getBytecodeSet(method); if (bytecodeSet == null) return false; return bytecodeSet.get(Constants.NEW) || bytecodeSet.get(Constants.INVOKEINTERFACE) || bytecodeSet.get(Constants.INVOKESPECIAL) || bytecodeSet.get(Constants.INVOKESTATIC) || bytecodeSet.get(Constants.INVOKEVIRTUAL); } @Override 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"); } @Override 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); if (methodGen == null) return; 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 (Type type : parameterTypeList) { if (type instanceof ObjectType) { ObjectType objectType = (ObjectType) type; for (ObjectType streamBase : streamBaseList) { 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 (PotentialOpenStream pos : potentialOpenStreamList) { 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) .addTypeOfNamedClass(stream.getStreamBase()).describe(TypeAnnotation.CLOSEIT_ROLE) .addSourceLine(classContext, methodGen, sourceFile, stream.getLocation().getHandle())); } } @Override public void inspectResult(ClassContext classContext, 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>() { @Override 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 + -