1 19 20 package edu.umd.cs.findbugs.detect; 21 22 23 import edu.umd.cs.findbugs.*; 24 import edu.umd.cs.findbugs.ba.*; 25 import edu.umd.cs.findbugs.ba.vna.*; 26 27 import java.util.*; 28 import org.apache.bcel.Constants; 29 import org.apache.bcel.classfile.*; 30 import org.apache.bcel.generic.*; 31 32 public final class FindMismatchedWaitOrNotify implements Detector, StatelessDetector { 33 private BugReporter bugReporter; 34 35 public FindMismatchedWaitOrNotify(BugReporter bugReporter) { 36 this.bugReporter = bugReporter; 37 } 38 39 @Override 40 public Object clone() { 41 try { 42 return super.clone(); 43 } catch (CloneNotSupportedException e) { 44 throw new AssertionError (e); 45 } 46 } 47 48 public void visitClassContext(ClassContext classContext) { 49 JavaClass jclass = classContext.getJavaClass(); 50 51 Method[] methodList = jclass.getMethods(); 52 for (Method method : methodList) { 53 MethodGen methodGen = classContext.getMethodGen(method); 54 if (methodGen == null) 55 continue; 56 57 BitSet bytecodeSet = classContext.getBytecodeSet(method); 60 if (bytecodeSet == null) continue; 61 if (!(bytecodeSet.get(Constants.MONITORENTER) && bytecodeSet.get(Constants.INVOKEVIRTUAL))) 62 continue; 63 64 try { 65 analyzeMethod(classContext, method); 66 } catch (DataflowAnalysisException e) { 67 bugReporter.logError("FindMismatchedWaitOrNotify: caught exception", e); 68 } catch (CFGBuilderException e) { 69 bugReporter.logError("FindMismatchedWaitOrNotify: caught exception", e); 70 } 71 } 72 } 73 74 private void analyzeMethod(ClassContext classContext, Method method) 75 throws CFGBuilderException, DataflowAnalysisException { 76 77 MethodGen methodGen = classContext.getMethodGen(method); 78 if (methodGen == null) return; 79 ConstantPoolGen cpg = methodGen.getConstantPool(); 80 CFG cfg = classContext.getCFG(method); 81 ValueNumberDataflow vnaDataflow = classContext.getValueNumberDataflow(method); 82 LockDataflow dataflow = classContext.getLockDataflow(method); 83 84 for (Iterator<Location> i = cfg.locationIterator(); i.hasNext();) { 85 Location location = i.next(); 86 87 InstructionHandle handle = location.getHandle(); 88 89 Instruction ins = handle.getInstruction(); 90 if (!(ins instanceof INVOKEVIRTUAL)) 91 continue; 92 INVOKEVIRTUAL inv = (INVOKEVIRTUAL) ins; 93 94 String methodName = inv.getName(cpg); 95 String methodSig = inv.getSignature(cpg); 96 97 if (Hierarchy.isMonitorWait(methodName, methodSig) 98 || Hierarchy.isMonitorNotify(methodName, methodSig)) { 99 int numConsumed = inv.consumeStack(cpg); 100 if (numConsumed == Constants.UNPREDICTABLE) 101 throw new DataflowAnalysisException("Unpredictable stack consumption", methodGen, handle); 102 103 ValueNumberFrame frame = vnaDataflow.getFactAtLocation(location); 104 if (!frame.isValid()) 105 continue; 107 if (frame.getStackDepth() - numConsumed < 0) 108 throw new DataflowAnalysisException("Stack underflow", methodGen, handle); 109 ValueNumber ref = frame.getValue(frame.getNumSlots() - numConsumed); 110 LockSet lockSet = dataflow.getFactAtLocation(location); 111 int lockCount = lockSet.getLockCount(ref.getNumber()); 112 113 if (lockCount == 0) { 114 Collection<ValueNumber> lockedValueNumbers = lockSet.getLockedValueNumbers(frame); 115 boolean foundMatch = false; 116 for(ValueNumber v : lockedValueNumbers) 117 if (frame.fuzzyMatch(ref, v)){ 118 foundMatch = true; 119 break; 120 } 121 122 if (!foundMatch) { 123 124 String type = methodName.equals("wait") 125 ? "MWN_MISMATCHED_WAIT" 126 : "MWN_MISMATCHED_NOTIFY"; 127 String sourceFile = classContext.getJavaClass().getSourceFileName(); 128 int priority = method.isPublic() ? NORMAL_PRIORITY : LOW_PRIORITY; 131 132 bugReporter.reportBug(new BugInstance(this, type, priority) 133 .addClassAndMethod(methodGen, sourceFile) 134 .addSourceLine(classContext, methodGen, sourceFile, handle)); 135 } 136 } 137 } 138 } 139 } 140 141 public void report() { 142 } 143 } 144 145 | Popular Tags |