Skip to content

Commit

Permalink
Merge branch 'Guardsquare:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
zlataovce authored Aug 3, 2024
2 parents 4a6ce86 + a80d389 commit 7ac7e22
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -267,12 +267,18 @@ public boolean methodMayHaveSideEffects(
@Override
public Value getMethodReturnValue(
Clazz clazz, AnyMethodrefConstant anyMethodrefConstant, String returnType) {
if (anyMethodrefConstant.referencedMethod == null || parameters == null) {
if (anyMethodrefConstant.referencedMethod == null) {
return super.getMethodReturnValue(clazz, anyMethodrefConstant, returnType);
}

if (!isStatic && parameters == null) {
log.error("Parameters unexpectedly null for non-static method");
return super.getMethodReturnValue(clazz, anyMethodrefConstant, returnType);
}

MethodExecutionInfo methodInfo =
new MethodExecutionInfo(anyMethodrefConstant, null, parameters);
new MethodExecutionInfo(
anyMethodrefConstant, null, parameters == null ? new Value[0] : parameters);
Executor executor = executorLookup.lookupExecutor(methodInfo);

MethodResult result = executeMethod(executor, methodInfo);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,13 @@ public class MethodExecutionInfo {
* @param parameters The parameters of the call, calling instance included.
*/
public MethodExecutionInfo(
@NotNull Clazz clazz, Method method, CodeLocation caller, Value... parameters) {
@NotNull Clazz clazz,
@NotNull Method method,
@Nullable CodeLocation caller,
@NotNull Value... parameters) {
Objects.requireNonNull(clazz);
Objects.requireNonNull(method);
Objects.requireNonNull(parameters);
targetClass = clazz;
signature = (MethodSignature) Signature.of(clazz, method);
this.caller = caller;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@ import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.types.shouldBeInstanceOf
import io.kotest.matchers.types.shouldNotBeInstanceOf
import proguard.classfile.ClassConstants
import proguard.classfile.MethodSignature
import proguard.evaluation.ExecutingInvocationUnit
import proguard.evaluation.MethodResult
import proguard.evaluation.PartialEvaluator
import proguard.evaluation.ParticularReferenceValueFactory
import proguard.evaluation.ValueCalculator
import proguard.evaluation.executor.Executor
import proguard.evaluation.executor.MethodExecutionInfo
import proguard.evaluation.value.ArrayReferenceValueFactory
import proguard.evaluation.value.DetailedArrayValueFactory
import proguard.evaluation.value.IdentifiedReferenceValue
Expand Down Expand Up @@ -377,4 +383,70 @@ class ExecutingInvocationUnitTest : FreeSpec({
val str = partialEvaluator.getVariablesBefore(instruction).getValue(variableTable["str"]!!)
str.shouldNotBeInstanceOf<ParticularReferenceValue>()
}

"Static method with no parameters executed" - {

val code = JavaSource(
"Test.java",
"""
class Test {
public void test(){
String str = foo();
}

public static String foo() {
return "42";
}
}
""",
)

val (programClassPool, libraryClassPool) = ClassPoolBuilder.fromSource(code, javacArguments = listOf("-g", "-source", "1.8", "-target", "1.8"))
val valueFactory: ValueFactory = ParticularValueFactory(DetailedArrayValueFactory(), ParticularReferenceValueFactory())

val fooExecutor = object : Executor {

override fun getMethodResult(
methodData: MethodExecutionInfo,
valueCalculator: ValueCalculator,
): MethodResult {
return MethodResult.Builder()
.setReturnValue(
valueCalculator.apply(
ClassConstants.TYPE_JAVA_LANG_STRING,
libraryClassPool.getClass(ClassConstants.NAME_JAVA_LANG_STRING),
true,
"42",
false,
null,
),
).build()
}

override fun getSupportedMethodSignatures(): MutableSet<MethodSignature> {
return mutableSetOf(MethodSignature("Test", "foo", "()Ljava/lang/String;"))
}
}

val invocationUnit = ExecutingInvocationUnit.Builder().addExecutor { fooExecutor }.build(valueFactory, libraryClassPool)
val partialEvaluator = PartialEvaluator(
valueFactory,
invocationUnit,
false,
)

val (instructions, variableTable) = PartialEvaluatorUtil.evaluate(
"Test",
"test",
"()V",
programClassPool,
partialEvaluator,
)

val (instruction, _) = instructions.last()

val str = partialEvaluator.getVariablesBefore(instruction).getValue(variableTable["str"]!!)
str.shouldBeInstanceOf<ParticularReferenceValue>()
str.value.preciseValue shouldBe "42"
}
})
3 changes: 3 additions & 0 deletions docs/md/releasenotes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
## Version 9.1.5

### Improved
- `ExecutingInvocationUnit` now supports execution of static methods with no parameters.

### Bugfixes

- Prevent `unknown enum value for KmVersionRequirementVersionKind` exception when processing code compiled with an outdated Kotlin version.
Expand Down

0 comments on commit 7ac7e22

Please sign in to comment.