📄 findnullderef.java.mine
字号:
public static LocalVariableAnnotation findLocalAnnotationFromValueNumber(Method method, Location location, ValueNumber valueNumber, ValueNumberFrame vnaFrame) { if (vnaFrame == null || vnaFrame.isBottom() || vnaFrame.isTop()) return null; LocalVariableAnnotation localAnnotation = null; for(int i = 0; i < vnaFrame.getNumLocals(); i++) { if (valueNumber.equals(vnaFrame.getValue(i))) { if (DEBUG) System.out.println("Found it in local " + i); InstructionHandle handle = location.getHandle(); int position1 = handle.getPrev().getPosition(); int position2 = handle.getPosition(); localAnnotation = LocalVariableAnnotation.getLocalVariableAnnotation(method, i, position1, position2); if (localAnnotation != null) return localAnnotation; } } return null; } private void reportNullDeref( WarningPropertySet propertySet, ClassContext classContext, Method method, Location location, String type, int priority, BugAnnotation variable) { MethodGen methodGen = classContext.getMethodGen(method); String sourceFile = classContext.getJavaClass().getSourceFileName(); BugInstance bugInstance = new BugInstance(this, type, priority) .addClassAndMethod(methodGen, sourceFile); if (variable != null) bugInstance.add(variable); else bugInstance.add(new LocalVariableAnnotation("?",-1,-1)); bugInstance.addSourceLine(classContext, methodGen, sourceFile, location.getHandle()).describe("SOURCE_LINE_DEREF"); if (FindBugsAnalysisFeatures.isRelaxedMode()) { WarningPropertyUtil.addPropertiesForLocation(propertySet, classContext, method, location); 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) { String sourceFile = classContext.getJavaClass().getSourceFileName(); MethodGen methodGen = classContext.getMethodGen(method); 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; }} 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"); } 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 = findAnnotationFromValueNumber(method, location, valueNumber, vnaFrame); } } catch (DataflowAnalysisException e) { // ignore } catch (CFGBuilderException e) { // ignore } BugInstance bugInstance = new BugInstance(this, warning, priority) .addClassAndMethod(methodGen, sourceFile); if (variableAnnotation != null) bugInstance.add(variableAnnotation); else bugInstance.add(new LocalVariableAnnotation("?", -1, -1)); if (wouldHaveBeenAKaboom) bugInstance.addSourceLine(classContext, methodGen, sourceFile, locationOfKaBoom.getHandle()); bugInstance.addSourceLine(classContext, methodGen, sourceFile, location.getHandle()).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); } /** * 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, boolean alwaysOnExceptionPath, boolean npeIfStatementCovered, boolean npeOnlyOnNonExceptionPaths) { 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"; if (npeOnlyOnNonExceptionPaths) bugType += "_OR_EXCEPTION"; if (alwaysOnExceptionPath) bugType += "_ON_EXCEPTION_PATH"; int priority = alwaysOnExceptionPath ? NORMAL_PRIORITY : HIGH_PRIORITY; if (!npeIfStatementCovered) priority++; // Add Locations in the set of locations at least one of which // is guaranteed to be dereferenced TreeSet<Location> sortedDerefLocationSet = new TreeSet<Location>(derefLocationSet); SortedSet<Location> sourceLocations; if (doomedLocations.isEmpty()) sourceLocations= new TreeSet<Location>(assignedNullLocationSet); else sourceLocations = doomedLocations; if (doomedLocations.isEmpty() || sortedDerefLocationSet.isEmpty()) return; boolean derefOutsideCatchBlock = false; for (Location loc : sortedDerefLocationSet) if (!inCatchNullBlock(loc)) { derefOutsideCatchBlock = true; break; } if (!derefOutsideCatchBlock) { if (skipIfInsideCatchNull()) return; priority++; } BugAnnotation variableAnnotation = null; try { for (Location loc : sourceLocations) { variableAnnotation = findAnnotationFromValueNumber(method, loc, refValue, vna.getFactAtLocation(loc)); if (variableAnnotation != null) break; } if (variableAnnotation == null) for (Location loc : sortedDerefLocationSet) { variableAnnotation = findAnnotationFromValueNumber(method, loc, refValue, vna.getFactAtLocation(loc)); if (variableAnnotation != null) break; } } catch (DataflowAnalysisException e) { } if (variableAnnotation == null) variableAnnotation = new LocalVariableAnnotation("?",-1,-1);// Create BugInstance BugInstance bugInstance = new BugInstance(this, bugType, priority) .addClassAndMethod(classContext.getJavaClass(), method); bugInstance.add(variableAnnotation); BitSet knownNull = new BitSet(); SortedSet<SourceLineAnnotation> knownNullLocations = new TreeSet<SourceLineAnnotation>(); for (Location loc : sourceLocations) { SourceLineAnnotation sourceLineAnnotation = SourceLineAnnotation.fromVisitedInstruction(classContext, classContext.getMethodGen(method), classContext.getJavaClass().getSourceFileName(), loc.getHandle()); 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); } } for(SourceLineAnnotation sourceLineAnnotation : knownNullLocations) bugInstance.add(sourceLineAnnotation).describe("SOURCE_LINE_KNOWN_NULL"); for (Location loc : sortedDerefLocationSet) { bugInstance.addSourceLine(classContext, method, loc).describe("SOURCE_LINE_DEREF"); } System.out.println("XXX GNPE: " + assignedNullLocationSet.size() + " " + doomedLocations.size() + " " + knownNullLocations.size() + " " + sortedDerefLocationSet.size()); if (knownNullLocations.size() > 1 || sortedDerefLocationSet.size() > 1) System.out.println(bugInstance.getMessage()); // Report it bugReporter.reportBug(bugInstance); } boolean inCatchNullBlock(Location loc) { int pc = loc.getHandle().getPosition(); int catchSize = Util.getSizeOfSurroundingTryBlock(classContext.getConstantPoolGen().getConstantPool(), method.getCode(), "java/lang/NullPointerException", pc); if ( catchSize < Integer.MAX_VALUE) return true; catchSize = Util.getSizeOfSurroundingTryBlock(classContext.getConstantPoolGen().getConstantPool(), method.getCode(), "java/lang/Exception", pc); if ( catchSize < 5) return true; catchSize = Util.getSizeOfSurroundingTryBlock(classContext.getConstantPoolGen().getConstantPool(), method.getCode(), "java/lang/RuntimeException", pc); if ( catchSize < 5) return true; catchSize = Util.getSizeOfSurroundingTryBlock(classContext.getConstantPoolGen().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 + -