📄 findnullderef.java
字号:
} } catch (CFGBuilderException e) { assert true; // ignore it } } if (DEBUG) System.out.println("Target block is " + (empty ? "empty" : "not empty")); if (!empty) { if (isThrower(target)) infeasibleEdgeSimplyThrowsException = true; } if (!empty && !previouslyDeadBlocks.get(target.getId())) { if (DEBUG) System.out.println("target was alive previously"); // Block was not dead before the null pointer analysis. // See if it is dead now by inspecting the null value frame. // If it's TOP, then the block became dead. IsNullValueFrame invFrame = invDataflow.getStartFact(target); createdDeadCode = invFrame.isTop(); if (DEBUG) System.out.println("target is now " + (createdDeadCode ? "dead" : "alive")); } } int priority; boolean valueIsNull = true; String warning; if (redundantBranch.secondValue == null) { if (redundantBranch.firstValue.isDefinitelyNull()) { warning = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"; priority = NORMAL_PRIORITY; } else { warning = "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"; valueIsNull = false; priority = isChecked ? NORMAL_PRIORITY : LOW_PRIORITY; } } else { boolean bothNull = redundantBranch.firstValue.isDefinitelyNull() && redundantBranch.secondValue.isDefinitelyNull(); if (redundantBranch.secondValue.isChecked()) isChecked = true; if (redundantBranch.secondValue.wouldHaveBeenAKaboom()) { wouldHaveBeenAKaboom = true; locationOfKaBoom = redundantBranch.secondValue .getLocationOfKaBoom(); } if (bothNull) { warning = "RCN_REDUNDANT_COMPARISON_TWO_NULL_VALUES"; priority = NORMAL_PRIORITY; } else { warning = "RCN_REDUNDANT_COMPARISON_OF_NULL_AND_NONNULL_VALUE"; priority = isChecked ? NORMAL_PRIORITY : LOW_PRIORITY; } } if (wouldHaveBeenAKaboom) { priority = HIGH_PRIORITY; warning = "RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE"; if (locationOfKaBoom == null) throw new NullPointerException("location of KaBoom is null"); } if (DEBUG) System.out.println(createdDeadCode + " " + infeasibleEdgeSimplyThrowsException + " " + valueIsNull + " " + priority); if (createdDeadCode && !infeasibleEdgeSimplyThrowsException) { priority += 0; } else if (createdDeadCode && infeasibleEdgeSimplyThrowsException) { // throw clause if (valueIsNull) priority += 0; else priority += 1; } else { // didn't create any dead code priority += 1; } if (DEBUG) { System.out.println("RCN" + priority + " " + redundantBranch.firstValue + " =? " + redundantBranch.secondValue + " : " + warning); if (isChecked) System.out.println("isChecked"); if (wouldHaveBeenAKaboom) System.out.println("wouldHaveBeenAKaboom"); if (createdDeadCode) System.out.println("createdDeadCode"); } if (priority > LOW_PRIORITY) return; BugAnnotation variableAnnotation = null; try { // Get the value number ValueNumberFrame vnaFrame = classContext.getValueNumberDataflow( method).getFactAtLocation(location); if (vnaFrame.isValid()) { Instruction ins = location.getHandle().getInstruction(); ValueNumber valueNumber = vnaFrame.getInstance(ins, classContext.getConstantPoolGen()); if (valueNumber.hasFlag(ValueNumber.CONSTANT_CLASS_OBJECT)) return; variableAnnotation = NullDerefAndRedundantComparisonFinder.findAnnotationFromValueNumber(method, location, valueNumber, vnaFrame); } } catch (DataflowAnalysisException e) { // ignore } catch (CFGBuilderException e) { // ignore } BugInstance bugInstance = new BugInstance(this, warning, priority) .addClassAndMethod(classContext.getJavaClass(), method); if (variableAnnotation != null) bugInstance.add(variableAnnotation); else bugInstance.add(new LocalVariableAnnotation("?", -1, -1)); if (wouldHaveBeenAKaboom) bugInstance.addSourceLine(classContext, method, locationOfKaBoom); bugInstance.addSourceLine(classContext, method, location).describe("SOURCE_REDUNDANT_NULL_CHECK"); if (FindBugsAnalysisFeatures.isRelaxedMode()) { WarningPropertySet propertySet = new WarningPropertySet(); WarningPropertyUtil.addPropertiesForLocation(propertySet, classContext, method, location); if (isChecked) propertySet.addProperty(NullDerefProperty.CHECKED_VALUE); if (wouldHaveBeenAKaboom) propertySet .addProperty(NullDerefProperty.WOULD_HAVE_BEEN_A_KABOOM); if (createdDeadCode) propertySet.addProperty(NullDerefProperty.CREATED_DEAD_CODE); propertySet.decorateBugInstance(bugInstance); priority = propertySet.computePriority(NORMAL_PRIORITY); bugInstance.setPriority(priority); } bugReporter.reportBug(bugInstance); } // XXX BugAnnotation getVariableAnnotation(Location location) { BugAnnotation variableAnnotation = null; try { // Get the value number ValueNumberFrame vnaFrame = classContext.getValueNumberDataflow( method).getFactAtLocation(location); if (vnaFrame.isValid()) { Instruction ins = location.getHandle().getInstruction(); ValueNumber valueNumber = vnaFrame.getInstance(ins, classContext.getConstantPoolGen()); if (valueNumber.hasFlag(ValueNumber.CONSTANT_CLASS_OBJECT)) return null; variableAnnotation = NullDerefAndRedundantComparisonFinder.findAnnotationFromValueNumber(method, location, valueNumber, vnaFrame); } } catch (DataflowAnalysisException e) { // ignore } catch (CFGBuilderException e) { // ignore } return variableAnnotation; } /** * Determine whether or not given instruction is a goto. * * @param instruction * the instruction * @return true if the instruction is a goto, false otherwise */ private boolean isGoto(Instruction instruction) { return instruction.getOpcode() == Constants.GOTO || instruction.getOpcode() == Constants.GOTO_W; } /* * (non-Javadoc) * * @see edu.umd.cs.findbugs.ba.npe.NullDerefAndRedundantComparisonCollector#foundGuaranteedNullDeref(java.util.Set, * java.util.Set, edu.umd.cs.findbugs.ba.vna.ValueNumber, boolean) */ public void foundGuaranteedNullDeref(@NonNull Set<Location> assignedNullLocationSet, @NonNull Set<Location> derefLocationSet, SortedSet<Location> doomedLocations, ValueNumberDataflow vna, ValueNumber refValue, BugAnnotation variableAnnotation, NullValueUnconditionalDeref deref, boolean npeIfStatementCovered) { if (refValue.hasFlag(ValueNumber.CONSTANT_CLASS_OBJECT)) return; if (DEBUG) { System.out.println("Found guaranteed null deref in " + method.getName()); for (Location loc : doomedLocations) System.out.println("Doomed at " + loc); } String bugType = "NP_GUARANTEED_DEREF"; int priority = NORMAL_PRIORITY; if (deref.isMethodReturnValue()) bugType = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"; else { if (deref.isAlwaysOnExceptionPath()) bugType += "_ON_EXCEPTION_PATH"; else priority = HIGH_PRIORITY; if (!npeIfStatementCovered) priority++; } // Add Locations in the set of locations at least one of which // is guaranteed to be dereferenced SortedSet<Location> sourceLocations; if (doomedLocations.isEmpty() || doomedLocations.size() > 3 && doomedLocations.size() > assignedNullLocationSet.size()) sourceLocations = new TreeSet<Location>(assignedNullLocationSet); else sourceLocations = doomedLocations; if (doomedLocations.isEmpty() || derefLocationSet.isEmpty()) return; boolean derefOutsideCatchBlock = false; for (Location loc : derefLocationSet) if (!inCatchNullBlock(loc)) { derefOutsideCatchBlock = true; break; } boolean uniqueDereferenceLocations = false; LineNumberTable table = method.getLineNumberTable(); if (table == null) uniqueDereferenceLocations = true; else { BitSet linesMentionedMultipleTimes = ClassContext.linesMentionedMultipleTimes(method); for(Location loc : derefLocationSet) { int lineNumber = table.getSourceLine(loc.getHandle().getPosition()); if (!linesMentionedMultipleTimes.get(lineNumber)) uniqueDereferenceLocations = true; } } if (!derefOutsideCatchBlock) { if (!uniqueDereferenceLocations || skipIfInsideCatchNull()) return; priority++; } if (!uniqueDereferenceLocations) priority++; // Create BugInstance BitSet knownNull = new BitSet(); SortedSet<SourceLineAnnotation> knownNullLocations = new TreeSet<SourceLineAnnotation>(); for (Location loc : sourceLocations) { SourceLineAnnotation sourceLineAnnotation = SourceLineAnnotation .fromVisitedInstruction(classContext, method, loc); if (sourceLineAnnotation == null) continue; int startLine = sourceLineAnnotation.getStartLine(); if (startLine == -1) knownNullLocations.add(sourceLineAnnotation); else if (!knownNull.get(startLine)) { knownNull.set(startLine); knownNullLocations.add(sourceLineAnnotation); } } FieldAnnotation storedField = null; MethodAnnotation invokedMethod = null; int parameterNumber = -1; if (derefLocationSet.size() == 1) { Location loc = derefLocationSet.iterator().next(); PointerUsageRequiringNonNullValue pu = null; try { UsagesRequiringNonNullValues usages = classContext.getUsagesRequiringNonNullValues(method); pu = usages.get(loc, refValue); } catch (DataflowAnalysisException e) { AnalysisContext.logError("Error getting UsagesRequiringNonNullValues for " + method, e); } catch (CFGBuilderException e) { AnalysisContext.logError("Error getting UsagesRequiringNonNullValues for " + method, e); } if (pu != null) { if (pu.getReturnFromNonNullMethod()) { bugType = "NP_NONNULL_RETURN_VIOLATION"; String methodName = method.getName(); String methodSig = method.getSignature(); if (methodName.equals("clone") && methodSig.equals("()Ljava/lang/Object;")) { bugType = "NP_CLONE_COULD_RETURN_NULL"; priority = NORMAL_PRIORITY; } else if (methodName.equals("toString") && methodSig.equals("()Ljava/lang/String;")) { bugType = "NP_TOSTRING_COULD_RETURN_NULL"; priority = NORMAL_PRIORITY; } } else { XField nonNullField = pu.getNonNullField(); if (nonNullField != null) { storedField = FieldAnnotation.fromXField( nonNullField ); bugType = "NP_STORE_INTO_NONNULL_FIELD"; } else { XMethodParameter nonNullParameter = pu.getNonNullParameter(); if (nonNullParameter != null) { XMethodParameter mp = nonNullParameter ; invokedMethod = MethodAnnotation.fromXMethod(mp.getMethod()); parameterNumber = mp.getParameterNumber(); bugType = "NP_NULL_PARAM_DEREF"; } } } } else if (!deref.isAlwaysOnExceptionPath()) bugType = "NP_NULL_ON_SOME_PATH"; else bugType = "NP_NULL_ON_SOME_PATH_EXCEPTION"; if (deref.isMethodReturnValue()) bugType = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"; } BugInstance bugInstance = new BugInstance(this, bugType, priority) .addClassAndMethod(classContext.getJavaClass(), method); if (invokedMethod != null) bugInstance.addMethod(invokedMethod).describe("METHOD_CALLED") .addInt(parameterNumber+1).describe("INT_MAYBE_NULL_ARG"); if (storedField!= null) bugInstance.addField(storedField).describe("FIELD_STORED"); bugInstance.add(variableAnnotation); if (variableAnnotation instanceof FieldAnnotation) bugInstance.describe("FIELD_CONTAINS_VALUE"); for (Location loc : derefLocationSet) bugInstance.addSourceLine(classContext, method, loc).describe(getDescription(loc, refValue)); for (SourceLineAnnotation sourceLineAnnotation : knownNullLocations) bugInstance.add(sourceLineAnnotation).describe( "SOURCE_LINE_KNOWN_NULL"); // If all deref locations are doomed // (i.e., locations where a normal return is not possible), // add a warning property indicating such. // Are all derefs at doomed locations? boolean allDerefsAtDoomedLocations = true; for (Location derefLoc : derefLocationSet) { if (!isDoomed(derefLoc)) { allDerefsAtDoomedLocations = false; break; } } if (allDerefsAtDoomedLocations) { // Add a WarningProperty WarningPropertySet propertySet = new WarningPropertySet(); propertySet.addProperty(DoomedCodeWarningProperty.DOOMED_CODE); propertySet.decorateBugInstance(bugInstance); } // Report it bugReporter.reportBug(bugInstance); } private boolean isDoomed(Location loc) { if (!MARK_DOOMED) { return false; } ReturnPathTypeDataflow rptDataflow; try { rptDataflow = classContext.getReturnPathTypeDataflow(method); ReturnPathType rpt = rptDataflow.getFactAtLocation(loc); return !rpt.canReturnNormally(); } catch (CheckedAnalysisException e) { AnalysisContext.logError("Error getting return path type", e); return false; } } String getDescription(Location loc, ValueNumber refValue) { PointerUsageRequiringNonNullValue pu; try { UsagesRequiringNonNullValues usages = classContext.getUsagesRequiringNonNullValues(method); pu = usages.get(loc, refValue); if (pu == null) return "SOURCE_LINE_DEREF"; return pu.getDescription(); } catch (DataflowAnalysisException e) { AnalysisContext.logError("Error getting UsagesRequiringNonNullValues for " + method, e); return "SOURCE_LINE_DEREF"; } catch (CFGBuilderException e) { AnalysisContext.logError("Error getting UsagesRequiringNonNullValues for " + method, e); return "SOURCE_LINE_DEREF"; } } boolean inCatchNullBlock(Location loc) { int pc = loc.getHandle().getPosition(); int catchSize = Util.getSizeOfSurroundingTryBlock(classContext.getJavaClass().getConstantPool(), method.getCode(), "java/lang/NullPointerException", pc); if (catchSize < Integer.MAX_VALUE) return true; catchSize = Util.getSizeOfSurroundingTryBlock(classContext.getJavaClass().getConstantPool(), method.getCode(), "java/lang/Exception", pc); if (catchSize < 5) return true; catchSize = Util.getSizeOfSurroundingTryBlock(classContext.getJavaClass().getConstantPool(), method.getCode(), "java/lang/RuntimeException", pc); if (catchSize < 5) return true; catchSize = Util.getSizeOfSurroundingTryBlock(classContext.getJavaClass().getConstantPool(), method.getCode(), "java/lang/Throwable", pc); if (catchSize < 5) return true; return false; }}// vim:ts=4
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -