    View Javadoc
    1   package org.apache.bcel.verifier.statics;
    2
    3   /* ====================================================================
    4    * The Apache Software License, Version 1.1
    5    *
    6    * Copyright (c) 2001 The Apache Software Foundation.  All rights
    7    * reserved.
    8    *
    9    * Redistribution and use in source and binary forms, with or without
    10   * modification, are permitted provided that the following conditions
    11   * are met:
    12   *
    13   * 1. Redistributions of source code must retain the above copyright
    14   *    notice, this list of conditions and the following disclaimer.
    15   *
    16   * 2. Redistributions in binary form must reproduce the above copyright
    17   *    notice, this list of conditions and the following disclaimer in
    18   *    the documentation and/or other materials provided with the
    19   *    distribution.
    20   *
    21   * 3. The end-user documentation included with the redistribution,
    22   *    if any, must include the following acknowledgment:
    23   *       "This product includes software developed by the
    24   *        Apache Software Foundation (http://www.apache.org/)."
    25   *    Alternately, this acknowledgment may appear in the software itself,
    26   *    if and wherever such third-party acknowledgments normally appear.
    27   *
    28   * 4. The names "Apache" and "Apache Software Foundation" and
    29   *    "Apache BCEL" must not be used to endorse or promote products
    30   *    derived from this software without prior written permission. For
    31   *    written permission, please contact apache@apache.org.
    32   *
    33   * 5. Products derived from this software may not be called "Apache",
    34   *    "Apache BCEL", nor may "Apache" appear in their name, without
    35   *    prior written permission of the Apache Software Foundation.
    36   *
    37   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
    38   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    39   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    40   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
    41   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    42   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    43   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
    44   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    45   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    46   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    47   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    48   * SUCH DAMAGE.
    49   * ====================================================================
    50   *
    51   * This software consists of voluntary contributions made by many
    52   * individuals on behalf of the Apache Software Foundation.  For more
    53   * information on the Apache Software Foundation, please see
    54   * <http://www.apache.org/>;.
    55   */
    56
    57  import org.apache.bcel.*;
    58  import org.apache.bcel.generic.*;
    59  import org.apache.bcel.classfile.*;
    60  import org.apache.bcel.verifier.*;
    61  import org.apache.bcel.verifier.exc.*;
    62
    63  /***
    64   * This PassVerifier verifies a class file according to
    65   * pass 3, static part as described in The Java Virtual
    66   * Machine Specification, 2nd edition.
    67   * More detailed information is to be found at the do_verify()
    68   * method's documentation.
    69   *
    70   * @version $Id: Pass3aVerifier.java,v 1.3 2002/06/13 09:32:50 enver Exp $
    71   * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
    72   * @see #do_verify()
    73   */
    74  public final class Pass3aVerifier extends PassVerifier{
    75
    76  	/*** The Verifier that created this. */
    77  	private Verifier myOwner;
    78
    79  	/***
    80  	 * The method number to verify.
    81  	 * This is the index in the array returned
    82  	 * by JavaClass.getMethods().
    83  	 */
    84  	private int method_no;
    85
    86  	/*** The one and only InstructionList object used by an instance of this class. It's here for performance reasons by do_verify() and its callees. */
    87  	InstructionList instructionList;
    88  	/*** The one and only Code object used by an instance of this class. It's here for performance reasons by do_verify() and its callees. */
    89  	Code code;
    90
    91  	/*** Should only be instantiated by a Verifier. */
    92  	public Pass3aVerifier(Verifier owner, int method_no){
    93  		myOwner = owner;
    94  		this.method_no = method_no;
    95  	}
    96
    97  	/***
    98  	 * Pass 3a is the verification of static constraints of
    99  	 * JVM code (such as legal targets of branch instructions).
    100 	 * This is the part of pass 3 where you do not need data
    101 	 * flow analysis.
    102 	 * JustIce also delays the checks for a correct exception
    103 	 * table of a Code attribute and correct line number entries
    104 	 * in a LineNumberTable attribute of a Code attribute (which
    105 	 * conceptually belong to pass 2) to this pass. Also, most
    106 	 * of the check for valid local variable entries in a
    107 	 * LocalVariableTable attribute of a Code attribute is
    108 	 * delayed until this pass.
    109 	 * All these checks need access to the code array of the
    110 	 * Code attribute.
    111 	 *
    112 	 * @throws InvalidMethodException if the method to verify does not exist.
    113 	 */
    114 	public VerificationResult do_verify(){
    115 		if (myOwner.doPass2().equals(VerificationResult.VR_OK)){
    116 			// Okay, class file was loaded correctly by Pass 1
    117 			// and satisfies static constraints of Pass 2.
    118 			JavaClass jc = Repository.lookupClass(myOwner.getClassName());
    119 			Method[] methods = jc.getMethods();
    120 			if (method_no >= methods.length){
    121 				throw new InvalidMethodException("METHOD DOES NOT EXIST!");
    122 			}
    123 			Method method = methods[method_no];
    124 			code = method.getCode();
    125
    126 			// No Code? Nothing to verify!
    127 			if ( method.isAbstract() || method.isNative() ){ // IF mg HAS NO CODE (static constraint of Pass 2)
    128 				return VerificationResult.VR_OK;
    129 			}
    130
    131 			// TODO:
    132 			// We want a very sophisticated code examination here with good explanations
    133 			// on where to look for an illegal instruction or such.
    134 			// Only after that we should try to build an InstructionList and throw an
    135 			// AssertionViolatedException if after our examination InstructionList building
    136 			// still fails.
    137 			// That examination should be implemented in a byte-oriented way, i.e. look for
    138 			// an instruction, make sure its validity, count its length, find the next
    139 			// instruction and so on.
    140 			try{
    141 				instructionList = new InstructionList(method.getCode().getCode());
    142 			}
    143 			catch(RuntimeException re){
    144 				return new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Bad bytecode in the code array of the Code attribute of method '"+method+"'.");
    145 			}
    146
    147 			instructionList.setPositions(true);
    148
    149 			// Start verification.
    150 			VerificationResult vr = VerificationResult.VR_OK; //default
    151 			try{
    152 				delayedPass2Checks();
    153 			}
    154 			catch(ClassConstraintException cce){
    155 				vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, cce.getMessage());
    156 				return vr;
    157 			}
    158 			try{
    159 				pass3StaticInstructionChecks();
    160 				pass3StaticInstructionOperandsChecks();
    161 			}
    162 			catch(StaticCodeConstraintException scce){
    163 				vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, scce.getMessage());
    164 			}
    165 			return vr;
    166 		}
    167 		else{ //did not pass Pass 2.
    168 			return VerificationResult.VR_NOTYET;
    169 		}
    170 	}
    171
    172 	/***
    173 	 * These are the checks that could be done in pass 2 but are delayed to pass 3
    174 	 * for performance reasons. Also, these checks need access to the code array
    175 	 * of the Code attribute of a Method so it's okay to perform them here.
    176 	 * Also see the description of the do_verify() method.
    177 	 *
    178 	 * @throws ClassConstraintException if the verification fails.
    179 	 * @see #do_verify()
    180 	 */
    181 	private void delayedPass2Checks(){
    182
    183 		int[] instructionPositions = instructionList.getInstructionPositions();
    184 		int codeLength = code.getCode().length;
    185
    186 		/////////////////////
    187 		// LineNumberTable //
    188 		/////////////////////
    189 		LineNumberTable lnt = code.getLineNumberTable();
    190 		if (lnt != null){
    191 			LineNumber[] lineNumbers = lnt.getLineNumberTable();
    192 			IntList offsets = new IntList();
    193 			lineNumber_loop: for (int i=0; i < lineNumbers.length; i++){ // may appear in any order.
    194 				for (int j=0; j < instructionPositions.length; j++){
    195 					// TODO: Make this a binary search! The instructionPositions array is naturally ordered!
    196 					int offset = lineNumbers[i].getStartPC();
    197 					if (instructionPositions[j] == offset){
    198 						if (offsets.contains(offset)){
    199 							addMessage("LineNumberTable attribute '"+code.getLineNumberTable()+"' refers to the same code offset ('"+offset+"') more than once which is violating the semantics [but is sometimes produced by IBM's 'jikes' compiler].");
    200 						}
    201 						else{
    202 							offsets.add(offset);
    203 						}
    204 						continue lineNumber_loop;
    205 					}
    206 				}
    207 				throw new ClassConstraintException("Code attribute '"+code+"' has a LineNumberTable attribute '"+code.getLineNumberTable()+"' referring to a code offset ('"+lineNumbers[i].getStartPC()+"') that does not exist.");
    208 			}
    209 		}
    210
    211 		///////////////////////////
    212 		// LocalVariableTable(s) //
    213 		///////////////////////////
    214 		/* We cannot use code.getLocalVariableTable() because there could be more
    215 		   than only one. This is a bug in BCEL. */
    216 		Attribute[] atts = code.getAttributes();
    217 		for (int a=0; a<atts.length; a++){
    218 			if (atts[a] instanceof LocalVariableTable){
    219 				LocalVariableTable lvt = (LocalVariableTable) atts[a];
    220 				if (lvt != null){
    221 					LocalVariable[] localVariables = lvt.getLocalVariableTable();
    222 					for (int i=0; i<localVariables.length; i++){
    223 						int startpc = localVariables[i].getStartPC();
    224 						int length  = localVariables[i].getLength();
    225
    226 						if (!contains(instructionPositions, startpc)){
    227 							throw new ClassConstraintException("Code attribute '"+code+"' has a LocalVariableTable attribute '"+code.getLocalVariableTable()+"' referring to a code offset ('"+startpc+"') that does not exist.");
    228 						}
    229 						if ( (!contains(instructionPositions, startpc+length)) && (startpc+length != codeLength) ){
    230 							throw new ClassConstraintException("Code attribute '"+code+"' has a LocalVariableTable attribute '"+code.getLocalVariableTable()+"' referring to a code offset start_pc+length ('"+(startpc+length)+"') that does not exist.");
    231 						}
    232 					}
    233 				}
    234 			}
    235 		}
    236
    237 		////////////////////
    238 		// ExceptionTable //
    239 		////////////////////
    240 		// In BCEL's "classfile" API, the startPC/endPC-notation is
    241 		// inclusive/exclusive as in the Java Virtual Machine Specification.
    242 		// WARNING: This is not true for BCEL's "generic" API.
    243 		CodeException[] exceptionTable = code.getExceptionTable();
    244 		for (int i=0; i<exceptionTable.length; i++){
    245 			int startpc = exceptionTable[i].getStartPC();
    246 			int endpc = exceptionTable[i].getEndPC();
    247 			int handlerpc = exceptionTable[i].getHandlerPC();
    248 			if (startpc >= endpc){
    249 				throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has its start_pc ('"+startpc+"') not smaller than its end_pc ('"+endpc+"').");
    250 			}
    251 			if (!contains(instructionPositions, startpc)){
    252 				throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has a non-existant bytecode offset as its start_pc ('"+startpc+"').");
    253 			}
    254 			if ( (!contains(instructionPositions, endpc)) && (endpc != codeLength)){
    255 				throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has a non-existant bytecode offset as its end_pc ('"+startpc+"') [that is also not equal to code_length ('"+codeLength+"')].");
    256 			}
    257 			if (!contains(instructionPositions, handlerpc)){
    258 				throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has a non-existant bytecode offset as its handler_pc ('"+handlerpc+"').");
    259 			}
    260 		}
    261 	}
    262
    263 	/***
    264 	 * These are the checks if constraints are satisfied which are described in the
    265 	 * Java Virtual Machine Specification, Second Edition as Static Constraints on
    266 	 * the instructions of Java Virtual Machine Code (chapter 4.8.1).
    267 	 *
    268 	 * @throws StaticCodeConstraintException if the verification fails.
    269 	 */
    270 	private void pass3StaticInstructionChecks(){
    271
    272 		// Code array must not be empty:
    273 		// Enforced in pass 2 (also stated in the static constraints of the Code
    274 		// array in vmspec2), together with pass 1 (reading code_length bytes and
    275 		// interpreting them as code[]). So this must not be checked again here.
    276
    277 		if (! (code.getCode().length < 65536)){// contradicts vmspec2 page 152 ("Limitations"), but is on page 134.
    278 			throw new StaticCodeInstructionConstraintException("Code array in code attribute '"+code+"' too big: must be smaller than 65536 bytes.");
    279 		}
    280
    281 		// First opcode at offset 0: okay, that's clear. Nothing to do.
    282
    283 		// Only instances of the instructions documented in Section 6.4 may appear in
    284 		// the code array.
    285
    286 		// For BCEL's sake, we cannot handle WIDE stuff, but hopefully BCEL does its job right :)
    287
    288 		// The last byte of the last instruction in the code array must be the byte at index
    289 		// code_length-1 : See the do_verify() comments. We actually don't iterate through the
    290 		// byte array, but use an InstructionList so we cannot check for this. But BCEL does
    291 		// things right, so it's implicitly okay.
    292
    293 		// TODO: Check how BCEL handles (and will handle) instructions like IMPDEP1, IMPDEP2,
    294 		//       BREAKPOINT... that BCEL knows about but which are illegal anyway.
    295 		//       We currently go the safe way here.
    296 		InstructionHandle ih = instructionList.getStart();
    297 		while (ih != null){
    298 			Instruction i = ih.getInstruction();
    299 			if (i instanceof IMPDEP1){
    300 				throw new StaticCodeInstructionConstraintException("IMPDEP1 must not be in the code, it is an illegal instruction for _internal_ JVM use!");
    301 			}
    302 			if (i instanceof IMPDEP2){
    303 				throw new StaticCodeInstructionConstraintException("IMPDEP2 must not be in the code, it is an illegal instruction for _internal_ JVM use!");
    304 			}
    305 			if (i instanceof BREAKPOINT){
    306 				throw new StaticCodeInstructionConstraintException("BREAKPOINT must not be in the code, it is an illegal instruction for _internal_ JVM use!");
    307 			}
    308 			ih = ih.getNext();
    309 		}
    310
    311 		// The original verifier seems to do this check here, too.
    312 		// An unreachable last instruction may also not fall through the
    313 		// end of the code, which is stupid -- but with the original
    314 		// verifier's subroutine semantics one cannot predict reachability.
    315 		Instruction last = instructionList.getEnd().getInstruction();
    316 		if (! ((last instanceof ReturnInstruction)	||
    317 					(last instanceof RET)    							||
    318 					(last instanceof GotoInstruction)			||
    319 					(last instanceof ATHROW) )) // JSR / JSR_W would possibly RETurn and then fall off the code!
    320 			throw new StaticCodeInstructionConstraintException("Execution must not fall off the bottom of the code array. This constraint is enforced statically as some existing verifiers do - so it may be a false alarm if the last instruction is not reachable.");
    321 	}
    322
    323 	/***
    324 	 * These are the checks for the satisfaction of constraints which are described in the
    325 	 * Java Virtual Machine Specification, Second Edition as Static Constraints on
    326 	 * the operands of instructions of Java Virtual Machine Code (chapter 4.8.1).
    327 	 * BCEL parses the code array to create an InstructionList and therefore has to check
    328 	 * some of these constraints. Additional checks are also implemented here.
    329 	 *
    330 	 * @throws StaticCodeConstraintException if the verification fails.
    331 	 */
    332 	private void pass3StaticInstructionOperandsChecks(){
    333 		// When building up the InstructionList, BCEL has already done all those checks
    334 		// mentioned in The Java Virtual Machine Specification, Second Edition, as
    335 		// "static constraints on the operands of instructions in the code array".
    336 		// TODO: see the do_verify() comments. Maybe we should really work on the
    337 		//       byte array first to give more comprehensive messages.
    338 		// TODO: Review Exception API, possibly build in some "offending instruction" thing
    339 		//       when we're ready to insulate the offending instruction by doing the
    340 		//       above thing.
    341
    342 		// TODO: Implement as much as possible here. BCEL does _not_ check everything.
    343
    344 		ConstantPoolGen cpg = new ConstantPoolGen(Repository.lookupClass(myOwner.getClassName()).getConstantPool());
    345 		InstOperandConstraintVisitor v = new InstOperandConstraintVisitor(cpg);
    346
    347 		// Checks for the things BCEL does _not_ handle itself.
    348 		InstructionHandle ih = instructionList.getStart();
    349 		while (ih != null){
    350 			Instruction i = ih.getInstruction();
    351
    352 			// An "own" constraint, due to JustIce's new definition of what "subroutine" means.
    353 			if (i instanceof JsrInstruction){
    354 				InstructionHandle target = ((JsrInstruction) i).getTarget();
    355 				if (target == instructionList.getStart()){
    356 					throw new StaticCodeInstructionOperandConstraintException("Due to JustIce's clear definition of subroutines, no JSR or JSR_W may have a top-level instruction (such as the very first instruction, which is targeted by instruction '"+ih+"' as its target.");
    357 				}
    358 				if (!(target.getInstruction() instanceof ASTORE)){
    359 					throw new StaticCodeInstructionOperandConstraintException("Due to JustIce's clear definition of subroutines, no JSR or JSR_W may target anything else than an ASTORE instruction. Instruction '"+ih+"' targets '"+target+"'.");
    360 				}
    361 			}
    362
    363 			// vmspec2, page 134-137
    364 			ih.accept(v);
    365
    366 			ih = ih.getNext();
    367 		}
    368
    369 	}
    370
    371 	/*** A small utility method returning if a given int i is in the given int[] ints. */
    372 	private static boolean contains(int[] ints, int i){
    373 		for (int j=0; j<ints.length; j++){
    374 			if (ints[j]==i) return true;
    375 		}
    376 		return false;
    377 	}
    378
    379 	/*** Returns the method number as supplied when instantiating. */
    380 	public int getMethodNo(){
    381 		return method_no;
    382 	}
    383
    384 	/***
    385 	 * This visitor class does the actual checking for the instruction
    386 	 * operand's constraints.
    387 	 */
    388 	private class InstOperandConstraintVisitor extends org.apache.bcel.generic.EmptyVisitor{
    389 		/*** The ConstantPoolGen instance this Visitor operates on. */
    390 		private ConstantPoolGen cpg;
    391
    392 		/*** The only Constructor. */
    393 		InstOperandConstraintVisitor(ConstantPoolGen cpg){
    394 			this.cpg = cpg;
    395 		}
    396
    397 		/***
    398 		 * Utility method to return the max_locals value of the method verified
    399 		 * by the surrounding Pass3aVerifier instance.
    400 		 */
    401 		private int max_locals(){
    402 			return Repository.lookupClass(myOwner.getClassName()).getMethods()[method_no].getCode().getMaxLocals();
    403 		}
    404
    405 		/***
    406 		 * A utility method to always raise an exeption.
    407 		 */
    408 		private void constraintViolated(Instruction i, String message) {
    409 			throw new StaticCodeInstructionOperandConstraintException("Instruction "+i+" constraint violated: "+message);
    410 		}
    411
    412 		/***
    413 		 * A utility method to raise an exception if the index is not
    414 		 * a valid constant pool index.
    415 		 */
    416 		private void indexValid(Instruction i, int idx){
    417 			if (idx < 0 || idx >= cpg.getSize()){
    418 				constraintViolated(i, "Illegal constant pool index '"+idx+"'.");
    419 			}
    420 		}
    421
    422 		///////////////////////////////////////////////////////////
    423 		// The Java Virtual Machine Specification, pages 134-137 //
    424 		///////////////////////////////////////////////////////////
    425 		/***
    426 		 * Assures the generic preconditions of a LoadClass instance.
    427 		 * The referenced class is loaded and pass2-verified.
    428 		 */
    429 		public void visitLoadClass(LoadClass o){
    430 			ObjectType t = o.getLoadClassType(cpg);
    431 			if (t != null){// null means "no class is loaded"
    432 				Verifier v = VerifierFactory.getVerifier(t.getClassName());
    433 				VerificationResult vr = v.doPass1();
    434 				if (vr.getStatus() != VerificationResult.VERIFIED_OK){
    435 					constraintViolated((Instruction) o, "Class '"+o.getLoadClassType(cpg).getClassName()+"' is referenced, but cannot be loaded: '"+vr+"'.");
    436 				}
    437 			}
    438 		}
    439
    440 		// The target of each jump and branch instruction [...] must be the opcode [...]
    441 		// BCEL _DOES_ handle this.
    442
    443 		// tableswitch: BCEL will do it, supposedly.
    444
    445 		// lookupswitch: BCEL will do it, supposedly.
    446
    447 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    448 		// LDC and LDC_W (LDC_W is a subclass of LDC in BCEL's model)
    449 		public void visitLDC(LDC o){
    450 			indexValid(o, o.getIndex());
    451 			Constant c = cpg.getConstant(o.getIndex());
    452 			if (! ( (c instanceof ConstantInteger)	||
    453 							(c instanceof ConstantFloat) 		||
    454 							(c instanceof ConstantString) ) ){
    455 				constraintViolated(o, "Operand of LDC or LDC_W must be one of CONSTANT_Integer, CONSTANT_Float or CONSTANT_String, but is '"+c+"'.");
    456 			}
    457 		}
    458
    459 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    460 		// LDC2_W
    461 		public void visitLDC2_W(LDC2_W o){
    462 			indexValid(o, o.getIndex());
    463 			Constant c = cpg.getConstant(o.getIndex());
    464 			if (! ( (c instanceof ConstantLong)	||
    465 							(c instanceof ConstantDouble) ) ){
    466 				constraintViolated(o, "Operand of LDC2_W must be CONSTANT_Long or CONSTANT_Double, but is '"+c+"'.");
    467 			}
    468 			try{
    469 				indexValid(o, o.getIndex()+1);
    470 			}
    471 			catch(StaticCodeInstructionOperandConstraintException e){
    472 				throw new AssertionViolatedException("OOPS: Does not BCEL handle that? LDC2_W operand has a problem.");
    473 			}
    474 		}
    475
    476 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    477  		//getfield, putfield, getstatic, putstatic
    478  		public void visitFieldInstruction(FieldInstruction o){
    479 			indexValid(o, o.getIndex());
    480 			Constant c = cpg.getConstant(o.getIndex());
    481 			if (! (c instanceof ConstantFieldref)){
    482 				constraintViolated(o, "Indexing a constant that's not a CONSTANT_Fieldref but a '"+c+"'.");
    483 			}
    484
    485 			String field_name = o.getFieldName(cpg);
    486
    487 			JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
    488 			Field[] fields = jc.getFields();
    489 			Field f = null;
    490 			for (int i=0; i<fields.length; i++){
    491 				if (fields[i].getName().equals(field_name)){
    492 					f = fields[i];
    493 					break;
    494 				}
    495 			}
    496 			if (f == null){
    497 				/* TODO: also look up if the field is inherited! */
    498 				constraintViolated(o, "Referenced field '"+field_name+"' does not exist in class '"+jc.getClassName()+"'.");
    499 			}
    500 			else{
    501 				/* TODO: Check if assignment compatibility is sufficient.
    502 				   What does Sun do? */
    503 				Type f_type = Type.getType(f.getSignature());
    504 				Type o_type = o.getType(cpg);
    505
    506 				/* TODO: Is there a way to make BCEL tell us if a field
    507 				has a void method's signature, i.e. "()I" instead of "I"? */
    508
    509 				if (! f_type.equals(o_type)){
    510 					constraintViolated(o, "Referenced field '"+field_name+"' has type '"+f_type+"' instead of '"+o_type+"' as expected.");
    511 				}
    512 				/* TODO: Check for access modifiers here. */
    513 			}
    514 		}
    515
    516 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    517 		public void visitInvokeInstruction(InvokeInstruction o){
    518 			indexValid(o, o.getIndex());
    519 			if (	(o instanceof INVOKEVIRTUAL)	||
    520 						(o instanceof INVOKESPECIAL)	||
    521 						(o instanceof INVOKESTATIC)	){
    522 				Constant c = cpg.getConstant(o.getIndex());
    523 				if (! (c instanceof ConstantMethodref)){
    524 					constraintViolated(o, "Indexing a constant that's not a CONSTANT_Methodref but a '"+c+"'.");
    525 				}
    526 				else{
    527 					// Constants are okay due to pass2.
    528 					ConstantNameAndType cnat = (ConstantNameAndType) (cpg.getConstant(((ConstantMethodref) c).getNameAndTypeIndex()));
    529 					ConstantUtf8 cutf8 = (ConstantUtf8) (cpg.getConstant(cnat.getNameIndex()));
    530 					if (cutf8.getBytes().equals(Constants.CONSTRUCTOR_NAME) && (!(o instanceof INVOKESPECIAL)) ){
    531 						constraintViolated(o, "Only INVOKESPECIAL is allowed to invoke instance initialization methods.");
    532 					}
    533 					if ( (! (cutf8.getBytes().equals(Constants.CONSTRUCTOR_NAME)) ) && (cutf8.getBytes().startsWith("<")) ){
    534 						constraintViolated(o, "No method with a name beginning with '<' other than the instance initialization methods may be called by the method invocation instructions.");
    535 					}
    536 				}
    537 			}
    538 			else{ //if (o instanceof INVOKEINTERFACE){
    539 				Constant c = cpg.getConstant(o.getIndex());
    540 				if (! (c instanceof ConstantInterfaceMethodref)){
    541 					constraintViolated(o, "Indexing a constant that's not a CONSTANT_InterfaceMethodref but a '"+c+"'.");
    542 				}
    543 				// TODO: From time to time check if BCEL allows to detect if the
    544 				// 'count' operand is consistent with the information in the
    545 				// CONSTANT_InterfaceMethodref and if the last operand is zero.
    546 				// By now, BCEL hides those two operands because they're superfluous.
    547
    548 				// Invoked method must not be <init> or <clinit>
    549 				ConstantNameAndType cnat = (ConstantNameAndType) (cpg.getConstant(((ConstantInterfaceMethodref)c).getNameAndTypeIndex()));
    550 				String name = ((ConstantUtf8) (cpg.getConstant(cnat.getNameIndex()))).getBytes();
    551 				if (name.equals(Constants.CONSTRUCTOR_NAME)){
    552 					constraintViolated(o, "Method to invoke must not be '"+Constants.CONSTRUCTOR_NAME+"'.");
    553 				}
    554 				if (name.equals(Constants.STATIC_INITIALIZER_NAME)){
    555 					constraintViolated(o, "Method to invoke must not be '"+Constants.STATIC_INITIALIZER_NAME+"'.");
    556 				}
    557 			}
    558
    559 			// The LoadClassType is the method-declaring class, so we have to check the other types.
    560
    561 			Type t = o.getReturnType(cpg);
    562 			if (t instanceof ArrayType){
    563 				t = ((ArrayType) t).getBasicType();
    564 			}
    565 			if (t instanceof ObjectType){
    566 				Verifier v = VerifierFactory.getVerifier(((ObjectType) t).getClassName());
    567 				VerificationResult vr = v.doPass2();
    568 				if (vr.getStatus() != VerificationResult.VERIFIED_OK){
    569 					constraintViolated(o, "Return type class/interface could not be verified successfully: '"+vr.getMessage()+"'.");
    570 				}
    571 			}
    572
    573 			Type[] ts = o.getArgumentTypes(cpg);
    574 			for (int i=0; i<ts.length; i++){
    575 				t = ts[i];
    576 				if (t instanceof ArrayType){
    577 					t = ((ArrayType) t).getBasicType();
    578 				}
    579 				if (t instanceof ObjectType){
    580 					Verifier v = VerifierFactory.getVerifier(((ObjectType) t).getClassName());
    581 					VerificationResult vr = v.doPass2();
    582 					if (vr.getStatus() != VerificationResult.VERIFIED_OK){
    583 						constraintViolated(o, "Argument type class/interface could not be verified successfully: '"+vr.getMessage()+"'.");
    584 					}
    585 				}
    586 			}
    587
    588 		}
    589
    590 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    591 		public void visitINSTANCEOF(INSTANCEOF o){
    592 			indexValid(o, o.getIndex());
    593 			Constant c = cpg.getConstant(o.getIndex());
    594 			if (!	(c instanceof ConstantClass)){
    595 				constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
    596 			}
    597 		}
    598
    599 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    600 		public void visitCHECKCAST(CHECKCAST o){
    601 			indexValid(o, o.getIndex());
    602 			Constant c = cpg.getConstant(o.getIndex());
    603 			if (!	(c instanceof ConstantClass)){
    604 				constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
    605 			}
    606 		}
    607
    608 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    609 		public void visitNEW(NEW o){
    610 			indexValid(o, o.getIndex());
    611 			Constant c = cpg.getConstant(o.getIndex());
    612 			if (!	(c instanceof ConstantClass)){
    613 				constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
    614 			}
    615 			else{
    616 				ConstantUtf8 cutf8 = (ConstantUtf8) (cpg.getConstant( ((ConstantClass) c).getNameIndex() ));
    617 				Type t = Type.getType("L"+cutf8.getBytes()+";");
    618 				if (t instanceof ArrayType){
    619 					constraintViolated(o, "NEW must not be used to create an array.");
    620 				}
    621 			}
    622
    623 		}
    624
    625 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    626 		public void visitMULTIANEWARRAY(MULTIANEWARRAY o){
    627 			indexValid(o, o.getIndex());
    628 			Constant c = cpg.getConstant(o.getIndex());
    629 			if (!	(c instanceof ConstantClass)){
    630 				constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
    631 			}
    632 			int dimensions2create = o.getDimensions();
    633 			if (dimensions2create < 1){
    634 				constraintViolated(o, "Number of dimensions to create must be greater than zero.");
    635 			}
    636 			Type t = o.getType(cpg);
    637 			if (t instanceof ArrayType){
    638 				int dimensions = ((ArrayType) t).getDimensions();
    639 				if (dimensions < dimensions2create){
    640 					constraintViolated(o, "Not allowed to create array with more dimensions ('+dimensions2create+') than the one referenced by the CONSTANT_Class '"+t+"'.");
    641 				}
    642 			}
    643 			else{
    644 				constraintViolated(o, "Expecting a CONSTANT_Class referencing an array type. [Constraint not found in The Java Virtual Machine Specification, Second Edition, 4.8.1]");
    645 			}
    646 		}
    647
    648 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    649 		public void visitANEWARRAY(ANEWARRAY o){
    650 			indexValid(o, o.getIndex());
    651 			Constant c = cpg.getConstant(o.getIndex());
    652 			if (!	(c instanceof ConstantClass)){
    653 				constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
    654 			}
    655 			Type t = o.getType(cpg);
    656 			if (t instanceof ArrayType){
    657 				int dimensions = ((ArrayType) t).getDimensions();
    658 				if (dimensions >= 255){
    659 					constraintViolated(o, "Not allowed to create an array with more than 255 dimensions.");
    660 				}
    661 			}
    662 		}
    663
    664 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    665 		public void visitNEWARRAY(NEWARRAY o){
    666 			byte t = o.getTypecode();
    667 			if (!	(	(t == Constants.T_BOOLEAN)	||
    668 							(t == Constants.T_CHAR)			||
    669 							(t == Constants.T_FLOAT)		||
    670 							(t == Constants.T_DOUBLE)		||
    671 							(t == Constants.T_BYTE)			||
    672 							(t == Constants.T_SHORT)		||
    673 							(t == Constants.T_INT)			||
    674 							(t == Constants.T_LONG)	)	){
    675 				constraintViolated(o, "Illegal type code '+t+' for 'atype' operand.");
    676 			}
    677 		}
    678
    679 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    680 		public void visitILOAD(ILOAD o){
    681 			int idx = o.getIndex();
    682 			if (idx < 0){
    683 				constraintViolated(o, "Index '"+idx+"' must be non-negative.");
    684 			}
    685 			else{
    686 				int maxminus1 =  max_locals()-1;
    687 				if (idx > maxminus1){
    688 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
    689 				}
    690 			}
    691 		}
    692
    693 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    694 		public void visitFLOAD(FLOAD o){
    695 			int idx = o.getIndex();
    696 			if (idx < 0){
    697 				constraintViolated(o, "Index '"+idx+"' must be non-negative.");
    698 			}
    699 			else{
    700 				int maxminus1 =  max_locals()-1;
    701 				if (idx > maxminus1){
    702 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
    703 				}
    704 			}
    705 		}
    706
    707 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    708 		public void visitALOAD(ALOAD o){
    709 			int idx = o.getIndex();
    710 			if (idx < 0){
    711 				constraintViolated(o, "Index '"+idx+"' must be non-negative.");
    712 			}
    713 			else{
    714 				int maxminus1 =  max_locals()-1;
    715 				if (idx > maxminus1){
    716 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
    717 				}
    718 			}
    719 		}
    720
    721 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    722 		public void visitISTORE(ISTORE o){
    723 			int idx = o.getIndex();
    724 			if (idx < 0){
    725 				constraintViolated(o, "Index '"+idx+"' must be non-negative.");
    726 			}
    727 			else{
    728 				int maxminus1 =  max_locals()-1;
    729 				if (idx > maxminus1){
    730 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
    731 				}
    732 			}
    733 		}
    734
    735 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    736 		public void visitFSTORE(FSTORE o){
    737 			int idx = o.getIndex();
    738 			if (idx < 0){
    739 				constraintViolated(o, "Index '"+idx+"' must be non-negative.");
    740 			}
    741 			else{
    742 				int maxminus1 =  max_locals()-1;
    743 				if (idx > maxminus1){
    744 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
    745 				}
    746 			}
    747 		}
    748
    749 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    750 		public void visitASTORE(ASTORE o){
    751 			int idx = o.getIndex();
    752 			if (idx < 0){
    753 				constraintViolated(o, "Index '"+idx+"' must be non-negative.");
    754 			}
    755 			else{
    756 				int maxminus1 =  max_locals()-1;
    757 				if (idx > maxminus1){
    758 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
    759 				}
    760 			}
    761 		}
    762
    763 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    764 		public void visitIINC(IINC o){
    765 			int idx = o.getIndex();
    766 			if (idx < 0){
    767 				constraintViolated(o, "Index '"+idx+"' must be non-negative.");
    768 			}
    769 			else{
    770 				int maxminus1 =  max_locals()-1;
    771 				if (idx > maxminus1){
    772 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
    773 				}
    774 			}
    775 		}
    776
    777 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    778 		public void visitRET(RET o){
    779 			int idx = o.getIndex();
    780 			if (idx < 0){
    781 				constraintViolated(o, "Index '"+idx+"' must be non-negative.");
    782 			}
    783 			else{
    784 				int maxminus1 =  max_locals()-1;
    785 				if (idx > maxminus1){
    786 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
    787 				}
    788 			}
    789 		}
    790
    791 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    792 		public void visitLLOAD(LLOAD o){
    793 			int idx = o.getIndex();
    794 			if (idx < 0){
    795 				constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
    796 			}
    797 			else{
    798 				int maxminus2 =  max_locals()-2;
    799 				if (idx > maxminus2){
    800 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'.");
    801 				}
    802 			}
    803 		}
    804
    805 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    806 		public void visitDLOAD(DLOAD o){
    807 			int idx = o.getIndex();
    808 			if (idx < 0){
    809 				constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
    810 			}
    811 			else{
    812 				int maxminus2 =  max_locals()-2;
    813 				if (idx > maxminus2){
    814 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'.");
    815 				}
    816 			}
    817 		}
    818
    819 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    820 		public void visitLSTORE(LSTORE o){
    821 			int idx = o.getIndex();
    822 			if (idx < 0){
    823 				constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
    824 			}
    825 			else{
    826 				int maxminus2 =  max_locals()-2;
    827 				if (idx > maxminus2){
    828 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'.");
    829 				}
    830 			}
    831 		}
    832
    833 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    834 		public void visitDSTORE(DSTORE o){
    835 			int idx = o.getIndex();
    836 			if (idx < 0){
    837 				constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
    838 			}
    839 			else{
    840 				int maxminus2 =  max_locals()-2;
    841 				if (idx > maxminus2){
    842 					constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'.");
    843 				}
    844 			}
    845 		}
    846
    847 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    848 		public void visitLOOKUPSWITCH(LOOKUPSWITCH o){
    849 			int[] matchs = o.getMatchs();
    850 			int max = Integer.MIN_VALUE;
    851 			for (int i=0; i<matchs.length; i++){
    852 				if (matchs[i] == max && i != 0){
    853 					constraintViolated(o, "Match '"+matchs[i]+"' occurs more than once.");
    854 				}
    855 				if (matchs[i] < max){
    856 					constraintViolated(o, "Lookup table must be sorted but isn't.");
    857 				}
    858 				else{
    859 					max = matchs[i];
    860 				}
    861 			}
    862 		}
    863
    864 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    865 		public void visitTABLESWITCH(TABLESWITCH o){
    866 			// "high" must be >= "low". We cannot check this, as BCEL hides
    867 			// it from us.
    868 		}
    869
    870 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    871 		public void visitPUTSTATIC(PUTSTATIC o){
    872 			String field_name = o.getFieldName(cpg);
    873 			JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
    874 			Field[] fields = jc.getFields();
    875 			Field f = null;
    876 			for (int i=0; i<fields.length; i++){
    877 				if (fields[i].getName().equals(field_name)){
    878 					f = fields[i];
    879 					break;
    880 				}
    881 			}
    882 			if (f == null){
    883 				throw new AssertionViolatedException("Field not found?!?");
    884 			}
    885
    886 			if (f.isFinal()){
    887 				if (!(myOwner.getClassName().equals(o.getClassType(cpg).getClassName()))){
    888 					constraintViolated(o, "Referenced field '"+f+"' is final and must therefore be declared in the current class '"+myOwner.getClassName()+"' which is not the case: it is declared in '"+o.getClassType(cpg).getClassName()+"'.");
    889 				}
    890 			}
    891
    892 			if (! (f.isStatic())){
    893 				constraintViolated(o, "Referenced field '"+f+"' is not static which it should be.");
    894 			}
    895
    896 			String meth_name = Repository.lookupClass(myOwner.getClassName()).getMethods()[method_no].getName();
    897
    898 			// If it's an interface, it can be set only in <clinit>.
    899 			if ((!(jc.isClass())) && (!(meth_name.equals(Constants.STATIC_INITIALIZER_NAME)))){
    900 				constraintViolated(o, "Interface field '"+f+"' must be set in a '"+Constants.STATIC_INITIALIZER_NAME+"' method.");
    901 			}
    902 		}
    903
    904 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    905 		public void visitGETSTATIC(GETSTATIC o){
    906 			String field_name = o.getFieldName(cpg);
    907 			JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
    908 			Field[] fields = jc.getFields();
    909 			Field f = null;
    910 			for (int i=0; i<fields.length; i++){
    911 				if (fields[i].getName().equals(field_name)){
    912 					f = fields[i];
    913 					break;
    914 				}
    915 			}
    916 			if (f == null){
    917 				throw new AssertionViolatedException("Field not found?!?");
    918 			}
    919
    920 			if (! (f.isStatic())){
    921 				constraintViolated(o, "Referenced field '"+f+"' is not static which it should be.");
    922 			}
    923 		}
    924
    925 		/* Checks if the constraints of operands of the said instruction(s) are satisfied. */
    926 		//public void visitPUTFIELD(PUTFIELD o){
    927 			// for performance reasons done in Pass 3b
    928 		//}
    929
    930 		/* Checks if the constraints of operands of the said instruction(s) are satisfied. */
    931 		//public void visitGETFIELD(GETFIELD o){
    932 			// for performance reasons done in Pass 3b
    933 		//}
    934
    935 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    936 		public void visitINVOKEINTERFACE(INVOKEINTERFACE o){
    937 			// INVOKEINTERFACE is a LoadClass; the Class where the referenced method is declared in,
    938 			// is therefore resolved/verified.
    939 			// INVOKEINTERFACE is an InvokeInstruction, the argument and return types are resolved/verified,
    940 			// too. So are the allowed method names.
    941 			String classname = o.getClassName(cpg);
    942 			JavaClass jc = Repository.lookupClass(classname);
    943 			Method[] ms = jc.getMethods();
    944 			Method m = null;
    945 			for (int i=0; i<ms.length; i++){
    946 				if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
    947 				     (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
    948 				     (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
    949 					m = ms[i];
    950 					break;
    951 				}
    952 			}
    953 			if (m == null){
    954 				constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature not found in class '"+jc.getClassName()+"'. The native verfier does allow the method to be declared in some superinterface, which the Java Virtual Machine Specification, Second Edition does not.");
    955 			}
    956 			if (jc.isClass()){
    957 				constraintViolated(o, "Referenced class '"+jc.getClassName()+"' is a class, but not an interface as expected.");
    958 			}
    959 		}
    960
    961 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    962 		public void visitINVOKESPECIAL(INVOKESPECIAL o){
    963 			// INVOKESPECIAL is a LoadClass; the Class where the referenced method is declared in,
    964 			// is therefore resolved/verified.
    965 			// INVOKESPECIAL is an InvokeInstruction, the argument and return types are resolved/verified,
    966 			// too. So are the allowed method names.
    967 			String classname = o.getClassName(cpg);
    968 			JavaClass jc = Repository.lookupClass(classname);
    969 			Method[] ms = jc.getMethods();
    970 			Method m = null;
    971 			for (int i=0; i<ms.length; i++){
    972 				if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
    973 				     (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
    974 				     (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
    975 					m = ms[i];
    976 					break;
    977 				}
    978 			}
    979 			if (m == null){
    980 				constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature not found in class '"+jc.getClassName()+"'. The native verfier does allow the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not.");
    981 			}
    982
    983 			JavaClass current = Repository.lookupClass(myOwner.getClassName());
    984 			if (current.isSuper()){
    985
    986 				if ((Repository.instanceOf( current, jc )) && (!current.equals(jc))){
    987
    988 					if (! (o.getMethodName(cpg).equals(Constants.CONSTRUCTOR_NAME) )){
    989 						// Special lookup procedure for ACC_SUPER classes.
    990
    991 						int supidx = -1;
    992
    993 						Method meth = null;
    994 						while (supidx != 0){
    995 							supidx = current.getSuperclassNameIndex();
    996 							current = Repository.lookupClass(current.getSuperclassName());
    997
    998 							Method[] meths = current.getMethods();
    999 							for (int i=0; i<meths.length; i++){
    1000 								if	( (meths[i].getName().equals(o.getMethodName(cpg))) &&
    1001 				     				(Type.getReturnType(meths[i].getSignature()).equals(o.getReturnType(cpg))) &&
    1002 				     				(objarrayequals(Type.getArgumentTypes(meths[i].getSignature()), o.getArgumentTypes(cpg))) ){
    1003 									meth = meths[i];
    1004 									break;
    1005 								}
    1006 							}
    1007 							if (meth != null) break;
    1008 						}
    1009 						if (meth == null){
    1010 							constraintViolated(o, "ACC_SUPER special lookup procedure not successful: method '"+o.getMethodName(cpg)+"' with proper signature not declared in superclass hierarchy.");
    1011 						}
    1012 					}
    1013 				}
    1014 			}
    1015
    1016
    1017 		}
    1018
    1019 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    1020 		public void visitINVOKESTATIC(INVOKESTATIC o){
    1021 			// INVOKESTATIC is a LoadClass; the Class where the referenced method is declared in,
    1022 			// is therefore resolved/verified.
    1023 			// INVOKESTATIC is an InvokeInstruction, the argument and return types are resolved/verified,
    1024 			// too. So are the allowed method names.
    1025 			String classname = o.getClassName(cpg);
    1026 			JavaClass jc = Repository.lookupClass(classname);
    1027 			Method[] ms = jc.getMethods();
    1028 			Method m = null;
    1029 			for (int i=0; i<ms.length; i++){
    1030 				if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
    1031 				     (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
    1032 				     (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
    1033 					m = ms[i];
    1034 					break;
    1035 				}
    1036 			}
    1037 			if (m == null){
    1038 				constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature not found in class '"+jc.getClassName()+"'. The native verifier possibly allows the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not.");
    1039 			}
    1040
    1041 			if (! (m.isStatic())){ // implies it's not abstract, verified in pass 2.
    1042 				constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' has ACC_STATIC unset.");
    1043 			}
    1044
    1045 		}
    1046
    1047
    1048 		/*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
    1049 		public void visitINVOKEVIRTUAL(INVOKEVIRTUAL o){
    1050 			// INVOKEVIRTUAL is a LoadClass; the Class where the referenced method is declared in,
    1051 			// is therefore resolved/verified.
    1052 			// INVOKEVIRTUAL is an InvokeInstruction, the argument and return types are resolved/verified,
    1053 			// too. So are the allowed method names.
    1054 			String classname = o.getClassName(cpg);
    1055 			JavaClass jc = Repository.lookupClass(classname);
    1056 			Method[] ms = jc.getMethods();
    1057 			Method m = null;
    1058 			for (int i=0; i<ms.length; i++){
    1059 				if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
    1060 				     (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
    1061 				     (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
    1062 					m = ms[i];
    1063 					break;
    1064 				}
    1065 			}
    1066 			if (m == null){
    1067 				constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature not found in class '"+jc.getClassName()+"'. The native verfier does allow the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not.");
    1068 			}
    1069 			if (! (jc.isClass())){
    1070 				constraintViolated(o, "Referenced class '"+jc.getClassName()+"' is an interface, but not a class as expected.");
    1071 			}
    1072
    1073 		}
    1074
    1075
    1076 		// WIDE stuff is BCEL-internal and cannot be checked here.
    1077
    1078 		/***
    1079 		 * A utility method like equals(Object) for arrays.
    1080 		 * The equality of the elements is based on their equals(Object)
    1081 		 * method instead of their object identity.
    1082 		 */
    1083 		private boolean objarrayequals(Object[] o, Object[] p){
    1084 			if (o.length != p.length){
    1085 				return false;
    1086 			}
    1087
    1088 			for (int i=0; i<o.length; i++){
    1089 				if (! (o[i].equals(p[i])) ){
    1090 					return false;
    1091 				}
    1092 			}
    1093
    1094 			return true;
    1095 		}
    1096
    1097 	}
    1098 }

This page was automatically generated by Maven