KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > detect > FindPuzzlers


1 /*
2  * FindBugs - Find bugs in Java programs
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.detect;
21
22
23 import org.apache.bcel.Repository;
24 import org.apache.bcel.classfile.Code;
25 import org.apache.bcel.classfile.JavaClass;
26
27 import edu.umd.cs.findbugs.BugInstance;
28 import edu.umd.cs.findbugs.BugReporter;
29 import edu.umd.cs.findbugs.BytecodeScanningDetector;
30 import edu.umd.cs.findbugs.OpcodeStack;
31 import edu.umd.cs.findbugs.OpcodeStack.Item;
32
33 public class FindPuzzlers extends BytecodeScanningDetector {
34
35
36     BugReporter bugReporter;
37     public FindPuzzlers(BugReporter bugReporter) {
38         this.bugReporter = bugReporter;
39     }
40
41
42
43     @Override JavaDoc
44          public void visit(Code obj) {
45         prevOpcodeIncrementedRegister = -1;
46         best_priority_for_ICAST_INTEGER_MULTIPLY_CAST_TO_LONG = LOW_PRIORITY+1;
47         prevOpCode = NOP;
48         stack.resetForMethodEntry(this);
49         badlyComputingOddState = 0;
50         resetIMulCastLong();
51         imul_distance = 10000;
52         super.visit(obj);
53     }
54
55     int imul_constant;
56     int imul_distance;
57     boolean imul_operand_is_parameter;
58     int prevOpcodeIncrementedRegister;
59     int valueOfConstantArgumentToShift;
60     int best_priority_for_ICAST_INTEGER_MULTIPLY_CAST_TO_LONG ;
61     boolean constantArgumentToShift;
62     
63     int badlyComputingOddState;
64     int prevOpCode;
65     OpcodeStack stack = new OpcodeStack();
66     
67     private void resetIMulCastLong() {
68         imul_constant = 1;
69         imul_operand_is_parameter = false;
70     }
71     private int adjustPriority(int factor, int priority) {
72         if (factor <= 4) return LOW_PRIORITY+2;
73         if (factor <= 10000) return priority+1;
74         if (factor <= 60*60*1000) return priority;
75         return priority-1;
76     }
77     private int adjustMultiplier(Object JavaDoc constant, int mul) {
78         if (!(constant instanceof Integer JavaDoc)) return mul;
79         return Math.abs(((Integer JavaDoc) constant).intValue()) * mul;
80         
81     }
82     @Override JavaDoc
83          public void sawOpcode(int seen) {
84         stack.mergeJumps(this);
85         
86         if (seen == IMUL) {
87             if (imul_distance != 1) resetIMulCastLong();
88             imul_distance = 0;
89             if (stack.getStackDepth() > 1) {
90                 OpcodeStack.Item item0 = stack.getStackItem(0);
91                 OpcodeStack.Item item1 = stack.getStackItem(1);
92                 imul_constant = adjustMultiplier(item0.getConstant(), imul_constant);
93                 imul_constant = adjustMultiplier(item1.getConstant(), imul_constant);
94
95                 if (item0.isInitialParameter() || item1.isInitialParameter())
96                     imul_operand_is_parameter = true;
97             }} else {
98                 imul_distance++;
99             }
100         
101         if (prevOpCode == IMUL && seen == I2L) {
102             int priority = adjustPriority(imul_constant, NORMAL_PRIORITY);
103             if (priority >= LOW_PRIORITY && imul_operand_is_parameter) priority = NORMAL_PRIORITY;
104             if (priority <= best_priority_for_ICAST_INTEGER_MULTIPLY_CAST_TO_LONG) {
105                 best_priority_for_ICAST_INTEGER_MULTIPLY_CAST_TO_LONG = priority;
106             bugReporter.reportBug(new BugInstance(this,
107                     "ICAST_INTEGER_MULTIPLY_CAST_TO_LONG",
108                     priority)
109                         .addClassAndMethod(this)
110                         .addSourceLine(this));
111             }
112         }
113         
114         if (getMethodName().equals("<clinit>") && (seen == PUTSTATIC || seen == GETSTATIC || seen == INVOKESTATIC)) {
115              String JavaDoc clazz = getClassConstantOperand();
116              if (!clazz.equals(getClassName())) {
117                  try {
118                      JavaClass targetClass = Repository.lookupClass(clazz);
119                     if (Repository.instanceOf(targetClass, getThisClass())) {
120                         int priority = NORMAL_PRIORITY;
121                         if (seen == GETSTATIC) priority--;
122                         if (!targetClass.isPublic()) priority++;
123                          bugReporter.reportBug(new BugInstance(this,
124                                  "IC_SUPERCLASS_USES_SUBCLASS_DURING_INITIALIZATION",
125                                 priority)
126                          .addClassAndMethod(this).addClass(getDottedClassConstantOperand())
127                          .addSourceLine(this)
128                             );
129                     }
130                 } catch (ClassNotFoundException JavaDoc e) {
131                     // ignore it
132
}
133                  
134              }
135         }
136          if (false && (seen == INVOKEVIRTUAL)
137                 && getNameConstantOperand().equals("equals")
138                 && getSigConstantOperand().equals("(Ljava/lang/Object;)Z")
139         && stack.getStackDepth() > 1) {
140             OpcodeStack.Item item0 = stack.getStackItem(0);
141             OpcodeStack.Item item1 = stack.getStackItem(1);
142
143             if (item0.isArray() || item1.isArray()) {
144                 bugReporter.reportBug(new BugInstance("EC_BAD_ARRAY_COMPARE", NORMAL_PRIORITY)
145                     .addClassAndMethod(this)
146                     .addSourceLine(this));
147         }
148         }
149  
150
151          if (seen >= IALOAD && seen <= SALOAD || seen >= IASTORE && seen <= SASTORE ) {
152              Item index = stack.getStackItem(0);
153              if (index.getSpecialKind() == Item.AVERAGE_COMPUTED_USING_DIVISION)
154                  bugReporter.reportBug(new BugInstance(this, "IM_AVERAGE_COMPUTATION_COULD_OVERFLOW", NORMAL_PRIORITY)
155                  .addClassAndMethod(this)
156                  .addSourceLine(this));
157          }
158
159         if ((seen == IFEQ || seen == IFNE) && getPrevOpcode(1) == IMUL
160             && ( getPrevOpcode(2) == SIPUSH
161                 || getPrevOpcode(2) == BIPUSH
162                 )
163             && getPrevOpcode(3) == IREM
164                 )
165              bugReporter.reportBug(new BugInstance(this, "IM_MULTIPLYING_RESULT_OF_IREM", LOW_PRIORITY)
166                                         .addClassAndMethod(this)
167                                         .addSourceLine(this));
168         if (seen == I2S && getPrevOpcode(1) == IUSHR
169                 && (!constantArgumentToShift || valueOfConstantArgumentToShift % 16 != 0)
170             ||
171             seen == I2B && getPrevOpcode(1) == IUSHR
172                 && (!constantArgumentToShift || valueOfConstantArgumentToShift % 8 != 0)
173              )
174              bugReporter.reportBug(new BugInstance(this, "ICAST_QUESTIONABLE_UNSIGNED_RIGHT_SHIFT", LOW_PRIORITY)
175                                         .addClassAndMethod(this)
176                                         .addSourceLine(this));
177
178         constantArgumentToShift = false;
179         if ( (seen == IUSHR
180                 || seen == ISHR
181                 || seen == ISHL )) {
182             if (stack.getStackDepth() <= 1) {
183                 // don't understand; lie so other detectors won't get concerned
184
constantArgumentToShift = true;
185                 valueOfConstantArgumentToShift = 8;
186                 }
187             else {
188             Object JavaDoc rightHandSide
189                  = stack.getStackItem(0).getConstant();
190             Object JavaDoc leftHandSide
191                 = stack.getStackItem(1).getConstant();
192             if (rightHandSide instanceof Integer JavaDoc) {
193                 constantArgumentToShift = true;
194                 valueOfConstantArgumentToShift = ((Integer JavaDoc) rightHandSide);
195                 if (valueOfConstantArgumentToShift < 0 || valueOfConstantArgumentToShift >= 32)
196                  bugReporter.reportBug(new BugInstance(this, "ICAST_BAD_SHIFT_AMOUNT",
197                             valueOfConstantArgumentToShift < 0 ? LOW_PRIORITY : HIGH_PRIORITY)
198                         .addClassAndMethod(this)
199                         .addInt(valueOfConstantArgumentToShift)
200                         .addSourceLine(this)
201                         );
202                 }
203                 if (leftHandSide != null
204                     && leftHandSide instanceof Integer JavaDoc
205                     && ((Integer JavaDoc) leftHandSide)
206                         > 0) {
207                 // boring; lie so other detectors won't get concerned
208
constantArgumentToShift = true;
209                 valueOfConstantArgumentToShift = 8;
210                     }
211             }
212             }
213
214
215
216        if (seen == INVOKEVIRTUAL && stack.getStackDepth() > 0
217                         && getClassConstantOperand().equals("java/util/Date")
218                         && getNameConstantOperand().equals("setMonth")
219                         && getSigConstantOperand().equals("(I)V")) {
220             OpcodeStack.Item item = stack.getStackItem(0);
221             Object JavaDoc o = item.getConstant();
222             if (o != null && o instanceof Integer JavaDoc) {
223                 int v = (Integer JavaDoc) o;
224                 if (v < 0 || v > 11)
225                  bugReporter.reportBug(new BugInstance(this, "DMI_BAD_MONTH", NORMAL_PRIORITY)
226                         .addClassAndMethod(this)
227                         .addInt(v)
228                         .addCalledMethod(this)
229                         .addSourceLine(this)
230                     );
231                 }
232         }
233                 
234        if (seen == INVOKEVIRTUAL && stack.getStackDepth() > 1
235                         && getClassConstantOperand().equals("java/util/Calendar")
236                         && getNameConstantOperand().equals("set")
237                         && getSigConstantOperand().equals("(III)V")
238         ||
239         seen == INVOKESPECIAL && stack.getStackDepth() > 1
240                         && getClassConstantOperand().equals("java/util/GregorianCalendar")
241                         && getNameConstantOperand().equals("<init>")
242                         && getSigConstantOperand().equals("(III)V")
243         ) {
244             OpcodeStack.Item item = stack.getStackItem(1);
245             Object JavaDoc o = item.getConstant();
246             if (o != null && o instanceof Integer JavaDoc) {
247                 int v = (Integer JavaDoc) o;
248                 if (v < 0 || v > 11)
249                  bugReporter.reportBug(new BugInstance(this, "DMI_BAD_MONTH", NORMAL_PRIORITY)
250                         .addClassAndMethod(this)
251                         .addInt(v)
252                         .addCalledMethod(this)
253                         .addSourceLine(this)
254                         );
255                 }
256         }
257                 
258
259
260         if (isRegisterStore() && (seen == ISTORE
261             || seen == ISTORE_0
262             || seen == ISTORE_1
263             || seen == ISTORE_2
264             || seen == ISTORE_3)
265             && getRegisterOperand() == prevOpcodeIncrementedRegister) {
266              bugReporter.reportBug(new BugInstance(this, "DLS_OVERWRITTEN_INCREMENT", HIGH_PRIORITY)
267                                         .addClassAndMethod(this)
268                                         .addSourceLine(this));
269
270             }
271         if (seen == IINC) {
272             prevOpcodeIncrementedRegister = getRegisterOperand();
273             }
274         else
275             prevOpcodeIncrementedRegister = -1;
276         
277         
278         // Java Puzzlers, Chapter 2, puzzle 1
279
// Look for ICONST_2 IREM ICONST_1 IF_ICMPNE L1
280

281         switch (badlyComputingOddState) {
282         case 0:
283             if (seen == ICONST_2) badlyComputingOddState++;
284             break;
285         case 1:
286             if (seen == IREM) badlyComputingOddState++;
287             else badlyComputingOddState = 0;
288             break;
289         case 2:
290             if (seen == ICONST_1) badlyComputingOddState++;
291             else badlyComputingOddState = 0;
292             break;
293         case 3:
294             if (seen == IF_ICMPEQ || seen == IF_ICMPNE)
295                  bugReporter.reportBug(new BugInstance(this, "IM_BAD_CHECK_FOR_ODD", NORMAL_PRIORITY)
296                          .addClassAndMethod(this)
297                          .addSourceLine(this));
298                 badlyComputingOddState = 0;
299             break;
300         }
301         
302         // Java Puzzlers, chapter 3, puzzle 12
303
if (seen == INVOKEVIRTUAL && stack.getStackDepth() > 0
304                   && (getNameConstantOperand().equals("toString")
305                       && getSigConstantOperand().equals("()Ljava/lang/String;")
306                       || getNameConstantOperand().equals("append")
307                       && getSigConstantOperand().equals("(Ljava/lang/Object;)Ljava/lang/StringBuilder;") && getClassConstantOperand().equals("java/lang/StringBuilder")
308                       || getNameConstantOperand().equals("append")
309                       && getSigConstantOperand().equals("(Ljava/lang/Object;)Ljava/lang/StringBuffer;") && getClassConstantOperand().equals("java/lang/StringBuffer")
310                       )
311                   ) {
312               String JavaDoc classConstants = getClassConstantOperand();
313               OpcodeStack.Item item = stack.getStackItem(0);
314               String JavaDoc signature = item.getSignature();
315               if (signature != null && signature.startsWith("["))
316                      bugReporter.reportBug(new BugInstance(this, "DMI_INVOKING_TOSTRING_ON_ARRAY", NORMAL_PRIORITY)
317                              .addClassAndMethod(this)
318                              .addSourceLine(this));
319           }
320
321     
322     
323         stack.sawOpcode(this,seen);
324         prevOpCode = seen;
325     }
326
327 }
328
Popular Tags