1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
155
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
165 if ( method.isAbstract() || method.isNative() ){
166 return VerificationResult.VR_OK;
167 }
168
169
170
171
172
173
174
175
176
177
178 try{
179 instructionList = new InstructionList(method.getCode().getCode());
180 }
181 catch(RuntimeException 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
188 VerificationResult vr = VerificationResult.VR_OK;
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 cce){
204 vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Class Cast Exception: " + cce.getMessage());
205 }
206 return vr;
207 }
208 else{
209 return VerificationResult.VR_NOTYET;
210 }
211 } catch (ClassNotFoundException e) {
212
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
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++){
239 for (int j=0; j < instructionPositions.length; j++){
240
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
258
259
260
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
284
285
286
287
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
318
319
320
321
322 if (! (code.getCode().length < 65536)){
323 throw new StaticCodeInstructionConstraintException("Code array in code attribute '"+code+"' too big: must be smaller than 65536 bytes.");
324 }
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
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
357
358
359
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
381
382
383
384
385
386
387
388
389
390
391 ConstantPoolGen cpg = new ConstantPoolGen(Repository.lookupClass(myOwner.getClassName()).getConstantPool());
392 InstOperandConstraintVisitor v = new InstOperandConstraintVisitor(cpg);
393
394
395 InstructionHandle ih = instructionList.getStart();
396 while (ih != null){
397 Instruction i = ih.getInstruction();
398
399
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
411 ih.accept(v);
412
413 ih = ih.getNext();
414 }
415
416 } catch (ClassNotFoundException e) {
417
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 e) {
458
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 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
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){
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
499
500
501
502
503
504
505 /*** Checks if the constraints of operands of the said instruction(s) are satisfied. */
506
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
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
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 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
559
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
592
593 Type f_type = Type.getType(f.getSignature());
594 Type o_type = o.getType(cpg);
595
596
597
598
599
600
601
602
603 }
604 } catch (ClassNotFoundException e) {
605
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
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{
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
638
639
640
641
642
643 ConstantNameAndType cnat = (ConstantNameAndType) (cpg.getConstant(((ConstantInterfaceMethodref)c).getNameAndTypeIndex()));
644 String 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
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
961
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 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 meth_name = Repository.lookupClass(myOwner.getClassName()).getMethods()[method_no].getName();
992
993
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 e) {
998
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 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 e) {
1024
1025 throw new AssertionViolatedException("Missing class: " + e.toString());
1026 }
1027 }
1028
1029
1030
1031
1032
1033
1034
1035
1036
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
1043
1044
1045
1046 String 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 e) {
1065
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
1074
1075
1076
1077 String 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
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 e) {
1129
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
1139
1140
1141
1142 String 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())){
1157 constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' has ACC_STATIC unset.");
1158 }
1159
1160 } catch (ClassNotFoundException e) {
1161
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
1171
1172
1173
1174 String 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 e) {
1194
1195 throw new AssertionViolatedException("Missing class: " + e.toString());
1196 }
1197 }
1198
1199
1200
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[] o, Object[] 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 }