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

📄 pass3averifier.java

📁 该开源工具主要用于class文件的操作
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
package org.apache.bcel.verifier.statics;/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2001 The Apache Software Foundation.  All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in *    the documentation and/or other materials provided with the *    distribution. * * 3. The end-user documentation included with the redistribution, *    if any, must include the following acknowledgment: *       "This product includes software developed by the *        Apache Software Foundation (http://www.apache.org/)." *    Alternately, this acknowledgment may appear in the software itself, *    if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and *    "Apache BCEL" must not be used to endorse or promote products *    derived from this software without prior written permission. For *    written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", *    "Apache BCEL", nor may "Apache" appear in their name, without *    prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation.  For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */import org.apache.bcel.*;import org.apache.bcel.generic.*;import org.apache.bcel.classfile.*;import org.apache.bcel.verifier.*;import org.apache.bcel.verifier.exc.*;import java.util.ArrayList;import java.util.HashMap;/** * This PassVerifier verifies a class file according to * pass 3, static part as described in The Java Virtual * Machine Specification, 2nd edition. * More detailed information is to be found at the do_verify() * method's documentation.  * * @version $Id: Pass3aVerifier.java,v 1.1.1.1 2001/10/29 20:00:37 jvanzyl Exp $ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A> * @see #do_verify() */public final class Pass3aVerifier extends PassVerifier{	/** The Verifier that created this. */	private Verifier myOwner;	/** 	 * The method number to verify.	 * This is the index in the array returned	 * by JavaClass.getMethods().	 */	private int method_no;	/** 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. */		InstructionList instructionList;	/** 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. */		Code code;	/** Should only be instantiated by a Verifier. */	public Pass3aVerifier(Verifier owner, int method_no){		myOwner = owner;		this.method_no = method_no;	}	/**	 * Pass 3a is the verification of static constraints of	 * JVM code (such as legal targets of branch instructions).	 * This is the part of pass 3 where you do not need data	 * flow analysis.	 * JustIce also delays the checks for a correct exception	 * table of a Code attribute and correct line number entries	 * in a LineNumberTable attribute of a Code attribute (which	 * conceptually belong to pass 2) to this pass. Also, most	 * of the check for valid local variable entries in a	 * LocalVariableTable attribute of a Code attribute is	 * delayed until this pass.	 * All these checks need access to the code array of the	 * Code attribute.	 *	 * @throws InvalidMethodException if the method to verify does not exist.	 */	public VerificationResult do_verify(){		if (myOwner.doPass2().equals(VerificationResult.VR_OK)){			// Okay, class file was loaded correctly by Pass 1			// and satisfies static constraints of Pass 2.			JavaClass jc = Repository.lookupClass(myOwner.getClassName());			Method[] methods = jc.getMethods();			if (method_no >= methods.length){				throw new InvalidMethodException("METHOD DOES NOT EXIST!");			}			Method method = methods[method_no];			code = method.getCode();						// No Code? Nothing to verify!			if ( method.isAbstract() || method.isNative() ){ // IF mg HAS NO CODE (static constraint of Pass 2)				return VerificationResult.VR_OK;			}			// TODO:			// We want a very sophisticated code examination here with good explanations			// on where to look for an illegal instruction or such.			// Only after that we should try to build an InstructionList and throw an			// AssertionViolatedException if after our examination InstructionList building			// still fails.			// That examination should be implemented in a byte-oriented way, i.e. look for			// an instruction, make sure its validity, count its length, find the next			// instruction and so on.			try{				instructionList = new InstructionList(method.getCode().getCode());			}			catch(RuntimeException re){				return new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Bad bytecode in the code array of the Code attribute of method '"+method+"'.");			}						instructionList.setPositions(true);			// Start verification.			VerificationResult vr = VerificationResult.VR_OK; //default			try{				delayedPass2Checks();			}			catch(ClassConstraintException cce){				vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, cce.getMessage());				return vr;			}			try{				pass3StaticInstructionChecks();				pass3StaticInstructionOperandsChecks();			}			catch(StaticCodeConstraintException scce){				vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, scce.getMessage());			}			return vr;		}		else{ //did not pass Pass 2.			return VerificationResult.VR_NOTYET;		}	}	/**	 * These are the checks that could be done in pass 2 but are delayed to pass 3	 * for performance reasons. Also, these checks need access to the code array	 * of the Code attribute of a Method so it's okay to perform them here.	 * Also see the description of the do_verify() method.	 *	 * @throws ClassConstraintException if the verification fails.	 * @see #do_verify()	 */	private void delayedPass2Checks(){		int[] instructionPositions = instructionList.getInstructionPositions();		int codeLength = code.getCode().length;		/////////////////////		// LineNumberTable //		/////////////////////		LineNumberTable lnt = code.getLineNumberTable();		if (lnt != null){			LineNumber[] lineNumbers = lnt.getLineNumberTable();			IntList offsets = new IntList();			lineNumber_loop: for (int i=0; i < lineNumbers.length; i++){ // may appear in any order.				for (int j=0; j < instructionPositions.length; j++){					// TODO: Make this a binary search! The instructionPositions array is naturally ordered!					int offset = lineNumbers[i].getStartPC();					if (instructionPositions[j] == offset){						if (offsets.contains(offset)){							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].");						}						else{							offsets.add(offset);						}						continue lineNumber_loop;					}				}				throw new ClassConstraintException("Code attribute '"+code+"' has a LineNumberTable attribute '"+code.getLineNumberTable()+"' referring to a code offset ('"+lineNumbers[i].getStartPC()+"') that does not exist.");			}		}		///////////////////////////		// LocalVariableTable(s) //		///////////////////////////		/* We cannot use code.getLocalVariableTable() because there could be more		   than only one. This is a bug in BCEL. */		Attribute[] atts = code.getAttributes();		for (int a=0; a<atts.length; a++){			if (atts[a] instanceof LocalVariableTable){				LocalVariableTable lvt = (LocalVariableTable) atts[a];				if (lvt != null){					LocalVariable[] localVariables = lvt.getLocalVariableTable();					for (int i=0; i<localVariables.length; i++){						int startpc = localVariables[i].getStartPC();						int length  = localVariables[i].getLength();										if (!contains(instructionPositions, startpc)){							throw new ClassConstraintException("Code attribute '"+code+"' has a LocalVariableTable attribute '"+code.getLocalVariableTable()+"' referring to a code offset ('"+startpc+"') that does not exist.");						}						if ( (!contains(instructionPositions, startpc+length)) && (startpc+length != codeLength) ){							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.");						}					}				}			}		}				////////////////////		// ExceptionTable //		////////////////////		// In BCEL's "classfile" API, the startPC/endPC-notation is		// inclusive/exclusive as in the Java Virtual Machine Specification.		// WARNING: This is not true for BCEL's "generic" API.		CodeException[] exceptionTable = code.getExceptionTable();		for (int i=0; i<exceptionTable.length; i++){			int startpc = exceptionTable[i].getStartPC();			int endpc = exceptionTable[i].getEndPC();			int handlerpc = exceptionTable[i].getHandlerPC();			if (startpc >= endpc){				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+"').");			}			if (!contains(instructionPositions, startpc)){				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+"').");			}			if ( (!contains(instructionPositions, endpc)) && (endpc != codeLength)){				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+"')].");			}			if (!contains(instructionPositions, handlerpc)){				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+"').");			}		}	}	/**	 * These are the checks if constraints are satisfied which are described in the	 * Java Virtual Machine Specification, Second Edition as Static Constraints on	 * the instructions of Java Virtual Machine Code (chapter 4.8.1).	 *	 * @throws StaticCodeConstraintException if the verification fails.	 */	private void pass3StaticInstructionChecks(){				// Code array must not be empty:		// Enforced in pass 2 (also stated in the static constraints of the Code		// array in vmspec2), together with pass 1 (reading code_length bytes and		// interpreting them as code[]). So this must not be checked again here.		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 implicitely 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()){

⌨️ 快捷键说明

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