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