| 1 19 20 package edu.umd.cs.findbugs.detect; 21 22 import java.util.HashSet ; 23 24 import org.apache.bcel.classfile.Code; 25 import org.apache.bcel.classfile.CodeException; 26 import org.apache.bcel.classfile.Constant; 27 import org.apache.bcel.classfile.ConstantClass; 28 import org.apache.bcel.classfile.ConstantPool; 29 import org.apache.bcel.classfile.JavaClass; 30 import org.apache.bcel.classfile.Method; 31 import org.apache.bcel.generic.ObjectType; 32 import org.apache.bcel.generic.ReferenceType; 33 import org.apache.bcel.generic.Type; 34 35 import edu.umd.cs.findbugs.BugAccumulator; 36 import edu.umd.cs.findbugs.BugInstance; 37 import edu.umd.cs.findbugs.BugReporter; 38 import edu.umd.cs.findbugs.BytecodeScanningDetector; 39 import edu.umd.cs.findbugs.JavaVersion; 40 import edu.umd.cs.findbugs.OpcodeStack; 41 import edu.umd.cs.findbugs.SourceLineAnnotation; 42 import edu.umd.cs.findbugs.ba.AnalysisContext; 43 import edu.umd.cs.findbugs.ba.CFGBuilderException; 44 import edu.umd.cs.findbugs.ba.DataflowAnalysisException; 45 import edu.umd.cs.findbugs.ba.Hierarchy; 46 import edu.umd.cs.findbugs.ba.ObjectTypeFactory; 47 import edu.umd.cs.findbugs.ba.type.TypeDataflow; 48 49 public class DumbMethods extends BytecodeScanningDetector { 50 51 private static final ObjectType CONDITION_TYPE = ObjectTypeFactory.getInstance("java.util.concurrent.locks.Condition"); 52 53 private HashSet <String > alreadyReported = new HashSet <String >(); 54 private BugReporter bugReporter; 55 private boolean sawCurrentTimeMillis; 56 private BugInstance gcInvocationBugReport; 57 private int gcInvocationPC; 58 private CodeException[] exceptionTable; 59 62 private String primitiveObjCtorSeen; 63 private boolean ctorSeen; 64 private boolean prevOpcodeWasReadLine; 65 private int prevOpcode; 66 private boolean isPublicStaticVoidMain; 67 private boolean isEqualsObject; 68 private boolean sawInstanceofCheck; 69 private boolean reportedBadCastInEquals; 70 71 private int randomNextIntState; 72 private boolean checkForBitIorofSignedByte; 73 74 private boolean jdk15ChecksEnabled; 75 76 private BugAccumulator accumulator; 77 public DumbMethods(BugReporter bugReporter) { 78 this.bugReporter = bugReporter; 79 accumulator = new BugAccumulator(bugReporter); 80 jdk15ChecksEnabled = JavaVersion.getRuntimeVersion().isSameOrNewerThan(JavaVersion.JAVA_1_5); 81 } 82 83 84 OpcodeStack stack = new OpcodeStack(); 85 86 @Override  87 public void visitAfter(JavaClass obj) { 88 accumulator.reportAccumulatedBugs(); 89 } 90 public static boolean isTestMethod(Method method) { 91 return method.getName().startsWith("test"); 92 } 93 @Override  94 public void visit(Method method) { 95 String cName = getDottedClassName(); 96 stack.resetForMethodEntry(this); 97 98 isPublicStaticVoidMain = method.isPublic() && method.isStatic() 99 && getMethodName().equals("main") 100 || cName.toLowerCase().indexOf("benchmark") >= 0; 101 prevOpcodeWasReadLine = false; 102 Code code = method.getCode(); 103 if (code != null) 104 this.exceptionTable = code.getExceptionTable(); 105 if (this.exceptionTable == null) 106 this.exceptionTable = new CodeException[0]; 107 primitiveObjCtorSeen = null; 108 ctorSeen = false; 109 randomNextIntState = 0; 110 checkForBitIorofSignedByte = false; 111 isEqualsObject = getMethodName().equals("equals") && getMethodSig().equals("(Ljava/lang/Object;)Z") 112 && !method.isStatic(); 113 sawInstanceofCheck = false; 114 reportedBadCastInEquals = false; 115 116 } 117 118 @Override  119 public void sawOpcode(int seen) { 120 stack.mergeJumps(this); 121 String opcodeName = OPCODE_NAMES[seen]; 122 123 if ((seen == INVOKEVIRTUAL 124 && getClassConstantOperand().equals("java/util/HashMap") && getNameConstantOperand() 125 .equals("get")) 126 || (seen == INVOKEINTERFACE 127 && getClassConstantOperand().equals("java/util/Map") && getNameConstantOperand() 128 .equals("get")) 129 || (seen == INVOKEVIRTUAL 130 && getClassConstantOperand() 131 .equals("java/util/HashSet") && getNameConstantOperand() 132 .equals("contains")) 133 || (seen == INVOKEINTERFACE 134 && getClassConstantOperand().equals("java/util/Set") && getNameConstantOperand() 135 .equals("contains"))) { 136 OpcodeStack.Item top = stack.getStackItem(0); 137 if (top.getSignature().equals("Ljava/net/URL;")) 138 bugReporter.reportBug(new BugInstance(this, 139 "DMI_COLLECTION_OF_URLS", HIGH_PRIORITY) 140 .addClassAndMethod(this) 141 .addSourceLine(this)); 142 } 143 144 145 if (isEqualsObject && !reportedBadCastInEquals) { 146 if (seen == INSTANCEOF || seen == INVOKEVIRTUAL && getNameConstantOperand().equals("getClass") 147 && getSigConstantOperand().equals("()Ljava/lang/Class;") 148 ) { 149 OpcodeStack.Item item = stack.getStackItem(0); 150 if (item.getRegisterNumber() == 1) sawInstanceofCheck = true; 151 } else if (seen == INVOKESPECIAL && getNameConstantOperand().equals("equals") 152 && getSigConstantOperand().equals("(Ljava/lang/Object;)Z")) { 153 OpcodeStack.Item item0 = stack.getStackItem(0); 154 OpcodeStack.Item item1 = stack.getStackItem(1); 155 if (item1.getRegisterNumber() + item0.getRegisterNumber() == 1) 156 sawInstanceofCheck = true; 157 } else if (seen == CHECKCAST && !sawInstanceofCheck) { 158 OpcodeStack.Item item = stack.getStackItem(0); 159 if (item.getRegisterNumber() == 1) { 160 if (getSizeOfSurroundingTryBlock(getPC()) == Integer.MAX_VALUE) 161 bugReporter.reportBug(new BugInstance(this, "BC_EQUALS_METHOD_SHOULD_WORK_FOR_ALL_OBJECTS", 162 NORMAL_PRIORITY) 163 .addClassAndMethod(this) 164 .addSourceLine(this)); 165 166 reportedBadCastInEquals = true; 167 } 168 } 169 } 170 { 171 boolean foundVacuousComparison = false; 172 if (seen == IF_ICMPGT || seen == IF_ICMPLE) { 173 OpcodeStack.Item rhs = stack.getStackItem(0); 174 Object rhsConstant = rhs.getConstant(); 175 if (rhsConstant instanceof Integer && ((Integer )rhsConstant).intValue() == Integer.MAX_VALUE) 176 foundVacuousComparison = true; 177 OpcodeStack.Item lhs = stack.getStackItem(1); 178 Object lhsConstant = lhs.getConstant(); 179 if (lhsConstant instanceof Integer && ((Integer )lhsConstant).intValue() == Integer.MIN_VALUE) 180 foundVacuousComparison = true; 181 182 } 183 if (seen == IF_ICMPLT || seen == IF_ICMPGE) { 184 OpcodeStack.Item rhs = stack.getStackItem(0); 185 Object rhsConstant = rhs.getConstant(); 186 if (rhsConstant instanceof Integer && ((Integer )rhsConstant).intValue() == Integer.MIN_VALUE) 187 foundVacuousComparison = true; 188 OpcodeStack.Item lhs = stack.getStackItem(1); 189 Object lhsConstant = lhs.getConstant(); 190 if (lhsConstant instanceof Integer && ((Integer )lhsConstant).intValue() == Integer.MAX_VALUE) 191 foundVacuousComparison = true; 192 193 } 194 if (foundVacuousComparison) 195 bugReporter.reportBug(new BugInstance(this, "INT_VACUOUS_COMPARISON", 196 getBranchOffset() < 0 ? HIGH_PRIORITY : NORMAL_PRIORITY) 197 .addClassAndMethod(this) 198 .addSourceLine(this)); 199 } 200 201 if (seen == INVOKESTATIC && 202 ( getClassConstantOperand().equals("java/lang/Math") || getClassConstantOperand().equals("java/lang/StrictMath")) 203 && getNameConstantOperand().equals("abs") 204 && getSigConstantOperand().equals("(I)I")) { 205 OpcodeStack.Item item0 = stack.getStackItem(0); 206 int special = item0.getSpecialKind(); 207 if (special == OpcodeStack.Item.RANDOM_INT) 208 bugReporter.reportBug(new BugInstance(this, "RV_ABSOLUTE_VALUE_OF_RANDOM_INT", 209 HIGH_PRIORITY) 210 .addClassAndMethod(this) 211 .addSourceLine(this)); 212 else if (special == OpcodeStack.Item.HASHCODE_INT) 213 bugReporter.reportBug(new BugInstance(this, "RV_ABSOLUTE_VALUE_OF_HASHCODE", 214 HIGH_PRIORITY) 215 .addClassAndMethod(this) 216 .addSourceLine(this)); 217 } 218 219 try { 220 int stackLoc = stackEntryThatMustBeNonnegative(seen); 221 if (stackLoc >= 0) { 222 OpcodeStack.Item tos = stack.getStackItem(stackLoc); 223 switch (tos.getSpecialKind()) { 224 case OpcodeStack.Item.HASHCODE_INT_REMAINDER: 225 bugReporter.reportBug(new BugInstance(this, "RV_REM_OF_HASHCODE", HIGH_PRIORITY) 226 .addClassAndMethod(this) 227 .addSourceLine(this)); 228 break; 229 case OpcodeStack.Item.RANDOM_INT: 230 case OpcodeStack.Item.RANDOM_INT_REMAINDER: 231 bugReporter.reportBug(new BugInstance(this, "RV_REM_OF_RANDOM_INT", HIGH_PRIORITY) 232 .addClassAndMethod(this) 233 .addSourceLine(this)); 234 break; 235 } 236 237 } 238 if (seen == IREM) { 239 OpcodeStack.Item item0 = stack.getStackItem(0); 240 Object constant0 = item0.getConstant(); 241 OpcodeStack.Item item1 = stack.getStackItem(1); 242 int special = item1.getSpecialKind(); 243 if (constant0 instanceof Integer && ((Integer )constant0).intValue() == 1) 244 bugReporter.reportBug(new BugInstance(this, "INT_BAD_REM_BY_1", HIGH_PRIORITY) 245 .addClassAndMethod(this) 246 .addSourceLine(this)); 247 } 248 249 if (stack.getStackDepth() >= 1 && (seen == LOOKUPSWITCH || seen == TABLESWITCH)) { 250 OpcodeStack.Item item0 = stack.getStackItem(0); 251 if (item0.getSpecialKind() == OpcodeStack.Item.SIGNED_BYTE) { 252 int[] switchLabels = getSwitchLabels(); 253 int [] switchOffsets = getSwitchOffsets(); 254 for(int i = 0; i < switchLabels.length; i++) { 255 int v = switchLabels[i]; 256 if (v <= -129 || v >= 128) 257 bugReporter.reportBug(new BugInstance(this, "INT_BAD_COMPARISON_WITH_SIGNED_BYTE", 258 HIGH_PRIORITY) 259 .addClassAndMethod(this) 260 .addInt(v) 261 .addSourceLine(this, getPC() + switchOffsets[i])); 262 263 } 264 } 265 } 266 if (stack.getStackDepth() >= 2) switch (seen) { 268 case IF_ICMPEQ: 269 case IF_ICMPNE: 270 case IF_ICMPLT: 271 case IF_ICMPLE: 272 case IF_ICMPGE: 273 case IF_ICMPGT: 274 OpcodeStack.Item item0 = stack.getStackItem(0); 275 OpcodeStack.Item item1 = stack.getStackItem(1); 276 int seen2 = seen; 277 if (item1.getSpecialKind() == OpcodeStack.Item.SIGNED_BYTE) { 278 OpcodeStack.Item tmp = item0; 279 item0 = item1; 280 item1 = tmp; 281 if (seen >= IF_ICMPLT && seen <= IF_ICMPGE) 282 seen2 += 2; 283 else if (seen >= IF_ICMPGT && seen <= IF_ICMPLE) 284 seen2 -= 2; 285 } 286 Object constant1 = item1.getConstant(); 287 if (item0.getSpecialKind() == OpcodeStack.Item.SIGNED_BYTE 288 && constant1 instanceof Number ) { 289 int v1 = ((Number )constant1).intValue(); 290 if (v1 <= -129 || v1 >= 128 || v1 == 127 && !(seen2 == IF_ICMPEQ || seen2 == IF_ICMPNE 291 292 )) { 293 int priority = HIGH_PRIORITY; 294 if (v1 == 127 && seen2 == IF_ICMPLE ) priority = NORMAL_PRIORITY; 295 if (v1 == 128 && seen2 == IF_ICMPLE) priority = NORMAL_PRIORITY; 296 if (v1 <= -129) priority = NORMAL_PRIORITY; 297 298 299 bugReporter.reportBug(new BugInstance(this, "INT_BAD_COMPARISON_WITH_SIGNED_BYTE", priority) 300 .addClassAndMethod(this) 301 .addInt(v1) 302 .addSourceLine(this)); 303 } 304 } 305 } 306 if (checkForBitIorofSignedByte && seen != I2B) { 307 bugReporter.reportBug(new BugInstance(this, "BIT_IOR_OF_SIGNED_BYTE", 308 prevOpcode == LOR ? HIGH_PRIORITY : NORMAL_PRIORITY) 309 .addClassAndMethod(this) 310 .addSourceLine(this)); 311 checkForBitIorofSignedByte = false; 312 } else if ((seen == IOR || seen == LOR) && stack.getStackDepth() >= 2) { 313 OpcodeStack.Item item0 = stack.getStackItem(0); 314 OpcodeStack.Item item1 = stack.getStackItem(1); 315 316 int special0 = item0.getSpecialKind(); 317 int special1 = item1.getSpecialKind(); 318 if (special0 == OpcodeStack.Item.SIGNED_BYTE 319 && special1 == OpcodeStack.Item.LOW_8_BITS_CLEAR 320 || special0 == OpcodeStack.Item.LOW_8_BITS_CLEAR && special1 == OpcodeStack.Item.SIGNED_BYTE ) 321 checkForBitIorofSignedByte = true; 322 else checkForBitIorofSignedByte = false; 323 } else checkForBitIorofSignedByte = false; 324 325 if (prevOpcodeWasReadLine && seen == INVOKEVIRTUAL 326 && getClassConstantOperand().equals("java/lang/String") 327 && getSigConstantOperand().startsWith("()")) { 328 String method = getNameConstantOperand(); 329 String sig = getSigConstantOperand(); 330 bugReporter.reportBug(new BugInstance(this, "NP_IMMEDIATE_DEREFERENCE_OF_READLINE", NORMAL_PRIORITY) 331 .addClassAndMethod(this) 332 .addSourceLine(this)); 333 } 334 335 prevOpcodeWasReadLine = 336 (seen == INVOKEVIRTUAL||seen == INVOKEINTERFACE) 337 && getNameConstantOperand().equals("readLine") 338 && getSigConstantOperand().equals("()Ljava/lang/String;"); 339 340 switch(randomNextIntState) { 342 case 0: 343 if (seen == INVOKEVIRTUAL 344 && getClassConstantOperand().equals("java/util/Random") 345 && getNameConstantOperand().equals("nextDouble") 346 || seen == INVOKESTATIC 347 && getClassConstantOperand().equals("java/lang/Math") 348 && getNameConstantOperand().equals("random")) 349 randomNextIntState = 1; 350 break; 351 case 1: 352 if (seen == D2I) { 353 bugReporter.reportBug(new BugInstance(this, "RV_01_TO_INT", HIGH_PRIORITY) 354 .addClassAndMethod(this) 355 .addSourceLine(this)); 356 randomNextIntState = 0; 357 } 358 else if (seen == DMUL) randomNextIntState = 4; 359 else randomNextIntState = 2; 360 break; 361 case 2: 362 if (seen == I2D) randomNextIntState = 3; 363 else if (seen == DMUL) randomNextIntState = 4; 364 else randomNextIntState = 0; 365 break; 366 case 3: 367 if (seen == DMUL) randomNextIntState = 4; 368 else randomNextIntState = 0; 369 break; 370 case 4: 371 if (seen == D2I) 372 bugReporter.reportBug(new BugInstance(this, "DM_NEXTINT_VIA_NEXTDOUBLE", NORMAL_PRIORITY) 373 .addClassAndMethod(this) 374 .addSourceLine(this)); 375 randomNextIntState = 0; 376 break; 377 default: 378 throw new IllegalStateException (); 379 } 380 if (isPublicStaticVoidMain && seen == INVOKEVIRTUAL 381 && getClassConstantOperand().startsWith("javax/swing/") 382 && (getNameConstantOperand().equals("show") 383 && getSigConstantOperand().equals("()V") 384 || getNameConstantOperand().equals("pack") 385 && getSigConstantOperand().equals("()V") 386 || getNameConstantOperand().equals("setVisible") 387 && getSigConstantOperand().equals("(Z)V"))) 388 bugReporter.reportBug(new BugInstance(this, "SW_SWING_METHODS_INVOKED_IN_SWING_THREAD", LOW_PRIORITY) 389 .addClassAndMethod(this) 390 .addSourceLine(this)); 391 392 408 if ((seen == INVOKEVIRTUAL) 409 && getNameConstantOperand().equals("isAnnotationPresent") 410 && getSigConstantOperand().equals("(Ljava/lang/Class;)Z") 411 && stack.getStackDepth() > 0) { 412 OpcodeStack.Item item = stack.getStackItem(0); 413 Object value = item.getConstant(); 414 if (value instanceof String ) { 415 String annotationClassName = (String ) value; 416 boolean lacksClassfileRetention 417 = AnalysisContext.currentAnalysisContext().getAnnotationRetentionDatabase().lacksClassfileRetention( 418 annotationClassName.replace('/','.')); 419 if (lacksClassfileRetention) 420 bugReporter.reportBug(new BugInstance(this, "DMI_ANNOTATION_IS_NOT_VISIBLE_TO_REFLECTION", 421 HIGH_PRIORITY) 422 .addClassAndMethod(this) 423 .addSourceLine(this) 424 .addCalledMethod(this)); 425 } 426 427 } 428 if ((seen == INVOKEVIRTUAL) 429 && getNameConstantOperand().equals("next") 430 && getSigConstantOperand().equals("()Ljava/lang/Object;") 431 && getMethodName().equals("hasNext") 432 && getMethodSig().equals("()Z") 433 && stack.getStackDepth() > 0) { 434 OpcodeStack.Item item = stack.getStackItem(0); 435 436 bugReporter.reportBug(new BugInstance(this, "DMI_CALLING_NEXT_FROM_HASNEXT", 437 item.isInitialParameter() && item.getRegisterNumber() == 0 ? NORMAL_PRIORITY : LOW_PRIORITY) 438 .addClassAndMethod(this) 439 .addSourceLine(this) 440 .addCalledMethod(this)); 441 442 } 443 444 445 if ((seen == INVOKESPECIAL) 446 && getClassConstantOperand().equals("java/lang/String") 447 && getNameConstantOperand().equals("<init>") 448 && getSigConstantOperand().equals("(Ljava/lang/String;)V")) 449 if (alreadyReported.add(getRefConstantOperand())) 450 bugReporter.reportBug(new BugInstance(this, "DM_STRING_CTOR", NORMAL_PRIORITY) 451 .addClassAndMethod(this) 452 .addSourceLine(this)); 453 if (seen == INVOKESTATIC 454 && getClassConstantOperand().equals("java/lang/System") 455 && getNameConstantOperand().equals("runFinalizersOnExit") 456 || seen == INVOKEVIRTUAL 457 && getClassConstantOperand().equals("java/lang/Runtime") 458 && getNameConstantOperand().equals("runFinalizersOnExit")) 459 bugReporter.reportBug(new BugInstance(this, "DM_RUN_FINALIZERS_ON_EXIT", HIGH_PRIORITY) 460 .addClassAndMethod(this) 461 .addSourceLine(this)); 462 if ((seen == INVOKESPECIAL) 463 && getClassConstantOperand().equals("java/lang/String") 464 && getNameConstantOperand().equals("<init>") 465 && getSigConstantOperand().equals("()V")) 466 if (alreadyReported.add(getRefConstantOperand())) 467 bugReporter.reportBug(new BugInstance(this, "DM_STRING_VOID_CTOR", NORMAL_PRIORITY) 468 .addClassAndMethod(this) 469 .addSourceLine(this)); 470 if (!isPublicStaticVoidMain && seen == INVOKESTATIC 471 && getClassConstantOperand().equals("java/lang/System") 472 && getNameConstantOperand().equals("exit") 473 && !getMethodName().equals("processWindowEvent") 474 && !getMethodName().startsWith("windowClos") 475 && getMethodName().indexOf("exit") == -1 476 && getMethodName().indexOf("Exit") == -1 477 && getMethodName().indexOf("crash") == -1 478 && getMethodName().indexOf("Crash") == -1 479 && getMethodName().indexOf("die") == -1 480 && getMethodName().indexOf("Die") == -1 481 && getMethodName().indexOf("main") == -1) 482 accumulator.accumulateBug(new BugInstance(this, "DM_EXIT", 483 getMethod().isStatic() ? LOW_PRIORITY : NORMAL_PRIORITY) 484 .addClassAndMethod(this), 485 SourceLineAnnotation.fromVisitedInstruction(this)); 486 if (((seen == INVOKESTATIC 487 && getClassConstantOperand().equals("java/lang/System")) 488 || (seen == INVOKEVIRTUAL 489 && getClassConstantOperand().equals("java/lang/Runtime"))) 490 && getNameConstantOperand().equals("gc") 491 && getSigConstantOperand().equals("()V") 492 && !getDottedClassName().startsWith("java.lang") 493 && !getMethodName().startsWith("gc") 494 && !getMethodName().endsWith("gc")) 495 if (alreadyReported.add(getRefConstantOperand())) { 496 if (isPublicStaticVoidMain) { 498 return; 500 } 501 if (isTestMethod(getMethod())) return; 502 gcInvocationBugReport = new BugInstance(this, "DM_GC", HIGH_PRIORITY) 506 .addClassAndMethod(this) 507 .addSourceLine(this); 508 gcInvocationPC = getPC(); 509 } 511 if ((seen == INVOKESPECIAL) 512 && getClassConstantOperand().equals("java/lang/Boolean") 513 && getNameConstantOperand().equals("<init>") 514 && !getClassName().equals("java/lang/Boolean") 515 ) 516 if (alreadyReported.add(getRefConstantOperand())) 517 bugReporter.reportBug(new BugInstance(this, "DM_BOOLEAN_CTOR", NORMAL_PRIORITY) 518 .addClassAndMethod(this) 519 .addSourceLine(this)); 520 if ((seen == INVOKESTATIC) 521 && getClassConstantOperand().equals("java/lang/System") 522 && (getNameConstantOperand().equals("currentTimeMillis") 523 || getNameConstantOperand().equals("nanoTime"))) 524 sawCurrentTimeMillis = true; 525 if ((seen == INVOKEVIRTUAL) 526 && getClassConstantOperand().equals("java/lang/String") 527 && getNameConstantOperand().equals("toString") 528 && getSigConstantOperand().equals("()Ljava/lang/String;")) 529 if (alreadyReported.add(getRefConstantOperand())) 530 bugReporter.reportBug(new BugInstance(this, "DM_STRING_TOSTRING", NORMAL_PRIORITY) 531 .addClassAndMethod(this) 532 .addSourceLine(this)); 533 if ((seen == INVOKEVIRTUAL) 534 && getClassConstantOperand().equals("java/lang/String") 535 && (getNameConstantOperand().equals("toUpperCase") 536 || getNameConstantOperand().equals("toLowerCase")) 537 && getSigConstantOperand().equals("()Ljava/lang/String;")) 538 if (alreadyReported.add(getRefConstantOperand())) 539 bugReporter.reportBug(new BugInstance(this, "DM_CONVERT_CASE", LOW_PRIORITY) 540 .addClassAndMethod(this) 541 .addSourceLine(this)); 542 543 if ((seen == INVOKESPECIAL) && getNameConstantOperand().equals("<init>")) { 544 String cls = getClassConstantOperand(); 545 String sig = getSigConstantOperand(); 546 if ((cls.equals("java/lang/Integer") && sig.equals("(I)V")) 547 || (cls.equals("java/lang/Float") && sig.equals("(F)V")) 548 || (cls.equals("java/lang/Double") && sig.equals("(D)V")) 549 || (cls.equals("java/lang/Long") && sig.equals("(J)V")) 550 || (cls.equals("java/lang/Byte") && sig.equals("(B)V")) 551 || (cls.equals("java/lang/Character") && sig.equals("(C)V")) 552 || (cls.equals("java/lang/Short") && sig.equals("(S)V")) 553 || (cls.equals("java/lang/Boolean") && sig.equals("(Z)V"))) { 554 primitiveObjCtorSeen = cls; 555 } else { 556 primitiveObjCtorSeen = null; 557 } 558 } else if ((primitiveObjCtorSeen != null) 559 && (seen == INVOKEVIRTUAL) 560 && getNameConstantOperand().equals("toString") 561 && getClassConstantOperand().equals(primitiveObjCtorSeen) 562 && getSigConstantOperand().equals("()Ljava/lang/String;")) { 563 bugReporter.reportBug(new BugInstance(this, "DM_BOXED_PRIMITIVE_TOSTRING", LOW_PRIORITY) 564 .addClassAndMethod(this) 565 .addSourceLine(this)); 566 primitiveObjCtorSeen = null; 567 } 568 else 569 primitiveObjCtorSeen = null; 570 571 if ((seen == INVOKESPECIAL) && getNameConstantOperand().equals("<init>")) { 572 ctorSeen = true; 573 } else if (ctorSeen 574 && (seen == INVOKEVIRTUAL) 575 && getClassConstantOperand().equals("java/lang/Object") 576 && getNameConstantOperand().equals("getClass") 577 && getSigConstantOperand().equals("()Ljava/lang/Class;")) { 578 accumulator.accumulateBug(new BugInstance(this, "DM_NEW_FOR_GETCLASS", LOW_PRIORITY) 579 .addClassAndMethod(this), this); 580 ctorSeen = false; 581 } else { 582 ctorSeen = false; 583 } 584 585 if (jdk15ChecksEnabled 586 && (seen == INVOKEVIRTUAL) 587 && isMonitorWait(getNameConstantOperand(), getSigConstantOperand())) { 588 checkMonitorWait(); 589 } 590 591 592 if ((seen == INVOKESPECIAL) 593 && getNameConstantOperand().equals("<init>") 594 && getClassConstantOperand().equals("java/lang/Thread")) { 595 String sig = getSigConstantOperand(); 596 if (sig.equals("()V") 597 || sig.equals("(Ljava/lang/String;)V") 598 || sig.equals("(Ljava/lang/ThreadGroup;Ljava/lang/String;)V")) 599 if (!getMethodName().equals("<init>") || (getPC() > 20)) { 600 bugReporter.reportBug(new BugInstance(this, "DM_USELESS_THREAD", LOW_PRIORITY) 601 .addClassAndMethod(this) 602 .addSourceLine(this)); 603 } 604 } 605 606 607 } finally { 608 stack.sawOpcode(this,seen); 609 prevOpcode = seen; 610 } 611 } 612 613 620 private int stackEntryThatMustBeNonnegative(int seen) { 621 switch(seen) { 622 case INVOKEINTERFACE: 623 if (getClassConstantOperand().equals("java/util/List")) { 624 return getStackEntryOfListCallThatMustBeNonnegative(); 625 } 626 break; 627 case INVOKEVIRTUAL: 628 if (getClassConstantOperand().equals("java/util/LinkedList") || getClassConstantOperand().equals("java/util/ArrayList")) { 629 return getStackEntryOfListCallThatMustBeNonnegative(); 630 } 631 break; 632 633 case IALOAD: 634 case AALOAD: 635 case SALOAD: 636 case CALOAD: 637 case BALOAD: 638 case LALOAD: 639 case DALOAD: 640 case FALOAD: 641 return 0; 642 case IASTORE: 643 case AASTORE: 644 case SASTORE: 645 case CASTORE: 646 case BASTORE: 647 case LASTORE: 648 case DASTORE: 649 case FASTORE: 650 return 1; 651 } 652 return -1; 653 } 654 private int getStackEntryOfListCallThatMustBeNonnegative() { 655 String name = getNameConstantOperand(); 656 if ((name.equals("add") || name.equals("set")) 657 && getSigConstantOperand().startsWith("(I")) 658 return 1; 659 if ((name.equals("get") || name.equals("remove")) 660 && getSigConstantOperand().startsWith("(I)")) 661 return 0; 662 return -1; 663 } 664 private void checkMonitorWait() { 665 try { 666 TypeDataflow typeDataflow = getClassContext().getTypeDataflow(getMethod()); 667 TypeDataflow.LocationAndFactPair pair = typeDataflow.getLocationAndFactForInstruction(getPC()); 668 669 if (pair == null) 670 return; 671 672 Type receiver = pair.frame.getInstance( 673 pair.location.getHandle().getInstruction(), 674 getClassContext().getConstantPoolGen() 675 ); 676 677 if (!(receiver instanceof ReferenceType)) 678 return; 679 680 if (Hierarchy.isSubtype((ReferenceType) receiver, CONDITION_TYPE)) { 681 bugReporter.reportBug(new BugInstance("DM_MONITOR_WAIT_ON_CONDITION", HIGH_PRIORITY) 682 .addClassAndMethod(this) 683 .addSourceLine(this)); 684 } 685 } catch (ClassNotFoundException e) { 686 bugReporter.reportMissingClass(e); 687 } catch (DataflowAnalysisException e) { 688 bugReporter.logError("Exception caught by DumbMethods", e); 689 } catch (CFGBuilderException e) { 690 bugReporter.logError("Exception caught by DumbMethods", e); 691 } 692 } 693 694 private boolean isMonitorWait(String name, String sig) { 695 return name.equals("wait") 697 && (sig.equals("()V") || sig.equals("(J)V") || sig.equals("(JI)V")); 698 } 699 700 @Override  701 public void visit(Code obj) { 702 super.visit(obj); 703 flush(); 704 } 705 706 709 private static final int OOM_CATCH_LEN = 20; 710 711 714 private void flush() { 715 if (gcInvocationBugReport != null && !sawCurrentTimeMillis) { 716 boolean outOfMemoryHandler = false; 719 for (CodeException handler : exceptionTable) { 720 if (gcInvocationPC < handler.getHandlerPC() || 721 gcInvocationPC > handler.getHandlerPC() + OOM_CATCH_LEN) 722 continue; 723 int catchTypeIndex = handler.getCatchType(); 724 if (catchTypeIndex > 0) { 725 ConstantPool cp = getThisClass().getConstantPool(); 726 Constant constant = cp.getConstant(catchTypeIndex); 727 if (constant instanceof ConstantClass) { 728 String exClassName = (String ) ((ConstantClass) constant).getConstantValue(cp); 729 if (exClassName.equals("java/lang/OutOfMemoryError")) { 730 outOfMemoryHandler = true; 731 break; 732 } 733 } 734 } 735 } 736 737 if (!outOfMemoryHandler) 738 bugReporter.reportBug(gcInvocationBugReport); 739 } 740 741 sawCurrentTimeMillis = false; 742 gcInvocationBugReport = null; 743 alreadyReported.clear(); 744 exceptionTable = null; 745 } 746 } 747 | Popular Tags |