/** * @param classContext * @param method */ private void analyzeMethod(ClassContext classContext, Method method) throws MethodUnprofitableException, CFGBuilderException, DataflowAnalysisException { if (method.isSynthetic() || (method.getAccessFlags() & Constants.ACC_BRIDGE) == Constants.ACC_BRIDGE) return; CFG cfg = classContext.getCFG(method); TypeDataflow typeDataflow = classContext.getTypeDataflow(method); ConstantPoolGen constantPoolGen = classContext.getConstantPoolGen(); locationLoop: for (Iterator<Location> iter = cfg.locationIterator(); iter.hasNext(); ) { Location location = iter.next(); InstructionHandle handle = location.getHandle(); Instruction ins = handle.getInstruction(); // Only consider invoke instructions if (!(ins instanceof InvokeInstruction)) continue; if (ins instanceof INVOKEINTERFACE) continue; InvokeInstruction inv = (InvokeInstruction) ins; TypeFrame frame = typeDataflow.getFactAtLocation(location); String methodName = inv.getMethodName(constantPoolGen); if (methodName.toLowerCase().indexOf("unsupported") >= 0) continue; String methodSig = inv.getSignature(constantPoolGen); if (methodSig.equals("()Ljava/lang/UnsupportedOperationException;")) continue; Set<XMethod> targets; try { targets = Hierarchy2.resolveMethodCallTargets(inv, frame, constantPoolGen); } catch (ClassNotFoundException e) { AnalysisContext.reportMissingClass(e); continue locationLoop; } if (targets.isEmpty()) continue locationLoop; int priority = targets.size() == 1 ? Priorities.HIGH_PRIORITY : Priorities.NORMAL_PRIORITY; for (XMethod m : targets) { if (!m.isUnsupported()) continue locationLoop; XClass xc = AnalysisContext.currentXFactory().getXClass(m.getClassDescriptor()); if (!(inv instanceof INVOKESTATIC) && !(m.isFinal() || xc.isFinal())) priority = Priorities.NORMAL_PRIORITY; if (xc == null || xc.isAbstract()) { try { if (!AnalysisContext.currentAnalysisContext() .getSubtypes2() .hasSubtypes(m.getClassDescriptor())) continue locationLoop; } catch (ClassNotFoundException e) { AnalysisContext.reportMissingClass(e); continue locationLoop; } } } BugInstance bug = new BugInstance(this, "DMI_UNSUPPORTED_METHOD", priority) .addClassAndMethod(classContext.getJavaClass(), method) .addCalledMethod(constantPoolGen, inv) .addSourceLine(classContext, method, location); bugReporter.reportBug(bug); } }
public static Set<ValueNumber> checkNonNullParams( Location location, ValueNumberFrame vnaFrame, ConstantPoolGen constantPool, @CheckForNull Method method, @CheckForNull IsNullValueFrame invFrame) throws DataflowAnalysisException { if (invFrame != null && !invFrame.isValid()) { return Collections.emptySet(); } INullnessAnnotationDatabase database = AnalysisContext.currentAnalysisContext().getNullnessAnnotationDatabase(); InvokeInstruction inv = (InvokeInstruction) location.getHandle().getInstruction(); XMethod called = XFactory.createXMethod(inv, constantPool); SignatureParser sigParser = new SignatureParser(called.getSignature()); int numParams = sigParser.getNumParameters(); Set<ValueNumber> result = new HashSet<ValueNumber>(); Iterator<String> parameterIterator = sigParser.parameterSignatureIterator(); for (int i = 0; i < numParams; i++) { String parameterSignature = parameterIterator.next(); char firstChar = parameterSignature.charAt(0); if (firstChar != 'L' && firstChar != '[') { continue; } int offset = sigParser.getSlotsFromTopOfStackForParameter(i); if (invFrame != null) { int slot = invFrame.getStackLocation(offset); if (!reportDereference(invFrame, slot)) { continue; } } if (database.parameterMustBeNonNull(called, i)) { int catchSizeNPE = Util.getSizeOfSurroundingTryBlock( method, "java/lang/NullPointerException", location.getHandle().getPosition()); int catchSizeNFE = Util.getSizeOfSurroundingTryBlock( method, "java/lang/NumberFormatException", location.getHandle().getPosition()); if (catchSizeNPE == Integer.MAX_VALUE && (!"java.lang.Integer".equals(called.getClassName()) || catchSizeNFE == Integer.MAX_VALUE)) { // Get the corresponding value number ValueNumber vn = vnaFrame.getArgument(inv, constantPool, i, sigParser); result.add(vn); } } } return result; }
/** * If this is a putfield or putstatic instruction, check to see if the field is @NonNull, and * treat it as dereferences. * * @param location the Location of the instruction * @param vnaFrame the ValueNumberFrame at the Location of the instruction * @param fact the dataflow value to modify * @throws DataflowAnalysisException */ private void checkNonNullPutField( Location location, ValueNumberFrame vnaFrame, UnconditionalValueDerefSet fact) throws DataflowAnalysisException { INullnessAnnotationDatabase database = AnalysisContext.currentAnalysisContext().getNullnessAnnotationDatabase(); FieldInstruction fieldIns = (FieldInstruction) location.getHandle().getInstruction(); XField field = XFactory.createXField(fieldIns, methodGen.getConstantPool()); char firstChar = field.getSignature().charAt(0); if (firstChar != 'L' && firstChar != '[') { return; } NullnessAnnotation resolvedAnnotation = database.getResolvedAnnotation(field, true); if (resolvedAnnotation == NullnessAnnotation.NONNULL) { IsNullValueFrame invFrame = invDataflow.getFactAtLocation(location); if (!invFrame.isValid()) { return; } IsNullValue value = invFrame.getTopValue(); if (reportDereference(value)) { ValueNumber vn = vnaFrame.getTopValue(); fact.addDeref(vn, location); } } }
public static LocalVariableAnnotation getLocalVariableAnnotation( Method method, Location location, IndexedInstruction ins) { int local = ins.getIndex(); InstructionHandle handle = location.getHandle(); int position1 = handle.getNext().getPosition(); int position2 = handle.getPosition(); return getLocalVariableAnnotation(method, local, position1, position2); }
private void analyzeMethod( ClassContext classContext, Method method, Collection<InjectionSource> selectedSources) throws DataflowAnalysisException, CheckedAnalysisException { TaintDataflow dataflow = getTaintDataFlow(classContext, method); ConstantPoolGen cpg = classContext.getConstantPoolGen(); String currentMethod = getFullMethodName(classContext.getMethodGen(method)); for (Iterator<Location> i = getLocationIterator(classContext, method); i.hasNext(); ) { Location location = i.next(); InstructionHandle handle = location.getHandle(); Instruction instruction = handle.getInstruction(); if (!(instruction instanceof InvokeInstruction)) { continue; } InvokeInstruction invoke = (InvokeInstruction) instruction; TaintFrame fact = dataflow.getFactAtLocation(location); assert fact != null; if (!fact.isValid()) { continue; } SourceLineAnnotation sourceLine = SourceLineAnnotation.fromVisitedInstruction(classContext, method, handle); checkTaintSink(getFullMethodName(cpg, invoke), fact, sourceLine, currentMethod); InjectionPoint injectionPoint = getInjectionPoint(invoke, cpg, handle, selectedSources); for (int offset : injectionPoint.getInjectableArguments()) { Taint parameterTaint = fact.getStackValue(offset); int priority = getPriority(parameterTaint); if (priority == Priorities.IGNORE_PRIORITY) { continue; } BugInstance bugInstance = new BugInstance(this, injectionPoint.getBugType(), priority); bugInstance.addClassAndMethod(classContext.getJavaClass(), method); bugInstance.addSourceLine(sourceLine); if (injectionPoint.getInjectableMethod() != null) { bugInstance.addString(injectionPoint.getInjectableMethod()); } reportBug(bugInstance, parameterTaint, currentMethod); } } }
/** * Check to see if the instruction has a null check associated with it, and if so, add a * dereference. * * @param location the Location of the instruction * @param vnaFrame ValueNumberFrame at the Location of the instruction * @param fact the dataflow value to modify * @throws DataflowAnalysisException */ private void checkInstance( Location location, ValueNumberFrame vnaFrame, UnconditionalValueDerefSet fact) throws DataflowAnalysisException { // See if this instruction has a null check. // If it does, the fall through predecessor will be // identify itself as the null check. if (!location.isFirstInstructionInBasicBlock()) { return; } if (invDataflow == null) { return; } BasicBlock fallThroughPredecessor = cfg.getPredecessorWithEdgeType(location.getBasicBlock(), EdgeTypes.FALL_THROUGH_EDGE); if (fallThroughPredecessor == null || !fallThroughPredecessor.isNullCheck()) { return; } // Get the null-checked value ValueNumber vn = vnaFrame.getInstance(location.getHandle().getInstruction(), methodGen.getConstantPool()); // Ignore dereferences of this if (!methodGen.isStatic()) { ValueNumber v = vnaFrame.getValue(0); if (v.equals(vn)) { return; } } if (vn.hasFlag(ValueNumber.CONSTANT_CLASS_OBJECT)) { return; } IsNullValueFrame startFact = null; startFact = invDataflow.getStartFact(fallThroughPredecessor); if (!startFact.isValid()) { return; } int slot = startFact.getInstanceSlot( location.getHandle().getInstruction(), methodGen.getConstantPool()); if (!reportDereference(startFact, slot)) { return; } if (DEBUG) { System.out.println("FOUND GUARANTEED DEREFERENCE"); System.out.println("Load: " + vnaFrame.getLoad(vn)); System.out.println("Pred: " + fallThroughPredecessor); System.out.println("startFact: " + startFact); System.out.println("Location: " + location); System.out.println("Value number frame: " + vnaFrame); System.out.println("Dereferenced valueNumber: " + vn); System.out.println("invDataflow: " + startFact); System.out.println("IGNORE_DEREF_OF_NCP: " + IGNORE_DEREF_OF_NCP); } // Mark the value number as being dereferenced at this location fact.addDeref(vn, location); }
public static Set<ValueNumber> checkUnconditionalDerefDatabase( Location location, ValueNumberFrame vnaFrame, ConstantPoolGen constantPool, @CheckForNull IsNullValueFrame invFrame, TypeDataflow typeDataflow) throws DataflowAnalysisException { if (invFrame != null && !invFrame.isValid()) { return Collections.emptySet(); } InvokeInstruction inv = (InvokeInstruction) location.getHandle().getInstruction(); SignatureParser sigParser = new SignatureParser(inv.getSignature(constantPool)); int numParams = sigParser.getNumParameters(); if (numParams == 0 || !sigParser.hasReferenceParameters()) { return Collections.emptySet(); } ParameterNullnessPropertyDatabase database = AnalysisContext.currentAnalysisContext().getUnconditionalDerefParamDatabase(); if (database == null) { if (DEBUG_CHECK_CALLS) { System.out.println("no database!"); } return Collections.emptySet(); } TypeFrame typeFrame = typeDataflow.getFactAtLocation(location); if (!typeFrame.isValid()) { if (DEBUG_CHECK_CALLS) { System.out.println("invalid type frame!"); } return Collections.emptySet(); } try { Set<XMethod> targetSet = Hierarchy2.resolveMethodCallTargets(inv, typeFrame, constantPool); if (targetSet.isEmpty()) { return Collections.emptySet(); } if (DEBUG_CHECK_CALLS) { System.out.println("target set size: " + targetSet.size()); } // Compute the intersection of all properties ParameterProperty derefParamSet = null; for (XMethod target : targetSet) { if (target.isStub()) { continue; } if (DEBUG_CHECK_CALLS) { System.out.print("Checking: " + target + ": "); } ParameterProperty targetDerefParamSet = database.getProperty(target.getMethodDescriptor()); if (targetDerefParamSet == null) { // Hmm...no information for this target. // assume it doesn't dereference anything if (DEBUG_CHECK_CALLS) { System.out.println("==> no information, assume no guaranteed dereferences"); } return Collections.emptySet(); } if (DEBUG_CHECK_CALLS) { System.out.println("==> " + targetDerefParamSet); } if (derefParamSet == null) { derefParamSet = new ParameterProperty(); derefParamSet.copyFrom(targetDerefParamSet); } else { derefParamSet.intersectWith(targetDerefParamSet); } } if (derefParamSet == null || derefParamSet.isEmpty()) { if (DEBUG) { System.out.println("** Nothing"); } return Collections.emptySet(); } if (DEBUG_CHECK_CALLS) { System.out.println( "** Summary of call @ " + location.getHandle().getPosition() + ": " + derefParamSet); } HashSet<ValueNumber> requiredToBeNonnull = new HashSet<ValueNumber>(); for (int i = 0; i < numParams; i++) { if (!derefParamSet.hasProperty(i)) { continue; } int argSlot = vnaFrame.getStackLocation(sigParser.getSlotsFromTopOfStackForParameter(i)); if (invFrame != null && !reportDereference(invFrame, argSlot)) { continue; } if (DEBUG_CHECK_CALLS) { System.out.println( " dereference @ " + location.getHandle().getPosition() + " of parameter " + i); } requiredToBeNonnull.add(vnaFrame.getValue(argSlot)); } return requiredToBeNonnull; } catch (ClassNotFoundException e) { AnalysisContext.reportMissingClass(e); } return Collections.emptySet(); }
private void analyzeMethod(ClassContext classContext, Method method) throws CFGBuilderException, DataflowAnalysisException { if (isSynthetic(method) || !prescreen(classContext, method)) return; XMethod xmethod = XFactory.createXMethod(classContext.getJavaClass(), method); if (xmethod.isSynthetic()) return; BugAccumulator accumulator = new BugAccumulator(bugReporter); CFG cfg = classContext.getCFG(method); TypeDataflow typeDataflow = classContext.getTypeDataflow(method); ValueNumberDataflow vnDataflow = classContext.getValueNumberDataflow(method); ConstantPoolGen cpg = classContext.getConstantPoolGen(); MethodGen methodGen = classContext.getMethodGen(method); if (methodGen == null) return; String fullMethodName = methodGen.getClassName() + "." + methodGen.getName(); String sourceFile = classContext.getJavaClass().getSourceFileName(); if (DEBUG) { System.out.println("\n" + fullMethodName); } // Process each instruction for (Iterator<Location> iter = cfg.locationIterator(); iter.hasNext(); ) { Location location = iter.next(); InstructionHandle handle = location.getHandle(); Instruction ins = handle.getInstruction(); // Only consider invoke instructions if (!(ins instanceof InvokeInstruction)) continue; InvokeInstruction inv = (InvokeInstruction) ins; XMethod invokedMethod = XFactory.createXMethod(inv, cpg); String invokedMethodName = invokedMethod.getName(); String argSignature = invokedMethod.getSignature(); argSignature = argSignature.substring(0, argSignature.indexOf(')') + 1); String call = invokedMethodName + argSignature; SignatureParser sigParser = new SignatureParser(inv.getSignature(cpg)); Collection<Info> collection = callMap.get(call); if (!callMap.containsKey(call)) continue; for (Info info : collection) { Subtypes2 subtypes2 = AnalysisContext.currentAnalysisContext().getSubtypes2(); if (DEBUG) System.out.println( "at " + handle.getPosition() + " Checking call to " + info.interfaceForCall + " : " + invokedMethod); try { if (!subtypes2.isSubtype(invokedMethod.getClassDescriptor(), info.interfaceForCall)) continue; } catch (ClassNotFoundException e) { if (info.interfaceForCall.getClassName().equals("java/util/Collection") && invokedMethod.getClassName().equals("com.google.common.collect.Multiset")) { assert true; // we know this is OK without needing to find definition of Multiset } else { AnalysisContext.reportMissingClass(e); continue; } } boolean allMethod; int typeArgument; if (info.typeIndex >= 0) { allMethod = false; typeArgument = info.typeIndex; } else { allMethod = true; typeArgument = -(1 + info.typeIndex); } int pos = info.argumentIndex; int lhsPos; if (inv instanceof INVOKESTATIC) lhsPos = sigParser.getSlotsFromTopOfStackForParameter(0); else lhsPos = sigParser.getTotalArgumentSize(); int stackPos = sigParser.getSlotsFromTopOfStackForParameter(pos); TypeFrame frame = typeDataflow.getFactAtLocation(location); if (!frame.isValid()) { // This basic block is probably dead continue; } Type operandType = frame.getStackValue(stackPos); if (operandType.equals(TopType.instance())) { // unreachable continue; } if (operandType.equals(NullType.instance())) { // ignore continue; } ValueNumberFrame vnFrame = vnDataflow.getFactAtLocation(location); if (!vnFrame.isValid()) { AnalysisContext.logError("Invalid value number frame in " + xmethod); continue; } ValueNumber objectVN = vnFrame.getStackValue(lhsPos); ValueNumber argVN = vnFrame.getStackValue(stackPos); if (objectVN.equals(argVN)) { String bugPattern = "DMI_COLLECTIONS_SHOULD_NOT_CONTAIN_THEMSELVES"; int priority = HIGH_PRIORITY; if (invokedMethodName.equals("removeAll")) { bugPattern = "DMI_USING_REMOVEALL_TO_CLEAR_COLLECTION"; priority = NORMAL_PRIORITY; } else if (invokedMethodName.endsWith("All")) { bugPattern = "DMI_VACUOUS_SELF_COLLECTION_CALL"; priority = NORMAL_PRIORITY; } if (invokedMethodName.startsWith("contains")) { InstructionHandle next = handle.getNext(); if (next != null) { Instruction nextIns = next.getInstruction(); if (nextIns instanceof InvokeInstruction) { XMethod nextMethod = XFactory.createXMethod((InvokeInstruction) nextIns, cpg); if (nextMethod.getName().equals("assertFalse")) continue; } } } accumulator.accumulateBug( new BugInstance(this, bugPattern, priority) .addClassAndMethod(methodGen, sourceFile) .addCalledMethod(methodGen, (InvokeInstruction) ins) .addOptionalAnnotation( ValueNumberSourceInfo.findAnnotationFromValueNumber( method, location, objectVN, vnFrame, "INVOKED_ON")), SourceLineAnnotation.fromVisitedInstruction( classContext, methodGen, sourceFile, handle)); } // Only consider generic... Type objectType = frame.getStackValue(lhsPos); if (!(objectType instanceof GenericObjectType)) continue; GenericObjectType operand = (GenericObjectType) objectType; int expectedTypeParameters = 1; String simpleName = info.interfaceForCall.getSimpleName(); if (simpleName.toLowerCase().endsWith("map") || simpleName.equals("Hashtable")) expectedTypeParameters = 2; else if (simpleName.equals("Table")) expectedTypeParameters = 3; // ... containers if (!operand.hasParameters()) continue; if (operand.getNumParameters() != expectedTypeParameters) continue; ClassDescriptor operandClass = DescriptorFactory.getClassDescriptor(operand); if (!isGenericCollection(operandClass)) continue; if (expectedTypeParameters == 2 && Subtypes2.instanceOf(operandClass, Map.class) && !TypeFrameModelingVisitor.isStraightGenericMap(operandClass)) continue; Type expectedType; if (allMethod) expectedType = operand; else expectedType = operand.getParameterAt(typeArgument); Type actualType = frame.getStackValue(stackPos); Type equalsType = actualType; if (allMethod) { if (!(actualType instanceof GenericObjectType)) { continue; } equalsType = ((GenericObjectType) actualType).getParameterAt(typeArgument); } IncompatibleTypes matchResult = compareTypes(expectedType, actualType, allMethod); boolean parmIsObject = expectedType.getSignature().equals("Ljava/lang/Object;"); boolean selfOperation = !allMethod && operand.equals(actualType) && !parmIsObject; if (!allMethod && !parmIsObject && actualType instanceof GenericObjectType) { GenericObjectType p2 = (GenericObjectType) actualType; List<? extends ReferenceType> parameters = p2.getParameters(); if (parameters != null && parameters.equals(operand.getParameters())) selfOperation = true; } if (!selfOperation && (matchResult == IncompatibleTypes.SEEMS_OK || matchResult.getPriority() == Priorities.IGNORE_PRIORITY)) continue; if (invokedMethodName.startsWith("contains") || invokedMethodName.equals("remove")) { InstructionHandle next = handle.getNext(); if (next != null) { Instruction nextIns = next.getInstruction(); if (nextIns instanceof InvokeInstruction) { XMethod nextMethod = XFactory.createXMethod((InvokeInstruction) nextIns, cpg); if (nextMethod.getName().equals("assertFalse")) continue; } } } else if (invokedMethodName.equals("get") || invokedMethodName.equals("remove")) { InstructionHandle next = handle.getNext(); if (next != null) { Instruction nextIns = next.getInstruction(); if (nextIns instanceof InvokeInstruction) { XMethod nextMethod = XFactory.createXMethod((InvokeInstruction) nextIns, cpg); if (nextMethod.getName().equals("assertNull")) continue; } } } boolean noisy = false; if (invokedMethodName.equals("get")) { UnconditionalValueDerefDataflow unconditionalValueDerefDataflow = classContext.getUnconditionalValueDerefDataflow(method); UnconditionalValueDerefSet unconditionalDeref = unconditionalValueDerefDataflow.getFactAtLocation(location); ValueNumberFrame vnAfter = vnDataflow.getFactAfterLocation(location); ValueNumber top = vnAfter.getTopValue(); noisy = unconditionalDeref.getValueNumbersThatAreUnconditionallyDereferenced().contains(top); } // Prepare bug report SourceLineAnnotation sourceLineAnnotation = SourceLineAnnotation.fromVisitedInstruction( classContext, methodGen, sourceFile, handle); // Report a bug that mentions each of the failed arguments in // matches if (expectedType instanceof GenericObjectType) expectedType = ((GenericObjectType) expectedType).getUpperBound(); int priority = matchResult.getPriority(); if (!operandClass.getClassName().startsWith("java/util") && priority == Priorities.HIGH_PRIORITY) priority = Math.max(priority, Priorities.NORMAL_PRIORITY); if (TestCaseDetector.likelyTestCase(xmethod)) priority = Math.max(priority, Priorities.NORMAL_PRIORITY); else if (selfOperation) priority = Priorities.HIGH_PRIORITY; ClassDescriptor expectedClassDescriptor = DescriptorFactory.createClassOrObjectDescriptorFromSignature( expectedType.getSignature()); ClassDescriptor actualClassDescriptor = DescriptorFactory.createClassOrObjectDescriptorFromSignature(equalsType.getSignature()); ClassSummary classSummary = AnalysisContext.currentAnalysisContext().getClassSummary(); Set<XMethod> targets = null; try { targets = Hierarchy2.resolveVirtualMethodCallTargets( actualClassDescriptor, "equals", "(Ljava/lang/Object;)Z", false, false); boolean allOk = targets.size() > 0; for (XMethod m2 : targets) if (!classSummary.mightBeEqualTo(m2.getClassDescriptor(), expectedClassDescriptor)) allOk = false; if (allOk) priority += 2; } catch (ClassNotFoundException e) { AnalysisContext.reportMissingClass(e); } String bugPattern = "GC_UNRELATED_TYPES"; BugInstance bug = new BugInstance(this, bugPattern, priority) .addClassAndMethod(methodGen, sourceFile) .addFoundAndExpectedType(actualType, expectedType) .addCalledMethod(methodGen, (InvokeInstruction) ins) .addOptionalAnnotation( ValueNumberSourceInfo.findAnnotationFromValueNumber( method, location, objectVN, vnFrame, "INVOKED_ON")) .addOptionalAnnotation( ValueNumberSourceInfo.findAnnotationFromValueNumber( method, location, argVN, vnFrame, "ARGUMENT")) .addEqualsMethodUsed(targets); if (noisy) { WarningPropertySet<WarningProperty> propertySet = new WarningPropertySet<WarningProperty>(); propertySet.addProperty(GeneralWarningProperty.NOISY_BUG); propertySet.decorateBugInstance(bug); } accumulator.accumulateBug(bug, sourceLineAnnotation); } } accumulator.reportAccumulatedBugs(); }