001: /*
002: * FindBugs - Find Bugs in Java programs
003: * Copyright (C) 2006, University of Maryland
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019:
020: package edu.umd.cs.findbugs.ba.npe;
021:
022: import java.util.BitSet;
023: import java.util.Iterator;
024: import java.util.Set;
025:
026: import org.apache.bcel.classfile.Method;
027: import org.apache.bcel.generic.ARETURN;
028: import org.apache.bcel.generic.ConstantPoolGen;
029: import org.apache.bcel.generic.FieldInstruction;
030: import org.apache.bcel.generic.Instruction;
031: import org.apache.bcel.generic.InstructionHandle;
032: import org.apache.bcel.generic.InvokeInstruction;
033: import org.apache.bcel.generic.PUTFIELD;
034: import org.apache.bcel.generic.PUTSTATIC;
035:
036: import edu.umd.cs.findbugs.SystemProperties;
037: import edu.umd.cs.findbugs.ba.AnalysisContext;
038: import edu.umd.cs.findbugs.ba.BasicBlock;
039: import edu.umd.cs.findbugs.ba.CFG;
040: import edu.umd.cs.findbugs.ba.CFGBuilderException;
041: import edu.umd.cs.findbugs.ba.ClassContext;
042: import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
043: import edu.umd.cs.findbugs.ba.Hierarchy;
044: import edu.umd.cs.findbugs.ba.INullnessAnnotationDatabase;
045: import edu.umd.cs.findbugs.ba.JavaClassAndMethod;
046: import edu.umd.cs.findbugs.ba.Location;
047: import edu.umd.cs.findbugs.ba.NullnessAnnotation;
048: import edu.umd.cs.findbugs.ba.SignatureParser;
049: import edu.umd.cs.findbugs.ba.XFactory;
050: import edu.umd.cs.findbugs.ba.XField;
051: import edu.umd.cs.findbugs.ba.XMethod;
052: import edu.umd.cs.findbugs.ba.type.TypeDataflow;
053: import edu.umd.cs.findbugs.ba.type.TypeFrame;
054: import edu.umd.cs.findbugs.ba.vna.ValueNumber;
055: import edu.umd.cs.findbugs.ba.vna.ValueNumberDataflow;
056: import edu.umd.cs.findbugs.ba.vna.ValueNumberFrame;
057:
058: /**
059: * @author pugh
060: */
061: public class DerefFinder {
062:
063: public static boolean DEBUG = SystemProperties
064: .getBoolean("deref.finder.debug");
065:
066: public static UsagesRequiringNonNullValues getAnalysis(
067: ClassContext classContext, Method method) {
068: XMethod this Method = classContext.getXClass().findMethod(
069: method.getName(), method.getSignature(),
070: method.isStatic());
071: if (DEBUG)
072: System.out.println(this Method);
073: UsagesRequiringNonNullValues derefs = new UsagesRequiringNonNullValues();
074: try {
075:
076: CFG cfg = classContext.getCFG(method);
077:
078: ValueNumberDataflow vna = classContext
079: .getValueNumberDataflow(method);
080: TypeDataflow typeDataflow = classContext
081: .getTypeDataflow(method);
082: INullnessAnnotationDatabase db = AnalysisContext
083: .currentAnalysisContext()
084: .getNullnessAnnotationDatabase();
085:
086: ParameterNullnessPropertyDatabase unconditionalDerefParamDatabase = AnalysisContext
087: .currentAnalysisContext()
088: .getUnconditionalDerefParamDatabase();
089: Iterator<BasicBlock> bbIter = cfg.blockIterator();
090: ConstantPoolGen cpg = classContext.getConstantPoolGen();
091: ValueNumber valueNumberForThis = null;
092: if (!method.isStatic()) {
093: ValueNumberFrame frameAtEntry = vna.getStartFact(cfg
094: .getEntry());
095: valueNumberForThis = frameAtEntry.getValue(0);
096: }
097:
098: NullnessAnnotation methodAnnotation = getMethodNullnessAnnotation(
099: classContext, method);
100:
101: while (bbIter.hasNext()) {
102: BasicBlock basicBlock = bbIter.next();
103:
104: if (basicBlock.isNullCheck()) {
105: InstructionHandle exceptionThrowerHandle = basicBlock
106: .getExceptionThrower();
107: Instruction exceptionThrower = exceptionThrowerHandle
108: .getInstruction();
109: ValueNumberFrame vnaFrame = vna
110: .getStartFact(basicBlock);
111: if (!vnaFrame.isValid())
112: continue;
113: ValueNumber valueNumber = vnaFrame.getInstance(
114: exceptionThrower, cpg);
115:
116: Location location = new Location(
117: exceptionThrowerHandle, basicBlock);
118: if (valueNumberForThis != valueNumber)
119: derefs.add(location, valueNumber,
120: PointerUsageRequiringNonNullValue
121: .getPointerDereference());
122:
123: }
124: }
125:
126: for (Iterator<Location> i = cfg.locationIterator(); i
127: .hasNext();) {
128: Location location = i.next();
129: InstructionHandle handle = location.getHandle();
130: Instruction ins = handle.getInstruction();
131: ValueNumberFrame valueNumberFrame = vna
132: .getFactAtLocation(location);
133: TypeFrame typeFrame = typeDataflow
134: .getFactAtLocation(location);
135: if (ins instanceof InvokeInstruction) {
136: InvokeInstruction inv = (InvokeInstruction) ins;
137: XMethod m = XFactory.createXMethod(inv, cpg);
138: SignatureParser sigParser = new SignatureParser(m
139: .getSignature());
140: int numParams = sigParser.getNumParameters();
141:
142: // Check nonnull annotations
143:
144: for (int j = 0; j < numParams; j++)
145: if (db.parameterMustBeNonNull(m, j)) {
146: int slot = sigParser
147: .getSlotsFromTopOfStackForParameter(j);
148: ValueNumber valueNumber = valueNumberFrame
149: .getStackValue(slot);
150: if (valueNumberForThis != valueNumber)
151: derefs
152: .add(
153: location,
154: valueNumber,
155: PointerUsageRequiringNonNullValue
156: .getPassedAsNonNullParameter(
157: m, j));
158: }
159:
160: // Check actual targets
161: try {
162: Set<JavaClassAndMethod> targetMethodSet = Hierarchy
163: .resolveMethodCallTargets(inv,
164: typeFrame, cpg);
165: BitSet unconditionallyDereferencedNullArgSet = null;
166: for (JavaClassAndMethod targetMethod : targetMethodSet) {
167:
168: ParameterNullnessProperty property = unconditionalDerefParamDatabase
169: .getProperty(targetMethod
170: .toMethodDescriptor());
171: if (property == null) {
172: unconditionallyDereferencedNullArgSet = null;
173: break;
174: }
175: BitSet foo = property.getAsBitSet();
176: if (unconditionallyDereferencedNullArgSet == null)
177: unconditionallyDereferencedNullArgSet = foo;
178: else
179: unconditionallyDereferencedNullArgSet
180: .intersects(foo);
181: if (unconditionallyDereferencedNullArgSet
182: .isEmpty())
183: break;
184: }
185:
186: if (unconditionallyDereferencedNullArgSet != null
187: && !unconditionallyDereferencedNullArgSet
188: .isEmpty()
189: && valueNumberFrame.isValid())
190: for (int j = unconditionallyDereferencedNullArgSet
191: .nextSetBit(0); j >= 0; j = unconditionallyDereferencedNullArgSet
192: .nextSetBit(j + 1)) {
193: int slot = sigParser
194: .getSlotsFromTopOfStackForParameter(j);
195: ValueNumber valueNumber = valueNumberFrame
196: .getStackValue(slot);
197: if (valueNumberForThis != valueNumber)
198: derefs
199: .add(
200: location,
201: valueNumber,
202: PointerUsageRequiringNonNullValue
203: .getPassedAsNonNullParameter(
204: m,
205: j));
206: }
207:
208: } catch (ClassNotFoundException e) {
209: AnalysisContext.reportMissingClass(e);
210: }
211:
212: } else if (ins instanceof ARETURN
213: && methodAnnotation == NullnessAnnotation.NONNULL) {
214: ValueNumber valueNumber = valueNumberFrame
215: .getTopValue();
216: if (valueNumberForThis != valueNumber)
217: derefs
218: .add(
219: location,
220: valueNumber,
221: PointerUsageRequiringNonNullValue
222: .getReturnFromNonNullMethod(this Method));
223:
224: } else if (ins instanceof PUTFIELD
225: || ins instanceof PUTSTATIC) {
226: FieldInstruction inf = (FieldInstruction) ins;
227: XField field = XFactory.createXField(inf, cpg);
228: NullnessAnnotation annotation = AnalysisContext
229: .currentAnalysisContext()
230: .getNullnessAnnotationDatabase()
231: .getResolvedAnnotation(field, false);
232: if (annotation == NullnessAnnotation.NONNULL) {
233: ValueNumber valueNumber = valueNumberFrame
234: .getTopValue();
235: if (valueNumberForThis != valueNumber)
236: derefs
237: .add(
238: location,
239: valueNumber,
240: PointerUsageRequiringNonNullValue
241: .getStoredIntoNonNullField(field));
242: }
243:
244: }
245: }
246:
247: } catch (CFGBuilderException e) {
248: AnalysisContext.logError("Error generating derefs for "
249: + this Method, e);
250: } catch (DataflowAnalysisException e) {
251: AnalysisContext.logError("Error generating derefs for "
252: + this Method, e);
253: }
254: return derefs;
255: }
256:
257: public static NullnessAnnotation getMethodNullnessAnnotation(
258: ClassContext classContext, Method method) {
259:
260: if (method.getSignature().indexOf(")L") >= 0
261: || method.getSignature().indexOf(")[") >= 0) {
262:
263: XMethod m = XFactory.createXMethod(classContext
264: .getJavaClass(), method);
265: return AnalysisContext.currentAnalysisContext()
266: .getNullnessAnnotationDatabase()
267: .getResolvedAnnotation(m, false);
268: }
269: return NullnessAnnotation.UNKNOWN_NULLNESS;
270: }
271:
272: }
|