KickJava   Java API By Example, From Geeks To Geeks.

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


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 java.util.*;
26 import org.apache.bcel.classfile.*;
27 import org.apache.bcel.generic.*;
28
29 public final class FindTwoLockWait implements Detector, StatelessDetector {
30
31     private BugReporter bugReporter;
32     private JavaClass javaClass;
33
34     private Collection<BugInstance> possibleWaitBugs = new LinkedList<BugInstance>();
35     private Collection<SourceLineAnnotation> possibleNotifyLocations = new LinkedList<SourceLineAnnotation>();
36     public FindTwoLockWait(BugReporter bugReporter) {
37         this.bugReporter = bugReporter;
38     }
39
40     @Override JavaDoc
41     public Object JavaDoc clone() {
42         try {
43             return super.clone();
44         } catch (CloneNotSupportedException JavaDoc e) {
45             throw new AssertionError JavaDoc(e);
46         }
47     }
48
49     public void visitClassContext(ClassContext classContext) {
50         javaClass = classContext.getJavaClass();
51         possibleWaitBugs.clear();
52         possibleNotifyLocations.clear();
53         Method[] methodList = javaClass.getMethods();
54         for (Method method : methodList) {
55             MethodGen methodGen = classContext.getMethodGen(method);
56             if (methodGen == null)
57                 continue;
58
59             if (!preScreen(methodGen))
60                 continue;
61
62             try {
63                 analyzeMethod(classContext, method);
64             } catch (DataflowAnalysisException e) {
65                 // bugReporter.logError("Error analyzing " + method.toString(), e);
66
} catch (CFGBuilderException e) {
67                 bugReporter.logError("Error analyzing " + method.toString(), e);
68             }
69         }
70         if (!possibleNotifyLocations.isEmpty())
71             for(BugInstance bug : possibleWaitBugs ) {
72                 for(SourceLineAnnotation notifyLine : possibleNotifyLocations)
73                     bug.addSourceLine(notifyLine).describe("SOURCE_NOTIFICATION_DEADLOCK");
74                 bugReporter.reportBug(bug);
75             }
76     }
77
78     private void analyzeMethod(ClassContext classContext, Method method)
79             throws CFGBuilderException, DataflowAnalysisException {
80
81         MethodGen methodGen = classContext.getMethodGen(method);
82         CFG cfg = classContext.getCFG(method);
83         LockDataflow dataflow = classContext.getLockDataflow(method);
84
85         for (Iterator<Location> j = cfg.locationIterator(); j.hasNext();) {
86             Location location = j.next();
87             visitLocation(classContext, location, methodGen, dataflow);
88         }
89     }
90
91     public boolean preScreen(MethodGen mg) {
92         ConstantPoolGen cpg = mg.getConstantPool();
93
94         int lockCount = mg.isSynchronized() ? 1 : 0;
95         boolean sawWaitOrNotify = false;
96
97         InstructionHandle handle = mg.getInstructionList().getStart();
98         while (handle != null && !(lockCount >= 2 && sawWaitOrNotify)) {
99             Instruction ins = handle.getInstruction();
100             if (ins instanceof MONITORENTER)
101                 ++lockCount;
102             else if (ins instanceof INVOKEVIRTUAL) {
103                 INVOKEVIRTUAL inv = (INVOKEVIRTUAL) ins;
104                 String JavaDoc methodName = inv.getMethodName(cpg);
105                 if (methodName.equals("wait") || methodName.startsWith("notify"))
106                     sawWaitOrNotify = true;
107             }
108
109             handle = handle.getNext();
110         }
111
112         return lockCount >= 2 && sawWaitOrNotify;
113     }
114
115     public void visitLocation(ClassContext classContext, Location location, MethodGen methodGen, LockDataflow dataflow) throws DataflowAnalysisException {
116         ConstantPoolGen cpg = methodGen.getConstantPool();
117         
118         if (Hierarchy.isMonitorWait(location.getHandle().getInstruction(), cpg)) {
119             int count = dataflow.getFactAtLocation(location).getNumLockedObjects();
120             if (count > 1) {
121                 // A wait with multiple locks held?
122
String JavaDoc sourceFile = javaClass.getSourceFileName();
123                 possibleWaitBugs.add(new BugInstance(this, "TLW_TWO_LOCK_WAIT", HIGH_PRIORITY )
124                         .addClass(javaClass)
125                         .addMethod(methodGen, sourceFile)
126                         .addSourceLine(classContext, methodGen, sourceFile, location.getHandle()));
127             }
128         }
129         if (Hierarchy.isMonitorNotify(location.getHandle().getInstruction(), cpg)) {
130             int count = dataflow.getFactAtLocation(location).getNumLockedObjects();
131             if (count > 1) {
132                 // A notify with multiple locks held?
133
String JavaDoc sourceFile = javaClass.getSourceFileName();
134                 possibleNotifyLocations.add(SourceLineAnnotation.fromVisitedInstruction(classContext, methodGen, sourceFile, location.getHandle()));
135             }
136         }
137     }
138
139     public void report() {
140     }
141 }
142
143 // vim:ts=3
144
Popular Tags