1 19 20 package edu.umd.cs.findbugs.detect; 21 22 23 import edu.umd.cs.findbugs.*; 24 import org.apache.bcel.classfile.Code; 25 26 public class WaitInLoop extends BytecodeScanningDetector implements StatelessDetector { 27 28 boolean sawWait = false; 29 boolean sawAwait = false; 30 boolean waitHasTimeout = false; 31 boolean sawNotify = false; 32 int notifyPC; 33 int earliestJump = 0; 34 int waitAt = 0; 35 private BugReporter bugReporter; 36 37 public WaitInLoop(BugReporter bugReporter) { 38 this.bugReporter = bugReporter; 39 } 40 41 42 43 @Override 44 public void visit(Code obj) { 45 sawWait = false; 46 sawAwait = false; 47 waitHasTimeout = false; 48 sawNotify = false; 49 earliestJump = 9999999; 50 super.visit(obj); 51 if ((sawWait || sawAwait) && waitAt < earliestJump) { 52 String bugType = sawWait ? "WA_NOT_IN_LOOP" : "WA_AWAIT_NOT_IN_LOOP"; 53 bugReporter.reportBug(new BugInstance(this, bugType, waitHasTimeout ? LOW_PRIORITY : NORMAL_PRIORITY) 54 .addClassAndMethod(this) 55 .addSourceLine(this, waitAt)); 56 } 57 if (sawNotify) 58 bugReporter.reportBug(new BugInstance(this, "NO_NOTIFY_NOT_NOTIFYALL", LOW_PRIORITY) 59 .addClassAndMethod(this) 60 .addSourceLine(this, notifyPC)); 61 } 62 63 @Override 64 public void sawOpcode(int seen) { 65 66 if ((seen == INVOKEVIRTUAL || seen == INVOKEINTERFACE) 67 && getNameConstantOperand().equals("notify") 68 && getSigConstantOperand().equals("()V")) { 69 sawNotify = true; 70 notifyPC = getPC(); 71 } 72 if (!(sawWait || sawAwait) 73 && (seen == INVOKEVIRTUAL || seen == INVOKEINTERFACE) 74 && (isMonitorWait() || isConditionAwait())) { 75 76 if (getNameConstantOperand().equals("wait")) { 77 sawWait = true; 78 } else { 79 sawAwait = true; 80 } 81 waitHasTimeout = !getSigConstantOperand().equals("()V"); 82 waitAt = getPC(); 83 earliestJump = getPC() + 1; 84 return; 85 } 86 if (seen >= IFEQ && seen <= GOTO 87 || seen >= IFNULL && seen <= GOTO_W) 88 earliestJump = Math.min(earliestJump, getBranchTarget()); 89 } 90 91 private boolean isConditionAwait() { 92 String className = getClassConstantOperand(); 93 String name = getNameConstantOperand(); 94 String sig = getSigConstantOperand(); 95 96 if (!className.equals("java/util/concurrent/locks/Condition")) return false; 97 98 if (!name.startsWith("await")) return false; 99 100 if ( 101 name.equals("await") && 102 (sig.equals("()V") || sig.equals("(JLjava/util/concurrent/TimeUnit;)V"))) 103 return true; 104 if (name.equals("awaitNanos") && sig.equals("(J)V")) 105 return true; 106 if (name.equals("awaitUninterruptibly") && sig.equals("()V")) 107 return true; 108 if (name.equals("awaitUntil") && sig.equals("(Ljava/util/Date;)V")) 109 return true; 110 111 return false; 112 } 113 114 private boolean isMonitorWait() { 115 String name = getNameConstantOperand(); 116 String sig = getSigConstantOperand(); 117 118 return name.equals("wait") 119 && (sig.equals("()V") || sig.equals("(J)V") || sig.equals("(JI)V")); 120 } 121 122 123 } 124 | Popular Tags |