View Javadoc

1   /*
2    * Copyright  2000-2004 The Apache Software Foundation
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License"); 
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License. 
15   *
16   */
17  package org.apache.bcel.verifier;
18  
19  import java.util.ArrayList;
20  import java.util.HashMap;
21  import java.util.Iterator;
22  import java.util.Map;
23  import org.apache.bcel.classfile.JavaClass;
24  import org.apache.bcel.verifier.statics.Pass1Verifier;
25  import org.apache.bcel.verifier.statics.Pass2Verifier;
26  import org.apache.bcel.verifier.statics.Pass3aVerifier;
27  import org.apache.bcel.verifier.structurals.Pass3bVerifier;
28  
29  /***
30   * A Verifier instance is there to verify a class file according to The Java Virtual
31   * Machine Specification, 2nd Edition.
32   *
33   * Pass-3b-verification includes pass-3a-verification;
34   * pass-3a-verification includes pass-2-verification;
35   * pass-2-verification includes pass-1-verification.
36   *
37   * A Verifier creates PassVerifier instances to perform the actual verification.
38   * Verifier instances are usually generated by the VerifierFactory.
39   *
40   * @version $Id: Verifier.java 386056 2006-03-15 11:31:56Z tcurdt $
41   * @author Enver Haase
42   * @see org.apache.bcel.verifier.VerifierFactory
43   * @see org.apache.bcel.verifier.PassVerifier
44   */
45  public class Verifier {
46  
47      /***
48       * The name of the class this verifier operates on.
49       */
50      private final String classname;
51      /*** A Pass1Verifier for this Verifier instance. */
52      private Pass1Verifier p1v;
53      /*** A Pass2Verifier for this Verifier instance. */
54      private Pass2Verifier p2v;
55      /*** The Pass3aVerifiers for this Verifier instance. Key: Interned string specifying the method number. */
56      private Map p3avs = new HashMap();
57      /*** The Pass3bVerifiers for this Verifier instance. Key: Interned string specifying the method number. */
58      private Map p3bvs = new HashMap();
59  
60  
61      /*** Returns the VerificationResult for the given pass. */
62      public VerificationResult doPass1() {
63          if (p1v == null) {
64              p1v = new Pass1Verifier(this);
65          }
66          return p1v.verify();
67      }
68  
69  
70      /*** Returns the VerificationResult for the given pass. */
71      public VerificationResult doPass2() {
72          if (p2v == null) {
73              p2v = new Pass2Verifier(this);
74          }
75          return p2v.verify();
76      }
77  
78  
79      /*** Returns the VerificationResult for the given pass. */
80      public VerificationResult doPass3a( int method_no ) {
81          String key = Integer.toString(method_no);
82          Pass3aVerifier p3av;
83          p3av = (Pass3aVerifier) (p3avs.get(key));
84          if (p3avs.get(key) == null) {
85              p3av = new Pass3aVerifier(this, method_no);
86              p3avs.put(key, p3av);
87          }
88          return p3av.verify();
89      }
90  
91  
92      /*** Returns the VerificationResult for the given pass. */
93      public VerificationResult doPass3b( int method_no ) {
94          String key = Integer.toString(method_no);
95          Pass3bVerifier p3bv;
96          p3bv = (Pass3bVerifier) (p3bvs.get(key));
97          if (p3bvs.get(key) == null) {
98              p3bv = new Pass3bVerifier(this, method_no);
99              p3bvs.put(key, p3bv);
100         }
101         return p3bv.verify();
102     }
103 
104 
105     /***
106      * Instantiation is done by the VerifierFactory.
107      *
108      * @see VerifierFactory
109      */
110     Verifier(String fully_qualified_classname) {
111         classname = fully_qualified_classname;
112         flush();
113     }
114 
115 
116     /***
117      * Returns the name of the class this verifier operates on.
118      * This is particularly interesting when this verifier was created
119      * recursively by another Verifier and you got a reference to this
120      * Verifier by the getVerifiers() method of the VerifierFactory.
121      * @see VerifierFactory
122      */
123     public final String getClassName() {
124         return classname;
125     }
126 
127 
128     /***
129      * Forget everything known about the class file; that means, really
130      * start a new verification of a possibly different class file from
131      * BCEL's repository.
132      *
133      */
134     public void flush() {
135         p1v = null;
136         p2v = null;
137         p3avs.clear();
138         p3bvs.clear();
139     }
140 
141 
142     /***
143      * This returns all the (warning) messages collected during verification.
144      * A prefix shows from which verifying pass a message originates.
145      */
146     public String[] getMessages() throws ClassNotFoundException {
147         ArrayList messages = new ArrayList();
148         if (p1v != null) {
149             String[] p1m = p1v.getMessages();
150             for (int i = 0; i < p1m.length; i++) {
151                 messages.add("Pass 1: " + p1m[i]);
152             }
153         }
154         if (p2v != null) {
155             String[] p2m = p2v.getMessages();
156             for (int i = 0; i < p2m.length; i++) {
157                 messages.add("Pass 2: " + p2m[i]);
158             }
159         }
160         Iterator p3as = p3avs.values().iterator();
161         while (p3as.hasNext()) {
162             Pass3aVerifier pv = (Pass3aVerifier) p3as.next();
163             String[] p3am = pv.getMessages();
164             int meth = pv.getMethodNo();
165             for (int i = 0; i < p3am.length; i++) {
166                 messages.add("Pass 3a, method " + meth + " ('"
167                         + org.apache.bcel.Repository.lookupClass(classname).getMethods()[meth]
168                         + "'): " + p3am[i]);
169             }
170         }
171         Iterator p3bs = p3bvs.values().iterator();
172         while (p3bs.hasNext()) {
173             Pass3bVerifier pv = (Pass3bVerifier) p3bs.next();
174             String[] p3bm = pv.getMessages();
175             int meth = pv.getMethodNo();
176             for (int i = 0; i < p3bm.length; i++) {
177                 messages.add("Pass 3b, method " + meth + " ('"
178                         + org.apache.bcel.Repository.lookupClass(classname).getMethods()[meth]
179                         + "'): " + p3bm[i]);
180             }
181         }
182         String[] ret = new String[messages.size()];
183         for (int i = 0; i < messages.size(); i++) {
184             ret[i] = (String) messages.get(i);
185         }
186         return ret;
187     }
188 
189 
190     /***
191      * Verifies class files.
192      * This is a simple demonstration of how the API of BCEL's
193      * class file verifier "JustIce" may be used.
194      * You should supply command-line arguments which are
195      * fully qualified namea of the classes to verify. These class files
196      * must be somewhere in your CLASSPATH (refer to Sun's
197      * documentation for questions about this) or you must have put the classes
198      * into the BCEL Repository yourself (via 'addClass(JavaClass)').
199      */
200     public static void main( String[] args ) {
201         System.out
202                 .println("JustIce by Enver Haase, (C) 2001-2002.\n<http://bcel.sourceforge.net>\n<http://jakarta.apache.org/bcel>\n");
203         for (int k = 0; k < args.length; k++) {
204             try {
205                 if (args[k].endsWith(".class")) {
206                     int dotclasspos = args[k].lastIndexOf(".class");
207                     if (dotclasspos != -1) {
208                         args[k] = args[k].substring(0, dotclasspos);
209                     }
210                 }
211                 args[k] = args[k].replace('/', '.');
212                 System.out.println("Now verifying: " + args[k] + "\n");
213                 Verifier v = VerifierFactory.getVerifier(args[k]);
214                 VerificationResult vr;
215                 vr = v.doPass1();
216                 System.out.println("Pass 1:\n" + vr);
217                 vr = v.doPass2();
218                 System.out.println("Pass 2:\n" + vr);
219                 if (vr == VerificationResult.VR_OK) {
220                     JavaClass jc = org.apache.bcel.Repository.lookupClass(args[k]);
221                     for (int i = 0; i < jc.getMethods().length; i++) {
222                         vr = v.doPass3a(i);
223                         System.out.println("Pass 3a, method number " + i + " ['"
224                                 + jc.getMethods()[i] + "']:\n" + vr);
225                         vr = v.doPass3b(i);
226                         System.out.println("Pass 3b, method number " + i + " ['"
227                                 + jc.getMethods()[i] + "']:\n" + vr);
228                     }
229                 }
230                 System.out.println("Warnings:");
231                 String[] warnings = v.getMessages();
232                 if (warnings.length == 0) {
233                     System.out.println("<none>");
234                 }
235                 for (int j = 0; j < warnings.length; j++) {
236                     System.out.println(warnings[j]);
237                 }
238                 System.out.println("\n");
239                 // avoid swapping.
240                 v.flush();
241                 org.apache.bcel.Repository.clearCache();
242                 System.gc();
243             } catch (ClassNotFoundException e) {
244                 e.printStackTrace();
245             }
246         }
247     }
248 }