📄 unconditionalvaluederefanalysis.java
字号:
/* * FindBugs - Find Bugs in Java programs * Copyright (C) 2006, 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.deref;import java.util.Set;import org.apache.bcel.classfile.Method;import org.apache.bcel.generic.ARETURN;import org.apache.bcel.generic.FieldInstruction;import org.apache.bcel.generic.Instruction;import org.apache.bcel.generic.InstructionHandle;import org.apache.bcel.generic.InvokeInstruction;import org.apache.bcel.generic.MethodGen;import org.apache.bcel.generic.PUTFIELD;import org.apache.bcel.generic.PUTSTATIC;import edu.umd.cs.findbugs.SystemProperties;import edu.umd.cs.findbugs.annotations.CheckForNull;import edu.umd.cs.findbugs.ba.AnalysisContext;import edu.umd.cs.findbugs.ba.AssertionMethods;import edu.umd.cs.findbugs.ba.BackwardDataflowAnalysis;import edu.umd.cs.findbugs.ba.BasicBlock;import edu.umd.cs.findbugs.ba.CFG;import edu.umd.cs.findbugs.ba.CFGBuilderException;import edu.umd.cs.findbugs.ba.ClassContext;import edu.umd.cs.findbugs.ba.Dataflow;import edu.umd.cs.findbugs.ba.DataflowAnalysisException;import edu.umd.cs.findbugs.ba.DataflowTestDriver;import edu.umd.cs.findbugs.ba.DepthFirstSearch;import edu.umd.cs.findbugs.ba.Edge;import edu.umd.cs.findbugs.ba.EdgeTypes;import edu.umd.cs.findbugs.ba.Hierarchy;import edu.umd.cs.findbugs.ba.JavaClassAndMethod;import edu.umd.cs.findbugs.ba.Location;import edu.umd.cs.findbugs.ba.NullnessAnnotation;import edu.umd.cs.findbugs.ba.NullnessAnnotationDatabase;import edu.umd.cs.findbugs.ba.ReverseDepthFirstSearch;import edu.umd.cs.findbugs.ba.SignatureParser;import edu.umd.cs.findbugs.ba.XFactory;import edu.umd.cs.findbugs.ba.XField;import edu.umd.cs.findbugs.ba.XMethod;import edu.umd.cs.findbugs.ba.npe.IsNullConditionDecision;import edu.umd.cs.findbugs.ba.npe.IsNullValue;import edu.umd.cs.findbugs.ba.npe.IsNullValueDataflow;import edu.umd.cs.findbugs.ba.npe.IsNullValueFrame;import edu.umd.cs.findbugs.ba.npe.ParameterNullnessProperty;import edu.umd.cs.findbugs.ba.npe.ParameterNullnessPropertyDatabase;import edu.umd.cs.findbugs.ba.type.TypeDataflow;import edu.umd.cs.findbugs.ba.type.TypeFrame;import edu.umd.cs.findbugs.ba.vna.AvailableLoad;import edu.umd.cs.findbugs.ba.vna.ValueNumber;import edu.umd.cs.findbugs.ba.vna.ValueNumberDataflow;import edu.umd.cs.findbugs.ba.vna.ValueNumberFrame;/** * Dataflow analysis to find values unconditionally derefenced in the future. * * @author David Hovemeyer */public class UnconditionalValueDerefAnalysis extends BackwardDataflowAnalysis<UnconditionalValueDerefSet> { public static final boolean DEBUG = SystemProperties.getBoolean("fnd.derefs.debug"); public static final boolean ASSUME_NONZERO_TRIP_LOOPS = SystemProperties.getBoolean("fnd.derefs.nonzerotrip"); public static final boolean IGNORE_DEREF_OF_NCP = SystemProperties.getBoolean("fnd.derefs.ignoreNCP", false); public static final boolean CHECK_ANNOTATIONS = SystemProperties.getBoolean("fnd.derefs.checkannotations", true); public static final boolean CHECK_CALLS = SystemProperties.getBoolean("fnd.derefs.checkcalls", true); public static final boolean DEBUG_CHECK_CALLS = SystemProperties.getBoolean("fnd.derefs.checkcalls.debug"); private CFG cfg; private final Method method; private MethodGen methodGen; private ValueNumberDataflow vnaDataflow; private AssertionMethods assertionMethods; private IsNullValueDataflow invDataflow; private TypeDataflow typeDataflow; /** * Constructor. * * @param rdfs the reverse depth-first-search (for the block order) * @param dfs TODO * @param cfg the CFG for the method * @param method TODO * @param methodGen the MethodGen for the method * @param vnaDataflow * @param assertionMethods AssertionMethods for the analyzed class */ public UnconditionalValueDerefAnalysis( ReverseDepthFirstSearch rdfs, DepthFirstSearch dfs, CFG cfg, Method method, MethodGen methodGen, ValueNumberDataflow vnaDataflow, AssertionMethods assertionMethods ) { super(rdfs, dfs); this.cfg = cfg; this.methodGen = methodGen; this.method = method; this.vnaDataflow = vnaDataflow; this.assertionMethods = assertionMethods; if (DEBUG) { System.out.println("UnconditionalValueDerefAnalysis analysis " + methodGen.getClassName() + "." + methodGen.getName() + " : " + methodGen.getSignature()); } } /** * HACK: use the given is-null dataflow to clear deref sets for * values that are known to be definitely non-null on a branch. * * @param invDataflow the IsNullValueDataflow to use */ public void clearDerefsOnNonNullBranches(IsNullValueDataflow invDataflow) { this.invDataflow = invDataflow; } /** * * */ public void setTypeDataflow(TypeDataflow typeDataflow) { this.typeDataflow= typeDataflow; } /* (non-Javadoc) * @see edu.umd.cs.findbugs.ba.AbstractDataflowAnalysis#isFactValid(java.lang.Object) */ @Override public boolean isFactValid(UnconditionalValueDerefSet fact) { return !fact.isTop() && !fact.isBottom(); } /* (non-Javadoc) * @see edu.umd.cs.findbugs.ba.AbstractDataflowAnalysis#transferInstruction(org.apache.bcel.generic.InstructionHandle, edu.umd.cs.findbugs.ba.BasicBlock, java.lang.Object) */ @Override public void transferInstruction(InstructionHandle handle, BasicBlock basicBlock, UnconditionalValueDerefSet fact) throws DataflowAnalysisException { Instruction instruction = handle.getInstruction(); if (false && DEBUG) { System.out.println("XXX: " + handle.getPosition() + " " + instruction); } if (fact.isTop()) return; Location location = new Location(handle, basicBlock); // If this is a call to an assertion method, // change the dataflow value to be TOP. // We don't want to report future derefs that would // be guaranteed only if the assertion methods // returns normally. // TODO: at some point, evaluate whether we should revisit this if (isAssertion(handle) // || handle.getInstruction() instanceof ATHROW ) { if (DEBUG) System.out.println("MAKING BOTTOM0 AT: " + location); fact.clear(); return; } // Get value number frame ValueNumberFrame vnaFrame = vnaDataflow.getFactAtLocation(location); if (!vnaFrame.isValid()) { if (DEBUG) System.out.println("MAKING TOP1 AT: " + location); // Probably dead code. // Assume this location can't be reached. makeFactTop(fact); return; } // Check for calls to a method that unconditionally dereferences // a parameter. Mark any such arguments as derefs. if (CHECK_CALLS && instruction instanceof InvokeInstruction) { checkUnconditionalDerefDatabase(location, vnaFrame, fact); } // If this is a method call instruction, // check to see if any of the parameters are @NonNull, // and treat them as dereferences. if (CHECK_ANNOTATIONS && instruction instanceof InvokeInstruction) { checkNonNullParams(location, vnaFrame, fact); } if (CHECK_ANNOTATIONS && instruction instanceof ARETURN) { XMethod thisMethod = XFactory.createXMethod(methodGen); checkNonNullReturnValue(thisMethod, location, vnaFrame, fact); } if (CHECK_ANNOTATIONS && (instruction instanceof PUTFIELD || instruction instanceof PUTSTATIC)) { checkNonNullPutField(location, vnaFrame, fact); } // Check to see if an instance value is dereferenced here checkInstance(location, vnaFrame, fact); if (false) fact.cleanDerefSet(location, vnaFrame); if (DEBUG && fact.isTop()) System.out.println("MAKING TOP2 At: " + location); } /** * Check method call at given location to see if it unconditionally * dereferences a parameter. Mark any such arguments as derefs. * * @param location the Location of the method call * @param vnaFrame ValueNumberFrame at the Location * @param fact the dataflow value to modify * @throws DataflowAnalysisException */ private void checkUnconditionalDerefDatabase( Location location, ValueNumberFrame vnaFrame, UnconditionalValueDerefSet fact) throws DataflowAnalysisException { InvokeInstruction inv = (InvokeInstruction) location.getHandle().getInstruction(); SignatureParser sigParser = new SignatureParser(inv.getSignature(methodGen.getConstantPool())); int numParams = sigParser.getNumParameters(); if (numParams == 0) return; ParameterNullnessPropertyDatabase database = AnalysisContext.currentAnalysisContext().getUnconditionalDerefParamDatabase(); if (database == null) { if (DEBUG_CHECK_CALLS) System.out.println("no database!"); return; } TypeFrame typeFrame = typeDataflow.getFactAtLocation(location); if (!typeFrame.isValid()) { if (DEBUG_CHECK_CALLS) System.out.println("invalid type frame!"); return; } try { Set<JavaClassAndMethod> targetSet = Hierarchy.resolveMethodCallTargets( inv, typeFrame, methodGen.getConstantPool()); if (targetSet.isEmpty()) return; if (DEBUG_CHECK_CALLS) System.out.println("target set size: " + targetSet.size()); // Compute the intersection of all properties ParameterNullnessProperty derefParamSet = null; for (JavaClassAndMethod target : targetSet) { if (DEBUG_CHECK_CALLS) System.out.print("Checking: " + target + ": "); ParameterNullnessProperty targetDerefParamSet = database.getProperty(target.toXMethod()); if (targetDerefParamSet == null) { // Hmm...no information for this target. // assume it doesn't dereference anything if (DEBUG_CHECK_CALLS) System.out.println("==> no information, assume no guaranteed dereferences"); return; } if (DEBUG_CHECK_CALLS) { System.out.println("==> " + targetDerefParamSet); } if (derefParamSet == null) { derefParamSet = new ParameterNullnessProperty(); derefParamSet.copyFrom(targetDerefParamSet); } else { derefParamSet.intersectWith(targetDerefParamSet); } } if (derefParamSet == null || derefParamSet.isEmpty()) { if (DEBUG) System.out.println("** Nothing"); return; } if (DEBUG_CHECK_CALLS) { System.out.println("** Summary of call @ " + location.getHandle().getPosition() + ": " + derefParamSet); } IsNullValueFrame invFrame = invDataflow.getFactAtLocation(location); if (invFrame != null && invFrame.isValid()) { for (int i = 0; i < numParams; i++) { if (!derefParamSet.isNonNull(i)) { continue; } int argSlot = vnaFrame.getStackLocation(sigParser.getSlotsFromTopOfStackForParameter(i)); if (!reportDereference(invFrame, argSlot)) continue; if (DEBUG_CHECK_CALLS) System.out.println(" dereference @ " + location.getHandle().getPosition() + " of parameter " + i); fact.addDeref(vnaFrame.getValue(argSlot), location); } } } catch (ClassNotFoundException e) { AnalysisContext.reportMissingClass(e); } } public static final boolean VERBOSE_NULLARG_DEBUG = SystemProperties.getBoolean("fnd.debug.nullarg.verbose"); /** * If this is a method call instruction, * check to see if any of the parameters are @NonNull, * and treat them as dereferences. * @param thisMethod TODO * @param location the Location of the instruction * @param vnaFrame the ValueNumberFrame at the Location of the instruction * @param fact the dataflow value to modify * * @throws DataflowAnalysisException */ private void checkNonNullReturnValue(XMethod thisMethod, Location location, ValueNumberFrame vnaFrame, UnconditionalValueDerefSet fact) throws DataflowAnalysisException { NullnessAnnotationDatabase database = AnalysisContext.currentAnalysisContext().getNullnessAnnotationDatabase(); if (database == null) { return; } IsNullValueFrame invFrame = invDataflow.getFactAtLocation(location); if (!invFrame.isValid()) return; if (database.getResolvedAnnotation(thisMethod, true) != NullnessAnnotation.NONNULL) return; IsNullValue value = invFrame.getTopValue(); if (value.isDefinitelyNotNull()) return; if (value.isDefinitelyNull()) return; ValueNumber vn = vnaFrame.getTopValue(); if (true) fact.addDeref(vn, location); } /** * If this is a putfield or putstatic instruction, * check to see if the field is @NonNull, * and treat it as dereferences. * * @param location the Location of the instruction * @param vnaFrame the ValueNumberFrame at the Location of the instruction * @param fact the dataflow value to modify * @throws DataflowAnalysisException */ private void checkNonNullPutField(Location location, ValueNumberFrame vnaFrame, UnconditionalValueDerefSet fact) throws DataflowAnalysisException { NullnessAnnotationDatabase database = AnalysisContext.currentAnalysisContext().getNullnessAnnotationDatabase(); if (database == null) { return; } FieldInstruction fieldIns = (FieldInstruction) location.getHandle().getInstruction(); XField field = XFactory.createXField(fieldIns, methodGen.getConstantPool()); char firstChar = field.getSignature().charAt(0); if (firstChar != 'L' && firstChar != '[') return; NullnessAnnotation resolvedAnnotation = database.getResolvedAnnotation(field, true); if (resolvedAnnotation == NullnessAnnotation.NONNULL) { IsNullValueFrame invFrame = invDataflow.getFactAtLocation(location); if (!invFrame.isValid()) return; IsNullValue value = invFrame.getTopValue(); if (reportDereference(value) ) { ValueNumber vn = vnaFrame.getTopValue(); fact.addDeref(vn, location); } } } /** * If this is a method call instruction, * check to see if any of the parameters are @NonNull, * and treat them as dereferences. * * @param location the Location of the instruction * @param vnaFrame the ValueNumberFrame at the Location of the instruction * @param fact the dataflow value to modify * @throws DataflowAnalysisException */ private void checkNonNullParams(Location location, ValueNumberFrame vnaFrame, UnconditionalValueDerefSet fact) throws DataflowAnalysisException { NullnessAnnotationDatabase database = AnalysisContext.currentAnalysisContext().getNullnessAnnotationDatabase(); if (database == null) { return; } InvokeInstruction inv = (InvokeInstruction) location.getHandle().getInstruction();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -