1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.  Oracle designates this
   7  * particular file as subject to the "Classpath" exception as provided
   8  * by Oracle in the LICENSE file that accompanied this code.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 /*
  26  * This file is available under and governed by the GNU General Public
  27  * License version 2 only, as published by the Free Software Foundation.
  28  * However, the following notice accompanied the original version of this
  29  * file:
  30  *
  31  * ASM: a very small and fast Java bytecode manipulation framework
  32  * Copyright (c) 2000-2011 INRIA, France Telecom
  33  * All rights reserved.
  34  *
  35  * Redistribution and use in source and binary forms, with or without
  36  * modification, are permitted provided that the following conditions
  37  * are met:
  38  * 1. Redistributions of source code must retain the above copyright
  39  *    notice, this list of conditions and the following disclaimer.
  40  * 2. Redistributions in binary form must reproduce the above copyright
  41  *    notice, this list of conditions and the following disclaimer in the
  42  *    documentation and/or other materials provided with the distribution.
  43  * 3. Neither the name of the copyright holders nor the names of its
  44  *    contributors may be used to endorse or promote products derived from
  45  *    this software without specific prior written permission.
  46  *
  47  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  48  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  50  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  51  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  52  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  53  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  54  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  55  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  57  * THE POSSIBILITY OF SUCH DAMAGE.
  58  */
  59 package jdk.internal.org.objectweb.asm.util;
  60 
  61 import java.io.FileInputStream;
  62 import java.io.IOException;
  63 import java.io.InputStream;
  64 import java.io.PrintWriter;
  65 import java.util.ArrayList;
  66 import java.util.HashMap;
  67 import java.util.List;
  68 import java.util.Map;
  69 import jdk.internal.org.objectweb.asm.AnnotationVisitor;
  70 import jdk.internal.org.objectweb.asm.Attribute;
  71 import jdk.internal.org.objectweb.asm.ClassReader;
  72 import jdk.internal.org.objectweb.asm.ClassVisitor;
  73 import jdk.internal.org.objectweb.asm.FieldVisitor;
  74 import jdk.internal.org.objectweb.asm.Label;
  75 import jdk.internal.org.objectweb.asm.MethodVisitor;
  76 import jdk.internal.org.objectweb.asm.ModuleVisitor;
  77 import jdk.internal.org.objectweb.asm.Opcodes;
  78 import jdk.internal.org.objectweb.asm.Type;
  79 import jdk.internal.org.objectweb.asm.TypePath;
  80 import jdk.internal.org.objectweb.asm.TypeReference;
  81 import jdk.internal.org.objectweb.asm.tree.ClassNode;
  82 import jdk.internal.org.objectweb.asm.tree.MethodNode;
  83 import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode;
  84 import jdk.internal.org.objectweb.asm.tree.analysis.Analyzer;
  85 import jdk.internal.org.objectweb.asm.tree.analysis.AnalyzerException;
  86 import jdk.internal.org.objectweb.asm.tree.analysis.BasicValue;
  87 import jdk.internal.org.objectweb.asm.tree.analysis.Frame;
  88 import jdk.internal.org.objectweb.asm.tree.analysis.SimpleVerifier;
  89 
  90 /**
  91  * A {@link ClassVisitor} that checks that its methods are properly used. More precisely this class
  92  * adapter checks each method call individually, based <i>only</i> on its arguments, but does
  93  * <i>not</i> check the <i>sequence</i> of method calls. For example, the invalid sequence {@code
  94  * visitField(ACC_PUBLIC, "i", "I", null)} {@code visitField(ACC_PUBLIC, "i", "D", null)} will
  95  * <i>not</i> be detected by this class adapter.
  96  *
  97  * <p><code>CheckClassAdapter</code> can be also used to verify bytecode transformations in order to
  98  * make sure that the transformed bytecode is sane. For example:
  99  *
 100  * <pre>
 101  * InputStream inputStream = ...; // get bytes for the source class
 102  * ClassReader classReader = new ClassReader(inputStream);
 103  * ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS);
 104  * ClassVisitor classVisitor = new <b>MyClassAdapter</b>(new CheckClassAdapter(classWriter, true));
 105  * classReader.accept(classVisitor, 0);
 106  *
 107  * StringWriter stringWriter = new StringWriter();
 108  * PrintWriter printWriter = new PrintWriter(stringWriter);
 109  * CheckClassAdapter.verify(new ClassReader(classWriter.toByteArray()), false, printWriter);
 110  * assertTrue(stringWriter.toString().isEmpty());
 111  * </pre>
 112  *
 113  * <p>The above code pass the transformed bytecode through a <code>CheckClassAdapter</code>, with
 114  * data flow checks enabled. These checks are not exactly the same as the JVM verification, but
 115  * provide some basic type checking for each method instruction. If the bytecode has errors, the
 116  * output text shows the erroneous instruction number, and a dump of the failed method with
 117  * information about the type of the local variables and of the operand stack slots for each
 118  * instruction. For example (format is - insnNumber locals : stack):
 119  *
 120  * <pre>
 121  * jdk.internal.org.objectweb.asm.tree.analysis.AnalyzerException: Error at instruction 71: Expected I, but found .
 122  *   at jdk.internal.org.objectweb.asm.tree.analysis.Analyzer.analyze(Analyzer.java:...)
 123  *   at jdk.internal.org.objectweb.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:...)
 124  * ...
 125  * remove()V
 126  * 00000 LinkedBlockingQueue$Itr . . . . . . . .  : ICONST_0
 127  * 00001 LinkedBlockingQueue$Itr . . . . . . . .  : I ISTORE 2
 128  * 00001 LinkedBlockingQueue$Itr <b>.</b> I . . . . . .  :
 129  * ...
 130  * 00071 LinkedBlockingQueue$Itr <b>.</b> I . . . . . .  : ILOAD 1
 131  * 00072 <b>?</b> INVOKESPECIAL java/lang/Integer.&lt;init&gt; (I)V
 132  * ...
 133  * </pre>
 134  *
 135  * <p>The above output shows that the local variable 1, loaded by the <code>ILOAD 1</code>
 136  * instruction at position <code>00071</code> is not initialized, whereas the local variable 2 is
 137  * initialized and contains an int value.
 138  *
 139  * @author Eric Bruneton
 140  */
 141 public class CheckClassAdapter extends ClassVisitor {
 142 
 143     private static final String ERROR_AT = ": error at index ";
 144 
 145     /** Whether the bytecode must be checked with a BasicVerifier. */
 146     private boolean checkDataFlow;
 147 
 148     /** The class version number. */
 149     private int version;
 150 
 151     /** Whether the {@link #visit} method has been called. */
 152     private boolean visitCalled;
 153 
 154     /** Whether the {@link #visitModule} method has been called. */
 155     private boolean visitModuleCalled;
 156 
 157     /** Whether the {@link #visitSource} method has been called. */
 158     private boolean visitSourceCalled;
 159 
 160     /** Whether the {@link #visitOuterClass} method has been called. */
 161     private boolean visitOuterClassCalled;
 162 
 163     /** Whether the {@link #visitNestHost} method has been called. */
 164     private boolean visitNestHostCalled;
 165 
 166     /**
 167       * The common package of all the nest members. Not {@literal null} if the visitNestMember method
 168       * has been called.
 169       */
 170     private String nestMemberPackageName;
 171 
 172     /** Whether the {@link #visitEnd} method has been called. */
 173     private boolean visitEndCalled;
 174 
 175     /** The index of the instruction designated by each visited label so far. */
 176     private Map<Label, Integer> labelInsnIndices;
 177 
 178     // -----------------------------------------------------------------------------------------------
 179     // Constructors
 180     // -----------------------------------------------------------------------------------------------
 181 
 182     /**
 183       * Constructs a new {@link CheckClassAdapter}. <i>Subclasses must not use this constructor</i>.
 184       * Instead, they must use the {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version.
 185       *
 186       * @param classVisitor the class visitor to which this adapter must delegate calls.
 187       */
 188     public CheckClassAdapter(final ClassVisitor classVisitor) {
 189         this(classVisitor, true);
 190     }
 191 
 192     /**
 193       * Constructs a new {@link CheckClassAdapter}. <i>Subclasses must not use this constructor</i>.
 194       * Instead, they must use the {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version.
 195       *
 196       * @param classVisitor the class visitor to which this adapter must delegate calls.
 197       * @param checkDataFlow whether to perform basic data flow checks. This option requires valid
 198       *     maxLocals and maxStack values.
 199       * @throws IllegalStateException If a subclass calls this constructor.
 200       */
 201     public CheckClassAdapter(final ClassVisitor classVisitor, final boolean checkDataFlow) {
 202         this(Opcodes.ASM7, classVisitor, checkDataFlow);
 203         if (getClass() != CheckClassAdapter.class) {
 204             throw new IllegalStateException();
 205         }
 206     }
 207 
 208     /**
 209       * Constructs a new {@link CheckClassAdapter}.
 210       *
 211       * @param api the ASM API version implemented by this visitor. Must be one of {@link
 212       *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
 213       * @param classVisitor the class visitor to which this adapter must delegate calls.
 214       * @param checkDataFlow {@literal true} to perform basic data flow checks, or {@literal false} to
 215       *     not perform any data flow check (see {@link CheckMethodAdapter}). This option requires
 216       *     valid maxLocals and maxStack values.
 217       */
 218     protected CheckClassAdapter(
 219             final int api, final ClassVisitor classVisitor, final boolean checkDataFlow) {
 220         super(api, classVisitor);
 221         this.labelInsnIndices = new HashMap<Label, Integer>();
 222         this.checkDataFlow = checkDataFlow;
 223     }
 224 
 225     // -----------------------------------------------------------------------------------------------
 226     // Implementation of the ClassVisitor interface
 227     // -----------------------------------------------------------------------------------------------
 228 
 229     @Override
 230     public void visit(
 231             final int version,
 232             final int access,
 233             final String name,
 234             final String signature,
 235             final String superName,
 236             final String[] interfaces) {
 237         if (visitCalled) {
 238             throw new IllegalStateException("visit must be called only once");
 239         }
 240         visitCalled = true;
 241         checkState();
 242         checkAccess(
 243                 access,
 244                 Opcodes.ACC_PUBLIC
 245                         | Opcodes.ACC_FINAL
 246                         | Opcodes.ACC_SUPER
 247                         | Opcodes.ACC_INTERFACE
 248                         | Opcodes.ACC_ABSTRACT
 249                         | Opcodes.ACC_SYNTHETIC
 250                         | Opcodes.ACC_ANNOTATION
 251                         | Opcodes.ACC_ENUM
 252                         | Opcodes.ACC_DEPRECATED
 253                         | Opcodes.ACC_MODULE);
 254         if (name == null) {
 255             throw new IllegalArgumentException("Illegal class name (null)");
 256         }
 257         if (!name.endsWith("package-info") && !name.endsWith("module-info")) {
 258             CheckMethodAdapter.checkInternalName(version, name, "class name");
 259         }
 260         if ("java/lang/Object".equals(name)) {
 261             if (superName != null) {
 262                 throw new IllegalArgumentException(
 263                         "The super class name of the Object class must be 'null'");
 264             }
 265         } else if (name.endsWith("module-info")) {
 266             if (superName != null) {
 267                 throw new IllegalArgumentException(
 268                         "The super class name of a module-info class must be 'null'");
 269             }
 270         } else {
 271             CheckMethodAdapter.checkInternalName(version, superName, "super class name");
 272         }
 273         if (signature != null) {
 274             checkClassSignature(signature);
 275         }
 276         if ((access & Opcodes.ACC_INTERFACE) != 0 && !"java/lang/Object".equals(superName)) {
 277             throw new IllegalArgumentException(
 278                     "The super class name of interfaces must be 'java/lang/Object'");
 279         }
 280         if (interfaces != null) {
 281             for (int i = 0; i < interfaces.length; ++i) {
 282                 CheckMethodAdapter.checkInternalName(
 283                         version, interfaces[i], "interface name at index " + i);
 284             }
 285         }
 286         this.version = version;
 287         super.visit(version, access, name, signature, superName, interfaces);
 288     }
 289 
 290     @Override
 291     public void visitSource(final String file, final String debug) {
 292         checkState();
 293         if (visitSourceCalled) {
 294             throw new IllegalStateException("visitSource can be called only once.");
 295         }
 296         visitSourceCalled = true;
 297         super.visitSource(file, debug);
 298     }
 299 
 300     @Override
 301     public ModuleVisitor visitModule(final String name, final int access, final String version) {
 302         checkState();
 303         if (visitModuleCalled) {
 304             throw new IllegalStateException("visitModule can be called only once.");
 305         }
 306         visitModuleCalled = true;
 307         checkFullyQualifiedName(this.version, name, "module name");
 308         checkAccess(access, Opcodes.ACC_OPEN | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_MANDATED);
 309         CheckModuleAdapter checkModuleAdapter =
 310                 new CheckModuleAdapter(
 311                         api, super.visitModule(name, access, version), (access & Opcodes.ACC_OPEN) != 0);
 312         checkModuleAdapter.classVersion = this.version;
 313         return checkModuleAdapter;
 314     }
 315 
 316     @Override
 317     public void visitNestHost(final String nestHost) {
 318         checkState();
 319         CheckMethodAdapter.checkInternalName(version, nestHost, "nestHost");
 320         if (visitNestHostCalled) {
 321             throw new IllegalStateException("visitNestHost can be called only once.");
 322         }
 323         if (nestMemberPackageName != null) {
 324             throw new IllegalStateException("visitNestHost and visitNestMember are mutually exclusive.");
 325         }
 326         visitNestHostCalled = true;
 327         super.visitNestHost(nestHost);
 328     }
 329 
 330     @Override
 331     public void visitNestMember(final String nestMember) {
 332         checkState();
 333         CheckMethodAdapter.checkInternalName(version, nestMember, "nestMember");
 334         if (visitNestHostCalled) {
 335             throw new IllegalStateException(
 336                     "visitMemberOfNest and visitNestHost are mutually exclusive.");
 337         }
 338         String packageName = packageName(nestMember);
 339         if (nestMemberPackageName == null) {
 340             nestMemberPackageName = packageName;
 341         } else if (!nestMemberPackageName.equals(packageName)) {
 342             throw new IllegalStateException(
 343                     "nest member " + nestMember + " should be in the package " + nestMemberPackageName);
 344         }
 345         super.visitNestMember(nestMember);
 346     }
 347 
 348     @Override
 349     public void visitOuterClass(final String owner, final String name, final String descriptor) {
 350         checkState();
 351         if (visitOuterClassCalled) {
 352             throw new IllegalStateException("visitOuterClass can be called only once.");
 353         }
 354         visitOuterClassCalled = true;
 355         if (owner == null) {
 356             throw new IllegalArgumentException("Illegal outer class owner");
 357         }
 358         if (descriptor != null) {
 359             CheckMethodAdapter.checkMethodDescriptor(version, descriptor);
 360         }
 361         super.visitOuterClass(owner, name, descriptor);
 362     }
 363 
 364     @Override
 365     public void visitInnerClass(
 366             final String name, final String outerName, final String innerName, final int access) {
 367         checkState();
 368         CheckMethodAdapter.checkInternalName(version, name, "class name");
 369         if (outerName != null) {
 370             CheckMethodAdapter.checkInternalName(version, outerName, "outer class name");
 371         }
 372         if (innerName != null) {
 373             int startIndex = 0;
 374             while (startIndex < innerName.length() && Character.isDigit(innerName.charAt(startIndex))) {
 375                 startIndex++;
 376             }
 377             if (startIndex == 0 || startIndex < innerName.length()) {
 378                 CheckMethodAdapter.checkIdentifier(version, innerName, startIndex, -1, "inner class name");
 379             }
 380         }
 381         checkAccess(
 382                 access,
 383                 Opcodes.ACC_PUBLIC
 384                         | Opcodes.ACC_PRIVATE
 385                         | Opcodes.ACC_PROTECTED
 386                         | Opcodes.ACC_STATIC
 387                         | Opcodes.ACC_FINAL
 388                         | Opcodes.ACC_INTERFACE
 389                         | Opcodes.ACC_ABSTRACT
 390                         | Opcodes.ACC_SYNTHETIC
 391                         | Opcodes.ACC_ANNOTATION
 392                         | Opcodes.ACC_ENUM);
 393         super.visitInnerClass(name, outerName, innerName, access);
 394     }
 395 
 396     @Override
 397     public FieldVisitor visitField(
 398             final int access,
 399             final String name,
 400             final String descriptor,
 401             final String signature,
 402             final Object value) {
 403         checkState();
 404         checkAccess(
 405                 access,
 406                 Opcodes.ACC_PUBLIC
 407                         | Opcodes.ACC_PRIVATE
 408                         | Opcodes.ACC_PROTECTED
 409                         | Opcodes.ACC_STATIC
 410                         | Opcodes.ACC_FINAL
 411                         | Opcodes.ACC_VOLATILE
 412                         | Opcodes.ACC_TRANSIENT
 413                         | Opcodes.ACC_SYNTHETIC
 414                         | Opcodes.ACC_ENUM
 415                         | Opcodes.ACC_DEPRECATED);
 416         CheckMethodAdapter.checkUnqualifiedName(version, name, "field name");
 417         CheckMethodAdapter.checkDescriptor(version, descriptor, /* canBeVoid = */ false);
 418         if (signature != null) {
 419             checkFieldSignature(signature);
 420         }
 421         if (value != null) {
 422             CheckMethodAdapter.checkConstant(value);
 423         }
 424         return new CheckFieldAdapter(api, super.visitField(access, name, descriptor, signature, value));
 425     }
 426 
 427     @Override
 428     public MethodVisitor visitMethod(
 429             final int access,
 430             final String name,
 431             final String descriptor,
 432             final String signature,
 433             final String[] exceptions) {
 434         checkState();
 435         checkAccess(
 436                 access,
 437                 Opcodes.ACC_PUBLIC
 438                         | Opcodes.ACC_PRIVATE
 439                         | Opcodes.ACC_PROTECTED
 440                         | Opcodes.ACC_STATIC
 441                         | Opcodes.ACC_FINAL
 442                         | Opcodes.ACC_SYNCHRONIZED
 443                         | Opcodes.ACC_BRIDGE
 444                         | Opcodes.ACC_VARARGS
 445                         | Opcodes.ACC_NATIVE
 446                         | Opcodes.ACC_ABSTRACT
 447                         | Opcodes.ACC_STRICT
 448                         | Opcodes.ACC_SYNTHETIC
 449                         | Opcodes.ACC_DEPRECATED);
 450         if (!"<init>".equals(name) && !"<clinit>".equals(name)) {
 451             CheckMethodAdapter.checkMethodIdentifier(version, name, "method name");
 452         }
 453         CheckMethodAdapter.checkMethodDescriptor(version, descriptor);
 454         if (signature != null) {
 455             checkMethodSignature(signature);
 456         }
 457         if (exceptions != null) {
 458             for (int i = 0; i < exceptions.length; ++i) {
 459                 CheckMethodAdapter.checkInternalName(
 460                         version, exceptions[i], "exception name at index " + i);
 461             }
 462         }
 463         CheckMethodAdapter checkMethodAdapter;
 464         if (checkDataFlow) {
 465             checkMethodAdapter =
 466                     new CheckMethodAdapter(
 467                             api,
 468                             access,
 469                             name,
 470                             descriptor,
 471                             super.visitMethod(access, name, descriptor, signature, exceptions),
 472                             labelInsnIndices);
 473         } else {
 474             checkMethodAdapter =
 475                     new CheckMethodAdapter(
 476                             api,
 477                             super.visitMethod(access, name, descriptor, signature, exceptions),
 478                             labelInsnIndices);
 479         }
 480         checkMethodAdapter.version = version;
 481         return checkMethodAdapter;
 482     }
 483 
 484     @Override
 485     public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
 486         checkState();
 487         CheckMethodAdapter.checkDescriptor(version, descriptor, false);
 488         return new CheckAnnotationAdapter(super.visitAnnotation(descriptor, visible));
 489     }
 490 
 491     @Override
 492     public AnnotationVisitor visitTypeAnnotation(
 493             final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
 494         checkState();
 495         int sort = new TypeReference(typeRef).getSort();
 496         if (sort != TypeReference.CLASS_TYPE_PARAMETER
 497                 && sort != TypeReference.CLASS_TYPE_PARAMETER_BOUND
 498                 && sort != TypeReference.CLASS_EXTENDS) {
 499             throw new IllegalArgumentException(
 500                     "Invalid type reference sort 0x" + Integer.toHexString(sort));
 501         }
 502         checkTypeRef(typeRef);
 503         CheckMethodAdapter.checkDescriptor(version, descriptor, false);
 504         return new CheckAnnotationAdapter(
 505                 super.visitTypeAnnotation(typeRef, typePath, descriptor, visible));
 506     }
 507 
 508     @Override
 509     public void visitAttribute(final Attribute attribute) {
 510         checkState();
 511         if (attribute == null) {
 512             throw new IllegalArgumentException("Invalid attribute (must not be null)");
 513         }
 514         super.visitAttribute(attribute);
 515     }
 516 
 517     @Override
 518     public void visitEnd() {
 519         checkState();
 520         visitEndCalled = true;
 521         super.visitEnd();
 522     }
 523 
 524     // -----------------------------------------------------------------------------------------------
 525     // Utility methods
 526     // -----------------------------------------------------------------------------------------------
 527 
 528     /** Checks that the visit method has been called and that visitEnd has not been called. */
 529     private void checkState() {
 530         if (!visitCalled) {
 531             throw new IllegalStateException("Cannot visit member before visit has been called.");
 532         }
 533         if (visitEndCalled) {
 534             throw new IllegalStateException("Cannot visit member after visitEnd has been called.");
 535         }
 536     }
 537 
 538     /**
 539       * Checks that the given access flags do not contain invalid flags. This method also checks that
 540       * mutually incompatible flags are not set simultaneously.
 541       *
 542       * @param access the access flags to be checked.
 543       * @param possibleAccess the valid access flags.
 544       */
 545     static void checkAccess(final int access, final int possibleAccess) {
 546         if ((access & ~possibleAccess) != 0) {
 547             throw new IllegalArgumentException("Invalid access flags: " + access);
 548         }
 549         int publicProtectedPrivate = Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED | Opcodes.ACC_PRIVATE;
 550         if (Integer.bitCount(access & publicProtectedPrivate) > 1) {
 551             throw new IllegalArgumentException(
 552                     "public, protected and private are mutually exclusive: " + access);
 553         }
 554         if (Integer.bitCount(access & (Opcodes.ACC_FINAL | Opcodes.ACC_ABSTRACT)) > 1) {
 555             throw new IllegalArgumentException("final and abstract are mutually exclusive: " + access);
 556         }
 557     }
 558 
 559     /**
 560       * Checks that the given name is a fully qualified name, using dots.
 561       *
 562       * @param version the class version.
 563       * @param name the name to be checked.
 564       * @param source the source of 'name' (e.g 'module' for a module name).
 565       */
 566     static void checkFullyQualifiedName(final int version, final String name, final String source) {
 567         try {
 568             int startIndex = 0;
 569             int dotIndex;
 570             while ((dotIndex = name.indexOf('.', startIndex + 1)) != -1) {
 571                 CheckMethodAdapter.checkIdentifier(version, name, startIndex, dotIndex, null);
 572                 startIndex = dotIndex + 1;
 573             }
 574             CheckMethodAdapter.checkIdentifier(version, name, startIndex, name.length(), null);
 575         } catch (IllegalArgumentException e) {
 576             throw new IllegalArgumentException(
 577                     "Invalid " + source + " (must be a fully qualified name): " + name, e);
 578         }
 579     }
 580 
 581     /**
 582       * Checks a class signature.
 583       *
 584       * @param signature a string containing the signature that must be checked.
 585       */
 586     public static void checkClassSignature(final String signature) {
 587         // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
 588         // ClassSignature:
 589         //   [TypeParameters] SuperclassSignature SuperinterfaceSignature*
 590         // SuperclassSignature:
 591         //   ClassTypeSignature
 592         // SuperinterfaceSignature:
 593         //   ClassTypeSignature
 594         int pos = 0;
 595         if (getChar(signature, 0) == '<') {
 596             pos = checkTypeParameters(signature, pos);
 597         }
 598         pos = checkClassTypeSignature(signature, pos);
 599         while (getChar(signature, pos) == 'L') {
 600             pos = checkClassTypeSignature(signature, pos);
 601         }
 602         if (pos != signature.length()) {
 603             throw new IllegalArgumentException(signature + ERROR_AT + pos);
 604         }
 605     }
 606 
 607     /**
 608       * Checks a method signature.
 609       *
 610       * @param signature a string containing the signature that must be checked.
 611       */
 612     public static void checkMethodSignature(final String signature) {
 613         // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
 614         // MethodSignature:
 615         //   [TypeParameters] ( JavaTypeSignature* ) Result ThrowsSignature*
 616         // Result:
 617         //   JavaTypeSignature
 618         //   VoidDescriptor
 619         // ThrowsSignature:
 620         //   ^ ClassTypeSignature
 621         //   ^ TypeVariableSignature
 622         int pos = 0;
 623         if (getChar(signature, 0) == '<') {
 624             pos = checkTypeParameters(signature, pos);
 625         }
 626         pos = checkChar('(', signature, pos);
 627         while ("ZCBSIFJDL[T".indexOf(getChar(signature, pos)) != -1) {
 628             pos = checkJavaTypeSignature(signature, pos);
 629         }
 630         pos = checkChar(')', signature, pos);
 631         if (getChar(signature, pos) == 'V') {
 632             ++pos;
 633         } else {
 634             pos = checkJavaTypeSignature(signature, pos);
 635         }
 636         while (getChar(signature, pos) == '^') {
 637             ++pos;
 638             if (getChar(signature, pos) == 'L') {
 639                 pos = checkClassTypeSignature(signature, pos);
 640             } else {
 641                 pos = checkTypeVariableSignature(signature, pos);
 642             }
 643         }
 644         if (pos != signature.length()) {
 645             throw new IllegalArgumentException(signature + ERROR_AT + pos);
 646         }
 647     }
 648 
 649     /**
 650       * Checks a field signature.
 651       *
 652       * @param signature a string containing the signature that must be checked.
 653       */
 654     public static void checkFieldSignature(final String signature) {
 655         // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
 656         // FieldSignature:
 657         //   ReferenceTypeSignature
 658         int pos = checkReferenceTypeSignature(signature, 0);
 659         if (pos != signature.length()) {
 660             throw new IllegalArgumentException(signature + ERROR_AT + pos);
 661         }
 662     }
 663 
 664     /**
 665       * Checks the type parameters of a class or method signature.
 666       *
 667       * @param signature a string containing the signature that must be checked.
 668       * @param startPos index of first character to be checked.
 669       * @return the index of the first character after the checked part.
 670       */
 671     private static int checkTypeParameters(final String signature, final int startPos) {
 672         // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
 673         // TypeParameters:
 674         //   < TypeParameter TypeParameter* >
 675         int pos = startPos;
 676         pos = checkChar('<', signature, pos);
 677         pos = checkTypeParameter(signature, pos);
 678         while (getChar(signature, pos) != '>') {
 679             pos = checkTypeParameter(signature, pos);
 680         }
 681         return pos + 1;
 682     }
 683 
 684     /**
 685       * Checks a type parameter of a class or method signature.
 686       *
 687       * @param signature a string containing the signature that must be checked.
 688       * @param startPos index of first character to be checked.
 689       * @return the index of the first character after the checked part.
 690       */
 691     private static int checkTypeParameter(final String signature, final int startPos) {
 692         // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
 693         // TypeParameter:
 694         //   Identifier ClassBound InterfaceBound*
 695         // ClassBound:
 696         //   : [ReferenceTypeSignature]
 697         // InterfaceBound:
 698         //   : ReferenceTypeSignature
 699         int pos = startPos;
 700         pos = checkSignatureIdentifier(signature, pos);
 701         pos = checkChar(':', signature, pos);
 702         if ("L[T".indexOf(getChar(signature, pos)) != -1) {
 703             pos = checkReferenceTypeSignature(signature, pos);
 704         }
 705         while (getChar(signature, pos) == ':') {
 706             pos = checkReferenceTypeSignature(signature, pos + 1);
 707         }
 708         return pos;
 709     }
 710 
 711     /**
 712       * Checks a reference type signature.
 713       *
 714       * @param signature a string containing the signature that must be checked.
 715       * @param pos index of first character to be checked.
 716       * @return the index of the first character after the checked part.
 717       */
 718     private static int checkReferenceTypeSignature(final String signature, final int pos) {
 719         // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
 720         // ReferenceTypeSignature:
 721         //   ClassTypeSignature
 722         //   TypeVariableSignature
 723         //   ArrayTypeSignature
 724         // ArrayTypeSignature:
 725         //   [ JavaTypeSignature
 726         switch (getChar(signature, pos)) {
 727             case 'L':
 728                 return checkClassTypeSignature(signature, pos);
 729             case '[':
 730                 return checkJavaTypeSignature(signature, pos + 1);
 731             default:
 732                 return checkTypeVariableSignature(signature, pos);
 733         }
 734     }
 735 
 736     /**
 737       * Checks a class type signature.
 738       *
 739       * @param signature a string containing the signature that must be checked.
 740       * @param startPos index of first character to be checked.
 741       * @return the index of the first character after the checked part.
 742       */
 743     private static int checkClassTypeSignature(final String signature, final int startPos) {
 744         // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
 745         // ClassTypeSignature:
 746         //   L [PackageSpecifier] SimpleClassTypeSignature ClassTypeSignatureSuffix* ;
 747         // PackageSpecifier:
 748         //   Identifier / PackageSpecifier*
 749         // SimpleClassTypeSignature:
 750         //   Identifier [TypeArguments]
 751         // ClassTypeSignatureSuffix:
 752         //   . SimpleClassTypeSignature
 753         int pos = startPos;
 754         pos = checkChar('L', signature, pos);
 755         pos = checkSignatureIdentifier(signature, pos);
 756         while (getChar(signature, pos) == '/') {
 757             pos = checkSignatureIdentifier(signature, pos + 1);
 758         }
 759         if (getChar(signature, pos) == '<') {
 760             pos = checkTypeArguments(signature, pos);
 761         }
 762         while (getChar(signature, pos) == '.') {
 763             pos = checkSignatureIdentifier(signature, pos + 1);
 764             if (getChar(signature, pos) == '<') {
 765                 pos = checkTypeArguments(signature, pos);
 766             }
 767         }
 768         return checkChar(';', signature, pos);
 769     }
 770 
 771     /**
 772       * Checks the type arguments in a class type signature.
 773       *
 774       * @param signature a string containing the signature that must be checked.
 775       * @param startPos index of first character to be checked.
 776       * @return the index of the first character after the checked part.
 777       */
 778     private static int checkTypeArguments(final String signature, final int startPos) {
 779         // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
 780         // TypeArguments:
 781         //   < TypeArgument TypeArgument* >
 782         int pos = startPos;
 783         pos = checkChar('<', signature, pos);
 784         pos = checkTypeArgument(signature, pos);
 785         while (getChar(signature, pos) != '>') {
 786             pos = checkTypeArgument(signature, pos);
 787         }
 788         return pos + 1;
 789     }
 790 
 791     /**
 792       * Checks a type argument in a class type signature.
 793       *
 794       * @param signature a string containing the signature that must be checked.
 795       * @param startPos index of first character to be checked.
 796       * @return the index of the first character after the checked part.
 797       */
 798     private static int checkTypeArgument(final String signature, final int startPos) {
 799         // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
 800         // TypeArgument:
 801         //   [WildcardIndicator] ReferenceTypeSignature
 802         //   *
 803         // WildcardIndicator:
 804         //   +
 805         //   -
 806         int pos = startPos;
 807         char c = getChar(signature, pos);
 808         if (c == '*') {
 809             return pos + 1;
 810         } else if (c == '+' || c == '-') {
 811             pos++;
 812         }
 813         return checkReferenceTypeSignature(signature, pos);
 814     }
 815 
 816     /**
 817       * Checks a type variable signature.
 818       *
 819       * @param signature a string containing the signature that must be checked.
 820       * @param startPos index of first character to be checked.
 821       * @return the index of the first character after the checked part.
 822       */
 823     private static int checkTypeVariableSignature(final String signature, final int startPos) {
 824         // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
 825         // TypeVariableSignature:
 826         //  T Identifier ;
 827         int pos = startPos;
 828         pos = checkChar('T', signature, pos);
 829         pos = checkSignatureIdentifier(signature, pos);
 830         return checkChar(';', signature, pos);
 831     }
 832 
 833     /**
 834       * Checks a Java type signature.
 835       *
 836       * @param signature a string containing the signature that must be checked.
 837       * @param startPos index of first character to be checked.
 838       * @return the index of the first character after the checked part.
 839       */
 840     private static int checkJavaTypeSignature(final String signature, final int startPos) {
 841         // From https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1:
 842         // JavaTypeSignature:
 843         //   ReferenceTypeSignature
 844         //   BaseType
 845         // BaseType:
 846         //   (one of)
 847         //   B C D F I J S Z
 848         int pos = startPos;
 849         switch (getChar(signature, pos)) {
 850             case 'B':
 851             case 'C':
 852             case 'D':
 853             case 'F':
 854             case 'I':
 855             case 'J':
 856             case 'S':
 857             case 'Z':
 858                 return pos + 1;
 859             default:
 860                 return checkReferenceTypeSignature(signature, pos);
 861         }
 862     }
 863 
 864     /**
 865       * Checks an identifier.
 866       *
 867       * @param signature a string containing the signature that must be checked.
 868       * @param startPos index of first character to be checked.
 869       * @return the index of the first character after the checked part.
 870       */
 871     private static int checkSignatureIdentifier(final String signature, final int startPos) {
 872         int pos = startPos;
 873         while (pos < signature.length() && ".;[/<>:".indexOf(signature.codePointAt(pos)) == -1) {
 874             pos = signature.offsetByCodePoints(pos, 1);
 875         }
 876         if (pos == startPos) {
 877             throw new IllegalArgumentException(signature + ": identifier expected at index " + startPos);
 878         }
 879         return pos;
 880     }
 881 
 882     /**
 883       * Checks a single character.
 884       *
 885       * @param c a character.
 886       * @param signature a string containing the signature that must be checked.
 887       * @param pos index of first character to be checked.
 888       * @return the index of the first character after the checked part.
 889       */
 890     private static int checkChar(final char c, final String signature, final int pos) {
 891         if (getChar(signature, pos) == c) {
 892             return pos + 1;
 893         }
 894         throw new IllegalArgumentException(signature + ": '" + c + "' expected at index " + pos);
 895     }
 896 
 897     /**
 898       * Returns the string character at the given index, or 0.
 899       *
 900       * @param string a string.
 901       * @param pos an index in 'string'.
 902       * @return the character at the given index, or 0 if there is no such character.
 903       */
 904     private static char getChar(final String string, final int pos) {
 905         return pos < string.length() ? string.charAt(pos) : (char) 0;
 906     }
 907 
 908     /**
 909       * Checks the reference to a type in a type annotation.
 910       *
 911       * @param typeRef a reference to an annotated type.
 912       */
 913     static void checkTypeRef(final int typeRef) {
 914         int mask = 0;
 915         switch (typeRef >>> 24) {
 916             case TypeReference.CLASS_TYPE_PARAMETER:
 917             case TypeReference.METHOD_TYPE_PARAMETER:
 918             case TypeReference.METHOD_FORMAL_PARAMETER:
 919                 mask = 0xFFFF0000;
 920                 break;
 921             case TypeReference.FIELD:
 922             case TypeReference.METHOD_RETURN:
 923             case TypeReference.METHOD_RECEIVER:
 924             case TypeReference.LOCAL_VARIABLE:
 925             case TypeReference.RESOURCE_VARIABLE:
 926             case TypeReference.INSTANCEOF:
 927             case TypeReference.NEW:
 928             case TypeReference.CONSTRUCTOR_REFERENCE:
 929             case TypeReference.METHOD_REFERENCE:
 930                 mask = 0xFF000000;
 931                 break;
 932             case TypeReference.CLASS_EXTENDS:
 933             case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
 934             case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
 935             case TypeReference.THROWS:
 936             case TypeReference.EXCEPTION_PARAMETER:
 937                 mask = 0xFFFFFF00;
 938                 break;
 939             case TypeReference.CAST:
 940             case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
 941             case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
 942             case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
 943             case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
 944                 mask = 0xFF0000FF;
 945                 break;
 946             default:
 947                 throw new AssertionError();
 948         }
 949         if ((typeRef & ~mask) != 0) {
 950             throw new IllegalArgumentException(
 951                     "Invalid type reference 0x" + Integer.toHexString(typeRef));
 952         }
 953     }
 954 
 955     /**
 956       * Returns the package name of an internal name.
 957       *
 958       * @param name an internal name.
 959       * @return the package name or "" if there is no package.
 960       */
 961     private static String packageName(final String name) {
 962         int index = name.lastIndexOf('/');
 963         if (index == -1) {
 964             return "";
 965         }
 966         return name.substring(0, index);
 967     }
 968 
 969     // -----------------------------------------------------------------------------------------------
 970     // Static verification methods
 971     // -----------------------------------------------------------------------------------------------
 972 
 973     /**
 974       * Checks the given class.
 975       *
 976       * <p>Usage: CheckClassAdapter &lt;binary class name or class file name&gt;
 977       *
 978       * @param args the command line arguments.
 979       * @throws IOException if the class cannot be found, or if an IO exception occurs.
 980       */
 981     public static void main(final String[] args) throws IOException {
 982         if (args.length != 1) {
 983             System.err.println(
 984                     "Verifies the given class.\n"
 985                             + "Usage: CheckClassAdapter <fully qualified class name or class file name>");
 986             return;
 987         }
 988 
 989         ClassReader classReader;
 990         if (args[0].endsWith(".class")) {
 991             InputStream inputStream =
 992                     new FileInputStream(args[0]); // NOPMD(AvoidFileStream): can't fix for 1.5 compatibility
 993             classReader = new ClassReader(inputStream);
 994         } else {
 995             classReader = new ClassReader(args[0]);
 996         }
 997 
 998         verify(classReader, false, new PrintWriter(System.err));
 999     }
