KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > bcel > verifier > statics > Pass3aVerifier


1 /*
2  * Copyright 2000-2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */

17 package org.apache.bcel.verifier.statics;
18
19
20 import org.apache.bcel.Constants;
21 import org.apache.bcel.Repository;
22 import org.apache.bcel.classfile.Attribute;
23 import org.apache.bcel.classfile.Code;
24 import org.apache.bcel.classfile.CodeException;
25 import org.apache.bcel.classfile.Constant;
26 import org.apache.bcel.classfile.ConstantClass;
27 import org.apache.bcel.classfile.ConstantDouble;
28 import org.apache.bcel.classfile.ConstantFieldref;
29 import org.apache.bcel.classfile.ConstantFloat;
30 import org.apache.bcel.classfile.ConstantInteger;
31 import org.apache.bcel.classfile.ConstantInterfaceMethodref;
32 import org.apache.bcel.classfile.ConstantLong;
33 import org.apache.bcel.classfile.ConstantMethodref;
34 import org.apache.bcel.classfile.ConstantNameAndType;
35 import org.apache.bcel.classfile.ConstantString;
36 import org.apache.bcel.classfile.ConstantUtf8;
37 import org.apache.bcel.classfile.Field;
38 import org.apache.bcel.classfile.JavaClass;
39 import org.apache.bcel.classfile.LineNumber;
40 import org.apache.bcel.classfile.LineNumberTable;
41 import org.apache.bcel.classfile.LocalVariable;
42 import org.apache.bcel.classfile.LocalVariableTable;
43 import org.apache.bcel.classfile.Method;
44 import org.apache.bcel.generic.ALOAD;
45 import org.apache.bcel.generic.ANEWARRAY;
46 import org.apache.bcel.generic.ASTORE;
47 import org.apache.bcel.generic.ATHROW;
48 import org.apache.bcel.generic.ArrayType;
49 import org.apache.bcel.generic.BREAKPOINT;
50 import org.apache.bcel.generic.CHECKCAST;
51 import org.apache.bcel.generic.ConstantPoolGen;
52 import org.apache.bcel.generic.DLOAD;
53 import org.apache.bcel.generic.DSTORE;
54 import org.apache.bcel.generic.FLOAD;
55 import org.apache.bcel.generic.FSTORE;
56 import org.apache.bcel.generic.FieldInstruction;
57 import org.apache.bcel.generic.GETSTATIC;
58 import org.apache.bcel.generic.GotoInstruction;
59 import org.apache.bcel.generic.IINC;
60 import org.apache.bcel.generic.ILOAD;
61 import org.apache.bcel.generic.IMPDEP1;
62 import org.apache.bcel.generic.IMPDEP2;
63 import org.apache.bcel.generic.INSTANCEOF;
64 import org.apache.bcel.generic.INVOKEINTERFACE;
65 import org.apache.bcel.generic.INVOKESPECIAL;
66 import org.apache.bcel.generic.INVOKESTATIC;
67 import org.apache.bcel.generic.INVOKEVIRTUAL;
68 import org.apache.bcel.generic.ISTORE;
69 import org.apache.bcel.generic.Instruction;
70 import org.apache.bcel.generic.InstructionHandle;
71 import org.apache.bcel.generic.InstructionList;
72 import org.apache.bcel.generic.InvokeInstruction;
73 import org.apache.bcel.generic.JsrInstruction;
74 import org.apache.bcel.generic.LDC;
75 import org.apache.bcel.generic.LDC2_W;
76 import org.apache.bcel.generic.LLOAD;
77 import org.apache.bcel.generic.LOOKUPSWITCH;
78 import org.apache.bcel.generic.LSTORE;
79 import org.apache.bcel.generic.LoadClass;
80 import org.apache.bcel.generic.MULTIANEWARRAY;
81 import org.apache.bcel.generic.NEW;
82 import org.apache.bcel.generic.NEWARRAY;
83 import org.apache.bcel.generic.ObjectType;
84 import org.apache.bcel.generic.PUTSTATIC;
85 import org.apache.bcel.generic.RET;
86 import org.apache.bcel.generic.ReturnInstruction;
87 import org.apache.bcel.generic.TABLESWITCH;
88 import org.apache.bcel.generic.Type;
89 import org.apache.bcel.verifier.PassVerifier;
90 import org.apache.bcel.verifier.VerificationResult;
91 import org.apache.bcel.verifier.Verifier;
92 import org.apache.bcel.verifier.VerifierFactory;
93 import org.apache.bcel.verifier.exc.AssertionViolatedException;
94 import org.apache.bcel.verifier.exc.ClassConstraintException;
95 import org.apache.bcel.verifier.exc.InvalidMethodException;
96 import org.apache.bcel.verifier.exc.StaticCodeConstraintException;
97 import org.apache.bcel.verifier.exc.StaticCodeInstructionConstraintException;
98 import org.apache.bcel.verifier.exc.StaticCodeInstructionOperandConstraintException;
99
100 /**
101  * This PassVerifier verifies a class file according to
102  * pass 3, static part as described in The Java Virtual
103  * Machine Specification, 2nd edition.
104  * More detailed information is to be found at the do_verify()
105  * method's documentation.
106  *
107  * @version $Id: Pass3aVerifier.java 386056 2006-03-15 11:31:56Z tcurdt $
108  * @author Enver Haase
109  * @see #do_verify()
110  */

