KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > bcel > internal > verifier > statics > Pass3aVerifier


1 package com.sun.org.apache.bcel.internal.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 com.sun.org.apache.bcel.internal.*;
58 import com.sun.org.apache.bcel.internal.generic.*;
59 import com.sun.org.apache.bcel.internal.classfile.*;
60 import com.sun.org.apache.bcel.internal.verifier.*;
61 import com.sun.org.apache.bcel.internal.verifier.exc.*;
62 import java.util.ArrayList JavaDoc;
63 import java.util.HashMap JavaDoc;
64
65 /**
66  * This PassVerifier verifies a class file according to
67  * pass 3, static part as described in The Java Virtual
68  * Machine Specification, 2nd edition.
69  * More detailed information is to be found at the do_verify()
70  * method's documentation.
71  *
72  * @version $Id: Pass3aVerifier.java,v 1.1.1.1 2001/10/29 20:00:37 jvanzyl Exp $
73  * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
74  * @see #do_verify()
75  */

76 public final class Pass3aVerifier extends PassVerifier{
77
78     /** The Verifier that created this. */
79     private Verifier myOwner;
80
81     /**
82      * The method number to verify.
83      * This is the index in the array returned
84      * by JavaClass.getMethods().
85      */

86     private int method_no;
87
88     /** 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. */
89     InstructionList instructionList;
90     /** 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. */
91     Code code;
92
93     /** Should only be instantiated by a Verifier. */
94     public Pass3aVerifier(Verifier owner, int method_no){
95         myOwner = owner;
96         this.method_no = method_no;
97     }
98
99     /**
100      * Pass 3a is the verification of static constraints of
101      * JVM code (such as legal targets of branch instructions).
102      * This is the part of pass 3 where you do not need data
103      * flow analysis.
104      * JustIce also delays the checks for a correct exception
105      * table of a Code attribute and correct line number entries
106      * in a LineNumberTable attribute of a Code attribute (which
107      * conceptually belong to pass 2) to this pass. Also, most
108      * of the check for valid local variable entries in a
109      * LocalVariableTable attribute of a Code attribute is
110      * delayed until this pass.
111      * All these checks need access to the code array of the
112      * Code attribute.
113      *
114      * @throws InvalidMethodException if the method to verify does not exist.
115      */

116     public VerificationResult do_verify(){
117         if (myOwner.doPass2().equals(VerificationResult.VR_OK)){
118             // Okay, class file was loaded correctly by Pass 1
119
// and satisfies static constraints of Pass 2.
120
JavaClass jc = Repository.lookupClass(myOwner.getClassName());
121             Method[] methods = jc.getMethods();
122             if (method_no >= methods.length){
123                 throw new InvalidMethodException("METHOD DOES NOT EXIST!");
124             }
125             Method method = methods[method_no];
126             code = method.getCode();
127             
128             // No Code? Nothing to verify!
129
if ( method.isAbstract() || method.isNative() ){ // IF mg HAS NO CODE (static constraint of Pass 2)
130
return VerificationResult.VR_OK;
131             }
132
133             // TODO:
134
// We want a very sophisticated code examination here with good explanations
135
// on where to look for an illegal instruction or such.
136
// Only after that we should try to build an InstructionList and throw an
137
// AssertionViolatedException if after our examination InstructionList building
138
// still fails.
139
// That examination should be implemented in a byte-oriented way, i.e. look for
140
// an instruction, make sure its validity, count its length, find the next
141
// instruction and so on.
142
try{
143                 instructionList = new InstructionList(method.getCode().getCode());
144             }
145             catch(RuntimeException JavaDoc re){
146                 return new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Bad bytecode in the code array of the Code attribute of method '"+method+"'.");
147             }
148             
149             instructionList.setPositions(true);
150
151             // Start verification.
152
VerificationResult vr = VerificationResult.VR_OK; //default
153
try{
154                 delayedPass2Checks();
155             }
156             catch(ClassConstraintException cce){
157                 vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, cce.getMessage());
158                 return vr;
159             }
160             try{
161                 pass3StaticInstructionChecks();
162                 pass3StaticInstructionOperandsChecks();
163             }
164             catch(StaticCodeConstraintException scce){
165                 vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, scce.getMessage());
166             }
167             return vr;
168         }
169         else{ //did not pass Pass 2.
170
return VerificationResult.VR_NOTYET;
171         }
172     }
173
174     /**
175      * These are the checks that could be done in pass 2 but are delayed to pass 3
176      * for performance reasons. Also, these checks need access to the code array
177      * of the Code attribute of a Method so it's okay to perform them here.
178      * Also see the description of the do_verify() method.
179      *
180      * @throws ClassConstraintException if the verification fails.
181      * @see #do_verify()
182      */

