1 34 35 package org.logicalcobwebs.asm.util; 36 37 import org.logicalcobwebs.asm.Label; 38 import org.logicalcobwebs.asm.CodeAdapter; 39 import org.logicalcobwebs.asm.CodeVisitor; 40 import org.logicalcobwebs.asm.Constants; 41 import org.logicalcobwebs.asm.Attribute; 42 43 import java.util.HashMap ; 44 45 55 56 public class CheckCodeAdapter extends CodeAdapter { 57 58 61 62 private boolean end; 63 64 68 69 private HashMap labels; 70 71 74 75 private final static int[] TYPE = new int[] { 76 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 7, -1, -1, 2, 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 9, 10, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 5, 5, 5, 5, -1, 3, 1, 3, 0, 0, 3, 3, 0, 0, -1, 11, 6, 6, -1, -1 }; 279 280 285 286 public CheckCodeAdapter (final CodeVisitor cv) { 287 super(cv); 288 this.labels = new HashMap (); 289 } 290 291 public void visitInsn (final int opcode) { 292 checkEnd(); 293 checkOpcode(opcode, 0); 294 cv.visitInsn(opcode); 295 } 296 297 public void visitIntInsn (final int opcode, final int operand) { 298 checkEnd(); 299 checkOpcode(opcode, 1); 300 switch (opcode) { 301 case Constants.BIPUSH: 302 checkSignedByte(operand, "Invalid operand"); 303 break; 304 case Constants.SIPUSH: 305 checkSignedShort(operand, "Invalid operand"); 306 break; 307 default: 309 if (operand < Constants.T_BOOLEAN || operand > Constants.T_LONG) { 310 throw new IllegalArgumentException ( 311 "Invalid operand (must be an array type code T_...): " + operand); 312 } 313 } 314 cv.visitIntInsn(opcode, operand); 315 } 316 317 public void visitVarInsn (final int opcode, final int var) { 318 checkEnd(); 319 checkOpcode(opcode, 2); 320 checkUnsignedShort(var, "Invalid variable index"); 321 cv.visitVarInsn(opcode, var); 322 } 323 324 public void visitTypeInsn (final int opcode, final String desc) { 325 checkEnd(); 326 checkOpcode(opcode, 3); 327 if (desc != null && desc.length() > 0 && desc.charAt(0) == '[') { 328 checkDesc(desc, false); 329 } else { 330 checkInternalName(desc, "type"); 331 } 332 if (opcode == Constants.NEW && desc.charAt(0) == '[') { 333 throw new IllegalArgumentException ( 334 "NEW cannot be used to create arrays: " + desc); 335 } 336 cv.visitTypeInsn(opcode, desc); 337 } 338 339 public void visitFieldInsn ( 340 final int opcode, 341 final String owner, 342 final String name, 343 final String desc) 344 { 345 checkEnd(); 346 checkOpcode(opcode, 4); 347 checkInternalName(owner, "owner"); 348 checkIdentifier(name, "name"); 349 checkDesc(desc, false); 350 cv.visitFieldInsn(opcode, owner, name, desc); 351 } 352 353 public void visitMethodInsn ( 354 final int opcode, 355 final String owner, 356 final String name, 357 final String desc) 358 { 359 checkEnd(); 360 checkOpcode(opcode, 5); 361 checkInternalName(owner, "owner"); 362 checkMethodIdentifier(name, "name"); 363 checkMethodDesc(desc); 364 cv.visitMethodInsn(opcode, owner, name, desc); 365 } 366 367 public void visitJumpInsn (final int opcode, final Label label) { 368 checkEnd(); 369 checkOpcode(opcode, 6); 370 checkLabel(label, false, "label"); 371 cv.visitJumpInsn(opcode, label); 372 } 373 374 public void visitLabel (final Label label) { 375 checkEnd(); 376 checkLabel(label, false, "label"); 377 if (labels.get(label) != null) { 378 throw new IllegalArgumentException ("Already visited label"); 379 } else { 380 labels.put(label, new Integer (labels.size())); 381 } 382 cv.visitLabel(label); 383 } 384 385 public void visitLdcInsn (final Object cst) { 386 checkEnd(); 387 checkConstant(cst); 388 cv.visitLdcInsn(cst); 389 } 390 391 public void visitIincInsn (final int var, final int increment) { 392 checkEnd(); 393 checkUnsignedShort(var, "Invalid variable index"); 394 checkSignedShort(increment, "Invalid increment"); 395 cv.visitIincInsn(var, increment); 396 } 397 398 public void visitTableSwitchInsn ( 399 final int min, 400 final int max, 401 final Label dflt, 402 final Label labels[]) 403 { 404 checkEnd(); 405 if (max < min) { 406 throw new IllegalArgumentException ( 407 "Max = " + max + " must be greater than or equal to min = " + min); 408 } 409 checkLabel(dflt, false, "default label"); 410 if (labels == null || labels.length != max - min + 1) { 411 throw new IllegalArgumentException ( 412 "There must be max - min + 1 labels"); 413 } 414 for (int i = 0; i < labels.length; ++i) { 415 checkLabel(labels[i], false, "label at index " + i); 416 } 417 cv.visitTableSwitchInsn(min, max, dflt, labels); 418 } 419 420 public void visitLookupSwitchInsn ( 421 final Label dflt, 422 final int keys[], 423 final Label labels[]) 424 { 425 checkEnd(); 426 checkLabel(dflt, false, "default label"); 427 if (keys == null || labels == null || keys.length != labels.length) { 428 throw new IllegalArgumentException ( 429 "There must be the same number of keys and labels"); 430 } 431 for (int i = 0; i < labels.length; ++i) { 432 checkLabel(labels[i], false, "label at index " + i); 433 } 434 cv.visitLookupSwitchInsn(dflt, keys, labels); 435 } 436 437 public void visitMultiANewArrayInsn (final String desc, final int dims) { 438 checkEnd(); 439 checkDesc(desc, false); 440 if (desc.charAt(0) != '[') { 441 throw new IllegalArgumentException ( 442 "Invalid descriptor (must be an array type descriptor): " + desc); 443 } 444 if (dims < 1) { 445 throw new IllegalArgumentException ( 446 "Invalid dimensions (must be greater than 0): " + dims); 447 } 448 if (dims > desc.lastIndexOf('[') + 1) { 449 throw new IllegalArgumentException ( 450 "Invalid dimensions (must not be greater than dims(desc)): " + dims); 451 } 452 cv.visitMultiANewArrayInsn(desc, dims); 453 } 454 455 public void visitTryCatchBlock ( 456 final Label start, 457 final Label end, 458 final Label handler, 459 final String type) 460 { 461 checkLabel(start, true, "start label"); 462 checkLabel(end, true, "end label"); 463 checkLabel(handler, true, "handler label"); 464 if (type != null) { 465 checkInternalName(type, "type"); 466 } 467 int s = ((Integer )labels.get(start)).intValue(); 468 int e = ((Integer )labels.get(end)).intValue(); 469 if (e <= s) { 470 throw new IllegalArgumentException ( 471 "Invalid start and end labels (end must be greater than start)"); 472 } 473 cv.visitTryCatchBlock(start, end, handler, type); 474 } 475 476 public void visitMaxs (final int maxStack, final int maxLocals) { 477 checkEnd(); 478 end = true; 479 checkUnsignedShort(maxStack, "Invalid max stack"); 480 checkUnsignedShort(maxLocals, "Invalid max locals"); 481 cv.visitMaxs(maxStack, maxLocals); 482 } 483 484 public void visitLocalVariable ( 485 final String name, 486 final String desc, 487 final Label start, 488 final Label end, 489 final int index) 490 { 491 checkIdentifier(name, "name"); 492 checkDesc(desc, false); 493 checkLabel(start, true, "start label"); 494 checkLabel(end, true, "end label"); 495 checkUnsignedShort(index, "Invalid variable index"); 496 int s = ((Integer )labels.get(start)).intValue(); 497 int e = ((Integer )labels.get(end)).intValue(); 498 if (e <= s) { 499 throw new IllegalArgumentException ( 500 "Invalid start and end labels (end must be greater than start)"); 501 } 502 cv.visitLocalVariable(name, desc, start, end, index); 503 } 504 505 public void visitLineNumber (final int line, final Label start) { 506 checkUnsignedShort(line, "Invalid line number"); 507 checkLabel(start, true, "start label"); 508 cv.visitLineNumber(line, start); 509 } 510 511 public void visitAttribute (Attribute attr) { 512 if (attr == null) { 513 throw new IllegalArgumentException ( 514 "Invalid attribute (must not be null)"); 515 } 516 } 517 518 520 523 524 void checkEnd () { 525 if (end) { 526 throw new IllegalStateException ( 527 "Cannot visit instructions after visitMaxs has been called."); 528 } 529 } 530 531 537 538 static void checkOpcode (final int opcode, final int type) { 539 if (opcode < 0 || opcode > 199 || TYPE[opcode] != type) { 540 throw new IllegalArgumentException ("Invalid opcode: " + opcode); 541 } 542 } 543 544 550 551 static void checkSignedByte (final int value, final String msg) { 552 if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) { 553 throw new IllegalArgumentException ( 554 msg + " (must be a signed byte): " + value); 555 } 556 } 557 558 564 565 static void checkSignedShort (final int value, final String msg) { 566 if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) { 567 throw new IllegalArgumentException ( 568 msg + " (must be a signed short): " + value); 569 } 570 } 571 572 578 579 static void checkUnsignedShort (final int value, final String msg) { 580 if (value < 0 || value > 65535) { 581 throw new IllegalArgumentException ( 582 msg + " (must be an unsigned short): " + value); 583 } 584 } 585 586 593 594 static void checkConstant (final Object cst) { 595 if (!(cst instanceof Integer ) && 596 !(cst instanceof Float ) && 597 !(cst instanceof Long ) && 598 !(cst instanceof Double ) && 599 !(cst instanceof String )) 600 { 601 throw new IllegalArgumentException ("Invalid constant: " + cst); 602 } 603 } 604 605 611 612 static void checkIdentifier (final String name, final String msg) { 613 checkIdentifier(name, 0, -1, msg); 614 } 615 616 625 626 static void checkIdentifier ( 627 final String name, 628 final int start, 629 final int end, 630 final String msg) 631 { 632 if (name == null || (end == -1 ? name.length() <= start : end <= start)) { 633 throw new IllegalArgumentException ( 634 "Invalid " + msg + " (must not be null or empty)"); 635 } 636 if (!Character.isJavaIdentifierStart(name.charAt(start))) { 637 throw new IllegalArgumentException ( 638 "Invalid " + msg + " (must be a valid Java identifier): " + name); 639 } 640 int max = (end == -1 ? name.length() : end); 641 for (int i = start + 1; i < max; ++i) { 642 if (!Character.isJavaIdentifierPart(name.charAt(i))) { 643 throw new IllegalArgumentException ( 644 "Invalid " + msg + " (must be a valid Java identifier): " + name); 645 } 646 } 647 } 648 649 656 657 static void checkMethodIdentifier (final String name, final String msg) { 658 if (name == null || name.length() == 0) { 659 throw new IllegalArgumentException ( 660 "Invalid " + msg + " (must not be null or empty)"); 661 } 662 if (name.equals("<init>") || name.equals("<clinit>")) { 663 return; 664 } 665 if (!Character.isJavaIdentifierStart(name.charAt(0))) { 666 throw new IllegalArgumentException ( 667 "Invalid " + msg + 668 " (must be a '<init>', '<clinit>' or a valid Java identifier): " + 669 name); 670 } 671 for (int i = 1; i < name.length(); ++i) { 672 if (!Character.isJavaIdentifierPart(name.charAt(i))) { 673 throw new IllegalArgumentException ( 674 "Invalid " + msg + 675 " (must be '<init>' or '<clinit>' or a valid Java identifier): " + 676 name); 677 } 678 } 679 } 680 681 687 688 static void checkInternalName (final String name, final String msg) { 689 checkInternalName(name, 0, -1, msg); 690 } 691 692 701 702 static void checkInternalName ( 703 final String name, 704 final int start, 705 final int end, 706 final String msg) 707 { 708 if (name == null || name.length() == 0) { 709 throw new IllegalArgumentException ( 710 "Invalid " + msg + " (must not be null or empty)"); 711 } 712 int max = (end == -1 ? name.length() : end); 713 try { 714 int begin = start; 715 int slash; 716 do { 717 slash = name.indexOf('/', begin + 1); 718 if (slash == -1 || slash > max) { 719 slash = max; 720 } 721 checkIdentifier(name, begin, slash, null); 722 begin = slash + 1; 723 } while (slash != max); 724 } catch (IllegalArgumentException _) { 725 throw new IllegalArgumentException ( 726 "Invalid " + msg + 727 " (must be a fully qualified class name in internal form): " + 728 name); 729 } 730 } 731 732 738 739 static void checkDesc (final String desc, final boolean canBeVoid) { 740 int end = checkDesc(desc, 0, canBeVoid); 741 if (end != desc.length()) { 742 throw new IllegalArgumentException ("Invalid descriptor: " + desc); 743 } 744 } 745 746 754 755 static int checkDesc ( 756 final String desc, 757 final int start, 758 final boolean canBeVoid) 759 { 760 if (desc == null || start >= desc.length()) { 761 throw new IllegalArgumentException ( 762 "Invalid type descriptor (must not be null or empty)"); 763 } 764 int index; 765 switch (desc.charAt(start)) { 766 case 'V': 767 if (canBeVoid) { 768 return start + 1; 769 } else { 770 throw new IllegalArgumentException ("Invalid descriptor: " + desc); 771 } 772 case 'Z': 773 case 'C': 774 case 'B': 775 case 'S': 776 case 'I': 777 case 'F': 778 case 'J': 779 case 'D': 780 return start + 1; 781 case '[': 782 index = start + 1; 783 while (index < desc.length() && desc.charAt(index) == '[') { 784 ++index; 785 } 786 if (index < desc.length()) { 787 return checkDesc(desc, index, false); 788 } else { 789 throw new IllegalArgumentException ("Invalid descriptor: " + desc); 790 } 791 case 'L': 792 index = desc.indexOf(';', start); 793 if (index == -1 || index - start < 2) { 794 throw new IllegalArgumentException ("Invalid descriptor: " + desc); 795 } 796 try { 797 checkInternalName(desc, start + 1, index, null); 798 } catch (IllegalArgumentException _) { 799 throw new IllegalArgumentException ("Invalid descriptor: " + desc); 800 } 801 return index + 1; 802 default: 803 throw new IllegalArgumentException ("Invalid descriptor: " + desc); 804 } 805 } 806 807 812 813 static void checkMethodDesc (final String desc) { 814 if (desc == null || desc.length() == 0) { 815 throw new IllegalArgumentException ( 816 "Invalid method descriptor (must not be null or empty)"); 817 } 818 if (desc.charAt(0) != '(' || desc.length() < 3) { 819 throw new IllegalArgumentException ("Invalid descriptor: " + desc); 820 } 821 int start = 1; 822 if (desc.charAt(start) != ')') { 823 do { 824 if (desc.charAt(start) == 'V') { 825 throw new IllegalArgumentException ("Invalid descriptor: " + desc); 826 } 827 start = checkDesc(desc, start, false); 828 } while (start < desc.length() && desc.charAt(start) != ')'); 829 } 830 start = checkDesc(desc, start + 1, true); 831 if (start != desc.length()) { 832 throw new IllegalArgumentException ("Invalid descriptor: " + desc); 833 } 834 } 835 836 844 845 void checkLabel ( 846 final Label label, 847 final boolean checkVisited, 848 final String msg) 849 { 850 if (label == null) { 851 throw new IllegalArgumentException ( 852 "Invalid " + msg + " (must not be null)"); 853 } 854 if (checkVisited && labels.get(label) == null) { 855 throw new IllegalArgumentException ( 856 "Invalid " + msg + " (must be visited first)"); 857 } 858 } 859 } 860 | Popular Tags |