111 public final class Pass3aVerifier extends PassVerifier{
112
113     /** The Verifier that created this. */
114     private Verifier myOwner;
115
116     /**
117      * The method number to verify.
118      * This is the index in the array returned
119      * by JavaClass.getMethods().
120      */

121     private int method_no;
122
123     /** 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. */
124     InstructionList instructionList;
125     /** 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. */
126     Code code;
127
128     /** Should only be instantiated by a Verifier. */
129     public Pass3aVerifier(Verifier owner, int method_no){
130         myOwner = owner;
131         this.method_no = method_no;
132     }
133
134     /**
135      * Pass 3a is the verification of static constraints of
136      * JVM code (such as legal targets of branch instructions).
137      * This is the part of pass 3 where you do not need data
138      * flow analysis.
139      * JustIce also delays the checks for a correct exception
140      * table of a Code attribute and correct line number entries
141      * in a LineNumberTable attribute of a Code attribute (which
142      * conceptually belong to pass 2) to this pass. Also, most
143      * of the check for valid local variable entries in a
144      * LocalVariableTable attribute of a Code attribute is
145      * delayed until this pass.
146      * All these checks need access to the code array of the
147      * Code attribute.
148      *
149      * @throws InvalidMethodException if the method to verify does not exist.
150      */

151     public VerificationResult do_verify(){
152         try {
153         if (myOwner.doPass2().equals(VerificationResult.VR_OK)){
154             // Okay, class file was loaded correctly by Pass 1
155
// and satisfies static constraints of Pass 2.
156
JavaClass jc = Repository.lookupClass(myOwner.getClassName());
157             Method[] methods = jc.getMethods();
158             if (method_no >= methods.length){
159                 throw new InvalidMethodException("METHOD DOES NOT EXIST!");
160             }
161             Method method = methods[method_no];
162             code = method.getCode();
163             
164             // No Code? Nothing to verify!
165
if ( method.isAbstract() || method.isNative() ){ // IF mg HAS NO CODE (static constraint of Pass 2)
166
return VerificationResult.VR_OK;
167             }
168
169             // TODO:
170
// We want a very sophisticated code examination here with good explanations
171
// on where to look for an illegal instruction or such.
172
// Only after that we should try to build an InstructionList and throw an
173
// AssertionViolatedException if after our examination InstructionList building
174
// still fails.
175
// That examination should be implemented in a byte-oriented way, i.e. look for
176
// an instruction, make sure its validity, count its length, find the next
177
// instruction and so on.
178
try{
179                 instructionList = new InstructionList(method.getCode().getCode());
180             }
181             catch(RuntimeException JavaDoc re){
182                 return new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Bad bytecode in the code array of the Code attribute of method '"+method+"'.");
183             }
184             
185             instructionList.setPositions(true);
186
187             // Start verification.
188
VerificationResult vr = VerificationResult.VR_OK; //default
189
try{
190                 delayedPass2Checks();
191             }
192             catch(ClassConstraintException cce){
193                 vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, cce.getMessage());
194                 return vr;
195             }
196             try{
197                 pass3StaticInstructionChecks();
198                 pass3StaticInstructionOperandsChecks();
199             }
200             catch(StaticCodeConstraintException scce){
201                 vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, scce.getMessage());
202             }
203             catch(ClassCastException JavaDoc cce){
204                 vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Class Cast Exception: " + cce.getMessage());
205             }
206             return vr;
207         }
208         else{ //did not pass Pass 2.
209
return VerificationResult.VR_NOTYET;
210         }
211         } catch (ClassNotFoundException JavaDoc e) {
212         // FIXME: maybe not the best way to handle this
213
throw new AssertionViolatedException("Missing class: " + e.toString());
214         }
215     }
216
217     /**
218      * These are the checks that could be done in pass 2 but are delayed to pass 3
219      * for performance reasons. Also, these checks need access to the code array
220      * of the Code attribute of a Method so it's okay to perform them here.
221      * Also see the description of the do_verify() method.
222      *
223      * @throws ClassConstraintException if the verification fails.
224      * @see #do_verify()
225      */

226     private void delayedPass2Checks(){
227
228         int[] instructionPositions = instructionList.getInstructionPositions();
229         int codeLength = code.getCode().length;
230
231         /////////////////////
232
// LineNumberTable //
233
/////////////////////
234
LineNumberTable lnt = code.getLineNumberTable();
235         if (lnt != null){
236             LineNumber[] lineNumbers = lnt.getLineNumberTable();
237             IntList offsets = new IntList();
238             lineNumber_loop: for (int i=0; i < lineNumbers.length; i++){ // may appear in any order.
239
for (int j=0; j < instructionPositions.length; j++){
240                     // TODO: Make this a binary search! The instructionPositions array is naturally ordered!
241
int offset = lineNumbers[i].getStartPC();
242                     if (instructionPositions[j] == offset){
243                         if (offsets.contains(offset)){
244                             addMessage("LineNumberTable attribute '"+code.getLineNumberTable()+"' refers to the same code offset ('"+offset+"') more than once which is violating the semantics [but is sometimes produced by IBM's 'jikes' compiler].");
245                         }
246                         else{
247                             offsets.add(offset);
248                         }
249                         continue lineNumber_loop;
250                     }
251                 }
252                 throw new ClassConstraintException("Code attribute '"+code+"' has a LineNumberTable attribute '"+code.getLineNumberTable()+"' referring to a code offset ('"+lineNumbers[i].getStartPC()+"') that does not exist.");
253             }
254         }
255
256         ///////////////////////////
257
// LocalVariableTable(s) //
258
///////////////////////////
259
/* We cannot use code.getLocalVariableTable() because there could be more
260            than only one. This is a bug in BCEL. */

261         Attribute[] atts = code.getAttributes();
262         for (int a=0; a<atts.length; a++){
263             if (atts[a] instanceof LocalVariableTable){
264                 LocalVariableTable lvt = (LocalVariableTable) atts[a];
265                 if (lvt != null){
266                     LocalVariable[] localVariables = lvt.getLocalVariableTable();
267                     for (int i=0; i<localVariables.length; i++){
268                         int startpc = localVariables[i].getStartPC();
269                         int length = localVariables[i].getLength();
270                 
271                         if (!contains(instructionPositions, startpc)){
272                             throw new ClassConstraintException("Code attribute '"+code+"' has a LocalVariableTable attribute '"+code.getLocalVariableTable()+"' referring to a code offset ('"+startpc+"') that does not exist.");
273                         }
274                         if ( (!contains(instructionPositions, startpc+length)) && (startpc+length != codeLength) ){
275                             throw new ClassConstraintException("Code attribute '"+code+"' has a LocalVariableTable attribute '"+code.getLocalVariableTable()+"' referring to a code offset start_pc+length ('"+(startpc+length)+"') that does not exist.");
276                         }
277                     }
278                 }
279             }
280         }
281         
282         ////////////////////
283
// ExceptionTable //
284
////////////////////
285
// In BCEL's "classfile" API, the startPC/endPC-notation is
286
// inclusive/exclusive as in the Java Virtual Machine Specification.
287
// WARNING: This is not true for BCEL's "generic" API.
288
CodeException[] exceptionTable = code.getExceptionTable();
289         for (int i=0; i<exceptionTable.length; i++){
290             int startpc = exceptionTable[i].getStartPC();
291             int endpc = exceptionTable[i].getEndPC();
292             int handlerpc = exceptionTable[i].getHandlerPC();
293             if (startpc >= endpc){
294                 throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has its start_pc ('"+startpc+"') not smaller than its end_pc ('"+endpc+"').");
295             }
296             if (!contains(instructionPositions, startpc)){
297                 throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has a non-existant bytecode offset as its start_pc ('"+startpc+"').");
298             }
299             if ( (!contains(instructionPositions, endpc)) && (endpc != codeLength)){
300                 throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has a non-existant bytecode offset as its end_pc ('"+startpc+"') [that is also not equal to code_length ('"+codeLength+"')].");
301             }
302             if (!contains(instructionPositions, handlerpc)){
303                 throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has a non-existant bytecode offset as its handler_pc ('"+handlerpc+"').");
304             }
305         }
306     }
307
308     /**
309      * These are the checks if constraints are satisfied which are described in the
310      * Java Virtual Machine Specification, Second Edition as Static Constraints on
311      * the instructions of Java Virtual Machine Code (chapter 4.8.1).
312      *
313      * @throws StaticCodeConstraintException if the verification fails.
314      */

