1 30 package com.tc.asm.util; 31 32 import com.tc.asm.AnnotationVisitor; 33 import com.tc.asm.Label; 34 import com.tc.asm.MethodAdapter; 35 import com.tc.asm.MethodVisitor; 36 import com.tc.asm.Opcodes; 37 import com.tc.asm.Attribute; 38 import com.tc.asm.Type; 39 40 import java.util.HashMap ; 41 42 54 public class CheckMethodAdapter extends MethodAdapter { 55 56 59 private boolean startCode; 60 61 64 private boolean endCode; 65 66 69 private boolean endMethod; 70 71 75 private HashMap labels; 76 77 80 private final static int[] TYPE; 81 82 static { 83 String s = "BBBBBBBBBBBBBBBBCCIAADDDDDAAAAAAAAAAAAAAAAAAAABBBBBBBBDD" 84 + "DDDAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" 85 + "BBBBBBBBBBBBBBBBBBBJBBBBBBBBBBBBBBBBBBBBHHHHHHHHHHHHHHHHD" 86 + "KLBBBBBBFFFFGGGGAECEBBEEBBAMHHAA"; 87 TYPE = new int[s.length()]; 88 for (int i = 0; i < TYPE.length; ++i) { 89 TYPE[i] = (s.charAt(i) - 'A' - 1); 90 } 91 } 92 93 305 310 public CheckMethodAdapter(final MethodVisitor cv) { 311 super(cv); 312 this.labels = new HashMap (); 313 } 314 315 public AnnotationVisitor visitAnnotation( 316 final String desc, 317 final boolean visible) 318 { 319 checkEndMethod(); 320 checkDesc(desc, false); 321 return new CheckAnnotationAdapter(mv.visitAnnotation(desc, visible)); 322 } 323 324 public AnnotationVisitor visitAnnotationDefault() { 325 checkEndMethod(); 326 return new CheckAnnotationAdapter(mv.visitAnnotationDefault(), false); 327 } 328 329 public AnnotationVisitor visitParameterAnnotation( 330 final int parameter, 331 final String desc, 332 final boolean visible) 333 { 334 checkEndMethod(); 335 checkDesc(desc, false); 336 return new CheckAnnotationAdapter(mv.visitParameterAnnotation(parameter, 337 desc, 338 visible)); 339 } 340 341 public void visitAttribute(final Attribute attr) { 342 checkEndMethod(); 343 if (attr == null) { 344 throw new IllegalArgumentException ("Invalid attribute (must not be null)"); 345 } 346 mv.visitAttribute(attr); 347 } 348 349 public void visitCode() { 350 startCode = true; 351 mv.visitCode(); 352 } 353 354 public void visitInsn(final int opcode) { 355 checkStartCode(); 356 checkEndCode(); 357 checkOpcode(opcode, 0); 358 mv.visitInsn(opcode); 359 } 360 361 public void visitIntInsn(final int opcode, final int operand) { 362 checkStartCode(); 363 checkEndCode(); 364 checkOpcode(opcode, 1); 365 switch (opcode) { 366 case Opcodes.BIPUSH: 367 checkSignedByte(operand, "Invalid operand"); 368 break; 369 case Opcodes.SIPUSH: 370 checkSignedShort(operand, "Invalid operand"); 371 break; 372 default: 374 if (operand < Opcodes.T_BOOLEAN || operand > Opcodes.T_LONG) { 375 throw new IllegalArgumentException ("Invalid operand (must be an array type code T_...): " 376 + operand); 377 } 378 } 379 mv.visitIntInsn(opcode, operand); 380 } 381 382 public void visitVarInsn(final int opcode, final int var) { 383 checkStartCode(); 384 checkEndCode(); 385 checkOpcode(opcode, 2); 386 checkUnsignedShort(var, "Invalid variable index"); 387 mv.visitVarInsn(opcode, var); 388 } 389 390 public void visitTypeInsn(final int opcode, final String desc) { 391 checkStartCode(); 392 checkEndCode(); 393 checkOpcode(opcode, 3); 394 if (desc != null && desc.length() > 0 && desc.charAt(0) == '[') { 395 checkDesc(desc, false); 396 } else { 397 checkInternalName(desc, "type"); 398 } 399 if (opcode == Opcodes.NEW && desc.charAt(0) == '[') { 400 throw new IllegalArgumentException ("NEW cannot be used to create arrays: " 401 + desc); 402 } 403 mv.visitTypeInsn(opcode, desc); 404 } 405 406 public void visitFieldInsn( 407 final int opcode, 408 final String owner, 409 final String name, 410 final String desc) 411 { 412 checkStartCode(); 413 checkEndCode(); 414 checkOpcode(opcode, 4); 415 checkInternalName(owner, "owner"); 416 checkIdentifier(name, "name"); 417 checkDesc(desc, false); 418 mv.visitFieldInsn(opcode, owner, name, desc); 419 } 420 421 public void visitMethodInsn( 422 final int opcode, 423 final String owner, 424 final String name, 425 final String desc) 426 { 427 checkStartCode(); 428 checkEndCode(); 429 checkOpcode(opcode, 5); 430 checkMethodIdentifier(name, "name"); 431 if (!name.equals("clone")) { 432 checkInternalName(owner, "owner"); 434 } 435 checkMethodDesc(desc); 436 mv.visitMethodInsn(opcode, owner, name, desc); 437 } 438 439 public void visitJumpInsn(final int opcode, final Label label) { 440 checkStartCode(); 441 checkEndCode(); 442 checkOpcode(opcode, 6); 443 checkLabel(label, false, "label"); 444 mv.visitJumpInsn(opcode, label); 445 } 446 447 public void visitLabel(final Label label) { 448 checkStartCode(); 449 checkEndCode(); 450 checkLabel(label, false, "label"); 451 if (labels.get(label) != null) { 452 throw new IllegalArgumentException ("Already visited label"); 453 } else { 454 labels.put(label, new Integer (labels.size())); 455 } 456 mv.visitLabel(label); 457 } 458 459 public void visitLdcInsn(final Object cst) { 460 checkStartCode(); 461 checkEndCode(); 462 if (!(cst instanceof Type)) { 463 checkConstant(cst); 464 } 465 mv.visitLdcInsn(cst); 466 } 467 468 public void visitIincInsn(final int var, final int increment) { 469 checkStartCode(); 470 checkEndCode(); 471 checkUnsignedShort(var, "Invalid variable index"); 472 checkSignedShort(increment, "Invalid increment"); 473 mv.visitIincInsn(var, increment); 474 } 475 476 public void visitTableSwitchInsn( 477 final int min, 478 final int max, 479 final Label dflt, 480 final Label labels[]) 481 { 482 checkStartCode(); 483 checkEndCode(); 484 if (max < min) { 485 throw new IllegalArgumentException ("Max = " + max 486 + " must be greater than or equal to min = " + min); 487 } 488 checkLabel(dflt, false, "default label"); 489 if (labels == null || labels.length != max - min + 1) { 490 throw new IllegalArgumentException ("There must be max - min + 1 labels"); 491 } 492 for (int i = 0; i < labels.length; ++i) { 493 checkLabel(labels[i], false, "label at index " + i); 494 } 495 mv.visitTableSwitchInsn(min, max, dflt, labels); 496 } 497 498 public void visitLookupSwitchInsn( 499 final Label dflt, 500 final int keys[], 501 final Label labels[]) 502 { 503 checkEndCode(); 504 checkStartCode(); 505 checkLabel(dflt, false, "default label"); 506 if (keys == null || labels == null || keys.length != labels.length) { 507 throw new IllegalArgumentException ("There must be the same number of keys and labels"); 508 } 509 for (int i = 0; i < labels.length; ++i) { 510 checkLabel(labels[i], false, "label at index " + i); 511 } 512 mv.visitLookupSwitchInsn(dflt, keys, labels); 513 } 514 515 public void visitMultiANewArrayInsn(final String desc, final int dims) { 516 checkStartCode(); 517 checkEndCode(); 518 checkDesc(desc, false); 519 if (desc.charAt(0) != '[') { 520 throw new IllegalArgumentException ("Invalid descriptor (must be an array type descriptor): " 521 + desc); 522 } 523 if (dims < 1) { 524 throw new IllegalArgumentException ("Invalid dimensions (must be greater than 0): " 525 + dims); 526 } 527 if (dims > desc.lastIndexOf('[') + 1) { 528 throw new IllegalArgumentException ("Invalid dimensions (must not be greater than dims(desc)): " 529 + dims); 530 } 531 mv.visitMultiANewArrayInsn(desc, dims); 532 } 533 534 public void visitTryCatchBlock( 535 final Label start, 536 final Label end, 537 final Label handler, 538 final String type) 539 { 540 checkStartCode(); 541 checkEndCode(); 542 if (type != null) { 543 checkInternalName(type, "type"); 544 } 545 mv.visitTryCatchBlock(start, end, handler, type); 546 } 547 548 public void visitLocalVariable( 549 final String name, 550 final String desc, 551 final String signature, 552 final Label start, 553 final Label end, 554 final int index) 555 { 556 checkStartCode(); 557 checkEndCode(); 558 checkIdentifier(name, "name"); 559 checkDesc(desc, false); 560 checkLabel(start, true, "start label"); 561 checkLabel(end, true, "end label"); 562 checkUnsignedShort(index, "Invalid variable index"); 563 int s = ((Integer ) labels.get(start)).intValue(); 564 int e = ((Integer ) labels.get(end)).intValue(); 565 if (e < s) { 566 throw new IllegalArgumentException ("Invalid start and end labels (end must be greater than start)"); 567 } 568 mv.visitLocalVariable(name, desc, signature, start, end, index); 569 } 570 571 public void visitLineNumber(final int line, final Label start) { 572 checkStartCode(); 573 checkEndCode(); 574 checkUnsignedShort(line, "Invalid line number"); 575 checkLabel(start, true, "start label"); 576 mv.visitLineNumber(line, start); 577 } 578 579 public void visitMaxs(final int maxStack, final int maxLocals) { 580 checkStartCode(); 581 checkEndCode(); 582 endCode = true; 583 checkUnsignedShort(maxStack, "Invalid max stack"); 584 checkUnsignedShort(maxLocals, "Invalid max locals"); 585 mv.visitMaxs(maxStack, maxLocals); 586 } 587 588 public void visitEnd() { 589 checkEndMethod(); 590 endMethod = true; 591 mv.visitEnd(); 592 } 593 594 596 599 void checkStartCode() { 600 if (!startCode) { 601 throw new IllegalStateException ("Cannot visit instructions before visitCode has been called."); 602 } 603 } 604 605 608 void checkEndCode() { 609 if (endCode) { 610 throw new IllegalStateException ("Cannot visit instructions after visitMaxs has been called."); 611 } 612 } 613 614 617 void checkEndMethod() { 618 if (endMethod) { 619 throw new IllegalStateException ("Cannot visit elements after visitEnd has been called."); 620 } 621 } 622 623 629 static void checkOpcode(final int opcode, final int type) { 630 if (opcode < 0 || opcode > 199 || TYPE[opcode] != type) { 631 throw new IllegalArgumentException ("Invalid opcode: " + opcode); 632 } 633 } 634 635 641 static void checkSignedByte(final int value, final String msg) { 642 if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) { 643 throw new IllegalArgumentException (msg 644 + " (must be a signed byte): " + value); 645 } 646 } 647 648 654 static void checkSignedShort(final int value, final String msg) { 655 if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) { 656 throw new IllegalArgumentException (msg 657 + " (must be a signed short): " + value); 658 } 659 } 660 661 667 static void checkUnsignedShort(final int value, final String msg) { 668 if (value < 0 || value > 65535) { 669 throw new IllegalArgumentException (msg 670 + " (must be an unsigned short): " + value); 671 } 672 } 673 674 680 static void checkConstant(final Object cst) { 681 if (!(cst instanceof Integer ) && !(cst instanceof Float ) 682 && !(cst instanceof Long ) && !(cst instanceof Double ) 683 && !(cst instanceof String )) 684 { 685 throw new IllegalArgumentException ("Invalid constant: " + cst); 686 } 687 } 688 689 695 static void checkIdentifier(final String name, final String msg) { 696 checkIdentifier(name, 0, -1, msg); 697 } 698 699 709 static void checkIdentifier( 710 final String name, 711 final int start, 712 final int end, 713 final String msg) 714 { 715 if (name == null || (end == -1 ? name.length() <= start : end <= start)) 716 { 717 throw new IllegalArgumentException ("Invalid " + msg 718 + " (must not be null or empty)"); 719 } 720 if (!Character.isJavaIdentifierStart(name.charAt(start))) { 721 throw new IllegalArgumentException ("Invalid " + msg 722 + " (must be a valid Java identifier): " + name); 723 } 724 int max = (end == -1 ? name.length() : end); 725 for (int i = start + 1; i < max; ++i) { 726 if (!Character.isJavaIdentifierPart(name.charAt(i))) { 727 throw new IllegalArgumentException ("Invalid " + msg 728 + " (must be a valid Java identifier): " + name); 729 } 730 } 731 } 732 733 740 static void checkMethodIdentifier(final String name, final String msg) { 741 if (name == null || name.length() == 0) { 742 throw new IllegalArgumentException ("Invalid " + msg 743 + " (must not be null or empty)"); 744 } 745 if (name.equals("<init>") || name.equals("<clinit>")) { 746 return; 747 } 748 if (!Character.isJavaIdentifierStart(name.charAt(0))) { 749 throw new IllegalArgumentException ("Invalid " 750 + msg 751 + " (must be a '<init>', '<clinit>' or a valid Java identifier): " 752 + name); 753 } 754 for (int i = 1; i < name.length(); ++i) { 755 if (!Character.isJavaIdentifierPart(name.charAt(i))) { 756 throw new IllegalArgumentException ("Invalid " 757 + msg 758 + " (must be '<init>' or '<clinit>' or a valid Java identifier): " 759 + name); 760 } 761 } 762 } 763 764 770 static void checkInternalName(final String name, final String msg) { 771 checkInternalName(name, 0, -1, msg); 772 } 773 774 784 static void checkInternalName( 785 final String name, 786 final int start, 787 final int end, 788 final String msg) 789 { 790 if (name == null || name.length() == 0) { 791 throw new IllegalArgumentException ("Invalid " + msg 792 + " (must not be null or empty)"); 793 } 794 int max = (end == -1 ? name.length() : end); 795 try { 796 int begin = start; 797 int slash; 798 do { 799 slash = name.indexOf('/', begin + 1); 800 if (slash == -1 || slash > max) { 801 slash = max; 802 } 803 checkIdentifier(name, begin, slash, null); 804 begin = slash + 1; 805 } while (slash != max); 806 } catch (IllegalArgumentException _) { 807 throw new IllegalArgumentException ("Invalid " 808 + msg 809 + " (must be a fully qualified class name in internal form): " 810 + name); 811 } 812 } 813 814 820 static void checkDesc(final String desc, final boolean canBeVoid) { 821 int end = checkDesc(desc, 0, canBeVoid); 822 if (end != desc.length()) { 823 throw new IllegalArgumentException ("Invalid descriptor: " + desc); 824 } 825 } 826 827 835 static int checkDesc( 836 final String desc, 837 final int start, 838 final boolean canBeVoid) 839 { 840 if (desc == null || start >= desc.length()) { 841 throw new IllegalArgumentException ("Invalid type descriptor (must not be null or empty)"); 842 } 843 int index; 844 switch (desc.charAt(start)) { 845 case 'V': 846 if (canBeVoid) { 847 return start + 1; 848 } else { 849 throw new IllegalArgumentException ("Invalid descriptor: " 850 + desc); 851 } 852 case 'Z': 853 case 'C': 854 case 'B': 855 case 'S': 856 case 'I': 857 case 'F': 858 case 'J': 859 case 'D': 860 return start + 1; 861 case '[': 862 index = start + 1; 863 while (index < desc.length() && desc.charAt(index) == '[') { 864 ++index; 865 } 866 if (index < desc.length()) { 867 return checkDesc(desc, index, false); 868 } else { 869 throw new IllegalArgumentException ("Invalid descriptor: " 870 + desc); 871 } 872 case 'L': 873 index = desc.indexOf(';', start); 874 if (index == -1 || index - start < 2) { 875 throw new IllegalArgumentException ("Invalid descriptor: " 876 + desc); 877 } 878 try { 879 checkInternalName(desc, start + 1, index, null); 880 } catch (IllegalArgumentException _) { 881 throw new IllegalArgumentException ("Invalid descriptor: " 882 + desc); 883 } 884 return index + 1; 885 default: 886 throw new IllegalArgumentException ("Invalid descriptor: " 887 + desc); 888 } 889 } 890 891 896 static void checkMethodDesc(final String desc) { 897 if (desc == null || desc.length() == 0) { 898 throw new IllegalArgumentException ("Invalid method descriptor (must not be null or empty)"); 899 } 900 if (desc.charAt(0) != '(' || desc.length() < 3) { 901 throw new IllegalArgumentException ("Invalid descriptor: " + desc); 902 } 903 int start = 1; 904 if (desc.charAt(start) != ')') { 905 do { 906 if (desc.charAt(start) == 'V') { 907 throw new IllegalArgumentException ("Invalid descriptor: " 908 + desc); 909 } 910 start = checkDesc(desc, start, false); 911 } while (start < desc.length() && desc.charAt(start) != ')'); 912 } 913 start = checkDesc(desc, start + 1, true); 914 if (start != desc.length()) { 915 throw new IllegalArgumentException ("Invalid descriptor: " + desc); 916 } 917 } 918 919 928 void checkLabel( 929 final Label label, 930 final boolean checkVisited, 931 final String msg) 932 { 933 if (label == null) { 934 throw new IllegalArgumentException ("Invalid " + msg 935 + " (must not be null)"); 936 } 937 if (checkVisited && labels.get(label) == null) { 938 throw new IllegalArgumentException ("Invalid " + msg 939 + " (must be visited first)"); 940 } 941 } 942 } 943 | Popular Tags |