001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.bcel.verifier.structurals; 018 019import org.apache.bcel.Const; 020import org.apache.bcel.Repository; 021import org.apache.bcel.classfile.Constant; 022import org.apache.bcel.classfile.ConstantClass; 023import org.apache.bcel.classfile.ConstantDouble; 024import org.apache.bcel.classfile.ConstantFieldref; 025import org.apache.bcel.classfile.ConstantFloat; 026import org.apache.bcel.classfile.ConstantInteger; 027import org.apache.bcel.classfile.ConstantLong; 028import org.apache.bcel.classfile.ConstantString; 029import org.apache.bcel.classfile.Field; 030import org.apache.bcel.classfile.JavaClass; 031//CHECKSTYLE:OFF (there are lots of references!) 032import org.apache.bcel.generic.*; 033//CHECKSTYLE:ON 034import org.apache.bcel.verifier.VerificationResult; 035import org.apache.bcel.verifier.Verifier; 036import org.apache.bcel.verifier.VerifierFactory; 037import org.apache.bcel.verifier.exc.AssertionViolatedException; 038import org.apache.bcel.verifier.exc.StructuralCodeConstraintException; 039 040/** 041 * A Visitor class testing for valid preconditions of JVM instructions. The instance of this class will throw a 042 * StructuralCodeConstraintException instance if an instruction is visitXXX()ed which has preconditions that are not 043 * satisfied. TODO: Currently, the JVM's behavior concerning monitors (MONITORENTER, MONITOREXIT) is not modeled in 044 * JustIce. 045 * 046 * @see StructuralCodeConstraintException 047 */ 048public class InstConstraintVisitor extends EmptyVisitor { 049 050 private static final ObjectType GENERIC_ARRAY = ObjectType.getInstance(GenericArray.class.getName()); 051 052 /** 053 * The Execution Frame we're working on. 054 * 055 * @see #setFrame(Frame f) 056 * @see #locals() 057 * @see #stack() 058 */ 059 private Frame frame; 060 061 /** 062 * The ConstantPoolGen we're working on. 063 * 064 * @see #setConstantPoolGen(ConstantPoolGen cpg) 065 */ 066 private ConstantPoolGen cpg; 067 068 /** 069 * The MethodGen we're working on. 070 * 071 * @see #setMethodGen(MethodGen mg) 072 */ 073 private MethodGen mg; 074 075 /** 076 * The constructor. Constructs a new instance of this class. 077 */ 078 public InstConstraintVisitor() { 079 } 080 081 /***************************************************************/ 082 /* MISC */ 083 /***************************************************************/ 084 /** 085 * Ensures the general preconditions of an instruction that accesses the stack. This method is here because BCEL has no 086 * such superinterface for the stack accessing instructions; and there are funny unexpected exceptions in the semantices 087 * of the superinterfaces and superclasses provided. E.g. SWAP is a StackConsumer, but DUP_X1 is not a StackProducer. 088 * Therefore, this method is called by all StackProducer, StackConsumer, and StackInstruction instances via their 089 * visitXXX() method. Unfortunately, as the superclasses and superinterfaces overlap, some instructions cause this 090 * method to be called two or three times. [TODO: Fix this.] 091 * 092 * @see #visitStackConsumer(StackConsumer o) 093 * @see #visitStackProducer(StackProducer o) 094 * @see #visitStackInstruction(StackInstruction o) 095 */ 096 private void _visitStackAccessor(final Instruction o) { 097 final int consume = o.consumeStack(cpg); // Stack values are always consumed first; then produced. 098 if (consume > stack().slotsUsed()) { 099 constraintViolated(o, "Cannot consume " + consume + " stack slots: only " + stack().slotsUsed() + " slot(s) left on stack!\nStack:\n" + stack()); 100 } 101 102 final int produce = o.produceStack(cpg) - o.consumeStack(cpg); // Stack values are always consumed first; then produced. 103 if (produce + stack().slotsUsed() > stack().maxStack()) { 104 constraintViolated(o, "Cannot produce " + produce + " stack slots: only " + (stack().maxStack() - stack().slotsUsed()) 105 + " free stack slot(s) left.\nStack:\n" + stack()); 106 } 107 } 108 109 /** 110 * Assures arrayref is of ArrayType or NULL; returns true if and only if arrayref is non-NULL. 111 * 112 * @throws StructuralCodeConstraintException if the above constraint is violated. 113 */ 114 private boolean arrayrefOfArrayType(final Instruction o, final Type arrayref) { 115 if (!(arrayref instanceof ArrayType || arrayref.equals(Type.NULL))) { 116 constraintViolated(o, "The 'arrayref' does not refer to an array but is of type " + arrayref + "."); 117 } 118 return arrayref instanceof ArrayType; 119 } 120 121 /** 122 * This method is called by the visitXXX() to notify the acceptor of this InstConstraintVisitor that a constraint 123 * violation has occurred. This is done by throwing an instance of a StructuralCodeConstraintException. 124 * 125 * @throws StructuralCodeConstraintException always. 126 */ 127 private void constraintViolated(final Instruction violator, final String description) { 128 final String fqClassName = violator.getClass().getName(); 129 throw new StructuralCodeConstraintException( 130 "Instruction " + fqClassName.substring(fqClassName.lastIndexOf('.') + 1) + " constraint violated: " + description); 131 } 132 133 private ObjectType getObjectType(final FieldInstruction o) { 134 final ReferenceType rt = o.getReferenceType(cpg); 135 if (rt instanceof ObjectType) { 136 return (ObjectType) rt; 137 } 138 constraintViolated(o, "expecting ObjectType but got " + rt); 139 return null; 140 } 141 142 /** 143 * Assures index is of type INT. 144 * 145 * @throws StructuralCodeConstraintException if the above constraint is not satisfied. 146 */ 147 private void indexOfInt(final Instruction o, final Type index) { 148 if (!index.equals(Type.INT)) { 149 constraintViolated(o, "The 'index' is not of type int but of type " + index + "."); 150 } 151 } 152 153 /** 154 * The LocalVariables we're working on. 155 * 156 * @see #setFrame(Frame f) 157 */ 158 private LocalVariables locals() { 159 return frame.getLocals(); 160 } 161 162 /** 163 * Assures the ReferenceType r is initialized (or Type.NULL). Formally, this means (!(r instanceof 164 * UninitializedObjectType)), because there are no uninitialized array types. 165 * 166 * @throws StructuralCodeConstraintException if the above constraint is not satisfied. 167 */ 168 private void referenceTypeIsInitialized(final Instruction o, final ReferenceType r) { 169 if (r instanceof UninitializedObjectType) { 170 constraintViolated(o, "Working on an uninitialized object '" + r + "'."); 171 } 172 } 173 174 /** 175 * Sets the ConstantPoolGen instance needed for constraint checking prior to execution. 176 */ 177 public void setConstantPoolGen(final ConstantPoolGen cpg) { // TODO could be package-protected? 178 this.cpg = cpg; 179 } 180 181 /** 182 * This returns the single instance of the InstConstraintVisitor class. To operate correctly, other values must have 183 * been set before actually using the instance. Use this method for performance reasons. 184 * 185 * @see #setConstantPoolGen(ConstantPoolGen cpg) 186 * @see #setMethodGen(MethodGen mg) 187 */ 188 public void setFrame(final Frame f) { // TODO could be package-protected? 189 this.frame = f; 190 // if (singleInstance.mg == null || singleInstance.cpg == null) 191 // throw new AssertionViolatedException("Forgot to set important values first."); 192 } 193 194 /** 195 * Sets the MethodGen instance needed for constraint checking prior to execution. 196 */ 197 public void setMethodGen(final MethodGen mg) { 198 this.mg = mg; 199 } 200 201 /** 202 * The OperandStack we're working on. 203 * 204 * @see #setFrame(Frame f) 205 */ 206 private OperandStack stack() { 207 return frame.getStack(); 208 } 209 210 /***************************************************************/ 211 /* "generic"visitXXXX methods where XXXX is an interface */ 212 /* therefore, we don't know the order of visiting; but we know */ 213 /* these methods are called before the visitYYYY methods below */ 214 /***************************************************************/ 215 216 /** Assures value is of type INT. */ 217 private void valueOfInt(final Instruction o, final Type value) { 218 if (!value.equals(Type.INT)) { 219 constraintViolated(o, "The 'value' is not of type int but of type " + value + "."); 220 } 221 } 222 223 /** 224 * Ensures the specific preconditions of the said instruction. 225 */ 226 @Override 227 public void visitAALOAD(final AALOAD o) { 228 final Type arrayref = stack().peek(1); 229 final Type index = stack().peek(0); 230 231 indexOfInt(o, index); 232 if (arrayrefOfArrayType(o, arrayref) && !(((ArrayType) arrayref).getElementType() instanceof ReferenceType)) { 233 constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a ReferenceType but to an array of " 234 + ((ArrayType) arrayref).getElementType() + "."); 235 } 236 // referenceTypeIsInitialized(o, (ReferenceType) (((ArrayType) arrayref).getElementType())); 237 } 238 239 /** 240 * Ensures the specific preconditions of the said instruction. 241 */ 242 @Override 243 public void visitAASTORE(final AASTORE o) { 244 final Type arrayref = stack().peek(2); 245 final Type index = stack().peek(1); 246 final Type value = stack().peek(0); 247 248 indexOfInt(o, index); 249 if (!(value instanceof ReferenceType)) { 250 constraintViolated(o, "The 'value' is not of a ReferenceType but of type " + value + "."); 251 } 252 // } else { 253 // referenceTypeIsInitialized(o, (ReferenceType) value); 254 // } 255 // 256 // Don't bother further with "referenceTypeIsInitialized()", there are no arrays 257 // of an uninitialized object type. 258 if (arrayrefOfArrayType(o, arrayref) && !(((ArrayType) arrayref).getElementType() instanceof ReferenceType)) { 259 constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a ReferenceType but to an array of " 260 + ((ArrayType) arrayref).getElementType() + "."); 261 } 262 // No check for array element assignment compatibility. This is done at runtime. 263 } 264 265 /** 266 * Ensures the specific preconditions of the said instruction. 267 */ 268 @Override 269 public void visitACONST_NULL(final ACONST_NULL o) { 270 // Nothing needs to be done here. 271 } 272 273 /** 274 * Ensures the specific preconditions of the said instruction. 275 */ 276 @Override 277 public void visitALOAD(final ALOAD o) { 278 // visitLoadInstruction(LoadInstruction) is called before. 279 280 // Nothing else needs to be done here. 281 } 282 283 /** 284 * Ensures the specific preconditions of the said instruction. 285 */ 286 @Override 287 public void visitANEWARRAY(final ANEWARRAY o) { 288 if (!stack().peek().equals(Type.INT)) { 289 constraintViolated(o, "The 'count' at the stack top is not of type '" + Type.INT + "' but of type '" + stack().peek() + "'."); 290 // The runtime constant pool item at that index must be a symbolic reference to a class, 291 // array, or interface type. See Pass 3a. 292 } 293 } 294 295 /** 296 * Ensures the specific preconditions of the said instruction. 297 */ 298 @Override 299 public void visitARETURN(final ARETURN o) { 300 if (!(stack().peek() instanceof ReferenceType)) { 301 constraintViolated(o, "The 'objectref' at the stack top is not of a ReferenceType but of type '" + stack().peek() + "'."); 302 } 303 final ReferenceType objectref = (ReferenceType) stack().peek(); 304 referenceTypeIsInitialized(o, objectref); 305 306 // The check below should already done via visitReturnInstruction(ReturnInstruction), see there. 307 // It cannot be done using Staerk-et-al's "set of object types" instead of a 308 // "wider cast object type", anyway. 309 // if (! objectref.isAssignmentCompatibleWith(mg.getReturnType() )) { 310 // constraintViolated(o, "The 'objectref' type "+objectref+ 311 // " at the stack top is not assignment compatible with the return type '"+mg.getReturnType()+"' of the method."); 312 // } 313 } 314 315 /** 316 * Ensures the specific preconditions of the said instruction. 317 */ 318 @Override 319 public void visitARRAYLENGTH(final ARRAYLENGTH o) { 320 final Type arrayref = stack().peek(0); 321 arrayrefOfArrayType(o, arrayref); 322 } 323 324 /** 325 * Ensures the specific preconditions of the said instruction. 326 */ 327 @Override 328 public void visitASTORE(final ASTORE o) { 329 if (!(stack().peek() instanceof ReferenceType || stack().peek() instanceof ReturnaddressType)) { 330 constraintViolated(o, "The 'objectref' is not of a ReferenceType or of ReturnaddressType but of " + stack().peek() + "."); 331 } 332 // if (stack().peek() instanceof ReferenceType) { 333 // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) ); 334 // } 335 } 336 337 /** 338 * Ensures the specific preconditions of the said instruction. 339 */ 340 @Override 341 public void visitATHROW(final ATHROW o) { 342 try { 343 // It's stated that 'objectref' must be of a ReferenceType --- but since Throwable is 344 // not derived from an ArrayType, it follows that 'objectref' must be of an ObjectType or Type.NULL. 345 if (!(stack().peek() instanceof ObjectType || stack().peek().equals(Type.NULL))) { 346 constraintViolated(o, "The 'objectref' is not of an (initialized) ObjectType but of type " + stack().peek() + "."); 347 } 348 349 // NULL is a subclass of every class, so to speak. 350 if (stack().peek().equals(Type.NULL)) { 351 return; 352 } 353 354 final ObjectType exc = (ObjectType) stack().peek(); 355 final ObjectType throwable = (ObjectType) Type.getType("Ljava/lang/Throwable;"); 356 if (!exc.subclassOf(throwable) && !exc.equals(throwable)) { 357 constraintViolated(o, "The 'objectref' is not of class Throwable or of a subclass of Throwable, but of '" + stack().peek() + "'."); 358 } 359 } catch (final ClassNotFoundException e) { 360 // FIXME: maybe not the best way to handle this 361 throw new AssertionViolatedException("Missing class: " + e, e); 362 } 363 } 364 365 /** 366 * Ensures the specific preconditions of the said instruction. 367 */ 368 @Override 369 public void visitBALOAD(final BALOAD o) { 370 final Type arrayref = stack().peek(1); 371 final Type index = stack().peek(0); 372 indexOfInt(o, index); 373 if (arrayrefOfArrayType(o, arrayref) 374 && !(((ArrayType) arrayref).getElementType().equals(Type.BOOLEAN) || ((ArrayType) arrayref).getElementType().equals(Type.BYTE))) { 375 constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a Type.BYTE or Type.BOOLEAN but to an array of '" 376 + ((ArrayType) arrayref).getElementType() + "'."); 377 } 378 } 379 380 /***************************************************************/ 381 /* "special"visitXXXX methods for one type of instruction each */ 382 /***************************************************************/ 383 384 /** 385 * Ensures the specific preconditions of the said instruction. 386 */ 387 @Override 388 public void visitBASTORE(final BASTORE o) { 389 final Type arrayref = stack().peek(2); 390 final Type index = stack().peek(1); 391 final Type value = stack().peek(0); 392 393 indexOfInt(o, index); 394 valueOfInt(o, value); 395 if (arrayrefOfArrayType(o, arrayref) 396 && !(((ArrayType) arrayref).getElementType().equals(Type.BOOLEAN) || ((ArrayType) arrayref).getElementType().equals(Type.BYTE))) { 397 constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a Type.BYTE or Type.BOOLEAN but to an array of '" 398 + ((ArrayType) arrayref).getElementType() + "'."); 399 } 400 } 401 402 /** 403 * Ensures the specific preconditions of the said instruction. 404 */ 405 @Override 406 public void visitBIPUSH(final BIPUSH o) { 407 // Nothing to do... 408 } 409 410 /** 411 * Ensures the specific preconditions of the said instruction. 412 */ 413 @Override 414 public void visitBREAKPOINT(final BREAKPOINT o) { 415 throw new AssertionViolatedException("In this JustIce verification pass there should not occur an illegal instruction such as BREAKPOINT."); 416 } 417 418 /** 419 * Ensures the specific preconditions of the said instruction. 420 */ 421 @Override 422 public void visitCALOAD(final CALOAD o) { 423 final Type arrayref = stack().peek(1); 424 final Type index = stack().peek(0); 425 426 indexOfInt(o, index); 427 arrayrefOfArrayType(o, arrayref); 428 } 429 430 /** 431 * Ensures the specific preconditions of the said instruction. 432 */ 433 @Override 434 public void visitCASTORE(final CASTORE o) { 435 final Type arrayref = stack().peek(2); 436 final Type index = stack().peek(1); 437 final Type value = stack().peek(0); 438 439 indexOfInt(o, index); 440 valueOfInt(o, value); 441 if (arrayrefOfArrayType(o, arrayref) && !((ArrayType) arrayref).getElementType().equals(Type.CHAR)) { 442 constraintViolated(o, "The 'arrayref' does not refer to an array with elements of type char but to an array of type " 443 + ((ArrayType) arrayref).getElementType() + "."); 444 } 445 } 446 447 /** 448 * Ensures the specific preconditions of the said instruction. 449 */ 450 @Override 451 public void visitCHECKCAST(final CHECKCAST o) { 452 // The objectref must be of type reference. 453 final Type objectref = stack().peek(0); 454 if (!(objectref instanceof ReferenceType)) { 455 constraintViolated(o, "The 'objectref' is not of a ReferenceType but of type " + objectref + "."); 456 } 457 // else{ 458 // referenceTypeIsInitialized(o, (ReferenceType) objectref); 459 // } 460 // The unsigned indexbyte1 and indexbyte2 are used to construct an index into the runtime constant pool of the 461 // current class (�3.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The runtime constant 462 // pool item at the index must be a symbolic reference to a class, array, or interface type. 463 final Constant c = cpg.getConstant(o.getIndex()); 464 if (!(c instanceof ConstantClass)) { 465 constraintViolated(o, "The Constant at 'index' is not a ConstantClass, but '" + c + "'."); 466 } 467 } 468 469 /***************************************************************/ 470 /* "generic" visitYYYY methods where YYYY is a superclass. */ 471 /* therefore, we know the order of visiting; we know */ 472 /* these methods are called after the visitXXXX methods above. */ 473 /***************************************************************/ 474 /** 475 * Ensures the general preconditions of a CPInstruction instance. 476 */ 477 @Override 478 public void visitCPInstruction(final CPInstruction o) { 479 final int idx = o.getIndex(); 480 if (idx < 0 || idx >= cpg.getSize()) { 481 throw new AssertionViolatedException("Huh?! Constant pool index of instruction '" + o + "' illegal? Pass 3a should have checked this!"); 482 } 483 } 484 485 /** 486 * Ensures the specific preconditions of the said instruction. 487 */ 488 @Override 489 public void visitD2F(final D2F o) { 490 if (stack().peek() != Type.DOUBLE) { 491 constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'."); 492 } 493 } 494 495 /** 496 * Ensures the specific preconditions of the said instruction. 497 */ 498 @Override 499 public void visitD2I(final D2I o) { 500 if (stack().peek() != Type.DOUBLE) { 501 constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'."); 502 } 503 } 504 505 /** 506 * Ensures the specific preconditions of the said instruction. 507 */ 508 @Override 509 public void visitD2L(final D2L o) { 510 if (stack().peek() != Type.DOUBLE) { 511 constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'."); 512 } 513 } 514 515 /** 516 * Ensures the specific preconditions of the said instruction. 517 */ 518 @Override 519 public void visitDADD(final DADD o) { 520 if (stack().peek() != Type.DOUBLE) { 521 constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'."); 522 } 523 if (stack().peek(1) != Type.DOUBLE) { 524 constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'."); 525 } 526 } 527 528 /** 529 * Ensures the specific preconditions of the said instruction. 530 */ 531 @Override 532 public void visitDALOAD(final DALOAD o) { 533 indexOfInt(o, stack().peek()); 534 if (stack().peek(1) == Type.NULL) { 535 return; 536 } 537 if (!(stack().peek(1) instanceof ArrayType)) { 538 constraintViolated(o, "Stack next-to-top must be of type double[] but is '" + stack().peek(1) + "'."); 539 } 540 final Type t = ((ArrayType) stack().peek(1)).getBasicType(); 541 if (t != Type.DOUBLE) { 542 constraintViolated(o, "Stack next-to-top must be of type double[] but is '" + stack().peek(1) + "'."); 543 } 544 } 545 546 /** 547 * Ensures the specific preconditions of the said instruction. 548 */ 549 @Override 550 public void visitDASTORE(final DASTORE o) { 551 if (stack().peek() != Type.DOUBLE) { 552 constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'."); 553 } 554 indexOfInt(o, stack().peek(1)); 555 if (stack().peek(2) == Type.NULL) { 556 return; 557 } 558 if (!(stack().peek(2) instanceof ArrayType)) { 559 constraintViolated(o, "Stack next-to-next-to-top must be of type double[] but is '" + stack().peek(2) + "'."); 560 } 561 final Type t = ((ArrayType) stack().peek(2)).getBasicType(); 562 if (t != Type.DOUBLE) { 563 constraintViolated(o, "Stack next-to-next-to-top must be of type double[] but is '" + stack().peek(2) + "'."); 564 } 565 } 566 567 /** 568 * Ensures the specific preconditions of the said instruction. 569 */ 570 @Override 571 public void visitDCMPG(final DCMPG o) { 572 if (stack().peek() != Type.DOUBLE) { 573 constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'."); 574 } 575 if (stack().peek(1) != Type.DOUBLE) { 576 constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'."); 577 } 578 } 579 580 /** 581 * Ensures the specific preconditions of the said instruction. 582 */ 583 @Override 584 public void visitDCMPL(final DCMPL o) { 585 if (stack().peek() != Type.DOUBLE) { 586 constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'."); 587 } 588 if (stack().peek(1) != Type.DOUBLE) { 589 constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'."); 590 } 591 } 592 593 /** 594 * Ensures the specific preconditions of the said instruction. 595 */ 596 @Override 597 public void visitDCONST(final DCONST o) { 598 // There's nothing to be done here. 599 } 600 601 /** 602 * Ensures the specific preconditions of the said instruction. 603 */ 604 @Override 605 public void visitDDIV(final DDIV o) { 606 if (stack().peek() != Type.DOUBLE) { 607 constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'."); 608 } 609 if (stack().peek(1) != Type.DOUBLE) { 610 constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'."); 611 } 612 } 613 614 /** 615 * Ensures the specific preconditions of the said instruction. 616 */ 617 @Override 618 public void visitDLOAD(final DLOAD o) { 619 // visitLoadInstruction(LoadInstruction) is called before. 620 621 // Nothing else needs to be done here. 622 } 623 624 /** 625 * Ensures the specific preconditions of the said instruction. 626 */ 627 @Override 628 public void visitDMUL(final DMUL o) { 629 if (stack().peek() != Type.DOUBLE) { 630 constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'."); 631 } 632 if (stack().peek(1) != Type.DOUBLE) { 633 constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'."); 634 } 635 } 636 637 /** 638 * Ensures the specific preconditions of the said instruction. 639 */ 640 @Override 641 public void visitDNEG(final DNEG o) { 642 if (stack().peek() != Type.DOUBLE) { 643 constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'."); 644 } 645 } 646 647 /** 648 * Ensures the specific preconditions of the said instruction. 649 */ 650 @Override 651 public void visitDREM(final DREM o) { 652 if (stack().peek() != Type.DOUBLE) { 653 constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'."); 654 } 655 if (stack().peek(1) != Type.DOUBLE) { 656 constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'."); 657 } 658 } 659 660 /** 661 * Ensures the specific preconditions of the said instruction. 662 */ 663 @Override 664 public void visitDRETURN(final DRETURN o) { 665 if (stack().peek() != Type.DOUBLE) { 666 constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'."); 667 } 668 } 669 670 /** 671 * Ensures the specific preconditions of the said instruction. 672 */ 673 @Override 674 public void visitDSTORE(final DSTORE o) { 675 // visitStoreInstruction(StoreInstruction) is called before. 676 677 // Nothing else needs to be done here. 678 } 679 680 /** 681 * Ensures the specific preconditions of the said instruction. 682 */ 683 @Override 684 public void visitDSUB(final DSUB o) { 685 if (stack().peek() != Type.DOUBLE) { 686 constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'."); 687 } 688 if (stack().peek(1) != Type.DOUBLE) { 689 constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'."); 690 } 691 } 692 693 /** 694 * Ensures the specific preconditions of the said instruction. 695 */ 696 @Override 697 public void visitDUP(final DUP o) { 698 if (stack().peek().getSize() != 1) { 699 constraintViolated(o, 700 "Won't DUP type on stack top '" + stack().peek() + "' because it must occupy exactly one slot, not '" + stack().peek().getSize() + "'."); 701 } 702 } 703 704 /** 705 * Ensures the specific preconditions of the said instruction. 706 */ 707 @Override 708 public void visitDUP_X1(final DUP_X1 o) { 709 if (stack().peek().getSize() != 1) { 710 constraintViolated(o, "Type on stack top '" + stack().peek() + "' should occupy exactly one slot, not '" + stack().peek().getSize() + "'."); 711 } 712 if (stack().peek(1).getSize() != 1) { 713 constraintViolated(o, 714 "Type on stack next-to-top '" + stack().peek(1) + "' should occupy exactly one slot, not '" + stack().peek(1).getSize() + "'."); 715 } 716 } 717 718 /** 719 * Ensures the specific preconditions of the said instruction. 720 */ 721 @Override 722 public void visitDUP_X2(final DUP_X2 o) { 723 if (stack().peek().getSize() != 1) { 724 constraintViolated(o, "Stack top type must be of size 1, but is '" + stack().peek() + "' of size '" + stack().peek().getSize() + "'."); 725 } 726 if (stack().peek(1).getSize() == 2) { 727 return; // Form 2, okay. 728 } 729 // stack().peek(1).getSize == 1. 730 if (stack().peek(2).getSize() != 1) { 731 constraintViolated(o, "If stack top's size is 1 and stack next-to-top's size is 1," + " stack next-to-next-to-top's size must also be 1, but is: '" 732 + stack().peek(2) + "' of size '" + stack().peek(2).getSize() + "'."); 733 } 734 } 735 736 /** 737 * Ensures the specific preconditions of the said instruction. 738 */ 739 @Override 740 public void visitDUP2(final DUP2 o) { 741 if (stack().peek().getSize() == 2) { 742 return; // Form 2, okay. 743 } 744 // stack().peek().getSize() == 1. 745 if (stack().peek(1).getSize() != 1) { 746 constraintViolated(o, "If stack top's size is 1, then stack next-to-top's size must also be 1. But it is '" + stack().peek(1) + "' of size '" 747 + stack().peek(1).getSize() + "'."); 748 } 749 } 750 751 /** 752 * Ensures the specific preconditions of the said instruction. 753 */ 754 @Override 755 public void visitDUP2_X1(final DUP2_X1 o) { 756 if (stack().peek().getSize() == 2) { 757 if (stack().peek(1).getSize() != 1) { 758 constraintViolated(o, "If stack top's size is 2, then stack next-to-top's size must be 1. But it is '" + stack().peek(1) + "' of size '" 759 + stack().peek(1).getSize() + "'."); 760 } 761 } else { // stack top is of size 1 762 if (stack().peek(1).getSize() != 1) { 763 constraintViolated(o, "If stack top's size is 1, then stack next-to-top's size must also be 1. But it is '" + stack().peek(1) + "' of size '" 764 + stack().peek(1).getSize() + "'."); 765 } 766 if (stack().peek(2).getSize() != 1) { 767 constraintViolated(o, "If stack top's size is 1, then stack next-to-next-to-top's size must also be 1. But it is '" + stack().peek(2) 768 + "' of size '" + stack().peek(2).getSize() + "'."); 769 } 770 } 771 } 772 773 /** 774 * Ensures the specific preconditions of the said instruction. 775 */ 776 @Override 777 public void visitDUP2_X2(final DUP2_X2 o) { 778 779 if (stack().peek(0).getSize() == 2) { 780 // stack top size is 2, next-to-top's size is 1 781 if (stack().peek(1).getSize() == 2 || stack().peek(2).getSize() == 1) { 782 return; // Form 2 783 } 784 constraintViolated(o, "If stack top's size is 2 and stack-next-to-top's size is 1," 785 + " then stack next-to-next-to-top's size must also be 1. But it is '" + stack().peek(2) + "' of size '" + stack().peek(2).getSize() + "'."); 786 } else if (stack().peek(1).getSize() == 1 && (stack().peek(2).getSize() == 2 || stack().peek(3).getSize() == 1)) { 787 return; // Form 1 788 } 789 constraintViolated(o, "The operand sizes on the stack do not match any of the four forms of usage of this instruction."); 790 } 791 792 /** 793 * Ensures the specific preconditions of the said instruction. 794 */ 795 @Override 796 public void visitF2D(final F2D o) { 797 if (stack().peek() != Type.FLOAT) { 798 constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'."); 799 } 800 } 801 802 /** 803 * Ensures the specific preconditions of the said instruction. 804 */ 805 @Override 806 public void visitF2I(final F2I o) { 807 if (stack().peek() != Type.FLOAT) { 808 constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'."); 809 } 810 } 811 812 /** 813 * Ensures the specific preconditions of the said instruction. 814 */ 815 @Override 816 public void visitF2L(final F2L o) { 817 if (stack().peek() != Type.FLOAT) { 818 constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'."); 819 } 820 } 821 822 /** 823 * Ensures the specific preconditions of the said instruction. 824 */ 825 @Override 826 public void visitFADD(final FADD o) { 827 if (stack().peek() != Type.FLOAT) { 828 constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'."); 829 } 830 if (stack().peek(1) != Type.FLOAT) { 831 constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'."); 832 } 833 } 834 835 /** 836 * Ensures the specific preconditions of the said instruction. 837 */ 838 @Override 839 public void visitFALOAD(final FALOAD o) { 840 indexOfInt(o, stack().peek()); 841 if (stack().peek(1) == Type.NULL) { 842 return; 843 } 844 if (!(stack().peek(1) instanceof ArrayType)) { 845 constraintViolated(o, "Stack next-to-top must be of type float[] but is '" + stack().peek(1) + "'."); 846 } 847 final Type t = ((ArrayType) stack().peek(1)).getBasicType(); 848 if (t != Type.FLOAT) { 849 constraintViolated(o, "Stack next-to-top must be of type float[] but is '" + stack().peek(1) + "'."); 850 } 851 } 852 853 /** 854 * Ensures the specific preconditions of the said instruction. 855 */ 856 @Override 857 public void visitFASTORE(final FASTORE o) { 858 if (stack().peek() != Type.FLOAT) { 859 constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'."); 860 } 861 indexOfInt(o, stack().peek(1)); 862 if (stack().peek(2) == Type.NULL) { 863 return; 864 } 865 if (!(stack().peek(2) instanceof ArrayType)) { 866 constraintViolated(o, "Stack next-to-next-to-top must be of type float[] but is '" + stack().peek(2) + "'."); 867 } 868 final Type t = ((ArrayType) stack().peek(2)).getBasicType(); 869 if (t != Type.FLOAT) { 870 constraintViolated(o, "Stack next-to-next-to-top must be of type float[] but is '" + stack().peek(2) + "'."); 871 } 872 } 873 874 /** 875 * Ensures the specific preconditions of the said instruction. 876 */ 877 @Override 878 public void visitFCMPG(final FCMPG o) { 879 if (stack().peek() != Type.FLOAT) { 880 constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'."); 881 } 882 if (stack().peek(1) != Type.FLOAT) { 883 constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'."); 884 } 885 } 886 887 /** 888 * Ensures the specific preconditions of the said instruction. 889 */ 890 @Override 891 public void visitFCMPL(final FCMPL o) { 892 if (stack().peek() != Type.FLOAT) { 893 constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'."); 894 } 895 if (stack().peek(1) != Type.FLOAT) { 896 constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'."); 897 } 898 } 899 900 /** 901 * Ensures the specific preconditions of the said instruction. 902 */ 903 @Override 904 public void visitFCONST(final FCONST o) { 905 // nothing to do here. 906 } 907 908 /** 909 * Ensures the specific preconditions of the said instruction. 910 */ 911 @Override 912 public void visitFDIV(final FDIV o) { 913 if (stack().peek() != Type.FLOAT) { 914 constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'."); 915 } 916 if (stack().peek(1) != Type.FLOAT) { 917 constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'."); 918 } 919 } 920 921 /** 922 * Ensures the general preconditions of a FieldInstruction instance. 923 */ 924 @Override 925 public void visitFieldInstruction(final FieldInstruction o) { 926 // visitLoadClass(o) has been called before: Every FieldOrMethod 927 // implements LoadClass. 928 // visitCPInstruction(o) has been called before. 929 // A FieldInstruction may be: GETFIELD, GETSTATIC, PUTFIELD, PUTSTATIC 930 final Constant c = cpg.getConstant(o.getIndex()); 931 if (!(c instanceof ConstantFieldref)) { 932 constraintViolated(o, "Index '" + o.getIndex() + "' should refer to a CONSTANT_Fieldref_info structure, but refers to '" + c + "'."); 933 } 934 // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o). 935 final Type t = o.getType(cpg); 936 if (t instanceof ObjectType) { 937 final String name = ((ObjectType) t).getClassName(); 938 final Verifier v = VerifierFactory.getVerifier(name); 939 final VerificationResult vr = v.doPass2(); 940 if (vr.getStatus() != VerificationResult.VERIFIED_OK) { 941 constraintViolated(o, "Class '" + name + "' is referenced, but cannot be loaded and resolved: '" + vr + "'."); 942 } 943 } 944 } 945 946 private Field visitFieldInstructionInternals(final FieldInstruction o) throws ClassNotFoundException { 947 final String fieldName = o.getFieldName(cpg); 948 final JavaClass jc = Repository.lookupClass(getObjectType(o).getClassName()); 949 final Field[] fields = jc.getFields(); 950 Field f = null; 951 for (final Field field : fields) { 952 if (field.getName().equals(fieldName)) { 953 final Type fType = Type.getType(field.getSignature()); 954 final Type oType = o.getType(cpg); 955 /* 956 * TODO: Check if assignment compatibility is sufficient. What does Sun do? 957 */ 958 if (fType.equals(oType)) { 959 f = field; 960 break; 961 } 962 } 963 } 964 if (f == null) { 965 throw new AssertionViolatedException("Field '" + fieldName + "' not found in " + jc.getClassName()); 966 } 967 final Type value = stack().peek(); 968 final Type t = Type.getType(f.getSignature()); 969 Type shouldbe = t; 970 if (shouldbe == Type.BOOLEAN || shouldbe == Type.BYTE || shouldbe == Type.CHAR || shouldbe == Type.SHORT) { 971 shouldbe = Type.INT; 972 } 973 if (t instanceof ReferenceType) { 974 ReferenceType rvalue = null; 975 if (value instanceof ReferenceType) { 976 rvalue = (ReferenceType) value; 977 referenceTypeIsInitialized(o, rvalue); 978 } else { 979 constraintViolated(o, "The stack top type '" + value + "' is not of a reference type as expected."); 980 } 981 // TODO: This can possibly only be checked using Staerk-et-al's "set-of-object types", not 982 // using "wider cast object types" created during verification. 983 // Comment it out if you encounter problems. See also the analogon at visitPUTFIELD|visitPUTSTATIC. 984 if (!rvalue.isAssignmentCompatibleWith(shouldbe)) { 985 constraintViolated(o, "The stack top type '" + value + "' is not assignment compatible with '" + shouldbe + "'."); 986 } 987 } else if (shouldbe != value) { 988 constraintViolated(o, "The stack top type '" + value + "' is not of type '" + shouldbe + "' as expected."); 989 } 990 return f; 991 } 992 993 /** 994 * Ensures the specific preconditions of the said instruction. 995 */ 996 @Override 997 public void visitFLOAD(final FLOAD o) { 998 // visitLoadInstruction(LoadInstruction) is called before. 999 1000 // Nothing else needs to be done here. 1001 } 1002 1003 /** 1004 * Ensures the specific preconditions of the said instruction. 1005 */ 1006 @Override 1007 public void visitFMUL(final FMUL o) { 1008 if (stack().peek() != Type.FLOAT) { 1009 constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'."); 1010 } 1011 if (stack().peek(1) != Type.FLOAT) { 1012 constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'."); 1013 } 1014 } 1015 1016 /** 1017 * Ensures the specific preconditions of the said instruction. 1018 */ 1019 @Override 1020 public void visitFNEG(final FNEG o) { 1021 if (stack().peek() != Type.FLOAT) { 1022 constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'."); 1023 } 1024 } 1025 1026 /** 1027 * Ensures the specific preconditions of the said instruction. 1028 */ 1029 @Override 1030 public void visitFREM(final FREM o) { 1031 if (stack().peek() != Type.FLOAT) { 1032 constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'."); 1033 } 1034 if (stack().peek(1) != Type.FLOAT) { 1035 constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'."); 1036 } 1037 } 1038 1039 /** 1040 * Ensures the specific preconditions of the said instruction. 1041 */ 1042 @Override 1043 public void visitFRETURN(final FRETURN o) { 1044 if (stack().peek() != Type.FLOAT) { 1045 constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'."); 1046 } 1047 } 1048 1049 /** 1050 * Ensures the specific preconditions of the said instruction. 1051 */ 1052 @Override 1053 public void visitFSTORE(final FSTORE o) { 1054 // visitStoreInstruction(StoreInstruction) is called before. 1055 1056 // Nothing else needs to be done here. 1057 } 1058 1059 /** 1060 * Ensures the specific preconditions of the said instruction. 1061 */ 1062 @Override 1063 public void visitFSUB(final FSUB o) { 1064 if (stack().peek() != Type.FLOAT) { 1065 constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'."); 1066 } 1067 if (stack().peek(1) != Type.FLOAT) { 1068 constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'."); 1069 } 1070 } 1071 1072 /** 1073 * Ensures the specific preconditions of the said instruction. 1074 */ 1075 @Override 1076 public void visitGETFIELD(final GETFIELD o) { 1077 try { 1078 final Type objectref = stack().peek(); 1079 if (!(objectref instanceof ObjectType || objectref == Type.NULL)) { 1080 constraintViolated(o, "Stack top should be an object reference that's not an array reference, but is '" + objectref + "'."); 1081 } 1082 1083 final String fieldName = o.getFieldName(cpg); 1084 1085 final JavaClass jc = Repository.lookupClass(getObjectType(o).getClassName()); 1086 Field[] fields = jc.getFields(); 1087 Field f = null; 1088 for (final Field field : fields) { 1089 if (field.getName().equals(fieldName)) { 1090 final Type fType = Type.getType(field.getSignature()); 1091 final Type oType = o.getType(cpg); 1092 /* 1093 * TODO: Check if assignment compatibility is sufficient. What does Sun do? 1094 */ 1095 if (fType.equals(oType)) { 1096 f = field; 1097 break; 1098 } 1099 } 1100 } 1101 1102 if (f == null) { 1103 final JavaClass[] superclasses = jc.getSuperClasses(); 1104 outer: for (final JavaClass superclass : superclasses) { 1105 fields = superclass.getFields(); 1106 for (final Field field : fields) { 1107 if (field.getName().equals(fieldName)) { 1108 final Type fType = Type.getType(field.getSignature()); 1109 final Type oType = o.getType(cpg); 1110 if (fType.equals(oType)) { 1111 f = field; 1112 if ((f.getAccessFlags() & (Const.ACC_PUBLIC | Const.ACC_PROTECTED)) == 0) { 1113 f = null; 1114 } 1115 break outer; 1116 } 1117 } 1118 } 1119 } 1120 if (f == null) { 1121 throw new AssertionViolatedException("Field '" + fieldName + "' not found in " + jc.getClassName()); 1122 } 1123 } 1124 1125 if (f.isProtected()) { 1126 final ObjectType classtype = getObjectType(o); 1127 final ObjectType curr = ObjectType.getInstance(mg.getClassName()); 1128 1129 if (classtype.equals(curr) || curr.subclassOf(classtype)) { 1130 final Type t = stack().peek(); 1131 if (t == Type.NULL) { 1132 return; 1133 } 1134 if (!(t instanceof ObjectType)) { 1135 constraintViolated(o, "The 'objectref' must refer to an object that's not an array. Found instead: '" + t + "'."); 1136 } 1137 // final ObjectType objreftype = (ObjectType) t; 1138 // if (!(objreftype.equals(curr) || objreftype.subclassOf(curr))) { 1139 // TODO: One day move to Staerk-et-al's "Set of object types" instead of "wider" object types 1140 // created during the verification. 1141 // "Wider" object types don't allow us to check for things like that below. 1142 // constraintViolated(o, "The referenced field has the ACC_PROTECTED modifier, "+ 1143 // "and it's a member of the current class or a superclass of the current class."+ 1144 // " However, the referenced object type '"+stack().peek()+ 1145 // "' is not the current class or a subclass of the current class."); 1146 //} 1147 } 1148 } 1149 1150 // TODO: Could go into Pass 3a. 1151 if (f.isStatic()) { 1152 constraintViolated(o, "Referenced field '" + f + "' is static which it shouldn't be."); 1153 } 1154 1155 } catch (final ClassNotFoundException e) { 1156 // FIXME: maybe not the best way to handle this 1157 throw new AssertionViolatedException("Missing class: " + e, e); 1158 } 1159 } 1160 1161 /** 1162 * Ensures the specific preconditions of the said instruction. 1163 */ 1164 @Override 1165 public void visitGETSTATIC(final GETSTATIC o) { 1166 // Field must be static: see Pass 3a. 1167 } 1168 1169 /** 1170 * Ensures the specific preconditions of the said instruction. 1171 */ 1172 @Override 1173 public void visitGOTO(final GOTO o) { 1174 // nothing to do here. 1175 } 1176 1177 /** 1178 * Ensures the specific preconditions of the said instruction. 1179 */ 1180 @Override 1181 public void visitGOTO_W(final GOTO_W o) { 1182 // nothing to do here. 1183 } 1184 1185 /** 1186 * Ensures the specific preconditions of the said instruction. 1187 */ 1188 @Override 1189 public void visitI2B(final I2B o) { 1190 if (stack().peek() != Type.INT) { 1191 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1192 } 1193 } 1194 1195 /** 1196 * Ensures the specific preconditions of the said instruction. 1197 */ 1198 @Override 1199 public void visitI2C(final I2C o) { 1200 if (stack().peek() != Type.INT) { 1201 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1202 } 1203 } 1204 1205 /** 1206 * Ensures the specific preconditions of the said instruction. 1207 */ 1208 @Override 1209 public void visitI2D(final I2D o) { 1210 if (stack().peek() != Type.INT) { 1211 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1212 } 1213 } 1214 1215 /** 1216 * Ensures the specific preconditions of the said instruction. 1217 */ 1218 @Override 1219 public void visitI2F(final I2F o) { 1220 if (stack().peek() != Type.INT) { 1221 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1222 } 1223 } 1224 1225 /** 1226 * Ensures the specific preconditions of the said instruction. 1227 */ 1228 @Override 1229 public void visitI2L(final I2L o) { 1230 if (stack().peek() != Type.INT) { 1231 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1232 } 1233 } 1234 1235 /** 1236 * Ensures the specific preconditions of the said instruction. 1237 */ 1238 @Override 1239 public void visitI2S(final I2S o) { 1240 if (stack().peek() != Type.INT) { 1241 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1242 } 1243 } 1244 1245 /** 1246 * Ensures the specific preconditions of the said instruction. 1247 */ 1248 @Override 1249 public void visitIADD(final IADD o) { 1250 if (stack().peek() != Type.INT) { 1251 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1252 } 1253 if (stack().peek(1) != Type.INT) { 1254 constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'."); 1255 } 1256 } 1257 1258 /** 1259 * Ensures the specific preconditions of the said instruction. 1260 */ 1261 @Override 1262 public void visitIALOAD(final IALOAD o) { 1263 indexOfInt(o, stack().peek()); 1264 if (stack().peek(1) == Type.NULL) { 1265 return; 1266 } 1267 if (!(stack().peek(1) instanceof ArrayType)) { 1268 constraintViolated(o, "Stack next-to-top must be of type int[] but is '" + stack().peek(1) + "'."); 1269 } 1270 final Type t = ((ArrayType) stack().peek(1)).getBasicType(); 1271 if (t != Type.INT) { 1272 constraintViolated(o, "Stack next-to-top must be of type int[] but is '" + stack().peek(1) + "'."); 1273 } 1274 } 1275 1276 /** 1277 * Ensures the specific preconditions of the said instruction. 1278 */ 1279 @Override 1280 public void visitIAND(final IAND o) { 1281 if (stack().peek() != Type.INT) { 1282 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1283 } 1284 if (stack().peek(1) != Type.INT) { 1285 constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'."); 1286 } 1287 } 1288 1289 /** 1290 * Ensures the specific preconditions of the said instruction. 1291 */ 1292 @Override 1293 public void visitIASTORE(final IASTORE o) { 1294 if (stack().peek() != Type.INT) { 1295 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1296 } 1297 indexOfInt(o, stack().peek(1)); 1298 if (stack().peek(2) == Type.NULL) { 1299 return; 1300 } 1301 if (!(stack().peek(2) instanceof ArrayType)) { 1302 constraintViolated(o, "Stack next-to-next-to-top must be of type int[] but is '" + stack().peek(2) + "'."); 1303 } 1304 final Type t = ((ArrayType) stack().peek(2)).getBasicType(); 1305 if (t != Type.INT) { 1306 constraintViolated(o, "Stack next-to-next-to-top must be of type int[] but is '" + stack().peek(2) + "'."); 1307 } 1308 } 1309 1310 /** 1311 * Ensures the specific preconditions of the said instruction. 1312 */ 1313 @Override 1314 public void visitICONST(final ICONST o) { 1315 // nothing to do here. 1316 } 1317 1318 /** 1319 * Ensures the specific preconditions of the said instruction. 1320 */ 1321 @Override 1322 public void visitIDIV(final IDIV o) { 1323 if (stack().peek() != Type.INT) { 1324 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1325 } 1326 if (stack().peek(1) != Type.INT) { 1327 constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'."); 1328 } 1329 } 1330 1331 /** 1332 * Ensures the specific preconditions of the said instruction. 1333 */ 1334 @Override 1335 public void visitIF_ACMPEQ(final IF_ACMPEQ o) { 1336 if (!(stack().peek() instanceof ReferenceType)) { 1337 constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '" + stack().peek() + "'."); 1338 } 1339 // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) ); 1340 1341 if (!(stack().peek(1) instanceof ReferenceType)) { 1342 constraintViolated(o, "The value at the stack next-to-top is not of a ReferenceType, but of type '" + stack().peek(1) + "'."); 1343 } 1344 // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek(1)) ); 1345 1346 } 1347 1348 /** 1349 * Ensures the specific preconditions of the said instruction. 1350 */ 1351 @Override 1352 public void visitIF_ACMPNE(final IF_ACMPNE o) { 1353 if (!(stack().peek() instanceof ReferenceType)) { 1354 constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '" + stack().peek() + "'."); 1355 // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) ); 1356 } 1357 if (!(stack().peek(1) instanceof ReferenceType)) { 1358 constraintViolated(o, "The value at the stack next-to-top is not of a ReferenceType, but of type '" + stack().peek(1) + "'."); 1359 // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek(1)) ); 1360 } 1361 } 1362 1363 /** 1364 * Ensures the specific preconditions of the said instruction. 1365 */ 1366 @Override 1367 public void visitIF_ICMPEQ(final IF_ICMPEQ o) { 1368 if (stack().peek() != Type.INT) { 1369 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1370 } 1371 if (stack().peek(1) != Type.INT) { 1372 constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'."); 1373 } 1374 } 1375 1376 /** 1377 * Ensures the specific preconditions of the said instruction. 1378 */ 1379 @Override 1380 public void visitIF_ICMPGE(final IF_ICMPGE o) { 1381 if (stack().peek() != Type.INT) { 1382 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1383 } 1384 if (stack().peek(1) != Type.INT) { 1385 constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'."); 1386 } 1387 } 1388 1389 /** 1390 * Ensures the specific preconditions of the said instruction. 1391 */ 1392 @Override 1393 public void visitIF_ICMPGT(final IF_ICMPGT o) { 1394 if (stack().peek() != Type.INT) { 1395 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1396 } 1397 if (stack().peek(1) != Type.INT) { 1398 constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'."); 1399 } 1400 } 1401 1402 /** 1403 * Ensures the specific preconditions of the said instruction. 1404 */ 1405 @Override 1406 public void visitIF_ICMPLE(final IF_ICMPLE o) { 1407 if (stack().peek() != Type.INT) { 1408 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1409 } 1410 if (stack().peek(1) != Type.INT) { 1411 constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'."); 1412 } 1413 } 1414 1415 /** 1416 * Ensures the specific preconditions of the said instruction. 1417 */ 1418 @Override 1419 public void visitIF_ICMPLT(final IF_ICMPLT o) { 1420 if (stack().peek() != Type.INT) { 1421 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1422 } 1423 if (stack().peek(1) != Type.INT) { 1424 constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'."); 1425 } 1426 } 1427 1428 /** 1429 * Ensures the specific preconditions of the said instruction. 1430 */ 1431 @Override 1432 public void visitIF_ICMPNE(final IF_ICMPNE o) { 1433 if (stack().peek() != Type.INT) { 1434 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1435 } 1436 if (stack().peek(1) != Type.INT) { 1437 constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'."); 1438 } 1439 } 1440 1441 /** 1442 * Ensures the specific preconditions of the said instruction. 1443 */ 1444 @Override 1445 public void visitIFEQ(final IFEQ o) { 1446 if (stack().peek() != Type.INT) { 1447 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1448 } 1449 } 1450 1451 /** 1452 * Ensures the specific preconditions of the said instruction. 1453 */ 1454 @Override 1455 public void visitIFGE(final IFGE o) { 1456 if (stack().peek() != Type.INT) { 1457 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1458 } 1459 } 1460 1461 /** 1462 * Ensures the specific preconditions of the said instruction. 1463 */ 1464 @Override 1465 public void visitIFGT(final IFGT o) { 1466 if (stack().peek() != Type.INT) { 1467 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1468 } 1469 } 1470 1471 /** 1472 * Ensures the specific preconditions of the said instruction. 1473 */ 1474 @Override 1475 public void visitIFLE(final IFLE o) { 1476 if (stack().peek() != Type.INT) { 1477 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1478 } 1479 } 1480 1481 /** 1482 * Ensures the specific preconditions of the said instruction. 1483 */ 1484 @Override 1485 public void visitIFLT(final IFLT o) { 1486 if (stack().peek() != Type.INT) { 1487 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1488 } 1489 } 1490 1491 /** 1492 * Ensures the specific preconditions of the said instruction. 1493 */ 1494 @Override 1495 public void visitIFNE(final IFNE o) { 1496 if (stack().peek() != Type.INT) { 1497 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1498 } 1499 } 1500 1501 /** 1502 * Ensures the specific preconditions of the said instruction. 1503 */ 1504 @Override 1505 public void visitIFNONNULL(final IFNONNULL o) { 1506 if (!(stack().peek() instanceof ReferenceType)) { 1507 constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '" + stack().peek() + "'."); 1508 } 1509 referenceTypeIsInitialized(o, (ReferenceType) stack().peek()); 1510 } 1511 1512 /** 1513 * Ensures the specific preconditions of the said instruction. 1514 */ 1515 @Override 1516 public void visitIFNULL(final IFNULL o) { 1517 if (!(stack().peek() instanceof ReferenceType)) { 1518 constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '" + stack().peek() + "'."); 1519 } 1520 referenceTypeIsInitialized(o, (ReferenceType) stack().peek()); 1521 } 1522 1523 /** 1524 * Ensures the specific preconditions of the said instruction. 1525 */ 1526 @Override 1527 public void visitIINC(final IINC o) { 1528 // Mhhh. In BCEL, at this time "IINC" is not a LocalVariableInstruction. 1529 if (locals().maxLocals() <= (o.getType(cpg).getSize() == 1 ? o.getIndex() : o.getIndex() + 1)) { 1530 constraintViolated(o, "The 'index' is not a valid index into the local variable array."); 1531 } 1532 1533 indexOfInt(o, locals().get(o.getIndex())); 1534 } 1535 1536 /** 1537 * Ensures the specific preconditions of the said instruction. 1538 */ 1539 @Override 1540 public void visitILOAD(final ILOAD o) { 1541 // All done by visitLocalVariableInstruction(), visitLoadInstruction() 1542 } 1543 1544 /** 1545 * Ensures the specific preconditions of the said instruction. 1546 */ 1547 @Override 1548 public void visitIMPDEP1(final IMPDEP1 o) { 1549 throw new AssertionViolatedException("In this JustIce verification pass there should not occur an illegal instruction such as IMPDEP1."); 1550 } 1551 1552 /** 1553 * Ensures the specific preconditions of the said instruction. 1554 */ 1555 @Override 1556 public void visitIMPDEP2(final IMPDEP2 o) { 1557 throw new AssertionViolatedException("In this JustIce verification pass there should not occur an illegal instruction such as IMPDEP2."); 1558 } 1559 1560 /** 1561 * Ensures the specific preconditions of the said instruction. 1562 */ 1563 @Override 1564 public void visitIMUL(final IMUL o) { 1565 if (stack().peek() != Type.INT) { 1566 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1567 } 1568 if (stack().peek(1) != Type.INT) { 1569 constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'."); 1570 } 1571 } 1572 1573 /** 1574 * Ensures the specific preconditions of the said instruction. 1575 */ 1576 @Override 1577 public void visitINEG(final INEG o) { 1578 if (stack().peek() != Type.INT) { 1579 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1580 } 1581 } 1582 1583 /** 1584 * Ensures the specific preconditions of the said instruction. 1585 */ 1586 @Override 1587 public void visitINSTANCEOF(final INSTANCEOF o) { 1588 // The objectref must be of type reference. 1589 final Type objectref = stack().peek(0); 1590 if (!(objectref instanceof ReferenceType)) { 1591 constraintViolated(o, "The 'objectref' is not of a ReferenceType but of type " + objectref + "."); 1592 } 1593 // else{ 1594 // referenceTypeIsInitialized(o, (ReferenceType) objectref); 1595 // } 1596 // The unsigned indexbyte1 and indexbyte2 are used to construct an index into the runtime constant pool of the 1597 // current class (�3.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The runtime constant 1598 // pool item at the index must be a symbolic reference to a class, array, or interface type. 1599 final Constant c = cpg.getConstant(o.getIndex()); 1600 if (!(c instanceof ConstantClass)) { 1601 constraintViolated(o, "The Constant at 'index' is not a ConstantClass, but '" + c + "'."); 1602 } 1603 } 1604 1605 /** 1606 * Ensures the specific preconditions of the said instruction. 1607 * 1608 * @since 6.0 1609 */ 1610 @Override 1611 public void visitINVOKEDYNAMIC(final INVOKEDYNAMIC o) { 1612 throw new UnsupportedOperationException("INVOKEDYNAMIC instruction is not supported at this time"); 1613 } 1614 1615 /** 1616 * Ensures the general preconditions of an InvokeInstruction instance. 1617 */ 1618 @Override 1619 public void visitInvokeInstruction(final InvokeInstruction o) { 1620 // visitLoadClass(o) has been called before: Every FieldOrMethod 1621 // implements LoadClass. 1622 // visitCPInstruction(o) has been called before. 1623 // TODO 1624 } 1625 1626 /** 1627 * Ensures the specific preconditions of the said instruction. 1628 */ 1629 @Override 1630 public void visitINVOKEINTERFACE(final INVOKEINTERFACE o) { 1631 // Method is not native, otherwise pass 3 would not happen. 1632 1633 final int count = o.getCount(); 1634 if (count == 0) { 1635 constraintViolated(o, "The 'count' argument must not be 0."); 1636 } 1637 // It is a ConstantInterfaceMethodref, Pass 3a made it sure. 1638 // TODO: Do we want to do anything with it? 1639 // ConstantInterfaceMethodref cimr = (ConstantInterfaceMethodref) (cpg.getConstant(o.getIndex())); 1640 1641 // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o). 1642 1643 final Type t = o.getType(cpg); 1644 if (t instanceof ObjectType) { 1645 final String name = ((ObjectType) t).getClassName(); 1646 final Verifier v = VerifierFactory.getVerifier(name); 1647 final VerificationResult vr = v.doPass2(); 1648 if (vr.getStatus() != VerificationResult.VERIFIED_OK) { 1649 constraintViolated(o, "Class '" + name + "' is referenced, but cannot be loaded and resolved: '" + vr + "'."); 1650 } 1651 } 1652 1653 final Type[] argtypes = o.getArgumentTypes(cpg); 1654 final int nargs = argtypes.length; 1655 1656 for (int i = nargs - 1; i >= 0; i--) { 1657 final Type fromStack = stack().peek(nargs - 1 - i); // 0 to nargs-1 1658 Type fromDesc = argtypes[i]; 1659 if (fromDesc == Type.BOOLEAN || fromDesc == Type.BYTE || fromDesc == Type.CHAR || fromDesc == Type.SHORT) { 1660 fromDesc = Type.INT; 1661 } 1662 if (!fromStack.equals(fromDesc)) { 1663 if (fromStack instanceof ReferenceType && fromDesc instanceof ReferenceType) { 1664 final ReferenceType rFromStack = (ReferenceType) fromStack; 1665 // ReferenceType rFromDesc = (ReferenceType) fromDesc; 1666 // TODO: This can only be checked when using Staerk-et-al's "set of object types" 1667 // instead of a "wider cast object type" created during verification. 1668 // if ( ! rFromStack.isAssignmentCompatibleWith(rFromDesc) ) { 1669 // constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+ 1670 // "' on the stack (which is not assignment compatible)."); 1671 // } 1672 referenceTypeIsInitialized(o, rFromStack); 1673 } else { 1674 constraintViolated(o, "Expecting a '" + fromDesc + "' but found a '" + fromStack + "' on the stack."); 1675 } 1676 } 1677 } 1678 1679 Type objref = stack().peek(nargs); 1680 if (objref == Type.NULL) { 1681 return; 1682 } 1683 if (!(objref instanceof ReferenceType)) { 1684 constraintViolated(o, "Expecting a reference type as 'objectref' on the stack, not a '" + objref + "'."); 1685 } 1686 referenceTypeIsInitialized(o, (ReferenceType) objref); 1687 if (!(objref instanceof ObjectType)) { 1688 if (!(objref instanceof ArrayType)) { // could be a ReturnaddressType 1689 constraintViolated(o, "Expecting an ObjectType as 'objectref' on the stack, not a '" + objref + "'."); 1690 } else { 1691 objref = GENERIC_ARRAY; 1692 } 1693 } 1694 1695 // String objref_classname = ((ObjectType) objref).getClassName(); 1696 // String theInterface = o.getClassName(cpg); 1697 // TODO: This can only be checked if we're using Staerk-et-al's "set of object types" 1698 // instead of "wider cast object types" generated during verification. 1699 // if ( ! Repository.implementationOf(objref_classname, theInterface) ) { 1700 // constraintViolated(o, "The 'objref' item '"+objref+"' does not implement '"+theInterface+"' as expected."); 1701 // } 1702 1703 int countedCount = 1; // 1 for the objectref 1704 for (int i = 0; i < nargs; i++) { 1705 countedCount += argtypes[i].getSize(); 1706 } 1707 if (count != countedCount) { 1708 constraintViolated(o, "The 'count' argument should probably read '" + countedCount + "' but is '" + count + "'."); 1709 } 1710 } 1711 1712 private int visitInvokeInternals(final InvokeInstruction o) throws ClassNotFoundException { 1713 final Type t = o.getType(cpg); 1714 if (t instanceof ObjectType) { 1715 final String name = ((ObjectType) t).getClassName(); 1716 final Verifier v = VerifierFactory.getVerifier(name); 1717 final VerificationResult vr = v.doPass2(); 1718 if (vr.getStatus() != VerificationResult.VERIFIED_OK) { 1719 constraintViolated(o, "Class '" + name + "' is referenced, but cannot be loaded and resolved: '" + vr + "'."); 1720 } 1721 } 1722 1723 final Type[] argtypes = o.getArgumentTypes(cpg); 1724 final int nargs = argtypes.length; 1725 1726 for (int i = nargs - 1; i >= 0; i--) { 1727 final Type fromStack = stack().peek(nargs - 1 - i); // 0 to nargs-1 1728 Type fromDesc = argtypes[i]; 1729 if (fromDesc == Type.BOOLEAN || fromDesc == Type.BYTE || fromDesc == Type.CHAR || fromDesc == Type.SHORT) { 1730 fromDesc = Type.INT; 1731 } 1732 if (!fromStack.equals(fromDesc)) { 1733 if (fromStack instanceof ReferenceType && fromDesc instanceof ReferenceType) { 1734 final ReferenceType rFromStack = (ReferenceType) fromStack; 1735 final ReferenceType rFromDesc = (ReferenceType) fromDesc; 1736 // TODO: This can possibly only be checked when using Staerk-et-al's "set of object types" instead 1737 // of a single "wider cast object type" created during verification. 1738 if (!rFromStack.isAssignmentCompatibleWith(rFromDesc)) { 1739 constraintViolated(o, 1740 "Expecting a '" + fromDesc + "' but found a '" + fromStack + "' on the stack (which is not assignment compatible)."); 1741 } 1742 referenceTypeIsInitialized(o, rFromStack); 1743 } else { 1744 constraintViolated(o, "Expecting a '" + fromDesc + "' but found a '" + fromStack + "' on the stack."); 1745 } 1746 } 1747 } 1748 return nargs; 1749 } 1750 1751 /** 1752 * Ensures the specific preconditions of the said instruction. 1753 */ 1754 @Override 1755 public void visitINVOKESPECIAL(final INVOKESPECIAL o) { 1756 try { 1757 // Don't init an object twice. 1758 if (o.getMethodName(cpg).equals(Const.CONSTRUCTOR_NAME) && !(stack().peek(o.getArgumentTypes(cpg).length) instanceof UninitializedObjectType)) { 1759 constraintViolated(o, 1760 "Possibly initializing object twice." 1761 + " A valid instruction sequence must not have an uninitialized object on the operand stack or in a local variable" 1762 + " during a backwards branch, or in a local variable in code protected by an exception handler." 1763 + " Please see The Java Virtual Machine Specification, Second Edition, 4.9.4 (pages 147 and 148) for details."); 1764 } 1765 1766 // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o). 1767 1768 final int nargs = visitInvokeInternals(o); 1769 Type objref = stack().peek(nargs); 1770 if (objref == Type.NULL) { 1771 return; 1772 } 1773 if (!(objref instanceof ReferenceType)) { 1774 constraintViolated(o, "Expecting a reference type as 'objectref' on the stack, not a '" + objref + "'."); 1775 } 1776 String objRefClassName = null; 1777 if (!o.getMethodName(cpg).equals(Const.CONSTRUCTOR_NAME)) { 1778 referenceTypeIsInitialized(o, (ReferenceType) objref); 1779 if (!(objref instanceof ObjectType)) { 1780 if (!(objref instanceof ArrayType)) { // could be a ReturnaddressType 1781 constraintViolated(o, "Expecting an ObjectType as 'objectref' on the stack, not a '" + objref + "'."); 1782 } else { 1783 objref = GENERIC_ARRAY; 1784 } 1785 } 1786 1787 objRefClassName = ((ObjectType) objref).getClassName(); 1788 } else { 1789 if (!(objref instanceof UninitializedObjectType)) { 1790 constraintViolated(o, "Expecting an UninitializedObjectType as 'objectref' on the stack, not a '" + objref 1791 + "'. Otherwise, you couldn't invoke a method since an array has no methods (not to speak of a return address)."); 1792 } 1793 objRefClassName = ((UninitializedObjectType) objref).getInitialized().getClassName(); 1794 } 1795 1796 final String theClass = o.getClassName(cpg); 1797 if (!Repository.instanceOf(objRefClassName, theClass)) { 1798 constraintViolated(o, "The 'objref' item '" + objref + "' does not implement '" + theClass + "' as expected."); 1799 } 1800 1801 } catch (final ClassNotFoundException e) { 1802 // FIXME: maybe not the best way to handle this 1803 throw new AssertionViolatedException("Missing class: " + e, e); 1804 } 1805 } 1806 1807 /** 1808 * Ensures the specific preconditions of the said instruction. 1809 */ 1810 @Override 1811 public void visitINVOKESTATIC(final INVOKESTATIC o) { 1812 try { 1813 // Method is not native, otherwise pass 3 would not happen. 1814 visitInvokeInternals(o); 1815 } catch (final ClassNotFoundException e) { 1816 // FIXME: maybe not the best way to handle this 1817 throw new AssertionViolatedException("Missing class: " + e, e); 1818 } 1819 } 1820 1821 /** 1822 * Ensures the specific preconditions of the said instruction. 1823 */ 1824 @Override 1825 public void visitINVOKEVIRTUAL(final INVOKEVIRTUAL o) { 1826 try { 1827 // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o). 1828 1829 final int nargs = visitInvokeInternals(o); 1830 Type objref = stack().peek(nargs); 1831 if (objref == Type.NULL) { 1832 return; 1833 } 1834 if (!(objref instanceof ReferenceType)) { 1835 constraintViolated(o, "Expecting a reference type as 'objectref' on the stack, not a '" + objref + "'."); 1836 } 1837 referenceTypeIsInitialized(o, (ReferenceType) objref); 1838 if (!(objref instanceof ObjectType)) { 1839 if (!(objref instanceof ArrayType)) { // could be a ReturnaddressType 1840 constraintViolated(o, "Expecting an ObjectType as 'objectref' on the stack, not a '" + objref + "'."); 1841 } else { 1842 objref = GENERIC_ARRAY; 1843 } 1844 } 1845 1846 final String objRefClassName = ((ObjectType) objref).getClassName(); 1847 1848 final String theClass = o.getClassName(cpg); 1849 1850 if (!Repository.instanceOf(objRefClassName, theClass)) { 1851 constraintViolated(o, "The 'objref' item '" + objref + "' does not implement '" + theClass + "' as expected."); 1852 } 1853 } catch (final ClassNotFoundException e) { 1854 // FIXME: maybe not the best way to handle this 1855 throw new AssertionViolatedException("Missing class: " + e, e); 1856 } 1857 } 1858 1859 /** 1860 * Ensures the specific preconditions of the said instruction. 1861 */ 1862 @Override 1863 public void visitIOR(final IOR o) { 1864 if (stack().peek() != Type.INT) { 1865 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1866 } 1867 if (stack().peek(1) != Type.INT) { 1868 constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'."); 1869 } 1870 } 1871 1872 /** 1873 * Ensures the specific preconditions of the said instruction. 1874 */ 1875 @Override 1876 public void visitIREM(final IREM o) { 1877 if (stack().peek() != Type.INT) { 1878 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1879 } 1880 if (stack().peek(1) != Type.INT) { 1881 constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'."); 1882 } 1883 } 1884 1885 /** 1886 * Ensures the specific preconditions of the said instruction. 1887 */ 1888 @Override 1889 public void visitIRETURN(final IRETURN o) { 1890 if (stack().peek() != Type.INT) { 1891 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1892 } 1893 } 1894 1895 /** 1896 * Ensures the specific preconditions of the said instruction. 1897 */ 1898 @Override 1899 public void visitISHL(final ISHL o) { 1900 if (stack().peek() != Type.INT) { 1901 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1902 } 1903 if (stack().peek(1) != Type.INT) { 1904 constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'."); 1905 } 1906 } 1907 1908 /** 1909 * Ensures the specific preconditions of the said instruction. 1910 */ 1911 @Override 1912 public void visitISHR(final ISHR o) { 1913 if (stack().peek() != Type.INT) { 1914 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1915 } 1916 if (stack().peek(1) != Type.INT) { 1917 constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'."); 1918 } 1919 } 1920 1921 /** 1922 * Ensures the specific preconditions of the said instruction. 1923 */ 1924 @Override 1925 public void visitISTORE(final ISTORE o) { 1926 // visitStoreInstruction(StoreInstruction) is called before. 1927 1928 // Nothing else needs to be done here. 1929 } 1930 1931 /** 1932 * Ensures the specific preconditions of the said instruction. 1933 */ 1934 @Override 1935 public void visitISUB(final ISUB o) { 1936 if (stack().peek() != Type.INT) { 1937 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1938 } 1939 if (stack().peek(1) != Type.INT) { 1940 constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'."); 1941 } 1942 } 1943 1944 /** 1945 * Ensures the specific preconditions of the said instruction. 1946 */ 1947 @Override 1948 public void visitIUSHR(final IUSHR o) { 1949 if (stack().peek() != Type.INT) { 1950 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1951 } 1952 if (stack().peek(1) != Type.INT) { 1953 constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'."); 1954 } 1955 } 1956 1957 /** 1958 * Ensures the specific preconditions of the said instruction. 1959 */ 1960 @Override 1961 public void visitIXOR(final IXOR o) { 1962 if (stack().peek() != Type.INT) { 1963 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 1964 } 1965 if (stack().peek(1) != Type.INT) { 1966 constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'."); 1967 } 1968 } 1969 1970 /** 1971 * Ensures the specific preconditions of the said instruction. 1972 */ 1973 @Override 1974 public void visitJSR(final JSR o) { 1975 // nothing to do here. 1976 } 1977 1978 /** 1979 * Ensures the specific preconditions of the said instruction. 1980 */ 1981 @Override 1982 public void visitJSR_W(final JSR_W o) { 1983 // nothing to do here. 1984 } 1985 1986 /** 1987 * Ensures the specific preconditions of the said instruction. 1988 */ 1989 @Override 1990 public void visitL2D(final L2D o) { 1991 if (stack().peek() != Type.LONG) { 1992 constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'."); 1993 } 1994 } 1995 1996 /** 1997 * Ensures the specific preconditions of the said instruction. 1998 */ 1999 @Override 2000 public void visitL2F(final L2F o) { 2001 if (stack().peek() != Type.LONG) { 2002 constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'."); 2003 } 2004 } 2005 2006 /** 2007 * Ensures the specific preconditions of the said instruction. 2008 */ 2009 @Override 2010 public void visitL2I(final L2I o) { 2011 if (stack().peek() != Type.LONG) { 2012 constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'."); 2013 } 2014 } 2015 2016 /** 2017 * Ensures the specific preconditions of the said instruction. 2018 */ 2019 @Override 2020 public void visitLADD(final LADD o) { 2021 if (stack().peek() != Type.LONG) { 2022 constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'."); 2023 } 2024 if (stack().peek(1) != Type.LONG) { 2025 constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'."); 2026 } 2027 } 2028 2029 /** 2030 * Ensures the specific preconditions of the said instruction. 2031 */ 2032 @Override 2033 public void visitLALOAD(final LALOAD o) { 2034 indexOfInt(o, stack().peek()); 2035 if (stack().peek(1) == Type.NULL) { 2036 return; 2037 } 2038 if (!(stack().peek(1) instanceof ArrayType)) { 2039 constraintViolated(o, "Stack next-to-top must be of type long[] but is '" + stack().peek(1) + "'."); 2040 } 2041 final Type t = ((ArrayType) stack().peek(1)).getBasicType(); 2042 if (t != Type.LONG) { 2043 constraintViolated(o, "Stack next-to-top must be of type long[] but is '" + stack().peek(1) + "'."); 2044 } 2045 } 2046 2047 /** 2048 * Ensures the specific preconditions of the said instruction. 2049 */ 2050 @Override 2051 public void visitLAND(final LAND o) { 2052 if (stack().peek() != Type.LONG) { 2053 constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'."); 2054 } 2055 if (stack().peek(1) != Type.LONG) { 2056 constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'."); 2057 } 2058 } 2059 2060 /** 2061 * Ensures the specific preconditions of the said instruction. 2062 */ 2063 @Override 2064 public void visitLASTORE(final LASTORE o) { 2065 if (stack().peek() != Type.LONG) { 2066 constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'."); 2067 } 2068 indexOfInt(o, stack().peek(1)); 2069 if (stack().peek(2) == Type.NULL) { 2070 return; 2071 } 2072 if (!(stack().peek(2) instanceof ArrayType)) { 2073 constraintViolated(o, "Stack next-to-next-to-top must be of type long[] but is '" + stack().peek(2) + "'."); 2074 } 2075 final Type t = ((ArrayType) stack().peek(2)).getBasicType(); 2076 if (t != Type.LONG) { 2077 constraintViolated(o, "Stack next-to-next-to-top must be of type long[] but is '" + stack().peek(2) + "'."); 2078 } 2079 } 2080 2081 /** 2082 * Ensures the specific preconditions of the said instruction. 2083 */ 2084 @Override 2085 public void visitLCMP(final LCMP o) { 2086 if (stack().peek() != Type.LONG) { 2087 constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'."); 2088 } 2089 if (stack().peek(1) != Type.LONG) { 2090 constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'."); 2091 } 2092 } 2093 2094 /** 2095 * Ensures the specific preconditions of the said instruction. 2096 */ 2097 @Override 2098 public void visitLCONST(final LCONST o) { 2099 // Nothing to do here. 2100 } 2101 2102 /** 2103 * Ensures the specific preconditions of the said instruction. 2104 */ 2105 @Override 2106 public void visitLDC(final LDC o) { 2107 // visitCPInstruction is called first. 2108 2109 final Constant c = cpg.getConstant(o.getIndex()); 2110 if (!(c instanceof ConstantInteger || c instanceof ConstantFloat || c instanceof ConstantString || c instanceof ConstantClass)) { 2111 constraintViolated(o, 2112 "Referenced constant should be a CONSTANT_Integer, a CONSTANT_Float, a CONSTANT_String or a CONSTANT_Class, but is '" + c + "'."); 2113 } 2114 } 2115 2116 /** 2117 * Ensures the specific preconditions of the said instruction. 2118 */ 2119 public void visitLDC_W(final LDC_W o) { 2120 // visitCPInstruction is called first. 2121 2122 final Constant c = cpg.getConstant(o.getIndex()); 2123 if (!(c instanceof ConstantInteger || c instanceof ConstantFloat || c instanceof ConstantString || c instanceof ConstantClass)) { 2124 constraintViolated(o, 2125 "Referenced constant should be a CONSTANT_Integer, a CONSTANT_Float, a CONSTANT_String or a CONSTANT_Class, but is '" + c + "'."); 2126 } 2127 } 2128 2129 /** 2130 * Ensures the specific preconditions of the said instruction. 2131 */ 2132 @Override 2133 public void visitLDC2_W(final LDC2_W o) { 2134 // visitCPInstruction is called first. 2135 2136 final Constant c = cpg.getConstant(o.getIndex()); 2137 if (!(c instanceof ConstantLong || c instanceof ConstantDouble)) { 2138 constraintViolated(o, "Referenced constant should be a CONSTANT_Integer, a CONSTANT_Float or a CONSTANT_String, but is '" + c + "'."); 2139 } 2140 } 2141 2142 /** 2143 * Ensures the specific preconditions of the said instruction. 2144 */ 2145 @Override 2146 public void visitLDIV(final LDIV o) { 2147 if (stack().peek() != Type.LONG) { 2148 constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'."); 2149 } 2150 if (stack().peek(1) != Type.LONG) { 2151 constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'."); 2152 } 2153 } 2154 2155 /** 2156 * Ensures the specific preconditions of the said instruction. 2157 */ 2158 @Override 2159 public void visitLLOAD(final LLOAD o) { 2160 // visitLoadInstruction(LoadInstruction) is called before. 2161 2162 // Nothing else needs to be done here. 2163 } 2164 2165 /** 2166 * Ensures the specific preconditions of the said instruction. 2167 */ 2168 @Override 2169 public void visitLMUL(final LMUL o) { 2170 if (stack().peek() != Type.LONG) { 2171 constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'."); 2172 } 2173 if (stack().peek(1) != Type.LONG) { 2174 constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'."); 2175 } 2176 } 2177 2178 /** 2179 * Ensures the specific preconditions of the said instruction. 2180 */ 2181 @Override 2182 public void visitLNEG(final LNEG o) { 2183 if (stack().peek() != Type.LONG) { 2184 constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'."); 2185 } 2186 } 2187 2188 /** 2189 * Assures the generic preconditions of a LoadClass instance. The referenced class is loaded and pass2-verified. 2190 */ 2191 @Override 2192 public void visitLoadClass(final LoadClass o) { 2193 final ObjectType t = o.getLoadClassType(cpg); 2194 if (t != null) {// null means "no class is loaded" 2195 final Verifier v = VerifierFactory.getVerifier(t.getClassName()); 2196 final VerificationResult vr = v.doPass2(); 2197 if (vr.getStatus() != VerificationResult.VERIFIED_OK) { 2198 constraintViolated((Instruction) o, 2199 "Class '" + o.getLoadClassType(cpg).getClassName() + "' is referenced, but cannot be loaded and resolved: '" + vr + "'."); 2200 } 2201 } 2202 } 2203 2204 /** 2205 * Assures the generic preconditions of a LoadInstruction instance. 2206 */ 2207 @Override 2208 public void visitLoadInstruction(final LoadInstruction o) { 2209 // visitLocalVariableInstruction(o) is called before, because it is more generic. 2210 2211 // LOAD instructions must not read Type.UNKNOWN 2212 if (locals().get(o.getIndex()) == Type.UNKNOWN) { 2213 constraintViolated(o, "Read-Access on local variable " + o.getIndex() + " with unknown content."); 2214 } 2215 2216 // LOAD instructions, two-slot-values at index N must have Type.UNKNOWN 2217 // as a symbol for the higher halve at index N+1 2218 // [suppose some instruction put an int at N+1--- our double at N is defective] 2219 if (o.getType(cpg).getSize() == 2 && locals().get(o.getIndex() + 1) != Type.UNKNOWN) { 2220 constraintViolated(o, 2221 "Reading a two-locals value from local variables " + o.getIndex() + " and " + (o.getIndex() + 1) + " where the latter one is destroyed."); 2222 } 2223 2224 // LOAD instructions must read the correct type. 2225 if (!(o instanceof ALOAD)) { 2226 if (locals().get(o.getIndex()) != o.getType(cpg)) { 2227 constraintViolated(o, "Local Variable type and LOADing Instruction type mismatch: Local Variable: '" + locals().get(o.getIndex()) 2228 + "'; Instruction type: '" + o.getType(cpg) + "'."); 2229 } 2230 } else if (!(locals().get(o.getIndex()) instanceof ReferenceType)) { 2231 constraintViolated(o, "Local Variable type and LOADing Instruction type mismatch: Local Variable: '" + locals().get(o.getIndex()) 2232 + "'; Instruction expects a ReferenceType."); 2233 } 2234 // ALOAD __IS ALLOWED__ to put uninitialized objects onto the stack! 2235 // referenceTypeIsInitialized(o, (ReferenceType) (locals().get(o.getIndex()))); 2236 2237 // LOAD instructions must have enough free stack slots. 2238 if (stack().maxStack() - stack().slotsUsed() < o.getType(cpg).getSize()) { 2239 constraintViolated(o, "Not enough free stack slots to load a '" + o.getType(cpg) + "' onto the OperandStack."); 2240 } 2241 } 2242 2243 /** 2244 * Assures the generic preconditions of a LocalVariableInstruction instance. That is, the index of the local variable 2245 * must be valid. 2246 */ 2247 @Override 2248 public void visitLocalVariableInstruction(final LocalVariableInstruction o) { 2249 if (locals().maxLocals() <= (o.getType(cpg).getSize() == 1 ? o.getIndex() : o.getIndex() + 1)) { 2250 constraintViolated(o, "The 'index' is not a valid index into the local variable array."); 2251 } 2252 } 2253 2254 /** 2255 * Ensures the specific preconditions of the said instruction. 2256 */ 2257 @Override 2258 public void visitLOOKUPSWITCH(final LOOKUPSWITCH o) { 2259 if (stack().peek() != Type.INT) { 2260 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 2261 } 2262 // See also pass 3a. 2263 } 2264 2265 /** 2266 * Ensures the specific preconditions of the said instruction. 2267 */ 2268 @Override 2269 public void visitLOR(final LOR o) { 2270 if (stack().peek() != Type.LONG) { 2271 constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'."); 2272 } 2273 if (stack().peek(1) != Type.LONG) { 2274 constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'."); 2275 } 2276 } 2277 2278 /** 2279 * Ensures the specific preconditions of the said instruction. 2280 */ 2281 @Override 2282 public void visitLREM(final LREM o) { 2283 if (stack().peek() != Type.LONG) { 2284 constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'."); 2285 } 2286 if (stack().peek(1) != Type.LONG) { 2287 constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'."); 2288 } 2289 } 2290 2291 /** 2292 * Ensures the specific preconditions of the said instruction. 2293 */ 2294 @Override 2295 public void visitLRETURN(final LRETURN o) { 2296 if (stack().peek() != Type.LONG) { 2297 constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'."); 2298 } 2299 } 2300 2301 /** 2302 * Ensures the specific preconditions of the said instruction. 2303 */ 2304 @Override 2305 public void visitLSHL(final LSHL o) { 2306 if (stack().peek() != Type.INT) { 2307 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 2308 } 2309 if (stack().peek(1) != Type.LONG) { 2310 constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'."); 2311 } 2312 } 2313 2314 /** 2315 * Ensures the specific preconditions of the said instruction. 2316 */ 2317 @Override 2318 public void visitLSHR(final LSHR o) { 2319 if (stack().peek() != Type.INT) { 2320 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 2321 } 2322 if (stack().peek(1) != Type.LONG) { 2323 constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'."); 2324 } 2325 } 2326 2327 /** 2328 * Ensures the specific preconditions of the said instruction. 2329 */ 2330 @Override 2331 public void visitLSTORE(final LSTORE o) { 2332 // visitStoreInstruction(StoreInstruction) is called before. 2333 2334 // Nothing else needs to be done here. 2335 } 2336 2337 /** 2338 * Ensures the specific preconditions of the said instruction. 2339 */ 2340 @Override 2341 public void visitLSUB(final LSUB o) { 2342 if (stack().peek() != Type.LONG) { 2343 constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'."); 2344 } 2345 if (stack().peek(1) != Type.LONG) { 2346 constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'."); 2347 } 2348 } 2349 2350 /** 2351 * Ensures the specific preconditions of the said instruction. 2352 */ 2353 @Override 2354 public void visitLUSHR(final LUSHR o) { 2355 if (stack().peek() != Type.INT) { 2356 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 2357 } 2358 if (stack().peek(1) != Type.LONG) { 2359 constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'."); 2360 } 2361 } 2362 2363 /** 2364 * Ensures the specific preconditions of the said instruction. 2365 */ 2366 @Override 2367 public void visitLXOR(final LXOR o) { 2368 if (stack().peek() != Type.LONG) { 2369 constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'."); 2370 } 2371 if (stack().peek(1) != Type.LONG) { 2372 constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'."); 2373 } 2374 } 2375 2376 /** 2377 * Ensures the specific preconditions of the said instruction. 2378 */ 2379 @Override 2380 public void visitMONITORENTER(final MONITORENTER o) { 2381 if (!(stack().peek() instanceof ReferenceType)) { 2382 constraintViolated(o, "The stack top should be of a ReferenceType, but is '" + stack().peek() + "'."); 2383 } 2384 // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) ); 2385 } 2386 2387 /** 2388 * Ensures the specific preconditions of the said instruction. 2389 */ 2390 @Override 2391 public void visitMONITOREXIT(final MONITOREXIT o) { 2392 if (!(stack().peek() instanceof ReferenceType)) { 2393 constraintViolated(o, "The stack top should be of a ReferenceType, but is '" + stack().peek() + "'."); 2394 } 2395 // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) ); 2396 } 2397 2398 /** 2399 * Ensures the specific preconditions of the said instruction. 2400 */ 2401 @Override 2402 public void visitMULTIANEWARRAY(final MULTIANEWARRAY o) { 2403 final int dimensions = o.getDimensions(); 2404 // Dimensions argument is okay: see Pass 3a. 2405 for (int i = 0; i < dimensions; i++) { 2406 if (stack().peek(i) != Type.INT) { 2407 constraintViolated(o, "The '" + dimensions + "' upper stack types should be 'int' but aren't."); 2408 } 2409 } 2410 // The runtime constant pool item at that index must be a symbolic reference to a class, 2411 // array, or interface type. See Pass 3a. 2412 } 2413 2414 /** 2415 * Ensures the specific preconditions of the said instruction. 2416 */ 2417 @Override 2418 public void visitNEW(final NEW o) { 2419 // visitCPInstruction(CPInstruction) has been called before. 2420 // visitLoadClass(LoadClass) has been called before. 2421 2422 final Type t = o.getType(cpg); 2423 if (!(t instanceof ReferenceType)) { 2424 throw new AssertionViolatedException("NEW.getType() returning a non-reference type?!"); 2425 } 2426 if (!(t instanceof ObjectType)) { 2427 constraintViolated(o, "Expecting a class type (ObjectType) to work on. Found: '" + t + "'."); 2428 } 2429 final ObjectType obj = (ObjectType) t; 2430 2431 // e.g.: Don't instantiate interfaces 2432 try { 2433 if (!obj.referencesClassExact()) { 2434 constraintViolated(o, "Expecting a class type (ObjectType) to work on. Found: '" + obj + "'."); 2435 } 2436 } catch (final ClassNotFoundException e) { 2437 constraintViolated(o, "Expecting a class type (ObjectType) to work on. Found: '" + obj + "'." + " which threw " + e); 2438 } 2439 } 2440 2441 /** 2442 * Ensures the specific preconditions of the said instruction. 2443 */ 2444 @Override 2445 public void visitNEWARRAY(final NEWARRAY o) { 2446 if (stack().peek() != Type.INT) { 2447 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 2448 } 2449 } 2450 2451 /** 2452 * Ensures the specific preconditions of the said instruction. 2453 */ 2454 @Override 2455 public void visitNOP(final NOP o) { 2456 // nothing is to be done here. 2457 } 2458 2459 /** 2460 * Ensures the specific preconditions of the said instruction. 2461 */ 2462 @Override 2463 public void visitPOP(final POP o) { 2464 if (stack().peek().getSize() != 1) { 2465 constraintViolated(o, "Stack top size should be 1 but stack top is '" + stack().peek() + "' of size '" + stack().peek().getSize() + "'."); 2466 } 2467 } 2468 2469 /** 2470 * Ensures the specific preconditions of the said instruction. 2471 */ 2472 @Override 2473 public void visitPOP2(final POP2 o) { 2474 if (stack().peek().getSize() != 2) { 2475 constraintViolated(o, "Stack top size should be 2 but stack top is '" + stack().peek() + "' of size '" + stack().peek().getSize() + "'."); 2476 } 2477 } 2478 2479 /** 2480 * Ensures the specific preconditions of the said instruction. 2481 */ 2482 @Override 2483 public void visitPUTFIELD(final PUTFIELD o) { 2484 try { 2485 2486 final Type objectref = stack().peek(1); 2487 if (!(objectref instanceof ObjectType || objectref == Type.NULL)) { 2488 constraintViolated(o, "Stack next-to-top should be an object reference that's not an array reference, but is '" + objectref + "'."); 2489 } 2490 2491 final Field f = visitFieldInstructionInternals(o); 2492 2493 if (f.isProtected()) { 2494 final ObjectType classtype = getObjectType(o); 2495 final ObjectType curr = ObjectType.getInstance(mg.getClassName()); 2496 2497 if (classtype.equals(curr) || curr.subclassOf(classtype)) { 2498 final Type tp = stack().peek(1); 2499 if (tp == Type.NULL) { 2500 return; 2501 } 2502 if (!(tp instanceof ObjectType)) { 2503 constraintViolated(o, "The 'objectref' must refer to an object that's not an array. Found instead: '" + tp + "'."); 2504 } 2505 final ObjectType objreftype = (ObjectType) tp; 2506 if (!(objreftype.equals(curr) || objreftype.subclassOf(curr))) { 2507 constraintViolated(o, 2508 "The referenced field has the ACC_PROTECTED modifier, and it's a member of the current class or" 2509 + " a superclass of the current class. However, the referenced object type '" + stack().peek() 2510 + "' is not the current class or a subclass of the current class."); 2511 } 2512 } 2513 } 2514 2515 // TODO: Could go into Pass 3a. 2516 if (f.isStatic()) { 2517 constraintViolated(o, "Referenced field '" + f + "' is static which it shouldn't be."); 2518 } 2519 2520 } catch (final ClassNotFoundException e) { 2521 // FIXME: maybe not the best way to handle this 2522 throw new AssertionViolatedException("Missing class: " + e, e); 2523 } 2524 } 2525 2526 /** 2527 * Ensures the specific preconditions of the said instruction. 2528 */ 2529 @Override 2530 public void visitPUTSTATIC(final PUTSTATIC o) { 2531 try { 2532 visitFieldInstructionInternals(o); 2533 } catch (final ClassNotFoundException e) { 2534 // FIXME: maybe not the best way to handle this 2535 throw new AssertionViolatedException("Missing class: " + e, e); 2536 } 2537 } 2538 2539 /** 2540 * Ensures the specific preconditions of the said instruction. 2541 */ 2542 @Override 2543 public void visitRET(final RET o) { 2544 if (!(locals().get(o.getIndex()) instanceof ReturnaddressType)) { 2545 constraintViolated(o, "Expecting a ReturnaddressType in local variable " + o.getIndex() + "."); 2546 } 2547 if (locals().get(o.getIndex()) == ReturnaddressType.NO_TARGET) { 2548 throw new AssertionViolatedException("RET expecting a target!"); 2549 } 2550 // Other constraints such as non-allowed overlapping subroutines are enforced 2551 // while building the Subroutines data structure. 2552 } 2553 2554 /** 2555 * Ensures the specific preconditions of the said instruction. 2556 */ 2557 @Override 2558 public void visitRETURN(final RETURN o) { 2559 if (mg.getName().equals(Const.CONSTRUCTOR_NAME) && Frame.getThis() != null && !mg.getClassName().equals(Type.OBJECT.getClassName())) { 2560 constraintViolated(o, "Leaving a constructor that itself did not call a constructor."); 2561 } 2562 } 2563 2564 /** 2565 * Assures the generic preconditions of a ReturnInstruction instance. 2566 */ 2567 @Override 2568 public void visitReturnInstruction(final ReturnInstruction o) { 2569 Type methodType = mg.getType(); 2570 if (methodType == Type.BOOLEAN || methodType == Type.BYTE || methodType == Type.SHORT || methodType == Type.CHAR) { 2571 methodType = Type.INT; 2572 } 2573 2574 if (o instanceof RETURN) { 2575 if (methodType == Type.VOID) { 2576 return; 2577 } 2578 constraintViolated(o, "RETURN instruction in non-void method."); 2579 } 2580 if (o instanceof ARETURN) { 2581 if (methodType == Type.VOID) { 2582 constraintViolated(o, "ARETURN instruction in void method."); 2583 } 2584 if (stack().peek() == Type.NULL) { 2585 return; 2586 } 2587 if (!(stack().peek() instanceof ReferenceType)) { 2588 constraintViolated(o, "Reference type expected on top of stack, but is: '" + stack().peek() + "'."); 2589 } 2590 referenceTypeIsInitialized(o, (ReferenceType) stack().peek()); 2591 // ReferenceType objectref = (ReferenceType) (stack().peek()); 2592 // TODO: This can only be checked if using Staerk-et-al's "set of object types" instead of a 2593 // "wider cast object type" created during verification. 2594 // if (! (objectref.isAssignmentCompatibleWith(mg.getType())) ) { 2595 // constraintViolated(o, "Type on stack top which should be returned is a '"+stack().peek()+ 2596 // "' which is not assignment compatible with the return type of this method, '"+mg.getType()+"'."); 2597 // } 2598 } else if (!methodType.equals(stack().peek())) { 2599 constraintViolated(o, "Current method has return type of '" + mg.getType() + "' expecting a '" + methodType 2600 + "' on top of the stack. But stack top is a '" + stack().peek() + "'."); 2601 } 2602 } 2603 2604 /** 2605 * Ensures the specific preconditions of the said instruction. 2606 */ 2607 @Override 2608 public void visitSALOAD(final SALOAD o) { 2609 indexOfInt(o, stack().peek()); 2610 if (stack().peek(1) == Type.NULL) { 2611 return; 2612 } 2613 if (!(stack().peek(1) instanceof ArrayType)) { 2614 constraintViolated(o, "Stack next-to-top must be of type short[] but is '" + stack().peek(1) + "'."); 2615 } 2616 final Type t = ((ArrayType) stack().peek(1)).getBasicType(); 2617 if (t != Type.SHORT) { 2618 constraintViolated(o, "Stack next-to-top must be of type short[] but is '" + stack().peek(1) + "'."); 2619 } 2620 } 2621 2622 /** 2623 * Ensures the specific preconditions of the said instruction. 2624 */ 2625 @Override 2626 public void visitSASTORE(final SASTORE o) { 2627 if (stack().peek() != Type.INT) { 2628 constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'."); 2629 } 2630 indexOfInt(o, stack().peek(1)); 2631 if (stack().peek(2) == Type.NULL) { 2632 return; 2633 } 2634 if (!(stack().peek(2) instanceof ArrayType)) { 2635 constraintViolated(o, "Stack next-to-next-to-top must be of type short[] but is '" + stack().peek(2) + "'."); 2636 } 2637 final Type t = ((ArrayType) stack().peek(2)).getBasicType(); 2638 if (t != Type.SHORT) { 2639 constraintViolated(o, "Stack next-to-next-to-top must be of type short[] but is '" + stack().peek(2) + "'."); 2640 } 2641 } 2642 2643 /** 2644 * Ensures the specific preconditions of the said instruction. 2645 */ 2646 @Override 2647 public void visitSIPUSH(final SIPUSH o) { 2648 // nothing to do here. Generic visitXXX() methods did the trick before. 2649 } 2650 2651 /** 2652 * Ensures the general preconditions of a StackConsumer instance. 2653 */ 2654 @Override 2655 public void visitStackConsumer(final StackConsumer o) { 2656 _visitStackAccessor((Instruction) o); 2657 } 2658 2659 /** 2660 * Ensures the general preconditions of a StackInstruction instance. 2661 */ 2662 @Override 2663 public void visitStackInstruction(final StackInstruction o) { 2664 _visitStackAccessor(o); 2665 } 2666 2667 /** 2668 * Ensures the general preconditions of a StackProducer instance. 2669 */ 2670 @Override 2671 public void visitStackProducer(final StackProducer o) { 2672 _visitStackAccessor((Instruction) o); 2673 } 2674 2675 /** 2676 * Assures the generic preconditions of a StoreInstruction instance. 2677 */ 2678 @Override 2679 public void visitStoreInstruction(final StoreInstruction o) { 2680 // visitLocalVariableInstruction(o) is called before, because it is more generic. 2681 2682 if (stack().isEmpty()) { // Don't bother about 1 or 2 stack slots used. This check is implicitly done below while type checking. 2683 constraintViolated(o, "Cannot STORE: Stack to read from is empty."); 2684 } 2685 2686 if (!(o instanceof ASTORE)) { 2687 if (!(stack().peek() == o.getType(cpg))) {// the other xSTORE types are singletons in BCEL. 2688 constraintViolated(o, 2689 "Stack top type and STOREing Instruction type mismatch: Stack top: '" + stack().peek() + "'; Instruction type: '" + o.getType(cpg) + "'."); 2690 } 2691 } else { // we deal with ASTORE 2692 final Type stacktop = stack().peek(); 2693 if (!(stacktop instanceof ReferenceType) && !(stacktop instanceof ReturnaddressType)) { 2694 constraintViolated(o, "Stack top type and STOREing Instruction type mismatch: Stack top: '" + stack().peek() 2695 + "'; Instruction expects a ReferenceType or a ReturnadressType."); 2696 } 2697 // if (stacktop instanceof ReferenceType) { 2698 // referenceTypeIsInitialized(o, (ReferenceType) stacktop); 2699 // } 2700 } 2701 } 2702 2703 /** 2704 * Ensures the specific preconditions of the said instruction. 2705 */ 2706 @Override 2707 public void visitSWAP(final SWAP o) { 2708 if (stack().peek().getSize() != 1) { 2709 constraintViolated(o, "The value at the stack top is not of size '1', but of size '" + stack().peek().getSize() + "'."); 2710 } 2711 if (stack().peek(1).getSize() != 1) { 2712 constraintViolated(o, "The value at the stack next-to-top is not of size '1', but of size '" + stack().peek(1).getSize() + "'."); 2713 } 2714 } 2715 2716 /** 2717 * Ensures the specific preconditions of the said instruction. 2718 */ 2719 @Override 2720 public void visitTABLESWITCH(final TABLESWITCH o) { 2721 indexOfInt(o, stack().peek()); 2722 // See Pass 3a. 2723 } 2724 2725}