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.PrintWriter; 63 import java.util.ArrayList; 64 import java.util.HashMap; 65 import java.util.Iterator; 66 import java.util.List; 67 import java.util.Map; 68 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.Opcodes; 77 import jdk.internal.org.objectweb.asm.Type; 78 import jdk.internal.org.objectweb.asm.TypePath; 79 import jdk.internal.org.objectweb.asm.TypeReference; 80 import jdk.internal.org.objectweb.asm.tree.ClassNode; 81 import jdk.internal.org.objectweb.asm.tree.MethodNode; 82 import jdk.internal.org.objectweb.asm.tree.analysis.Analyzer; 83 import jdk.internal.org.objectweb.asm.tree.analysis.BasicValue; 84 import jdk.internal.org.objectweb.asm.tree.analysis.Frame; 85 import jdk.internal.org.objectweb.asm.tree.analysis.SimpleVerifier; 86 87 /** 88 * A {@link ClassVisitor} that checks that its methods are properly used. More 89 * precisely this class adapter checks each method call individually, based 90 * <i>only</i> on its arguments, but does <i>not</i> check the <i>sequence</i> 91 * of method calls. For example, the invalid sequence 92 * <tt>visitField(ACC_PUBLIC, "i", "I", null)</tt> <tt>visitField(ACC_PUBLIC, 93 * "i", "D", null)</tt> will <i>not</i> be detected by this class adapter. 94 * 95 * <p> 96 * <code>CheckClassAdapter</code> can be also used to verify bytecode 97 * transformations in order to make sure transformed bytecode is sane. For 98 * example: 99 * 100 * <pre> 101 * InputStream is = ...; // get bytes for the source class 102 * ClassReader cr = new ClassReader(is); 103 * ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS); 104 * ClassVisitor cv = new <b>MyClassAdapter</b>(new CheckClassAdapter(cw)); 105 * cr.accept(cv, 0); 106 * 107 * StringWriter sw = new StringWriter(); 108 * PrintWriter pw = new PrintWriter(sw); 109 * CheckClassAdapter.verify(new ClassReader(cw.toByteArray()), false, pw); 110 * assertTrue(sw.toString(), sw.toString().length()==0); 111 * </pre> 112 * 113 * Above code runs transformed bytecode trough the 114 * <code>CheckClassAdapter</code>. It won't be exactly the same verification as 115 * JVM does, but it run data flow analysis for the code of each method and 116 * checks that expectations are met for each method instruction. 117 * 118 * <p> 119 * If method bytecode has errors, assertion text will show the erroneous 120 * instruction number and dump of the failed method with information about 121 * locals and stack slot for each instruction. For example (format is - 122 * insnNumber locals : stack): 123 * 124 * <pre> 125 * jdk.internal.org.objectweb.asm.tree.analysis.AnalyzerException: Error at instruction 71: Expected I, but found . 126 * at jdk.internal.org.objectweb.asm.tree.analysis.Analyzer.analyze(Analyzer.java:289) 127 * at jdk.internal.org.objectweb.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:135) 128 * ... 129 * remove()V 130 * 00000 LinkedBlockingQueue$Itr . . . . . . . . : 131 * ICONST_0 132 * 00001 LinkedBlockingQueue$Itr . . . . . . . . : I 133 * ISTORE 2 134 * 00001 LinkedBlockingQueue$Itr <b>.</b> I . . . . . . : 135 * ... 136 * 137 * 00071 LinkedBlockingQueue$Itr <b>.</b> I . . . . . . : 138 * ILOAD 1 139 * 00072 <b>?</b> 140 * INVOKESPECIAL java/lang/Integer.<init> (I)V 141 * ... 142 * </pre> 143 * 144 * In the above output you can see that variable 1 loaded by 145 * <code>ILOAD 1</code> instruction at position <code>00071</code> is not 146 * initialized. You can also see that at the beginning of the method (code 147 * inserted by the transformation) variable 2 is initialized. 148 * 149 * <p> 150 * Note that when used like that, <code>CheckClassAdapter.verify()</code> can 151 * trigger additional class loading, because it is using 152 * <code>SimpleVerifier</code>. 153 * 154 * @author Eric Bruneton 155 */ 156 public class CheckClassAdapter extends ClassVisitor { 157 158 /** 159 * The class version number. 160 */ 161 private int version; 162 163 /** 164 * <tt>true</tt> if the visit method has been called. 165 */ 166 private boolean start; 167 168 /** 169 * <tt>true</tt> if the visitSource method has been called. 170 */ 171 private boolean source; 172 173 /** 174 * <tt>true</tt> if the visitOuterClass method has been called. 175 */ 176 private boolean outer; 177 178 /** 179 * <tt>true</tt> if the visitEnd method has been called. 180 */ 181 private boolean end; 182 183 /** 184 * The already visited labels. This map associate Integer values to Label 185 * keys. 186 */ 187 private Map<Label, Integer> labels; 188 189 /** 190 * <tt>true</tt> if the method code must be checked with a BasicVerifier. 191 */ 192 private boolean checkDataFlow; 193 194 /** 195 * Checks a given class. 196 * <p> 197 * Usage: CheckClassAdapter <binary class name or class file name> 198 * 199 * @param args 200 * the command line arguments. 201 * 202 * @throws Exception 203 * if the class cannot be found, or if an IO exception occurs. 204 */ 205 public static void main(final String[] args) throws Exception { 206 if (args.length != 1) { 207 System.err.println("Verifies the given class."); 208 System.err.println("Usage: CheckClassAdapter " 209 + "<fully qualified class name or class file name>"); 210 return; 211 } 212 ClassReader cr; 213 if (args[0].endsWith(".class")) { 214 cr = new ClassReader(new FileInputStream(args[0])); 215 } else { 216 cr = new ClassReader(args[0]); 217 } 218 219 verify(cr, false, new PrintWriter(System.err)); 220 } 221 222 /** 223 * Checks a given class. 224 * 225 * @param cr 226 * a <code>ClassReader</code> that contains bytecode for the 227 * analysis. 228 * @param loader 229 * a <code>ClassLoader</code> which will be used to load 230 * referenced classes. This is useful if you are verifiying 231 * multiple interdependent classes. 232 * @param dump 233 * true if bytecode should be printed out not only when errors 234 * are found. 235 * @param pw 236 * write where results going to be printed 237 */ 238 public static void verify(final ClassReader cr, final ClassLoader loader, 239 final boolean dump, final PrintWriter pw) { 240 ClassNode cn = new ClassNode(); 241 cr.accept(new CheckClassAdapter(cn, false), ClassReader.SKIP_DEBUG); 242 243 Type syperType = cn.superName == null ? null : Type 244 .getObjectType(cn.superName); 245 List<MethodNode> methods = cn.methods; 246 247 List<Type> interfaces = new ArrayList<Type>(); 248 for (Iterator<String> i = cn.interfaces.iterator(); i.hasNext();) { 249 interfaces.add(Type.getObjectType(i.next().toString())); 250 } 251 252 for (int i = 0; i < methods.size(); ++i) { 253 MethodNode method = methods.get(i); 254 SimpleVerifier verifier = new SimpleVerifier( 255 Type.getObjectType(cn.name), syperType, interfaces, 256 (cn.access & Opcodes.ACC_INTERFACE) != 0); 257 Analyzer<BasicValue> a = new Analyzer<BasicValue>(verifier); 258 if (loader != null) { 259 verifier.setClassLoader(loader); 260 } 261 try { 262 a.analyze(cn.name, method); 263 if (!dump) { 264 continue; 265 } 266 } catch (Exception e) { 267 e.printStackTrace(pw); 268 } 269 printAnalyzerResult(method, a, pw); 270 } 271 pw.flush(); 272 } 273 274 /** 275 * Checks a given class 276 * 277 * @param cr 278 * a <code>ClassReader</code> that contains bytecode for the 279 * analysis. 280 * @param dump 281 * true if bytecode should be printed out not only when errors 282 * are found. 283 * @param pw 284 * write where results going to be printed 285 */ 286 public static void verify(final ClassReader cr, final boolean dump, 287 final PrintWriter pw) { 288 verify(cr, null, dump, pw); 289 } 290 291 static void printAnalyzerResult(MethodNode method, Analyzer<BasicValue> a, 292 final PrintWriter pw) { 293 Frame<BasicValue>[] frames = a.getFrames(); 294 Textifier t = new Textifier(); 295 TraceMethodVisitor mv = new TraceMethodVisitor(t); 296 297 pw.println(method.name + method.desc); 298 for (int j = 0; j < method.instructions.size(); ++j) { 299 method.instructions.get(j).accept(mv); 300 301 StringBuffer s = new StringBuffer(); 302 Frame<BasicValue> f = frames[j]; 303 if (f == null) { 304 s.append('?'); 305 } else { 306 for (int k = 0; k < f.getLocals(); ++k) { 307 s.append(getShortName(f.getLocal(k).toString())) 308 .append(' '); 309 } 310 s.append(" : "); 311 for (int k = 0; k < f.getStackSize(); ++k) { 312 s.append(getShortName(f.getStack(k).toString())) 313 .append(' '); 314 } 315 } 316 while (s.length() < method.maxStack + method.maxLocals + 1) { 317 s.append(' '); 318 } 319 pw.print(Integer.toString(j + 100000).substring(1)); 320 pw.print(" " + s + " : " + t.text.get(t.text.size() - 1)); 321 } 322 for (int j = 0; j < method.tryCatchBlocks.size(); ++j) { 323 method.tryCatchBlocks.get(j).accept(mv); 324 pw.print(" " + t.text.get(t.text.size() - 1)); 325 } 326 pw.println(); 327 } 328 329 private static String getShortName(final String name) { 330 int n = name.lastIndexOf('/'); 331 int k = name.length(); 332 if (name.charAt(k - 1) == ';') { 333 k--; 334 } 335 return n == -1 ? name : name.substring(n + 1, k); 336 } 337 338 /** 339 * Constructs a new {@link CheckClassAdapter}. <i>Subclasses must not use 340 * this constructor</i>. Instead, they must use the 341 * {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version. 342 * 343 * @param cv 344 * the class visitor to which this adapter must delegate calls. 345 */ 346 public CheckClassAdapter(final ClassVisitor cv) { 347 this(cv, true); 348 } 349 350 /** 351 * Constructs a new {@link CheckClassAdapter}. <i>Subclasses must not use 352 * this constructor</i>. Instead, they must use the 353 * {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version. 354 * 355 * @param cv 356 * the class visitor to which this adapter must delegate calls. 357 * @param checkDataFlow 358 * <tt>true</tt> to perform basic data flow checks, or 359 * <tt>false</tt> to not perform any data flow check (see 360 * {@link CheckMethodAdapter}). This option requires valid 361 * maxLocals and maxStack values. 362 */ 363 public CheckClassAdapter(final ClassVisitor cv, final boolean checkDataFlow) { 364 this(Opcodes.ASM5, cv, checkDataFlow); 365 } 366 367 /** 368 * Constructs a new {@link CheckClassAdapter}. 369 * 370 * @param api 371 * the ASM API version implemented by this visitor. Must be one 372 * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. 373 * @param cv 374 * the class visitor to which this adapter must delegate calls. 375 * @param checkDataFlow 376 * <tt>true</tt> to perform basic data flow checks, or 377 * <tt>false</tt> to not perform any data flow check (see 378 * {@link CheckMethodAdapter}). This option requires valid 379 * maxLocals and maxStack values. 380 */ 381 protected CheckClassAdapter(final int api, final ClassVisitor cv, 382 final boolean checkDataFlow) { 383 super(api, cv); 384 this.labels = new HashMap<Label, Integer>(); 385 this.checkDataFlow = checkDataFlow; 386 } 387 388 // ------------------------------------------------------------------------ 389 // Implementation of the ClassVisitor interface 390 // ------------------------------------------------------------------------ 391 392 @Override 393 public void visit(final int version, final int access, final String name, 394 final String signature, final String superName, 395 final String[] interfaces) { 396 if (start) { 397 throw new IllegalStateException("visit must be called only once"); 398 } 399 start = true; 400 checkState(); 401 checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL 402 + Opcodes.ACC_SUPER + Opcodes.ACC_INTERFACE 403 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC 404 + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM 405 + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE 406 if (name == null || !name.endsWith("package-info")) { 407 CheckMethodAdapter.checkInternalName(name, "class name"); 408 } 409 if ("java/lang/Object".equals(name)) { 410 if (superName != null) { 411 throw new IllegalArgumentException( 412 "The super class name of the Object class must be 'null'"); 413 } 414 } else { 415 CheckMethodAdapter.checkInternalName(superName, "super class name"); 416 } 417 if (signature != null) { 418 checkClassSignature(signature); 419 } 420 if ((access & Opcodes.ACC_INTERFACE) != 0) { 421 if (!"java/lang/Object".equals(superName)) { 422 throw new IllegalArgumentException( 423 "The super class name of interfaces must be 'java/lang/Object'"); 424 } 425 } 426 if (interfaces != null) { 427 for (int i = 0; i < interfaces.length; ++i) { 428 CheckMethodAdapter.checkInternalName(interfaces[i], 429 "interface name at index " + i); 430 } 431 } 432 this.version = version; 433 super.visit(version, access, name, signature, superName, interfaces); 434 } 435 436 @Override 437 public void visitSource(final String file, final String debug) { 438 checkState(); 439 if (source) { 440 throw new IllegalStateException( 441 "visitSource can be called only once."); 442 } 443 source = true; 444 super.visitSource(file, debug); 445 } 446 447 @Override 448 public void visitOuterClass(final String owner, final String name, 449 final String desc) { 450 checkState(); 451 if (outer) { 452 throw new IllegalStateException( 453 "visitOuterClass can be called only once."); 454 } 455 outer = true; 456 if (owner == null) { 457 throw new IllegalArgumentException("Illegal outer class owner"); 458 } 459 if (desc != null) { 460 CheckMethodAdapter.checkMethodDesc(desc); 461 } 462 super.visitOuterClass(owner, name, desc); 463 } 464 465 @Override 466 public void visitInnerClass(final String name, final String outerName, 467 final String innerName, final int access) { 468 checkState(); 469 CheckMethodAdapter.checkInternalName(name, "class name"); 470 if (outerName != null) { 471 CheckMethodAdapter.checkInternalName(outerName, "outer class name"); 472 } 473 if (innerName != null) { 474 CheckMethodAdapter.checkIdentifier(innerName, "inner class name"); 475 } 476 checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE 477 + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC 478 + Opcodes.ACC_FINAL + Opcodes.ACC_INTERFACE 479 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC 480 + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM); 481 super.visitInnerClass(name, outerName, innerName, access); 482 } 483 484 @Override 485 public FieldVisitor visitField(final int access, final String name, 486 final String desc, final String signature, final Object value) { 487 checkState(); 488 checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE 489 + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC 490 + Opcodes.ACC_FINAL + Opcodes.ACC_VOLATILE 491 + Opcodes.ACC_TRANSIENT + Opcodes.ACC_SYNTHETIC 492 + Opcodes.ACC_ENUM + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE 493 CheckMethodAdapter.checkUnqualifiedName(version, name, "field name"); 494 CheckMethodAdapter.checkDesc(desc, false); 495 if (signature != null) { 496 checkFieldSignature(signature); 497 } 498 if (value != null) { 499 CheckMethodAdapter.checkConstant(value); 500 } 501 FieldVisitor av = super 502 .visitField(access, name, desc, signature, value); 503 return new CheckFieldAdapter(av); 504 } 505 506 @Override 507 public MethodVisitor visitMethod(final int access, final String name, 508 final String desc, final String signature, final String[] exceptions) { 509 checkState(); 510 checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE 511 + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC 512 + Opcodes.ACC_FINAL + Opcodes.ACC_SYNCHRONIZED 513 + Opcodes.ACC_BRIDGE + Opcodes.ACC_VARARGS + Opcodes.ACC_NATIVE 514 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_STRICT 515 + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE 516 if (!"<init>".equals(name) && !"<clinit>".equals(name)) { 517 CheckMethodAdapter.checkMethodIdentifier(version, name, 518 "method name"); 519 } 520 CheckMethodAdapter.checkMethodDesc(desc); 521 if (signature != null) { 522 checkMethodSignature(signature); 523 } 524 if (exceptions != null) { 525 for (int i = 0; i < exceptions.length; ++i) { 526 CheckMethodAdapter.checkInternalName(exceptions[i], 527 "exception name at index " + i); 528 } 529 } 530 CheckMethodAdapter cma; 531 if (checkDataFlow) { 532 cma = new CheckMethodAdapter(access, name, desc, super.visitMethod( 533 access, name, desc, signature, exceptions), labels); 534 } else { 535 cma = new CheckMethodAdapter(super.visitMethod(access, name, desc, 536 signature, exceptions), labels); 537 } 538 cma.version = version; 539 return cma; 540 } 541 542 @Override 543 public AnnotationVisitor visitAnnotation(final String desc, 544 final boolean visible) { 545 checkState(); 546 CheckMethodAdapter.checkDesc(desc, false); 547 return new CheckAnnotationAdapter(super.visitAnnotation(desc, visible)); 548 } 549 550 @Override 551 public AnnotationVisitor visitTypeAnnotation(final int typeRef, 552 final TypePath typePath, final String desc, final boolean visible) { 553 checkState(); 554 int sort = typeRef >>> 24; 555 if (sort != TypeReference.CLASS_TYPE_PARAMETER 556 && sort != TypeReference.CLASS_TYPE_PARAMETER_BOUND 557 && sort != TypeReference.CLASS_EXTENDS) { 558 throw new IllegalArgumentException("Invalid type reference sort 0x" 559 + Integer.toHexString(sort)); 560 } 561 checkTypeRefAndPath(typeRef, typePath); 562 CheckMethodAdapter.checkDesc(desc, false); 563 return new CheckAnnotationAdapter(super.visitTypeAnnotation(typeRef, 564 typePath, desc, visible)); 565 } 566 567 @Override 568 public void visitAttribute(final Attribute attr) { 569 checkState(); 570 if (attr == null) { 571 throw new IllegalArgumentException( 572 "Invalid attribute (must not be null)"); 573 } 574 super.visitAttribute(attr); 575 } 576 577 @Override 578 public void visitEnd() { 579 checkState(); 580 end = true; 581 super.visitEnd(); 582 } 583 584 // ------------------------------------------------------------------------ 585 // Utility methods 586 // ------------------------------------------------------------------------ 587 588 /** 589 * Checks that the visit method has been called and that visitEnd has not 590 * been called. 591 */ 592 private void checkState() { 593 if (!start) { 594 throw new IllegalStateException( 595 "Cannot visit member before visit has been called."); 596 } 597 if (end) { 598 throw new IllegalStateException( 599 "Cannot visit member after visitEnd has been called."); 600 } 601 } 602 603 /** 604 * Checks that the given access flags do not contain invalid flags. This 605 * method also checks that mutually incompatible flags are not set 606 * simultaneously. 607 * 608 * @param access 609 * the access flags to be checked 610 * @param possibleAccess 611 * the valid access flags. 612 */ 613 static void checkAccess(final int access, final int possibleAccess) { 614 if ((access & ~possibleAccess) != 0) { 615 throw new IllegalArgumentException("Invalid access flags: " 616 + access); 617 } 618 int pub = (access & Opcodes.ACC_PUBLIC) == 0 ? 0 : 1; 619 int pri = (access & Opcodes.ACC_PRIVATE) == 0 ? 0 : 1; 620 int pro = (access & Opcodes.ACC_PROTECTED) == 0 ? 0 : 1; 621 if (pub + pri + pro > 1) { 622 throw new IllegalArgumentException( 623 "public private and protected are mutually exclusive: " 624 + access); 625 } 626 int fin = (access & Opcodes.ACC_FINAL) == 0 ? 0 : 1; 627 int abs = (access & Opcodes.ACC_ABSTRACT) == 0 ? 0 : 1; 628 if (fin + abs > 1) { 629 throw new IllegalArgumentException( 630 "final and abstract are mutually exclusive: " + access); 631 } 632 } 633 634 /** 635 * Checks a class signature. 636 * 637 * @param signature 638 * a string containing the signature that must be checked. 639 */ 640 public static void checkClassSignature(final String signature) { 641 // ClassSignature: 642 // FormalTypeParameters? ClassTypeSignature ClassTypeSignature* 643 644 int pos = 0; 645 if (getChar(signature, 0) == '<') { 646 pos = checkFormalTypeParameters(signature, pos); 647 } 648 pos = checkClassTypeSignature(signature, pos); 649 while (getChar(signature, pos) == 'L') { 650 pos = checkClassTypeSignature(signature, pos); 651 } 652 if (pos != signature.length()) { 653 throw new IllegalArgumentException(signature + ": error at index " 654 + pos); 655 } 656 } 657 658 /** 659 * Checks a method signature. 660 * 661 * @param signature 662 * a string containing the signature that must be checked. 663 */ 664 public static void checkMethodSignature(final String signature) { 665 // MethodTypeSignature: 666 // FormalTypeParameters? ( TypeSignature* ) ( TypeSignature | V ) ( 667 // ^ClassTypeSignature | ^TypeVariableSignature )* 668 669 int pos = 0; 670 if (getChar(signature, 0) == '<') { 671 pos = checkFormalTypeParameters(signature, pos); 672 } 673 pos = checkChar('(', signature, pos); 674 while ("ZCBSIFJDL[T".indexOf(getChar(signature, pos)) != -1) { 675 pos = checkTypeSignature(signature, pos); 676 } 677 pos = checkChar(')', signature, pos); 678 if (getChar(signature, pos) == 'V') { 679 ++pos; 680 } else { 681 pos = checkTypeSignature(signature, pos); 682 } 683 while (getChar(signature, pos) == '^') { 684 ++pos; 685 if (getChar(signature, pos) == 'L') { 686 pos = checkClassTypeSignature(signature, pos); 687 } else { 688 pos = checkTypeVariableSignature(signature, pos); 689 } 690 } 691 if (pos != signature.length()) { 692 throw new IllegalArgumentException(signature + ": error at index " 693 + pos); 694 } 695 } 696 697 /** 698 * Checks a field signature. 699 * 700 * @param signature 701 * a string containing the signature that must be checked. 702 */ 703 public static void checkFieldSignature(final String signature) { 704 int pos = checkFieldTypeSignature(signature, 0); 705 if (pos != signature.length()) { 706 throw new IllegalArgumentException(signature + ": error at index " 707 + pos); 708 } 709 } 710 711 /** 712 * Checks the reference to a type in a type annotation. 713 * 714 * @param typeRef 715 * a reference to an annotated type. 716 * @param typePath 717 * the path to the annotated type argument, wildcard bound, array 718 * element type, or static inner type within 'typeRef'. May be 719 * <tt>null</tt> if the annotation targets 'typeRef' as a whole. 720 */ 721 static void checkTypeRefAndPath(int typeRef, TypePath typePath) { 722 int mask = 0; 723 switch (typeRef >>> 24) { 724 case TypeReference.CLASS_TYPE_PARAMETER: 725 case TypeReference.METHOD_TYPE_PARAMETER: 726 case TypeReference.METHOD_FORMAL_PARAMETER: 727 mask = 0xFFFF0000; 728 break; 729 case TypeReference.FIELD: 730 case TypeReference.METHOD_RETURN: 731 case TypeReference.METHOD_RECEIVER: 732 case TypeReference.LOCAL_VARIABLE: 733 case TypeReference.RESOURCE_VARIABLE: 734 case TypeReference.INSTANCEOF: 735 case TypeReference.NEW: 736 case TypeReference.CONSTRUCTOR_REFERENCE: 737 case TypeReference.METHOD_REFERENCE: 738 mask = 0xFF000000; 739 break; 740 case TypeReference.CLASS_EXTENDS: 741 case TypeReference.CLASS_TYPE_PARAMETER_BOUND: 742 case TypeReference.METHOD_TYPE_PARAMETER_BOUND: 743 case TypeReference.THROWS: 744 case TypeReference.EXCEPTION_PARAMETER: 745 mask = 0xFFFFFF00; 746 break; 747 case TypeReference.CAST: 748 case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: 749 case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT: 750 case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: 751 case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT: 752 mask = 0xFF0000FF; 753 break; 754 default: 755 throw new IllegalArgumentException("Invalid type reference sort 0x" 756 + Integer.toHexString(typeRef >>> 24)); 757 } 758 if ((typeRef & ~mask) != 0) { 759 throw new IllegalArgumentException("Invalid type reference 0x" 760 + Integer.toHexString(typeRef)); 761 } 762 if (typePath != null) { 763 for (int i = 0; i < typePath.getLength(); ++i) { 764 int step = typePath.getStep(i); 765 if (step != TypePath.ARRAY_ELEMENT 766 && step != TypePath.INNER_TYPE 767 && step != TypePath.TYPE_ARGUMENT 768 && step != TypePath.WILDCARD_BOUND) { 769 throw new IllegalArgumentException( 770 "Invalid type path step " + i + " in " + typePath); 771 } 772 if (step != TypePath.TYPE_ARGUMENT 773 && typePath.getStepArgument(i) != 0) { 774 throw new IllegalArgumentException( 775 "Invalid type path step argument for step " + i 776 + " in " + typePath); 777 } 778 } 779 } 780 } 781 782 /** 783 * Checks the formal type parameters of a class or method signature. 784 * 785 * @param signature 786 * a string containing the signature that must be checked. 787 * @param pos 788 * index of first character to be checked. 789 * @return the index of the first character after the checked part. 790 */ 791 private static int checkFormalTypeParameters(final String signature, int pos) { 792 // FormalTypeParameters: 793 // < FormalTypeParameter+ > 794 795 pos = checkChar('<', signature, pos); 796 pos = checkFormalTypeParameter(signature, pos); 797 while (getChar(signature, pos) != '>') { 798 pos = checkFormalTypeParameter(signature, pos); 799 } 800 return pos + 1; 801 } 802 803 /** 804 * Checks a formal type parameter of a class or method signature. 805 * 806 * @param signature 807 * a string containing the signature that must be checked. 808 * @param pos 809 * index of first character to be checked. 810 * @return the index of the first character after the checked part. 811 */ 812 private static int checkFormalTypeParameter(final String signature, int pos) { 813 // FormalTypeParameter: 814 // Identifier : FieldTypeSignature? (: FieldTypeSignature)* 815 816 pos = checkIdentifier(signature, pos); 817 pos = checkChar(':', signature, pos); 818 if ("L[T".indexOf(getChar(signature, pos)) != -1) { 819 pos = checkFieldTypeSignature(signature, pos); 820 } 821 while (getChar(signature, pos) == ':') { 822 pos = checkFieldTypeSignature(signature, pos + 1); 823 } 824 return pos; 825 } 826 827 /** 828 * Checks a field type signature. 829 * 830 * @param signature 831 * a string containing the signature that must be checked. 832 * @param pos 833 * index of first character to be checked. 834 * @return the index of the first character after the checked part. 835 */ 836 private static int checkFieldTypeSignature(final String signature, int pos) { 837 // FieldTypeSignature: 838 // ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature 839 // 840 // ArrayTypeSignature: 841 // [ TypeSignature 842 843 switch (getChar(signature, pos)) { 844 case 'L': 845 return checkClassTypeSignature(signature, pos); 846 case '[': 847 return checkTypeSignature(signature, pos + 1); 848 default: 849 return checkTypeVariableSignature(signature, pos); 850 } 851 } 852 853 /** 854 * Checks a class type signature. 855 * 856 * @param signature 857 * a string containing the signature that must be checked. 858 * @param pos 859 * index of first character to be checked. 860 * @return the index of the first character after the checked part. 861 */ 862 private static int checkClassTypeSignature(final String signature, int pos) { 863 // ClassTypeSignature: 864 // L Identifier ( / Identifier )* TypeArguments? ( . Identifier 865 // TypeArguments? )* ; 866 867 pos = checkChar('L', signature, pos); 868 pos = checkIdentifier(signature, pos); 869 while (getChar(signature, pos) == '/') { 870 pos = checkIdentifier(signature, pos + 1); 871 } 872 if (getChar(signature, pos) == '<') { 873 pos = checkTypeArguments(signature, pos); 874 } 875 while (getChar(signature, pos) == '.') { 876 pos = checkIdentifier(signature, pos + 1); 877 if (getChar(signature, pos) == '<') { 878 pos = checkTypeArguments(signature, pos); 879 } 880 } 881 return checkChar(';', signature, pos); 882 } 883 884 /** 885 * Checks the type arguments in a class type signature. 886 * 887 * @param signature 888 * a string containing the signature that must be checked. 889 * @param pos 890 * index of first character to be checked. 891 * @return the index of the first character after the checked part. 892 */ 893 private static int checkTypeArguments(final String signature, int pos) { 894 // TypeArguments: 895 // < TypeArgument+ > 896 897 pos = checkChar('<', signature, pos); 898 pos = checkTypeArgument(signature, pos); 899 while (getChar(signature, pos) != '>') { 900 pos = checkTypeArgument(signature, pos); 901 } 902 return pos + 1; 903 } 904 905 /** 906 * Checks a type argument in a class type signature. 907 * 908 * @param signature 909 * a string containing the signature that must be checked. 910 * @param pos 911 * index of first character to be checked. 912 * @return the index of the first character after the checked part. 913 */ 914 private static int checkTypeArgument(final String signature, int pos) { 915 // TypeArgument: 916 // * | ( ( + | - )? FieldTypeSignature ) 917 918 char c = getChar(signature, pos); 919 if (c == '*') { 920 return pos + 1; 921 } else if (c == '+' || c == '-') { 922 pos++; 923 } 924 return checkFieldTypeSignature(signature, pos); 925 } 926 927 /** 928 * Checks a type variable signature. 929 * 930 * @param signature 931 * a string containing the signature that must be checked. 932 * @param pos 933 * index of first character to be checked. 934 * @return the index of the first character after the checked part. 935 */ 936 private static int checkTypeVariableSignature(final String signature, 937 int pos) { 938 // TypeVariableSignature: 939 // T Identifier ; 940 941 pos = checkChar('T', signature, pos); 942 pos = checkIdentifier(signature, pos); 943 return checkChar(';', signature, pos); 944 } 945 946 /** 947 * Checks a type signature. 948 * 949 * @param signature 950 * a string containing the signature that must be checked. 951 * @param pos 952 * index of first character to be checked. 953 * @return the index of the first character after the checked part. 954 */ 955 private static int checkTypeSignature(final String signature, int pos) { 956 // TypeSignature: 957 // Z | C | B | S | I | F | J | D | FieldTypeSignature 958 959 switch (getChar(signature, pos)) { 960 case 'Z': 961 case 'C': 962 case 'B': 963 case 'S': 964 case 'I': 965 case 'F': 966 case 'J': 967 case 'D': 968 return pos + 1; 969 default: 970 return checkFieldTypeSignature(signature, pos); 971 } 972 } 973 974 /** 975 * Checks an identifier. 976 * 977 * @param signature 978 * a string containing the signature that must be checked. 979 * @param pos 980 * index of first character to be checked. 981 * @return the index of the first character after the checked part. 982 */ 983 private static int checkIdentifier(final String signature, int pos) { 984 if (!Character.isJavaIdentifierStart(getChar(signature, pos))) { 985 throw new IllegalArgumentException(signature 986 + ": identifier expected at index " + pos); 987 } 988 ++pos; 989 while (Character.isJavaIdentifierPart(getChar(signature, pos))) { 990 ++pos; 991 } 992 return pos; 993 } 994 995 /** 996 * Checks a single character. 997 * 998 * @param signature 999 * a string containing the signature that must be checked. 1000 * @param pos 1001 * index of first character to be checked. 1002 * @return the index of the first character after the checked part. 1003 */ 1004 private static int checkChar(final char c, final String signature, int pos) { 1005 if (getChar(signature, pos) == c) { 1006 return pos + 1; 1007 } 1008 throw new IllegalArgumentException(signature + ": '" + c 1009 + "' expected at index " + pos); 1010 } 1011 1012 /** 1013 * Returns the signature car at the given index. 1014 * 1015 * @param signature 1016 * a signature. 1017 * @param pos 1018 * an index in signature. 1019 * @return the character at the given index, or 0 if there is no such 1020 * character. 1021 */ 1022 private static char getChar(final String signature, int pos) { 1023 return pos < signature.length() ? signature.charAt(pos) : (char) 0; 1024 } 1025 }