1 30 package org.objectweb.asm.util; 31 32 import org.objectweb.asm.AnnotationVisitor; 33 import org.objectweb.asm.Label; 34 import org.objectweb.asm.MethodAdapter; 35 import org.objectweb.asm.MethodVisitor; 36 import org.objectweb.asm.Opcodes; 37 import org.objectweb.asm.Attribute; 38 import org.objectweb.asm.Type; 39 40 import java.util.HashMap ; 41 42 54 public class CheckMethodAdapter extends MethodAdapter { 55 56 59 private boolean end; 60 61 65 private HashMap labels; 66 67 70 private final static int[] TYPE; 71 72 static { 73 String s = "BBBBBBBBBBBBBBBBCCIAADDDDDAAAAAAAAAAAAAAAAAAAABBBBBBBBDD" 74 + "DDDAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" 75 + "BBBBBBBBBBBBBBBBBBBJBBBBBBBBBBBBBBBBBBBBHHHHHHHHHHHHHHHHD" 76 + "KLBBBBBBFFFFGGGGAECEBBEEBBAMHHAA"; 77 TYPE = new int[s.length()]; 78 for (int i = 0; i < TYPE.length; ++i) { 79 TYPE[i] = (s.charAt(i) - 'A' - 1); 80 } 81 } 82 83 295 300 public CheckMethodAdapter(final MethodVisitor cv) { 301 super(cv); 302 this.labels = new HashMap (); 303 } 304 305 public AnnotationVisitor visitAnnotation( 306 final String desc, 307 final boolean visible) 308 { 309 return mv.visitAnnotation(desc, visible); 311 } 312 313 public AnnotationVisitor visitAnnotationDefault() { 314 return mv.visitAnnotationDefault(); 316 } 317 318 public AnnotationVisitor visitParameterAnnotation( 319 final int parameter, 320 final String desc, 321 final boolean visible) 322 { 323 return mv.visitParameterAnnotation(parameter, desc, visible); 325 } 326 327 public void visitAttribute(Attribute attr) { 328 if (attr == null) { 329 throw new IllegalArgumentException ("Invalid attribute (must not be null)"); 330 } 331 } 332 333 public void visitInsn(final int opcode) { 334 checkEnd(); 335 checkOpcode(opcode, 0); 336 mv.visitInsn(opcode); 337 } 338 339 public void visitIntInsn(final int opcode, final int operand) { 340 checkEnd(); 341 checkOpcode(opcode, 1); 342 switch (opcode) { 343 case Opcodes.BIPUSH: 344 checkSignedByte(operand, "Invalid operand"); 345 break; 346 case Opcodes.SIPUSH: 347 checkSignedShort(operand, "Invalid operand"); 348 break; 349 default: 351 if (operand < Opcodes.T_BOOLEAN || operand > Opcodes.T_LONG) { 352 throw new IllegalArgumentException ("Invalid operand (must be an array type code T_...): " 353 + operand); 354 } 355 } 356 mv.visitIntInsn(opcode, operand); 357 } 358 359 public void visitVarInsn(final int opcode, final int var) { 360 checkEnd(); 361 checkOpcode(opcode, 2); 362 checkUnsignedShort(var, "Invalid variable index"); 363 mv.visitVarInsn(opcode, var); 364 } 365 366 public void visitTypeInsn(final int opcode, final String desc) { 367 checkEnd(); 368 checkOpcode(opcode, 3); 369 if (desc != null && desc.length() > 0 && desc.charAt(0) == '[') { 370 checkDesc(desc, false); 371 } else { 372 checkInternalName(desc, "type"); 373 } 374 if (opcode == Opcodes.NEW && desc.charAt(0) == '[') { 375 throw new IllegalArgumentException ("NEW cannot be used to create arrays: " 376 + desc); 377 } 378 mv.visitTypeInsn(opcode, desc); 379 } 380 381 public void visitFieldInsn( 382 final int opcode, 383 final String owner, 384 final String name, 385 final String desc) 386 { 387 checkEnd(); 388 checkOpcode(opcode, 4); 389 checkInternalName(owner, "owner"); 390 checkIdentifier(name, "name"); 391 checkDesc(desc, false); 392 mv.visitFieldInsn(opcode, owner, name, desc); 393 } 394 395 public void visitMethodInsn( 396 final int opcode, 397 final String owner, 398 final String name, 399 final String desc) 400 { 401 checkEnd(); 402 checkOpcode(opcode, 5); 403 checkMethodIdentifier(name, "name"); 404 if (!name.equals("clone")) { 405 checkInternalName(owner, "owner"); 407 } 408 checkMethodDesc(desc); 409 mv.visitMethodInsn(opcode, owner, name, desc); 410 } 411 412 public void visitJumpInsn(final int opcode, final Label label) { 413 checkEnd(); 414 checkOpcode(opcode, 6); 415 checkLabel(label, false, "label"); 416 mv.visitJumpInsn(opcode, label); 417 } 418 419 public void visitLabel(final Label label) { 420 checkEnd(); 421 checkLabel(label, false, "label"); 422 if (labels.get(label) != null) { 423 throw new IllegalArgumentException ("Already visited label"); 424 } else { 425 labels.put(label, new Integer (labels.size())); 426 } 427 mv.visitLabel(label); 428 } 429 430 public void visitLdcInsn(final Object cst) { 431 checkEnd(); 432 if (!(cst instanceof Type)) { 433 checkConstant(cst); 434 } 435 mv.visitLdcInsn(cst); 436 } 437 438 public void visitIincInsn(final int var, final int increment) { 439 checkEnd(); 440 checkUnsignedShort(var, "Invalid variable index"); 441 checkSignedShort(increment, "Invalid increment"); 442 mv.visitIincInsn(var, increment); 443 } 444 445 public void visitTableSwitchInsn( 446 final int min, 447 final int max, 448 final Label dflt, 449 final Label labels[]) 450 { 451 checkEnd(); 452 if (max < min) { 453 throw new IllegalArgumentException ("Max = " + max 454 + " must be greater than or equal to min = " + min); 455 } 456 checkLabel(dflt, false, "default label"); 457 if (labels == null || labels.length != max - min + 1) { 458 throw new IllegalArgumentException ("There must be max - min + 1 labels"); 459 } 460 for (int i = 0; i < labels.length; ++i) { 461 checkLabel(labels[i], false, "label at index " + i); 462 } 463 mv.visitTableSwitchInsn(min, max, dflt, labels); 464 } 465 466 public void visitLookupSwitchInsn( 467 final Label dflt, 468 final int keys[], 469 final Label labels[]) 470 { 471 checkEnd(); 472 checkLabel(dflt, false, "default label"); 473 if (keys == null || labels == null || keys.length != labels.length) { 474 throw new IllegalArgumentException ("There must be the same number of keys and labels"); 475 } 476 for (int i = 0; i < labels.length; ++i) { 477 checkLabel(labels[i], false, "label at index " + i); 478 } 479 mv.visitLookupSwitchInsn(dflt, keys, labels); 480 } 481 482 public void visitMultiANewArrayInsn(final String desc, final int dims) { 483 checkEnd(); 484 checkDesc(desc, false); 485 if (desc.charAt(0) != '[') { 486 throw new IllegalArgumentException ("Invalid descriptor (must be an array type descriptor): " 487 + desc); 488 } 489 if (dims < 1) { 490 throw new IllegalArgumentException ("Invalid dimensions (must be greater than 0): " 491 + dims); 492 } 493 if (dims > desc.lastIndexOf('[') + 1) { 494 throw new IllegalArgumentException ("Invalid dimensions (must not be greater than dims(desc)): " 495 + dims); 496 } 497 mv.visitMultiANewArrayInsn(desc, dims); 498 } 499 500 public void visitTryCatchBlock( 501 final Label start, 502 final Label end, 503 final Label handler, 504 final String type) 505 { 506 checkEnd(); 507 checkLabel(start, true, "start label"); 508 checkLabel(end, true, "end label"); 509 checkLabel(handler, true, "handler label"); 510 if (type != null) { 511 checkInternalName(type, "type"); 512 } 513 int s = ((Integer ) labels.get(start)).intValue(); 514 int e = ((Integer ) labels.get(end)).intValue(); 515 if (e < s) { 516 throw new IllegalArgumentException ("Invalid start and end labels (end must be greater than start)"); 517 } 518 mv.visitTryCatchBlock(start, end, handler, type); 519 } 520 521 public void visitLocalVariable( 522 final String name, 523 final String desc, 524 final String signature, 525 final Label start, 526 final Label end, 527 final int index) 528 { 529 checkEnd(); 530 checkIdentifier(name, "name"); 531 checkDesc(desc, false); 532 checkLabel(start, true, "start label"); 533 checkLabel(end, true, "end label"); 534 checkUnsignedShort(index, "Invalid variable index"); 535 int s = ((Integer ) labels.get(start)).intValue(); 536 int e = ((Integer ) labels.get(end)).intValue(); 537 if (e < s) { 538 throw new IllegalArgumentException ("Invalid start and end labels (end must be greater than start)"); 539 } 540 mv.visitLocalVariable(name, desc, signature, start, end, index); 541 } 542 543 public void visitLineNumber(final int line, final Label start) { 544 checkEnd(); 545 checkUnsignedShort(line, "Invalid line number"); 546 checkLabel(start, true, "start label"); 547 mv.visitLineNumber(line, start); 548 } 549 550 public void visitMaxs(final int maxStack, final int maxLocals) { 551 checkEnd(); 552 end = true; 553 checkUnsignedShort(maxStack, "Invalid max stack"); 554 checkUnsignedShort(maxLocals, "Invalid max locals"); 555 mv.visitMaxs(maxStack, maxLocals); 556 } 557 558 560 563 void checkEnd() { 564 if (end) { 565 throw new IllegalStateException ("Cannot visit instructions after visitMaxs has been called."); 566 } 567 } 568 569 575 static void checkOpcode(final int opcode, final int type) { 576 if (opcode < 0 || opcode > 199 || TYPE[opcode] != type) { 577 throw new IllegalArgumentException ("Invalid opcode: " + opcode); 578 } 579 } 580 581 587 static void checkSignedByte(final int value, final String msg) { 588 if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) { 589 throw new IllegalArgumentException (msg 590 + " (must be a signed byte): " + value); 591 } 592 } 593 594 600 static void checkSignedShort(final int value, final String msg) { 601 if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) { 602 throw new IllegalArgumentException (msg 603 + " (must be a signed short): " + value); 604 } 605 } 606 607 613 static void checkUnsignedShort(final int value, final String msg) { 614 if (value < 0 || value > 65535) { 615 throw new IllegalArgumentException (msg 616 + " (must be an unsigned short): " + value); 617 } 618 } 619 620 626 static void checkConstant(final Object cst) { 627 if (!(cst instanceof Integer ) && !(cst instanceof Float ) 628 && !(cst instanceof Long ) && !(cst instanceof Double ) 629 && !(cst instanceof String )) 630 { 631 throw new IllegalArgumentException ("Invalid constant: " + cst); 632 } 633 } 634 635 641 static void checkIdentifier(final String name, final String msg) { 642 checkIdentifier(name, 0, -1, msg); 643 } 644 645 655 static void checkIdentifier( 656 final String name, 657 final int start, 658 final int end, 659 final String msg) 660 { 661 if (name == null || (end == -1 ? name.length() <= start : end <= start)) 662 { 663 throw new IllegalArgumentException ("Invalid " + msg 664 + " (must not be null or empty)"); 665 } 666 if (!Character.isJavaIdentifierStart(name.charAt(start))) { 667 throw new IllegalArgumentException ("Invalid " + msg 668 + " (must be a valid Java identifier): " + name); 669 } 670 int max = (end == -1 ? name.length() : end); 671 for (int i = start + 1; i < max; ++i) { 672 if (!Character.isJavaIdentifierPart(name.charAt(i))) { 673 throw new IllegalArgumentException ("Invalid " + msg 674 + " (must be a valid Java identifier): " + name); 675 } 676 } 677 } 678 679 686 static void checkMethodIdentifier(final String name, final String msg) { 687 if (name == null || name.length() == 0) { 688 throw new IllegalArgumentException ("Invalid " + msg 689 + " (must not be null or empty)"); 690 } 691 if (name.equals("<init>") || name.equals("<clinit>")) { 692 return; 693 } 694 if (!Character.isJavaIdentifierStart(name.charAt(0))) { 695 throw new IllegalArgumentException ("Invalid " 696 + msg 697 + " (must be a '<init>', '<clinit>' or a valid Java identifier): " 698 + name); 699 } 700 for (int i = 1; i < name.length(); ++i) { 701 if (!Character.isJavaIdentifierPart(name.charAt(i))) { 702 throw new IllegalArgumentException ("Invalid " 703 + msg 704 + " (must be '<init>' or '<clinit>' or a valid Java identifier): " 705 + name); 706 } 707 } 708 } 709 710 716 static void checkInternalName(final String name, final String msg) { 717 checkInternalName(name, 0, -1, msg); 718 } 719 720 730 static void checkInternalName( 731 final String name, 732 final int start, 733 final int end, 734 final String msg) 735 { 736 if (name == null || name.length() == 0) { 737 throw new IllegalArgumentException ("Invalid " + msg 738 + " (must not be null or empty)"); 739 } 740 int max = (end == -1 ? name.length() : end); 741 try { 742 int begin = start; 743 int slash; 744 do { 745 slash = name.indexOf('/', begin + 1); 746 if (slash == -1 || slash > max) { 747 slash = max; 748 } 749 checkIdentifier(name, begin, slash, null); 750 begin = slash + 1; 751 } while (slash != max); 752 } catch (IllegalArgumentException _) { 753 throw new IllegalArgumentException ("Invalid " 754 + msg 755 + " (must be a fully qualified class name in internal form): " 756 + name); 757 } 758 } 759 760 766 static void checkDesc(final String desc, final boolean canBeVoid) { 767 int end = checkDesc(desc, 0, canBeVoid); 768 if (end != desc.length()) { 769 throw new IllegalArgumentException ("Invalid descriptor: " + desc); 770 } 771 } 772 773 781 static int checkDesc( 782 final String desc, 783 final int start, 784 final boolean canBeVoid) 785 { 786 if (desc == null || start >= desc.length()) { 787 throw new IllegalArgumentException ("Invalid type descriptor (must not be null or empty)"); 788 } 789 int index; 790 switch (desc.charAt(start)) { 791 case 'V': 792 if (canBeVoid) { 793 return start + 1; 794 } else { 795 throw new IllegalArgumentException ("Invalid descriptor: " 796 + desc); 797 } 798 case 'Z': 799 case 'C': 800 case 'B': 801 case 'S': 802 case 'I': 803 case 'F': 804 case 'J': 805 case 'D': 806 return start + 1; 807 case '[': 808 index = start + 1; 809 while (index < desc.length() && desc.charAt(index) == '[') { 810 ++index; 811 } 812 if (index < desc.length()) { 813 return checkDesc(desc, index, false); 814 } else { 815 throw new IllegalArgumentException ("Invalid descriptor: " 816 + desc); 817 } 818 case 'L': 819 index = desc.indexOf(';', start); 820 if (index == -1 || index - start < 2) { 821 throw new IllegalArgumentException ("Invalid descriptor: " 822 + desc); 823 } 824 try { 825 checkInternalName(desc, start + 1, index, null); 826 } catch (IllegalArgumentException _) { 827 throw new IllegalArgumentException ("Invalid descriptor: " 828 + desc); 829 } 830 return index + 1; 831 default: 832 throw new IllegalArgumentException ("Invalid descriptor: " 833 + desc); 834 } 835 } 836 837 842 static void checkMethodDesc(final String desc) { 843 if (desc == null || desc.length() == 0) { 844 throw new IllegalArgumentException ("Invalid method descriptor (must not be null or empty)"); 845 } 846 if (desc.charAt(0) != '(' || desc.length() < 3) { 847 throw new IllegalArgumentException ("Invalid descriptor: " + desc); 848 } 849 int start = 1; 850 if (desc.charAt(start) != ')') { 851 do { 852 if (desc.charAt(start) == 'V') { 853 throw new IllegalArgumentException ("Invalid descriptor: " 854 + desc); 855 } 856 start = checkDesc(desc, start, false); 857 } while (start < desc.length() && desc.charAt(start) != ')'); 858 } 859 start = checkDesc(desc, start + 1, true); 860 if (start != desc.length()) { 861 throw new IllegalArgumentException ("Invalid descriptor: " + desc); 862 } 863 } 864 865 874 void checkLabel( 875 final Label label, 876 final boolean checkVisited, 877 final String msg) 878 { 879 if (label == null) { 880 throw new IllegalArgumentException ("Invalid " + msg 881 + " (must not be null)"); 882 } 883 if (checkVisited && labels.get(label) == null) { 884 throw new IllegalArgumentException ("Invalid " + msg 885 + " (must be visited first)"); 886 } 887 } 888 } 889 | Popular Tags |