public class ExecutingInvocationUnit extends BasicInvocationUnit
This ExecutingInvocationUnit
reflectively executes the method calls it visits on a given
ParticularReferenceValue
.
After the (reflective) execution of method, it also takes care to replace values on stack/variables if needed. This needs to be done, as the PartialEvaluator treats all entries on stack/variables as immutable, and assumes that every change creates a new object.
Before a method call, the stack/variables can contain multiple references to the same object. If the method call then creates a new Variable (representing an updated object), we need to update all references to this new Variable.
There are some methods which always return a new object when the method is actually executed in the JVM (e.g. StringBuilder.toString). For such method calls, we never update the stack/variables (Denylist, Case 1)
For certain methods (e.g. the Constructor), we always need to replace the value on stack/variables (Allowlist, Case 3)
In all other cases, we assume the underlying object was changed if the returned value is of the same type as the called upon instance. This is an approximation, which works well for Strings, StringBuffer, StringBuilder (Approximation, Case 3)
Modifier and Type | Class and Description |
---|---|
static class |
ExecutingInvocationUnit.Builder
Builds an
ExecutingInvocationUnit . |
Modifier and Type | Field and Description |
---|---|
static boolean |
DEBUG |
valueFactory
Modifier | Constructor and Description |
---|---|
|
ExecutingInvocationUnit(ValueFactory valueFactory)
Deprecated.
|
protected |
ExecutingInvocationUnit(ValueFactory valueFactory,
java.util.Map<java.lang.String,java.util.Set<java.lang.String>> alwaysReturnsNewInstance,
java.util.Map<java.lang.String,java.util.Set<java.lang.String>> alwaysModifiesInstance,
boolean enableSameInstanceIdApproximation)
Creates an invocation unit resolving the methods from the specified classes via reflection.
|
Modifier and Type | Method and Description |
---|---|
boolean |
alwaysReturnsNewInstance(java.lang.String internalClassName,
java.lang.String methodName)
Returns true, if a call to internalClassName.methodName should return a new (i.e.
|
Value |
executeMethod(Clazz callingClass,
Method callingMethod,
int callingOffset,
Clazz clazz,
Method method,
Value... parameters)
Executes a method, by reflectively trying to call it with the given parameters.
|
Value |
executeMethod(ConcreteCall call,
Value... parameters)
Executes a method, by reflectively trying to call the method represented by the given
Call . |
Value |
getFieldValue(Clazz clazz,
FieldrefConstant fieldrefConstant,
java.lang.String type)
Returns the value of the specified field.
|
Value |
getMethodReturnValue(Clazz clazz,
AnyMethodrefConstant anyMethodrefConstant,
java.lang.String returnType)
Returns the return value of the specified method.
|
boolean |
isSupportedClass(java.lang.String internalClassName)
Returns true if the class is supported by the invocation unit.
|
boolean |
isSupportedMethodCall(java.lang.String internalClassName,
java.lang.String methodName)
Returns true if a method call can be called reflectively.
|
boolean |
methodMayHaveSideEffects(Clazz clazz,
AnyMethodrefConstant anyMethodrefConstant,
java.lang.String returnType)
Returns true if the method itself can modify the stack/variables and therefore
needs to be executed even if it returns void.
|
boolean |
returnsOwnInstance(Clazz clazz,
Method method,
Value instance)
Determines if the stack/variables need to be updated.
|
void |
setMethodParameterValue(Clazz clazz,
AnyMethodrefConstant anyMethodrefConstant,
int parameterIndex,
Value value)
Sets the value of the specified method parameter.
|
void |
visitAnyMethodrefConstant(Clazz clazz,
AnyMethodrefConstant anyMethodrefConstant)
Visits any RefConstant instance.
|
getExceptionValue, getFieldClassValue, getMethodParameterValue, getMethodReturnValue, setFieldClassValue, setFieldValue, setMethodReturnValue, visitLibraryField, visitLibraryMethod, visitProgramField, visitProgramMethod
enterExceptionHandler, enterMethod, exitMethod, invokeMember, visitFieldrefConstant, visitInvokeDynamicConstant, visitParameter
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
enterExceptionHandler, enterMethod, exitMethod, invokeMember
visitAnyMember, visitLibraryMember, visitProgramMember
visitAnyConstant, visitAnyRefConstant, visitClassConstant, visitDoubleConstant, visitDynamicConstant, visitFloatConstant, visitIntegerConstant, visitInterfaceMethodrefConstant, visitLongConstant, visitMethodHandleConstant, visitMethodrefConstant, visitMethodTypeConstant, visitModuleConstant, visitNameAndTypeConstant, visitPackageConstant, visitPrimitiveArrayConstant, visitStringConstant, visitUtf8Constant
protected ExecutingInvocationUnit(ValueFactory valueFactory, java.util.Map<java.lang.String,java.util.Set<java.lang.String>> alwaysReturnsNewInstance, java.util.Map<java.lang.String,java.util.Set<java.lang.String>> alwaysModifiesInstance, boolean enableSameInstanceIdApproximation)
valueFactory
- a value factoryalwaysReturnsNewInstance
- a mapping from class name to method name of methods that the invocation unit will assume to always return a new referencealwaysModifiesInstance
- a mapping from class name to method name of methods that the invocation unit will assume to modify the calling instanceenableSameInstanceIdApproximation
- whether the invocation unit will assume for classes not supported for execution that they might return the same reference of the calling
instance if their types match@Deprecated public ExecutingInvocationUnit(ValueFactory valueFactory)
public void setMethodParameterValue(Clazz clazz, AnyMethodrefConstant anyMethodrefConstant, int parameterIndex, Value value)
SimplifiedInvocationUnit
setMethodParameterValue
in class BasicInvocationUnit
public boolean methodMayHaveSideEffects(Clazz clazz, AnyMethodrefConstant anyMethodrefConstant, java.lang.String returnType)
SimplifiedInvocationUnit
methodMayHaveSideEffects
in class SimplifiedInvocationUnit
public Value getMethodReturnValue(Clazz clazz, AnyMethodrefConstant anyMethodrefConstant, java.lang.String returnType)
SimplifiedInvocationUnit
getMethodReturnValue
in class BasicInvocationUnit
public void visitAnyMethodrefConstant(Clazz clazz, AnyMethodrefConstant anyMethodrefConstant)
ConstantVisitor
visitAnyMethodrefConstant
in interface ConstantVisitor
visitAnyMethodrefConstant
in class SimplifiedInvocationUnit
public Value getFieldValue(Clazz clazz, FieldrefConstant fieldrefConstant, java.lang.String type)
SimplifiedInvocationUnit
getFieldValue
in class BasicInvocationUnit
public boolean isSupportedMethodCall(java.lang.String internalClassName, java.lang.String methodName)
public boolean isSupportedClass(java.lang.String internalClassName)
public Value executeMethod(ConcreteCall call, Value... parameters)
Call
.call
- The method to call.parameters
- An array containing the parameters values (for a non-static call, parameters[0] is the instance.public Value executeMethod(Clazz callingClass, Method callingMethod, int callingOffset, Clazz clazz, Method method, Value... parameters)
callingClass
- The class from where the method is being executed from.callingMethod
- The method from where the method is being executed from.callingOffset
- The offset from where the method is being executed from.parameters
- An array containing the parameters values (for a non-static call, parameters[0] is the instance.public boolean alwaysReturnsNewInstance(java.lang.String internalClassName, java.lang.String methodName)
internalClassName
- full class name of the base class of the method (e.g. java/lang/StringBuilder).methodName
- method name.public boolean returnsOwnInstance(Clazz clazz, Method method, Value instance)
Limitations: We are only checking if the instance of the call was modified, i.e. - for static calls, no value should be replaced on stack/variables (since no instance exists), and - the method call assumes that the parameters are not changed.
This is an approximation which works well for StringBuilder/StringBuffer and Strings.