183     private void delayedPass2Checks(){
184
185         int[] instructionPositions = instructionList.getInstructionPositions();
186         int codeLength = code.getCode().length;
187
188         /////////////////////
189
// LineNumberTable //
190
/////////////////////
191
LineNumberTable lnt = code.getLineNumberTable();
192         if (lnt != null){
193             LineNumber[] lineNumbers = lnt.getLineNumberTable();
194             IntList offsets = new IntList();
195             lineNumber_loop: for (int i=0; i < lineNumbers.length; i++){ // may appear in any order.
196
for (int j=0; j < instructionPositions.length; j++){
197                     // TODO: Make this a binary search! The instructionPositions array is naturally ordered!
198
int offset = lineNumbers[i].getStartPC();
199                     if (instructionPositions[j] == offset){
200                         if (offsets.contains(offset)){
201                             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].");
202                         }
203                         else{
204                             offsets.add(offset);
205                         }
206                         continue lineNumber_loop;
207                     }
208                 }
209                 throw new ClassConstraintException("Code attribute '"+code+"' has a LineNumberTable attribute '"+code.getLineNumberTable()+"' referring to a code offset ('"+lineNumbers[i].getStartPC()+"') that does not exist.");
210             }
211         }
212
213         ///////////////////////////
214
// LocalVariableTable(s) //
215
///////////////////////////
216
/* We cannot use code.getLocalVariableTable() because there could be more
217            than only one. This is a bug in BCEL. */

218         Attribute[] atts = code.getAttributes();
219         for (int a=0; a<atts.length; a++){
220             if (atts[a] instanceof LocalVariableTable){
221                 LocalVariableTable lvt = (LocalVariableTable) atts[a];
222                 if (lvt != null){
223                     LocalVariable[] localVariables = lvt.getLocalVariableTable();
224                     for (int i=0; i<localVariables.length; i++){
225                         int startpc = localVariables[i].getStartPC();
226                         int length = localVariables[i].getLength();
227                 
228                         if (!contains(instructionPositions, startpc)){
229                             throw new ClassConstraintException("Code attribute '"+code+"' has a LocalVariableTable attribute '"+code.getLocalVariableTable()+"' referring to a code offset ('"+startpc+"') that does not exist.");
230                         }
231                         if ( (!contains(instructionPositions, startpc+length)) && (startpc+length != codeLength) ){
232                             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.");
233                         }
234                     }
235                 }
236             }
237         }
238         
239         ////////////////////
240
// ExceptionTable //
241
////////////////////
242
// In BCEL's "classfile" API, the startPC/endPC-notation is
243
// inclusive/exclusive as in the Java Virtual Machine Specification.
244
// WARNING: This is not true for BCEL's "generic" API.
245
CodeException[] exceptionTable = code.getExceptionTable();
246         for (int i=0; i<exceptionTable.length; i++){
247             int startpc = exceptionTable[i].getStartPC();
248             int endpc = exceptionTable[i].getEndPC();
249             int handlerpc = exceptionTable[i].getHandlerPC();
250             if (startpc >= endpc){
251                 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+"').");
252             }
253             if (!contains(instructionPositions, startpc)){
254                 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+"').");
255             }
256             if ( (!contains(instructionPositions, endpc)) && (endpc != codeLength)){
257                 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+"')].");
258             }
259             if (!contains(instructionPositions, handlerpc)){
260                 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+"').");
261             }
262         }
263     }
264
265     /**
266      * These are the checks if constraints are satisfied which are described in the
267      * Java Virtual Machine Specification, Second Edition as Static Constraints on
268      * the instructions of Java Virtual Machine Code (chapter 4.8.1).
269      *
270      * @throws StaticCodeConstraintException if the verification fails.
271      */

