Home | History | Annotate | Download | only in verifier
      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$
     43  * @see VerifierFactory
     44  * @see PassVerifier
     45  */
     46 public class Verifier {
     47 
     48     /**
     49      * The name of the class this verifier operates on.
     50      */
     51     private final String classname;
     52     /** A Pass1Verifier for this Verifier instance. */
     53     private Pass1Verifier p1v;
     54     /** A Pass2Verifier for this Verifier instance. */
     55     private Pass2Verifier p2v;
     56     /** The Pass3aVerifiers for this Verifier instance. Key: Interned string specifying the method number. */
     57     private final Map<String, Pass3aVerifier> p3avs = new HashMap<>();
     58     /** The Pass3bVerifiers for this Verifier instance. Key: Interned string specifying the method number. */
     59     private final Map<String, Pass3bVerifier> p3bvs = new HashMap<>();
     60 
     61 
     62     /** Returns the VerificationResult for the given pass. */
     63     public VerificationResult doPass1() {
     64         if (p1v == null) {
     65             p1v = new Pass1Verifier(this);
     66         }
     67         return p1v.verify();
     68     }
     69 
     70 
     71     /** Returns the VerificationResult for the given pass. */
     72     public VerificationResult doPass2() {
     73         if (p2v == null) {
     74             p2v = new Pass2Verifier(this);
     75         }
     76         return p2v.verify();
     77     }
     78 
     79 
     80     /** Returns the VerificationResult for the given pass. */
     81     public VerificationResult doPass3a( final int method_no ) {
     82         final String key = Integer.toString(method_no);
     83         Pass3aVerifier p3av;
     84         p3av = p3avs.get(key);
     85         if (p3avs.get(key) == null) {
     86             p3av = new Pass3aVerifier(this, method_no);
     87             p3avs.put(key, p3av);
     88         }
     89         return p3av.verify();
     90     }
     91 
     92 
     93     /** Returns the VerificationResult for the given pass. */
     94     public VerificationResult doPass3b( final int method_no ) {
     95         final String key = Integer.toString(method_no);
     96         Pass3bVerifier p3bv;
     97         p3bv = p3bvs.get(key);
     98         if (p3bvs.get(key) == null) {
     99             p3bv = new Pass3bVerifier(this, method_no);
    100             p3bvs.put(key, p3bv);
    101         }
    102         return p3bv.verify();
    103     }
    104 
    105 
    106     /**
    107      * Instantiation is done by the VerifierFactory.
    108      *
    109      * @see VerifierFactory
    110      */
    111     Verifier(final String fully_qualified_classname) {
    112         classname = fully_qualified_classname;
    113         flush();
    114     }
    115 
    116 
    117     /**
    118      * Returns the name of the class this verifier operates on.
    119      * This is particularly interesting when this verifier was created
    120      * recursively by another Verifier and you got a reference to this
    121      * Verifier by the getVerifiers() method of the VerifierFactory.
    122      * @see VerifierFactory
    123      */
    124     public final String getClassName() {
    125         return classname;
    126     }
    127 
    128 
    129     /**
    130      * Forget everything known about the class file; that means, really
    131      * start a new verification of a possibly different class file from
    132      * BCEL's repository.
    133      *
    134      */
    135     public void flush() {
    136         p1v = null;
    137         p2v = null;
    138         p3avs.clear();
    139         p3bvs.clear();
    140     }
    141 
    142 
    143     /**
    144      * This returns all the (warning) messages collected during verification.
    145      * A prefix shows from which verifying pass a message originates.
    146      */
    147     public String[] getMessages() throws ClassNotFoundException {
    148         final List<String> messages = new ArrayList<>();
    149         if (p1v != null) {
    150             final String[] p1m = p1v.getMessages();
    151             for (final String element : p1m) {
    152                 messages.add("Pass 1: " + element);
    153             }
    154         }
    155         if (p2v != null) {
    156             final String[] p2m = p2v.getMessages();
    157             for (final String element : p2m) {
    158                 messages.add("Pass 2: " + element);
    159             }
    160         }
    161         for (final Pass3aVerifier pv : p3avs.values()) {
    162             final String[] p3am = pv.getMessages();
    163             final int meth = pv.getMethodNo();
    164             for (final String element : p3am) {
    165                 messages.add("Pass 3a, method " + meth + " ('"
    166                         + org.apache.bcel.Repository.lookupClass(classname).getMethods()[meth]
    167                         + "'): " + element);
    168             }
    169         }
    170         for (final Pass3bVerifier pv : p3bvs.values()) {
    171             final String[] p3bm = pv.getMessages();
    172             final int meth = pv.getMethodNo();
    173             for (final String element : p3bm) {
    174                 messages.add("Pass 3b, method " + meth + " ('"
    175                         + org.apache.bcel.Repository.lookupClass(classname).getMethods()[meth]
    176                         + "'): " + element);
    177             }
    178         }
    179 
    180         return messages.toArray(new String[messages.size()]);
    181     }
    182 
    183 
    184     /**
    185      * Verifies class files.
    186      * This is a simple demonstration of how the API of BCEL's
    187      * class file verifier "JustIce" may be used.
    188      * You should supply command-line arguments which are
    189      * fully qualified namea of the classes to verify. These class files
    190      * must be somewhere in your CLASSPATH (refer to Sun's
    191      * documentation for questions about this) or you must have put the classes
    192      * into the BCEL Repository yourself (via 'addClass(JavaClass)').
    193      */
    194     public static void main( final String[] args ) {
    195         System.out
    196                 .println("JustIce by Enver Haase, (C) 2001-2002.\n<http://bcel.sourceforge.net>\n<http://commons.apache.org/bcel>\n");
    197         for (int k = 0; k < args.length; k++) {
    198             try {
    199                 if (args[k].endsWith(".class")) {
    200                     final int dotclasspos = args[k].lastIndexOf(".class");
    201                     if (dotclasspos != -1) {
    202                         args[k] = args[k].substring(0, dotclasspos);
    203                     }
    204                 }
    205                 args[k] = args[k].replace('/', '.');
    206                 System.out.println("Now verifying: " + args[k] + "\n");
    207                 final Verifier v = VerifierFactory.getVerifier(args[k]);
    208                 VerificationResult vr;
    209                 vr = v.doPass1();
    210                 System.out.println("Pass 1:\n" + vr);
    211                 vr = v.doPass2();
    212                 System.out.println("Pass 2:\n" + vr);
    213                 if (vr == VerificationResult.VR_OK) {
    214                     final JavaClass jc = org.apache.bcel.Repository.lookupClass(args[k]);
    215                     for (int i = 0; i < jc.getMethods().length; i++) {
    216                         vr = v.doPass3a(i);
    217                         System.out.println("Pass 3a, method number " + i + " ['"
    218                                 + jc.getMethods()[i] + "']:\n" + vr);
    219                         vr = v.doPass3b(i);
    220                         System.out.println("Pass 3b, method number " + i + " ['"
    221                                 + jc.getMethods()[i] + "']:\n" + vr);
    222                     }
    223                 }
    224                 System.out.println("Warnings:");
    225                 final String[] warnings = v.getMessages();
    226                 if (warnings.length == 0) {
    227                     System.out.println("<none>");
    228                 }
    229                 for (final String warning : warnings) {
    230                     System.out.println(warning);
    231                 }
    232                 System.out.println("\n");
    233                 // avoid swapping.
    234                 v.flush();
    235                 org.apache.bcel.Repository.clearCache();
    236                 System.gc();
    237             } catch (final ClassNotFoundException e) {
    238                 e.printStackTrace();
    239             }
    240         }
    241     }
    242 }
    243