⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pass3averifier.java

📁 Java Bytecode Editor 是一个 JAVA 的字节码反汇编和修改器。它可以很方便的修改已经编译成 Class 文件的 JAVA 文件。
💻 JAVA
📖 第 1 页 / 共 4 页
字号:

		if (! (code.getCode().length < 65536)){// contradicts vmspec2 page 152 ("Limitations"), but is on page 134.
			throw new StaticCodeInstructionConstraintException("Code array in code attribute '"+code+"' too big: must be smaller than 65536 bytes.");
		}

		// First opcode at offset 0: okay, that's clear. Nothing to do.
		
		// Only instances of the instructions documented in Section 6.4 may appear in
		// the code array.
		
		// For BCEL's sake, we cannot handle WIDE stuff, but hopefully BCEL does its job right :)
		
		// The last byte of the last instruction in the code array must be the byte at index
		// code_length-1 : See the do_verify() comments. We actually don't iterate through the
		// byte array, but use an InstructionList so we cannot check for this. But BCEL does
		// things right, so it's implicitly okay.
		
		// TODO: Check how BCEL handles (and will handle) instructions like IMPDEP1, IMPDEP2,
		//       BREAKPOINT... that BCEL knows about but which are illegal anyway.
		//       We currently go the safe way here.
		InstructionHandle ih = instructionList.getStart();
		while (ih != null){
			Instruction i = ih.getInstruction();
			if (i instanceof IMPDEP1){
				throw new StaticCodeInstructionConstraintException("IMPDEP1 must not be in the code, it is an illegal instruction for _internal_ JVM use!");
			}
			if (i instanceof IMPDEP2){
				throw new StaticCodeInstructionConstraintException("IMPDEP2 must not be in the code, it is an illegal instruction for _internal_ JVM use!");
			}
			if (i instanceof BREAKPOINT){
				throw new StaticCodeInstructionConstraintException("BREAKPOINT must not be in the code, it is an illegal instruction for _internal_ JVM use!");
			}
			ih = ih.getNext();
		}
		
		// The original verifier seems to do this check here, too.
		// An unreachable last instruction may also not fall through the
		// end of the code, which is stupid -- but with the original
		// verifier's subroutine semantics one cannot predict reachability.
		Instruction last = instructionList.getEnd().getInstruction();
		if (! ((last instanceof ReturnInstruction)	||
					(last instanceof RET)    							||
					(last instanceof GotoInstruction)			||
					(last instanceof ATHROW) )) // JSR / JSR_W would possibly RETurn and then fall off the code!
			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.");
	}

	/**
	 * These are the checks for the satisfaction of constraints which are described in the
	 * Java Virtual Machine Specification, Second Edition as Static Constraints on
	 * the operands of instructions of Java Virtual Machine Code (chapter 4.8.1).
	 * BCEL parses the code array to create an InstructionList and therefore has to check
	 * some of these constraints. Additional checks are also implemented here.
	 *
	 * @throws StaticCodeConstraintException if the verification fails.
	 */
	private void pass3StaticInstructionOperandsChecks(){
		// When building up the InstructionList, BCEL has already done all those checks
		// mentioned in The Java Virtual Machine Specification, Second Edition, as
		// "static constraints on the operands of instructions in the code array".
		// TODO: see the do_verify() comments. Maybe we should really work on the
		//       byte array first to give more comprehensive messages.
		// TODO: Review Exception API, possibly build in some "offending instruction" thing
		//       when we're ready to insulate the offending instruction by doing the
		//       above thing.

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

		ConstantPoolGen cpg = new ConstantPoolGen(Repository.lookupClass(myOwner.getClassName()).getConstantPool());
		InstOperandConstraintVisitor v = new InstOperandConstraintVisitor(cpg);
	
		// Checks for the things BCEL does _not_ handle itself.
		InstructionHandle ih = instructionList.getStart();
		while (ih != null){
			Instruction i = ih.getInstruction();
			
			// An "own" constraint, due to JustIce's new definition of what "subroutine" means.
			if (i instanceof JsrInstruction){
				InstructionHandle target = ((JsrInstruction) i).getTarget();
				if (target == instructionList.getStart()){
					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.");
				}
				if (!(target.getInstruction() instanceof ASTORE)){
					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+"'.");
				}
			}
			
			// vmspec2, page 134-137
			ih.accept(v);
			
			ih = ih.getNext();
		}

	}
	
	/** A small utility method returning if a given int i is in the given int[] ints. */
	private static boolean contains(int[] ints, int i){
		for (int j=0; j<ints.length; j++){
			if (ints[j]==i) return true;
		}
		return false;
	}

	/** Returns the method number as supplied when instantiating. */
	public int getMethodNo(){
		return method_no;
	}

	/**
	 * This visitor class does the actual checking for the instruction
	 * operand's constraints.
	 */
	private class InstOperandConstraintVisitor extends org.apache.bcel.generic.EmptyVisitor{
		/** The ConstantPoolGen instance this Visitor operates on. */
		private ConstantPoolGen cpg;

		/** The only Constructor. */
		InstOperandConstraintVisitor(ConstantPoolGen cpg){
			this.cpg = cpg;
		}

		/**
		 * Utility method to return the max_locals value of the method verified
		 * by the surrounding Pass3aVerifier instance.
		 */
		private int max_locals(){
			return Repository.lookupClass(myOwner.getClassName()).getMethods()[method_no].getCode().getMaxLocals();
		}

		/**
		 * A utility method to always raise an exeption.
		 */
		private void constraintViolated(Instruction i, String message) {
			throw new StaticCodeInstructionOperandConstraintException("Instruction "+i+" constraint violated: "+message);
		}

		/**
		 * A utility method to raise an exception if the index is not
		 * a valid constant pool index.
		 */
		private void indexValid(Instruction i, int idx){
			if (idx < 0 || idx >= cpg.getSize()){
				constraintViolated(i, "Illegal constant pool index '"+idx+"'.");
			}
		}

		///////////////////////////////////////////////////////////
		// The Java Virtual Machine Specification, pages 134-137 //
		///////////////////////////////////////////////////////////
		/**
		 * Assures the generic preconditions of a LoadClass instance.
		 * The referenced class is loaded and pass2-verified.
		 */
		public void visitLoadClass(LoadClass o){
			ObjectType t = o.getLoadClassType(cpg);
			if (t != null){// null means "no class is loaded"
				Verifier v = VerifierFactory.getVerifier(t.getClassName());
				VerificationResult vr = v.doPass1();
				if (vr.getStatus() != VerificationResult.VERIFIED_OK){
					constraintViolated((Instruction) o, "Class '"+o.getLoadClassType(cpg).getClassName()+"' is referenced, but cannot be loaded: '"+vr+"'.");
				}
			}
		}
		
		// The target of each jump and branch instruction [...] must be the opcode [...]
		// BCEL _DOES_ handle this.

		// tableswitch: BCEL will do it, supposedly.
		
		// lookupswitch: BCEL will do it, supposedly.
		
		/** Checks if the constraints of operands of the said instruction(s) are satisfied. */
		// LDC and LDC_W (LDC_W is a subclass of LDC in BCEL's model)
		public void visitLDC(LDC o){
			indexValid(o, o.getIndex());
			Constant c = cpg.getConstant(o.getIndex());
			if (! ( (c instanceof ConstantInteger)	||
							(c instanceof ConstantFloat) 		||
							(c instanceof ConstantString) ) ){
				constraintViolated(o, "Operand of LDC or LDC_W must be one of CONSTANT_Integer, CONSTANT_Float or CONSTANT_String, but is '"+c+"'.");
			}
		}

		/** Checks if the constraints of operands of the said instruction(s) are satisfied. */
		// LDC2_W
		public void visitLDC2_W(LDC2_W o){
			indexValid(o, o.getIndex());
			Constant c = cpg.getConstant(o.getIndex());
			if (! ( (c instanceof ConstantLong)	||
							(c instanceof ConstantDouble) ) ){
				constraintViolated(o, "Operand of LDC2_W must be CONSTANT_Long or CONSTANT_Double, but is '"+c+"'.");
			}
			try{
				indexValid(o, o.getIndex()+1);
			}
			catch(StaticCodeInstructionOperandConstraintException e){
				throw new AssertionViolatedException("OOPS: Does not BCEL handle that? LDC2_W operand has a problem.");
			}
		}

		/** Checks if the constraints of operands of the said instruction(s) are satisfied. */
 		//getfield, putfield, getstatic, putstatic
 		public void visitFieldInstruction(FieldInstruction o){
			indexValid(o, o.getIndex());
			Constant c = cpg.getConstant(o.getIndex());
			if (! (c instanceof ConstantFieldref)){
				constraintViolated(o, "Indexing a constant that's not a CONSTANT_Fieldref but a '"+c+"'.");
			}
			
			String field_name = o.getFieldName(cpg);
 
			JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
			Field[] fields = jc.getFields();
			Field f = null;
			for (int i=0; i<fields.length; i++){
				if (fields[i].getName().equals(field_name)){
					f = fields[i];
					break;
				}
			}
			if (f == null){
				/* TODO: also look up if the field is inherited! */
				constraintViolated(o, "Referenced field '"+field_name+"' does not exist in class '"+jc.getClassName()+"'.");
			}
			else{
				/* TODO: Check if assignment compatibility is sufficient.
				   What does Sun do? */
				Type f_type = Type.getType(f.getSignature());
				Type o_type = o.getType(cpg);
				
				/* TODO: Is there a way to make BCEL tell us if a field
				has a void method's signature, i.e. "()I" instead of "I"? */
				
				if (! f_type.equals(o_type)){
					constraintViolated(o, "Referenced field '"+field_name+"' has type '"+f_type+"' instead of '"+o_type+"' as expected.");
				}
				/* TODO: Check for access modifiers here. */
			}
		}	

		/** Checks if the constraints of operands of the said instruction(s) are satisfied. */
		public void visitInvokeInstruction(InvokeInstruction o){
			indexValid(o, o.getIndex());
			if (	(o instanceof INVOKEVIRTUAL)	||
						(o instanceof INVOKESPECIAL)	||
						(o instanceof INVOKESTATIC)	){
				Constant c = cpg.getConstant(o.getIndex());
				if (! (c instanceof ConstantMethodref)){
					constraintViolated(o, "Indexing a constant that's not a CONSTANT_Methodref but a '"+c+"'.");
				}
				else{
					// Constants are okay due to pass2.
					ConstantNameAndType cnat = (ConstantNameAndType) (cpg.getConstant(((ConstantMethodref) c).getNameAndTypeIndex()));
					ConstantUtf8 cutf8 = (ConstantUtf8) (cpg.getConstant(cnat.getNameIndex()));
					if (cutf8.getBytes().equals(Constants.CONSTRUCTOR_NAME) && (!(o instanceof INVOKESPECIAL)) ){
						constraintViolated(o, "Only INVOKESPECIAL is allowed to invoke instance initialization methods.");
					}
					if ( (! (cutf8.getBytes().equals(Constants.CONSTRUCTOR_NAME)) ) && (cutf8.getBytes().startsWith("<")) ){
						constraintViolated(o, "No method with a name beginning with '<' other than the instance initialization methods may be called by the method invocation instructions.");
					}
				}
			}
			else{ //if (o instanceof INVOKEINTERFACE){
				Constant c = cpg.getConstant(o.getIndex());
				if (! (c instanceof ConstantInterfaceMethodref)){
					constraintViolated(o, "Indexing a constant that's not a CONSTANT_InterfaceMethodref but a '"+c+"'.");
				}
				// TODO: From time to time check if BCEL allows to detect if the
				// 'count' operand is consistent with the information in the
				// CONSTANT_InterfaceMethodref and if the last operand is zero.
				// By now, BCEL hides those two operands because they're superfluous.
				
				// Invoked method must not be <init> or <clinit>
				ConstantNameAndType cnat = (ConstantNameAndType) (cpg.getConstant(((ConstantInterfaceMethodref)c).getNameAndTypeIndex()));
				String name = ((ConstantUtf8) (cpg.getConstant(cnat.getNameIndex()))).getBytes();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -