⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 findrefcomparison.java

📁 A static analysis tool to find bugs in Java programs
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
			this.propertySet = propertySet;			this.location = location;		}	}	private interface WarningDecorator {		public void decorate(WarningWithProperties warn);	}	private void analyzeMethod(ClassContext classContext, final Method method)	throws CFGBuilderException, DataflowAnalysisException {		MethodGen methodGen = classContext.getMethodGen(method);		if (methodGen == null) return;		boolean sawCallToEquals = false;		JavaClass jclass = classContext.getJavaClass();		ConstantPoolGen cpg = classContext.getConstantPoolGen();		// Enqueue all of the potential violations we find in the method.		// Normally we'll only report the first highest-priority warning,		// but if in relaxed mode or if REPORT_ALL_REF_COMPARISONS is set,		// then we'll report everything.		LinkedList<WarningWithProperties> refComparisonList =			new LinkedList<WarningWithProperties>();		LinkedList<WarningWithProperties> stringComparisonList =			new LinkedList<WarningWithProperties>();		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);		RefComparisonTypeFrameModelingVisitor visitor =			new RefComparisonTypeFrameModelingVisitor(methodGen.getConstantPool(), bugReporter);		TypeAnalysis typeAnalysis =			new TypeAnalysis(method, methodGen, cfg, dfs, typeMerger, visitor, bugReporter, exceptionSetFactory) {			@Override public void initEntryFact(TypeFrame result) {				super.initEntryFact(result);				for(int i = 0; i < methodGen.getMaxLocals(); i++) {					Type t = result.getValue(i);					if (t.equals(ObjectType.STRING))						result.setValue(i, parameterStringTypeInstance);				}			}		};		TypeDataflow typeDataflow = new TypeDataflow(cfg, typeAnalysis);		typeDataflow.execute();		// Inspect Locations in the method for suspicious ref comparisons and calls to equals()		for (Iterator<Location> i = cfg.locationIterator(); i.hasNext();) {			Location location = i.next();			sawCallToEquals = inspectLocation(					sawCallToEquals,					jclass,					cpg,					method,					methodGen,					refComparisonList,					stringComparisonList,					visitor,					typeDataflow, location);		}		// Add method-wide properties to BugInstances		final boolean sawEquals = sawCallToEquals;		decorateWarnings(stringComparisonList, new WarningDecorator(){			public void decorate(WarningWithProperties warn) {				if (sawEquals) {					warn.propertySet.addProperty(RefComparisonWarningProperty.SAW_CALL_TO_EQUALS);				}				if (false && !(method.isPublic() || method.isProtected())) {					warn.propertySet.addProperty(RefComparisonWarningProperty.PRIVATE_METHOD);				}			}		});		decorateWarnings(refComparisonList, new WarningDecorator() {			public void decorate(WarningWithProperties warn) {				if (sawEquals) {					warn.propertySet.addProperty(RefComparisonWarningProperty.SAW_CALL_TO_EQUALS);				}			}		});		// Report violations		boolean relaxed = FindBugsAnalysisFeatures.isRelaxedMode();		reportBest(classContext, method, stringComparisonList, relaxed);		reportBest(classContext, method, refComparisonList, relaxed);	}	private boolean inspectLocation(			boolean sawCallToEquals,			JavaClass jclass,			ConstantPoolGen cpg,			Method method,			MethodGen methodGen,			LinkedList<WarningWithProperties> refComparisonList,			LinkedList<WarningWithProperties> stringComparisonList,			RefComparisonTypeFrameModelingVisitor visitor,			TypeDataflow typeDataflow, Location location) throws DataflowAnalysisException {		Instruction ins = location.getHandle().getInstruction();		short opcode = ins.getOpcode();		if (opcode == Constants.IF_ACMPEQ || opcode == Constants.IF_ACMPNE) {			checkRefComparison(					location,					jclass,					methodGen,					visitor,					typeDataflow,					stringComparisonList,					refComparisonList);		} else if (invokeInstanceSet.get(opcode)) {			InvokeInstruction inv = (InvokeInstruction) ins;			String methodName = inv.getMethodName(cpg);			String methodSig = inv.getSignature(cpg);			if (isEqualsMethod(methodName, methodSig)) {				sawCallToEquals = true;				checkEqualsComparison(location, jclass, method, methodGen, typeDataflow);			}		}		return sawCallToEquals;	}	private void decorateWarnings(			LinkedList<WarningWithProperties> stringComparisonList,			WarningDecorator warningDecorator) {		for (WarningWithProperties warn : stringComparisonList) {			warningDecorator.decorate(warn);			warn.instance.setPriority(warn.propertySet.computePriority(NORMAL_PRIORITY));		}	}	private void reportBest(			ClassContext classContext,			Method method,			LinkedList<WarningWithProperties> warningList,			boolean relaxed) {		boolean reportAll = relaxed || REPORT_ALL_REF_COMPARISONS;		WarningWithProperties best = null;		for (WarningWithProperties warn : warningList) {			if (best == null || warn.instance.getPriority() < best.instance.getPriority()) {				best = warn;			}			if (reportAll) {				if (relaxed) {					// Add general warning properties					WarningPropertyUtil.addPropertiesForLocation(							warn.propertySet,							classContext,							method,							warn.location);					// Convert warning properties to bug properties					warn.propertySet.decorateBugInstance(warn.instance);				}				bugReporter.reportBug(warn.instance);			}		}		if (best != null && !reportAll) {			bugReporter.reportBug(best.instance);		}	}	private boolean isEqualsMethod(String methodName, String methodSig) {		return (methodName.equals("equals") && methodSig.equals("(Ljava/lang/Object;)Z"))		|| (methodName.equals("equalIgnoreCases") && methodSig.equals("(Ljava/lang/String;)Z"));	}	private void checkRefComparison(			Location location,			JavaClass jclass,			MethodGen methodGen,			RefComparisonTypeFrameModelingVisitor visitor,			TypeDataflow typeDataflow,			List<WarningWithProperties> stringComparisonList,			List<WarningWithProperties> refComparisonList) 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")) {				handleStringComparison(jclass, methodGen, visitor, stringComparisonList, location, lhsType, rhsType);			} else if (suspiciousSet.contains(lhs)) {				handleSuspiciousRefComparison(jclass, methodGen, refComparisonList, location, lhs);			}		}	}	private void handleStringComparison(			JavaClass jclass,			MethodGen methodGen,			RefComparisonTypeFrameModelingVisitor visitor,			List<WarningWithProperties> stringComparisonList,			Location location,			Type lhsType,			Type rhsType) {		if (DEBUG) System.out.println("String/String comparison at " + location.getHandle());		// Compute the priority:		// - two static strings => do not report		// - dynamic string and anything => high		// - static string and unknown => medium		// - all other cases => low		// System.out.println("Compare " + lhsType + " == " + rhsType);		byte type1 = lhsType.getType();		byte type2 = rhsType.getType();		String bugPattern = "ES_COMPARING_STRINGS_WITH_EQ";		// T1 T2 result		// S  S  no-op		// D  ?  high		// ?  D  high		// S  ?  normal		// ?  S  normal		WarningPropertySet propertySet = new WarningPropertySet();		if (type1 == T_STATIC_STRING && type2 == T_STATIC_STRING) {			propertySet.addProperty(RefComparisonWarningProperty.COMPARE_STATIC_STRINGS);		} else if (type1 == T_DYNAMIC_STRING || type2 == T_DYNAMIC_STRING) {			propertySet.addProperty(RefComparisonWarningProperty.DYNAMIC_AND_UNKNOWN);		} else if (type2 == T_PARAMETER_STRING || type1 == T_PARAMETER_STRING) {			bugPattern = "ES_COMPARING_PARAMETER_STRING_WITH_EQ";			if (methodGen.isPublic() || methodGen.isProtected()) propertySet.addProperty(RefComparisonWarningProperty.STRING_PARAMETER_IN_PUBLIC_METHOD);			else propertySet.addProperty(RefComparisonWarningProperty.STRING_PARAMETER);		} else if (type1 == T_STATIC_STRING || type2 == T_STATIC_STRING) {			propertySet.addProperty(RefComparisonWarningProperty.STATIC_AND_UNKNOWN);		} else if (visitor.sawStringIntern()) {			propertySet.addProperty(RefComparisonWarningProperty.SAW_INTERN);		}		String sourceFile = jclass.getSourceFileName();		BugInstance instance =			new BugInstance(this, bugPattern, BASE_ES_PRIORITY)		.addClassAndMethod(methodGen, sourceFile)		.addType("Ljava/lang/String;").describe(TypeAnnotation.FOUND_ROLE)		.addSourceLine(this.classContext, methodGen, sourceFile, location.getHandle());		WarningWithProperties warn = new WarningWithProperties(instance, propertySet, location);		stringComparisonList.add(warn);	}	private void handleSuspiciousRefComparison(			JavaClass jclass,			MethodGen methodGen,			List<WarningWithProperties> refComparisonList,			Location location,			String lhs) {		String sourceFile = jclass.getSourceFileName();		BugInstance instance = new BugInstance(this, "RC_REF_COMPARISON", lhs.equals("java.lang.Boolean") ? NORMAL_PRIORITY : HIGH_PRIORITY)		.addClassAndMethod(methodGen, sourceFile)		.addType("L" + lhs.replace('.', '/')+";").describe(TypeAnnotation.FOUND_ROLE)		.addSourceLine(this.classContext, methodGen, sourceFile, location.getHandle());		refComparisonList.add(new WarningWithProperties(instance, new WarningPropertySet(), location));	}	private static boolean testLikeName(String name) {		return name.toLowerCase().indexOf("test") >= 0;	}	private void checkEqualsComparison(			Location location,			JavaClass jclass,			Method method,			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);		// Ignore top and bottom values		if (lhsType_.getType() == T_TOP || lhsType_.getType() == T_BOTTOM				|| rhsType_.getType() == T_TOP || rhsType_.getType() == T_BOTTOM)			return;		boolean looksLikeTestCase = method.getName().startsWith("test") && method.isPublic() && method.getSignature().equals("()V")				|| testLikeName(jclass.getClassName())|| testLikeName(jclass.getSuperclassName());		int priorityModifier = 0;		if (looksLikeTestCase) priorityModifier = 1;		if (methodGen.getName().startsWith("test") && methodGen.getSignature().equals("()V")) {			try {				if (jclass.getSuperclassName().equals("junit.framework.TestCase") || Hierarchy.isSubtype(methodGen.getClassName(), "junit.framework.TestCase"))					priorityModifier=2;			} catch (ClassNotFoundException e) { 				AnalysisContext.reportMissingClass(e);			}		}		if (!(lhsType_ instanceof ReferenceType) || !(rhsType_ instanceof ReferenceType)) {			if (rhsType_.getType() == T_NULL) {					// A literal null value was passed directly to equals().				if (!looksLikeTestCase)					bugReporter.reportBug(new BugInstance(this, "EC_NULL_ARG", NORMAL_PRIORITY)					.addClassAndMethod(methodGen, sourceFile)					.addSourceLine(this.classContext, 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;		}		if (lhsType_ instanceof ArrayType && rhsType_ instanceof ArrayType)			bugReporter.reportBug(new BugInstance(this, "EC_BAD_ARRAY_COMPARE", NORMAL_PRIORITY)			.addClassAndMethod(methodGen, sourceFile)			.addFoundAndExpectedType(rhsType_.getSignature(), lhsType_.getSignature())			.addSourceLine(this.classContext, methodGen, sourceFile, location.getHandle())			);		IncompatibleTypes result = IncompatibleTypes.getPriorityForAssumingCompatible(lhsType_, rhsType_);				if (result == IncompatibleTypes.ARRAY_AND_NON_ARRAY || result == IncompatibleTypes.ARRAY_AND_OBJECT) 			bugReporter.reportBug(new BugInstance(this, "EC_ARRAY_AND_NONARRAY", result.getPriority())			.addClassAndMethod(methodGen, sourceFile)		 .addFoundAndExpectedType(rhsType_.getSignature(), lhsType_.getSignature())			.addSourceLine(this.classContext, methodGen, sourceFile, location.getHandle())			);		else if (result == IncompatibleTypes.INCOMPATIBLE_CLASSES) {			String lhsSig = lhsType_.getSignature();			String rhsSig = rhsType_.getSignature();			boolean core = lhsSig.startsWith("Ljava") && rhsSig.startsWith("Ljava");			if (core) {				looksLikeTestCase = false;				priorityModifier = 0;			}			if (!looksLikeTestCase) bugReporter.reportBug(new BugInstance(this, "EC_UNRELATED_TYPES", result.getPriority() + priorityModifier)			.addClassAndMethod(methodGen, sourceFile)	.addFoundAndExpectedType(rhsType_.getSignature(), lhsType_.getSignature())					.addSourceLine(this.classContext, methodGen, sourceFile, location.getHandle())			);		}		else if (result == IncompatibleTypes.UNRELATED_CLASS_AND_INTERFACE) 			bugReporter.reportBug(new BugInstance(this, "EC_UNRELATED_CLASS_AND_INTERFACE", result.getPriority())			.addClassAndMethod(methodGen, sourceFile)	  .addFoundAndExpectedType(rhsType_.getSignature(), lhsType_.getSignature())					.addSourceLine(this.classContext, methodGen, sourceFile, location.getHandle())			);		else if (result == IncompatibleTypes.UNRELATED_INTERFACES) 			bugReporter.reportBug(new BugInstance(this, "EC_UNRELATED_INTERFACES", result.getPriority())			.addClassAndMethod(methodGen, sourceFile)	 .addFoundAndExpectedType(rhsType_.getSignature(), lhsType_.getSignature())					.addSourceLine(this.classContext, methodGen, sourceFile, location.getHandle())			);	}	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>() {			@Override			public Dataflow<TypeFrame, TypeAnalysis> createDataflow(ClassContext classContext, Method method)			throws CFGBuilderException, DataflowAnalysisException {				RepositoryLookupFailureCallback lookupFailureCallback =					classContext.getLookupFailureCallback();				MethodGen methodGen = classContext.getMethodGen(method);				if (methodGen == null)					throw new DataflowAnalysisException("Could not get methodGen for " + method.toString());				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(method, 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]);	}	public void report() {		// do nothing	}}//vim:ts=3

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -