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>
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.
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 * @throws IllegalStateException
363 * If a subclass calls this constructor.
364 */
365 public CheckClassAdapter(final ClassVisitor cv, final boolean checkDataFlow) {
366 this(Opcodes.ASM5, cv, checkDataFlow);
367 if (getClass() != CheckClassAdapter.class) {
368 throw new IllegalStateException();
369 }
370 }
371
372 /**
373 * Constructs a new {@link CheckClassAdapter}.
374 *
375 * @param api
376 * the ASM API version implemented by this visitor. Must be one
377 * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
378 * @param cv
379 * the class visitor to which this adapter must delegate calls.
380 * @param checkDataFlow
381 * <tt>true</tt> to perform basic data flow checks, or
382 * <tt>false</tt> to not perform any data flow check (see
383 * {@link CheckMethodAdapter}). This option requires valid
384 * maxLocals and maxStack values.
385 */
386 protected CheckClassAdapter(final int api, final ClassVisitor cv,
387 final boolean checkDataFlow) {
388 super(api, cv);
389 this.labels = new HashMap<Label, Integer>();
390 this.checkDataFlow = checkDataFlow;
391 }
392
393 // ------------------------------------------------------------------------
394 // Implementation of the ClassVisitor interface
395 // ------------------------------------------------------------------------
396
397 @Override
398 public void visit(final int version, final int access, final String name,
399 final String signature, final String superName,
400 final String[] interfaces) {
401 if (start) {
402 throw new IllegalStateException("visit must be called only once");
403 }
404 start = true;
405 checkState();
406 checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL
407 + Opcodes.ACC_SUPER + Opcodes.ACC_INTERFACE
408 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC
409 + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM
410 + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
411 if (name == null || !name.endsWith("package-info")) {
412 CheckMethodAdapter.checkInternalName(name, "class name");
413 }
414 if ("java/lang/Object".equals(name)) {
415 if (superName != null) {
416 throw new IllegalArgumentException(
417 "The super class name of the Object class must be 'null'");
418 }
419 } else {
420 CheckMethodAdapter.checkInternalName(superName, "super class name");
421 }
422 if (signature != null) {
423 checkClassSignature(signature);
424 }
425 if ((access & Opcodes.ACC_INTERFACE) != 0) {
426 if (!"java/lang/Object".equals(superName)) {
427 throw new IllegalArgumentException(
428 "The super class name of interfaces must be 'java/lang/Object'");
429 }
430 }
431 if (interfaces != null) {
432 for (int i = 0; i < interfaces.length; ++i) {
433 CheckMethodAdapter.checkInternalName(interfaces[i],
434 "interface name at index " + i);
435 }
436 }
437 this.version = version;
438 super.visit(version, access, name, signature, superName, interfaces);
439 }
440
441 @Override
442 public void visitSource(final String file, final String debug) {
443 checkState();
444 if (source) {
445 throw new IllegalStateException(
446 "visitSource can be called only once.");
447 }
448 source = true;
449 super.visitSource(file, debug);
450 }
451
452 @Override
453 public void visitOuterClass(final String owner, final String name,
454 final String desc) {
455 checkState();
456 if (outer) {
457 throw new IllegalStateException(
458 "visitOuterClass can be called only once.");
459 }
460 outer = true;
461 if (owner == null) {
462 throw new IllegalArgumentException("Illegal outer class owner");
463 }
464 if (desc != null) {
465 CheckMethodAdapter.checkMethodDesc(desc);
466 }
467 super.visitOuterClass(owner, name, desc);
468 }
469
470 @Override
471 public void visitInnerClass(final String name, final String outerName,
|
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.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.analysis.Analyzer;
84 import jdk.internal.org.objectweb.asm.tree.analysis.BasicValue;
85 import jdk.internal.org.objectweb.asm.tree.analysis.Frame;
86 import jdk.internal.org.objectweb.asm.tree.analysis.SimpleVerifier;
87
88 /**
89 * A {@link ClassVisitor} that checks that its methods are properly used. More
90 * precisely this class adapter checks each method call individually, based
91 * <i>only</i> on its arguments, but does <i>not</i> check the <i>sequence</i>
92 * of method calls. For example, the invalid sequence
93 * <tt>visitField(ACC_PUBLIC, "i", "I", null)</tt> <tt>visitField(ACC_PUBLIC,
94 * "i", "D", null)</tt> will <i>not</i> be detected by this class adapter.
95 *
96 * <p>
165 * <tt>true</tt> if the visit method has been called.
166 */
167 private boolean start;
168
169 /**
170 * <tt>true</tt> if the visitSource method has been called.
171 */
172 private boolean source;
173
174 /**
175 * <tt>true</tt> if the visitOuterClass method has been called.
176 */
177 private boolean outer;
178
179 /**
180 * <tt>true</tt> if the visitEnd method has been called.
181 */
182 private boolean end;
183
184 /**
185 * <tt>true</tt> if the visitModule method has been called.
186 */
187 private boolean module;
188
189 /**
190 * The already visited labels. This map associate Integer values to Label
191 * keys.
192 */
193 private Map<Label, Integer> labels;
194
195 /**
196 * <tt>true</tt> if the method code must be checked with a BasicVerifier.
197 */
198 private boolean checkDataFlow;
199
200 /**
201 * Checks a given class.
202 * <p>
203 * Usage: CheckClassAdapter <binary class name or class file name>
204 *
205 * @param args
206 * the command line arguments.
207 *
208 * @throws Exception
209 * if the class cannot be found, or if an IO exception occurs.
352 public CheckClassAdapter(final ClassVisitor cv) {
353 this(cv, true);
354 }
355
356 /**
357 * Constructs a new {@link CheckClassAdapter}. <i>Subclasses must not use
358 * this constructor</i>. Instead, they must use the
359 * {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version.
360 *
361 * @param cv
362 * the class visitor to which this adapter must delegate calls.
363 * @param checkDataFlow
364 * <tt>true</tt> to perform basic data flow checks, or
365 * <tt>false</tt> to not perform any data flow check (see
366 * {@link CheckMethodAdapter}). This option requires valid
367 * maxLocals and maxStack values.
368 * @throws IllegalStateException
369 * If a subclass calls this constructor.
370 */
371 public CheckClassAdapter(final ClassVisitor cv, final boolean checkDataFlow) {
372 this(Opcodes.ASM6, cv, checkDataFlow);
373 if (getClass() != CheckClassAdapter.class) {
374 throw new IllegalStateException();
375 }
376 }
377
378 /**
379 * Constructs a new {@link CheckClassAdapter}.
380 *
381 * @param api
382 * the ASM API version implemented by this visitor. Must be one
383 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
384 * @param cv
385 * the class visitor to which this adapter must delegate calls.
386 * @param checkDataFlow
387 * <tt>true</tt> to perform basic data flow checks, or
388 * <tt>false</tt> to not perform any data flow check (see
389 * {@link CheckMethodAdapter}). This option requires valid
390 * maxLocals and maxStack values.
391 */
392 protected CheckClassAdapter(final int api, final ClassVisitor cv,
393 final boolean checkDataFlow) {
394 super(api, cv);
395 this.labels = new HashMap<Label, Integer>();
396 this.checkDataFlow = checkDataFlow;
397 }
398
399 // ------------------------------------------------------------------------
400 // Implementation of the ClassVisitor interface
401 // ------------------------------------------------------------------------
402
403 @Override
404 public void visit(final int version, final int access, final String name,
405 final String signature, final String superName,
406 final String[] interfaces) {
407 if (start) {
408 throw new IllegalStateException("visit must be called only once");
409 }
410 start = true;
411 checkState();
412 checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL
413 + Opcodes.ACC_SUPER + Opcodes.ACC_INTERFACE
414 + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC
415 + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM
416 + Opcodes.ACC_DEPRECATED + Opcodes.ACC_MODULE
417 + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
418 if (name == null) {
419 throw new IllegalArgumentException("Illegal class name (null)");
420 }
421 if (!name.endsWith("package-info")) {
422 CheckMethodAdapter.checkInternalName(name, "class name");
423 }
424 if ("java/lang/Object".equals(name)) {
425 if (superName != null) {
426 throw new IllegalArgumentException(
427 "The super class name of the Object class must be 'null'");
428 }
429 } else {
430 CheckMethodAdapter.checkInternalName(superName, "super class name");
431 }
432 if (signature != null) {
433 checkClassSignature(signature);
434 }
435 if ((access & Opcodes.ACC_INTERFACE) != 0) {
436 if (!"java/lang/Object".equals(superName)) {
437 throw new IllegalArgumentException(
438 "The super class name of interfaces must be 'java/lang/Object'");
439 }
440 }
441 if (interfaces != null) {
442 for (int i = 0; i < interfaces.length; ++i) {
443 CheckMethodAdapter.checkInternalName(interfaces[i],
444 "interface name at index " + i);
445 }
446 }
447 this.version = version;
448 super.visit(version, access, name, signature, superName, interfaces);
449 }
450
451 @Override
452 public void visitSource(final String file, final String debug) {
453 checkState();
454 if (source) {
455 throw new IllegalStateException(
456 "visitSource can be called only once.");
457 }
458 source = true;
459 super.visitSource(file, debug);
460 }
461
462 @Override
463 public ModuleVisitor visitModule(String name, int access, String version) {
464 checkState();
465 if (module) {
466 throw new IllegalStateException(
467 "visitModule can be called only once.");
468 }
469 module = true;
470 if (name == null) {
471 throw new IllegalArgumentException("Illegal module name (null)");
472 }
473 checkAccess(access, Opcodes.ACC_OPEN | Opcodes.ACC_SYNTHETIC);
474 return new CheckModuleAdapter(super.visitModule(name, access, version),
475 (access & Opcodes.ACC_OPEN) != 0);
476 }
477
478 @Override
479 public void visitOuterClass(final String owner, final String name,
480 final String desc) {
481 checkState();
482 if (outer) {
483 throw new IllegalStateException(
484 "visitOuterClass can be called only once.");
485 }
486 outer = true;
487 if (owner == null) {
488 throw new IllegalArgumentException("Illegal outer class owner");
489 }
490 if (desc != null) {
491 CheckMethodAdapter.checkMethodDesc(desc);
492 }
493 super.visitOuterClass(owner, name, desc);
494 }
495
496 @Override
497 public void visitInnerClass(final String name, final String outerName,
|