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