Skip to content

Commit

Permalink
Extend information that Executors can provide to `ExecutingInvocati…
Browse files Browse the repository at this point in the history
…onUnit`

Before executors were just able to return a "result" value that represented either the object created by constructors or the return value of a method. Several changes and improvements on the code are present to allow the executors to specify more precise information:
- The concept of "result" is not present anymore in `ExecutingInvocationUnit`, now constructors are handled differently from return values. Constructors now work by specifying that the calling instance was modified
- Introduce a `MethodResult` class for the values returned by `Executor#getMethodResult`. This class can contain not only the return value, but information on whether the calling instance or arguments were modified during the analyzed method invocation
- There is no visibility anymore for `ExecutingInvocationUnit` of the logic in executors to specify if the returned value is the same reference as the calling instance. Now the executor takes care itself to specify that information in `MethodResult` by setting an updated instance
- Executors are now able to provide more fine-grained information, including specifying a value that is not particular. The aforementioned change on executors now providing full information on the returned instance id even when execution fails relies on this
- Executors can still tell `ExecutingInvocationUnit` to create its fallback value if they return an invalid `MethodResult`
  • Loading branch information
capoz authored and Toon Willemot committed Apr 25, 2024
1 parent e37898f commit bd74a66
Show file tree
Hide file tree
Showing 19 changed files with 1,189 additions and 597 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import static proguard.classfile.ClassConstants.METHOD_NAME_INIT;
import static proguard.classfile.ClassConstants.TYPE_JAVA_LANG_STRING;
import static proguard.classfile.util.ClassUtil.internalTypeFromClassName;
import static proguard.classfile.util.ClassUtil.isNullOrFinal;
import static proguard.classfile.util.ClassUtil.isExtendable;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand Down Expand Up @@ -148,7 +148,7 @@ public ValueAbstractState newObject(Clazz clazz) {
(IdentifiedReferenceValue)
valueFactory.createReferenceValue(
clazz,
isNullOrFinal(clazz),
isExtendable(clazz),
true,
new CodeLocation(
programLocation.getClazz(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import proguard.classfile.util.ClassUtil;
import proguard.classfile.visitor.ReferencedClassesExtractor;
import proguard.evaluation.ExecutingInvocationUnit;
import proguard.evaluation.MethodResult;
import proguard.evaluation.value.IdentifiedReferenceValue;
import proguard.evaluation.value.TopValue;
import proguard.evaluation.value.TypedReferenceValue;
Expand Down Expand Up @@ -216,14 +217,24 @@ private void executeMethod(
throw new IllegalStateException("Unexpected number of parameters");
}

Value result = executingInvocationUnit.executeMethod(call, operandsArray);
String returnType = internalMethodReturnType(targetMethod.getDescriptor(targetClass));
MethodResult result = null;

if (!call.isStatic() && UNKNOWN.getValue().equals(operandsArray[0])) {
result = MethodResult.invalidResult();
} else {
result = executingInvocationUnit.executeMethod(call, operandsArray);
}

pushReturnValue(state, result, returnType);
String returnType = internalMethodReturnType(targetMethod.getDescriptor(targetClass));
if (!isVoidReturnType(returnType)) {
Value returnValue =
result.isReturnValuePresent() ? result.getReturnValue() : UNKNOWN.getValue();
pushReturnValue(state, returnValue, returnType);
}

if (executingInvocationUnit.returnsOwnInstance(targetClass, targetMethod, operandsArray[0])) {
updateStack(state, result, returnType);
updateHeap(state, result);
if (result.isInstanceUpdated()) {
updateStack(state, result.getUpdatedInstance(), returnType);
updateHeap(state, result.getUpdatedInstance());
}
}

Expand All @@ -241,25 +252,25 @@ private void pushReturnTypedValue(
valueFactory.createReferenceValue(
ClassUtil.internalMethodReturnType(returnType),
referencedClassesExtractor.getReturnClass(),
ClassUtil.isNullOrFinal(referencedClassesExtractor.getReturnClass()),
ClassUtil.isExtendable(referencedClassesExtractor.getReturnClass()),
true);
pushReturnValue(state, result, returnType);
}
}

private void pushReturnValue(
JvmAbstractState<ValueAbstractState> state, Value result, String returnType) {
if (!isVoidReturnType(returnType)) {
if (isInternalCategory2Type(returnType)) {
state.push(TOP_VALUE);
}
state.push(new ValueAbstractState(result));
if (isInternalCategory2Type(returnType)) {
state.push(TOP_VALUE);
}
state.push(new ValueAbstractState(result));
}

private void updateStack(
JvmAbstractState<ValueAbstractState> state, Value result, String returnType) {
if (!(result instanceof IdentifiedReferenceValue)) return;
if (!(result instanceof IdentifiedReferenceValue)) {
return;
}

IdentifiedReferenceValue identifiedReferenceValue = (IdentifiedReferenceValue) result;
StackAbstractState<ValueAbstractState> operandStack = state.getFrame().getOperandStack();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

import static proguard.classfile.ClassConstants.TYPE_JAVA_LANG_STRING;
import static proguard.classfile.util.ClassUtil.internalTypeFromClassName;
import static proguard.classfile.util.ClassUtil.isNullOrFinal;
import static proguard.classfile.util.ClassUtil.isExtendable;

import java.security.InvalidParameterException;
import java.util.ArrayList;
Expand Down Expand Up @@ -733,7 +733,7 @@ public void visitClassConstant(Clazz clazz, ClassConstant classConstant) {
getAbstractReferenceValue(
internalTypeFromClassName(classConstant.getName(clazz)),
classConstant.referencedClass,
isNullOrFinal(classConstant.referencedClass),
isExtendable(classConstant.referencedClass),
true));
}
}
Expand Down
10 changes: 8 additions & 2 deletions base/src/main/java/proguard/classfile/util/ClassUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@
* </ul>
*/
public class ClassUtil {

private static final String EMPTY_STRING = "";

private ClassUtil() {}

/**
* Checks whether the given class magic number is correct.
*
Expand Down Expand Up @@ -1798,8 +1801,11 @@ public static String externalPackagePrefix(String externalClassName) {
+ 1);
}

/** Returns `true` if a {@link Clazz} is null or if it represents a final class. */
public static boolean isNullOrFinal(Clazz clazz) {
/**
* Returns `true` if a {@link Clazz} is null or if it does not represent a final class. This means
* that for the sake of our analysis we can consider value of this class not extendable.
*/
public static boolean isExtendable(Clazz clazz) {
return clazz == null || (clazz.getAccessFlags() & FINAL) == 0;
}
}
12 changes: 6 additions & 6 deletions base/src/main/java/proguard/evaluation/BasicInvocationUnit.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public Value getExceptionValue(Clazz clazz, ClassConstant catchClassConstant) {
return valueFactory.createReferenceValue(
ClassUtil.internalTypeFromClassName(catchClassName),
catchClass,
ClassUtil.isNullOrFinal(catchClass),
ClassUtil.isExtendable(catchClass),
false);
}

Expand All @@ -84,7 +84,7 @@ public Value getFieldClassValue(Clazz clazz, FieldrefConstant fieldrefConstant,
fieldrefConstant.referencedFieldAccept(this);

return valueFactory.createValue(
type, returnTypeClass, ClassUtil.isNullOrFinal(returnTypeClass), true);
type, returnTypeClass, ClassUtil.isExtendable(returnTypeClass), true);
}

public void setFieldValue(Clazz clazz, FieldrefConstant fieldrefConstant, Value value) {
Expand All @@ -97,7 +97,7 @@ public Value getFieldValue(Clazz clazz, FieldrefConstant fieldrefConstant, Strin
fieldrefConstant.referencedFieldAccept(this);

return valueFactory.createValue(
type, returnTypeClass, ClassUtil.isNullOrFinal(returnTypeClass), true);
type, returnTypeClass, ClassUtil.isExtendable(returnTypeClass), true);
}

public void setMethodParameterValue(
Expand All @@ -111,7 +111,7 @@ public Value getMethodParameterValue(
boolean isThis = parameterIndex == 0 && (method.getAccessFlags() & STATIC) == 0;

return valueFactory.createValue(
type, referencedClass, ClassUtil.isNullOrFinal(referencedClass), !isThis);
type, referencedClass, ClassUtil.isExtendable(referencedClass), !isThis);
}

public void setMethodReturnValue(Clazz clazz, Method method, Value value) {
Expand All @@ -125,7 +125,7 @@ public Value getMethodReturnValue(
anyMethodrefConstant.referencedMethodAccept(this);

return valueFactory.createValue(
type, returnTypeClass, ClassUtil.isNullOrFinal(returnTypeClass), true);
type, returnTypeClass, ClassUtil.isExtendable(returnTypeClass), true);
}

/** Returns the return value of the specified method. */
Expand All @@ -140,7 +140,7 @@ public Value getMethodReturnValue(
: null;

return valueFactory.createValue(
type, referencedClass, ClassUtil.isNullOrFinal(referencedClass), true);
type, referencedClass, ClassUtil.isExtendable(referencedClass), true);
}

// Implementations for MemberVisitor.
Expand Down

0 comments on commit bd74a66

Please sign in to comment.