📄 findnullderef.java.mine
字号:
checkNonNullParam(location, cpg, typeDataflow, invokeInstruction, nullArgSet, definitelyNullArgSet); } private void examinePutfieldInstruction(Location location, PUTFIELD ins, ConstantPoolGen cpg) throws DataflowAnalysisException, CFGBuilderException { IsNullValueDataflow invDataflow = classContext.getIsNullValueDataflow(method); IsNullValueFrame frame = invDataflow.getFactAtLocation(location); if (!frame.isValid()) return; IsNullValue tos = frame.getTopValue(); if (tos.mightBeNull()) { XField field = XFactory.createXField(ins, cpg); NullnessAnnotation annotation = AnalysisContext.currentAnalysisContext().getNullnessAnnotationDatabase().getResolvedAnnotation(field, false); if (annotation == NullnessAnnotation.NONNULL) { MethodGen methodGen = classContext.getMethodGen(method); String sourceFile = classContext.getJavaClass().getSourceFileName(); BugInstance warning = new BugInstance("NP_STORE_INTO_NONNULL_FIELD", tos.isDefinitelyNull() ? HIGH_PRIORITY : NORMAL_PRIORITY) .addClassAndMethod(methodGen, sourceFile) .addField(field) .addSourceLine(classContext, methodGen, sourceFile, location.getHandle()); bugReporter.reportBug(warning); } } } 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); if (!frame.isValid()) return; IsNullValue tos = frame.getTopValue(); if (tos.mightBeNull()) { MethodGen methodGen = classContext.getMethodGen(method); String sourceFile = classContext.getJavaClass().getSourceFileName(); 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(bugPattern,priority) .addClassAndMethod(methodGen, sourceFile) .addSourceLine(classContext, methodGen, sourceFile, location.getHandle()); 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(); MethodGen methodGen = classContext.getMethodGen(method); String sourceFile = classContext.getJavaClass().getSourceFileName(); 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 { bugType = "NP_NULL_PARAM_DEREF"; priority = LOW_PRIORITY; } if (caught) priority++; if (dangerousCallTargetList.size() > veryDangerousCallTargetList.size()) priority++; else propertySet.addProperty(NullArgumentWarningProperty.ACTUAL_PARAMETER_GUARANTEED_NULL); BugInstance warning = new BugInstance(bugType, priority) .addClassAndMethod(methodGen, sourceFile) .addMethod(XFactory.createXMethod(invokeInstruction, cpg)).describe("METHOD_CALLED") .addSourceLine(classContext, methodGen, sourceFile, location.getHandle()) ; // Check which params might be null addParamAnnotations(definitelyNullArgSet, unconditionallyDereferencedNullArgSet, propertySet, warning); // Add annotations for dangerous method call targets for (JavaClassAndMethod dangerousCallTarget : veryDangerousCallTargetList) { warning.addMethod(dangerousCallTarget).describe("METHOD_DANGEROUS_TARGET_ACTUAL_GUARANTEED_NULL"); } dangerousCallTargetList.removeAll(veryDangerousCallTargetList);// Add annotations for dangerous method call targets for (JavaClassAndMethod dangerousCallTarget : dangerousCallTargetList) { warning.addMethod(dangerousCallTarget).describe("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("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( BitSet definitelyNullArgSet, BitSet violatedParamSet, WarningPropertySet propertySet, BugInstance warning) { for (int i = 0; i < 32; ++i) { if (violatedParamSet.get(i)) { boolean definitelyNull = definitelyNullArgSet.get(i); if (definitelyNull) { propertySet.addProperty(NullArgumentWarningProperty.ARG_DEFINITELY_NULL); } // 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(); 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); } MethodGen methodGen = classContext.getMethodGen(method); String sourceFile = classContext.getJavaClass().getSourceFileName(); int priority = definitelyNull ? HIGH_PRIORITY : NORMAL_PRIORITY; if (caught) priority++; BugInstance warning = new BugInstance("NP_NONNULL_PARAM_VIOLATION", priority) .addClassAndMethod(methodGen, sourceFile) .addMethod(m).describe("METHOD_CALLED") .addInt(i).describe("INT_NONNULL_PARAM") .addSourceLine(classContext, methodGen, sourceFile, location.getHandle()); 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 = 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.isNullOnSomePath() || duplicated && refValue.isDefinitelyNull()) { String type = "NP_NULL_ON_SOME_PATH"; int priority = NORMAL_PRIORITY; if (caught) priority++; if (onExceptionPath) type = "NP_NULL_ON_SOME_PATH_EXCEPTION"; else if (refValue.isReturnValue()) type = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"; else if (refValue.isParamValue()) { 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); if (type.equals("NP_NULL_ON_SOME_PATH")) return; reportNullDeref(propertySet, classContext, method, location, type, priority, variable); } } /** * @param method TODO * @param location * @param valueNumber * @param vnaFrame * @return */ public static BugAnnotation findAnnotationFromValueNumber(Method method, Location location, ValueNumber valueNumber, ValueNumberFrame vnaFrame) { LocalVariableAnnotation ann = findLocalAnnotationFromValueNumber(method, location, valueNumber, vnaFrame); if (ann != null && ann.isSignificant()) return ann; FieldAnnotation field = findFieldAnnotationFromValueNumber(method, location, valueNumber, vnaFrame); if (field != null) return field; return ann; } public static FieldAnnotation findFieldAnnotationFromValueNumber(Method method, Location location, ValueNumber valueNumber, ValueNumberFrame vnaFrame) { XField field = findXFieldFromValueNumber(method, location, valueNumber, vnaFrame); if (field == null) return null; return FieldAnnotation.fromXField(field); } public static XField findXFieldFromValueNumber(Method method, Location location, ValueNumber valueNumber, ValueNumberFrame vnaFrame) { if (vnaFrame == null || vnaFrame.isBottom() || vnaFrame.isTop()) return null; AvailableLoad load = vnaFrame.getLoad(valueNumber); if (load != null) { return load.getField(); } return null; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -