
org.apache.bcel.verifier.structurals.ExecutionVisitor Maven / Gradle / Ivy
Show all versions of bcel Show documentation
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.bcel.verifier.structurals;
import org.apache.bcel.Const;
import org.apache.bcel.classfile.Constant;
import org.apache.bcel.classfile.ConstantClass;
import org.apache.bcel.classfile.ConstantDouble;
import org.apache.bcel.classfile.ConstantFloat;
import org.apache.bcel.classfile.ConstantInteger;
import org.apache.bcel.classfile.ConstantLong;
import org.apache.bcel.classfile.ConstantString;
// CHECKSTYLE:OFF (there are lots of references!)
import org.apache.bcel.generic.*;
//CHECKSTYLE:ON
/**
* This Visitor class may be used for a type-based Java Virtual Machine
* simulation.
*
* It does not check for correct types on the OperandStack or in the
* LocalVariables; nor does it check their sizes are sufficiently big.
* Thus, to use this Visitor for bytecode verifying, you have to make sure
* externally that the type constraints of the Java Virtual Machine instructions
* are satisfied. An InstConstraintVisitor may be used for this.
* Anyway, this Visitor does not mandate it. For example, when you
* visitIADD(IADD o), then there are two stack slots popped and one
* stack slot containing a Type.INT is pushed (where you could also
* pop only one slot if you know there are two Type.INT on top of the
* stack). Monitor-specific behaviour is not simulated.
*
* Conventions:
*
* Type.VOID will never be pushed onto the stack. Type.DOUBLE and Type.LONG
* that would normally take up two stack slots (like Double_HIGH and
* Double_LOW) are represented by a simple single Type.DOUBLE or Type.LONG
* object on the stack here.
*
* If a two-slot type is stored into a local variable, the next variable
* is given the type Type.UNKNOWN.
*
* @version $Id$
* @see #visitDSTORE(DSTORE o)
* @see InstConstraintVisitor
*/
public class ExecutionVisitor extends EmptyVisitor{
/**
* The executionframe we're operating on.
*/
private Frame frame = null;
/**
* The ConstantPoolGen we're working with.
* @see #setConstantPoolGen(ConstantPoolGen)
*/
private ConstantPoolGen cpg = null;
/**
* Constructor. Constructs a new instance of this class.
*/
public ExecutionVisitor() {}
/**
* The OperandStack from the current Frame we're operating on.
* @see #setFrame(Frame)
*/
private OperandStack stack() {
return frame.getStack();
}
/**
* The LocalVariables from the current Frame we're operating on.
* @see #setFrame(Frame)
*/
private LocalVariables locals() {
return frame.getLocals();
}
/**
* Sets the ConstantPoolGen needed for symbolic execution.
*/
public void setConstantPoolGen(final ConstantPoolGen cpg) { // TODO could be package-protected?
this.cpg = cpg;
}
/**
* The only method granting access to the single instance of
* the ExecutionVisitor class. Before actively using this
* instance, SET THE ConstantPoolGen FIRST.
* @see #setConstantPoolGen(ConstantPoolGen)
*/
public void setFrame(final Frame f) { // TODO could be package-protected?
this.frame = f;
}
///** Symbolically executes the corresponding Java Virtual Machine instruction. */
//public void visitWIDE(WIDE o) {
// The WIDE instruction is modelled as a flag
// of the embedded instructions in BCEL.
// Therefore BCEL checks for possible errors
// when parsing in the .class file: We don't
// have even the possibilty to care for WIDE
// here.
//}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitAALOAD(final AALOAD o) {
stack().pop(); // pop the index int
//System.out.print(stack().peek());
final Type t = stack().pop(); // Pop Array type
if (t == Type.NULL) {
stack().push(Type.NULL);
} // Do nothing stackwise --- a NullPointerException is thrown at Run-Time
else{
final ArrayType at = (ArrayType) t;
stack().push(at.getElementType());
}
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitAASTORE(final AASTORE o) {
stack().pop();
stack().pop();
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitACONST_NULL(final ACONST_NULL o) {
stack().push(Type.NULL);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitALOAD(final ALOAD o) {
stack().push(locals().get(o.getIndex()));
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitANEWARRAY(final ANEWARRAY o) {
stack().pop(); //count
stack().push( new ArrayType(o.getType(cpg), 1) );
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitARETURN(final ARETURN o) {
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitARRAYLENGTH(final ARRAYLENGTH o) {
stack().pop();
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitASTORE(final ASTORE o) {
locals().set(o.getIndex(), stack().pop());
//System.err.println("TODO-DEBUG: set LV '"+o.getIndex()+"' to '"+locals().get(o.getIndex())+"'.");
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitATHROW(final ATHROW o) {
final Type t = stack().pop();
stack().clear();
if (t.equals(Type.NULL)) {
stack().push(Type.getType("Ljava/lang/NullPointerException;"));
} else {
stack().push(t);
}
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitBALOAD(final BALOAD o) {
stack().pop();
stack().pop();
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitBASTORE(final BASTORE o) {
stack().pop();
stack().pop();
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitBIPUSH(final BIPUSH o) {
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitCALOAD(final CALOAD o) {
stack().pop();
stack().pop();
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitCASTORE(final CASTORE o) {
stack().pop();
stack().pop();
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitCHECKCAST(final CHECKCAST o) {
// It's possibly wrong to do so, but SUN's
// ByteCode verifier seems to do (only) this, too.
// TODO: One could use a sophisticated analysis here to check
// if a type cannot possibly be cated to another and by
// so doing predict the ClassCastException at run-time.
stack().pop();
stack().push(o.getType(cpg));
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitD2F(final D2F o) {
stack().pop();
stack().push(Type.FLOAT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitD2I(final D2I o) {
stack().pop();
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitD2L(final D2L o) {
stack().pop();
stack().push(Type.LONG);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDADD(final DADD o) {
stack().pop();
stack().pop();
stack().push(Type.DOUBLE);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDALOAD(final DALOAD o) {
stack().pop();
stack().pop();
stack().push(Type.DOUBLE);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDASTORE(final DASTORE o) {
stack().pop();
stack().pop();
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDCMPG(final DCMPG o) {
stack().pop();
stack().pop();
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDCMPL(final DCMPL o) {
stack().pop();
stack().pop();
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDCONST(final DCONST o) {
stack().push(Type.DOUBLE);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDDIV(final DDIV o) {
stack().pop();
stack().pop();
stack().push(Type.DOUBLE);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDLOAD(final DLOAD o) {
stack().push(Type.DOUBLE);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDMUL(final DMUL o) {
stack().pop();
stack().pop();
stack().push(Type.DOUBLE);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDNEG(final DNEG o) {
stack().pop();
stack().push(Type.DOUBLE);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDREM(final DREM o) {
stack().pop();
stack().pop();
stack().push(Type.DOUBLE);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDRETURN(final DRETURN o) {
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDSTORE(final DSTORE o) {
locals().set(o.getIndex(), stack().pop());
locals().set(o.getIndex()+1, Type.UNKNOWN);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDSUB(final DSUB o) {
stack().pop();
stack().pop();
stack().push(Type.DOUBLE);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDUP(final DUP o) {
final Type t = stack().pop();
stack().push(t);
stack().push(t);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDUP_X1(final DUP_X1 o) {
final Type w1 = stack().pop();
final Type w2 = stack().pop();
stack().push(w1);
stack().push(w2);
stack().push(w1);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDUP_X2(final DUP_X2 o) {
final Type w1 = stack().pop();
final Type w2 = stack().pop();
if (w2.getSize() == 2) {
stack().push(w1);
stack().push(w2);
stack().push(w1);
}
else{
final Type w3 = stack().pop();
stack().push(w1);
stack().push(w3);
stack().push(w2);
stack().push(w1);
}
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDUP2(final DUP2 o) {
final Type t = stack().pop();
if (t.getSize() == 2) {
stack().push(t);
stack().push(t);
}
else{ // t.getSize() is 1
final Type u = stack().pop();
stack().push(u);
stack().push(t);
stack().push(u);
stack().push(t);
}
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDUP2_X1(final DUP2_X1 o) {
final Type t = stack().pop();
if (t.getSize() == 2) {
final Type u = stack().pop();
stack().push(t);
stack().push(u);
stack().push(t);
}
else{ //t.getSize() is1
final Type u = stack().pop();
final Type v = stack().pop();
stack().push(u);
stack().push(t);
stack().push(v);
stack().push(u);
stack().push(t);
}
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitDUP2_X2(final DUP2_X2 o) {
final Type t = stack().pop();
if (t.getSize() == 2) {
final Type u = stack().pop();
if (u.getSize() == 2) {
stack().push(t);
stack().push(u);
stack().push(t);
}else{
final Type v = stack().pop();
stack().push(t);
stack().push(v);
stack().push(u);
stack().push(t);
}
}
else{ //t.getSize() is 1
final Type u = stack().pop();
final Type v = stack().pop();
if (v.getSize() == 2) {
stack().push(u);
stack().push(t);
stack().push(v);
stack().push(u);
stack().push(t);
}else{
final Type w = stack().pop();
stack().push(u);
stack().push(t);
stack().push(w);
stack().push(v);
stack().push(u);
stack().push(t);
}
}
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitF2D(final F2D o) {
stack().pop();
stack().push(Type.DOUBLE);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitF2I(final F2I o) {
stack().pop();
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitF2L(final F2L o) {
stack().pop();
stack().push(Type.LONG);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitFADD(final FADD o) {
stack().pop();
stack().pop();
stack().push(Type.FLOAT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitFALOAD(final FALOAD o) {
stack().pop();
stack().pop();
stack().push(Type.FLOAT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitFASTORE(final FASTORE o) {
stack().pop();
stack().pop();
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitFCMPG(final FCMPG o) {
stack().pop();
stack().pop();
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitFCMPL(final FCMPL o) {
stack().pop();
stack().pop();
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitFCONST(final FCONST o) {
stack().push(Type.FLOAT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitFDIV(final FDIV o) {
stack().pop();
stack().pop();
stack().push(Type.FLOAT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitFLOAD(final FLOAD o) {
stack().push(Type.FLOAT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitFMUL(final FMUL o) {
stack().pop();
stack().pop();
stack().push(Type.FLOAT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitFNEG(final FNEG o) {
stack().pop();
stack().push(Type.FLOAT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitFREM(final FREM o) {
stack().pop();
stack().pop();
stack().push(Type.FLOAT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitFRETURN(final FRETURN o) {
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitFSTORE(final FSTORE o) {
locals().set(o.getIndex(), stack().pop());
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitFSUB(final FSUB o) {
stack().pop();
stack().pop();
stack().push(Type.FLOAT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitGETFIELD(final GETFIELD o) {
stack().pop();
Type t = o.getFieldType(cpg);
if ( t.equals(Type.BOOLEAN) ||
t.equals(Type.CHAR) ||
t.equals(Type.BYTE) ||
t.equals(Type.SHORT) ) {
t = Type.INT;
}
stack().push(t);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitGETSTATIC(final GETSTATIC o) {
Type t = o.getFieldType(cpg);
if ( t.equals(Type.BOOLEAN) ||
t.equals(Type.CHAR) ||
t.equals(Type.BYTE) ||
t.equals(Type.SHORT) ) {
t = Type.INT;
}
stack().push(t);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitGOTO(final GOTO o) {
// no stack changes.
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitGOTO_W(final GOTO_W o) {
// no stack changes.
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitI2B(final I2B o) {
stack().pop();
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitI2C(final I2C o) {
stack().pop();
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitI2D(final I2D o) {
stack().pop();
stack().push(Type.DOUBLE);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitI2F(final I2F o) {
stack().pop();
stack().push(Type.FLOAT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitI2L(final I2L o) {
stack().pop();
stack().push(Type.LONG);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitI2S(final I2S o) {
stack().pop();
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIADD(final IADD o) {
stack().pop();
stack().pop();
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIALOAD(final IALOAD o) {
stack().pop();
stack().pop();
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIAND(final IAND o) {
stack().pop();
stack().pop();
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIASTORE(final IASTORE o) {
stack().pop();
stack().pop();
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitICONST(final ICONST o) {
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIDIV(final IDIV o) {
stack().pop();
stack().pop();
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIF_ACMPEQ(final IF_ACMPEQ o) {
stack().pop();
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIF_ACMPNE(final IF_ACMPNE o) {
stack().pop();
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIF_ICMPEQ(final IF_ICMPEQ o) {
stack().pop();
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIF_ICMPGE(final IF_ICMPGE o) {
stack().pop();
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIF_ICMPGT(final IF_ICMPGT o) {
stack().pop();
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIF_ICMPLE(final IF_ICMPLE o) {
stack().pop();
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIF_ICMPLT(final IF_ICMPLT o) {
stack().pop();
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIF_ICMPNE(final IF_ICMPNE o) {
stack().pop();
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIFEQ(final IFEQ o) {
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIFGE(final IFGE o) {
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIFGT(final IFGT o) {
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIFLE(final IFLE o) {
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIFLT(final IFLT o) {
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIFNE(final IFNE o) {
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIFNONNULL(final IFNONNULL o) {
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIFNULL(final IFNULL o) {
stack().pop();
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIINC(final IINC o) {
// stack is not changed.
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitILOAD(final ILOAD o) {
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitIMUL(final IMUL o) {
stack().pop();
stack().pop();
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitINEG(final INEG o) {
stack().pop();
stack().push(Type.INT);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
@Override
public void visitINSTANCEOF(final INSTANCEOF o) {
stack().pop();
stack().push(Type.INT);
}
/**
* Symbolically executes the corresponding Java Virtual Machine instruction.
* @since 6.0
*/
@Override
public void visitINVOKEDYNAMIC(final INVOKEDYNAMIC o) {
for (int i=0; i