1 19 20 package edu.umd.cs.findbugs.ba.type; 21 22 import org.apache.bcel.Constants; 23 import org.apache.bcel.classfile.Attribute; 24 import org.apache.bcel.classfile.Field; 25 import org.apache.bcel.classfile.Signature; 26 import org.apache.bcel.generic.*; 27 28 import edu.umd.cs.findbugs.ba.AbstractFrameModelingVisitor; 29 import edu.umd.cs.findbugs.ba.AnalysisContext; 30 import edu.umd.cs.findbugs.ba.DataflowAnalysisException; 31 import edu.umd.cs.findbugs.ba.Debug; 32 import edu.umd.cs.findbugs.ba.Hierarchy; 33 import edu.umd.cs.findbugs.ba.InvalidBytecodeException; 34 import edu.umd.cs.findbugs.ba.Location; 35 import edu.umd.cs.findbugs.ba.ObjectTypeFactory; 36 import edu.umd.cs.findbugs.ba.XField; 37 import edu.umd.cs.findbugs.ba.generic.GenericUtilities; 38 import edu.umd.cs.findbugs.ba.vna.ValueNumber; 39 import edu.umd.cs.findbugs.ba.vna.ValueNumberDataflow; 40 import edu.umd.cs.findbugs.ba.vna.ValueNumberFrame; 41 42 54 public class TypeFrameModelingVisitor extends AbstractFrameModelingVisitor<Type, TypeFrame> 55 implements Constants, Debug { 56 57 static private final ObjectType COLLECTION_TYPE = ObjectTypeFactory.getInstance("java.util.Collection"); 58 59 private ValueNumberDataflow valueNumberDataflow; 60 61 private short lastOpcode; 63 private boolean instanceOfFollowedByBranch; 64 private Type instanceOfType; 65 private ValueNumber instanceOfValueNumber; 66 67 private FieldStoreTypeDatabase database; 68 69 74 public TypeFrameModelingVisitor(ConstantPoolGen cpg) { 75 super(cpg); 76 } 77 78 85 public void setValueNumberDataflow(ValueNumberDataflow valueNumberDataflow) { 86 this.valueNumberDataflow = valueNumberDataflow; 87 } 88 89 96 public short getLastOpcode() { 97 return lastOpcode; 98 } 99 100 108 public boolean isInstanceOfFollowedByBranch() { 109 return instanceOfFollowedByBranch; 110 } 111 112 119 public Type getInstanceOfType() { 120 return instanceOfType; 121 } 122 123 130 public ValueNumber getInstanceOfValueNumber() { 131 return instanceOfValueNumber; 132 } 133 134 141 public void setFieldStoreTypeDatabase(FieldStoreTypeDatabase database) { 142 this.database = database; 143 } 144 145 @Override 146 public Type getDefaultValue() { 147 return TypeFrame.getBottomType(); 148 } 149 150 @Override 151 public void analyzeInstruction(Instruction ins) throws DataflowAnalysisException { 152 instanceOfFollowedByBranch = false; 153 super.analyzeInstruction(ins); 154 lastOpcode = ins.getOpcode(); 155 } 156 157 162 public void startBasicBlock() { 163 lastOpcode = -1; 164 instanceOfType = null; 165 instanceOfValueNumber = null; 166 } 167 168 172 protected void consumeStack(Instruction ins) { 173 ConstantPoolGen cpg = getCPG(); 174 TypeFrame frame = getFrame(); 175 176 int numWordsConsumed = ins.consumeStack(cpg); 177 if (numWordsConsumed == Constants.UNPREDICTABLE) 178 throw new InvalidBytecodeException("Unpredictable stack consumption for " + ins); 179 try { 180 while (numWordsConsumed-- > 0) { 181 frame.popValue(); 182 } 183 } catch (DataflowAnalysisException e) { 184 throw new InvalidBytecodeException("Stack underflow for " + ins + ": " + e.getMessage()); 185 } 186 } 187 188 194 protected void pushValue(Type type) { 195 TypeFrame frame = getFrame(); 196 if (type.getType() == T_LONG) { 197 frame.pushValue(Type.LONG); 198 frame.pushValue(TypeFrame.getLongExtraType()); 199 } else if (type.getType() == T_DOUBLE) { 200 frame.pushValue(Type.DOUBLE); 201 frame.pushValue(TypeFrame.getDoubleExtraType()); 202 } else 203 frame.pushValue(type); 204 } 205 206 209 protected void pushReturnType(InvokeInstruction ins) { 210 ConstantPoolGen cpg = getCPG(); 211 Type type = ins.getType(cpg); 212 if (type.getType() != T_VOID) 213 pushValue(type); 214 } 215 216 220 @Override 221 public void modelNormalInstruction(Instruction ins, int numWordsConsumed, int numWordsProduced) { 222 if (VERIFY_INTEGRITY) { 223 if (numWordsProduced > 0) 224 throw new InvalidBytecodeException("missing visitor method for " + ins); 225 } 226 super.modelNormalInstruction(ins, numWordsConsumed, numWordsProduced); 227 } 228 229 233 242 @Override 243 public void visitATHROW(ATHROW obj) { 244 } 246 247 @Override 248 public void visitACONST_NULL(ACONST_NULL obj) { 249 pushValue(TypeFrame.getNullType()); 250 } 251 252 @Override 253 public void visitDCONST(DCONST obj) { 254 pushValue(Type.DOUBLE); 255 } 256 257 @Override 258 public void visitFCONST(FCONST obj) { 259 pushValue(Type.FLOAT); 260 } 261 262 @Override 263 public void visitICONST(ICONST obj) { 264 pushValue(Type.INT); 265 } 266 267 @Override 268 public void visitLCONST(LCONST obj) { 269 pushValue(Type.LONG); 270 } 271 272 @Override 273 public void visitLDC(LDC obj) { 274 pushValue(obj.getType(getCPG())); 275 } 276 277 @Override 278 public void visitLDC2_W(LDC2_W obj) { 279 pushValue(obj.getType(getCPG())); 280 } 281 282 @Override 283 public void visitBIPUSH(BIPUSH obj) { 284 pushValue(Type.INT); 285 } 286 287 @Override 288 public void visitSIPUSH(SIPUSH obj) { 289 pushValue(Type.INT); 290 } 291 292 @Override 293 public void visitGETSTATIC(GETSTATIC obj) { 294 modelFieldLoad(obj); 295 } 296 297 @Override 298 public void visitGETFIELD(GETFIELD obj) { 299 modelFieldLoad(obj); 300 } 301 302 public void modelFieldLoad(FieldInstruction obj) { 303 consumeStack(obj); 304 305 Type loadType = obj.getType(getCPG()); 306 Type originalLoadType = loadType; 307 308 try { 309 XField xfield = Hierarchy.findXField(obj, getCPG()); 312 if (database != null && (loadType instanceof ReferenceType) && xfield != null) { 313 FieldStoreType property = database.getProperty(xfield); 314 if (property != null) { 315 loadType = property.getLoadType((ReferenceType) loadType); 316 } 317 } 318 319 if (originalLoadType.equals(loadType) && xfield != null) { 324 Field field = Hierarchy.findField(xfield.getClassName(), xfield.getName()); 326 String signature = null; 327 for (Attribute a : field.getAttributes()) { 328 if (a instanceof Signature) { 329 signature = ((Signature) a).getSignature(); 330 break; 331 } 332 } 333 334 if (signature != null && 336 (loadType instanceof ObjectType || loadType instanceof ArrayType) && 337 !(loadType instanceof ExceptionObjectType) 338 ) { 339 loadType = GenericUtilities.getType( signature ); 340 } 341 } 342 } catch (ClassNotFoundException e) { 343 AnalysisContext.reportMissingClass(e); 344 } catch (RuntimeException e) {} 346 pushValue(loadType); 347 } 348 349 @Override 350 public void visitINVOKESTATIC(INVOKESTATIC obj) { 351 consumeStack(obj); 352 pushReturnType(obj); 353 } 354 355 @Override 356 public void visitINVOKESPECIAL(INVOKESPECIAL obj) { 357 consumeStack(obj); 358 pushReturnType(obj); 359 } 360 361 @Override 362 public void visitINVOKEINTERFACE(INVOKEINTERFACE obj) { 363 if (handleToArray(obj)) return; 364 consumeStack(obj); 365 pushReturnType(obj); 366 } 367 368 @Override 369 public void visitINVOKEVIRTUAL(INVOKEVIRTUAL obj) { 370 TypeFrame frame = getFrame(); 371 if (obj.getMethodName(cpg).equals("initCause") && obj.getSignature(cpg).equals("(Ljava/lang/Throwable;)Ljava/lang/Throwable;") && obj.getClassName(cpg).endsWith("Exception")) { 372 try { 373 374 frame.popValue(); 375 return; 376 } catch (DataflowAnalysisException e) { 377 378 } 379 } 380 if (handleToArray(obj)) return; 381 consumeStack(obj); 382 pushReturnType(obj); 383 } 384 385 private boolean handleToArray(InvokeInstruction obj) { 386 try { 387 TypeFrame frame = getFrame(); 388 if (obj.getName(getCPG()).equals("toArray")) { 389 ReferenceType target = obj.getReferenceType(getCPG()); 390 String signature = obj.getSignature(getCPG()); 391 if (signature.equals("([Ljava/lang/Object;)[Ljava/lang/Object;") && target.isAssignmentCompatibleWith(COLLECTION_TYPE)) { 392 393 boolean topIsExact = frame.isExact(frame.getStackLocation(0)); 394 Type resultType = frame.popValue(); 395 frame.popValue(); 396 frame.pushValue(resultType); 397 frame.setExact(frame.getStackLocation(0), topIsExact); 398 return true; 399 } else if (signature.equals("()[Ljava/lang/Object;")) { 400 consumeStack(obj); 401 pushReturnType(obj); 402 frame.setExact(frame.getStackLocation(0), true); 403 return true; 404 } 405 } 406 return false; 407 } catch (DataflowAnalysisException e) { 408 return false; 409 } catch (ClassNotFoundException e) { 410 AnalysisContext.reportMissingClass(e); 411 return false; 412 } 413 } 414 @Override 415 public void visitCHECKCAST(CHECKCAST obj) { 416 consumeStack(obj); 417 pushValue(obj.getType(getCPG())); 418 } 419 420 @Override 421 public void visitINSTANCEOF(INSTANCEOF obj) { 422 if (valueNumberDataflow != null) { 423 try { 426 ValueNumberFrame vnaFrame = valueNumberDataflow.getFactAtLocation(getLocation()); 427 if (vnaFrame.isValid()) { 428 instanceOfValueNumber = vnaFrame.getTopValue(); 429 instanceOfType = obj.getType(getCPG()); 430 } 431 } catch (DataflowAnalysisException e) { 432 } 434 } 435 436 437 consumeStack(obj); 438 pushValue(Type.INT); 439 } 440 441 @Override 442 public void visitIFNULL(IFNULL obj) { 443 444 if (valueNumberDataflow != null) { 445 try { 448 ValueNumberFrame vnaFrame = valueNumberDataflow 449 .getFactAtLocation(getLocation()); 450 if (vnaFrame.isValid()) { 451 instanceOfValueNumber = vnaFrame.getTopValue(); 452 453 instanceOfType = NullType.instance(); 454 instanceOfFollowedByBranch = true; 455 } 456 } catch (DataflowAnalysisException e) { 457 } 459 } 460 461 consumeStack(obj); 462 } 463 @Override 464 public void visitIFNONNULL(IFNONNULL obj) { 465 466 if (valueNumberDataflow != null) { 467 try { 470 ValueNumberFrame vnaFrame = valueNumberDataflow 471 .getFactAtLocation(getLocation()); 472 if (vnaFrame.isValid()) { 473 instanceOfValueNumber = vnaFrame.getTopValue(); 474 475 instanceOfType = NullType.instance(); 476 instanceOfFollowedByBranch = true; 477 } 478 } catch (DataflowAnalysisException e) { 479 } 481 } 482 483 consumeStack(obj); 484 } 485 @Override 486 public void visitFCMPL(FCMPL obj) { 487 consumeStack(obj); 488 pushValue(Type.INT); 489 } 490 491 @Override 492 public void visitFCMPG(FCMPG obj) { 493 consumeStack(obj); 494 pushValue(Type.INT); 495 } 496 497 @Override 498 public void visitDCMPL(DCMPL obj) { 499 consumeStack(obj); 500 pushValue(Type.INT); 501 } 502 503 @Override 504 public void visitDCMPG(DCMPG obj) { 505 consumeStack(obj); 506 pushValue(Type.INT); 507 } 508 509 @Override 510 public void visitLCMP(LCMP obj) { 511 consumeStack(obj); 512 pushValue(Type.INT); 513 } 514 515 @Override 516 public void visitD2F(D2F obj) { 517 consumeStack(obj); 518 pushValue(Type.FLOAT); 519 } 520 521 @Override 522 public void visitD2I(D2I obj) { 523 consumeStack(obj); 524 pushValue(Type.INT); 525 } 526 527 @Override 528 public void visitD2L(D2L obj) { 529 consumeStack(obj); 530 pushValue(Type.LONG); 531 } 532 533 @Override 534 public void visitF2D(F2D obj) { 535 consumeStack(obj); 536 pushValue(Type.DOUBLE); 537 } 538 539 @Override 540 public void visitF2I(F2I obj) { 541 consumeStack(obj); 542 pushValue(Type.INT); 543 } 544 545 @Override 546 public void visitF2L(F2L obj) { 547 consumeStack(obj); 548 pushValue(Type.LONG); 549 } 550 551 @Override 552 public void visitI2B(I2B obj) { 553 consumeStack(obj); 554 pushValue(Type.BYTE); 555 } 556 557 @Override 558 public void visitI2C(I2C obj) { 559 consumeStack(obj); 560 pushValue(Type.CHAR); 561 } 562 563 @Override 564 public void visitI2D(I2D obj) { 565 consumeStack(obj); 566 pushValue(Type.DOUBLE); 567 } 568 569 @Override 570 public void visitI2F(I2F obj) { 571 consumeStack(obj); 572 pushValue(Type.FLOAT); 573 } 574 575 @Override 576 public void visitI2L(I2L obj) { 577 consumeStack(obj); 578 pushValue(Type.LONG); 579 } 580 581 @Override 582 public void visitI2S(I2S obj) { 583 } 585 @Override 586 public void visitL2D(L2D obj) { 587 consumeStack(obj); 588 pushValue(Type.DOUBLE); 589 } 590 591 @Override 592 public void visitL2F(L2F obj) { 593 consumeStack(obj); 594 pushValue(Type.FLOAT); 595 } 596 597 @Override 598 public void visitL2I(L2I obj) { 599 consumeStack(obj); 600 pushValue(Type.INT); 601 } 602 603 @Override 604 public void visitIAND(IAND obj) { 605 consumeStack(obj); 606 pushValue(Type.INT); 607 } 608 609 @Override 610 public void visitLAND(LAND obj) { 611 consumeStack(obj); 612 pushValue(Type.LONG); 613 } 614 615 @Override 616 public void visitIOR(IOR obj) { 617 consumeStack(obj); 618 pushValue(Type.INT); 619 } 620 621 @Override 622 public void visitLOR(LOR obj) { 623 consumeStack(obj); 624 pushValue(Type.LONG); 625 } 626 627 @Override 628 public void visitIXOR(IXOR obj) { 629 consumeStack(obj); 630 pushValue(Type.INT); 631 } 632 633 @Override 634 public void visitLXOR(LXOR obj) { 635 consumeStack(obj); 636 pushValue(Type.LONG); 637 } 638 639 @Override 640 public void visitISHR(ISHR obj) { 641 consumeStack(obj); 642 pushValue(Type.INT); 643 } 644 645 @Override 646 public void visitIUSHR(IUSHR obj) { 647 consumeStack(obj); 648 pushValue(Type.INT); 649 } 650 651 @Override 652 public void visitLSHR(LSHR obj) { 653 consumeStack(obj); 654 pushValue(Type.LONG); 655 } 656 657 @Override 658 public void visitLUSHR(LUSHR obj) { 659 consumeStack(obj); 660 pushValue(Type.LONG); 661 } 662 663 @Override 664 public void visitISHL(ISHL obj) { 665 consumeStack(obj); 666 pushValue(Type.INT); 667 } 668 669 @Override 670 public void visitLSHL(LSHL obj) { 671 consumeStack(obj); 672 pushValue(Type.LONG); 673 } 674 675 @Override 676 public void visitDADD(DADD obj) { 677 consumeStack(obj); 678 pushValue(Type.DOUBLE); 679 } 680 681 @Override 682 public void visitFADD(FADD obj) { 683 consumeStack(obj); 684 pushValue(Type.FLOAT); 685 } 686 687 @Override 688 public void visitIADD(IADD obj) { 689 consumeStack(obj); 690 pushValue(Type.INT); 691 } 692 693 @Override 694 public void visitLADD(LADD obj) { 695 consumeStack(obj); 696 pushValue(Type.LONG); 697 } 698 699 @Override 700 public void visitDSUB(DSUB obj) { 701 consumeStack(obj); 702 pushValue(Type.DOUBLE); 703 } 704 705 @Override 706 public void visitFSUB(FSUB obj) { 707 consumeStack(obj); 708 pushValue(Type.FLOAT); 709 } 710 711 @Override 712 public void visitISUB(ISUB obj) { 713 consumeStack(obj); 714 pushValue(Type.INT); 715 } 716 717 @Override 718 public void visitLSUB(LSUB obj) { 719 consumeStack(obj); 720 pushValue(Type.LONG); 721 } 722 723 @Override 724 public void visitDMUL(DMUL obj) { 725 consumeStack(obj); 726 pushValue(Type.DOUBLE); 727 } 728 729 @Override 730 public void visitFMUL(FMUL obj) { 731 consumeStack(obj); 732 pushValue(Type.FLOAT); 733 } 734 735 @Override 736 public void visitIMUL(IMUL obj) { 737 consumeStack(obj); 738 pushValue(Type.INT); 739 } 740 741 @Override 742 public void visitLMUL(LMUL obj) { 743 consumeStack(obj); 744 pushValue(Type.LONG); 745 } 746 747 @Override 748 public void visitDDIV(DDIV obj) { 749 consumeStack(obj); 750 pushValue(Type.DOUBLE); 751 } 752 753 @Override 754 public void visitFDIV(FDIV obj) { 755 consumeStack(obj); 756 pushValue(Type.FLOAT); 757 } 758 759 @Override 760 public void visitIDIV(IDIV obj) { 761 consumeStack(obj); 762 pushValue(Type.INT); 763 } 764 765 @Override 766 public void visitLDIV(LDIV obj) { 767 consumeStack(obj); 768 pushValue(Type.LONG); 769 } 770 771 @Override 772 public void visitDREM(DREM obj) { 773 consumeStack(obj); 774 pushValue(Type.DOUBLE); 775 } 776 777 @Override 778 public void visitFREM(FREM obj) { 779 consumeStack(obj); 780 pushValue(Type.FLOAT); 781 } 782 783 @Override 784 public void visitIREM(IREM obj) { 785 consumeStack(obj); 786 pushValue(Type.INT); 787 } 788 789 @Override 790 public void visitLREM(LREM obj) { 791 consumeStack(obj); 792 pushValue(Type.LONG); 793 } 794 795 @Override 796 public void visitIINC(IINC obj) { 797 } 799 @Override 800 public void visitDNEG(DNEG obj) { 801 } 803 @Override 804 public void visitFNEG(FNEG obj) { 805 } 807 @Override 808 public void visitINEG(INEG obj) { 809 consumeStack(obj); 810 pushValue(Type.INT); 811 } 812 813 @Override 814 public void visitLNEG(LNEG obj) { 815 } 817 @Override 818 public void visitARRAYLENGTH(ARRAYLENGTH obj) { 819 consumeStack(obj); 820 pushValue(Type.INT); 821 } 822 823 @Override 824 public void visitAALOAD(AALOAD obj) { 825 TypeFrame frame = getFrame(); 829 try { 830 frame.popValue(); Type arrayType = frame.popValue(); if (arrayType instanceof ArrayType) { 833 ArrayType arr = (ArrayType) arrayType; 834 pushValue(arr.getElementType()); 835 } else { 836 pushValue(TypeFrame.getBottomType()); 837 } 838 } catch (DataflowAnalysisException e) { 839 throw new InvalidBytecodeException("Stack underflow: " + e.getMessage()); 840 } 841 } 842 843 @Override 844 public void visitBALOAD(BALOAD obj) { 845 consumeStack(obj); 846 pushValue(Type.BYTE); 847 } 848 849 @Override 850 public void visitCALOAD(CALOAD obj) { 851 consumeStack(obj); 852 pushValue(Type.CHAR); 853 } 854 855 @Override 856 public void visitDALOAD(DALOAD obj) { 857 consumeStack(obj); 858 pushValue(Type.DOUBLE); 859 } 860 861 @Override 862 public void visitFALOAD(FALOAD obj) { 863 consumeStack(obj); 864 pushValue(Type.FLOAT); 865 } 866 867 @Override 868 public void visitIALOAD(IALOAD obj) { 869 consumeStack(obj); 870 pushValue(Type.INT); 871 } 872 873 @Override 874 public void visitLALOAD(LALOAD obj) { 875 consumeStack(obj); 876 pushValue(Type.LONG); 877 } 878 879 @Override 880 public void visitSALOAD(SALOAD obj) { 881 consumeStack(obj); 882 pushValue(Type.SHORT); 883 } 884 885 887 @Override 888 public void visitNEW(NEW obj) { 889 pushValue(obj.getType(getCPG())); 892 893 setTopOfStackIsExact(); 895 } 896 897 @Override 898 public void visitNEWARRAY(NEWARRAY obj) { 899 consumeStack(obj); 900 Type elementType = obj.getType(); 901 pushValue(elementType); 902 903 setTopOfStackIsExact(); 905 } 906 907 @Override 908 public void visitANEWARRAY(ANEWARRAY obj) { 909 consumeStack(obj); 910 Type elementType = obj.getType(getCPG()); 911 pushValue(new ArrayType(elementType, 1)); 912 913 setTopOfStackIsExact(); 915 } 916 917 @Override 918 public void visitMULTIANEWARRAY(MULTIANEWARRAY obj) { 919 consumeStack(obj); 920 Type elementType = obj.getType(getCPG()); 921 pushValue(elementType); 922 setTopOfStackIsExact(); 924 } 925 926 private void setTopOfStackIsExact() { 927 TypeFrame frame = getFrame(); 928 frame.setExact(frame.getNumSlots() - 1, true); 929 } 930 931 @Override 932 public void visitJSR(JSR obj) { 933 pushValue(ReturnaddressType.NO_TARGET); 934 } 935 936 @Override 937 public void visitJSR_W(JSR_W obj) { 938 pushValue(ReturnaddressType.NO_TARGET); 939 } 940 941 @Override 942 public void visitRET(RET obj) { 943 } 945 @Override 946 public void visitIFEQ(IFEQ obj) { 947 if (lastOpcode == Constants.INSTANCEOF) 948 instanceOfFollowedByBranch = true; 949 super.visitIFEQ(obj); 950 } 951 952 @Override 953 public void visitIFGT(IFGT obj) { 954 if (lastOpcode == Constants.INSTANCEOF) 955 instanceOfFollowedByBranch = true; 956 super.visitIFGT(obj); 957 } 958 959 @Override 960 public void visitIFLE(IFLE obj) { 961 if (lastOpcode == Constants.INSTANCEOF) 962 instanceOfFollowedByBranch = true; 963 super.visitIFLE(obj); 964 } 965 966 @Override 967 public void visitIFNE(IFNE obj) { 968 if (lastOpcode == Constants.INSTANCEOF) 969 instanceOfFollowedByBranch = true; 970 super.visitIFNE(obj); 971 } 972 973 } 974 975 | Popular Tags |