315     private void pass3StaticInstructionChecks(){
316         
317         // Code array must not be empty:
318
// Enforced in pass 2 (also stated in the static constraints of the Code
319
// array in vmspec2), together with pass 1 (reading code_length bytes and
320
// interpreting them as code[]). So this must not be checked again here.
321

322         if (! (code.getCode().length < 65536)){// contradicts vmspec2 page 152 ("Limitations"), but is on page 134.
323
throw new StaticCodeInstructionConstraintException("Code array in code attribute '"+code+"' too big: must be smaller than 65536 bytes.");
324         }
325
326         // First opcode at offset 0: okay, that's clear. Nothing to do.
327

328         // Only instances of the instructions documented in Section 6.4 may appear in
329
// the code array.
330

331         // For BCEL's sake, we cannot handle WIDE stuff, but hopefully BCEL does its job right :)
332

333         // The last byte of the last instruction in the code array must be the byte at index
334
// code_length-1 : See the do_verify() comments. We actually don't iterate through the
335
// byte array, but use an InstructionList so we cannot check for this. But BCEL does
336
// things right, so it's implicitly okay.
337

338         // TODO: Check how BCEL handles (and will handle) instructions like IMPDEP1, IMPDEP2,
339
// BREAKPOINT... that BCEL knows about but which are illegal anyway.
340
// We currently go the safe way here.
341
InstructionHandle ih = instructionList.getStart();
342         while (ih != null){
343             Instruction i = ih.getInstruction();
344             if (i instanceof IMPDEP1){
345                 throw new StaticCodeInstructionConstraintException("IMPDEP1 must not be in the code, it is an illegal instruction for _internal_ JVM use!");
346             }
347             if (i instanceof IMPDEP2){
348                 throw new StaticCodeInstructionConstraintException("IMPDEP2 must not be in the code, it is an illegal instruction for _internal_ JVM use!");
349             }
350             if (i instanceof BREAKPOINT){
351                 throw new StaticCodeInstructionConstraintException("BREAKPOINT must not be in the code, it is an illegal instruction for _internal_ JVM use!");
352             }
353             ih = ih.getNext();
354         }
355         
356         // The original verifier seems to do this check here, too.
357
// An unreachable last instruction may also not fall through the
358
// end of the code, which is stupid -- but with the original
359
// verifier's subroutine semantics one cannot predict reachability.
360
Instruction last = instructionList.getEnd().getInstruction();
361         if (! ((last instanceof ReturnInstruction) ||
362                     (last instanceof RET) ||
363                     (last instanceof GotoInstruction) ||
364                     (last instanceof ATHROW) )) {
365             throw new StaticCodeInstructionConstraintException("Execution must not fall off the bottom of the code array. This constraint is enforced statically as some existing verifiers do - so it may be a false alarm if the last instruction is not reachable.");
366         }
367     }
368
369     /**
370      * These are the checks for the satisfaction of constraints which are described in the
371      * Java Virtual Machine Specification, Second Edition as Static Constraints on
372      * the operands of instructions of Java Virtual Machine Code (chapter 4.8.1).
373      * BCEL parses the code array to create an InstructionList and therefore has to check
374      * some of these constraints. Additional checks are also implemented here.
375      *
376      * @throws StaticCodeConstraintException if the verification fails.
377      */

378     private void pass3StaticInstructionOperandsChecks(){
379         try {
380         // When building up the InstructionList, BCEL has already done all those checks
381
// mentioned in The Java Virtual Machine Specification, Second Edition, as
382
// "static constraints on the operands of instructions in the code array".
383
// TODO: see the do_verify() comments. Maybe we should really work on the
384
// byte array first to give more comprehensive messages.
385
// TODO: Review Exception API, possibly build in some "offending instruction" thing
386
// when we're ready to insulate the offending instruction by doing the
387
// above thing.
388

389         // TODO: Implement as much as possible here. BCEL does _not_ check everything.
390

391         ConstantPoolGen cpg = new ConstantPoolGen(Repository.lookupClass(myOwner.getClassName()).getConstantPool());
392         InstOperandConstraintVisitor v = new InstOperandConstraintVisitor(cpg);
393     
394         // Checks for the things BCEL does _not_ handle itself.
395
InstructionHandle ih = instructionList.getStart();
396         while (ih != null){
397             Instruction i = ih.getInstruction();
398             
399             // An "own" constraint, due to JustIce's new definition of what "subroutine" means.
400
if (i instanceof JsrInstruction){
401                 InstructionHandle target = ((JsrInstruction) i).getTarget();
402                 if (target == instructionList.getStart()){
403                     throw new StaticCodeInstructionOperandConstraintException("Due to JustIce's clear definition of subroutines, no JSR or JSR_W may have a top-level instruction (such as the very first instruction, which is targeted by instruction '"+ih+"' as its target.");
404                 }
405                 if (!(target.getInstruction() instanceof ASTORE)){
406                     throw new StaticCodeInstructionOperandConstraintException("Due to JustIce's clear definition of subroutines, no JSR or JSR_W may target anything else than an ASTORE instruction. Instruction '"+ih+"' targets '"+target+"'.");
407                 }
408             }
409             
410             // vmspec2, page 134-137
411
ih.accept(v);
412             
413             ih = ih.getNext();
414         }
415
416         } catch (ClassNotFoundException JavaDoc e) {
417         // FIXME: maybe not the best way to handle this
418
throw new AssertionViolatedException("Missing class: " + e.toString());
419         }
420     }
421     
422     /** A small utility method returning if a given int i is in the given int[] ints. */
423     private static boolean contains(int[] ints, int i){
424         for (int j=0; j<ints.length; j++){
425             if (ints[j]==i) {
426                 return true;
427             }
428         }
429         return false;
430     }
431
432     /** Returns the method number as supplied when instantiating. */
433     public int getMethodNo(){
434         return method_no;
435     }
436
437     /**
438      * This visitor class does the actual checking for the instruction
439      * operand's constraints.
440      */

