1 17 package org.apache.bcel.verifier.statics; 18 19 20 import org.apache.bcel.Constants; 21 import org.apache.bcel.Repository; 22 import org.apache.bcel.classfile.Attribute; 23 import org.apache.bcel.classfile.Code; 24 import org.apache.bcel.classfile.CodeException; 25 import org.apache.bcel.classfile.Constant; 26 import org.apache.bcel.classfile.ConstantClass; 27 import org.apache.bcel.classfile.ConstantDouble; 28 import org.apache.bcel.classfile.ConstantFieldref; 29 import org.apache.bcel.classfile.ConstantFloat; 30 import org.apache.bcel.classfile.ConstantInteger; 31 import org.apache.bcel.classfile.ConstantInterfaceMethodref; 32 import org.apache.bcel.classfile.ConstantLong; 33 import org.apache.bcel.classfile.ConstantMethodref; 34 import org.apache.bcel.classfile.ConstantNameAndType; 35 import org.apache.bcel.classfile.ConstantString; 36 import org.apache.bcel.classfile.ConstantUtf8; 37 import org.apache.bcel.classfile.Field; 38 import org.apache.bcel.classfile.JavaClass; 39 import org.apache.bcel.classfile.LineNumber; 40 import org.apache.bcel.classfile.LineNumberTable; 41 import org.apache.bcel.classfile.LocalVariable; 42 import org.apache.bcel.classfile.LocalVariableTable; 43 import org.apache.bcel.classfile.Method; 44 import org.apache.bcel.generic.ALOAD; 45 import org.apache.bcel.generic.ANEWARRAY; 46 import org.apache.bcel.generic.ASTORE; 47 import org.apache.bcel.generic.ATHROW; 48 import org.apache.bcel.generic.ArrayType; 49 import org.apache.bcel.generic.BREAKPOINT; 50 import org.apache.bcel.generic.CHECKCAST; 51 import org.apache.bcel.generic.ConstantPoolGen; 52 import org.apache.bcel.generic.DLOAD; 53 import org.apache.bcel.generic.DSTORE; 54 import org.apache.bcel.generic.FLOAD; 55 import org.apache.bcel.generic.FSTORE; 56 import org.apache.bcel.generic.FieldInstruction; 57 import org.apache.bcel.generic.GETSTATIC; 58 import org.apache.bcel.generic.GotoInstruction; 59 import org.apache.bcel.generic.IINC; 60 import org.apache.bcel.generic.ILOAD; 61 import org.apache.bcel.generic.IMPDEP1; 62 import org.apache.bcel.generic.IMPDEP2; 63 import org.apache.bcel.generic.INSTANCEOF; 64 import org.apache.bcel.generic.INVOKEINTERFACE; 65 import org.apache.bcel.generic.INVOKESPECIAL; 66 import org.apache.bcel.generic.INVOKESTATIC; 67 import org.apache.bcel.generic.INVOKEVIRTUAL; 68 import org.apache.bcel.generic.ISTORE; 69 import org.apache.bcel.generic.Instruction; 70 import org.apache.bcel.generic.InstructionHandle; 71 import org.apache.bcel.generic.InstructionList; 72 import org.apache.bcel.generic.InvokeInstruction; 73 import org.apache.bcel.generic.JsrInstruction; 74 import org.apache.bcel.generic.LDC; 75 import org.apache.bcel.generic.LDC2_W; 76 import org.apache.bcel.generic.LLOAD; 77 import org.apache.bcel.generic.LOOKUPSWITCH; 78 import org.apache.bcel.generic.LSTORE; 79 import org.apache.bcel.generic.LoadClass; 80 import org.apache.bcel.generic.MULTIANEWARRAY; 81 import org.apache.bcel.generic.NEW; 82 import org.apache.bcel.generic.NEWARRAY; 83 import org.apache.bcel.generic.ObjectType; 84 import org.apache.bcel.generic.PUTSTATIC; 85 import org.apache.bcel.generic.RET; 86 import org.apache.bcel.generic.ReturnInstruction; 87 import org.apache.bcel.generic.TABLESWITCH; 88 import org.apache.bcel.generic.Type; 89 import org.apache.bcel.verifier.PassVerifier; 90 import org.apache.bcel.verifier.VerificationResult; 91 import org.apache.bcel.verifier.Verifier; 92 import org.apache.bcel.verifier.VerifierFactory; 93 import org.apache.bcel.verifier.exc.AssertionViolatedException; 94 import org.apache.bcel.verifier.exc.ClassConstraintException; 95 import org.apache.bcel.verifier.exc.InvalidMethodException; 96 import org.apache.bcel.verifier.exc.StaticCodeConstraintException; 97 import org.apache.bcel.verifier.exc.StaticCodeInstructionConstraintException; 98 import org.apache.bcel.verifier.exc.StaticCodeInstructionOperandConstraintException; 99 100 111 public final class Pass3aVerifier extends PassVerifier{ 112 113 114 private Verifier myOwner; 115 116 121 private int method_no; 122 123 124 InstructionList instructionList; 125 126 Code code; 127 128 129 public Pass3aVerifier(Verifier owner, int method_no){ 130 myOwner = owner; 131 this.method_no = method_no; 132 } 133 134 151 public VerificationResult do_verify(){ 152 try { 153 if (myOwner.doPass2().equals(VerificationResult.VR_OK)){ 154 JavaClass jc = Repository.lookupClass(myOwner.getClassName()); 157 Method[] methods = jc.getMethods(); 158 if (method_no >= methods.length){ 159 throw new InvalidMethodException("METHOD DOES NOT EXIST!"); 160 } 161 Method method = methods[method_no]; 162 code = method.getCode(); 163 164 if ( method.isAbstract() || method.isNative() ){ return VerificationResult.VR_OK; 167 } 168 169 try{ 179 instructionList = new InstructionList(method.getCode().getCode()); 180 } 181 catch(RuntimeException re){ 182 return new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Bad bytecode in the code array of the Code attribute of method '"+method+"'."); 183 } 184 185 instructionList.setPositions(true); 186 187 VerificationResult vr = VerificationResult.VR_OK; try{ 190 delayedPass2Checks(); 191 } 192 catch(ClassConstraintException cce){ 193 vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, cce.getMessage()); 194 return vr; 195 } 196 try{ 197 pass3StaticInstructionChecks(); 198 pass3StaticInstructionOperandsChecks(); 199 } 200 catch(StaticCodeConstraintException scce){ 201 vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, scce.getMessage()); 202 } 203 catch(ClassCastException cce){ 204 vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Class Cast Exception: " + cce.getMessage()); 205 } 206 return vr; 207 } 208 else{ return VerificationResult.VR_NOTYET; 210 } 211 } catch (ClassNotFoundException e) { 212 throw new AssertionViolatedException("Missing class: " + e.toString()); 214 } 215 } 216 217 226 private void delayedPass2Checks(){ 227 228 int[] instructionPositions = instructionList.getInstructionPositions(); 229 int codeLength = code.getCode().length; 230 231 LineNumberTable lnt = code.getLineNumberTable(); 235 if (lnt != null){ 236 LineNumber[] lineNumbers = lnt.getLineNumberTable(); 237 IntList offsets = new IntList(); 238 lineNumber_loop: for (int i=0; i < lineNumbers.length; i++){ for (int j=0; j < instructionPositions.length; j++){ 240 int offset = lineNumbers[i].getStartPC(); 242 if (instructionPositions[j] == offset){ 243 if (offsets.contains(offset)){ 244 addMessage("LineNumberTable attribute '"+code.getLineNumberTable()+"' refers to the same code offset ('"+offset+"') more than once which is violating the semantics [but is sometimes produced by IBM's 'jikes' compiler]."); 245 } 246 else{ 247 offsets.add(offset); 248 } 249 continue lineNumber_loop; 250 } 251 } 252 throw new ClassConstraintException("Code attribute '"+code+"' has a LineNumberTable attribute '"+code.getLineNumberTable()+"' referring to a code offset ('"+lineNumbers[i].getStartPC()+"') that does not exist."); 253 } 254 } 255 256 261 Attribute[] atts = code.getAttributes(); 262 for (int a=0; a<atts.length; a++){ 263 if (atts[a] instanceof LocalVariableTable){ 264 LocalVariableTable lvt = (LocalVariableTable) atts[a]; 265 if (lvt != null){ 266 LocalVariable[] localVariables = lvt.getLocalVariableTable(); 267 for (int i=0; i<localVariables.length; i++){ 268 int startpc = localVariables[i].getStartPC(); 269 int length = localVariables[i].getLength(); 270 271 if (!contains(instructionPositions, startpc)){ 272 throw new ClassConstraintException("Code attribute '"+code+"' has a LocalVariableTable attribute '"+code.getLocalVariableTable()+"' referring to a code offset ('"+startpc+"') that does not exist."); 273 } 274 if ( (!contains(instructionPositions, startpc+length)) && (startpc+length != codeLength) ){ 275 throw new ClassConstraintException("Code attribute '"+code+"' has a LocalVariableTable attribute '"+code.getLocalVariableTable()+"' referring to a code offset start_pc+length ('"+(startpc+length)+"') that does not exist."); 276 } 277 } 278 } 279 } 280 } 281 282 CodeException[] exceptionTable = code.getExceptionTable(); 289 for (int i=0; i<exceptionTable.length; i++){ 290 int startpc = exceptionTable[i].getStartPC(); 291 int endpc = exceptionTable[i].getEndPC(); 292 int handlerpc = exceptionTable[i].getHandlerPC(); 293 if (startpc >= endpc){ 294 throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has its start_pc ('"+startpc+"') not smaller than its end_pc ('"+endpc+"')."); 295 } 296 if (!contains(instructionPositions, startpc)){ 297 throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has a non-existant bytecode offset as its start_pc ('"+startpc+"')."); 298 } 299 if ( (!contains(instructionPositions, endpc)) && (endpc != codeLength)){ 300 throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has a non-existant bytecode offset as its end_pc ('"+startpc+"') [that is also not equal to code_length ('"+codeLength+"')]."); 301 } 302 if (!contains(instructionPositions, handlerpc)){ 303 throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has a non-existant bytecode offset as its handler_pc ('"+handlerpc+"')."); 304 } 305 } 306 } 307 308 315 private void pass3StaticInstructionChecks(){ 316 317 322 if (! (code.getCode().length < 65536)){ throw new StaticCodeInstructionConstraintException("Code array in code attribute '"+code+"' too big: must be smaller than 65536 bytes."); 324 } 325 326 328 331 333 338 InstructionHandle ih = instructionList.getStart(); 342 while (ih != null){ 343 Instruction i = ih.getInstruction(); 344 if (i instanceof IMPDEP1){ 345 throw new StaticCodeInstructionConstraintException("IMPDEP1 must not be in the code, it is an illegal instruction for _internal_ JVM use!"); 346 } 347 if (i instanceof IMPDEP2){ 348 throw new StaticCodeInstructionConstraintException("IMPDEP2 must not be in the code, it is an illegal instruction for _internal_ JVM use!"); 349 } 350 if (i instanceof BREAKPOINT){ 351 throw new StaticCodeInstructionConstraintException("BREAKPOINT must not be in the code, it is an illegal instruction for _internal_ JVM use!"); 352 } 353 ih = ih.getNext(); 354 } 355 356 Instruction last = instructionList.getEnd().getInstruction(); 361 if (! ((last instanceof ReturnInstruction) || 362 (last instanceof RET) || 363 (last instanceof GotoInstruction) || 364 (last instanceof ATHROW) )) { 365 throw new StaticCodeInstructionConstraintException("Execution must not fall off the bottom of the code array. This constraint is enforced statically as some existing verifiers do - so it may be a false alarm if the last instruction is not reachable."); 366 } 367 } 368 369 378 private void pass3StaticInstructionOperandsChecks(){ 379 try { 380 389 391 ConstantPoolGen cpg = new ConstantPoolGen(Repository.lookupClass(myOwner.getClassName()).getConstantPool()); 392 InstOperandConstraintVisitor v = new InstOperandConstraintVisitor(cpg); 393 394 InstructionHandle ih = instructionList.getStart(); 396 while (ih != null){ 397 Instruction i = ih.getInstruction(); 398 399 if (i instanceof JsrInstruction){ 401 InstructionHandle target = ((JsrInstruction) i).getTarget(); 402 if (target == instructionList.getStart()){ 403 throw new StaticCodeInstructionOperandConstraintException("Due to JustIce's clear definition of subroutines, no JSR or JSR_W may have a top-level instruction (such as the very first instruction, which is targeted by instruction '"+ih+"' as its target."); 404 } 405 if (!(target.getInstruction() instanceof ASTORE)){ 406 throw new StaticCodeInstructionOperandConstraintException("Due to JustIce's clear definition of subroutines, no JSR or JSR_W may target anything else than an ASTORE instruction. Instruction '"+ih+"' targets '"+target+"'."); 407 } 408 } 409 410 ih.accept(v); 412 413 ih = ih.getNext(); 414 } 415 416 } catch (ClassNotFoundException e) { 417 throw new AssertionViolatedException("Missing class: " + e.toString()); 419 } 420 } 421 422 423 private static boolean contains(int[] ints, int i){ 424 for (int j=0; j<ints.length; j++){ 425 if (ints[j]==i) { 426 return true; 427 } 428 } 429 return false; 430 } 431 432 433 public int getMethodNo(){ 434 return method_no; 435 } 436 437 441 private class InstOperandConstraintVisitor extends org.apache.bcel.generic.EmptyVisitor{ 442 443 private ConstantPoolGen cpg; 444 445 446 InstOperandConstraintVisitor(ConstantPoolGen cpg){ 447 this.cpg = cpg; 448 } 449 450 454 private int max_locals(){ 455 try { 456 return Repository.lookupClass(myOwner.getClassName()).getMethods()[method_no].getCode().getMaxLocals(); 457 } catch (ClassNotFoundException e) { 458 throw new AssertionViolatedException("Missing class: " + e.toString()); 460 } 461 } 462 463 466 private void constraintViolated(Instruction i, String message) { 467 throw new StaticCodeInstructionOperandConstraintException("Instruction "+i+" constraint violated: "+message); 468 } 469 470 474 private void indexValid(Instruction i, int idx){ 475 if (idx < 0 || idx >= cpg.getSize()){ 476 constraintViolated(i, "Illegal constant pool index '"+idx+"'."); 477 } 478 } 479 480 487 public void visitLoadClass(LoadClass o){ 488 ObjectType t = o.getLoadClassType(cpg); 489 if (t != null){ Verifier v = VerifierFactory.getVerifier(t.getClassName()); 491 VerificationResult vr = v.doPass1(); 492 if (vr.getStatus() != VerificationResult.VERIFIED_OK){ 493 constraintViolated((Instruction) o, "Class '"+o.getLoadClassType(cpg).getClassName()+"' is referenced, but cannot be loaded: '"+vr+"'."); 494 } 495 } 496 } 497 498 501 503 505 506 public void visitLDC(LDC o){ 508 indexValid(o, o.getIndex()); 509 Constant c = cpg.getConstant(o.getIndex()); 510 if (c instanceof ConstantClass){ 511 addMessage("Operand of LDC or LDC_W is CONSTANT_Class '"+c+"' - this is only supported in JDK 1.5 and higher."); 512 } 513 else{ 514 if (! ( (c instanceof ConstantInteger) || 515 (c instanceof ConstantFloat) || 516 (c instanceof ConstantString) ) ){ 517 constraintViolated(o, "Operand of LDC or LDC_W must be one of CONSTANT_Integer, CONSTANT_Float or CONSTANT_String, but is '"+c+"'."); 518 } 519 } 520 } 521 522 523 public void visitLDC2_W(LDC2_W o){ 525 indexValid(o, o.getIndex()); 526 Constant c = cpg.getConstant(o.getIndex()); 527 if (! ( (c instanceof ConstantLong) || 528 (c instanceof ConstantDouble) ) ){ 529 constraintViolated(o, "Operand of LDC2_W must be CONSTANT_Long or CONSTANT_Double, but is '"+c+"'."); 530 } 531 try{ 532 indexValid(o, o.getIndex()+1); 533 } 534 catch(StaticCodeInstructionOperandConstraintException e){ 535 throw new AssertionViolatedException("OOPS: Does not BCEL handle that? LDC2_W operand has a problem."); 536 } 537 } 538 539 540 public void visitFieldInstruction(FieldInstruction o){ 542 try { 543 indexValid(o, o.getIndex()); 544 Constant c = cpg.getConstant(o.getIndex()); 545 if (! (c instanceof ConstantFieldref)){ 546 constraintViolated(o, "Indexing a constant that's not a CONSTANT_Fieldref but a '"+c+"'."); 547 } 548 549 String field_name = o.getFieldName(cpg); 550 551 JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName()); 552 Field[] fields = jc.getFields(); 553 Field f = null; 554 for (int i=0; i<fields.length; i++){ 555 if (fields[i].getName().equals(field_name)){ 556 Type f_type = Type.getType(fields[i].getSignature()); 557 Type o_type = o.getType(cpg); 558 561 if (f_type.equals(o_type)){ 562 f = fields[i]; 563 break; 564 } 565 } 566 } 567 if (f == null){ 568 JavaClass[] superclasses = jc.getSuperClasses(); 569 outer: 570 for (int j=0; j<superclasses.length; j++){ 571 fields = superclasses[j].getFields(); 572 for (int i=0; i<fields.length; i++){ 573 if (fields[i].getName().equals(field_name)){ 574 Type f_type = Type.getType(fields[i].getSignature()); 575 Type o_type = o.getType(cpg); 576 if (f_type.equals(o_type)){ 577 f = fields[i]; 578 if ((f.getAccessFlags() & (Constants.ACC_PUBLIC | Constants.ACC_PROTECTED)) == 0) { 579 f = null; 580 } 581 break outer; 582 } 583 } 584 } 585 } 586 if (f == null) { 587 constraintViolated(o, "Referenced field '"+field_name+"' does not exist in class '"+jc.getClassName()+"'."); 588 } 589 } 590 else{ 591 593 Type f_type = Type.getType(f.getSignature()); 594 Type o_type = o.getType(cpg); 595 596 602 603 } 604 } catch (ClassNotFoundException e) { 605 throw new AssertionViolatedException("Missing class: " + e.toString()); 607 } 608 } 609 610 611 public void visitInvokeInstruction(InvokeInstruction o){ 612 indexValid(o, o.getIndex()); 613 if ( (o instanceof INVOKEVIRTUAL) || 614 (o instanceof INVOKESPECIAL) || 615 (o instanceof INVOKESTATIC) ){ 616 Constant c = cpg.getConstant(o.getIndex()); 617 if (! (c instanceof ConstantMethodref)){ 618 constraintViolated(o, "Indexing a constant that's not a CONSTANT_Methodref but a '"+c+"'."); 619 } 620 else{ 621 ConstantNameAndType cnat = (ConstantNameAndType) (cpg.getConstant(((ConstantMethodref) c).getNameAndTypeIndex())); 623 ConstantUtf8 cutf8 = (ConstantUtf8) (cpg.getConstant(cnat.getNameIndex())); 624 if (cutf8.getBytes().equals(Constants.CONSTRUCTOR_NAME) && (!(o instanceof INVOKESPECIAL)) ){ 625 constraintViolated(o, "Only INVOKESPECIAL is allowed to invoke instance initialization methods."); 626 } 627 if ( (! (cutf8.getBytes().equals(Constants.CONSTRUCTOR_NAME)) ) && (cutf8.getBytes().startsWith("<")) ){ 628 constraintViolated(o, "No method with a name beginning with '<' other than the instance initialization methods may be called by the method invocation instructions."); 629 } 630 } 631 } 632 else{ Constant c = cpg.getConstant(o.getIndex()); 634 if (! (c instanceof ConstantInterfaceMethodref)){ 635 constraintViolated(o, "Indexing a constant that's not a CONSTANT_InterfaceMethodref but a '"+c+"'."); 636 } 637 642 ConstantNameAndType cnat = (ConstantNameAndType) (cpg.getConstant(((ConstantInterfaceMethodref)c).getNameAndTypeIndex())); 644 String name = ((ConstantUtf8) (cpg.getConstant(cnat.getNameIndex()))).getBytes(); 645 if (name.equals(Constants.CONSTRUCTOR_NAME)){ 646 constraintViolated(o, "Method to invoke must not be '"+Constants.CONSTRUCTOR_NAME+"'."); 647 } 648 if (name.equals(Constants.STATIC_INITIALIZER_NAME)){ 649 constraintViolated(o, "Method to invoke must not be '"+Constants.STATIC_INITIALIZER_NAME+"'."); 650 } 651 } 652 653 655 Type t = o.getReturnType(cpg); 656 if (t instanceof ArrayType){ 657 t = ((ArrayType) t).getBasicType(); 658 } 659 if (t instanceof ObjectType){ 660 Verifier v = VerifierFactory.getVerifier(((ObjectType) t).getClassName()); 661 VerificationResult vr = v.doPass2(); 662 if (vr.getStatus() != VerificationResult.VERIFIED_OK){ 663 constraintViolated(o, "Return type class/interface could not be verified successfully: '"+vr.getMessage()+"'."); 664 } 665 } 666 667 Type[] ts = o.getArgumentTypes(cpg); 668 for (int i=0; i<ts.length; i++){ 669 t = ts[i]; 670 if (t instanceof ArrayType){ 671 t = ((ArrayType) t).getBasicType(); 672 } 673 if (t instanceof ObjectType){ 674 Verifier v = VerifierFactory.getVerifier(((ObjectType) t).getClassName()); 675 VerificationResult vr = v.doPass2(); 676 if (vr.getStatus() != VerificationResult.VERIFIED_OK){ 677 constraintViolated(o, "Argument type class/interface could not be verified successfully: '"+vr.getMessage()+"'."); 678 } 679 } 680 } 681 682 } 683 684 685 public void visitINSTANCEOF(INSTANCEOF o){ 686 indexValid(o, o.getIndex()); 687 Constant c = cpg.getConstant(o.getIndex()); 688 if (! (c instanceof ConstantClass)){ 689 constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'."); 690 } 691 } 692 693 694 public void visitCHECKCAST(CHECKCAST o){ 695 indexValid(o, o.getIndex()); 696 Constant c = cpg.getConstant(o.getIndex()); 697 if (! (c instanceof ConstantClass)){ 698 constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'."); 699 } 700 } 701 702 703 public void visitNEW(NEW o){ 704 indexValid(o, o.getIndex()); 705 Constant c = cpg.getConstant(o.getIndex()); 706 if (! (c instanceof ConstantClass)){ 707 constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'."); 708 } 709 else{ 710 ConstantUtf8 cutf8 = (ConstantUtf8) (cpg.getConstant( ((ConstantClass) c).getNameIndex() )); 711 Type t = Type.getType("L"+cutf8.getBytes()+";"); 712 if (t instanceof ArrayType){ 713 constraintViolated(o, "NEW must not be used to create an array."); 714 } 715 } 716 717 } 718 719 720 public void visitMULTIANEWARRAY(MULTIANEWARRAY o){ 721 indexValid(o, o.getIndex()); 722 Constant c = cpg.getConstant(o.getIndex()); 723 if (! (c instanceof ConstantClass)){ 724 constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'."); 725 } 726 int dimensions2create = o.getDimensions(); 727 if (dimensions2create < 1){ 728 constraintViolated(o, "Number of dimensions to create must be greater than zero."); 729 } 730 Type t = o.getType(cpg); 731 if (t instanceof ArrayType){ 732 int dimensions = ((ArrayType) t).getDimensions(); 733 if (dimensions < dimensions2create){ 734 constraintViolated(o, "Not allowed to create array with more dimensions ('+dimensions2create+') than the one referenced by the CONSTANT_Class '"+t+"'."); 735 } 736 } 737 else{ 738 constraintViolated(o, "Expecting a CONSTANT_Class referencing an array type. [Constraint not found in The Java Virtual Machine Specification, Second Edition, 4.8.1]"); 739 } 740 } 741 742 743 public void visitANEWARRAY(ANEWARRAY o){ 744 indexValid(o, o.getIndex()); 745 Constant c = cpg.getConstant(o.getIndex()); 746 if (! (c instanceof ConstantClass)){ 747 constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'."); 748 } 749 Type t = o.getType(cpg); 750 if (t instanceof ArrayType){ 751 int dimensions = ((ArrayType) t).getDimensions(); 752 if (dimensions >= 255){ 753 constraintViolated(o, "Not allowed to create an array with more than 255 dimensions."); 754 } 755 } 756 } 757 758 759 public void visitNEWARRAY(NEWARRAY o){ 760 byte t = o.getTypecode(); 761 if (! ( (t == Constants.T_BOOLEAN) || 762 (t == Constants.T_CHAR) || 763 (t == Constants.T_FLOAT) || 764 (t == Constants.T_DOUBLE) || 765 (t == Constants.T_BYTE) || 766 (t == Constants.T_SHORT) || 767 (t == Constants.T_INT) || 768 (t == Constants.T_LONG) ) ){ 769 constraintViolated(o, "Illegal type code '+t+' for 'atype' operand."); 770 } 771 } 772 773 774 public void visitILOAD(ILOAD o){ 775 int idx = o.getIndex(); 776 if (idx < 0){ 777 constraintViolated(o, "Index '"+idx+"' must be non-negative."); 778 } 779 else{ 780 int maxminus1 = max_locals()-1; 781 if (idx > maxminus1){ 782 constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'."); 783 } 784 } 785 } 786 787 788 public void visitFLOAD(FLOAD o){ 789 int idx = o.getIndex(); 790 if (idx < 0){ 791 constraintViolated(o, "Index '"+idx+"' must be non-negative."); 792 } 793 else{ 794 int maxminus1 = max_locals()-1; 795 if (idx > maxminus1){ 796 constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'."); 797 } 798 } 799 } 800 801 802 public void visitALOAD(ALOAD o){ 803 int idx = o.getIndex(); 804 if (idx < 0){ 805 constraintViolated(o, "Index '"+idx+"' must be non-negative."); 806 } 807 else{ 808 int maxminus1 = max_locals()-1; 809 if (idx > maxminus1){ 810 constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'."); 811 } 812 } 813 } 814 815 816 public void visitISTORE(ISTORE o){ 817 int idx = o.getIndex(); 818 if (idx < 0){ 819 constraintViolated(o, "Index '"+idx+"' must be non-negative."); 820 } 821 else{ 822 int maxminus1 = max_locals()-1; 823 if (idx > maxminus1){ 824 constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'."); 825 } 826 } 827 } 828 829 830 public void visitFSTORE(FSTORE o){ 831 int idx = o.getIndex(); 832 if (idx < 0){ 833 constraintViolated(o, "Index '"+idx+"' must be non-negative."); 834 } 835 else{ 836 int maxminus1 = max_locals()-1; 837 if (idx > maxminus1){ 838 constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'."); 839 } 840 } 841 } 842 843 844 public void visitASTORE(ASTORE o){ 845 int idx = o.getIndex(); 846 if (idx < 0){ 847 constraintViolated(o, "Index '"+idx+"' must be non-negative."); 848 } 849 else{ 850 int maxminus1 = max_locals()-1; 851 if (idx > maxminus1){ 852 constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'."); 853 } 854 } 855 } 856 857 858 public void visitIINC(IINC o){ 859 int idx = o.getIndex(); 860 if (idx < 0){ 861 constraintViolated(o, "Index '"+idx+"' must be non-negative."); 862 } 863 else{ 864 int maxminus1 = max_locals()-1; 865 if (idx > maxminus1){ 866 constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'."); 867 } 868 } 869 } 870 871 872 public void visitRET(RET o){ 873 int idx = o.getIndex(); 874 if (idx < 0){ 875 constraintViolated(o, "Index '"+idx+"' must be non-negative."); 876 } 877 else{ 878 int maxminus1 = max_locals()-1; 879 if (idx > maxminus1){ 880 constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'."); 881 } 882 } 883 } 884 885 886 public void visitLLOAD(LLOAD o){ 887 int idx = o.getIndex(); 888 if (idx < 0){ 889 constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]"); 890 } 891 else{ 892 int maxminus2 = max_locals()-2; 893 if (idx > maxminus2){ 894 constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'."); 895 } 896 } 897 } 898 899 900 public void visitDLOAD(DLOAD o){ 901 int idx = o.getIndex(); 902 if (idx < 0){ 903 constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]"); 904 } 905 else{ 906 int maxminus2 = max_locals()-2; 907 if (idx > maxminus2){ 908 constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'."); 909 } 910 } 911 } 912 913 914 public void visitLSTORE(LSTORE o){ 915 int idx = o.getIndex(); 916 if (idx < 0){ 917 constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]"); 918 } 919 else{ 920 int maxminus2 = max_locals()-2; 921 if (idx > maxminus2){ 922 constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'."); 923 } 924 } 925 } 926 927 928 public void visitDSTORE(DSTORE o){ 929 int idx = o.getIndex(); 930 if (idx < 0){ 931 constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]"); 932 } 933 else{ 934 int maxminus2 = max_locals()-2; 935 if (idx > maxminus2){ 936 constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'."); 937 } 938 } 939 } 940 941 942 public void visitLOOKUPSWITCH(LOOKUPSWITCH o){ 943 int[] matchs = o.getMatchs(); 944 int max = Integer.MIN_VALUE; 945 for (int i=0; i<matchs.length; i++){ 946 if (matchs[i] == max && i != 0){ 947 constraintViolated(o, "Match '"+matchs[i]+"' occurs more than once."); 948 } 949 if (matchs[i] < max){ 950 constraintViolated(o, "Lookup table must be sorted but isn't."); 951 } 952 else{ 953 max = matchs[i]; 954 } 955 } 956 } 957 958 959 public void visitTABLESWITCH(TABLESWITCH o){ 960 } 963 964 965 public void visitPUTSTATIC(PUTSTATIC o){ 966 try { 967 String field_name = o.getFieldName(cpg); 968 JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName()); 969 Field[] fields = jc.getFields(); 970 Field f = null; 971 for (int i=0; i<fields.length; i++){ 972 if (fields[i].getName().equals(field_name)){ 973 f = fields[i]; 974 break; 975 } 976 } 977 if (f == null){ 978 throw new AssertionViolatedException("Field not found?!?"); 979 } 980 981 if (f.isFinal()){ 982 if (!(myOwner.getClassName().equals(o.getClassType(cpg).getClassName()))){ 983 constraintViolated(o, "Referenced field '"+f+"' is final and must therefore be declared in the current class '"+myOwner.getClassName()+"' which is not the case: it is declared in '"+o.getClassType(cpg).getClassName()+"'."); 984 } 985 } 986 987 if (! (f.isStatic())){ 988 constraintViolated(o, "Referenced field '"+f+"' is not static which it should be."); 989 } 990 991 String meth_name = Repository.lookupClass(myOwner.getClassName()).getMethods()[method_no].getName(); 992 993 if ((!(jc.isClass())) && (!(meth_name.equals(Constants.STATIC_INITIALIZER_NAME)))){ 995 constraintViolated(o, "Interface field '"+f+"' must be set in a '"+Constants.STATIC_INITIALIZER_NAME+"' method."); 996 } 997 } catch (ClassNotFoundException e) { 998 throw new AssertionViolatedException("Missing class: " + e.toString()); 1000 } 1001 } 1002 1003 1004 public void visitGETSTATIC(GETSTATIC o){ 1005 try { 1006 String field_name = o.getFieldName(cpg); 1007 JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName()); 1008 Field[] fields = jc.getFields(); 1009 Field f = null; 1010 for (int i=0; i<fields.length; i++){ 1011 if (fields[i].getName().equals(field_name)){ 1012 f = fields[i]; 1013 break; 1014 } 1015 } 1016 if (f == null){ 1017 throw new AssertionViolatedException("Field not found?!?"); 1018 } 1019 1020 if (! (f.isStatic())){ 1021 constraintViolated(o, "Referenced field '"+f+"' is not static which it should be."); 1022 } 1023 } catch (ClassNotFoundException e) { 1024 throw new AssertionViolatedException("Missing class: " + e.toString()); 1026 } 1027 } 1028 1029 1030 1034 1035 1039 1040 public void visitINVOKEINTERFACE(INVOKEINTERFACE o){ 1041 try { 1042 String classname = o.getClassName(cpg); 1047 JavaClass jc = Repository.lookupClass(classname); 1048 Method[] ms = jc.getMethods(); 1049 Method m = null; 1050 for (int i=0; i<ms.length; i++){ 1051 if ( (ms[i].getName().equals(o.getMethodName(cpg))) && 1052 (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) && 1053 (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){ 1054 m = ms[i]; 1055 break; 1056 } 1057 } 1058 if (m == null){ 1059 constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature '"+o.getSignature(cpg)+"' not found in class '"+jc.getClassName()+"'. The native verifier does allow the method to be declared in some superinterface, which the Java Virtual Machine Specification, Second Edition does not."); 1060 } 1061 if (jc.isClass()){ 1062 constraintViolated(o, "Referenced class '"+jc.getClassName()+"' is a class, but not an interface as expected."); 1063 } 1064 } catch (ClassNotFoundException e) { 1065 throw new AssertionViolatedException("Missing class: " + e.toString()); 1067 } 1068 } 1069 1070 1071 public void visitINVOKESPECIAL(INVOKESPECIAL o){ 1072 try { 1073 String classname = o.getClassName(cpg); 1078 JavaClass jc = Repository.lookupClass(classname); 1079 Method[] ms = jc.getMethods(); 1080 Method m = null; 1081 for (int i=0; i<ms.length; i++){ 1082 if ( (ms[i].getName().equals(o.getMethodName(cpg))) && 1083 (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) && 1084 (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){ 1085 m = ms[i]; 1086 break; 1087 } 1088 } 1089 if (m == null){ 1090 constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature '"+o.getSignature(cpg)+"' not found in class '"+jc.getClassName()+"'. The native verifier does allow the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not."); 1091 } 1092 1093 JavaClass current = Repository.lookupClass(myOwner.getClassName()); 1094 if (current.isSuper()){ 1095 1096 if ((Repository.instanceOf( current, jc )) && (!current.equals(jc))){ 1097 1098 if (! (o.getMethodName(cpg).equals(Constants.CONSTRUCTOR_NAME) )){ 1099 1101 int supidx = -1; 1102 1103 Method meth = null; 1104 while (supidx != 0){ 1105 supidx = current.getSuperclassNameIndex(); 1106 current = Repository.lookupClass(current.getSuperclassName()); 1107 1108 Method[] meths = current.getMethods(); 1109 for (int i=0; i<meths.length; i++){ 1110 if ( (meths[i].getName().equals(o.getMethodName(cpg))) && 1111 (Type.getReturnType(meths[i].getSignature()).equals(o.getReturnType(cpg))) && 1112 (objarrayequals(Type.getArgumentTypes(meths[i].getSignature()), o.getArgumentTypes(cpg))) ){ 1113 meth = meths[i]; 1114 break; 1115 } 1116 } 1117 if (meth != null) { 1118 break; 1119 } 1120 } 1121 if (meth == null){ 1122 constraintViolated(o, "ACC_SUPER special lookup procedure not successful: method '"+o.getMethodName(cpg)+"' with proper signature not declared in superclass hierarchy."); 1123 } 1124 } 1125 } 1126 } 1127 1128 } catch (ClassNotFoundException e) { 1129 throw new AssertionViolatedException("Missing class: " + e.toString()); 1131 } 1132 1133 } 1134 1135 1136 public void visitINVOKESTATIC(INVOKESTATIC o){ 1137 try { 1138 String classname = o.getClassName(cpg); 1143 JavaClass jc = Repository.lookupClass(classname); 1144 Method[] ms = jc.getMethods(); 1145 Method m = null; 1146 for (int i=0; i<ms.length; i++){ 1147 if ( (ms[i].getName().equals(o.getMethodName(cpg))) && 1148 (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) && 1149 (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){ 1150 m = ms[i]; 1151 break; 1152 } 1153 } 1154 if (m == null){ 1155 constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature '"+o.getSignature(cpg) +"' not found in class '"+jc.getClassName()+"'. The native verifier possibly allows the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not."); 1156 } else if (! (m.isStatic())){ constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' has ACC_STATIC unset."); 1158 } 1159 1160 } catch (ClassNotFoundException e) { 1161 throw new AssertionViolatedException("Missing class: " + e.toString()); 1163 } 1164 } 1165 1166 1167 1168 public void visitINVOKEVIRTUAL(INVOKEVIRTUAL o){ 1169 try { 1170 String classname = o.getClassName(cpg); 1175 JavaClass jc = Repository.lookupClass(classname); 1176 Method[] ms = jc.getMethods(); 1177 Method m = null; 1178 for (int i=0; i<ms.length; i++){ 1179 if ( (ms[i].getName().equals(o.getMethodName(cpg))) && 1180 (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) && 1181 (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){ 1182 m = ms[i]; 1183 break; 1184 } 1185 } 1186 if (m == null){ 1187 constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature '"+o.getSignature(cpg)+"' not found in class '"+jc.getClassName()+"'. The native verifier does allow the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not."); 1188 } 1189 if (! (jc.isClass())){ 1190 constraintViolated(o, "Referenced class '"+jc.getClassName()+"' is an interface, but not a class as expected."); 1191 } 1192 1193 } catch (ClassNotFoundException e) { 1194 throw new AssertionViolatedException("Missing class: " + e.toString()); 1196 } 1197 } 1198 1199 1200 1202 1207 private boolean objarrayequals(Object [] o, Object [] p){ 1208 if (o.length != p.length){ 1209 return false; 1210 } 1211 1212 for (int i=0; i<o.length; i++){ 1213 if (! (o[i].equals(p[i])) ){ 1214 return false; 1215 } 1216 } 1217 1218 return true; 1219 } 1220 1221 } 1222} 1223 | Popular Tags |