KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * FindBugs - Find bugs in Java programs
3  * Copyright (C) 2003-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 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 JavaDoc
40     public Object JavaDoc clone() {
41         try {
42             return super.clone();
43         } catch (CloneNotSupportedException JavaDoc e) {
44             throw new AssertionError JavaDoc(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             // Don't bother analyzing the method unless there is both locking
58
// and a method call.
59
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 JavaDoc methodName = inv.getName(cpg);
95             String JavaDoc 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                     // Probably dead code
106
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 JavaDoc type = methodName.equals("wait")
125                         ? "MWN_MISMATCHED_WAIT"
126                                 : "MWN_MISMATCHED_NOTIFY";
127                         String JavaDoc sourceFile = classContext.getJavaClass().getSourceFileName();
128                         // Report as medium priority only if the method is public.
129
// Non-public methods may be properly locked in a calling context.
130
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 //vim:ts=3
146
Popular Tags