KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * Bytecode Analysis Framework
3  * Copyright (C) 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 import java.util.HashSet JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.Set JavaDoc;
25
26 import org.apache.bcel.classfile.Method;
27 import org.apache.bcel.generic.MethodGen;
28
29 import edu.umd.cs.findbugs.BugInstance;
30 import edu.umd.cs.findbugs.BugReporter;
31 import edu.umd.cs.findbugs.Detector;
32 import edu.umd.cs.findbugs.SystemProperties;
33 import edu.umd.cs.findbugs.ba.CFG;
34 import edu.umd.cs.findbugs.ba.CFGBuilderException;
35 import edu.umd.cs.findbugs.ba.ClassContext;
36 import edu.umd.cs.findbugs.ba.Dataflow;
37 import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
38 import edu.umd.cs.findbugs.ba.DataflowCFGPrinter;
39 import edu.umd.cs.findbugs.ba.DepthFirstSearch;
40 import edu.umd.cs.findbugs.ba.SignatureConverter;
41 import edu.umd.cs.findbugs.ba.obl.Obligation;
42 import edu.umd.cs.findbugs.ba.obl.ObligationAnalysis;
43 import edu.umd.cs.findbugs.ba.obl.ObligationFactory;
44 import edu.umd.cs.findbugs.ba.obl.PolicyDatabase;
45 import edu.umd.cs.findbugs.ba.obl.State;
46 import edu.umd.cs.findbugs.ba.obl.StateSet;
47 import edu.umd.cs.findbugs.ba.type.TypeDataflow;
48
49 /**
50  * Find unsatisfied obligations in Java methods.
51  * Examples: open streams, open database connections, etc.
52  *
53  * <p>See Weimer and Necula,
54  * <a HREF="http://doi.acm.org/10.1145/1028976.1029011"
55  * >Finding and preventing run-time error handling mistakes</a>,
56  * OOPSLA 2004.</p>
57  *
58  * @author David Hovemeyer
59  */

60 public class FindUnsatisfiedObligation implements Detector {
61     
62     private static final boolean ENABLE = SystemProperties.getBoolean("oa.enable");
63     private static final boolean DEBUG = SystemProperties.getBoolean("oa.debug");
64     private static final boolean DEBUG_PRINTCFG = SystemProperties.getBoolean("oa.printcfg");
65     private static final String JavaDoc DEBUG_METHOD = SystemProperties.getProperty("oa.method");
66     
67     private BugReporter bugReporter;
68     private ObligationFactory factory;
69     private PolicyDatabase database;
70     
71     public FindUnsatisfiedObligation(BugReporter bugReporter) {
72         this.bugReporter = bugReporter;
73         this.factory = new ObligationFactory();
74         this.database = buildDatabase();
75     }
76
77     /* (non-Javadoc)
78      * @see edu.umd.cs.findbugs.Detector#visitClassContext(edu.umd.cs.findbugs.ba.ClassContext)
79      */

80     public void visitClassContext(ClassContext classContext) {
81         if (!ENABLE) {
82             return;
83         }
84         
85         // FIXME: prescreen class
86

87         Method[] methodList = classContext.getJavaClass().getMethods();
88         for (Method method : methodList) {
89             if (DEBUG_METHOD != null && !method.getName().equals(DEBUG_METHOD))
90                 continue;
91
92             MethodGen methodGen = classContext.getMethodGen(method);
93
94             if (methodGen != null) {
95                 // FIXME: prescreen method
96
analyzeMethod(classContext, method);
97             }
98         }
99     }
100
101     /**
102      * Analyze given method for unsatisfied obligations.
103      *
104      * @param classContext the ClassContext of the class containing the method
105      * @param method the method
106      */

107     private void analyzeMethod(ClassContext classContext, Method method) {
108         MethodGen methodGen = classContext.getMethodGen(method);
109         if (methodGen == null) return;
110         if (DEBUG) {
111             System.out.println("*** Analyzing method " +
112                     SignatureConverter.convertMethodSignature(methodGen));
113         }
114
115         try {
116             CFG cfg = classContext.getCFG(method);
117             DepthFirstSearch dfs = classContext.getDepthFirstSearch(method);
118             TypeDataflow typeDataflow = classContext.getTypeDataflow(method);
119             assert typeDataflow != null;
120             
121             ObligationAnalysis analysis =
122                 new ObligationAnalysis(dfs, typeDataflow, methodGen, factory, database, bugReporter);
123             Dataflow<StateSet, ObligationAnalysis> dataflow =
124                 new Dataflow<StateSet, ObligationAnalysis>(cfg, analysis);
125             
126             dataflow.execute();
127             
128             if (DEBUG_PRINTCFG) {
129                 System.out.println("Dataflow CFG:");
130                 DataflowCFGPrinter.printCFG(dataflow, System.out);
131             }
132             
133             // See if there are any states with nonempty obligation sets
134
StateSet factAtExit = dataflow.getStartFact(cfg.getExit());
135             Set JavaDoc<Obligation> leakedObligationSet = new HashSet JavaDoc<Obligation>();
136             for (Iterator JavaDoc<State> i = factAtExit.stateIterator(); i.hasNext();) {
137                 State state = i.next();
138                 for (int id = 0; id < factory.getMaxObligationTypes(); ++id) {
139                     if (state.getObligationSet().getCount(id) > 0) {
140                         leakedObligationSet.add(factory.getObligationById(id));
141                     }
142                 }
143             }
144
145             for (Obligation obligation : leakedObligationSet) {
146                 bugReporter.reportBug(new BugInstance(this, "OS_OPEN_STREAM", NORMAL_PRIORITY)
147                         .addClassAndMethod(methodGen, classContext.getJavaClass().getSourceFileName())
148                         .addClass(obligation.getClassName()).describe("CLASS_REFTYPE")
149                 );
150             }
151         } catch (CFGBuilderException e) {
152             bugReporter.logError(
153                     "Error building CFG for " +
154                     SignatureConverter.convertMethodSignature(methodGen), e);
155         } catch (DataflowAnalysisException e) {
156             bugReporter.logError(
157                     "ObligationAnalysis error while analyzing " +
158                     SignatureConverter.convertMethodSignature(methodGen), e);
159         }
160     }
161
162     /* (non-Javadoc)
163      * @see edu.umd.cs.findbugs.Detector#report()
164      */

165     public void report() {
166         // Nothing to do here
167
}
168
169     /**
170      * Create the PolicyDatabase.
171      *
172      * @return the PolicyDatabase
173      */

174     private PolicyDatabase buildDatabase() {
175         PolicyDatabase result = new PolicyDatabase();
176         
177         // Create the Obligation types
178
Obligation inputStreamObligation = factory.addObligation("java.io.InputStream");
179         Obligation outputStreamObligation = factory.addObligation("java.io.OutputStream");
180
181         // Add the database entries describing methods that add and delete
182
// obligations.
183
result.addEntry("java.io.FileInputStream", "<init>", "(Ljava/lang/String;)V", false,
184                 PolicyDatabase.ADD, inputStreamObligation);
185         result.addEntry("java.io.FileOutputStream", "<init>", "(Ljava/lang/String;)V", false,
186                 PolicyDatabase.ADD, outputStreamObligation);
187         result.addEntry("java.io.InputStream", "close", "()V", false,
188                 PolicyDatabase.DEL, inputStreamObligation);
189         result.addEntry("java.io.OutputStream", "close", "()V", false,
190                 PolicyDatabase.DEL, outputStreamObligation);
191         
192         return result;
193     }
194
195 }
196
Popular Tags