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 }