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