441     private class InstOperandConstraintVisitor extends org.apache.bcel.generic.EmptyVisitor{
442         /** The ConstantPoolGen instance this Visitor operates on. */
443         private ConstantPoolGen cpg;
444
445         /** The only Constructor. */
446         InstOperandConstraintVisitor(ConstantPoolGen cpg){
447             this.cpg = cpg;
448         }
449
450         /**
451          * Utility method to return the max_locals value of the method verified
452          * by the surrounding Pass3aVerifier instance.
453          */

454         private int max_locals(){
455            try {
456             return Repository.lookupClass(myOwner.getClassName()).getMethods()[method_no].getCode().getMaxLocals();
457             } catch (ClassNotFoundException JavaDoc e) {
458             // FIXME: maybe not the best way to handle this
459
throw new AssertionViolatedException("Missing class: " + e.toString());
460             }
461         }
462
463         /**
464          * A utility method to always raise an exeption.
465          */

466         private void constraintViolated(Instruction i, String JavaDoc message) {
467             throw new StaticCodeInstructionOperandConstraintException("Instruction "+i+" constraint violated: "+message);
468         }
469
470         /**
471          * A utility method to raise an exception if the index is not
472          * a valid constant pool index.
473          */

474         private void indexValid(Instruction i, int idx){
475             if (idx < 0 || idx >= cpg.getSize()){
476                 constraintViolated(i, "Illegal constant pool index '"+idx+"'.");
477             }
478         }
479
480         ///////////////////////////////////////////////////////////
481
// The Java Virtual Machine Specification, pages 134-137 //
482
///////////////////////////////////////////////////////////
483
/**
484          * Assures the generic preconditions of a LoadClass instance.
485          * The referenced class is loaded and pass2-verified.
486          */

487         public void visitLoadClass(LoadClass o){
488             ObjectType t = o.getLoadClassType(cpg);
489             if (t != null){// null means "no class is loaded"
490
Verifier v = VerifierFactory.getVerifier(t.getClassName());
491                 VerificationResult vr = v.doPass1();
492                 if (vr.getStatus() != VerificationResult.VERIFIED_OK){
493                     constraintViolated((Instruction) o, "Class '"+o.getLoadClassType(cpg).getClassName()+"' is referenced, but cannot be loaded: '"+vr+"'.");
494                 }
495             }
496         }
497         
498         // The target of each jump and branch instruction [...] must be the opcode [...]
499
// BCEL _DOES_ handle this.
500

501         // tableswitch: BCEL will do it, supposedly.
502

503         // lookupswitch: BCEL will do it, supposedly.
504

505         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
506         // LDC and LDC_W (LDC_W is a subclass of LDC in BCEL's model)
507
public void visitLDC(LDC o){
508             indexValid(o, o.getIndex());
509             Constant c = cpg.getConstant(o.getIndex());
510             if (c instanceof ConstantClass){
511               addMessage("Operand of LDC or LDC_W is CONSTANT_Class '"+c+"' - this is only supported in JDK 1.5 and higher.");
512             }
513             else{
514               if (! ( (c instanceof ConstantInteger) ||
515                       (c instanceof ConstantFloat) ||
516                 (c instanceof ConstantString) ) ){
517             constraintViolated(o, "Operand of LDC or LDC_W must be one of CONSTANT_Integer, CONSTANT_Float or CONSTANT_String, but is '"+c+"'.");
518               }
519             }
520         }
521
522         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
523         // LDC2_W
524
public void visitLDC2_W(LDC2_W o){
525             indexValid(o, o.getIndex());
526             Constant c = cpg.getConstant(o.getIndex());
527             if (! ( (c instanceof ConstantLong) ||
528                             (c instanceof ConstantDouble) ) ){
529                 constraintViolated(o, "Operand of LDC2_W must be CONSTANT_Long or CONSTANT_Double, but is '"+c+"'.");
530             }
531             try{
532                 indexValid(o, o.getIndex()+1);
533             }
534             catch(StaticCodeInstructionOperandConstraintException e){
535                 throw new AssertionViolatedException("OOPS: Does not BCEL handle that? LDC2_W operand has a problem.");
536             }
537         }
538
539         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
540         //getfield, putfield, getstatic, putstatic
541
public void visitFieldInstruction(FieldInstruction o){
542            try {
543             indexValid(o, o.getIndex());
544             Constant c = cpg.getConstant(o.getIndex());
545             if (! (c instanceof ConstantFieldref)){
546                 constraintViolated(o, "Indexing a constant that's not a CONSTANT_Fieldref but a '"+c+"'.");
547             }
548             
549             String JavaDoc field_name = o.getFieldName(cpg);
550  
551             JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
552             Field[] fields = jc.getFields();
553             Field f = null;
554             for (int i=0; i<fields.length; i++){
555                 if (fields[i].getName().equals(field_name)){
556                   Type f_type = Type.getType(fields[i].getSignature());
557                   Type o_type = o.getType(cpg);
558                     /* TODO: Check if assignment compatibility is sufficient.
559                    * What does Sun do?
560                    */

561                   if (f_type.equals(o_type)){
562                         f = fields[i];
563                         break;
564                     }
565                 }
566             }
567             if (f == null){
568                 JavaClass[] superclasses = jc.getSuperClasses();
569                 outer:
570                 for (int j=0; j<superclasses.length; j++){
571                     fields = superclasses[j].getFields();
572                     for (int i=0; i<fields.length; i++){
573                         if (fields[i].getName().equals(field_name)){
574                             Type f_type = Type.getType(fields[i].getSignature());
575                             Type o_type = o.getType(cpg);
576                             if (f_type.equals(o_type)){
577                                 f = fields[i];
578                                 if ((f.getAccessFlags() & (Constants.ACC_PUBLIC | Constants.ACC_PROTECTED)) == 0) {
579                                     f = null;
580                                 }
581                                 break outer;
582                             }
583                         }
584                     }
585                 }
586                 if (f == null) {
587                     constraintViolated(o, "Referenced field '"+field_name+"' does not exist in class '"+jc.getClassName()+"'.");
588                 }
589             }
590             else{
591                 /* TODO: Check if assignment compatibility is sufficient.
592                    What does Sun do? */

593                 Type f_type = Type.getType(f.getSignature());
594                 Type o_type = o.getType(cpg);
595                                 
596                 // Argh. Sun's implementation allows us to have multiple fields of
597
// the same name but with a different signature.
598
//if (! f_type.equals(o_type)){
599
// constraintViolated(o, "Referenced field '"+field_name+"' has type '"+f_type+"' instead of '"+o_type+"' as expected.");
600
//}
601

602                 /* TODO: Check for access modifiers here. */
603             }
604             } catch (ClassNotFoundException JavaDoc e) {
605             // FIXME: maybe not the best way to handle this
606
throw new AssertionViolatedException("Missing class: " + e.toString());
607             }
608         }
609
610         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
611         public void visitInvokeInstruction(InvokeInstruction o){
612             indexValid(o, o.getIndex());
613             if ( (o instanceof INVOKEVIRTUAL) ||
614                         (o instanceof INVOKESPECIAL) ||
615                         (o instanceof INVOKESTATIC) ){
616                 Constant c = cpg.getConstant(o.getIndex());
617                 if (! (c instanceof ConstantMethodref)){
618                     constraintViolated(o, "Indexing a constant that's not a CONSTANT_Methodref but a '"+c+"'.");
619                 }
620                 else{
621                     // Constants are okay due to pass2.
622
ConstantNameAndType cnat = (ConstantNameAndType) (cpg.getConstant(((ConstantMethodref) c).getNameAndTypeIndex()));
623                     ConstantUtf8 cutf8 = (ConstantUtf8) (cpg.getConstant(cnat.getNameIndex()));
624                     if (cutf8.getBytes().equals(Constants.CONSTRUCTOR_NAME) && (!(o instanceof INVOKESPECIAL)) ){
625                         constraintViolated(o, "Only INVOKESPECIAL is allowed to invoke instance initialization methods.");
626                     }
627                     if ( (! (cutf8.getBytes().equals(Constants.CONSTRUCTOR_NAME)) ) && (cutf8.getBytes().startsWith("<")) ){
628                         constraintViolated(o, "No method with a name beginning with '<' other than the instance initialization methods may be called by the method invocation instructions.");
629                     }
630                 }
631             }
632             else{ //if (o instanceof INVOKEINTERFACE){
633
Constant c = cpg.getConstant(o.getIndex());
634                 if (! (c instanceof ConstantInterfaceMethodref)){
635                     constraintViolated(o, "Indexing a constant that's not a CONSTANT_InterfaceMethodref but a '"+c+"'.");
636                 }
637                 // TODO: From time to time check if BCEL allows to detect if the
638
// 'count' operand is consistent with the information in the
639
// CONSTANT_InterfaceMethodref and if the last operand is zero.
640
// By now, BCEL hides those two operands because they're superfluous.
641

642                 // Invoked method must not be <init> or <clinit>
643
ConstantNameAndType cnat = (ConstantNameAndType) (cpg.getConstant(((ConstantInterfaceMethodref)c).getNameAndTypeIndex()));
644                 String JavaDoc name = ((ConstantUtf8) (cpg.getConstant(cnat.getNameIndex()))).getBytes();
645                 if (name.equals(Constants.CONSTRUCTOR_NAME)){
646                     constraintViolated(o, "Method to invoke must not be '"+Constants.CONSTRUCTOR_NAME+"'.");
647                 }
648                 if (name.equals(Constants.STATIC_INITIALIZER_NAME)){
649                     constraintViolated(o, "Method to invoke must not be '"+Constants.STATIC_INITIALIZER_NAME+"'.");
650                 }
651             }
652         
653             // The LoadClassType is the method-declaring class, so we have to check the other types.
654

655             Type t = o.getReturnType(cpg);
656             if (t instanceof ArrayType){
657                 t = ((ArrayType) t).getBasicType();
658             }
659             if (t instanceof ObjectType){
660                 Verifier v = VerifierFactory.getVerifier(((ObjectType) t).getClassName());
661                 VerificationResult vr = v.doPass2();
662                 if (vr.getStatus() != VerificationResult.VERIFIED_OK){
663                     constraintViolated(o, "Return type class/interface could not be verified successfully: '"+vr.getMessage()+"'.");
664                 }
665             }
666             
667             Type[] ts = o.getArgumentTypes(cpg);
668             for (int i=0; i<ts.length; i++){
669                 t = ts[i];
670                 if (t instanceof ArrayType){
671                     t = ((ArrayType) t).getBasicType();
672                 }
673                 if (t instanceof ObjectType){
674                     Verifier v = VerifierFactory.getVerifier(((ObjectType) t).getClassName());
675                     VerificationResult vr = v.doPass2();
676                     if (vr.getStatus() != VerificationResult.VERIFIED_OK){
677                         constraintViolated(o, "Argument type class/interface could not be verified successfully: '"+vr.getMessage()+"'.");
678                     }
679                 }
680             }
681             
682         }
683         
684         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
685         public void visitINSTANCEOF(INSTANCEOF o){
686             indexValid(o, o.getIndex());
687             Constant c = cpg.getConstant(o.getIndex());
688             if (! (c instanceof ConstantClass)){
689                 constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
690             }
691         }
692
693         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
694         public void visitCHECKCAST(CHECKCAST o){
695             indexValid(o, o.getIndex());
696             Constant c = cpg.getConstant(o.getIndex());
697             if (! (c instanceof ConstantClass)){
698                 constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
699             }
700         }
701
702         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
703         public void visitNEW(NEW o){
704             indexValid(o, o.getIndex());
705             Constant c = cpg.getConstant(o.getIndex());
706             if (! (c instanceof ConstantClass)){
707                 constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
708             }
709             else{
710                 ConstantUtf8 cutf8 = (ConstantUtf8) (cpg.getConstant( ((ConstantClass) c).getNameIndex() ));
711                 Type t = Type.getType("L"+cutf8.getBytes()+";");
712                 if (t instanceof ArrayType){
713                     constraintViolated(o, "NEW must not be used to create an array.");
714                 }
715             }
716             
717         }
718
719         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
720         public void visitMULTIANEWARRAY(MULTIANEWARRAY o){
721             indexValid(o, o.getIndex());
722             Constant c = cpg.getConstant(o.getIndex());
723             if (! (c instanceof ConstantClass)){
724                 constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
725             }
726             int dimensions2create = o.getDimensions();
727             if (dimensions2create < 1){
728                 constraintViolated(o, "Number of dimensions to create must be greater than zero.");
729             }
730             Type t = o.getType(cpg);
731             if (t instanceof ArrayType){
732                 int dimensions = ((ArrayType) t).getDimensions();
733                 if (dimensions < dimensions2create){
734                     constraintViolated(o, "Not allowed to create array with more dimensions ('+dimensions2create+') than the one referenced by the CONSTANT_Class '"+t+"'.");
735                 }
736             }
737             else{
738                 constraintViolated(o, "Expecting a CONSTANT_Class referencing an array type. [Constraint not found in The Java Virtual Machine Specification, Second Edition, 4.8.1]");
739             }
740         }
741
742         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
743         public void visitANEWARRAY(ANEWARRAY o){
744             indexValid(o, o.getIndex());
745             Constant c = cpg.getConstant(o.getIndex());
746             if (! (c instanceof ConstantClass)){
747                 constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
748             }
749             Type t = o.getType(cpg);
750             if (t instanceof ArrayType){
751                 int dimensions = ((ArrayType) t).getDimensions();
752                 if (dimensions >= 255){
753                     constraintViolated(o, "Not allowed to create an array with more than 255 dimensions.");
754                 }
755             }
756         }
757
758         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
759         public void visitNEWARRAY(NEWARRAY o){
760             byte t = o.getTypecode();
761             if (! ( (t == Constants.T_BOOLEAN) ||
762                             (t == Constants.T_CHAR) ||
763                             (t == Constants.T_FLOAT) ||
764                             (t == Constants.T_DOUBLE) ||
765                             (t == Constants.T_BYTE) ||
766                             (t == Constants.T_SHORT) ||
767                             (t == Constants.T_INT) ||
768                             (t == Constants.T_LONG) ) ){
769                 constraintViolated(o, "Illegal type code '+t+' for 'atype' operand.");
770             }
771         }
772
773         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
774         public void visitILOAD(ILOAD o){
775             int idx = o.getIndex();
776             if (idx < 0){
777                 constraintViolated(o, "Index '"+idx+"' must be non-negative.");
778             }
779             else{
780                 int maxminus1 = max_locals()-1;
781                 if (idx > maxminus1){
782                     constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
783                 }
784             }
785         }
786
787         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
788         public void visitFLOAD(FLOAD o){
789             int idx = o.getIndex();
790             if (idx < 0){
791                 constraintViolated(o, "Index '"+idx+"' must be non-negative.");
792             }
793             else{
794                 int maxminus1 = max_locals()-1;
795                 if (idx > maxminus1){
796                     constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
797                 }
798             }
799         }
800
801         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
802         public void visitALOAD(ALOAD o){
803             int idx = o.getIndex();
804             if (idx < 0){
805                 constraintViolated(o, "Index '"+idx+"' must be non-negative.");
806             }
807             else{
808                 int maxminus1 = max_locals()-1;
809                 if (idx > maxminus1){
810                     constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
811                 }
812             }
813         }
814         
815         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
816         public void visitISTORE(ISTORE o){
817             int idx = o.getIndex();
818             if (idx < 0){
819                 constraintViolated(o, "Index '"+idx+"' must be non-negative.");
820             }
821             else{
822                 int maxminus1 = max_locals()-1;
823                 if (idx > maxminus1){
824                     constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
825                 }
826             }
827         }
828         
829         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
830         public void visitFSTORE(FSTORE o){
831             int idx = o.getIndex();
832             if (idx < 0){
833                 constraintViolated(o, "Index '"+idx+"' must be non-negative.");
834             }
835             else{
836                 int maxminus1 = max_locals()-1;
837                 if (idx > maxminus1){
838                     constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
839                 }
840             }
841         }
842
843         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
844         public void visitASTORE(ASTORE o){
845             int idx = o.getIndex();
846             if (idx < 0){
847                 constraintViolated(o, "Index '"+idx+"' must be non-negative.");
848             }
849             else{
850                 int maxminus1 = max_locals()-1;
851                 if (idx > maxminus1){
852                     constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
853                 }
854             }
855         }
856
857         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
858         public void visitIINC(IINC o){
859             int idx = o.getIndex();
860             if (idx < 0){
861                 constraintViolated(o, "Index '"+idx+"' must be non-negative.");
862             }
863             else{
864                 int maxminus1 = max_locals()-1;
865                 if (idx > maxminus1){
866                     constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
867                 }
868             }
869         }
870
871         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
872         public void visitRET(RET o){
873             int idx = o.getIndex();
874             if (idx < 0){
875                 constraintViolated(o, "Index '"+idx+"' must be non-negative.");
876             }
877             else{
878                 int maxminus1 = max_locals()-1;
879                 if (idx > maxminus1){
880                     constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
881                 }
882             }
883         }
884
885         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
886         public void visitLLOAD(LLOAD o){
887             int idx = o.getIndex();
888             if (idx < 0){
889                 constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
890             }
891             else{
892                 int maxminus2 = max_locals()-2;
893                 if (idx > maxminus2){
894                     constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'.");
895                 }
896             }
897         }
898         
899         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
900         public void visitDLOAD(DLOAD o){
901             int idx = o.getIndex();
902             if (idx < 0){
903                 constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
904             }
905             else{
906                 int maxminus2 = max_locals()-2;
907                 if (idx > maxminus2){
908                     constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'.");
909                 }
910             }
911         }
912         
913         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
914         public void visitLSTORE(LSTORE o){
915             int idx = o.getIndex();
916             if (idx < 0){
917                 constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
918             }
919             else{
920                 int maxminus2 = max_locals()-2;
921                 if (idx > maxminus2){
922                     constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'.");
923                 }
924             }
925         }
926         
927         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
928         public void visitDSTORE(DSTORE o){
929             int idx = o.getIndex();
930             if (idx < 0){
931                 constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
932             }
933             else{
934                 int maxminus2 = max_locals()-2;
935                 if (idx > maxminus2){
936                     constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'.");
937                 }
938             }
939         }
940
941         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
942         public void visitLOOKUPSWITCH(LOOKUPSWITCH o){
943             int[] matchs = o.getMatchs();
944             int max = Integer.MIN_VALUE;
945             for (int i=0; i<matchs.length; i++){
946                 if (matchs[i] == max && i != 0){
947                     constraintViolated(o, "Match '"+matchs[i]+"' occurs more than once.");
948                 }
949                 if (matchs[i] < max){
950                     constraintViolated(o, "Lookup table must be sorted but isn't.");
951                 }
952                 else{
953                     max = matchs[i];
954                 }
955             }
956         }
957
958         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
959         public void visitTABLESWITCH(TABLESWITCH o){
960             // "high" must be >= "low". We cannot check this, as BCEL hides
961
// it from us.
962
}
963
964         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
965         public void visitPUTSTATIC(PUTSTATIC o){
966             try {
967             String JavaDoc field_name = o.getFieldName(cpg);
968             JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
969             Field[] fields = jc.getFields();
970             Field f = null;
971             for (int i=0; i<fields.length; i++){
972                 if (fields[i].getName().equals(field_name)){
973                     f = fields[i];
974                     break;
975                 }
976             }
977             if (f == null){
978                 throw new AssertionViolatedException("Field not found?!?");
979             }
980
981             if (f.isFinal()){
982                 if (!(myOwner.getClassName().equals(o.getClassType(cpg).getClassName()))){
983                     constraintViolated(o, "Referenced field '"+f+"' is final and must therefore be declared in the current class '"+myOwner.getClassName()+"' which is not the case: it is declared in '"+o.getClassType(cpg).getClassName()+"'.");
984                 }
985             }
986
987             if (! (f.isStatic())){
988                 constraintViolated(o, "Referenced field '"+f+"' is not static which it should be.");
989             }
990
991             String JavaDoc meth_name = Repository.lookupClass(myOwner.getClassName()).getMethods()[method_no].getName();
992
993             // If it's an interface, it can be set only in <clinit>.
994
if ((!(jc.isClass())) && (!(meth_name.equals(Constants.STATIC_INITIALIZER_NAME)))){
995                 constraintViolated(o, "Interface field '"+f+"' must be set in a '"+Constants.STATIC_INITIALIZER_NAME+"' method.");
996             }
997             } catch (ClassNotFoundException JavaDoc e) {
998             // FIXME: maybe not the best way to handle this
999
throw new AssertionViolatedException("Missing class: " + e.toString());
1000            }
1001        }
1002
1003        /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
1004        public void visitGETSTATIC(GETSTATIC o){
1005            try {
1006            String JavaDoc field_name = o.getFieldName(cpg);
1007            JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
1008            Field[] fields = jc.getFields();
1009            Field f = null;
1010            for (int i=0; i<fields.length; i++){
1011                if (fields[i].getName().equals(field_name)){
1012                    f = fields[i];
1013                    break;
1014                }
1015            }
1016            if (f == null){
1017                throw new AssertionViolatedException("Field not found?!?");
1018            }
1019
1020            if (! (f.isStatic())){
1021                constraintViolated(o, "Referenced field '"+f+"' is not static which it should be.");
1022            }
1023            } catch (ClassNotFoundException JavaDoc e) {
1024            // FIXME: maybe not the best way to handle this
1025
throw new AssertionViolatedException("Missing class: " + e.toString());
1026            }
1027        }
1028
1029        /* Checks if the constraints of operands of the said instruction(s) are satisfied. */
1030        //public void visitPUTFIELD(PUTFIELD o){
1031
// for performance reasons done in Pass 3b
1032
//}
1033

1034        /* Checks if the constraints of operands of the said instruction(s) are satisfied. */
1035        //public void visitGETFIELD(GETFIELD o){
1036
// for performance reasons done in Pass 3b
1037
//}
1038

1039        /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
1040        public void visitINVOKEINTERFACE(INVOKEINTERFACE o){
1041            try {
1042            // INVOKEINTERFACE is a LoadClass; the Class where the referenced method is declared in,
1043
// is therefore resolved/verified.
1044
// INVOKEINTERFACE is an InvokeInstruction, the argument and return types are resolved/verified,
1045
// too. So are the allowed method names.
1046
String JavaDoc classname = o.getClassName(cpg);
1047            JavaClass jc = Repository.lookupClass(classname);
1048            Method[] ms = jc.getMethods();
1049            Method m = null;
1050            for (int i=0; i<ms.length; i++){
1051                if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
1052                     (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
1053                     (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
1054                    m = ms[i];
1055                    break;
1056                }
1057            }
1058            if (m == null){
1059                constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature '"+o.getSignature(cpg)+"' not found in class '"+jc.getClassName()+"'. The native verifier does allow the method to be declared in some superinterface, which the Java Virtual Machine Specification, Second Edition does not.");
1060            }
1061            if (jc.isClass()){
1062                constraintViolated(o, "Referenced class '"+jc.getClassName()+"' is a class, but not an interface as expected.");
1063            }
1064            } catch (ClassNotFoundException JavaDoc e) {
1065            // FIXME: maybe not the best way to handle this
1066
throw new AssertionViolatedException("Missing class: " + e.toString());
1067            }
1068        }
1069
1070        /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
1071        public void visitINVOKESPECIAL(INVOKESPECIAL o){
1072            try {
1073            // INVOKESPECIAL is a LoadClass; the Class where the referenced method is declared in,
1074
// is therefore resolved/verified.
1075
// INVOKESPECIAL is an InvokeInstruction, the argument and return types are resolved/verified,
1076
// too. So are the allowed method names.
1077
String JavaDoc classname = o.getClassName(cpg);
1078            JavaClass jc = Repository.lookupClass(classname);
1079            Method[] ms = jc.getMethods();
1080            Method m = null;
1081            for (int i=0; i<ms.length; i++){
1082                if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
1083                     (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
1084                     (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
1085                    m = ms[i];
1086                    break;
1087                }
1088            }
1089            if (m == null){
1090                constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature '"+o.getSignature(cpg)+"' not found in class '"+jc.getClassName()+"'. The native verifier does allow the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not.");
1091            }
1092            
1093            JavaClass current = Repository.lookupClass(myOwner.getClassName());
1094            if (current.isSuper()){
1095            
1096                if ((Repository.instanceOf( current, jc )) && (!current.equals(jc))){
1097                    
1098                    if (! (o.getMethodName(cpg).equals(Constants.CONSTRUCTOR_NAME) )){
1099                        // Special lookup procedure for ACC_SUPER classes.
1100

1101                        int supidx = -1;
1102                        
1103                        Method meth = null;
1104                        while (supidx != 0){
1105                            supidx = current.getSuperclassNameIndex();
1106                            current = Repository.lookupClass(current.getSuperclassName());
1107                            
1108                            Method[] meths = current.getMethods();
1109                            for (int i=0; i<meths.length; i++){
1110                                if ( (meths[i].getName().equals(o.getMethodName(cpg))) &&
1111                                    (Type.getReturnType(meths[i].getSignature()).equals(o.getReturnType(cpg))) &&
1112                                    (objarrayequals(Type.getArgumentTypes(meths[i].getSignature()), o.getArgumentTypes(cpg))) ){
1113                                    meth = meths[i];
1114                                    break;
1115                                }
1116                            }
1117                            if (meth != null) {
1118                                break;
1119                            }
1120                        }
1121                        if (meth == null){
1122                            constraintViolated(o, "ACC_SUPER special lookup procedure not successful: method '"+o.getMethodName(cpg)+"' with proper signature not declared in superclass hierarchy.");
1123                        }
1124                    }
1125                }
1126            }
1127            
1128            } catch (ClassNotFoundException JavaDoc e) {
1129            // FIXME: maybe not the best way to handle this
1130
throw new AssertionViolatedException("Missing class: " + e.toString());
1131            }
1132            
1133        }
1134        
1135        /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
1136        public void visitINVOKESTATIC(INVOKESTATIC o){
1137            try {
1138            // INVOKESTATIC is a LoadClass; the Class where the referenced method is declared in,
1139
// is therefore resolved/verified.
1140
// INVOKESTATIC is an InvokeInstruction, the argument and return types are resolved/verified,
1141
// too. So are the allowed method names.
1142
String JavaDoc classname = o.getClassName(cpg);
1143            JavaClass jc = Repository.lookupClass(classname);
1144            Method[] ms = jc.getMethods();
1145            Method m = null;
1146            for (int i=0; i<ms.length; i++){
1147                if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
1148                     (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
1149                     (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
1150                    m = ms[i];
1151                    break;
1152                }
1153            }
1154            if (m == null){
1155                constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature '"+o.getSignature(cpg) +"' not found in class '"+jc.getClassName()+"'. The native verifier possibly allows the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not.");
1156            } else if (! (m.isStatic())){ // implies it's not abstract, verified in pass 2.
1157
constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' has ACC_STATIC unset.");
1158            }
1159        
1160            } catch (ClassNotFoundException JavaDoc e) {
1161            // FIXME: maybe not the best way to handle this
1162
throw new AssertionViolatedException("Missing class: " + e.toString());
1163            }
1164        }
1165
1166
1167        /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
1168        public void visitINVOKEVIRTUAL(INVOKEVIRTUAL o){
1169            try {
1170            // INVOKEVIRTUAL is a LoadClass; the Class where the referenced method is declared in,
1171
// is therefore resolved/verified.
1172
// INVOKEVIRTUAL is an InvokeInstruction, the argument and return types are resolved/verified,
1173
// too. So are the allowed method names.
1174
String JavaDoc classname = o.getClassName(cpg);
1175            JavaClass jc = Repository.lookupClass(classname);
1176            Method[] ms = jc.getMethods();
1177            Method m = null;
1178            for (int i=0; i<ms.length; i++){
1179                if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
1180                     (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
1181                     (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
1182                    m = ms[i];
1183                    break;
1184                }
1185            }
1186            if (m == null){
1187                constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature '"+o.getSignature(cpg)+"' not found in class '"+jc.getClassName()+"'. The native verifier does allow the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not.");
1188            }
1189            if (! (jc.isClass())){
1190                constraintViolated(o, "Referenced class '"+jc.getClassName()+"' is an interface, but not a class as expected.");
1191            }
1192                    
1193            } catch (ClassNotFoundException JavaDoc e) {
1194            // FIXME: maybe not the best way to handle this
1195
throw new AssertionViolatedException("Missing class: " + e.toString());
1196            }
1197        }
1198
1199        
1200        // WIDE stuff is BCEL-internal and cannot be checked here.
1201

1202        /**
1203         * A utility method like equals(Object) for arrays.
1204         * The equality of the elements is based on their equals(Object)
1205         * method instead of their object identity.
1206         */

1207        private boolean objarrayequals(Object JavaDoc[] o, Object JavaDoc[] p){
1208            if (o.length != p.length){
1209                return false;
1210            }
1211            
1212            for (int i=0; i<o.length; i++){
1213                if (! (o[i].equals(p[i])) ){
1214                    return false;
1215                }
1216            }
1217            
1218            return true;
1219        }
1220
1221    }
1222}
1223
Popular Tags