Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion sootup.callgraph/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@
<artifactId>sootup.jimple.frontend</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependency>
<groupId>org.soot-oss</groupId>
<artifactId>sootup.java.core</artifactId>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
import sootup.core.model.SootMethod;
import sootup.core.model.SourceType;
import sootup.core.signatures.MethodSignature;
import sootup.core.signatures.PolymorphicMethodSignature;
import sootup.core.signatures.PolymorphicMethodSubSignature;
import sootup.core.types.ClassType;
import sootup.core.types.Type;
import sootup.java.bytecode.frontend.inputlocation.DefaultRuntimeAnalysisInputLocation;
import sootup.java.bytecode.frontend.inputlocation.JavaClassPathAnalysisInputLocation;
import sootup.java.core.types.JavaClassType;
Expand Down Expand Up @@ -1131,4 +1135,47 @@ public void testIssue1373() {
assertNotEquals(call.sourceMethodSignature(), call.targetMethodSignature());
}
}

@Test
public void testPolymorphicSignatureExamples() {
CallGraph cg = loadCallGraph("Polymorphic", "PolymorphicSignatureExamples");

ClassType methodHandleType = identifierFactory.getClassType("java.lang.invoke.MethodHandle");
ClassType varHandleType = identifierFactory.getClassType("java.lang.invoke.VarHandle");
Type returnType = identifierFactory.getType("java.lang.Object");
Type parameterTypes = identifierFactory.getType("java.lang.Object[]");

MethodSignature invokeExactMethodSig =
new PolymorphicMethodSignature(
methodHandleType,
new PolymorphicMethodSubSignature(
"invokeExact", Collections.singletonList(parameterTypes), returnType));
Set<MethodSignature> callSourcesInvokeExact = cg.callSourcesTo(invokeExactMethodSig);
assertTrue(callSourcesInvokeExact.contains(mainMethodSignature));

MethodSignature invokeMethodSig =
new PolymorphicMethodSignature(
methodHandleType,
new PolymorphicMethodSubSignature(
"invoke", Collections.singletonList(parameterTypes), returnType));
Set<MethodSignature> callSourcesInvoke = cg.callSourcesTo(invokeMethodSig);
assertTrue(callSourcesInvoke.contains(mainMethodSignature));

MethodSignature getMethodSig =
new PolymorphicMethodSignature(
varHandleType,
new PolymorphicMethodSubSignature(
"get", Collections.singletonList(parameterTypes), returnType));
Set<MethodSignature> callSourcesGet = cg.callSourcesTo(getMethodSig);
assertTrue(callSourcesGet.contains(mainMethodSignature));

MethodSignature varTypeMethodSig =
identifierFactory.getMethodSignature(
identifierFactory.getClassType("java.lang.invoke.VarHandle"),
"varType",
"java.lang.Class",
Collections.emptyList());
Set<MethodSignature> callSourcesVarType = cg.callSourcesTo(varTypeMethodSig);
assertTrue(callSourcesVarType.contains(mainMethodSignature));
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.VarHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

class VarHandleGetExample {
static int value = 42;
}

class VarHandleInstanceExample {
int instanceValue = 100;
}

class Base {
protected void method1(String dummy) {
}
}

class Derived extends Base {}

class PolymorphicSignatureExamples {
public static void main(String[] args) throws Throwable {
MethodHandle handle1 = MethodHandles.lookup().findVirtual(
String.class, "indexOf", MethodType.methodType(int.class, String.class, int.class)
);
int result = (int) handle1.invokeExact("HelloWorld", "lo", 3);


MethodHandle handle3 = MethodHandles.lookup()
.findVirtual(Base.class, "method1", MethodType.methodType(void.class, String.class));
handle3.invoke(new Derived(), "SubClass!");

VarHandle handle4 = MethodHandles.lookup()
.findStaticVarHandle(VarHandleGetExample.class, "value", int.class);
handle4.get();

VarHandle handle5 = MethodHandles.lookup()
.findVarHandle(VarHandleInstanceExample.class, "instanceValue", int.class);
handle5.varType();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package sootup.core.signatures;

/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 2018-2020 Linghui Luo, Jan Martin Persch, Christian Brüggemann and others
* %%
* This program 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 2.1 of the
* License, or (at your option) any later version.
*
* This program 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 General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
* #L%
*/

import org.jspecify.annotations.NonNull;
import sootup.core.types.ClassType;
import sootup.core.types.Type;

/**
* A marker subclass for {@code MethodSignature}. Used to identify the fully qualified signature of
* a polymorphic call site within the framework. Allows downstream analyses to check {@code (sig
* instanceof PolymorphicMethodSignature)}.
*/
public class PolymorphicMethodSignature extends MethodSignature {

/** Pass-through constructor to instantiate a polymorphic method signature. */
public PolymorphicMethodSignature(
@NonNull ClassType declaringClass,
@NonNull String methodName,
@NonNull Iterable<Type> parameters,
@NonNull Type fqReturnType) {
super(declaringClass, new PolymorphicMethodSubSignature(methodName, parameters, fqReturnType));
}

/**
* Constructs a polymorphic method signature using an already instantiated polymorphic
* sub-signature.
*/
public PolymorphicMethodSignature(
@NonNull ClassType declaringClass, @NonNull PolymorphicMethodSubSignature polySubSignature) {
super(declaringClass, polySubSignature);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package sootup.core.signatures;

/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 2018-2020 Linghui Luo, Jan Martin Persch, Christian Brüggemann and others
* %%
* This program 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 2.1 of the
* License, or (at your option) any later version.
*
* This program 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 General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
* #L%
*/

import org.jspecify.annotations.NonNull;
import sootup.core.types.Type;

/**
* A marker subclass for {@code MethodSubSignature}. Used to identify the sub-signature of a
* polymorphic call site.
*/
public class PolymorphicMethodSubSignature extends MethodSubSignature {
public PolymorphicMethodSubSignature(
@NonNull String name, @NonNull Iterable<? extends Type> parameterTypes, @NonNull Type type) {
super(name, parameterTypes, type);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,15 @@
import sootup.core.model.Position;
import sootup.core.signatures.FieldSignature;
import sootup.core.signatures.MethodSignature;
import sootup.core.signatures.PolymorphicMethodSignature;
import sootup.core.signatures.PolymorphicMethodSubSignature;
import sootup.core.transform.BodyInterceptor;
import sootup.core.types.*;
import sootup.core.util.Modifiers;
import sootup.core.views.View;
import sootup.java.core.AnnotationUsage;
import sootup.java.core.JavaIdentifierFactory;
import sootup.java.core.JavaSootMethod;
import sootup.java.core.jimple.basic.JavaLocal;
import sootup.java.core.language.JavaJimple;
import sootup.java.core.types.JavaClassType;
Expand Down Expand Up @@ -1091,8 +1095,53 @@ private void convertMethodInsn(@NonNull MethodInsnNode insn) {
JavaClassType cls = identifierFactory.getClassType(AsmUtil.toQualifiedName(clsName));
List<Type> sigTypes = AsmUtil.toJimpleSignatureDesc(insn.desc);
Type returnType = sigTypes.remove((sigTypes.size() - 1));
MethodSignature methodSignature =
identifierFactory.getMethodSignature(cls, insn.name, returnType, sigTypes);
// Methods with polymorphic signatures from the classes {@link java.lang.invoke.MethodHandle}
// and
// {@link java.lang.invoke.VarHandle}, require special treatment. Those methods can operate with
// any of
// a wide range of argument and return types. Instead of using the provided method signature,
// these methods
// are resolved as the original method signature from MethodHandle and VarHandle, because those
// methods exist
// while analyzing!
String methodSignatureName = insn.name;
JavaClassType methodHandleType =
identifierFactory.getClassType("java.lang.invoke.MethodHandle");
JavaClassType varHandleType = identifierFactory.getClassType("java.lang.invoke.VarHandle");
JavaClassType polyAnnotationType =
identifierFactory.getClassType("java.lang.invoke.MethodHandle$PolymorphicSignature");
// temp variable to hold the polymorphic signature match if we find one
MethodSignature polyMethodSignature = null;
if (cls.equals(methodHandleType) || cls.equals(varHandleType)) {
Set<? extends SootMethod> matchingMethods =
view.getClassOrThrow(cls).getMethodsByName(methodSignatureName);
// method name matching exactly one method signature name from Method/VarHandle
if (matchingMethods.size() == 1) {
MethodSignature possiblePolyMethodSig = matchingMethods.iterator().next().getSignature();
JavaSootMethod sootMethod =
(JavaSootMethod) view.getMethod(possiblePolyMethodSig).orElse(null);
if (sootMethod != null) {
for (AnnotationUsage annotations : sootMethod.getAnnotations()) {
// method is annotated with MethodHandle$PolymorphicSignature
if (annotations.getAnnotation().equals(polyAnnotationType)) {
polyMethodSignature =
new PolymorphicMethodSignature(
cls,
new PolymorphicMethodSubSignature(
possiblePolyMethodSig.getName(),
possiblePolyMethodSig.getParameterTypes(),
possiblePolyMethodSig.getType()));
break;
}
}
}
}
}
final MethodSignature methodSignature =
polyMethodSignature != null
? polyMethodSignature
// standard: method not annotated with MethodHandle$PolymorphicSignature
: identifierFactory.getMethodSignature(cls, methodSignatureName, returnType, sigTypes);
int nrArgs = sigTypes.size();
final Operand[] operands;
Immediate[] argList = new Immediate[nrArgs];
Expand Down
Loading