📄 findrefcomparison.java
字号:
static boolean sawStringIntern; public void visitClassContext(ClassContext classContext) { JavaClass jclass = classContext.getJavaClass(); Method[] methodList = jclass.getMethods(); sawStringIntern = false; for (int i = 0; i < methodList.length; ++i) { Method method = methodList[i]; MethodGen methodGen = classContext.getMethodGen(method); if (methodGen == null) continue; // Prescreening - must have IF_ACMPEQ, IF_ACMPNE, // or an invocation of an instance method BitSet bytecodeSet = classContext.getBytecodeSet(method); if (!bytecodeSet.intersects(prescreenSet)) continue; if (DEBUG) System.out.println("FindRefComparison: analyzing " + SignatureConverter.convertMethodSignature(methodGen)); try { analyzeMethod(classContext, method); } catch (CFGBuilderException e) { bugReporter.logError(e.toString()); } catch (DataflowAnalysisException e) { bugReporter.logError(e.toString()); } } } private void analyzeMethod(ClassContext classContext, Method method) throws CFGBuilderException, DataflowAnalysisException { boolean sawCallToEquals = false; JavaClass jclass = classContext.getJavaClass(); ConstantPoolGen cpg = classContext.getConstantPoolGen(); MethodGen methodGen = classContext.getMethodGen(method); // Report at most one String comparison per method. // We report the first highest priority warning. stringComparison = null; refComparison = null; CFG cfg = classContext.getCFG(method); DepthFirstSearch dfs = classContext.getDepthFirstSearch(method); ExceptionSetFactory exceptionSetFactory = classContext.getExceptionSetFactory(method); // Perform type analysis using our special type merger // (which handles String types specially, keeping track of // which ones appear to be dynamically created) RefComparisonTypeMerger typeMerger = new RefComparisonTypeMerger(bugReporter, exceptionSetFactory); TypeFrameModelingVisitor visitor = new RefComparisonTypeFrameModelingVisitor(methodGen.getConstantPool(), bugReporter); TypeAnalysis typeAnalysis = new TypeAnalysis(methodGen, cfg, dfs, typeMerger, visitor, bugReporter, exceptionSetFactory); TypeDataflow typeDataflow = new TypeDataflow(cfg, typeAnalysis); typeDataflow.execute(); for (Iterator<Location> i = cfg.locationIterator(); i.hasNext();) { Location location = i.next(); Instruction ins = location.getHandle().getInstruction(); short opcode = ins.getOpcode(); if (opcode == Constants.IF_ACMPEQ || opcode == Constants.IF_ACMPNE) { checkRefComparison(location, jclass, methodGen, typeDataflow); } else if (invokeInstanceSet.get(opcode)) { InvokeInstruction inv = (InvokeInstruction) ins; String methodName = inv.getMethodName(cpg); String methodSig = inv.getSignature(cpg); if ((methodName.equals("equals") && methodSig.equals("(Ljava/lang/Object;)Z")) || (methodName.equals("equalIgnoreCases") && methodSig.equals("(Ljava/lang/String;)Z"))) { sawCallToEquals = true; checkEqualsComparison(location, jclass, methodGen, typeDataflow); } } } // If a String reference comparison was found in the method, // report it if (stringComparison != null) { if (sawCallToEquals && stringComparison.getPriority() >= NORMAL_PRIORITY) { // System.out.println("Reducing priority of " + stringComparison); stringComparison.setPriority(1 + stringComparison.getPriority()); } if (stringComparison.getPriority() >= NORMAL_PRIORITY && !(method.isPublic() || method.isProtected())) { // System.out.print("private/packed"); stringComparison.setPriority(1 + stringComparison.getPriority()); } if (stringComparison.getPriority() <= LOW_PRIORITY) { bugReporter.reportBug(stringComparison); } } if (refComparison != null) { if (false && sawCallToEquals) { // System.out.println("Reducing priority of " + refComparison); refComparison.setPriority(1 + refComparison.getPriority()); } if (refComparison.getPriority() <= LOW_PRIORITY) bugReporter.reportBug(refComparison); } } private void checkRefComparison(Location location, JavaClass jclass, MethodGen methodGen, TypeDataflow typeDataflow) throws DataflowAnalysisException { InstructionHandle handle = location.getHandle(); TypeFrame frame = typeDataflow.getFactAtLocation(location); if (frame.getStackDepth() < 2) throw new DataflowAnalysisException("Stack underflow", methodGen, handle); int numSlots = frame.getNumSlots(); Type lhsType = frame.getValue(numSlots - 1); Type rhsType = frame.getValue(numSlots - 2); if (lhsType instanceof ReferenceType && rhsType instanceof ReferenceType) { String lhs = SignatureConverter.convert(lhsType.getSignature()); String rhs = SignatureConverter.convert(rhsType.getSignature()); if (!lhs.equals(rhs)) return; if (lhs.equals("java.lang.String") && rhs.equals("java.lang.String")) { if (DEBUG) System.out.println("String/String comparison at " + handle); // Compute the priority: // - two static strings => do not report // - dynamic string and anything => high // - static string and unknown => medium // - all other cases => low int priority = NORMAL_PRIORITY; // System.out.println("Compare " + lhsType + " == " + rhsType); byte type1 = lhsType.getType(); byte type2 = rhsType.getType(); // T1 T2 result // S S no-op // D ? high // ? D high // S ? normal // ? S normal if (type1 == T_STATIC_STRING && type2 == T_STATIC_STRING) priority = LOW_PRIORITY + 1; else if (type1 == T_DYNAMIC_STRING || type2 == T_DYNAMIC_STRING) priority = HIGH_PRIORITY; else if (type1 == T_STATIC_STRING || type2 == T_STATIC_STRING) priority = LOW_PRIORITY; else if (sawStringIntern) priority = LOW_PRIORITY; if (priority <= LOW_PRIORITY) { String sourceFile = jclass.getSourceFileName(); BugInstance instance = new BugInstance(this, "ES_COMPARING_STRINGS_WITH_EQ", priority) .addClassAndMethod(methodGen, sourceFile) .addSourceLine(methodGen, sourceFile, handle) .addClass("java.lang.String").describe("CLASS_REFTYPE"); if (REPORT_ALL_REF_COMPARISONS) bugReporter.reportBug(instance); else if (stringComparison == null || priority < stringComparison.getPriority()) stringComparison = instance; } } else if (suspiciousSet.contains(lhs) && suspiciousSet.contains(rhs)) { String sourceFile = jclass.getSourceFileName(); BugInstance instance = new BugInstance(this, "RC_REF_COMPARISON", NORMAL_PRIORITY) .addClassAndMethod(methodGen, sourceFile) .addSourceLine(methodGen, sourceFile, handle) .addClass(lhs).describe("CLASS_REFTYPE"); if (REPORT_ALL_REF_COMPARISONS) bugReporter.reportBug(instance); else if (refComparison == null) refComparison = instance; } } } private void checkEqualsComparison(Location location, JavaClass jclass, MethodGen methodGen, TypeDataflow typeDataflow) throws DataflowAnalysisException { InstructionHandle handle = location.getHandle(); String sourceFile = jclass.getSourceFileName(); TypeFrame frame = typeDataflow.getFactAtLocation(location); if (frame.getStackDepth() < 2) throw new DataflowAnalysisException("Stack underflow", methodGen, handle); int numSlots = frame.getNumSlots(); Type lhsType_ = frame.getValue(numSlots - 2); Type rhsType_ = frame.getValue(numSlots - 1); if (lhsType_.equals(rhsType_)) return; // Ignore top and bottom values if (lhsType_.getType() == T_TOP || lhsType_.getType() == T_BOTTOM || rhsType_.getType() == T_TOP || rhsType_.getType() == T_BOTTOM) return; if (!(lhsType_ instanceof ReferenceType) || !(rhsType_ instanceof ReferenceType)) { if (rhsType_.getType() == T_NULL) { // A literal null value was passed directly to equals(). bugReporter.reportBug(new BugInstance(this, "EC_NULL_ARG", NORMAL_PRIORITY) .addClassAndMethod(methodGen, sourceFile) .addSourceLine(methodGen, sourceFile, location.getHandle())); } else if (lhsType_.getType() == T_NULL) { // Hmm...in this case, equals() is being invoked on // a literal null value. This is really the // purview of FindNullDeref. So, we'll just do nothing. } else { bugReporter.logError("equals() used to compare non-object type(s) " + lhsType_ + " and " + rhsType_ + " in " + SignatureConverter.convertMethodSignature(methodGen) + " at " + location.getHandle()); } return; } // For now, ignore the case where either reference is not // of an object type. (It could be either an array or null.) if (!(lhsType_ instanceof ObjectType) || !(rhsType_ instanceof ObjectType)) return; ObjectType lhsType = (ObjectType) lhsType_; ObjectType rhsType = (ObjectType) rhsType_; int priority = LOW_PRIORITY + 1; String bugType = "EC_UNRELATED_TYPES"; // See if the types are related by inheritance. try { if (!Hierarchy.isSubtype(lhsType, rhsType) && !Hierarchy.isSubtype(rhsType, lhsType)) { // We have unrelated types. // If both types are interfaces, then it is conceivable that // there are class types that implement both interfaces, // so the comparision might be meaningful. Classify such // cases as medium. Other cases are high priority. if (lhsType.referencesInterfaceExact() && rhsType.referencesInterfaceExact()) { // TODO: This would be a good place to assume a closed // universe and look at subclasses. priority = NORMAL_PRIORITY; bugType = "EC_UNRELATED_INTERFACES"; } else { // TODO: it is possible that an unknown subclass of // the class type implements the interface. // Again, a subclass search could answer this // question if we had a closed universe. priority = HIGH_PRIORITY; } } } catch (ClassNotFoundException e) { bugReporter.reportMissingClass(e); return; } if (priority <= LOW_PRIORITY) { bugReporter.reportBug(new BugInstance(this, bugType, priority) .addClassAndMethod(methodGen, sourceFile) .addSourceLine(methodGen, sourceFile, location.getHandle()) .addClass(lhsType.getClassName()).describe("CLASS_REFTYPE") .addClass(rhsType.getClassName()).describe("CLASS_REFTYPE")); } } public void report() { } public static void main(String[] argv) throws Exception { if (argv.length != 1) { System.err.println("Usage: " + FindRefComparison.class.getName() + " <class file>"); System.exit(1); } DataflowTestDriver<TypeFrame, TypeAnalysis> driver = new DataflowTestDriver<TypeFrame, TypeAnalysis>() { public Dataflow<TypeFrame, TypeAnalysis> createDataflow(ClassContext classContext, Method method) throws CFGBuilderException, DataflowAnalysisException { RepositoryLookupFailureCallback lookupFailureCallback = classContext.getLookupFailureCallback(); MethodGen methodGen = classContext.getMethodGen(method); DepthFirstSearch dfs = classContext.getDepthFirstSearch(method); CFG cfg = classContext.getCFG(method); ExceptionSetFactory exceptionSetFactory = classContext.getExceptionSetFactory(method); TypeMerger typeMerger = new RefComparisonTypeMerger(lookupFailureCallback, exceptionSetFactory); TypeFrameModelingVisitor visitor = new RefComparisonTypeFrameModelingVisitor(methodGen.getConstantPool(), lookupFailureCallback); TypeAnalysis analysis = new TypeAnalysis(methodGen, cfg, dfs, typeMerger, visitor, lookupFailureCallback, exceptionSetFactory); Dataflow<TypeFrame, TypeAnalysis> dataflow = new Dataflow<TypeFrame, TypeAnalysis>(cfg, analysis); dataflow.execute(); return dataflow; } }; driver.execute(argv[0]); }}// vim:ts=3
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -