1 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 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 constant, int mul) { 78 if (!(constant instanceof Integer )) return mul; 79 return Math.abs(((Integer ) constant).intValue()) * mul; 80 81 } 82 @Override 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 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 e) { 131 } 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 constantArgumentToShift = true; 185 valueOfConstantArgumentToShift = 8; 186 } 187 else { 188 Object rightHandSide 189 = stack.getStackItem(0).getConstant(); 190 Object leftHandSide 191 = stack.getStackItem(1).getConstant(); 192 if (rightHandSide instanceof Integer ) { 193 constantArgumentToShift = true; 194 valueOfConstantArgumentToShift = ((Integer ) 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 205 && ((Integer ) leftHandSide) 206 > 0) { 207 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 o = item.getConstant(); 222 if (o != null && o instanceof Integer ) { 223 int v = (Integer ) 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 o = item.getConstant(); 246 if (o != null && o instanceof Integer ) { 247 int v = (Integer ) 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 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 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 classConstants = getClassConstantOperand(); 313 OpcodeStack.Item item = stack.getStackItem(0); 314 String 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 |