📄 isnullvalueanalysis.java
字号:
/* * Bytecode Analysis Framework * Copyright (C) 2003,2004 University of Maryland * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */package edu.umd.cs.findbugs.ba;import java.util.*;import org.apache.bcel.Constants;import org.apache.bcel.classfile.Method;import org.apache.bcel.generic.*;/** * A dataflow analysis to detect potential null pointer dereferences. * * @author David Hovemeyer * @see IsNullValue * @see IsNullValueFrame * @see IsNullValueFrameModelingVisitor */public class IsNullValueAnalysis extends FrameDataflowAnalysis<IsNullValue, IsNullValueFrame> implements EdgeTypes { private static final boolean DEBUG = Boolean.getBoolean("inva.debug"); static { if (DEBUG) System.out.println("Debug enabled"); } private static final boolean NO_SPLIT_DOWNGRADE_NSP = Boolean.getBoolean("inva.noSplitDowngradeNSP"); private static final boolean NO_SWITCH_DEFAULT_AS_EXCEPTION = Boolean.getBoolean("inva.noSwitchDefaultAsException"); /** * If this property is true, then we assume parameters * and return values can be null (but aren't definitely null). */ static final boolean UNKNOWN_VALUES_ARE_NSP = Boolean.getBoolean("findbugs.nullderef.assumensp"); private MethodGen methodGen; private IsNullValueFrameModelingVisitor visitor; private ValueNumberDataflow vnaDataflow; private int[] numNonExceptionSuccessorMap; private IsNullValueFrame lastFrame; public IsNullValueAnalysis(MethodGen methodGen, CFG cfg, ValueNumberDataflow vnaDataflow, DepthFirstSearch dfs, AssertionMethods assertionMethods) { super(dfs); this.methodGen = methodGen; this.visitor = new IsNullValueFrameModelingVisitor(methodGen.getConstantPool(), assertionMethods); this.vnaDataflow = vnaDataflow; this.numNonExceptionSuccessorMap = new int[cfg.getNumBasicBlocks()]; // For each basic block, calculate the number of non-exception successors. Iterator<Edge> i = cfg.edgeIterator(); while (i.hasNext()) { Edge edge = i.next(); if (edge.isExceptionEdge()) continue; int srcBlockId = edge.getSource().getId(); numNonExceptionSuccessorMap[srcBlockId]++; } } public IsNullValueFrame createFact() { return new IsNullValueFrame(methodGen.getMaxLocals()); } public void initEntryFact(IsNullValueFrame result) { result.setValid(); int numLocals = methodGen.getMaxLocals(); boolean instanceMethod = !methodGen.isStatic(); for (int i = 0; i < numLocals; ++i) { IsNullValue paramValue; if (UNKNOWN_VALUES_ARE_NSP && !(instanceMethod && i == 0)) paramValue = IsNullValue.nullOnSomePathValue(); else paramValue = IsNullValue.nonReportingNotNullValue(); result.setValue(i, paramValue); } }/* // FIXME: because of a bug in the 2.2 generics-enabled javac, // we can't override this method. Javac doesn't emit the needed // bridge method. public void transfer(BasicBlock basicBlock, InstructionHandle end, IsNullValueFrame start, IsNullValueFrame result) throws DataflowAnalysisException { lastFrame = null; super.transfer(basicBlock, end, start, result); // Determine if this basic block ends in a redundant branch. if (end == null) { if (lastFrame == null) result.setDecision(null); else { IsNullConditionDecision decision = getDecision(basicBlock, lastFrame); result.setDecision(decision); } } }*/ // FIXME: This is a workaround for the generics-java bug. public void startTransfer(BasicBlock basicBlock, Object start_) throws DataflowAnalysisException { lastFrame = null; } // FIXME: This is a workaround for the generics-java bug. public void endTransfer(BasicBlock basicBlock, InstructionHandle end, Object result_) throws DataflowAnalysisException { IsNullValueFrame result = (IsNullValueFrame) result_; // Determine if this basic block ends in a redundant branch. if (end == null) { if (lastFrame == null) result.setDecision(null); else { IsNullConditionDecision decision = getDecision(basicBlock, lastFrame); if (DEBUG) System.out.println("Decision=" + decision); result.setDecision(decision); } } } public void transferInstruction(InstructionHandle handle, BasicBlock basicBlock, IsNullValueFrame fact) throws DataflowAnalysisException { // If this is the last instruction in the block, // save the result immediately before the instruction. if (handle == basicBlock.getLastInstruction()) { lastFrame = createFact(); lastFrame.copyFrom(fact); } // Model the instruction visitor.setFrame(fact); Instruction ins = handle.getInstruction(); ins.accept(visitor); // Special case: // The instruction may have produced previously seen values // about which new is-null information is known. // If any other instances of the produced values exist, // update their is-null information. int numProduced = ins.produceStack(methodGen.getConstantPool()); if (numProduced == Constants.UNPREDICTABLE) throw new AnalysisException("Unpredictable stack production", methodGen, handle); int start = fact.getNumSlots() - numProduced; ValueNumberFrame vnaFrameAfter = vnaDataflow.getFactAfterLocation(new Location(handle, basicBlock)); for (int i = start; i < fact.getNumSlots(); ++i) { ValueNumber value = vnaFrameAfter.getValue(i); IsNullValue isNullValue = fact.getValue(i); for (int j = 0; j < start; ++j) { ValueNumber otherValue = vnaFrameAfter.getValue(j); if (value.equals(otherValue)) { // Same value is in both slots. // Update the is-null information to match // the new information. fact.setValue(j, isNullValue); } } } } private static final BitSet nullComparisonInstructionSet = new BitSet(); static { nullComparisonInstructionSet.set(Constants.IFNULL); nullComparisonInstructionSet.set(Constants.IFNONNULL); nullComparisonInstructionSet.set(Constants.IF_ACMPEQ); nullComparisonInstructionSet.set(Constants.IF_ACMPNE); } public void meetInto(IsNullValueFrame fact, Edge edge, IsNullValueFrame result) throws DataflowAnalysisException { if (fact.isValid()) { IsNullValueFrame tmpFact = null; final int numSlots = fact.getNumSlots(); if (!NO_SPLIT_DOWNGRADE_NSP) { // Downgrade NSP to DNR on non-exception control splits if (!edge.isExceptionEdge() && numNonExceptionSuccessorMap[edge.getSource().getId()] > 1) { tmpFact = modifyFrame(fact, tmpFact); for (int i = 0; i < numSlots; ++i) { IsNullValue value = tmpFact.getValue(i); if (value.equals(IsNullValue.nullOnSomePathValue())) tmpFact.setValue(i, IsNullValue.nonReportingNullOnSomePathValue()); } } } if (!NO_SWITCH_DEFAULT_AS_EXCEPTION) { if (edge.getType() == SWITCH_DEFAULT_EDGE) { tmpFact = modifyFrame(fact, tmpFact); tmpFact.toExceptionValues(); } } final BasicBlock destBlock = edge.getTarget(); if (destBlock.isExceptionHandler()) { // Exception handler - clear stack and push a non-null value // to represent the exception. tmpFact = modifyFrame(fact, tmpFact); tmpFact.clearStack(); // Downgrade NULL and NSP to DNR if the handler is for // CloneNotSupportedException or InterruptedException CodeExceptionGen handler = destBlock.getExceptionGen(); ObjectType catchType = handler.getCatchType(); if (catchType != null) { String catchClass = catchType.getClassName(); if (catchClass.equals("java.lang.CloneNotSupportedException") || catchClass.equals("java.lang.InterruptedException")) { for (int i = 0; i < tmpFact.getNumSlots(); ++i) { IsNullValue value = tmpFact.getValue(i); if (value.isDefinitelyNull() || value.isNullOnSomePath()) tmpFact.setValue(i, IsNullValue.nonReportingNullOnSomePathValue()); } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -