📄 findnullderef.java
字号:
} } private void examineReturnInstruction(Location location) throws DataflowAnalysisException, CFGBuilderException { if (DEBUG_NULLRETURN) { System.out.println("Checking null return at " + location); } IsNullValueDataflow invDataflow = classContext .getIsNullValueDataflow(method); IsNullValueFrame frame = invDataflow.getFactAtLocation(location); ValueNumberFrame vnaFrame = classContext.getValueNumberDataflow(method).getFactAtLocation(location); if (!vnaFrame.isValid()) return; ValueNumber valueNumber = vnaFrame.getTopValue(); if (!frame.isValid()) return; IsNullValue tos = frame.getTopValue(); if (tos.isDefinitelyNull()) { BugAnnotation variable = NullDerefAndRedundantComparisonFinder.findAnnotationFromValueNumber(method, location, valueNumber, vnaFrame); String bugPattern = "NP_NONNULL_RETURN_VIOLATION"; int priority = NORMAL_PRIORITY; if (tos.isDefinitelyNull() && !tos.isException()) priority = HIGH_PRIORITY; String methodName = method.getName(); if (methodName.equals("clone")) { bugPattern = "NP_CLONE_COULD_RETURN_NULL"; priority = NORMAL_PRIORITY; } else if (methodName.equals("toString")) { bugPattern = "NP_TOSTRING_COULD_RETURN_NULL"; priority = NORMAL_PRIORITY; } BugInstance warning = new BugInstance(this, bugPattern, priority) .addClassAndMethod(classContext.getJavaClass(), method).addOptionalAnnotation(variable).addSourceLine( classContext, method, location); bugReporter.reportBug(warning); } } private void checkUnconditionallyDereferencedParam(Location location, ConstantPoolGen cpg, TypeDataflow typeDataflow, InvokeInstruction invokeInstruction, BitSet nullArgSet, BitSet definitelyNullArgSet) throws DataflowAnalysisException, ClassNotFoundException { boolean caught = inCatchNullBlock(location); if (caught && skipIfInsideCatchNull()) return; // See what methods might be called here TypeFrame typeFrame = typeDataflow.getFactAtLocation(location); Set<JavaClassAndMethod> targetMethodSet = Hierarchy .resolveMethodCallTargets(invokeInstruction, typeFrame, cpg); if (DEBUG_NULLARG) { System.out.println("Possibly called methods: " + targetMethodSet); } // See if any call targets unconditionally dereference one of the null // arguments BitSet unconditionallyDereferencedNullArgSet = new BitSet(); List<JavaClassAndMethod> dangerousCallTargetList = new LinkedList<JavaClassAndMethod>(); List<JavaClassAndMethod> veryDangerousCallTargetList = new LinkedList<JavaClassAndMethod>(); for (JavaClassAndMethod targetMethod : targetMethodSet) { if (DEBUG_NULLARG) { System.out.println("For target method " + targetMethod); } ParameterNullnessProperty property = unconditionalDerefParamDatabase .getProperty(targetMethod.toXMethod()); if (property == null) continue; if (DEBUG_NULLARG) { System.out.println("\tUnconditionally dereferenced params: " + property); } BitSet targetUnconditionallyDereferencedNullArgSet = property .getViolatedParamSet(nullArgSet); if (targetUnconditionallyDereferencedNullArgSet.isEmpty()) continue; dangerousCallTargetList.add(targetMethod); unconditionallyDereferencedNullArgSet .or(targetUnconditionallyDereferencedNullArgSet); if (!property.getViolatedParamSet(definitelyNullArgSet).isEmpty()) veryDangerousCallTargetList.add(targetMethod); } if (dangerousCallTargetList.isEmpty()) return; WarningPropertySet propertySet = new WarningPropertySet(); // See if there are any safe targets Set<JavaClassAndMethod> safeCallTargetSet = new HashSet<JavaClassAndMethod>(); safeCallTargetSet.addAll(targetMethodSet); safeCallTargetSet.removeAll(dangerousCallTargetList); if (safeCallTargetSet.isEmpty()) { propertySet .addProperty(NullArgumentWarningProperty.ALL_DANGEROUS_TARGETS); if (dangerousCallTargetList.size() == 1) { propertySet .addProperty(NullArgumentWarningProperty.MONOMORPHIC_CALL_SITE); } } // Call to private method? In theory there should be only one possible // target. boolean privateCall = safeCallTargetSet.isEmpty() && dangerousCallTargetList.size() == 1 && dangerousCallTargetList.get(0).getMethod().isPrivate(); String bugType; int priority; if (privateCall || invokeInstruction.getOpcode() == Constants.INVOKESTATIC || invokeInstruction.getOpcode() == Constants.INVOKESPECIAL) { bugType = "NP_NULL_PARAM_DEREF_NONVIRTUAL"; priority = HIGH_PRIORITY; } else if (safeCallTargetSet.isEmpty()) { bugType = "NP_NULL_PARAM_DEREF_ALL_TARGETS_DANGEROUS"; priority = NORMAL_PRIORITY; } else { return; } if (caught) priority++; if (dangerousCallTargetList.size() > veryDangerousCallTargetList.size()) priority++; else propertySet .addProperty(NullArgumentWarningProperty.ACTUAL_PARAMETER_GUARANTEED_NULL); BugInstance warning = new BugInstance(this,bugType, priority) .addClassAndMethod(classContext.getJavaClass(), method).addMethod( XFactory.createXMethod(invokeInstruction, cpg)) .describe("METHOD_CALLED").addSourceLine(classContext, method, location); // Check which params might be null addParamAnnotations(location, definitelyNullArgSet, unconditionallyDereferencedNullArgSet, propertySet, warning); if (bugType.equals("NP_NULL_PARAM_DEREF_ALL_TARGETS_DANGEROUS")) { // Add annotations for dangerous method call targets for (JavaClassAndMethod dangerousCallTarget : veryDangerousCallTargetList) { warning.addMethod(dangerousCallTarget).describe( MethodAnnotation.METHOD_DANGEROUS_TARGET_ACTUAL_GUARANTEED_NULL); } dangerousCallTargetList.removeAll(veryDangerousCallTargetList); if (DEBUG_NULLARG) { // Add annotations for dangerous method call targets for (JavaClassAndMethod dangerousCallTarget : dangerousCallTargetList) { warning.addMethod(dangerousCallTarget).describe( MethodAnnotation.METHOD_DANGEROUS_TARGET); } // Add safe method call targets. // This is useful to see which other call targets the analysis // considered. for (JavaClassAndMethod safeMethod : safeCallTargetSet) { warning.addMethod(safeMethod).describe(MethodAnnotation.METHOD_SAFE_TARGET); } }} decorateWarning(location, propertySet, warning); bugReporter.reportBug(warning); } private void decorateWarning(Location location, WarningPropertySet propertySet, BugInstance warning) { if (FindBugsAnalysisFeatures.isRelaxedMode()) { WarningPropertyUtil.addPropertiesForLocation(propertySet, classContext, method, location); } propertySet.decorateBugInstance(warning); } private void addParamAnnotations(Location location, BitSet definitelyNullArgSet, BitSet violatedParamSet, WarningPropertySet propertySet, BugInstance warning) { ValueNumberFrame vnaFrame = null; try { vnaFrame = classContext.getValueNumberDataflow(method).getFactAtLocation(location); } catch (DataflowAnalysisException e) { AnalysisContext.logError("error", e); } catch (CFGBuilderException e) { AnalysisContext.logError("error", e); } InvokeInstruction instruction = (InvokeInstruction) location.getHandle().getInstruction(); SignatureParser sigParser = new SignatureParser(instruction.getSignature(classContext.getConstantPoolGen())); for (int i = violatedParamSet.nextSetBit(0); i >= 0; i = violatedParamSet.nextSetBit(i + 1)) { boolean definitelyNull = definitelyNullArgSet.get(i); if (definitelyNull) propertySet .addProperty(NullArgumentWarningProperty.ARG_DEFINITELY_NULL); ValueNumber valueNumber = null; if (vnaFrame != null) try { valueNumber = vnaFrame. getArgument(instruction, classContext.getConstantPoolGen(), i, sigParser ); BugAnnotation variableAnnotation = NullDerefAndRedundantComparisonFinder.findAnnotationFromValueNumber(method, location, valueNumber, vnaFrame); warning.addOptionalAnnotation(variableAnnotation); } catch (DataflowAnalysisException e) { AnalysisContext.logError("error", e); } // Note: we report params as being indexed starting from 1, not // 0 warning.addInt(i + 1).describe( definitelyNull ? "INT_NULL_ARG" : "INT_MAYBE_NULL_ARG"); } } /** * We have a method invocation in which a possibly or definitely null * parameter is passed. Check it against the library of nonnull annotations. * * @param location * @param cpg * @param typeDataflow * @param invokeInstruction * @param nullArgSet * @param definitelyNullArgSet * @throws ClassNotFoundException */ private void checkNonNullParam(Location location, ConstantPoolGen cpg, TypeDataflow typeDataflow, InvokeInstruction invokeInstruction, BitSet nullArgSet, BitSet definitelyNullArgSet) throws ClassNotFoundException { boolean caught = inCatchNullBlock(location); if (caught && skipIfInsideCatchNull()) return; XMethod m = XFactory.createXMethod(invokeInstruction, cpg); NullnessAnnotationDatabase db = AnalysisContext .currentAnalysisContext().getNullnessAnnotationDatabase(); SignatureParser sigParser = new SignatureParser(invokeInstruction.getSignature(cpg)); for (int i = nullArgSet.nextSetBit(0); i >= 0; i = nullArgSet .nextSetBit(i + 1)) { if (db.parameterMustBeNonNull(m, i)) { boolean definitelyNull = definitelyNullArgSet.get(i); if (DEBUG_NULLARG) { System.out.println("QQQ2: " + i + " -- " + i + " is null"); System.out.println("QQQ nullArgSet: " + nullArgSet); System.out.println("QQQ dnullArgSet: " + definitelyNullArgSet); } BugAnnotation variableAnnotation = null; try { ValueNumberFrame vnaFrame = classContext.getValueNumberDataflow(method).getFactAtLocation(location); ValueNumber valueNumber = vnaFrame. getArgument(invokeInstruction, cpg, i, sigParser ); variableAnnotation = NullDerefAndRedundantComparisonFinder.findAnnotationFromValueNumber(method, location, valueNumber, vnaFrame); } catch (DataflowAnalysisException e) { AnalysisContext.logError("error", e); } catch (CFGBuilderException e) { AnalysisContext.logError("error", e); } int priority = definitelyNull ? HIGH_PRIORITY : NORMAL_PRIORITY; if (caught) priority++; String description = definitelyNull ? "INT_NULL_ARG" : "INT_MAYBE_NULL_ARG"; BugInstance warning = new BugInstance(this, "NP_NONNULL_PARAM_VIOLATION", priority) .addClassAndMethod(classContext.getJavaClass(), method).addMethod(m) .describe("METHOD_CALLED").addInt(i+1).describe( description).addOptionalAnnotation(variableAnnotation).addSourceLine( classContext, method, location); bugReporter.reportBug(warning); } } } public void report() { } public boolean skipIfInsideCatchNull() { return classContext.getJavaClass().getClassName().indexOf("Test") >= 0 || method.getName().indexOf("test") >= 0 || method.getName().indexOf("Test") >= 0; } public void foundNullDeref(ClassContext classContext, Location location, ValueNumber valueNumber, IsNullValue refValue, ValueNumberFrame vnaFrame) { WarningPropertySet propertySet = new WarningPropertySet(); if (valueNumber.hasFlag(ValueNumber.CONSTANT_CLASS_OBJECT)) return; boolean onExceptionPath = refValue.isException(); if (onExceptionPath) { propertySet.addProperty(GeneralWarningProperty.ON_EXCEPTION_PATH); } int pc = location.getHandle().getPosition(); BugAnnotation variable = NullDerefAndRedundantComparisonFinder.findAnnotationFromValueNumber(method, location, valueNumber, vnaFrame); boolean duplicated = false; try { CFG cfg = classContext.getCFG(method); duplicated = cfg.getLocationsContainingInstructionWithOffset(pc) .size() > 1; } catch (CFGBuilderException e) { } boolean caught = inCatchNullBlock(location); if (caught && skipIfInsideCatchNull()) return; if (!duplicated && refValue.isDefinitelyNull()) { String type = onExceptionPath ? "NP_ALWAYS_NULL_EXCEPTION" : "NP_ALWAYS_NULL"; int priority = onExceptionPath ? NORMAL_PRIORITY : HIGH_PRIORITY; if (caught) priority++; reportNullDeref(propertySet, classContext, method, location, type, priority, variable); } else if (refValue.mightBeNull() && refValue.isParamValue()) { String type; int priority = NORMAL_PRIORITY; if (caught) priority++; if (method.getName().equals("equals") && method.getSignature() .equals("(Ljava/lang/Object;)Z")) { if (caught) return; type = "NP_EQUALS_SHOULD_HANDLE_NULL_ARGUMENT"; } else type = "NP_ARGUMENT_MIGHT_BE_NULL"; if (DEBUG) System.out.println("Reporting null on some path: value=" + refValue); reportNullDeref(propertySet, classContext, method, location, type, priority, variable); } } private void reportNullDeref(WarningPropertySet propertySet, ClassContext classContext, Method method, Location location, String type, int priority, BugAnnotation variable) { BugInstance bugInstance = new BugInstance(this, type, priority) .addClassAndMethod(classContext.getJavaClass(), method); if (variable != null) bugInstance.add(variable); else bugInstance.add(new LocalVariableAnnotation("?", -1, -1)); bugInstance.addSourceLine(classContext, method, location).describe("SOURCE_LINE_DEREF"); if (FindBugsAnalysisFeatures.isRelaxedMode()) { WarningPropertyUtil.addPropertiesForLocation(propertySet, classContext, method, location); } if (isDoomed(location)) { // Add a WarningProperty propertySet.addProperty(DoomedCodeWarningProperty.DOOMED_CODE); } propertySet.decorateBugInstance(bugInstance); bugReporter.reportBug(bugInstance); } public static boolean isThrower(BasicBlock target) { InstructionHandle ins = target.getFirstInstruction(); int maxCount = 7; while (ins != null) { if (maxCount-- <= 0) break; Instruction i = ins.getInstruction(); if (i instanceof ATHROW) { return true; } if (i instanceof InstructionTargeter || i instanceof ReturnInstruction) return false; ins = ins.getNext(); } return false; } public void foundRedundantNullCheck(Location location, RedundantBranch redundantBranch) { boolean isChecked = redundantBranch.firstValue.isChecked(); boolean wouldHaveBeenAKaboom = redundantBranch.firstValue .wouldHaveBeenAKaboom(); Location locationOfKaBoom = redundantBranch.firstValue .getLocationOfKaBoom(); boolean createdDeadCode = false; boolean infeasibleEdgeSimplyThrowsException = false; Edge infeasibleEdge = redundantBranch.infeasibleEdge; if (infeasibleEdge != null) { if (DEBUG) System.out.println("Check if " + redundantBranch + " creates dead code"); BasicBlock target = infeasibleEdge.getTarget(); if (DEBUG) System.out.println("Target block is " + (target.isExceptionThrower() ? " exception thrower" : " not exception thrower")); // If the block is empty, it probably doesn't matter that it was // killed. // FIXME: really, we should crawl the immediately reachable blocks // starting at the target block to see if any of them are dead and // nonempty. boolean empty = !target.isExceptionThrower() && (target.isEmpty() || isGoto(target.getFirstInstruction() .getInstruction())); if (!empty) { try { if (classContext.getCFG(method).getNumIncomingEdges(target) > 1) { if (DEBUG) System.out .println("Target of infeasible edge has multiple incoming edges"); empty = true;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -