All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.evosuite.symbolic.vm.CallVM Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) 2010-2018 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 .
 */
package org.evosuite.symbolic.vm;

import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;

import org.evosuite.symbolic.expr.bv.IntegerConstant;
import org.evosuite.symbolic.expr.fp.RealConstant;
import org.evosuite.symbolic.expr.ref.ReferenceConstant;
import org.evosuite.symbolic.expr.ref.ReferenceExpression;
import org.evosuite.symbolic.instrument.ConcolicInstrumentingClassLoader;
import org.evosuite.symbolic.instrument.ConcolicMethodAdapter;
import org.objectweb.asm.Type;
import org.evosuite.dse.AbstractVM;

/**
 * Explicit inter-procedural control transfer: InvokeXXX, Return, etc.
 * 
 * We ignore the CALLER_STACK_PARAM calls here, as we have maintained the
 * operand stack during the caller's execution, so we already know the operand
 * stack values and therefore the parameter values to be used for a given method
 * invocation.
 * 
 * @author [email protected] (Christoph Csallner)
 */
public final class CallVM extends AbstractVM {

	private final SymbolicEnvironment env;

	/**
	 * Constructor
	 */
	public CallVM(SymbolicEnvironment env, ConcolicInstrumentingClassLoader classLoader) {
		this.env = env;
		this.classLoader = classLoader;
	}

	/**
	 * Start executing a static (class) initializer -- ()
	 */
	private void CLINIT_BEGIN(String className) {
		/*
		 * () method can read textually earlier fields
		 */
		env.ensurePrepared(className);
		Frame frame = new StaticInitializerFrame(className);
		env.pushFrame(frame); // () has no parameters
	}

	/**
	 * @param function
	 *            the method we are looking for in the frame stack
	 * @return constructor matches with the current frame, after discarding some
	 *         frames when necessary to match
	 */
	private boolean discardFrames(String className, String methName, Member function) {
		if (function == null)
			throw new IllegalArgumentException("function should be non null");

		if (env.topFrame() instanceof FakeBottomFrame)
			return false;

		Frame topFrame = env.topFrame();
		if (topFrame instanceof StaticInitializerFrame) {
			StaticInitializerFrame clinitFrame = (StaticInitializerFrame) topFrame;
			if (methName.equals(conf.INIT) && clinitFrame.getClassName().equals(className)) {
				return true;
			}
		}

		if (function != null && function.equals(topFrame.getMember()))
			return true;

		env.popFrame();
		return discardFrames(className, methName, function);
	}

	/**
	 * Begin of a basic block that is the begin of an exception handler.
	 * 
	 * We could be in an entirely different invocation frame than the previous
	 * instruction was in.
	 * 
	 * TODO: Account for different call sites in the same method. This may lead
	 * to the need to discard frames although they are of the same function as
	 * indicated by the parameters.
	 */
	@Override
	public void HANDLER_BEGIN(int access, String className, String methName, String methDesc) {

		if (conf.CLINIT.equals(methName)) {

			discardFramesClassInitializer(className, methName);

		} else {

			// the method or constructor containing this handler
			Member function = null;
			if (conf.INIT.equals(methName))
				function = resolveConstructorOverloading(className, methDesc);
			else
				function = resolveMethodOverloading(className, methName, methDesc);

			/**
			 * function could be equal to null if handler is in class
			 * initializer
			 */
			discardFrames(className, methName, function);
		}

		env.topFrame().operandStack.clearOperands();
		/**
		 * This exception is added to the HANDLER_BEGIN because no other
		 * instruction adds the corresponding exception. The handler will store
		 * the exception to the locals table
		 */
		ReferenceConstant exception_reference = new ReferenceConstant(Type.getType(Exception.class), -1);
		env.topFrame().operandStack.pushRef(exception_reference);
	}

	private boolean discardFramesClassInitializer(String className, String methName) {
		if (!conf.CLINIT.equals(methName))
			throw new IllegalArgumentException("methName should be ");

		if (env.topFrame() instanceof FakeBottomFrame)
			return false;

		Frame topFrame = env.topFrame();
		if (topFrame instanceof StaticInitializerFrame) {
			StaticInitializerFrame clinitFrame = (StaticInitializerFrame) topFrame;
			if (methName.equals(conf.CLINIT) && clinitFrame.getClassName().equals(className)) {
				return true;
			}
		}

		env.popFrame();
		return discardFramesClassInitializer(className, methName);
	}

	private final HashMap memberInfos = new HashMap();
	private final ConcolicInstrumentingClassLoader classLoader;

	/**
	 * Cache max values for this method, except for static initializers.
	 */
	@Override
	public void METHOD_MAXS(String className, String methName, String methDesc, int maxStack, int maxLocals) {
		if (conf.CLINIT.equals(methName))
			return;

		Member member = null;
		if (conf.INIT.equals(methName))
			member = resolveConstructorOverloading(className, methDesc);
		else
			member = resolveMethodOverloading(className, methName, methDesc);

		if (member == null)
			return; // TODO: could not resolve method or constructor

		if (memberInfos.containsKey(member))
			return;

		memberInfos.put(member, new MemberInfo(maxStack, maxLocals));
	}

	/**
	 * Pop operands off caller stack
	 * 
	 * Method methName is about to start execution.
	 * 
	 * At this point we have either already seen (observed InvokeXXX) or missed
	 * this invocation of the methName method.
	 * 
	 * We miss any of the following: - invoke  (as there are no such
	 * statements) - invoke  (as we do not add instrumentation code for
	 * these)
	 * 
	 * User code cannot call the () method directly. Instead, the JVM
	 * invokes a class's initializer implicitly, upon the first use of the
	 * class.
	 * 
	 * http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc.html
	 * #32316
	 * http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc
	 * .html#19075
	 * http://java.sun.com/docs/books/jvms/second_edition/html/Overview
	 * .doc.html#16262
	 */
	@Override
	public void METHOD_BEGIN(int access, String className, String methName, String methDesc) {
		/* TODO: Use access param to determine needsThis */

		if (conf.CLINIT.equals(methName)) {
			CLINIT_BEGIN(className);
			return;
		}

		if (env.topFrame().weInvokedInstrumentedCode() == false) {
			// An uninstrumented caller has called instrumented code
			// This is problemtatic
		}

		prepareStackIfNeeded(className, methName, methDesc);

		/* Begin of a method or constructor */
		final Frame callerFrame = env.topFrame(); // guy who (transitively)
													// called us
		Frame frame;
		boolean calleeNeedsThis = false;
		if (conf.INIT.equals(methName)) {
			Constructor constructor = resolveConstructorOverloading(className, methDesc);
			int maxLocals = conf.MAX_LOCALS_DEFAULT;
			MemberInfo memberInfo = memberInfos.get(constructor);
			if (memberInfo != null)
				maxLocals = memberInfo.maxLocals;
			frame = new ConstructorFrame(constructor, maxLocals);
			calleeNeedsThis = true;

			if (callerFrame.weInvokedInstrumentedCode() == false) {
				/**
				 * Since this is a constructor called from un-instrumented code,
				 * we need to "simulate" the missing NEW. This means 1) create a
				 * new object reference 2) populate the localstable with the new
				 * reference
				 */
				Class clazz = classLoader.getClassForName(className);
				Type objectType = Type.getType(clazz);
				ReferenceConstant newObject = this.env.heap.buildNewReferenceConstant(objectType);
				frame.localsTable.setRefLocal(0, newObject);
			}
		} else {
			Method method = resolveMethodOverloading(className, methName, methDesc);
			int maxLocals = conf.MAX_LOCALS_DEFAULT;
			MemberInfo memberInfo = memberInfos.get(method);
			if (memberInfo != null)
				maxLocals = memberInfo.maxLocals;
			frame = new MethodFrame(method, maxLocals);
			calleeNeedsThis = !Modifier.isStatic(method.getModifiers());
		}

		/*
		 * If our caller called uninstrumented code then we should not ruin his
		 * operand stack! Instead, METHOD_BEGIN_PARAM will supply the concrete
		 * parameter values and create corresponding symbolic constants.
		 */
		if (callerFrame.weInvokedInstrumentedCode() == false) {

			env.pushFrame(frame);

			// deal with Class.newInstance?

			return;
		}

		/*
		 * Our caller directly called us. We should take our parameters from his
		 * stack.
		 */
		Class[] paramTypes = getArgumentClasses(methDesc);
		final Deque params = new LinkedList();
		Iterator it = env.topFrame().operandStack.iterator();
		for (int i = paramTypes.length - 1; i >= 0; i--) {
			// read parameters from caller operand srack
			Operand param = it.next();
			params.push(param);
		}

		int index = 0;
		for (Operand param : params) {
			frame.localsTable.setOperand(index + (calleeNeedsThis ? 1 : 0), param);
			if (param instanceof SingleWordOperand)
				index += 1;
			else if (param instanceof DoubleWordOperand)
				index += 2;
			else {
				throw new IllegalStateException("Unknown operand type " + param.getClass().getName());
			}
		}

		if (calleeNeedsThis) { // "this" instance
			Operand param = it.next();
			ReferenceOperand refOperand = (ReferenceOperand) param;
			frame.localsTable.setRefLocal(0, refOperand.getReference());
		}

		env.pushFrame(frame);
	}

	private void prepareStackIfNeeded(String className, String methName, String methDesc) {

		Method method = null;
		if (env.isEmpty()) {
			Class claz = classLoader.getClassForName(className);

			Method[] declMeths = claz.getDeclaredMethods();
			for (Method declMeth : declMeths) {
				if (!Modifier.isPublic(declMeth.getModifiers()))
					continue;
				if (declMeth.getName().equals(methName))
					method = declMeth;
			}

			if (method != null) {
				env.prepareStack(method);
			}
		}

		if (env.isEmpty()) {
			throw new IllegalStateException();
		}

	}

	@Override
	public void METHOD_BEGIN_RECEIVER(Object value) {
		if (!env.callerFrame().weInvokedInstrumentedCode()) {
			ReferenceExpression ref = env.heap.getReference(value);
			env.topFrame().localsTable.setRefLocal(0, ref);
		}
	}

	@Override
	public void METHOD_BEGIN_PARAM(int nr, int index, int value) {
		if (!env.callerFrame().weInvokedInstrumentedCode()) {
			IntegerConstant literal_value = ExpressionFactory.buildNewIntegerConstant(value);
			env.topFrame().localsTable.setBv32Local(index, literal_value);
		}
	}

	@Override
	public void METHOD_BEGIN_PARAM(int nr, int index, boolean value) {
		if (!env.callerFrame().weInvokedInstrumentedCode()) {
			METHOD_BEGIN_PARAM(nr, index, value ? 1 : 0);
		}
	}

	@Override
	public void METHOD_BEGIN_PARAM(int nr, int index, byte value) {
		if (!env.callerFrame().weInvokedInstrumentedCode()) {
			METHOD_BEGIN_PARAM(nr, index, (int) value);
		}
	}

	@Override
	public void METHOD_BEGIN_PARAM(int nr, int index, char value) {
		if (!env.callerFrame().weInvokedInstrumentedCode()) {
			METHOD_BEGIN_PARAM(nr, index, (int) value);
		}
	}

	@Override
	public void METHOD_BEGIN_PARAM(int nr, int index, short value) {
		if (!env.callerFrame().weInvokedInstrumentedCode()) {
			METHOD_BEGIN_PARAM(nr, index, (int) value);
		}
	}

	@Override
	public void METHOD_BEGIN_PARAM(int nr, int index, long value) {
		if (!env.callerFrame().weInvokedInstrumentedCode()) {
			IntegerConstant literal_value = ExpressionFactory.buildNewIntegerConstant(value);
			env.topFrame().localsTable.setBv64Local(index, literal_value);
		}
	}

	@Override
	public void METHOD_BEGIN_PARAM(int nr, int index, double value) {
		if (!env.callerFrame().weInvokedInstrumentedCode()) {
			RealConstant literal_value = ExpressionFactory.buildNewRealConstant(value);
			env.topFrame().localsTable.setFp64Local(index, literal_value);
		}
	}

	@Override
	public void METHOD_BEGIN_PARAM(int nr, int index, float value) {
		if (!env.callerFrame().weInvokedInstrumentedCode()) {
			RealConstant literal_value = ExpressionFactory.buildNewRealConstant(value);
			env.topFrame().localsTable.setFp32Local(index, literal_value);
		}
	}

	@Override
	public void METHOD_BEGIN_PARAM(int nr, int index, Object conc_ref) {
		if (!env.callerFrame().weInvokedInstrumentedCode()) {
			ReferenceExpression symb_ref = env.heap.getReference(conc_ref);
			env.topFrame().localsTable.setRefLocal(index, symb_ref);
		}
	}

	/**
	 * Asm method descriptor --> Method parameters as Java Reflection classes.
	 * 
	 * Does not include the receiver for
	 */
	private Class[] getArgumentClasses(String methDesc) {
		Class[] classes;

		Type[] asmTypes = Type.getArgumentTypes(methDesc);
		classes = new Class[asmTypes.length];
		for (int i = 0; i < classes.length; i++)
			classes[i] = classLoader.getClassForType(asmTypes[i]);

		return classes;
	}

	/**
	 * Resolves (static) method overloading.
	 * 
	 * Ensures that owner class is prepared.
	 * 
	 * FIXME: user code calling java.util.Deque.isEmpty() crashes this method
	 * 
	 * @return method named name, declared by owner or one of its super-classes,
	 *         which has the parameters encoded in methDesc.
	 */
	private Method resolveMethodOverloading(String owner, String name, String methDesc) {
		Method method = null;
		final Deque> interfaces = new LinkedList>();

		Class claz = env.ensurePrepared(owner);
		/* Resolve method overloading -- need method parameter types */
		Class[] argTypes = getArgumentClasses(methDesc);

		while ((method == null) && (claz != null)) {
			Class[] ifaces = claz.getInterfaces();
			for (Class iface : ifaces)
				interfaces.add(iface);

			try { // TODO: Need getDeclaredMethods here?
				method = claz.getDeclaredMethod(name, argTypes);
			} catch (NoSuchMethodException nsme) { // TODO: do not use
													// exceptions
				claz = claz.getSuperclass();
			}

			if (claz == null && !interfaces.isEmpty())
				claz = interfaces.pop();
		}

		if (method == null)
			throw new IllegalArgumentException("Failed to resolve " + owner + "." + name);

		return method;
	}

	private Constructor resolveConstructorOverloading(String owner, String desc) {
		Constructor constructor = null;

		Class claz = env.ensurePrepared(owner);

		/* Resolve overloading -- need parameter types */
		Class[] argTypes = getArgumentClasses(desc);

		try {
			constructor = claz.getDeclaredConstructor(argTypes);
		} catch (NoSuchMethodException nsme) {
			throw new IllegalArgumentException("Failed to resolve constructor of " + owner);
		}

		return constructor;
	}

	/**
	 * @return method is instrumented. It is neither native nor declared by an
	 *         ignored JDK class, etc.
	 */
	private boolean isIgnored(Method method) {
		if (Modifier.isNative(method.getModifiers()))
			return false;

		/* virtual method */

		if (method.getDeclaringClass().isAnonymousClass()) {
			// anonymous class
			String name = method.getDeclaringClass().getName();
			int indexOf = name.indexOf("$");
			String fullyQualifiedTopLevelClassName = name.substring(0, indexOf);
			return !conf.isIgnored(fullyQualifiedTopLevelClassName);
		} else {
			String declClass = method.getDeclaringClass().getCanonicalName();
			return !conf.isIgnored(declClass);

		}
	}

	/**
	 * Method call
	 * 
    *
  • not a constructor
  • *
  • not a class initializer
  • *
* * @return static method descriptor */ private Method methodCall(String className, String methName, String methDesc) { final Method method = resolveMethodOverloading(className, methName, methDesc); /* private method may be native */ boolean instrumented = isIgnored(method); env.topFrame().invokeInstrumentedCode(instrumented); return method; } /** * http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2. * doc6.html#invokestatic */ @Override public void INVOKESTATIC(String className, String methName, String methDesc) { stackParamCount = 0; env.topFrame().invokeNeedsThis = false; methodCall(className, methName, methDesc); } /** * Used to invoke any *
    *
  • instance initialization method = (constructor + field init) *
  • *
  • private method
  • *
  • method of a superclass of the current class
  • *
* * No dynamic dispatch (unlike InvokeVirtual) * * http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2. * doc6.html#invokespecial * http://java.sun.com/docs/books/jvms/second_edition * /html/Overview.doc.html#12174 * http://java.sun.com/docs/books/jvms/second_edition * /html/Concepts.doc.html#33032 */ @Override public void INVOKESPECIAL(String className, String methName, String methDesc) { stackParamCount = 0; env.topFrame().invokeNeedsThis = true; if (conf.INIT.equals(methName)) { boolean instrumented = !conf.isIgnored(className); env.topFrame().invokeInstrumentedCode(instrumented); } else { methodCall(className, methName, methDesc); } } @Override public void INVOKESPECIAL(Object conc_receiver, String className, String methName, String methDesc) { INVOKESPECIAL(className, methName, methDesc); // String concreteClassName = conc_receiver.getClass().getName(); // if (concreteClassName != null) { // INVOKESPECIAL(concreteClassName, methName, methDesc); // } else { // INVOKESPECIAL(className, methName, methDesc); // } } /** * We get this callback right before the user code makes the corresponding * virtual call to method className.methName(methDesc). See: * {@link ConcolicMethodAdapter#visitMethodInsn} * *

* The current instrumentation system only calls this version of * INVOKEVIRTUAL for methods that take two or fewer parameters. * * http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2. * doc6.html#invokevirtual */ @Override public void INVOKEVIRTUAL(Object conc_receiver, String className, String methName, String methDesc) { stackParamCount = 0; env.topFrame().invokeNeedsThis = true; Iterator it = env.topFrame().operandStack.iterator(); Type[] argTypes = Type.getArgumentTypes(methDesc); for (int i = 0; i < argTypes.length; i++) { it.next(); } ReferenceOperand ref_operand = (ReferenceOperand) it.next(); ReferenceExpression symb_receiver = ref_operand.getReference(); env.heap.initializeReference(conc_receiver, symb_receiver); if (nullReferenceViolation(conc_receiver, symb_receiver)) return; String concreteClassName = conc_receiver.getClass().getName(); Method virtualMethod = methodCall(concreteClassName, methName, methDesc); chooseReceiverType(className, conc_receiver, methDesc, virtualMethod); } private boolean nullReferenceViolation(Object conc_receiver, ReferenceExpression symb_receiver) { return conc_receiver == null; } /** * We get this callback right before the user code makes the corresponding * call to interface method className.methName(methDesc). See: * {@link ConcolicMethodAdapter#visitMethodInsn} * *

* http://java.sun.com/docs/books/jvms/second_edition/html/Instructions2. * doc6.html#invokeinterface */ @Override public void INVOKEINTERFACE(Object conc_receiver, String className, String methName, String methDesc) { stackParamCount = 0; env.topFrame().invokeNeedsThis = true; if (nullReferenceViolation(conc_receiver, null)) return; String concreteClassName = conc_receiver.getClass().getName(); Method method = methodCall(concreteClassName, methName, methDesc); chooseReceiverType(className, conc_receiver, methDesc, method); } /** * Add dynamic type of receiver to path condition. */ private void chooseReceiverType(String className, Object receiver, String methDesc, Method staticMethod) { if (nullReferenceViolation(receiver, null)) { throw new IllegalArgumentException("we are post null-deref check"); } /* * Only encode the receiver type in a constraint if dynamic dispatach * can happen: not(isFinal(static receiver type)) */ final Class staticReceiver = env.ensurePrepared(className); if (Modifier.isFinal(staticReceiver.getModifiers())) return; /* * Heuristic: Do not encode the receiver type if a method is * "final native", e.g., Object.getClass(). * * not( isNative(static method descriptor) && isFinal(static method * descriptor)) */ final int methodModifiers = staticMethod.getModifiers(); if (Modifier.isNative(methodModifiers) && Modifier.isFinal(methodModifiers)) return; } private Frame popFrameAndDisposeCallerParams() { Frame frame = env.popFrame(); if (!env.isEmpty() && env.topFrame().weInvokedInstrumentedCode()) env.topFrame().disposeMethInvokeArgs(frame); return frame; } /** * Dispose our frame, we have no value to return. */ @Override public void RETURN() { popFrameAndDisposeCallerParams(); } /** * Dispose our frame and transfer the return value back. */ @Override public void IRETURN() { Frame returningFrame = popFrameAndDisposeCallerParams(); if (env.topFrame().weInvokedInstrumentedCode()) { Operand ret_val = returningFrame.operandStack.popOperand(); env.topFrame().operandStack.pushOperand(ret_val); } } @Override public void LRETURN() { IRETURN(); } @Override public void FRETURN() { IRETURN(); } @Override public void DRETURN() { IRETURN(); } @Override public void ARETURN() { IRETURN(); } /** * No actual return value. * * If we invoked uninstrumented code, then throw away the parameters passed * to that uninstrumented code. */ @Override public void CALL_RESULT(String owner, String name, String desc) { if (env.topFrame().weInvokedInstrumentedCode()) // RETURN already did it return; else { /** * Since control flow is returning from un-instrumented code, we * must get rid of the method arguments since the callee did not * consume the method arguments. */ env.topFrame().disposeMethInvokeArgs(desc); } } /** * Our chance to capture the value returned by a native or un-instrumented * method. */ @Override public void CALL_RESULT(boolean res, String owner, String name, String desc) { CALL_RESULT(owner, name, desc); if (env.topFrame().weInvokedInstrumentedCode()) { // RETURN already did // it return; } else { /** * We are returning from uninstrumented code. This is the only way * of storing the uninstrumented return value to the symbolic state. */ int i = res ? 1 : 0; IntegerConstant value = ExpressionFactory.buildNewIntegerConstant(i); env.topFrame().operandStack.pushBv32(value); } } /** * int, short, byte all map to a BitVec32 * * TODO: Will this work for char? */ @Override public void CALL_RESULT(int res, String owner, String name, String desc) { CALL_RESULT(owner, name, desc); if (env.topFrame().weInvokedInstrumentedCode()) {// RETURN already did // it return; } else { /** * We are returning from uninstrumented code. This is the only way * of storing the uninstrumented return value to the symbolic state. */ IntegerConstant value = ExpressionFactory.buildNewIntegerConstant(res); env.topFrame().operandStack.pushBv32(value); } } @Override public void CALL_RESULT(Object res, String owner, String name, String desc) { CALL_RESULT(owner, name, desc); if (env.topFrame().weInvokedInstrumentedCode()) // RETURN already did it return; else { /** * We are returning from uninstrumented code. This is the only way * of storing the method return value to the symbolic state. */ ReferenceExpression symb_ref = env.heap.getReference(res); env.topFrame().operandStack.pushRef(symb_ref); } } @Override public void CALL_RESULT(long res, String owner, String name, String desc) { CALL_RESULT(owner, name, desc); if (env.topFrame().weInvokedInstrumentedCode()) { // RETURN already did it return; } else { /** * We are returning from uninstrumented code. This is the only way * of storing the uninstrumented return value to the symbolic state. */ IntegerConstant value = ExpressionFactory.buildNewIntegerConstant(res); env.topFrame().operandStack.pushBv64(value); } } @Override public void CALL_RESULT(double res, String owner, String name, String desc) { CALL_RESULT(owner, name, desc); if (env.topFrame().weInvokedInstrumentedCode()) { // RETURN already did it return; } else { /** * We are returning from uninstrumented code. This is the only way * of storing the uninstrumented return value to the symbolic state. */ RealConstant value = ExpressionFactory.buildNewRealConstant(res); env.topFrame().operandStack.pushFp64(value); } } @Override public void CALL_RESULT(float res, String owner, String name, String desc) { CALL_RESULT(owner, name, desc); if (env.topFrame().weInvokedInstrumentedCode()) {// RETURN already did // it return; } else { /** * We are returning from uninstrumented code. This is the only way * of storing the uninstrumented return value to the symbolic state. */ RealConstant value = ExpressionFactory.buildNewRealConstant(res); env.topFrame().operandStack.pushFp32(value); } } /** * Nested class: Container for maximum size of operand stack and maximum * number of local variables. */ private final static class MemberInfo { @SuppressWarnings("unused") final int maxStack, maxLocals; MemberInfo(int maxStack, int maxLocals) { this.maxStack = maxStack; this.maxLocals = maxLocals; } } int stackParamCount = 0; @Override public void CALLER_STACK_PARAM(int nr, int calleeLocalsIndex, int value) { stackParamCount++; } @Override public void CALLER_STACK_PARAM(int nr, int calleeLocalsIndex, boolean value) { stackParamCount++; } @Override public void CALLER_STACK_PARAM(int nr, int calleeLocalsIndex, short value) { stackParamCount++; } @Override public void CALLER_STACK_PARAM(int nr, int calleeLocalsIndex, byte value) { stackParamCount++; } @Override public void CALLER_STACK_PARAM(int nr, int calleeLocalsIndex, char value) { stackParamCount++; } @Override public void CALLER_STACK_PARAM(int nr, int calleeLocalsIndex, long value) { stackParamCount++; } @Override public void CALLER_STACK_PARAM(int nr, int calleeLocalsIndex, float value) { stackParamCount++; } @Override public void CALLER_STACK_PARAM(int nr, int calleeLocalsIndex, double value) { stackParamCount++; } @Override public void CALLER_STACK_PARAM(int nr, int calleeLocalsIndex, Object conc_ref) { stackParamCount++; int operand_index = stackParamCount - 1; Operand op = getOperand(operand_index); ReferenceOperand ref_op = (ReferenceOperand) op; ReferenceExpression symb_ref = ref_op.getReference(); env.heap.initializeReference(conc_ref, symb_ref); } private Operand getOperand(int index) { Operand op; Iterator it = env.topFrame().operandStack.iterator(); for (int i = 0; i < index + 1; i++) { op = it.next(); if (i == index) { return op; } } return null; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy