KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > ba > npe > NullDerefAndRedundantComparisonFinder


1 /*
2  * Bytecode analysis framework
3  * Copyright (C) 2005, University of Maryland
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */

19
20 package edu.umd.cs.findbugs.ba.npe;
21
22 import java.util.BitSet JavaDoc;
23 import java.util.Collections JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.HashSet JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.LinkedList JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Map JavaDoc;
30 import java.util.Set JavaDoc;
31 import java.util.SortedSet JavaDoc;
32 import java.util.TreeSet JavaDoc;
33
34 import org.apache.bcel.Constants;
35 import org.apache.bcel.classfile.LineNumberTable;
36 import org.apache.bcel.classfile.Method;
37 import org.apache.bcel.generic.Instruction;
38 import org.apache.bcel.generic.InstructionHandle;
39 import org.apache.bcel.generic.InvokeInstruction;
40
41 import edu.umd.cs.findbugs.SystemProperties;
42 import edu.umd.cs.findbugs.ba.AnalysisFeatures;
43 import edu.umd.cs.findbugs.ba.AssertionMethods;
44 import edu.umd.cs.findbugs.ba.BasicBlock;
45 import edu.umd.cs.findbugs.ba.CFGBuilderException;
46 import edu.umd.cs.findbugs.ba.ClassContext;
47 import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
48 import edu.umd.cs.findbugs.ba.Edge;
49 import edu.umd.cs.findbugs.ba.EdgeTypes;
50 import edu.umd.cs.findbugs.ba.Location;
51 import edu.umd.cs.findbugs.ba.deref.UnconditionalValueDerefDataflow;
52 import edu.umd.cs.findbugs.ba.deref.UnconditionalValueDerefSet;
53 import edu.umd.cs.findbugs.ba.vna.ValueNumber;
54 import edu.umd.cs.findbugs.ba.vna.ValueNumberDataflow;
55 import edu.umd.cs.findbugs.ba.vna.ValueNumberFrame;
56
57 /**
58  * A user-friendly front end for finding null pointer dereferences
59  * and redundant null comparisions.
60  *
61  * @see IsNullValueAnalysis
62  * @author David Hovemeyer
63  */

