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