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

📄 typeframemodelingvisitor.java

📁 A static analysis tool to find bugs in Java programs
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/* * Bytecode Analysis Framework * Copyright (C) 2003-2005 University of Maryland *  * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. *  * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. *  * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */package edu.umd.cs.findbugs.ba.type;import org.apache.bcel.Constants;import org.apache.bcel.classfile.Attribute;import org.apache.bcel.classfile.Field;import org.apache.bcel.classfile.Signature;import org.apache.bcel.generic.*;import edu.umd.cs.findbugs.ba.AbstractFrameModelingVisitor;import edu.umd.cs.findbugs.ba.AnalysisContext;import edu.umd.cs.findbugs.ba.DataflowAnalysisException;import edu.umd.cs.findbugs.ba.Debug;import edu.umd.cs.findbugs.ba.Hierarchy;import edu.umd.cs.findbugs.ba.InvalidBytecodeException;import edu.umd.cs.findbugs.ba.Location;import edu.umd.cs.findbugs.ba.ObjectTypeFactory;import edu.umd.cs.findbugs.ba.XField;import edu.umd.cs.findbugs.ba.generic.GenericUtilities;import edu.umd.cs.findbugs.ba.vna.ValueNumber;import edu.umd.cs.findbugs.ba.vna.ValueNumberDataflow;import edu.umd.cs.findbugs.ba.vna.ValueNumberFrame;/** * Visitor to model the effects of bytecode instructions on the * types of the values (local and operand stack) in Java stack frames. * This visitor does not verify that the types are sensible * for the bytecodes executed.  In other words, this isn't a bytecode * verifier, although it wouldn't be too hard to turn it into * something vaguely verifier-like. * * @author David Hovemeyer * @see TypeFrame * @see TypeAnalysis */public class TypeFrameModelingVisitor extends AbstractFrameModelingVisitor<Type, TypeFrame>		implements Constants, Debug {	static private final  ObjectType COLLECTION_TYPE = ObjectTypeFactory.getInstance("java.util.Collection");	private ValueNumberDataflow valueNumberDataflow;	// Fields for precise modeling of instanceof instructions.	private short lastOpcode;	private boolean instanceOfFollowedByBranch;	private Type instanceOfType;	private ValueNumber instanceOfValueNumber;	private FieldStoreTypeDatabase database;	/**	 * Constructor.	 *	 * @param cpg the ConstantPoolGen of the method whose instructions we are examining	 */	public TypeFrameModelingVisitor(ConstantPoolGen cpg) {		super(cpg);	}	/**	 * Set ValueNumberDataflow for the method being analyzed.	 * This is optional; if set, we will use the information to more	 * accurately model the effects of instanceof instructions.	 * 	 * @param valueNumberDataflow the ValueNumberDataflow	 */	public void setValueNumberDataflow(ValueNumberDataflow valueNumberDataflow) {		this.valueNumberDataflow = valueNumberDataflow;	}	/**	 * Get the last opcode analyzed by this visitor.	 * The TypeAnalysis may use this to get more precise types in	 * the resulting frame.	 * 	 * @return the last opcode analyzed by this visitor	 */	public short getLastOpcode() {		return lastOpcode;	}	/**	 * Return whether an instanceof instruction was followed by a branch.	 * The TypeAnalysis may use this to get more precise types in	 * the resulting frame.	 * 	 * @return true if an instanceof instruction was followed by a branch,	 *         false if not	 */	public boolean isInstanceOfFollowedByBranch() {		return instanceOfFollowedByBranch;	}	/**	 * Get the type of the most recent instanceof instruction modeled.	 * The TypeAnalysis may use this to get more precise types in	 * the resulting frame.	 * 	 * @return the Type checked by the most recent instanceof instruction	 */	public Type getInstanceOfType() {		return instanceOfType;	}	/**	 * Get the value number of the most recent instanceof instruction modeled.	 * The TypeAnalysis may use this to get more precise types in	 * the resulting frame.	 * 	 * @return the ValueNumber checked by the most recent instanceof instruction	 */	public ValueNumber getInstanceOfValueNumber() {		return instanceOfValueNumber;	}	/**	 * Set the field store type database.	 * We can use this to get more accurate types for values loaded	 * from fields.	 * 	 * @param database the FieldStoreTypeDatabase	 */	public void setFieldStoreTypeDatabase(FieldStoreTypeDatabase database) {		this.database = database;	}	@Override	public Type getDefaultValue() {		return TypeFrame.getBottomType();	}	@Override	public void analyzeInstruction(Instruction ins) throws DataflowAnalysisException {		instanceOfFollowedByBranch = false;		super.analyzeInstruction(ins);		lastOpcode = ins.getOpcode();	}	/**	 * This method must be called at the beginning of modeling	 * a basic block in order to clear information cached	 * for instanceof modeling.	 */	public void startBasicBlock() {		lastOpcode = -1;		instanceOfType = null;		instanceOfValueNumber = null;	}	/**	 * Consume stack.  This is a convenience method for instructions	 * where the types of popped operands can be ignored.	 */	protected void consumeStack(Instruction ins) {		ConstantPoolGen cpg = getCPG();		TypeFrame frame = getFrame();		int numWordsConsumed = ins.consumeStack(cpg);		if (numWordsConsumed == Constants.UNPREDICTABLE)			throw new InvalidBytecodeException("Unpredictable stack consumption for " + ins);		try {			while (numWordsConsumed-- > 0) {				frame.popValue();			}		} catch (DataflowAnalysisException e) {			throw new InvalidBytecodeException("Stack underflow for " + ins + ": " + e.getMessage());		}	}	/**	 * Work around some weirdness in BCEL (inherited from JVM Spec 1):	 * BCEL considers long and double types to consume two slots on the	 * stack.  This method ensures that we push two types for	 * each double or long value.	 */	protected void pushValue(Type type) {		TypeFrame frame = getFrame();		if (type.getType() == T_LONG) {			frame.pushValue(Type.LONG);			frame.pushValue(TypeFrame.getLongExtraType());		} else if (type.getType() == T_DOUBLE) {			frame.pushValue(Type.DOUBLE);			frame.pushValue(TypeFrame.getDoubleExtraType());		} else			frame.pushValue(type);	}	/**	 * Helper for pushing the return type of an invoke instruction.	 */	protected void pushReturnType(InvokeInstruction ins) {		ConstantPoolGen cpg = getCPG();		Type type = ins.getType(cpg);		if (type.getType() != T_VOID)			pushValue(type);	}	/**	 * This is overridden only to ensure that we don't rely on the	 * base class to handle instructions that produce stack operands.	 */	@Override	public void modelNormalInstruction(Instruction ins, int numWordsConsumed, int numWordsProduced) {		if (VERIFY_INTEGRITY) {			if (numWordsProduced > 0)				throw new InvalidBytecodeException("missing visitor method for " + ins);		}		super.modelNormalInstruction(ins, numWordsConsumed, numWordsProduced);	}	// ----------------------------------------------------------------------	// Instruction visitor methods	// ----------------------------------------------------------------------	// NOTES:	// - Instructions that only consume operands need not be overridden,	//   because the base class visit methods handle them correctly.	// - Instructions that simply move values around in the frame,	//   such as DUP, xLOAD, etc., do not need to be overridden because	//   the base class handles them.	// - Instructions that consume and produce should call	//   consumeStack(Instruction) and then explicitly push produced operands.	@Override	public void visitATHROW(ATHROW obj) {		// do nothing. The same value remains on the stack (but we jump to a new location)	}	@Override	public void visitACONST_NULL(ACONST_NULL obj) {		pushValue(TypeFrame.getNullType());	}	@Override	public void visitDCONST(DCONST obj) {		pushValue(Type.DOUBLE);	}	@Override	public void visitFCONST(FCONST obj) {		pushValue(Type.FLOAT);	}	@Override	public void visitICONST(ICONST obj) {		pushValue(Type.INT);	}	@Override	public void visitLCONST(LCONST obj) {		pushValue(Type.LONG);	}	@Override	public void visitLDC(LDC obj) {		pushValue(obj.getType(getCPG()));	}	@Override	public void visitLDC2_W(LDC2_W obj) {		pushValue(obj.getType(getCPG()));	}	@Override	public void visitBIPUSH(BIPUSH obj) {		pushValue(Type.INT);	}	@Override	public void visitSIPUSH(SIPUSH obj) {		pushValue(Type.INT);	}	@Override	public void visitGETSTATIC(GETSTATIC obj) {		modelFieldLoad(obj);	}	@Override		 public void visitGETFIELD(GETFIELD obj) {		modelFieldLoad(obj);	}	public void modelFieldLoad(FieldInstruction obj) {		consumeStack(obj);		Type loadType = obj.getType(getCPG());		Type originalLoadType = loadType;		try {			// Check the field store type database to see if we can			// get a more precise type for this load.			XField xfield = Hierarchy.findXField(obj, getCPG());			if (database != null && (loadType instanceof ReferenceType) && xfield != null) {				FieldStoreType property = database.getProperty(xfield);				if (property != null) {					loadType = property.getLoadType((ReferenceType) loadType);				}			}			// [Added: Support for Generics]			// XXX If the loadType was not changed by the FieldStoreTypeDatabase, then			// we can assume, that the signature for obj is still relevant. This should			// be updated by inserting generic information in the FieldStoreTypeDatabase			if (originalLoadType.equals(loadType) && xfield != null) {				// find the field and its signature				Field field = Hierarchy.findField(xfield.getClassName(), xfield.getName());				String signature = null;				for (Attribute a : field.getAttributes()) {					if (a instanceof Signature) {						signature = ((Signature) a).getSignature();						break;					}				}				// replace loadType with information from field signature (conservative)				if (signature != null && 					(loadType instanceof ObjectType || loadType instanceof ArrayType) &&					!(loadType instanceof ExceptionObjectType)					) {					loadType = GenericUtilities.getType( signature );				}			}		} catch (ClassNotFoundException e) {			AnalysisContext.reportMissingClass(e);		} catch (RuntimeException e) {} // degrade gracefully		pushValue(loadType);	}	@Override	public void visitINVOKESTATIC(INVOKESTATIC obj) {		consumeStack(obj);		pushReturnType(obj);	}	@Override	public void visitINVOKESPECIAL(INVOKESPECIAL obj) {		consumeStack(obj);		pushReturnType(obj);	}	@Override	public void visitINVOKEINTERFACE(INVOKEINTERFACE obj) {		if (handleToArray(obj)) return;		consumeStack(obj);		pushReturnType(obj);	}	@Override	public void visitINVOKEVIRTUAL(INVOKEVIRTUAL obj) {		TypeFrame frame = getFrame();		if (obj.getMethodName(cpg).equals("initCause") && obj.getSignature(cpg).equals("(Ljava/lang/Throwable;)Ljava/lang/Throwable;") && obj.getClassName(cpg).endsWith("Exception")) {			try {				frame.popValue();				return;			} catch (DataflowAnalysisException e) {			}		}		if (handleToArray(obj)) return;		consumeStack(obj);		pushReturnType(obj);	}	private boolean handleToArray(InvokeInstruction obj) {		try {		TypeFrame frame = getFrame();		if (obj.getName(getCPG()).equals("toArray")) {			ReferenceType target = obj.getReferenceType(getCPG());			String signature = obj.getSignature(getCPG());			if (signature.equals("([Ljava/lang/Object;)[Ljava/lang/Object;") && target.isAssignmentCompatibleWith(COLLECTION_TYPE)) {				boolean topIsExact = frame.isExact(frame.getStackLocation(0));				Type resultType = frame.popValue();				frame.popValue();				frame.pushValue(resultType);				frame.setExact(frame.getStackLocation(0), topIsExact);				return true;			} else if (signature.equals("()[Ljava/lang/Object;")) {				consumeStack(obj);				pushReturnType(obj);				frame.setExact(frame.getStackLocation(0), true);				return true;			}		}		return false;		} catch (DataflowAnalysisException e) {			return false;		} catch (ClassNotFoundException e) {			AnalysisContext.reportMissingClass(e);			return false;		}	}	@Override	public void visitCHECKCAST(CHECKCAST obj) {		consumeStack(obj);		pushValue(obj.getType(getCPG()));	}	@Override	public void visitINSTANCEOF(INSTANCEOF obj) {		if (valueNumberDataflow != null) {			// Record the value number of the value checked by this instruction,			// and the type the value was compared to.			try {				ValueNumberFrame vnaFrame = valueNumberDataflow.getFactAtLocation(getLocation());				if (vnaFrame.isValid()) {					instanceOfValueNumber = vnaFrame.getTopValue();					instanceOfType = obj.getType(getCPG());				}			} catch (DataflowAnalysisException e) {				// Ignore			}		}		consumeStack(obj);		pushValue(Type.INT);	}	@Override	public void visitIFNULL(IFNULL obj) {		if (valueNumberDataflow != null) {			// Record the value number of the value checked by this instruction,			// and the type the value was compared to.			try {				ValueNumberFrame vnaFrame = valueNumberDataflow						.getFactAtLocation(getLocation());				if (vnaFrame.isValid()) {					instanceOfValueNumber = vnaFrame.getTopValue();					instanceOfType = NullType.instance();					instanceOfFollowedByBranch = true;				}			} catch (DataflowAnalysisException e) {				// Ignore			}		}		consumeStack(obj);	}	@Override	public void visitIFNONNULL(IFNONNULL obj) {		if (valueNumberDataflow != null) {			// Record the value number of the value checked by this instruction,			// and the type the value was compared to.			try {				ValueNumberFrame vnaFrame = valueNumberDataflow						.getFactAtLocation(getLocation());				if (vnaFrame.isValid()) {					instanceOfValueNumber = vnaFrame.getTopValue();					instanceOfType = NullType.instance();					instanceOfFollowedByBranch = true;				}			} catch (DataflowAnalysisException e) {				// Ignore			}		}		consumeStack(obj);	}	@Override	public void visitFCMPL(FCMPL obj) {		consumeStack(obj);		pushValue(Type.INT);

⌨️ 快捷键说明

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