/** * Copyright (C) 2010-2017 Gordon Fraser, Andrea Arcuri and EvoSuite * contributors * * This file is part of EvoSuite. * * EvoSuite 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 3.0 of the License, or * (at your option) any later version. * * EvoSuite 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 Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with EvoSuite. If not, see <http://www.gnu.org/licenses/>. */ package org.evosuite.symbolic.vm; import java.util.Vector; import org.evosuite.symbolic.expr.bv.IntegerConstant; import org.evosuite.symbolic.expr.bv.IntegerValue; import org.evosuite.symbolic.expr.ref.ReferenceExpression; import org.evosuite.symbolic.expr.IntegerConstraint; import org.evosuite.dse.AbstractVM; /** * Java byte codes we group together as "jump-related" * * Explicit intra-procedural control transfer, conditional or unconditional: * Goto, jump, etc. * * @author csallner@uta.edu (Christoph Csallner) */ public final class JumpVM extends AbstractVM { private final SymbolicEnvironment env; private final PathConditionCollector pc; /** * Constructor */ public JumpVM(SymbolicEnvironment env, PathConditionCollector pc) { this.env = env; this.pc = pc; } /** * (p == 0) is just ((p == right) with right==0). (p != 0) is just (not (p * == 0)). * * http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2. * doc6.html#ifcond */ @Override public void IFEQ(String className, String methName, int branchIndex, int p) { env.topFrame().operandStack.pushBv32(ExpressionFactory.ICONST_0); // right // hand // side // argument // of // EQ comparison IF_ICMPEQ(className, methName, branchIndex, p, 0); // use general // implementation } @Override public void IFNE(String className, String methName, int branchIndex, int p) { IFEQ(className, methName, branchIndex, p); } /** * (p < 0) is just ((p < right) with right==0). (p >= 0) is just (not (p < * 0)). * * http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2. * doc6.html#ifcond */ @Override public void IFLT(String className, String methName, int branchIndex, int p) { env.topFrame().operandStack.pushBv32(ExpressionFactory.ICONST_0); // right // hand // side // argument // of // LT comparison IF_ICMPLT(className, methName, branchIndex, p, 0); // use general // implementation } @Override public void IFGE(String className, String methName, int branchIndex, int p) { IFLT(className, methName, branchIndex, p); } /** * (p > 0) is just (0 < p). (0 < p) is just ((left < p) with left==0). * * (p <= 0) is just (0 >= p). (0 >= p) is just (not (0 * < p * )). * * http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2. * doc6.html#ifcond */ @Override public void IFGT(String className, String methName, int branchIndex, int p) { IntegerValue rightBv = env.topFrame().operandStack.popBv32(); // symbolic // version // of // p env.topFrame().operandStack.pushBv32(ExpressionFactory.ICONST_0); // left // hand // side // argument // of // LT comparison env.topFrame().operandStack.pushBv32(rightBv); // right hand side // argument of LT // comparison IF_ICMPLT(className, methName, branchIndex, 0, p); } @Override public void IFLE(String className, String methName, int branchIndex, int p) { IFGT(className, methName, branchIndex, p); } /** * (left == right). (left != right) is just (not (left == right)). * * http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2. * doc6.html#if_icmpcond */ @Override public void IF_ICMPEQ(String className, String methName, int branchIndex, int left, int right) { IntegerValue rightOp = env.topFrame().operandStack.popBv32(); IntegerValue leftOp = env.topFrame().operandStack.popBv32(); IntegerConstraint cnstr; if (left == right) cnstr = ConstraintFactory.eq(leftOp, rightOp); // "True" branch else cnstr = ConstraintFactory.neq(leftOp, rightOp); // "False" branch // add branch condition iif local constraint is concrete if (cnstr.getLeftOperand().containsSymbolicVariable() || cnstr.getRightOperand().containsSymbolicVariable()) pc.addBranchCondition(className, methName, branchIndex, cnstr); } @Override public void IF_ICMPNE(String className, String methName, int branchIndex, int left, int right) { IF_ICMPEQ(className, methName, branchIndex, left, right); } /** * (left < right). (left >= right) is just (not (left < right)). * * http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2. * doc6.html#if_icmpcond */ @Override public void IF_ICMPLT(String className, String methName, int branchIndex, int left, int right) { IntegerValue rightBv = env.topFrame().operandStack.popBv32(); IntegerValue leftBv = env.topFrame().operandStack.popBv32(); IntegerConstraint cnstr; if (left < right) cnstr = ConstraintFactory.lt(leftBv, rightBv); // True Branch else cnstr = ConstraintFactory.gte(leftBv, rightBv); // False branch // add branch condition iif local constraint is concrete if (cnstr.getLeftOperand().containsSymbolicVariable() || cnstr.getRightOperand().containsSymbolicVariable()) pc.addBranchCondition(className, methName, branchIndex, cnstr); } @Override public void IF_ICMPGE(String className, String methName, int branchIndex, int left, int right) { IF_ICMPLT(className, methName, branchIndex, left, right); } /** * (left > right) is just (right < left). (left <= right) is just (not (left * > right)). * * http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2. * doc6.html#if_icmpcond */ @Override public void IF_ICMPGT(String className, String methName, int branchIndex, int left, int right) { // FIXME: Replace following five instructions with SWAP IntegerValue rightBv = env.topFrame().operandStack.popBv32(); IntegerValue leftBv = env.topFrame().operandStack.popBv32(); env.topFrame().operandStack.pushBv32(rightBv); env.topFrame().operandStack.pushBv32(leftBv); IF_ICMPLT(className, methName, branchIndex, right, left); } @Override public void IF_ICMPLE(String className, String methName, int branchIndex, int left, int right) { IF_ICMPGT(className, methName, branchIndex, left, right); } /* Reference equality */ /** * (left == right). (left != right) is just (not (left == right)). * * http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2. * doc6.html#if_acmpcond */ @Override public void IF_ACMPEQ(String className, String methName, int branchIndex, Object conc_left, Object conc_right) { ReferenceExpression right_ref = env.topFrame().operandStack.popRef(); ReferenceExpression left_ref = env.topFrame().operandStack.popRef(); env.heap.initializeReference(conc_left, left_ref); env.heap.initializeReference(conc_right, right_ref); } @Override public void IF_ACMPNE(String className, String methName, int branchIndex, Object left, Object right) { IF_ACMPEQ(className, methName, branchIndex, left, right); } /** * http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2. * doc6.html#ifnull */ @Override public void IFNULL(String className, String methName, int branchIndex, Object p) { // right hand side argument of EQ env.topFrame().operandStack.pushNullRef(); // comparison IF_ACMPEQ(className, methName, branchIndex, p, null); // use general // implementation } @Override public void IFNONNULL(String className, String methName, int branchIndex, Object p) { IFNULL(className, methName, branchIndex, p); } /* switch */ /** * <b>switch</b> statement that has consecutively numbered cases. I.e., * there are no holes (missing targets) between the lowest and highest * target. Hence the compiler does not need to translate the case values to * offsets. * * <p> * We treat the switch statement as a nested if in order lowest to highest * index as follows. * * <pre> * if (x==lowest) .. * else * { * if (x==second_lowest) .. * else * { * if .. * </pre> * * http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2. * doc14.html#tableswitch */ @Override public void TABLESWITCH(String className, String methName, int branchIndex, int goalConcrete, int min, int max) { final IntegerValue value = env.topFrame().operandStack.popBv32(); Vector<IntegerConstraint> constraints = new Vector<IntegerConstraint>(); // process each time in the same order: lowest to highest target for (int i = min; i <= max; i++) { IntegerConstant literal = ExpressionFactory .buildNewIntegerConstant(i); IntegerConstraint constraint; if (goalConcrete == i) { constraint = ConstraintFactory.eq(value, literal); constraints.add(constraint); break; } else { constraint = ConstraintFactory.neq(value, literal); constraints.add(constraint); } } for (int i = 0; i < constraints.size() - 1; i++) { IntegerConstraint cnstrt = constraints.get(i); if (cnstrt.getLeftOperand().containsSymbolicVariable() || cnstrt.getRightOperand().containsSymbolicVariable()) pc.addSupportingConstraint(cnstrt); } // add branch condition iif local constraint is concrete IntegerConstraint cnstr = constraints.get(constraints.size() - 1); if (cnstr.getLeftOperand().containsSymbolicVariable() || cnstr.getRightOperand().containsSymbolicVariable()) pc.addBranchCondition(className, methName, branchIndex, cnstr); } /** * <b>switch</b> statement whose cases may not be numbered consecutively. * I.e., there may be holes (missing targets) between the lowest and highest * target. * * <p> * Very similar to {@link #TABLESWITCH}. The main difference is that here we * are given a list of explicit goals. Tableswitch defines its goals * implicitly, between min and max. * * http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2. * doc8.html#lookupswitch */ @Override public void LOOKUPSWITCH(String className, String methName, int branchIndex, int goalConcrete, int[] targetsConcrete) { // TODO: target array remains constant. Do we really need to create and // pass // this array every time as a paremeter? final IntegerValue goal = env.topFrame().operandStack.popBv32(); Vector<IntegerConstraint> constraints = new Vector<IntegerConstraint>(); for (int targetConcrete : targetsConcrete) { IntegerConstant integerConstant = ExpressionFactory .buildNewIntegerConstant(targetConcrete); IntegerConstraint constraint; if (goalConcrete == targetConcrete) { constraint = ConstraintFactory.eq(goal, integerConstant); constraints.add(constraint); break; } else { constraint = ConstraintFactory.neq(goal, integerConstant); constraints.add(constraint); } } for (int i = 0; i < constraints.size() - 1; i++) { IntegerConstraint cnstrnt = constraints.get(i); if (cnstrnt.getLeftOperand().containsSymbolicVariable() || cnstrnt.getRightOperand().containsSymbolicVariable()) pc.addSupportingConstraint(cnstrnt); } // add branch condition iif local constraint is concrete IntegerConstraint cnstr = constraints.get(constraints.size() - 1); if (cnstr.getLeftOperand().containsSymbolicVariable() || cnstr.getRightOperand().containsSymbolicVariable()) { pc.addBranchCondition(className, methName, branchIndex, cnstr); } } /** * Unconditional jump * * No change to operand stack or local variables. * * ... ==> ... * * http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2. * doc5.html#goto */ @Override public void GOTO() { /* Concrete execution will take us to the next bytecode. */ } @Override public void GOTO_W() { GOTO(); } /** * http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2.doc * .html#athrow */ @Override public void ATHROW(Throwable throwable) { /** * This instructions pops the operand stack and throws an exception. We * only update the operand stack since exceptions are not explicitly * modelled in the VM. */ this.env.topFrame().operandStack.popRef(); /* Concrete execution will take us to the next bytecode. */ } /* Subroutine jump */ /** * Unconditional jump (to sub-routine, finally block) * * Pushes address onto operand stack, which finally block will astore. * * ... ==> ..., address * * http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2. * doc7.html#jsr */ @Override public void JSR() { throw new UnsupportedOperationException("Implement ME!"); } @Override public void JSR_W() { JSR(); } /** * Return from sub-routine * * Operand stack and local variables remain unchanged. * * ... ==> ... * * http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2. * doc12.html#ret */ @Override public void RET() { /* Concrete execution will take us to the next bytecode. */ } }