64 public class NullDerefAndRedundantComparisonFinder {
65     private static final boolean DEBUG = SystemProperties.getBoolean("fnd.debug");
66     private static final boolean DEBUG_DEREFS = SystemProperties.getBoolean("fnd.derefs.debug");
67     
68     private ClassContext classContext;
69     private Method method;
70     private NullDerefAndRedundantComparisonCollector collector;
71     private final boolean findGuaranteedDerefs;
72     
73     private List JavaDoc<RedundantBranch> redundantBranchList;
74     private BitSet JavaDoc definitelySameBranchSet;
75     private BitSet JavaDoc definitelyDifferentBranchSet;
76     private BitSet JavaDoc undeterminedBranchSet;
77     private BitSet JavaDoc lineMentionedMultipleTimes;
78
79     private IsNullValueDataflow invDataflow;
80     private ValueNumberDataflow vnaDataflow;
81     private UnconditionalValueDerefDataflow uvdDataflow;
82     private AssertionMethods assertionMethods;
83
84     static {
85         if (DEBUG) System.out.println("fnd.debug enabled");
86     }
87     /**
88      * Constructor.
89      *
90      * @param classContext the ClassContext
91      * @param method the method to analyze
92      * @param collector the NullDerefAndRedundantComparisonCollector used to report
93      * null derefs and redundant null comparisons
94      */

95     public NullDerefAndRedundantComparisonFinder(
96             ClassContext classContext,
97             Method method,
98             NullDerefAndRedundantComparisonCollector collector) {
99         
100         this.classContext = classContext;
101         this.method = method;
102         this.collector = collector;
103         this.findGuaranteedDerefs = classContext.getAnalysisContext().getBoolProperty(
104                 AnalysisFeatures.TRACK_GUARANTEED_VALUE_DEREFS_IN_NULL_POINTER_ANALYSIS);
105         this.lineMentionedMultipleTimes = ClassContext.linesMentionedMultipleTimes(method);
106         
107         this.redundantBranchList = new LinkedList JavaDoc<RedundantBranch>();
108         this.definitelySameBranchSet = new BitSet JavaDoc();
109         this.definitelyDifferentBranchSet = new BitSet JavaDoc();
110         this.undeterminedBranchSet = new BitSet JavaDoc();
111         this.assertionMethods = classContext.getAssertionMethods();
112     }
113     
114     public void execute() throws DataflowAnalysisException, CFGBuilderException {
115         // Do the null-value analysis
116
this.invDataflow = classContext.getIsNullValueDataflow(method);
117         this.vnaDataflow = classContext.getValueNumberDataflow(method);
118         if (findGuaranteedDerefs) {
119             if (DEBUG_DEREFS) {
120                 System.out.println(
121                         "Checking for guaranteed derefs in " +
122                         classContext.getCFG(method).getMethodName());
123             }
124             this.uvdDataflow = classContext.getUnconditionalValueDerefDataflow(method);
125         }
126
127         // Check method and report potential null derefs and
128
// redundant null comparisons.
129
examineBasicBlocks();
130         if (findGuaranteedDerefs) {
131             examineNullValues();
132         }
133         examineRedundantBranches();
134
135     }
136
137     /**
138      * Examine basic blocks for null checks and potentially-redundant
139      * null comparisons.
140      *
141      * @throws DataflowAnalysisException
142      * @throws CFGBuilderException
143      */

144     private void examineBasicBlocks() throws DataflowAnalysisException, CFGBuilderException {
145         // Look for null check blocks where the reference being checked
146
// is definitely null, or null on some path
147
Iterator JavaDoc<BasicBlock> bbIter = invDataflow.getCFG().blockIterator();
148         while (bbIter.hasNext()) {
149             BasicBlock basicBlock = bbIter.next();
150
151             if (basicBlock.isNullCheck()) {
152                 analyzeNullCheck(classContext, method, invDataflow, basicBlock);
153             } else if (!basicBlock.isEmpty()) {
154                 // Look for all reference comparisons where
155
// - both values compared are definitely null, or
156
// - one value is definitely null and one is definitely not null
157
// These cases are not null dereferences,
158
// but they are quite likely to indicate an error, so while we've got
159
// information about null values, we may as well report them.
160
InstructionHandle lastHandle = basicBlock.getLastInstruction();
161                 Instruction last = lastHandle.getInstruction();
162                 switch (last.getOpcode()) {
163                 case Constants.IF_ACMPEQ:
164                 case Constants.IF_ACMPNE:
165                     analyzeRefComparisonBranch(basicBlock, lastHandle);
166                     break;
167                 case Constants.IFNULL:
168                 case Constants.IFNONNULL:
169                     analyzeIfNullBranch(basicBlock, lastHandle);
170                     break;
171                 }
172             }
173         }
174     }
175     
176     /**
177      * Collected information about a single value number
178      * observed at one or more locations to be both
179      * definitely-null and unconditionally dereferenced.
180      */

181     static class NullValueUnconditionalDeref {
182         private boolean alwaysOnExceptionPath;
183         private Set JavaDoc<Location> derefLocationSet;
184         
185         public NullValueUnconditionalDeref() {
186             this.alwaysOnExceptionPath = true;
187             this.derefLocationSet = new HashSet JavaDoc<Location>();
188         }
189
190         /**
191          * @param isNullValue
192          * @param unconditionalDerefLocationSet
193          */

194         public void add(IsNullValue isNullValue, Set JavaDoc<Location> unconditionalDerefLocationSet) {
195             if (!isNullValue.isException()) {
196                 alwaysOnExceptionPath = false;
197             }
198             derefLocationSet.addAll(unconditionalDerefLocationSet);
199         }
200         
201         /**
202          * @return Returns the derefLocationSet.
203          */

204         public Set JavaDoc<Location> getDerefLocationSet() {
205             return derefLocationSet;
206         }
207         
208         /**
209          * @return Returns the alwaysOnExceptionPath.
210          */

211         public boolean isAlwaysOnExceptionPath() {
212             return alwaysOnExceptionPath;
213         }
214     }
215     
216     /**
217      * Examine null values.
218      * Report any that are guaranteed to be dereferenced on
219      * non-implicit-exception paths.
220      *
221      * @throws CFGBuilderException
222      * @throws DataflowAnalysisException
223      */

224     private void examineNullValues() throws CFGBuilderException, DataflowAnalysisException {
225         Set JavaDoc<LocationWhereValueBecomesNull> locationWhereValueBecomesNullSet =
226             invDataflow.getAnalysis().getLocationWhereValueBecomesNullSet();
227         if (DEBUG_DEREFS) {
228             System.out.println("----------------------- examineNullValues " + locationWhereValueBecomesNullSet.size());
229         }
230         
231                 Map JavaDoc<ValueNumber, SortedSet JavaDoc<Location>> bugLocationMap =
232             new HashMap JavaDoc<ValueNumber, SortedSet JavaDoc<Location>>();
233         // Inspect the method for locations where a null value is guaranteed to
234
// be dereferenced. Add the dereference locations
235
Map JavaDoc<ValueNumber, NullValueUnconditionalDeref> nullValueGuaranteedDerefMap =
236             new HashMap JavaDoc<ValueNumber, NullValueUnconditionalDeref>();
237         
238         // Check every location
239
for (Iterator JavaDoc<Location> i = classContext.getCFG(method).locationIterator(); i.hasNext();) {
240             Location location = i.next();
241             
242             if (DEBUG_DEREFS) {
243                 System.out.println("At location " + location);
244             }
245             {
246                 Instruction in = location.getHandle().getInstruction();
247                 if (in instanceof InvokeInstruction &&assertionMethods.isAssertionCall((InvokeInstruction) in) ) {
248                     if (DEBUG_DEREFS)
249                         System.out.println("Skipping because it is an assertion method ");
250                     continue;
251                 }
252                 
253             }
254
255             checkForUnconditionallyDereferencedNullValues(
256                     location,
257                     bugLocationMap,
258                     nullValueGuaranteedDerefMap,
259                     vnaDataflow.getFactAtLocation(location), invDataflow.getFactAtLocation(location), uvdDataflow.getFactAfterLocation(location));
260         }
261         HashSet JavaDoc<ValueNumber> npeIfStatementCovered = new HashSet JavaDoc<ValueNumber>(nullValueGuaranteedDerefMap.keySet());
262         
263         // Check every non-exception control edge
264
for (Iterator JavaDoc<Edge> i = classContext.getCFG(method).edgeIterator(); i.hasNext();) {
265             Edge edge = i.next();
266             
267             if (edge.isExceptionEdge()) {
268                 continue;
269             }
270             
271             if (DEBUG_DEREFS) {
272                 System.out.println("On edge " + edge.formatAsString(false));
273             }
274             
275             ValueNumberFrame vnaFact = vnaDataflow.getResultFact(edge.getSource());
276             IsNullValueFrame invFact = invDataflow.getFactOnEdge(edge);
277             UnconditionalValueDerefSet uvdFact = uvdDataflow.getFactOnEdge(edge);
278             Location location = Location.getLastLocation(edge.getSource());
279             if (location != null) {
280                 Instruction in = location.getHandle().getInstruction();
281                 if (in instanceof InvokeInstruction &&assertionMethods.isAssertionCall((InvokeInstruction) in) ) {
282                     if (DEBUG_DEREFS)
283                         System.out.println("Skipping because it is an assertion method ");
284                     continue;
285                 }
286                 
287
288             checkForUnconditionallyDereferencedNullValues(
289                     location,
290                     bugLocationMap,
291                     nullValueGuaranteedDerefMap,
292                     vnaFact, invFact, uvdFact);
293             }
294         }
295         // For each value number that is null somewhere in the
296
// method, collect the set of locations where it becomes null.
297
// FIXME: we may see some locations that are not guaranteed to be dereferenced (how to fix this?)
298
Map JavaDoc<ValueNumber, Set JavaDoc<Location>> nullValueAssignmentMap =
299             new HashMap JavaDoc<ValueNumber, Set JavaDoc<Location>>();
300         for (LocationWhereValueBecomesNull lwvbn : locationWhereValueBecomesNullSet) {
301             if (DEBUG_DEREFS) System.out.println("OOO " + lwvbn);
302             Set JavaDoc<Location> locationSet = nullValueAssignmentMap.get(lwvbn.getValueNumber());
303             if (locationSet == null) {
304                 locationSet = new HashSet JavaDoc<Location>();
305                 nullValueAssignmentMap.put(lwvbn.getValueNumber(), locationSet);
306             }
307             locationSet.add(lwvbn.getLocation());
308             if (DEBUG_DEREFS)
309                 System.out.println(lwvbn.getValueNumber() + " becomes null at " + lwvbn.getLocation());
310         }
311
312         // Report
313
for (Map.Entry JavaDoc<ValueNumber, NullValueUnconditionalDeref> e : nullValueGuaranteedDerefMap.entrySet()) {
314             ValueNumber valueNumber = e.getKey();
315             Set JavaDoc<Location> derefLocationSet = e.getValue().getDerefLocationSet();
316             Set JavaDoc<Location> assignedNullLocationSet = nullValueAssignmentMap.get(valueNumber);
317             if (assignedNullLocationSet == null) {
318                 if (DEBUG_DEREFS) {
319                     String JavaDoc where = classContext.getJavaClass().getClassName() + "." + method.getName() + ":" + method.getSignature();
320                     System.out.println("Problem at " + where);
321                     for (Location loc : derefLocationSet) {
322                         System.out.println("Dereference at " + loc);
323                     }
324                 }
325                 // TODO: figure out why this is failing
326
if (false)
327                 assert false: "No assigned NullLocationSet for " + valueNumber + " in " + nullValueAssignmentMap.keySet()
328                 + " while analyzing " + classContext.getJavaClass().getClassName() + "." + method.getName();
329                 assignedNullLocationSet = Collections.EMPTY_SET;
330             }
331             collector.foundGuaranteedNullDeref(
332                     assignedNullLocationSet,
333                     derefLocationSet,
334                     bugLocationMap.get(valueNumber),
335                     vnaDataflow, valueNumber,
336                     e.getValue().isAlwaysOnExceptionPath(), npeIfStatementCovered.contains(valueNumber));
337         }
338     }
339
340     /**
341      * Check for unconditionally dereferenced null values
342      * at a particular location in the CFG.
343      * @param thisLocation TODO
344      * @param bugLocations TODO
345      * @param nullValueGuaranteedDerefMap map to be populated with null values and where they are derefed
346      * @param vnaFrame value number frame to check
347      * @param invFrame null-value frame to check
348      * @param derefSet set of unconditionally derefed values at this location
349      */

350     private void checkForUnconditionallyDereferencedNullValues(
351             Location thisLocation,
352             Map JavaDoc<ValueNumber, SortedSet JavaDoc<Location>> bugLocations,
353             Map JavaDoc<ValueNumber, NullValueUnconditionalDeref> nullValueGuaranteedDerefMap,
354             ValueNumberFrame vnaFrame, IsNullValueFrame invFrame, UnconditionalValueDerefSet derefSet) {
355         
356         if (DEBUG_DEREFS) {
357             System.out.println("vna *** " + vnaFrame);
358             System.out.println("inv *** " + invFrame);
359             System.out.println("deref * " + derefSet);
360         }
361         
362         // Make sure the frames contain meaningful information
363
if (!vnaFrame.isValid() || !invFrame.isValid() || vnaFrame.getNumSlots() != invFrame.getNumSlots()) {
364             return;
365         }
366
367         // See if there are any definitely-null values in the frame
368
for (int j = 0; j < invFrame.getNumSlots(); j++) {
369             IsNullValue isNullValue = invFrame.getValue(j);
370             
371             if (isNullValue.isDefinitelyNull()) {
372                 // Is this value unconditionally dereferenced?
373
ValueNumber valueNumber = vnaFrame.getValue(j);
374                 
375                 if (derefSet.isUnconditionallyDereferenced(valueNumber)) {
376                     noteUnconditionallyDereferencedNullValue(
377                             thisLocation,
378                             bugLocations,
379                             nullValueGuaranteedDerefMap,
380                             derefSet, isNullValue, valueNumber);
381                 }
382             }
383         }
384
385         // See if there are any known-null values in the heap that
386
// will be dereferenced in the future.
387
for (Map.Entry JavaDoc<ValueNumber, IsNullValue> entry : invFrame.getKnownValueMapEntrySet()) {
388             if (!entry.getValue().isDefinitelyNull()) {
389                 continue;
390             }
391             
392             if (derefSet.isUnconditionallyDereferenced(entry.getKey())) {
393                 noteUnconditionallyDereferencedNullValue(
394                         thisLocation,
395                         bugLocations,
396                         nullValueGuaranteedDerefMap,
397                         derefSet, entry.getValue(), entry.getKey());
398             }
399         }
400         
401     }
402
403     /**
404      * Note the locations where a known-null value is unconditionally
405      * dereferenced.
406      * @param thisLocation TODO
407      * @param bugLocations TODO
408      * @param nullValueGuaranteedDerefMap map of null values to sets of Locations where they are derefed
409      * @param derefSet set of values known to be unconditionally dereferenced
410      * @param isNullValue the null value
411      * @param valueNumber the value number of the null value
412      */

413     private void noteUnconditionallyDereferencedNullValue(Location thisLocation, Map JavaDoc<ValueNumber, SortedSet JavaDoc<Location>> bugLocations, Map JavaDoc<ValueNumber, NullValueUnconditionalDeref> nullValueGuaranteedDerefMap, UnconditionalValueDerefSet derefSet, IsNullValue isNullValue, ValueNumber valueNumber) {
414         if (DEBUG) {
415             System.out.println("%%% HIT for value number " + valueNumber + " @ " + thisLocation);
416         }
417         
418         // OK, we have a null value that is unconditionally
419
// derferenced. Make a note of the locations where it
420
// will be dereferenced.
421
NullValueUnconditionalDeref thisNullValueDeref = nullValueGuaranteedDerefMap.get(valueNumber);
422         if (thisNullValueDeref == null) {
423             thisNullValueDeref = new NullValueUnconditionalDeref();
424             nullValueGuaranteedDerefMap.put(valueNumber, thisNullValueDeref);
425         }
426         thisNullValueDeref.add(isNullValue, derefSet.getUnconditionalDerefLocationSet(valueNumber));
427     
428         if (thisLocation != null) {
429             SortedSet JavaDoc<Location> locationsForThisBug = bugLocations.get(valueNumber);
430
431             if (locationsForThisBug == null) {
432                 locationsForThisBug = new TreeSet JavaDoc<Location>();
433                 bugLocations.put(valueNumber, locationsForThisBug);
434             }
435             locationsForThisBug.add(thisLocation);
436         }
437     }
438
439     /**
440      * Examine redundant branches.
441      */

442     private void examineRedundantBranches() {
443         for (RedundantBranch redundantBranch : redundantBranchList) {
444             if (DEBUG) System.out.println("Redundant branch: " + redundantBranch);
445             int lineNumber = redundantBranch.lineNumber;
446
447             // The source to bytecode compiler may sometimes duplicate blocks of
448
// code along different control paths. So, to report the bug,
449
// we check to ensure that the branch is REALLY determined each
450
// place it is duplicated, and that it is determined in the same way.
451

452             boolean confused = undeterminedBranchSet.get(lineNumber) ||
453                     (definitelySameBranchSet.get(lineNumber) && definitelyDifferentBranchSet.get(lineNumber));
454
455             // confused if there is JSR confusion or multiple null checks with different results on the same line
456

457             boolean reportIt = true;
458             if (lineMentionedMultipleTimes.get(lineNumber) && confused)
459                 reportIt = false;
460             if (redundantBranch.location.getBasicBlock().isInJSRSubroutine() /* occurs in a JSR */
461                     && confused)
462                 reportIt = false;
463             if (reportIt) {
464                 collector.foundRedundantNullCheck(redundantBranch.location, redundantBranch);
465             }
466         }
467     }
468
469     private void analyzeRefComparisonBranch(
470             BasicBlock basicBlock,
471             InstructionHandle lastHandle) throws DataflowAnalysisException {
472         
473         Location location = new Location(lastHandle, basicBlock);
474
475         IsNullValueFrame frame = invDataflow.getFactAtLocation(location);
476         if (!frame.isValid()) {
477             // Probably dead code due to pruning infeasible exception edges.
478
return;
479         }
480         if (frame.getStackDepth() < 2)
481             throw new DataflowAnalysisException("Stack underflow at " + lastHandle);
482
483         // Find the line number.
484
int lineNumber = getLineNumber(method, lastHandle);
485         if (lineNumber < 0)
486             return;
487
488         int numSlots = frame.getNumSlots();
489         IsNullValue top = frame.getValue(numSlots - 1);
490         IsNullValue topNext = frame.getValue(numSlots - 2);
491
492         boolean definitelySame = top.isDefinitelyNull() && topNext.isDefinitelyNull();
493         boolean definitelyDifferent =
494                 (top.isDefinitelyNull() && topNext.isDefinitelyNotNull()) ||
495                 (top.isDefinitelyNotNull() && topNext.isDefinitelyNull());
496
497         if (definitelySame || definitelyDifferent) {
498             if (definitelySame) {
499                 if (DEBUG) System.out.println("Line " + lineNumber + " always same");
500                 definitelySameBranchSet.set(lineNumber);
501             }
502             if (definitelyDifferent) {
503                 if (DEBUG) System.out.println("Line " + lineNumber + " always different");
504                 definitelyDifferentBranchSet.set(lineNumber);
505             }
506
507             RedundantBranch redundantBranch = new RedundantBranch(location, lineNumber, top, topNext);
508             
509             // Figure out which control edge is made infeasible by the redundant comparison
510
boolean wantSame = (lastHandle.getInstruction().getOpcode() == Constants.IF_ACMPEQ);
511             int infeasibleEdgeType = (wantSame == definitelySame)
512                     ? EdgeTypes.FALL_THROUGH_EDGE : EdgeTypes.IFCMP_EDGE;
513             Edge infeasibleEdge = invDataflow.getCFG().getOutgoingEdgeWithType(basicBlock, infeasibleEdgeType);
514             redundantBranch.setInfeasibleEdge(infeasibleEdge);
515             
516             if (DEBUG) System.out.println("Adding redundant branch: " + redundantBranch);
517             redundantBranchList.add(redundantBranch);
518         } else {
519             if (DEBUG) System.out.println("Line " + lineNumber + " undetermined");
520             undeterminedBranchSet.set(lineNumber);
521         }
522     }
523
524     // This is called for both IFNULL and IFNONNULL instructions.
525
private void analyzeIfNullBranch(
526             BasicBlock basicBlock,
527             InstructionHandle lastHandle) throws DataflowAnalysisException {
528         
529         Location location = new Location(lastHandle, basicBlock);
530
531         IsNullValueFrame frame = invDataflow.getFactAtLocation(location);
532
533         if (!frame.isValid()) {
534             // This is probably dead code due to an infeasible exception edge.
535
return;
536         }
537
538         IsNullValue top = frame.getTopValue();
539
540         // Find the line number.
541
int lineNumber = getLineNumber(method, lastHandle);
542         if (lineNumber < 0)
543             return;
544         
545         if (!(top.isDefinitelyNull() || top.isDefinitelyNotNull())) {
546             if (DEBUG) System.out.println("Line " + lineNumber + " undetermined");
547             undeterminedBranchSet.set(lineNumber);
548             return;
549         }
550
551         // Figure out if the branch is always taken
552
// or always not taken.
553
short opcode = lastHandle.getInstruction().getOpcode();
554         boolean definitelySame = top.isDefinitelyNull();
555         if (opcode != Constants.IFNULL) definitelySame = !definitelySame;
556
557         if (definitelySame) {
558             if (DEBUG) System.out.println("Line " + lineNumber + " always same");
559             definitelySameBranchSet.set(lineNumber);
560         } else {
561             if (DEBUG) System.out.println("Line " + lineNumber + " always different");
562             definitelyDifferentBranchSet.set(lineNumber);
563         }
564
565         RedundantBranch redundantBranch = new RedundantBranch(location, lineNumber, top);
566         
567         // Determine which control edge is made infeasible by the redundant comparison
568
boolean wantNull = (opcode == Constants.IFNULL);
569         int infeasibleEdgeType = (wantNull == top.isDefinitelyNull())
570                 ? EdgeTypes.FALL_THROUGH_EDGE : EdgeTypes.IFCMP_EDGE;
571         Edge infeasibleEdge = invDataflow.getCFG().getOutgoingEdgeWithType(basicBlock, infeasibleEdgeType);
572         redundantBranch.setInfeasibleEdge(infeasibleEdge);
573         
574         if (DEBUG) System.out.println("Adding redundant branch: " + redundantBranch);
575         redundantBranchList.add(redundantBranch);
576     }
577
578     private void analyzeNullCheck(ClassContext classContext, Method method, IsNullValueDataflow invDataflow,
579             BasicBlock basicBlock)
580         throws DataflowAnalysisException, CFGBuilderException {
581         // Look for null checks where the value checked is definitely
582
// null or null on some path.
583

584         InstructionHandle exceptionThrowerHandle = basicBlock.getExceptionThrower();
585         Instruction exceptionThrower = exceptionThrowerHandle.getInstruction();
586         
587         // Get the stack values at entry to the null check.
588
IsNullValueFrame frame = invDataflow.getStartFact(basicBlock);
589         if (!frame.isValid())
590             return;
591
592         
593         // Could the reference be null?
594
IsNullValue refValue = frame.getInstance(exceptionThrower, classContext.getConstantPoolGen());
595         if (DEBUG) {
596             System.out.println("For basic block " + basicBlock + " value is " + refValue);
597         }
598         if (!refValue.mightBeNull())
599             return;
600         
601         // Get the value number
602
ValueNumberFrame vnaFrame = classContext.getValueNumberDataflow(method).getStartFact(basicBlock);
603         if (!vnaFrame.isValid())
604             return;
605         ValueNumber valueNumber = vnaFrame.getInstance(exceptionThrower, classContext.getConstantPoolGen());
606         Location location = new Location(exceptionThrowerHandle, basicBlock);
607         if (DEBUG) System.out.println("Warning: VN " + valueNumber + " invf: " + frame + " @ " + location);
608         
609         // Issue a warning
610
collector.foundNullDeref(classContext, location, valueNumber, refValue, vnaFrame);
611     }
612
613     private static int getLineNumber(Method method, InstructionHandle handle) {
614         LineNumberTable table = method.getCode().getLineNumberTable();
615         if (table == null)
616             return -1;
617         return table.getSourceLine(handle.getPosition());
618     }
619 }
Popular Tags