1000 
1001     /**
1002       * Checks the given class.
1003       *
1004       * @param classReader the class to be checked.
1005       * @param printResults whether to print the results of the bytecode verification.
1006       * @param printWriter where the results (or the stack trace in case of error) must be printed.
1007       */
1008     public static void verify(
1009             final ClassReader classReader, final boolean printResults, final PrintWriter printWriter) {
1010         verify(classReader, null, printResults, printWriter);
1011     }
1012 
1013     /**
1014       * Checks the given class.
1015       *
1016       * @param classReader the class to be checked.
1017       * @param loader a <code>ClassLoader</code> which will be used to load referenced classes. May be
1018       *     {@literal null}.
1019       * @param printResults whether to print the results of the bytecode verification.
1020       * @param printWriter where the results (or the stack trace in case of error) must be printed.
1021       */
1022     public static void verify(
1023             final ClassReader classReader,
1024             final ClassLoader loader,
1025             final boolean printResults,
1026             final PrintWriter printWriter) {
1027         ClassNode classNode = new ClassNode();
1028         classReader.accept(
1029                 new CheckClassAdapter(Opcodes.ASM7, classNode, false) {}, ClassReader.SKIP_DEBUG);
1030 
1031         Type syperType = classNode.superName == null ? null : Type.getObjectType(classNode.superName);
1032         List<MethodNode> methods = classNode.methods;
1033 
1034         List<Type> interfaces = new ArrayList<Type>();
1035         for (String interfaceName : classNode.interfaces) {
1036             interfaces.add(Type.getObjectType(interfaceName));
1037         }
1038 
1039         for (MethodNode method : methods) {
1040             SimpleVerifier verifier =
1041                     new SimpleVerifier(
1042                             Type.getObjectType(classNode.name),
1043                             syperType,
1044                             interfaces,
1045                             (classNode.access & Opcodes.ACC_INTERFACE) != 0);
1046             Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(verifier);
1047             if (loader != null) {
1048                 verifier.setClassLoader(loader);
1049             }
1050             try {
1051                 analyzer.analyze(classNode.name, method);
1052             } catch (AnalyzerException e) {
1053                 e.printStackTrace(printWriter);
1054             }
1055             if (printResults) {
1056                 printAnalyzerResult(method, analyzer, printWriter);
1057             }
1058         }
1059         printWriter.flush();
1060     }
1061 
1062     static void printAnalyzerResult(
1063             final MethodNode method, final Analyzer<BasicValue> analyzer, final PrintWriter printWriter) {
1064         Textifier textifier = new Textifier();
1065         TraceMethodVisitor traceMethodVisitor = new TraceMethodVisitor(textifier);
1066 
1067         printWriter.println(method.name + method.desc);
1068         for (int i = 0; i < method.instructions.size(); ++i) {
1069             method.instructions.get(i).accept(traceMethodVisitor);
1070 
1071             StringBuilder stringBuilder = new StringBuilder();
1072             Frame<BasicValue> frame = analyzer.getFrames()[i];
1073             if (frame == null) {
1074                 stringBuilder.append('?');
1075             } else {
1076                 for (int j = 0; j < frame.getLocals(); ++j) {
1077                     stringBuilder.append(getUnqualifiedName(frame.getLocal(j).toString())).append(' ');
1078                 }
1079                 stringBuilder.append(" : ");
1080                 for (int j = 0; j < frame.getStackSize(); ++j) {
1081                     stringBuilder.append(getUnqualifiedName(frame.getStack(j).toString())).append(' ');
1082                 }
1083             }
1084             while (stringBuilder.length() < method.maxStack + method.maxLocals + 1) {
1085                 stringBuilder.append(' ');
1086             }
1087             printWriter.print(Integer.toString(i + 100000).substring(1));
1088             printWriter.print(
1089                     " " + stringBuilder + " : " + textifier.text.get(textifier.text.size() - 1));
1090         }
1091         for (TryCatchBlockNode tryCatchBlock : method.tryCatchBlocks) {
1092             tryCatchBlock.accept(traceMethodVisitor);
1093             printWriter.print(" " + textifier.text.get(textifier.text.size() - 1));
1094         }
1095         printWriter.println();
1096     }
1097 
1098     private static String getUnqualifiedName(final String name) {
1099         int lastSlashIndex = name.lastIndexOf('/');
1100         if (lastSlashIndex == -1) {
1101             return name;
1102         } else {
1103             int endIndex = name.length();
1104             if (name.charAt(endIndex - 1) == ';') {
1105                 endIndex--;
1106             }
1107             return name.substring(lastSlashIndex + 1, endIndex);
1108         }
1109     }
1110 }