Skip to content

Commit

Permalink
Merge branch 'neo' into lipen/taint-panda
Browse files Browse the repository at this point in the history
  • Loading branch information
Lipen committed Jun 17, 2024
2 parents eb988d9 + 6c37ac4 commit ae856ab
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 3 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
pull_request:
branches:
- develop
- neo

permissions:
contents: read
Expand Down Expand Up @@ -105,4 +106,4 @@ jobs:
if: always()
with:
files: "**/build/test-results/**/*.xml"
check_name: "Lifecycle test results"
check_name: "Lifecycle test results"
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,7 @@ data class JcLambdaExpr(
val callSiteArgTypes: List<JcType>,
val callSiteReturnType: JcType,
val callSiteArgs: List<JcValue>,
val isNewInvokeSpecial: Boolean,
) : JcCallExpr {

override val method get() = bsmRef.method
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,28 @@ class JcInstListBuilder(val method: JcMethod,val instList: JcInstList<JcRawInst>
if (dynamicMethodType !is BsmMethodTypeArg) return null
if (implementation !is BsmHandle) return null

val argTypes: List<TypeName>
val tag = implementation.tag
var isNewInvokeSpecial = false
if (tag == 6) {
// Invoke static case
argTypes = implementation.argTypes
} else if (tag == 8) {
isNewInvokeSpecial = true
argTypes = implementation.argTypes
} else {
// Invoke non-static case
check(tag == 5 || tag == 7 || tag == 9) {
"Unexpected tag for invoke dynamic $tag"
}
argTypes = implementation.argTypes.toMutableList()
// Adding 'this' type as first argument type
argTypes.add(0, implementation.declaringClass)
}

// Check implementation signature match (starts with) call site arguments
for ((index, argType) in expr.callSiteArgTypes.withIndex()) {
if (argType != implementation.argTypes.getOrNull(index)) return null
if (argType != argTypes.getOrNull(index)) return null
}

val klass = implementation.declaringClass.asType() as JcClassType
Expand All @@ -303,7 +322,8 @@ class JcInstListBuilder(val method: JcMethod,val instList: JcInstList<JcRawInst>
expr.callSiteMethodName,
expr.callSiteArgTypes.map { it.asType() },
expr.callSiteReturnType.asType(),
expr.callSiteArgs.map { it.accept(this) as JcValue }
expr.callSiteArgs.map { it.accept(this) as JcValue },
isNewInvokeSpecial
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@

package org.jacodb.testing.cfg

import org.jacodb.api.jvm.cfg.JcAssignInst
import org.jacodb.api.jvm.cfg.JcLambdaExpr
import org.jacodb.api.jvm.ext.findClass
import org.jacodb.testing.WithGlobalDB
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test

class InvokeDynamicTest : BaseInstructionsTest() {
Expand All @@ -43,6 +46,21 @@ class InvokeDynamicTest : BaseInstructionsTest() {
@Test
fun `test complex invoke dynamic`() = runStaticMethod<InvokeDynamicExamples>("testComplexInvokeDynamic")

@Test
fun `test resolving virtual lambda`() {
val clazz = cp.findClass<InvokeDynamicExamples.CollectionWithInnerMap>()
val method = clazz.declaredMethods.find { it.name == "putAll" }!!
val instructions = method.instList
val first = instructions[0] as JcAssignInst
assertTrue(first.rhv is JcLambdaExpr)
val third = instructions[2] as JcAssignInst
assertTrue(third.rhv is JcLambdaExpr)
runStaticMethod<InvokeDynamicExamples>("testNonStaticLambda")
}

@Test
fun `invoke dynamic constructor`() = runStaticMethod<InvokeDynamicExamples>("testInvokeDynamicConstructor")

private inline fun <reified T> runStaticMethod(name: String) {
val clazz = cp.findClass<T>()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package org.jacodb.testing.cfg;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

public class InvokeDynamicExamples {
Expand Down Expand Up @@ -95,4 +97,68 @@ public static String testComplexInvokeDynamic() {
String actual = runComplexStringConcat("abc", 42);
return expected.equals(actual) ? "OK" : "BAD";
}

static class A {
private final String prefix;

public A(String prefix) {
this.prefix = prefix;
}

@Override
public String toString() {
return prefix + "456";
}
}

private static String invokeDynamicConstructor(Function<String, A> f){
A a = f.apply("123");
return a.toString();
}

public static String testInvokeDynamicConstructor() {
final String result = invokeDynamicConstructor(A::new);
return "123456".equals(result) ? "OK" : "BAD";
}

public static class CollectionWithInnerMap {
private final Map<String, String> innerMap;

public CollectionWithInnerMap() {
innerMap = new HashMap<>();
}

private void add(String key, String value) {
innerMap.put(key, value);
}

public void putAll(Map<String, String> map) {
map.forEach(this::removeBindingResultIfNecessary);
map.forEach(this::privateRemoveBindingResultIfNecessary);
innerMap.putAll(map);
}

void removeBindingResultIfNecessary(String key, String value) {
if (!key.isEmpty()) {
add(key + "cde", value);
}
}

private void privateRemoveBindingResultIfNecessary(String key, String value) {
if (!key.isEmpty()) {
add(key + "abc", value);
}
}
}

public static String testNonStaticLambda() {
CollectionWithInnerMap collection = new CollectionWithInnerMap();
Map<String, String> map = new HashMap<>();
map.put("abc", "cde");
map.put("dead", "beef");
collection.putAll(map);
String expected = "beef";
String actual = collection.innerMap.get("deadabc");
return expected.equals(actual) ? "OK" : "BAD";
}
}

0 comments on commit ae856ab

Please sign in to comment.