272     private void pass3StaticInstructionChecks(){
273         
274         // Code array must not be empty:
275
// Enforced in pass 2 (also stated in the static constraints of the Code
276
// array in vmspec2), together with pass 1 (reading code_length bytes and
277
// interpreting them as code[]). So this must not be checked again here.
278

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

285         // Only instances of the instructions documented in Section 6.4 may appear in
286
// the code array.
287

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

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

295         // TODO: Check how BCEL handles (and will handle) instructions like IMPDEP1, IMPDEP2,
296
// BREAKPOINT... that BCEL knows about but which are illegal anyway.
297
// We currently go the safe way here.
298
InstructionHandle ih = instructionList.getStart();
299         while (ih != null){
300             Instruction i = ih.getInstruction();
301             if (i instanceof IMPDEP1){
302                 throw new StaticCodeInstructionConstraintException("IMPDEP1 must not be in the code, it is an illegal instruction for _internal_ JVM use!");
303             }
304             if (i instanceof IMPDEP2){
305                 throw new StaticCodeInstructionConstraintException("IMPDEP2 must not be in the code, it is an illegal instruction for _internal_ JVM use!");
306             }
307             if (i instanceof BREAKPOINT){
308                 throw new StaticCodeInstructionConstraintException("BREAKPOINT must not be in the code, it is an illegal instruction for _internal_ JVM use!");
309             }
310             ih = ih.getNext();
311         }
312         
313         // The original verifier seems to do this check here, too.
314
// An unreachable last instruction may also not fall through the
315
// end of the code, which is stupid -- but with the original
316
// verifier's subroutine semantics one cannot predict reachability.
317
Instruction last = instructionList.getEnd().getInstruction();
318         if (! ((last instanceof ReturnInstruction) ||
319                     (last instanceof RET) ||
320                     (last instanceof GotoInstruction) ||
321                     (last instanceof ATHROW) )) // JSR / JSR_W would possibly RETurn and then fall off the code!
322
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.");
323     }
324
325     /**
326      * These are the checks for the satisfaction of constraints which are described in the
327      * Java Virtual Machine Specification, Second Edition as Static Constraints on
328      * the operands of instructions of Java Virtual Machine Code (chapter 4.8.1).
329      * BCEL parses the code array to create an InstructionList and therefore has to check
330      * some of these constraints. Additional checks are also implemented here.
331      *
332      * @throws StaticCodeConstraintException if the verification fails.
333      */

334     private void pass3StaticInstructionOperandsChecks(){
335         // When building up the InstructionList, BCEL has already done all those checks
336
// mentioned in The Java Virtual Machine Specification, Second Edition, as
337
// "static constraints on the operands of instructions in the code array".
338
// TODO: see the do_verify() comments. Maybe we should really work on the
339
// byte array first to give more comprehensive messages.
340
// TODO: Review Exception API, possibly build in some "offending instruction" thing
341
// when we're ready to insulate the offending instruction by doing the
342
// above thing.
343

344         // TODO: Implement as much as possible here. BCEL does _not_ check everything.
345

346         ConstantPoolGen cpg = new ConstantPoolGen(Repository.lookupClass(myOwner.getClassName()).getConstantPool());
347         InstOperandConstraintVisitor v = new InstOperandConstraintVisitor(cpg);
348     
349         // Checks for the things BCEL does _not_ handle itself.
350
InstructionHandle ih = instructionList.getStart();
351         while (ih != null){
352             Instruction i = ih.getInstruction();
353             
354             // An "own" constraint, due to JustIce's new definition of what "subroutine" means.
355
if (i instanceof JsrInstruction){
356                 InstructionHandle target = ((JsrInstruction) i).getTarget();
357                 if (target == instructionList.getStart()){
358                     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.");
359                 }
360                 if (!(target.getInstruction() instanceof ASTORE)){
361                     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+"'.");
362                 }
363             }
364             
365             // vmspec2, page 134-137
366
ih.accept(v);
367             
368             ih = ih.getNext();
369         }
370
371     }
372     
373     /** A small utility method returning if a given int i is in the given int[] ints. */
374     private static boolean contains(int[] ints, int i){
375         for (int j=0; j<ints.length; j++){
376             if (ints[j]==i) return true;
377         }
378         return false;
379     }
380
381     /** Returns the method number as supplied when instantiating. */
382     public int getMethodNo(){
383         return method_no;
384     }
385
386     /**
387      * This visitor class does the actual checking for the instruction
388      * operand's constraints.
389      */

390     private class InstOperandConstraintVisitor extends com.sun.org.apache.bcel.internal.generic.EmptyVisitor{
391         /** The ConstantPoolGen instance this Visitor operates on. */
392         private ConstantPoolGen cpg;
393
394         /** The only Constructor. */
395         InstOperandConstraintVisitor(ConstantPoolGen cpg){
396             this.cpg = cpg;
397         }
398
399         /**
400          * Utility method to return the max_locals value of the method verified
401          * by the surrounding Pass3aVerifier instance.
402          */

403         private int max_locals(){
404             return Repository.lookupClass(myOwner.getClassName()).getMethods()[method_no].getCode().getMaxLocals();
405         }
406
407         /**
408          * A utility method to always raise an exeption.
409          */

410         private void constraintViolated(Instruction i, String JavaDoc message) {
411             throw new StaticCodeInstructionOperandConstraintException("Instruction "+i+" constraint violated: "+message);
412         }
413
414         /**
415          * A utility method to raise an exception if the index is not
416          * a valid constant pool index.
417          */

418         private void indexValid(Instruction i, int idx){
419             if (idx < 0 || idx >= cpg.getSize()){
420                 constraintViolated(i, "Illegal constant pool index '"+idx+"'.");
421             }
422         }
423
424         ///////////////////////////////////////////////////////////
425
// The Java Virtual Machine Specification, pages 134-137 //
426
///////////////////////////////////////////////////////////
427
/**
428          * Assures the generic preconditions of a LoadClass instance.
429          * The referenced class is loaded and pass2-verified.
430          */

431         public void visitLoadClass(LoadClass o){
432             ObjectType t = o.getLoadClassType(cpg);
433             if (t != null){// null means "no class is loaded"
434
Verifier v = VerifierFactory.getVerifier(t.getClassName());
435                 VerificationResult vr = v.doPass1();
436                 if (vr.getStatus() != VerificationResult.VERIFIED_OK){
437                     constraintViolated((Instruction) o, "Class '"+o.getLoadClassType(cpg).getClassName()+"' is referenced, but cannot be loaded: '"+vr+"'.");
438                 }
439             }
440         }
441         
442         // The target of each jump and branch instruction [...] must be the opcode [...]
443
// BCEL _DOES_ handle this.
444

445         // tableswitch: BCEL will do it, supposedly.
446

447         // lookupswitch: BCEL will do it, supposedly.
448

449         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
450         // LDC and LDC_W (LDC_W is a subclass of LDC in BCEL's model)
451
public void visitLDC(LDC o){
452             indexValid(o, o.getIndex());
453             Constant c = cpg.getConstant(o.getIndex());
454             if (! ( (c instanceof ConstantInteger) ||
455                             (c instanceof ConstantFloat) ||
456                             (c instanceof ConstantString) ) ){
457                 constraintViolated(o, "Operand of LDC or LDC_W must be one of CONSTANT_Integer, CONSTANT_Float or CONSTANT_String, but is '"+c+"'.");
458             }
459         }
460
461         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
462         // LDC2_W
463
public void visitLDC2_W(LDC2_W o){
464             indexValid(o, o.getIndex());
465             Constant c = cpg.getConstant(o.getIndex());
466             if (! ( (c instanceof ConstantLong) ||
467                             (c instanceof ConstantDouble) ) ){
468                 constraintViolated(o, "Operand of LDC2_W must be CONSTANT_Long or CONSTANT_Double, but is '"+c+"'.");
469             }
470             try{
471                 indexValid(o, o.getIndex()+1);
472             }
473             catch(StaticCodeInstructionOperandConstraintException e){
474                 throw new AssertionViolatedException("OOPS: Does not BCEL handle that? LDC2_W operand has a problem.");
475             }
476         }
477
478         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
479         //getfield, putfield, getstatic, putstatic
480
public void visitFieldInstruction(FieldInstruction o){
481             indexValid(o, o.getIndex());
482             Constant c = cpg.getConstant(o.getIndex());
483             if (! (c instanceof ConstantFieldref)){
484                 constraintViolated(o, "Indexing a constant that's not a CONSTANT_Fieldref but a '"+c+"'.");
485             }
486         }
487
488         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
489         public void visitInvokeInstruction(InvokeInstruction o){
490             indexValid(o, o.getIndex());
491             if ( (o instanceof INVOKEVIRTUAL) ||
492                         (o instanceof INVOKESPECIAL) ||
493                         (o instanceof INVOKESTATIC) ){
494                 Constant c = cpg.getConstant(o.getIndex());
495                 if (! (c instanceof ConstantMethodref)){
496                     constraintViolated(o, "Indexing a constant that's not a CONSTANT_Methodref but a '"+c+"'.");
497                 }
498                 else{
499                     // Constants are okay due to pass2.
500
ConstantNameAndType cnat = (ConstantNameAndType) (cpg.getConstant(((ConstantMethodref) c).getNameAndTypeIndex()));
501                     ConstantUtf8 cutf8 = (ConstantUtf8) (cpg.getConstant(cnat.getNameIndex()));
502                     if (cutf8.getBytes().equals(Constants.CONSTRUCTOR_NAME) && (!(o instanceof INVOKESPECIAL)) ){
503                         constraintViolated(o, "Only INVOKESPECIAL is allowed to invoke instance initialization methods.");
504                     }
505                     if ( (! (cutf8.getBytes().equals(Constants.CONSTRUCTOR_NAME)) ) && (cutf8.getBytes().startsWith("<")) ){
506                         constraintViolated(o, "No method with a name beginning with '<' other than the instance initialization methods may be called by the method invocation instructions.");
507                     }
508                 }
509             }
510             else{ //if (o instanceof INVOKEINTERFACE){
511
Constant c = cpg.getConstant(o.getIndex());
512                 if (! (c instanceof ConstantInterfaceMethodref)){
513                     constraintViolated(o, "Indexing a constant that's not a CONSTANT_InterfaceMethodref but a '"+c+"'.");
514                 }
515                 // TODO: From time to time check if BCEL allows to detect if the
516
// 'count' operand is consistent with the information in the
517
// CONSTANT_InterfaceMethodref and if the last operand is zero.
518
// By now, BCEL hides those two operands because they're superfluous.
519

520                 // Invoked method must not be <init> or <clinit>
521
ConstantNameAndType cnat = (ConstantNameAndType) (cpg.getConstant(((ConstantInterfaceMethodref)c).getNameAndTypeIndex()));
522                 String JavaDoc name = ((ConstantUtf8) (cpg.getConstant(cnat.getNameIndex()))).getBytes();
523                 if (name.equals(Constants.CONSTRUCTOR_NAME)){
524                     constraintViolated(o, "Method to invoke must not be '"+Constants.CONSTRUCTOR_NAME+"'.");
525                 }
526                 if (name.equals(Constants.STATIC_INITIALIZER_NAME)){
527                     constraintViolated(o, "Method to invoke must not be '"+Constants.STATIC_INITIALIZER_NAME+"'.");
528                 }
529             }
530         
531             // The LoadClassType is the method-declaring class, so we have to check the other types.
532

533             Type t = o.getReturnType(cpg);
534             if (t instanceof ArrayType){
535                 t = ((ArrayType) t).getBasicType();
536             }
537             if (t instanceof ObjectType){
538                 Verifier v = VerifierFactory.getVerifier(((ObjectType) t).getClassName());
539                 VerificationResult vr = v.doPass2();
540                 if (vr.getStatus() != VerificationResult.VERIFIED_OK){
541                     constraintViolated(o, "Return type class/interface could not be verified successfully: '"+vr.getMessage()+"'.");
542                 }
543             }
544             
545             Type[] ts = o.getArgumentTypes(cpg);
546             for (int i=0; i<ts.length; i++){
547                 t = ts[i];
548                 if (t instanceof ArrayType){
549                     t = ((ArrayType) t).getBasicType();
550                 }
551                 if (t instanceof ObjectType){
552                     Verifier v = VerifierFactory.getVerifier(((ObjectType) t).getClassName());
553                     VerificationResult vr = v.doPass2();
554                     if (vr.getStatus() != VerificationResult.VERIFIED_OK){
555                         constraintViolated(o, "Argument type class/interface could not be verified successfully: '"+vr.getMessage()+"'.");
556                     }
557                 }
558             }
559             
560         }
561         
562         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
563         public void visitINSTANCEOF(INSTANCEOF o){
564             indexValid(o, o.getIndex());
565             Constant c = cpg.getConstant(o.getIndex());
566             if (! (c instanceof ConstantClass)){
567                 constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
568             }
569         }
570
571         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
572         public void visitCHECKCAST(CHECKCAST o){
573             indexValid(o, o.getIndex());
574             Constant c = cpg.getConstant(o.getIndex());
575             if (! (c instanceof ConstantClass)){
576                 constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
577             }
578         }
579
580         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
581         public void visitNEW(NEW o){
582             indexValid(o, o.getIndex());
583             Constant c = cpg.getConstant(o.getIndex());
584             if (! (c instanceof ConstantClass)){
585                 constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
586             }
587             else{
588                 ConstantUtf8 cutf8 = (ConstantUtf8) (cpg.getConstant( ((ConstantClass) c).getNameIndex() ));
589                 Type t = Type.getType("L"+cutf8.getBytes()+";");
590                 if (t instanceof ArrayType){
591                     constraintViolated(o, "NEW must not be used to create an array.");
592                 }
593             }
594             
595         }
596
597         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
598         public void visitMULTIANEWARRAY(MULTIANEWARRAY o){
599             indexValid(o, o.getIndex());
600             Constant c = cpg.getConstant(o.getIndex());
601             if (! (c instanceof ConstantClass)){
602                 constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
603             }
604             int dimensions2create = o.getDimensions();
605             if (dimensions2create < 1){
606                 constraintViolated(o, "Number of dimensions to create must be greater than zero.");
607             }
608             Type t = o.getType(cpg);
609             if (t instanceof ArrayType){
610                 int dimensions = ((ArrayType) t).getDimensions();
611                 if (dimensions < dimensions2create){
612                     constraintViolated(o, "Not allowed to create array with more dimensions ('+dimensions2create+') than the one referenced by the CONSTANT_Class '"+t+"'.");
613                 }
614             }
615             else{
616                 constraintViolated(o, "Expecting a CONSTANT_Class referencing an array type. [Constraint not found in The Java Virtual Machine Specification, Second Edition, 4.8.1]");
617             }
618         }
619
620         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
621         public void visitANEWARRAY(ANEWARRAY o){
622             indexValid(o, o.getIndex());
623             Constant c = cpg.getConstant(o.getIndex());
624             if (! (c instanceof ConstantClass)){
625                 constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
626             }
627             Type t = o.getType(cpg);
628             if (t instanceof ArrayType){
629                 int dimensions = ((ArrayType) t).getDimensions();
630                 if (dimensions >= 255){
631                     constraintViolated(o, "Not allowed to create an array with more than 255 dimensions.");
632                 }
633             }
634         }
635
636         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
637         public void visitNEWARRAY(NEWARRAY o){
638             byte t = o.getTypecode();
639             if (! ( (t == Constants.T_BOOLEAN) ||
640                             (t == Constants.T_CHAR) ||
641                             (t == Constants.T_FLOAT) ||
642                             (t == Constants.T_DOUBLE) ||
643                             (t == Constants.T_BYTE) ||
644                             (t == Constants.T_SHORT) ||
645                             (t == Constants.T_INT) ||
646                             (t == Constants.T_LONG) ) ){
647                 constraintViolated(o, "Illegal type code '+t+' for 'atype' operand.");
648             }
649         }
650
651         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
652         public void visitILOAD(ILOAD o){
653             int idx = o.getIndex();
654             if (idx < 0){
655                 constraintViolated(o, "Index '"+idx+"' must be non-negative.");
656             }
657             else{
658                 int maxminus1 = max_locals()-1;
659                 if (idx > maxminus1){
660                     constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
661                 }
662             }
663         }
664
665         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
666         public void visitFLOAD(FLOAD o){
667             int idx = o.getIndex();
668             if (idx < 0){
669                 constraintViolated(o, "Index '"+idx+"' must be non-negative.");
670             }
671             else{
672                 int maxminus1 = max_locals()-1;
673                 if (idx > maxminus1){
674                     constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
675                 }
676             }
677         }
678
679         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
680         public void visitALOAD(ALOAD 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 visitISTORE(ISTORE 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 visitFSTORE(FSTORE 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 visitASTORE(ASTORE 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 visitIINC(IINC 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 visitRET(RET 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 visitLLOAD(LLOAD o){
765             int idx = o.getIndex();
766             if (idx < 0){
767                 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.]");
768             }
769             else{
770                 int maxminus2 = max_locals()-2;
771                 if (idx > maxminus2){
772                     constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'.");
773                 }
774             }
775         }
776         
777         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
778         public void visitDLOAD(DLOAD o){
779             int idx = o.getIndex();
780             if (idx < 0){
781                 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.]");
782             }
783             else{
784                 int maxminus2 = max_locals()-2;
785                 if (idx > maxminus2){
786                     constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'.");
787                 }
788             }
789         }
790         
791         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
792         public void visitLSTORE(LSTORE 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 visitDSTORE(DSTORE 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 visitLOOKUPSWITCH(LOOKUPSWITCH o){
821             int[] matchs = o.getMatchs();
822             int max = Integer.MIN_VALUE;
823             for (int i=0; i<matchs.length; i++){
824                 if (matchs[i] == max && i != 0){
825                     constraintViolated(o, "Match '"+matchs[i]+"' occurs more than once.");
826                 }
827                 if (matchs[i] < max){
828                     constraintViolated(o, "Lookup table must be sorted but isn't.");
829                 }
830                 else{
831                     max = matchs[i];
832                 }
833             }
834         }
835
836         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
837         public void visitTABLESWITCH(TABLESWITCH o){
838             // "high" must be >= "low". We cannot check this, as BCEL hides
839
// it from us.
840
}
841
842         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
843         public void visitPUTSTATIC(PUTSTATIC o){
844             String JavaDoc field_name = o.getFieldName(cpg);
845             JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
846             Field[] fields = jc.getFields();
847             Field f = null;
848             for (int i=0; i<fields.length; i++){
849                 if (fields[i].getName().equals(field_name)){
850                     f = fields[i];
851                     break;
852                 }
853             }
854             if (f == null){
855                 throw new AssertionViolatedException("Field not found?!?");
856             }
857
858             if (f.isFinal()){
859                 if (!(myOwner.getClassName().equals(o.getClassType(cpg).getClassName()))){
860                     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()+"'.");
861                 }
862             }
863
864             if (! (f.isStatic())){
865                 constraintViolated(o, "Referenced field '"+f+"' is not static which it should be.");
866             }
867
868             String JavaDoc meth_name = Repository.lookupClass(myOwner.getClassName()).getMethods()[method_no].getName();
869
870             // If it's an interface, it can be set only in <clinit>.
871
if ((!(jc.isClass())) && (!(meth_name.equals(Constants.STATIC_INITIALIZER_NAME)))){
872                 constraintViolated(o, "Interface field '"+f+"' must be set in a '"+Constants.STATIC_INITIALIZER_NAME+"' method.");
873             }
874         }
875
876         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
877         public void visitGETSTATIC(GETSTATIC o){
878             String JavaDoc field_name = o.getFieldName(cpg);
879             JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
880             Field[] fields = jc.getFields();
881             Field f = null;
882             for (int i=0; i<fields.length; i++){
883                 if (fields[i].getName().equals(field_name)){
884                     f = fields[i];
885                     break;
886                 }
887             }
888             if (f == null){
889                 throw new AssertionViolatedException("Field not found?!?");
890             }
891
892             if (! (f.isStatic())){
893                 constraintViolated(o, "Referenced field '"+f+"' is not static which it should be.");
894             }
895         }
896
897         /* Checks if the constraints of operands of the said instruction(s) are satisfied. */
898         //public void visitPUTFIELD(PUTFIELD o){
899
// for performance reasons done in Pass 3b
900
//}
901

902         /* Checks if the constraints of operands of the said instruction(s) are satisfied. */
903         //public void visitGETFIELD(GETFIELD o){
904
// for performance reasons done in Pass 3b
905
//}
906

907         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
908         public void visitINVOKEINTERFACE(INVOKEINTERFACE o){
909             // INVOKEINTERFACE is a LoadClass; the Class where the referenced method is declared in,
910
// is therefore resolved/verified.
911
// INVOKEINTERFACE is an InvokeInstruction, the argument and return types are resolved/verified,
912
// too. So are the allowed method names.
913
String JavaDoc classname = o.getClassName(cpg);
914             JavaClass jc = Repository.lookupClass(classname);
915             Method[] ms = jc.getMethods();
916             Method m = null;
917             for (int i=0; i<ms.length; i++){
918                 if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
919                      (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
920                      (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
921                     m = ms[i];
922                     break;
923                 }
924             }
925             if (m == null){
926                 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.");
927             }
928             if (jc.isClass()){
929                 constraintViolated(o, "Referenced class '"+jc.getClassName()+"' is a class, but not an interface as expected.");
930             }
931         }
932
933         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
934         public void visitINVOKESPECIAL(INVOKESPECIAL o){
935             // INVOKESPECIAL is a LoadClass; the Class where the referenced method is declared in,
936
// is therefore resolved/verified.
937
// INVOKESPECIAL is an InvokeInstruction, the argument and return types are resolved/verified,
938
// too. So are the allowed method names.
939
String JavaDoc classname = o.getClassName(cpg);
940             JavaClass jc = Repository.lookupClass(classname);
941             Method[] ms = jc.getMethods();
942             Method m = null;
943             for (int i=0; i<ms.length; i++){
944                 if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
945                      (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
946                      (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
947                     m = ms[i];
948                     break;
949                 }
950             }
951             if (m == null){
952                 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.");
953             }
954             
955             JavaClass current = Repository.lookupClass(myOwner.getClassName());
956             if (current.isSuper()){
957             
958                 if ((Repository.instanceOf( current, jc )) && (!current.equals(jc))){
959                     
960                     if (! (o.getMethodName(cpg).equals(Constants.CONSTRUCTOR_NAME) )){
961                         // Special lookup procedure for ACC_SUPER classes.
962

963                         int supidx = -1;
964                         
965                         Method meth = null;
966                         while (supidx != 0){
967                             supidx = current.getSuperclassNameIndex();
968                             current = Repository.lookupClass(current.getSuperclassName());
969                             
970                             Method[] meths = current.getMethods();
971                             for (int i=0; i<meths.length; i++){
972                                 if ( (meths[i].getName().equals(o.getMethodName(cpg))) &&
973                                     (Type.getReturnType(meths[i].getSignature()).equals(o.getReturnType(cpg))) &&
974                                     (objarrayequals(Type.getArgumentTypes(meths[i].getSignature()), o.getArgumentTypes(cpg))) ){
975                                     meth = meths[i];
976                                     break;
977                                 }
978                             }
979                             if (meth != null) break;
980                         }
981                         if (meth == null){
982                             constraintViolated(o, "ACC_SUPER special lookup procedure not successful: method '"+o.getMethodName(cpg)+"' with proper signature not declared in superclass hierarchy.");
983                         }
984                     }
985                 }
986             }
987             
988             
989         }
990         
991         /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
992         public void visitINVOKESTATIC(INVOKESTATIC o){
993             // INVOKESTATIC is a LoadClass; the Class where the referenced method is declared in,
994
// is therefore resolved/verified.
995
// INVOKESTATIC is an InvokeInstruction, the argument and return types are resolved/verified,
996
// too. So are the allowed method names.
997
String JavaDoc classname = o.getClassName(cpg);
998             JavaClass jc = Repository.lookupClass(classname);
999             Method[] ms = jc.getMethods();
1000            Method m = null;
1001            for (int i=0; i<ms.length; i++){
1002                if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
1003                     (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
1004                     (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
1005                    m = ms[i];
1006                    break;
1007                }
1008            }
1009            if (m == null){
1010                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.");
1011            }
1012            
1013            if (! (m.isStatic())){ // implies it's not abstract, verified in pass 2.
1014
constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' has ACC_STATIC unset.");
1015            }
1016        
1017        }
1018
1019
1020        /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
1021        public void visitINVOKEVIRTUAL(INVOKEVIRTUAL o){
1022            // INVOKEVIRTUAL is a LoadClass; the Class where the referenced method is declared in,
1023
// is therefore resolved/verified.
1024
// INVOKEVIRTUAL is an InvokeInstruction, the argument and return types are resolved/verified,
1025
// too. So are the allowed method names.
1026
String JavaDoc classname = o.getClassName(cpg);
1027            JavaClass jc = Repository.lookupClass(classname);
1028            Method[] ms = jc.getMethods();
1029            Method m = null;
1030            for (int i=0; i<ms.length; i++){
1031                if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
1032                     (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
1033                     (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
1034                    m = ms[i];
1035                    break;
1036                }
1037            }
1038            if (m == null){
1039                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.");
1040            }
1041            if (! (jc.isClass())){
1042                constraintViolated(o, "Referenced class '"+jc.getClassName()+"' is an interface, but not a class as expected.");
1043            }
1044                    
1045        }
1046
1047        
1048        // WIDE stuff is BCEL-internal and cannot be checked here.
1049

1050        /**
1051         * A utility method like equals(Object) for arrays.
1052         * The equality of the elements is based on their equals(Object)
1053         * method instead of their object identity.
1054         */

1055        private boolean objarrayequals(Object JavaDoc[] o, Object JavaDoc[] p){
1056            if (o.length != p.length){
1057                return false;
1058            }
1059            
1060            for (int i=0; i<o.length; i++){
1061                if (! (o[i].equals(p[i])) ){
1062                    return false;
1063                }
1064            }
1065            
1066            return true;
1067        }
1068
1069    }
1070}
1071
Popular Tags