From 1fd2fe265b48fc03426004cbc8c5cafd5f63c774 Mon Sep 17 00:00:00 2001 From: Markus Schmidt Date: Mon, 17 Jul 2023 12:30:16 +0200 Subject: [PATCH 01/16] fix off by one: iterating over a all type items; adapt it according to old soots implementation --- .../sootup/java/bytecode/frontend/AsmMethodSource.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java index 067aa461843..a9f06720a6e 100644 --- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java +++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java @@ -1345,7 +1345,7 @@ private void convertInvokeDynamicInsn(@Nonnull InvokeDynamicInsnNode insn) { // Generate parameters & returnType & parameterTypes List types = AsmUtil.toJimpleSignatureDesc(insn.desc); - int nrArgs = types.size() - 1; + int nrArgs = types.size() - 1; // don't handle the return type here List parameterTypes = new ArrayList<>(nrArgs); List methodArgs = new ArrayList<>(nrArgs); @@ -1383,12 +1383,12 @@ private void convertInvokeDynamicInsn(@Nonnull InvokeDynamicInsnNode insn) { AbstractInvokeExpr expr = (AbstractInvokeExpr) opr.value; List types = expr.getMethodSignature().getParameterTypes(); Operand[] oprs; - int nrArgs = types.size() - 1; + int nrArgs = types.size(); final boolean isStaticInvokeExpr = expr instanceof JStaticInvokeExpr; if (isStaticInvokeExpr) { - oprs = (nrArgs <= 0) ? null : new Operand[nrArgs]; + oprs = (nrArgs == 0) ? null : new Operand[nrArgs]; } else { - oprs = (nrArgs < 0) ? null : new Operand[nrArgs + 1]; + oprs = new Operand[nrArgs + 1]; } if (oprs != null) { while (nrArgs-- > 0) { From f5420790d9770eca114bb7d5114d2765364bd445 Mon Sep 17 00:00:00 2001 From: Markus Schmidt Date: Mon, 17 Jul 2023 12:30:31 +0200 Subject: [PATCH 02/16] cleanup --- .../bytecode/frontend/AsmMethodSource.java | 33 +++---------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java index a9f06720a6e..3fa2fdfdf04 100644 --- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java +++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java @@ -1345,7 +1345,7 @@ private void convertInvokeDynamicInsn(@Nonnull InvokeDynamicInsnNode insn) { // Generate parameters & returnType & parameterTypes List types = AsmUtil.toJimpleSignatureDesc(insn.desc); - int nrArgs = types.size() - 1; // don't handle the return type here + int nrArgs = types.size() - 1; // don't handle the return type here List parameterTypes = new ArrayList<>(nrArgs); List methodArgs = new ArrayList<>(nrArgs); @@ -1353,8 +1353,9 @@ private void convertInvokeDynamicInsn(@Nonnull InvokeDynamicInsnNode insn) { // Beware: Call stack is FIFO, Jimple is linear for (int i = nrArgs - 1; i >= 0; i--) { - parameterTypes.add(types.get(i)); - args[i] = operandStack.popImmediate(types.get(i)); + final Type type = types.get(i); + parameterTypes.add(type); + args[i] = operandStack.popImmediate(type); methodArgs.add((Immediate) args[i].stackOrValue()); } if (methodArgs.size() > 1) { @@ -1418,32 +1419,6 @@ private void convertInvokeDynamicInsn(@Nonnull InvokeDynamicInsnNode insn) { addReadOperandAssignments(); } - // private @Nonnull MethodRef toSootMethodRef(@Nonnull Handle methodHandle) { - // String bsmClsName = AsmUtil.toQualifiedName(methodHandle.getOwner()); - // JavaClassType bsmCls = view.getIdentifierFactory().getClassSignature(bsmClsName); - // List bsmSigTypes = AsmUtil.toJimpleSignatureDesc(methodHandle.getDesc(), view); - // Type returnType = bsmSigTypes.remove(bsmSigTypes.size() - 1); - // MethodSignature methodSignature = - // view.getIdentifierFactory().getMethodSignature(methodHandle.getName(), bsmCls, - // returnType, bsmSigTypes); - // boolean isStatic = methodHandle.getTag() == MethodHandle.Kind.REF_INVOKE_STATIC.getValue(); - // return Jimple.createSymbolicMethodRef(methodSignature, isStatic); - // } - // - // private JFieldRef toSootFieldRef(Handle methodHandle) { - // String bsmClsName = AsmUtil.toQualifiedName(methodHandle.getOwner()); - // JavaClassType bsmCls = view.getIdentifierFactory().getClassSignature(bsmClsName); - // - // Type t = AsmUtil.toJimpleSignatureDesc(methodHandle.getDesc(), view).get(0); - // int kind = methodHandle.getTag(); - // boolean isStatic = kind == MethodHandle.Kind.REF_GET_FIELD_STATIC.getValue() - // || kind == MethodHandle.Kind.REF_PUT_FIELD_STATIC.getValue(); - // - // FieldSignature fieldSignature = - // view.getIdentifierFactory().getFieldSignature(methodHandle.getName(), bsmCls, t); - // return Jimple.createSymbolicFieldRef(fieldSignature, isStatic); - // } - private void convertMultiANewArrayInsn(@Nonnull MultiANewArrayInsnNode insn) { StackFrame frame = operandStack.getOrCreateStackframe(insn); Operand[] out = frame.getOut(); From 453bb7bd0d774056ce873cb49b6c5b31a7e24b40 Mon Sep 17 00:00:00 2001 From: Jonas Klauke Date: Fri, 11 Aug 2023 17:53:16 +0200 Subject: [PATCH 03/16] used FieldSignature instead of FieldRef in MethodHandle --- .../core/jimple/common/constant/MethodHandle.java | 14 ++++++++------ .../java/bytecode/frontend/AsmMethodSource.java | 9 ++++++++- .../java/sootup/java/core/language/JavaJimple.java | 4 ++-- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/constant/MethodHandle.java b/sootup.core/src/main/java/sootup/core/jimple/common/constant/MethodHandle.java index d7e0bf53303..58cfd51cd75 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/constant/MethodHandle.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/constant/MethodHandle.java @@ -23,8 +23,8 @@ */ import javax.annotation.Nonnull; -import sootup.core.jimple.common.ref.JFieldRef; import sootup.core.jimple.visitor.ConstantVisitor; +import sootup.core.signatures.FieldSignature; import sootup.core.signatures.MethodSignature; import sootup.core.types.Type; @@ -80,19 +80,19 @@ public static Kind getKind(String kind) { } private final MethodSignature methodSignature; - private final JFieldRef fieldRef; + private final FieldSignature fieldSignature; public int tag; public MethodHandle(MethodSignature methodSignature, int tag, Type type) { this.methodSignature = methodSignature; this.tag = tag; - this.fieldRef = null; + this.fieldSignature = null; this.type = type; } - public MethodHandle(JFieldRef ref, int tag, Type type) { - this.fieldRef = ref; + public MethodHandle(FieldSignature ref, int tag, Type type) { + this.fieldSignature = ref; this.tag = tag; this.methodSignature = null; this.type = type; @@ -110,7 +110,9 @@ public static boolean isMethodRef(int kind) { // FIXME: [ms] serialize in a way it can be restored with the same parameters; adapt Jimple.g4 and // JimpleConverter.java public String toString() { - return "handle: " + methodSignature; + return "handle: " + + (methodSignature == null ? "" : methodSignature) + + (fieldSignature == null ? "" : fieldSignature); } @Nonnull diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java index 536a6619dfb..db76ca5dd91 100644 --- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java +++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java @@ -1148,7 +1148,7 @@ private Immediate toSootValue(@Nonnull Object val) throws UnsupportedOperationEx } else { v = JavaJimple.getInstance() - .newMethodHandle(toSootFieldRef((Handle) val), ((Handle) val).getTag()); + .newMethodHandle(toSootFieldSignature((Handle) val), ((Handle) val).getTag()); } } else { throw new UnsupportedOperationException("Unknown constant type: " + val.getClass()); @@ -1172,6 +1172,13 @@ private JFieldRef toSootFieldRef(Handle methodHandle) { } } + private FieldSignature toSootFieldSignature(Handle methodHandle) { + String bsmClsName = AsmUtil.toQualifiedName(methodHandle.getOwner()); + JavaClassType bsmCls = identifierFactory.getClassType(bsmClsName); + Type t = AsmUtil.toJimpleSignatureDesc(methodHandle.getDesc()).get(0); + return identifierFactory.getFieldSignature(methodHandle.getName(), bsmCls, t); + } + private MethodSignature toMethodSignature(Handle methodHandle) { String bsmClsName = AsmUtil.toQualifiedName(methodHandle.getOwner()); JavaClassType bsmCls = identifierFactory.getClassType(bsmClsName); diff --git a/sootup.java.core/src/main/java/sootup/java/core/language/JavaJimple.java b/sootup.java.core/src/main/java/sootup/java/core/language/JavaJimple.java index 23bc6b44319..3ec7d04c4ca 100644 --- a/sootup.java.core/src/main/java/sootup/java/core/language/JavaJimple.java +++ b/sootup.java.core/src/main/java/sootup/java/core/language/JavaJimple.java @@ -32,7 +32,7 @@ import sootup.core.jimple.common.constant.MethodType; import sootup.core.jimple.common.constant.StringConstant; import sootup.core.jimple.common.ref.JCaughtExceptionRef; -import sootup.core.jimple.common.ref.JFieldRef; +import sootup.core.signatures.FieldSignature; import sootup.core.signatures.MethodSignature; import sootup.core.types.NullType; import sootup.core.types.PrimitiveType; @@ -86,7 +86,7 @@ public StringConstant newStringConstant(String value) { return new StringConstant(value, getIdentifierFactory().getType("java.lang.String")); } - public MethodHandle newMethodHandle(JFieldRef ref, int tag) { + public MethodHandle newMethodHandle(FieldSignature ref, int tag) { return new MethodHandle( ref, tag, getIdentifierFactory().getType("java.lang.invoke.MethodHandle")); } From 5e8fc4a2bd01d3d2b6d52d8b01ebda00939a093a Mon Sep 17 00:00:00 2001 From: Jonas Klauke Date: Fri, 11 Aug 2023 17:53:34 +0200 Subject: [PATCH 04/16] added Test for Records in Java14 --- .../java14/binary/RecordTest.class | Bin 0 -> 1216 bytes .../java14/source/RecordTest.java | 6 +++ .../minimaltestsuite/java14/RecordTest.java | 51 ++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 shared-test-resources/miniTestSuite/java14/binary/RecordTest.class create mode 100644 shared-test-resources/miniTestSuite/java14/source/RecordTest.java create mode 100644 sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java14/RecordTest.java diff --git a/shared-test-resources/miniTestSuite/java14/binary/RecordTest.class b/shared-test-resources/miniTestSuite/java14/binary/RecordTest.class new file mode 100644 index 0000000000000000000000000000000000000000..f10d31483f04146a0c7febafc173050014f7935c GIT binary patch literal 1216 zcmaJ=U2hUW6g?Lx3%C@DZM9-ss;$DdminzheXzzzf*-M@5BfB~q-+bjxVtp*Klxx2 z8xtP<0sbiC9d?mLNFR3Y?A>$ExpVf;?>~cI0G{J%3K2v##B|IdPRJgMQ&H{+>!|!u zHf^Uxh(9we(|bXP7E6aoB#_jQ(s2noA?1VW()9==_^B$yyp9aA{MI1kYGcX+&oQl| zN{*#-Ixb_8knn6jODGg;W4cOdcHOd$E4a#aZQ-`}?Up2DChMw-{+fhR?qf9=Uv(rr3s&$FFy$$m$;Za5Kee4Zu=t4~Zp;8y~BY^SI+G6apEG(oRgmUM<1 z($(;gur)T}fv|!m|}YPEEfWVm0O*;~>61tNdk+-|nj`#W7?2 z1R42rXvWSt(r29Fzr$+|F%oo{I~dNk*8L>-bsV+p)oL#kbCpIBLd#^Z3qN zpGV26{Q_T!8yx=!F9F|Xfb+N+fD7D&I#I&d9$;k_nz*A8^(t2>!8zjxv}s}<+(tKYcfE4|9YfTa!Q;cX5wB1yZd30FUqlD}MpmfC1G2 literal 0 HcmV?d00001 diff --git a/shared-test-resources/miniTestSuite/java14/source/RecordTest.java b/shared-test-resources/miniTestSuite/java14/source/RecordTest.java new file mode 100644 index 00000000000..cc11333dcf5 --- /dev/null +++ b/shared-test-resources/miniTestSuite/java14/source/RecordTest.java @@ -0,0 +1,6 @@ +record RecordTest(int a, String b) { + public RecordTest(int a, String b) { + this.a = a; + this.b = b; + } +} \ No newline at end of file diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java14/RecordTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java14/RecordTest.java new file mode 100644 index 00000000000..154bd616084 --- /dev/null +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java14/RecordTest.java @@ -0,0 +1,51 @@ +package sootup.java.bytecode.minimaltestsuite.java14; + +import categories.Java9Test; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSignature; +import sootup.java.bytecode.minimaltestsuite.MinimalBytecodeTestSuiteBase; +import sootup.java.core.JavaIdentifierFactory; +import sootup.java.core.types.JavaClassType; + +/** @author Jonas Klauke */ +@Category(Java9Test.class) +public class RecordTest extends MinimalBytecodeTestSuiteBase { + + @Override + public JavaClassType getDeclaredClassSignature() { + return JavaIdentifierFactory.getInstance().getClassType("RecordTest"); + } + + @Override + public MethodSignature getMethodSignature() { + System.out.println(getDeclaredClassSignature()); + return identifierFactory.getMethodSignature( + getDeclaredClassSignature(), + "equals", + "boolean", + Collections.singletonList("java.lang.Object")); + } + + @Override + public List expectedBodyStmts() { + return Stream.of( + "l0 := @this: RecordTest", + "l1 := @parameter0: java.lang.Object", + "$stack2 = dynamicinvoke \"equals\" (l0, l1) (class \"LRecordTest;\", \"a;b\", handle: , handle: )", + "return $stack2") + .collect(Collectors.toCollection(ArrayList::new)); + } + + @Test + public void test() { + SootMethod method = loadMethod(getMethodSignature()); + assertJimpleStmts(method, expectedBodyStmts()); + } +} From e544a578b8f6befa5b6b37d98fe1f71e4a99521a Mon Sep 17 00:00:00 2001 From: Jonas Klauke Date: Mon, 14 Aug 2023 18:16:24 +0200 Subject: [PATCH 05/16] added the tag to the methodhandle serialization. Adapted the jimple parser to the new changes --- .../InstantiateClassValueVisitorTest.java | 12 +- .../jimple/common/constant/MethodHandle.java | 109 ++++++++++++------ .../minimaltestsuite/java14/RecordTest.java | 44 ++++++- .../sootup/java/core/language/JavaJimple.java | 12 +- .../src/main/antlr4/sootup/jimple/Jimple.g4 | 5 +- .../sootup/jimple/parser/JimpleConverter.java | 22 ++-- .../jimple/MethodAcceptingLamExpr.jimple | 2 +- .../resources/jimple/MethodReference.jimple | 2 +- .../java8/MethodAcceptingLamExprTest.java | 2 +- 9 files changed, 149 insertions(+), 61 deletions(-) diff --git a/sootup.callgraph/src/test/java/sootup/callgraph/InstantiateClassValueVisitorTest.java b/sootup.callgraph/src/test/java/sootup/callgraph/InstantiateClassValueVisitorTest.java index 7186e18082e..2313bfaea48 100644 --- a/sootup.callgraph/src/test/java/sootup/callgraph/InstantiateClassValueVisitorTest.java +++ b/sootup.callgraph/src/test/java/sootup/callgraph/InstantiateClassValueVisitorTest.java @@ -14,13 +14,10 @@ import sootup.core.jimple.basic.Local; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.constant.BooleanConstant; -import sootup.core.jimple.common.constant.ClassConstant; import sootup.core.jimple.common.constant.DoubleConstant; -import sootup.core.jimple.common.constant.EnumConstant; import sootup.core.jimple.common.constant.FloatConstant; import sootup.core.jimple.common.constant.IntConstant; import sootup.core.jimple.common.constant.LongConstant; -import sootup.core.jimple.common.constant.MethodHandle; import sootup.core.jimple.common.constant.MethodType; import sootup.core.jimple.common.constant.StringConstant; import sootup.core.jimple.common.expr.JAddExpr; @@ -70,6 +67,7 @@ import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation; import sootup.java.core.JavaProject; import sootup.java.core.JavaSootClass; +import sootup.java.core.language.JavaJimple; import sootup.java.core.language.JavaLanguage; @Category(Java8Test.class) @@ -153,10 +151,10 @@ private void fillList(List listWithAllValues, View view) { listWithAllValues.add(FloatConstant.getInstance(2.5f)); listWithAllValues.add(IntConstant.getInstance(3)); listWithAllValues.add(LongConstant.getInstance(3L)); - listWithAllValues.add(new StringConstant("String", StringClass)); - listWithAllValues.add(new EnumConstant("3", StringClass)); - listWithAllValues.add(new ClassConstant("java/lang/String", StringClass)); - listWithAllValues.add(new MethodHandle(toStringMethod, 3, StringClass)); + listWithAllValues.add(stringConstant); + listWithAllValues.add(JavaJimple.getInstance().newEnumConstant("3", "EnumTest")); + listWithAllValues.add(JavaJimple.getInstance().newClassConstant("java/lang/String")); + listWithAllValues.add(JavaJimple.getInstance().newMethodHandle(toStringMethod, 5)); listWithAllValues.add(new MethodType(toStringMethod.getSubSignature(), StringClass)); listWithAllValues.add(new JAddExpr(stringConstant, stringConstant)); listWithAllValues.add(new JAndExpr(stringConstant, stringConstant)); diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/constant/MethodHandle.java b/sootup.core/src/main/java/sootup/core/jimple/common/constant/MethodHandle.java index 58cfd51cd75..fd1792c29e4 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/constant/MethodHandle.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/constant/MethodHandle.java @@ -4,7 +4,7 @@ * #%L * Soot - a J*va Optimization Framework * %% - * Copyright (C) 2005-2020 Jennifer Lhotak, Andreas Dann, Linghui Luo and others + * Copyright (C) 2005-2023 Jennifer Lhotak, Andreas Dann, Linghui, Luo Jonas Klauke 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 @@ -26,11 +26,13 @@ import sootup.core.jimple.visitor.ConstantVisitor; import sootup.core.signatures.FieldSignature; import sootup.core.signatures.MethodSignature; +import sootup.core.signatures.SootClassMemberSignature; +import sootup.core.signatures.SootClassMemberSubSignature; import sootup.core.types.Type; public class MethodHandle implements Constant { - private final Type type; + @Nonnull private final Type type; public enum Kind { REF_GET_FIELD(1, "REF_GET_FIELD"), @@ -60,6 +62,10 @@ public int getValue() { return val; } + public String getValueName() { + return valStr; + } + public static Kind getKind(int kind) { for (Kind k : Kind.values()) { if (k.getValue() == kind) { @@ -69,50 +75,83 @@ public static Kind getKind(int kind) { throw new RuntimeException("Error: No method handle kind for value '" + kind + "'."); } - public static Kind getKind(String kind) { + public static Kind getKind(String kindName) { for (Kind k : Kind.values()) { - if (k.toString().equals(kind)) { + if (k.getValueName().equals(kindName)) { return k; } } - throw new RuntimeException("Error: No method handle kind for value '" + kind + "'."); + throw new RuntimeException("Error: No method handle kind for value name '" + kindName + "'."); } } - private final MethodSignature methodSignature; - private final FieldSignature fieldSignature; + @Nonnull + private final SootClassMemberSignature referenceSignature; - public int tag; + @Nonnull private final Kind kind; - public MethodHandle(MethodSignature methodSignature, int tag, Type type) { - this.methodSignature = methodSignature; - this.tag = tag; - this.fieldSignature = null; + public MethodHandle( + @Nonnull SootClassMemberSignature referenceSignature, + int tag, + @Nonnull Type type) { + this.kind = Kind.getKind(tag); this.type = type; + this.referenceSignature = referenceSignature; + if ((this.isMethodRef() && !(referenceSignature instanceof MethodSignature)) + || (this.isFieldRef() && !(referenceSignature instanceof FieldSignature))) { + throw new IllegalArgumentException( + "Tag:" + + tag + + " " + + kind.valStr + + " does not match with the given signature:" + + referenceSignature.getClass()); + } } - public MethodHandle(FieldSignature ref, int tag, Type type) { - this.fieldSignature = ref; - this.tag = tag; - this.methodSignature = null; + public MethodHandle( + @Nonnull SootClassMemberSignature referenceSignature, + @Nonnull MethodHandle.Kind kind, + @Nonnull Type type) { + this.kind = kind; this.type = type; + this.referenceSignature = referenceSignature; + if ((this.isMethodRef() && !(referenceSignature instanceof MethodSignature)) + || (this.isFieldRef() && !(referenceSignature instanceof FieldSignature))) { + throw new IllegalArgumentException( + "Kind:" + + kind.valStr + + " does not match with the given signature:" + + referenceSignature.getClass()); + } } - public static boolean isMethodRef(int kind) { - return kind == Kind.REF_INVOKE_VIRTUAL.getValue() - || kind == Kind.REF_INVOKE_STATIC.getValue() - || kind == Kind.REF_INVOKE_SPECIAL.getValue() - || kind == Kind.REF_INVOKE_CONSTRUCTOR.getValue() - || kind == Kind.REF_INVOKE_INTERFACE.getValue(); + public static boolean isMethodRef(int tag) { + return tag == Kind.REF_INVOKE_VIRTUAL.getValue() + || tag == Kind.REF_INVOKE_STATIC.getValue() + || tag == Kind.REF_INVOKE_SPECIAL.getValue() + || tag == Kind.REF_INVOKE_CONSTRUCTOR.getValue() + || tag == Kind.REF_INVOKE_INTERFACE.getValue(); + } + + public static boolean isFieldRef(int tag) { + return tag == Kind.REF_GET_FIELD.getValue() + || tag == Kind.REF_PUT_FIELD.getValue() + || tag == Kind.REF_PUT_FIELD_STATIC.getValue() + || tag == Kind.REF_GET_FIELD_STATIC.getValue(); + } + + public boolean isMethodRef() { + return MethodHandle.isMethodRef(this.kind.getValue()); + } + + public boolean isFieldRef() { + return MethodHandle.isFieldRef(this.kind.getValue()); } @Override - // FIXME: [ms] serialize in a way it can be restored with the same parameters; adapt Jimple.g4 and - // JimpleConverter.java public String toString() { - return "handle: " - + (methodSignature == null ? "" : methodSignature) - + (fieldSignature == null ? "" : fieldSignature); + return "methodhandle: \"" + kind.valStr + "\" " + referenceSignature; } @Nonnull @@ -121,8 +160,8 @@ public Type getType() { return type; } - public MethodSignature getMethodSignature() { - return methodSignature; + public SootClassMemberSignature getReferenceSignature() { + return referenceSignature; } @Override @@ -132,9 +171,9 @@ public void accept(@Nonnull ConstantVisitor v) { @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((methodSignature == null) ? 0 : methodSignature.hashCode()); + int result = type.hashCode(); + result = 31 * result + referenceSignature.hashCode(); + result = 31 * result + kind.hashCode(); return result; } @@ -150,10 +189,6 @@ public boolean equals(Object obj) { return false; } MethodHandle other = (MethodHandle) obj; - if (methodSignature == null) { - return other.methodSignature == null; - } else { - return methodSignature.equals(other.methodSignature); - } + return referenceSignature.equals(other.referenceSignature); } } diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java14/RecordTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java14/RecordTest.java index 154bd616084..c56e28548c9 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java14/RecordTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java14/RecordTest.java @@ -1,5 +1,8 @@ package sootup.java.bytecode.minimaltestsuite.java14; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import categories.Java9Test; import java.util.ArrayList; import java.util.Collections; @@ -8,10 +11,17 @@ import java.util.stream.Stream; import org.junit.Test; import org.junit.experimental.categories.Category; +import sootup.core.jimple.basic.Immediate; +import sootup.core.jimple.common.expr.JDynamicInvokeExpr; +import sootup.core.jimple.common.stmt.Stmt; import sootup.core.model.SootMethod; +import sootup.core.signatures.FieldSignature; import sootup.core.signatures.MethodSignature; +import sootup.core.signatures.PackageName; +import sootup.core.types.PrimitiveType; import sootup.java.bytecode.minimaltestsuite.MinimalBytecodeTestSuiteBase; import sootup.java.core.JavaIdentifierFactory; +import sootup.java.core.language.JavaJimple; import sootup.java.core.types.JavaClassType; /** @author Jonas Klauke */ @@ -38,7 +48,7 @@ public List expectedBodyStmts() { return Stream.of( "l0 := @this: RecordTest", "l1 := @parameter0: java.lang.Object", - "$stack2 = dynamicinvoke \"equals\" (l0, l1) (class \"LRecordTest;\", \"a;b\", handle: , handle: )", + "$stack2 = dynamicinvoke \"equals\" (l0, l1) (class \"LRecordTest;\", \"a;b\", methodhandle: \"REF_GET_FIELD\" , methodhandle: \"REF_GET_FIELD\" )", "return $stack2") .collect(Collectors.toCollection(ArrayList::new)); } @@ -47,5 +57,37 @@ public List expectedBodyStmts() { public void test() { SootMethod method = loadMethod(getMethodSignature()); assertJimpleStmts(method, expectedBodyStmts()); + List dynamicInvokes = + method.getBody().getStmts().stream() + .filter(Stmt::containsInvokeExpr) + .map(Stmt::getInvokeExpr) + .filter(abstractInvokeExpr -> abstractInvokeExpr instanceof JDynamicInvokeExpr) + .map(abstractInvokeExpr -> (JDynamicInvokeExpr) abstractInvokeExpr) + .collect(Collectors.toList()); + assertEquals(1, dynamicInvokes.size()); + JDynamicInvokeExpr invoke = dynamicInvokes.get(0); + + // test bootstrap args + List bootTrapArgs = invoke.getBootstrapArgs(); + assertTrue(bootTrapArgs.contains(JavaJimple.getInstance().newClassConstant("LRecordTest;"))); + assertTrue(bootTrapArgs.contains(JavaJimple.getInstance().newStringConstant("a;b"))); + assertTrue( + bootTrapArgs.contains( + JavaJimple.getInstance() + .newMethodHandle( + new FieldSignature( + new JavaClassType("RecordTest", new PackageName("")), + "a", + PrimitiveType.getInt()), + 1))); + assertTrue( + bootTrapArgs.contains( + JavaJimple.getInstance() + .newMethodHandle( + new FieldSignature( + new JavaClassType("RecordTest", new PackageName("")), + "b", + new JavaClassType("String", new PackageName("java.lang"))), + 1))); } } diff --git a/sootup.java.core/src/main/java/sootup/java/core/language/JavaJimple.java b/sootup.java.core/src/main/java/sootup/java/core/language/JavaJimple.java index 3ec7d04c4ca..5d238bf85b8 100644 --- a/sootup.java.core/src/main/java/sootup/java/core/language/JavaJimple.java +++ b/sootup.java.core/src/main/java/sootup/java/core/language/JavaJimple.java @@ -32,8 +32,8 @@ import sootup.core.jimple.common.constant.MethodType; import sootup.core.jimple.common.constant.StringConstant; import sootup.core.jimple.common.ref.JCaughtExceptionRef; -import sootup.core.signatures.FieldSignature; -import sootup.core.signatures.MethodSignature; +import sootup.core.signatures.SootClassMemberSignature; +import sootup.core.signatures.SootClassMemberSubSignature; import sootup.core.types.NullType; import sootup.core.types.PrimitiveType; import sootup.core.types.Type; @@ -86,14 +86,16 @@ public StringConstant newStringConstant(String value) { return new StringConstant(value, getIdentifierFactory().getType("java.lang.String")); } - public MethodHandle newMethodHandle(FieldSignature ref, int tag) { + public MethodHandle newMethodHandle( + SootClassMemberSignature ref, int tag) { return new MethodHandle( ref, tag, getIdentifierFactory().getType("java.lang.invoke.MethodHandle")); } - public MethodHandle newMethodHandle(MethodSignature ref, int tag) { + public MethodHandle newMethodHandle( + SootClassMemberSignature ref, MethodHandle.Kind kind) { return new MethodHandle( - ref, tag, getIdentifierFactory().getType("java.lang.invoke.MethodHandle")); + ref, kind, getIdentifierFactory().getType("java.lang.invoke.MethodHandle")); } public MethodType newMethodType(List parameterTypes, Type returnType) { diff --git a/sootup.jimple.parser/src/main/antlr4/sootup/jimple/Jimple.g4 b/sootup.jimple.parser/src/main/antlr4/sootup/jimple/Jimple.g4 index 31082f1cd23..ecfbf9debcb 100644 --- a/sootup.jimple.parser/src/main/antlr4/sootup/jimple/Jimple.g4 +++ b/sootup.jimple.parser/src/main/antlr4/sootup/jimple/Jimple.g4 @@ -280,6 +280,9 @@ grammar Jimple; /*local*/ local=identifier | /*constant*/ constant; + methodhandle: + 'methodhandle: ' STRING_CONSTANT (method_signature|field_signature); + constant : /*boolean*/ BOOL_CONSTANT | /*integer*/ integer_constant | @@ -287,7 +290,7 @@ grammar Jimple; /*string*/ STRING_CONSTANT | /*clazz*/ CLASS STRING_CONSTANT | /*null*/ NULL | - methodhandle='handle:' method_signature | + methodhandle | methodtype='methodtype:' method_subsignature ; binop : diff --git a/sootup.jimple.parser/src/main/java/sootup/jimple/parser/JimpleConverter.java b/sootup.jimple.parser/src/main/java/sootup/jimple/parser/JimpleConverter.java index 6dda6e812b3..66334b3caf0 100644 --- a/sootup.jimple.parser/src/main/java/sootup/jimple/parser/JimpleConverter.java +++ b/sootup.jimple.parser/src/main/java/sootup/jimple/parser/JimpleConverter.java @@ -23,6 +23,8 @@ import sootup.core.model.*; import sootup.core.signatures.FieldSignature; import sootup.core.signatures.MethodSignature; +import sootup.core.signatures.SootClassMemberSignature; +import sootup.core.signatures.SootClassMemberSubSignature; import sootup.core.transform.BodyInterceptor; import sootup.core.types.*; import sootup.java.core.JavaIdentifierFactory; @@ -696,13 +698,19 @@ public Constant visitConstant(JimpleParser.ConstantContext ctx) { return BooleanConstant.getInstance(firstChar == 't' || firstChar == 'T'); } else if (ctx.NULL() != null) { return NullConstant.getInstance(); - } else if (ctx.methodhandle != null && ctx.method_signature() != null) { - final MethodSignature methodSignature = - util.getMethodSignature(ctx.method_signature(), ctx); - // TODO: [ms] support handles with JFieldRef too - // FIXME: [ms] update/specify tag when its printed - // return JavaJimple.getInstance().newMethodHandle( , 0); - return JavaJimple.getInstance().newMethodHandle(methodSignature, 0); + } else if (ctx.methodhandle() != null) { + JimpleParser.MethodhandleContext methodhandleContext = ctx.methodhandle(); + final String kindName = methodhandleContext.STRING_CONSTANT().getText(); + final SootClassMemberSignature + referenceSignature = + (methodhandleContext.method_signature() != null) + ? util.getMethodSignature( + methodhandleContext.method_signature(), methodhandleContext) + : util.getFieldSignature(methodhandleContext.field_signature()); + return JavaJimple.getInstance() + .newMethodHandle( + referenceSignature, + MethodHandle.Kind.getKind(kindName.substring(1, kindName.length() - 1))); } else if (ctx.methodtype != null && ctx.method_subsignature() != null) { final JimpleParser.Type_listContext typelist = ctx.method_subsignature().type_list(); final List typeList = util.getTypeList(typelist); diff --git a/sootup.jimple.parser/src/test/java/resources/jimple/MethodAcceptingLamExpr.jimple b/sootup.jimple.parser/src/test/java/resources/jimple/MethodAcceptingLamExpr.jimple index edace00f545..e2c37e9db00 100644 --- a/sootup.jimple.parser/src/test/java/resources/jimple/MethodAcceptingLamExpr.jimple +++ b/sootup.jimple.parser/src/test/java/resources/jimple/MethodAcceptingLamExpr.jimple @@ -19,7 +19,7 @@ public super class MethodAcceptingLamExpr extends java.lang.Object l0 := @this: MethodAcceptingLamExpr; - $stack2 = dynamicinvoke "calcPercentage" () (methodtype: double __METHODTYPE__(double), handle: , methodtype: double __METHODTYPE__(double)); + $stack2 = dynamicinvoke "calcPercentage" () (methodtype: double __METHODTYPE__(double), methodhandle: "REF_INVOKE_STATIC" , methodtype: double __METHODTYPE__(double)); l1 = $stack2; diff --git a/sootup.jimple.parser/src/test/java/resources/jimple/MethodReference.jimple b/sootup.jimple.parser/src/test/java/resources/jimple/MethodReference.jimple index e433a96e522..33aeb4fc0ff 100644 --- a/sootup.jimple.parser/src/test/java/resources/jimple/MethodReference.jimple +++ b/sootup.jimple.parser/src/test/java/resources/jimple/MethodReference.jimple @@ -41,7 +41,7 @@ public super class MethodReference extends java.lang.Object $stack4 = staticinvoke (l1); - $stack5 = dynamicinvoke "display" (l1) (methodtype: void __METHODTYPE__(), handle: , methodtype: void __METHODTYPE__()); + $stack5 = dynamicinvoke "display" (l1) (methodtype: void __METHODTYPE__(), methodhandle: "REF_INVOKE_VIRTUAL" , methodtype: void __METHODTYPE__()); l2 = $stack5; diff --git a/sootup.jimple.parser/src/test/java/sootup/jimple/parser/javatestsuite/java8/MethodAcceptingLamExprTest.java b/sootup.jimple.parser/src/test/java/sootup/jimple/parser/javatestsuite/java8/MethodAcceptingLamExprTest.java index 3710d168925..fd4e0f5269d 100644 --- a/sootup.jimple.parser/src/test/java/sootup/jimple/parser/javatestsuite/java8/MethodAcceptingLamExprTest.java +++ b/sootup.jimple.parser/src/test/java/sootup/jimple/parser/javatestsuite/java8/MethodAcceptingLamExprTest.java @@ -30,7 +30,7 @@ public void test() { public List expectedBodyStmts() { return Stream.of( "l0 := @this: MethodAcceptingLamExpr", - "$stack2 = dynamicinvoke \"calcPercentage\" () (methodtype: double __METHODTYPE__(double), handle: , methodtype: double __METHODTYPE__(double))", + "$stack2 = dynamicinvoke \"calcPercentage\" () (methodtype: double __METHODTYPE__(double), methodhandle: \"REF_INVOKE_STATIC\" , methodtype: double __METHODTYPE__(double))", "l1 = $stack2", "$stack4 = ", "$stack3 = new java.lang.StringBuilder", From 859304efe89dd3541453fb0f17646605cff50cd2 Mon Sep 17 00:00:00 2001 From: Jonas Klauke Date: Mon, 14 Aug 2023 18:29:39 +0200 Subject: [PATCH 06/16] Adapted bytecode testcases to new methodhandle serialization --- .../minimaltestsuite/java11/TypeInferenceLambdaTest.java | 2 +- .../minimaltestsuite/java8/MethodAcceptingLamExprTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java11/TypeInferenceLambdaTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java11/TypeInferenceLambdaTest.java index f640bfc4714..454822e66e8 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java11/TypeInferenceLambdaTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java11/TypeInferenceLambdaTest.java @@ -33,7 +33,7 @@ public MethodSignature getMethodSignature() { public List expectedBodyStmts() { return Stream.of( "l0 := @this: TypeInferenceLambda", - "l1 = dynamicinvoke \"apply\" () (methodtype: java.lang.Object __METHODTYPE__(java.lang.Object,java.lang.Object), handle: , methodtype: java.lang.Integer __METHODTYPE__(java.lang.Integer,java.lang.Integer))", + "l1 = dynamicinvoke \"apply\" () (methodtype: java.lang.Object __METHODTYPE__(java.lang.Object,java.lang.Object), methodhandle: \"REF_INVOKE_STATIC\" , methodtype: java.lang.Integer __METHODTYPE__(java.lang.Integer,java.lang.Integer))", "$stack4 = staticinvoke (2)", "$stack3 = staticinvoke (3)", "$stack5 = interfaceinvoke l1.($stack4, $stack3)", diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java8/MethodAcceptingLamExprTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java8/MethodAcceptingLamExprTest.java index 9042cd14b7d..7901fb7612d 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java8/MethodAcceptingLamExprTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java8/MethodAcceptingLamExprTest.java @@ -43,7 +43,7 @@ public void test() { public List expectedBodyStmts() { return Stream.of( "l0 := @this: MethodAcceptingLamExpr", - "l1 = dynamicinvoke \"calcPercentage\" () (methodtype: double __METHODTYPE__(double), handle: , methodtype: double __METHODTYPE__(double))", + "l1 = dynamicinvoke \"calcPercentage\" () (methodtype: double __METHODTYPE__(double), methodhandle: \"REF_INVOKE_STATIC\" , methodtype: double __METHODTYPE__(double))", "$stack3 = ", "$stack2 = new java.lang.StringBuilder", "specialinvoke $stack2.()>()", From d13cc919a98e9f5be31b31546f3ede075cabfadf Mon Sep 17 00:00:00 2001 From: Markus Schmidt Date: Mon, 14 Aug 2023 22:42:50 +0200 Subject: [PATCH 07/16] fix annotations --- .../src/test/java/sootup/java/bytecode/Soot1577.java | 7 ++++++- .../src/test/java/sootup/java/bytecode/Soot1580.java | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/Soot1577.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/Soot1577.java index 5e76875a2fa..56bb29a92d2 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/Soot1577.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/Soot1577.java @@ -1,7 +1,10 @@ package sootup.java.bytecode; +import categories.Java8Test; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; +import org.junit.experimental.categories.Category; import sootup.core.inputlocation.AnalysisInputLocation; import sootup.core.model.SootMethod; import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation; @@ -10,16 +13,18 @@ import sootup.java.core.language.JavaLanguage; import sootup.java.core.views.JavaView; +@Category(Java8Test.class) public class Soot1577 { final String directory = "../shared-test-resources/soot-1577/"; @Test + @Ignore("conversion fails - could be a dex2jar conversion problem") public void test() { AnalysisInputLocation inputLocation = new JavaClassPathAnalysisInputLocation(directory); JavaProject project = - JavaProject.builder(new JavaLanguage(7)).addInputLocation(inputLocation).build(); + JavaProject.builder(new JavaLanguage(8)).addInputLocation(inputLocation).build(); JavaView view = project.createView(); diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/Soot1580.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/Soot1580.java index 9cecd0aa910..0d5555d72ec 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/Soot1580.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/Soot1580.java @@ -1,9 +1,11 @@ package sootup.java.bytecode; +import categories.Java8Test; import java.nio.file.Path; import java.nio.file.Paths; import org.junit.Assert; import org.junit.Test; +import org.junit.experimental.categories.Category; import sootup.core.inputlocation.AnalysisInputLocation; import sootup.core.model.SootMethod; import sootup.core.types.ClassType; @@ -15,6 +17,7 @@ import sootup.java.core.language.JavaLanguage; import sootup.java.core.views.JavaView; +@Category(Java8Test.class) public class Soot1580 { final Path jar = Paths.get("../shared-test-resources/soot-1580/jpush-android_v3.0.5.jar"); From 03b20238b96fafa5b7f4c09a2ec6583239165e4f Mon Sep 17 00:00:00 2001 From: Markus Schmidt Date: Mon, 14 Aug 2023 22:44:20 +0200 Subject: [PATCH 08/16] add proposed indy testcase - rhs is null --- shared-test-resources/bugfixes/Indy.java | 15 ++++++++++ .../core/jimple/common/stmt/JAssignStmt.java | 4 ++- .../java/sootup/java/bytecode/IndyTests.java | 30 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 shared-test-resources/bugfixes/Indy.java create mode 100644 sootup.java.bytecode/src/test/java/sootup/java/bytecode/IndyTests.java diff --git a/shared-test-resources/bugfixes/Indy.java b/shared-test-resources/bugfixes/Indy.java new file mode 100644 index 00000000000..800203ab873 --- /dev/null +++ b/shared-test-resources/bugfixes/Indy.java @@ -0,0 +1,15 @@ +import java.time.LocalDate; +import java.time.Period; +import java.util.stream.LongStream; +import java.util.stream.Stream; +class Indy{ + public Stream test(LocalDate endExclusive, Period step) { + long months = step.toTotalMonths(); + long days = step.getDays(); + int sign = months > 0 || days > 0 ? 1 : -1; + long steps = 200000 / (months + days); + return LongStream.rangeClosed(0, steps).mapToObj( + n -> endExclusive.plusDays(days * n)); + } + +} \ No newline at end of file diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/stmt/JAssignStmt.java b/sootup.core/src/main/java/sootup/core/jimple/common/stmt/JAssignStmt.java index 389f13edb12..01e871d4abe 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/stmt/JAssignStmt.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/stmt/JAssignStmt.java @@ -53,7 +53,9 @@ public JAssignStmt( } if (!validateValue(rValue)) { throw new RuntimeException( - "Illegal Assignment statement. Make sure that right hand side has a valid operand."); + "Illegal Assignment statement. Make sure that right hand side (" + + rValue + + ") has a valid operand."); } } diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/IndyTests.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/IndyTests.java new file mode 100644 index 00000000000..f1ced45cb93 --- /dev/null +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/IndyTests.java @@ -0,0 +1,30 @@ +package sootup.java.bytecode; + +import org.junit.Assert; +import org.junit.Test; +import sootup.core.inputlocation.AnalysisInputLocation; +import sootup.core.model.SootMethod; +import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation; +import sootup.java.core.JavaProject; +import sootup.java.core.JavaSootClass; +import sootup.java.core.language.JavaLanguage; +import sootup.java.core.views.JavaView; + +/** InvokeDynamics and the Operand stack.. */ +public class IndyTests { + final String directory = "../shared-test-resources/misc/"; + + @Test + public void test() { + AnalysisInputLocation inputLocation = + new JavaClassPathAnalysisInputLocation(directory); + + JavaProject project = + JavaProject.builder(new JavaLanguage(8)).addInputLocation(inputLocation).build(); + + JavaView view = project.createView(); + Assert.assertEquals(1, view.getClasses().size()); + + view.getClasses().stream().findFirst().get().getMethods().forEach(SootMethod::getBody); + } +} From 6bf2fb7ae0dc0d936c6075c03164347b8cd058d2 Mon Sep 17 00:00:00 2001 From: Markus Schmidt Date: Mon, 14 Aug 2023 22:54:44 +0200 Subject: [PATCH 09/16] fix errmsg and directory --- .../main/java/sootup/core/jimple/common/stmt/JAssignStmt.java | 2 +- .../src/test/java/sootup/java/bytecode/IndyTests.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/stmt/JAssignStmt.java b/sootup.core/src/main/java/sootup/core/jimple/common/stmt/JAssignStmt.java index 01e871d4abe..865223653cb 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/stmt/JAssignStmt.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/stmt/JAssignStmt.java @@ -55,7 +55,7 @@ public JAssignStmt( throw new RuntimeException( "Illegal Assignment statement. Make sure that right hand side (" + rValue - + ") has a valid operand."); + + ") is a valid operand."); } } diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/IndyTests.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/IndyTests.java index f1ced45cb93..45fb8cd0e82 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/IndyTests.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/IndyTests.java @@ -12,7 +12,7 @@ /** InvokeDynamics and the Operand stack.. */ public class IndyTests { - final String directory = "../shared-test-resources/misc/"; + final String directory = "../shared-test-resources/bugfixes/"; @Test public void test() { From 1472cb74ea15fdd5e7b00888a6a52c9863486fdb Mon Sep 17 00:00:00 2001 From: Markus Schmidt Date: Tue, 15 Aug 2023 09:24:10 +0200 Subject: [PATCH 10/16] add missing annotation --- .../src/test/java/sootup/java/bytecode/IndyTests.java | 3 +++ .../minimaltestsuite/java14/SwitchExprWithYieldTest.java | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/IndyTests.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/IndyTests.java index 45fb8cd0e82..c0cc8ba5e63 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/IndyTests.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/IndyTests.java @@ -1,7 +1,9 @@ package sootup.java.bytecode; +import categories.Java9Test; import org.junit.Assert; import org.junit.Test; +import org.junit.experimental.categories.Category; import sootup.core.inputlocation.AnalysisInputLocation; import sootup.core.model.SootMethod; import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation; @@ -11,6 +13,7 @@ import sootup.java.core.views.JavaView; /** InvokeDynamics and the Operand stack.. */ +@Category(Java9Test.class) public class IndyTests { final String directory = "../shared-test-resources/bugfixes/"; diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java14/SwitchExprWithYieldTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java14/SwitchExprWithYieldTest.java index a0c7f2a48fe..f03a07a699a 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java14/SwitchExprWithYieldTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java14/SwitchExprWithYieldTest.java @@ -25,7 +25,6 @@ public JavaClassType getDeclaredClassSignature() { @Override public MethodSignature getMethodSignature() { - System.out.println(getDeclaredClassSignature()); return identifierFactory.getMethodSignature( getDeclaredClassSignature(), "switchSomething", "void", Collections.emptyList()); } From c4297293b00bd642a8f4fa627c19456c83937ce0 Mon Sep 17 00:00:00 2001 From: Markus Schmidt Date: Tue, 15 Aug 2023 10:27:28 +0200 Subject: [PATCH 11/16] simplified test input; add missing .class --- shared-test-resources/bugfixes/Indy.class | Bin 0 -> 1064 bytes shared-test-resources/bugfixes/Indy.java | 18 +++++++++--------- 2 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 shared-test-resources/bugfixes/Indy.class diff --git a/shared-test-resources/bugfixes/Indy.class b/shared-test-resources/bugfixes/Indy.class new file mode 100644 index 0000000000000000000000000000000000000000..1b83ecee8411bf2eeb26e8c39f3437f23313f6e7 GIT binary patch literal 1064 zcmbVL%Wl&^6g?A%m^cmzg#rzvKuKvHPy@>bkRTEwQc96hy6B2YGA(YLv1N}d<7hFp;%!0Xc^95kKaR$K|23 zGdL1M#gKdIN>@E+FzSuH0xlwN!m?3-%}`0)W952Iq(Z?bPFJdaA~9HQ^p=O*^MscK z?=KPMB^xD_$;gAio4$z1pJAik=$#=Q#B!)yUuvv(l84isK!jZRVOz5=*|>tM1UTUV zL#O^vfob?Z6K$Kg#*ppG(Ud+NekQVv}M0T$BD*uL+vT>S9+~k6CkYhZr;TzyX5}EfW~7lT@WI)0*a2urDMq z+@M>VXZH#!Bx~0#0?-i4trM6GA7QjkQ3OtKIfKt+$Rwe9Wuf00MF rRdPruE9K_(*BJjTi|FGdj} literal 0 HcmV?d00001 diff --git a/shared-test-resources/bugfixes/Indy.java b/shared-test-resources/bugfixes/Indy.java index 800203ab873..2143e237efe 100644 --- a/shared-test-resources/bugfixes/Indy.java +++ b/shared-test-resources/bugfixes/Indy.java @@ -1,15 +1,15 @@ import java.time.LocalDate; import java.time.Period; -import java.util.stream.LongStream; import java.util.stream.Stream; +import java.util.stream.IntStream; + +/** conversion failed when there is a merge (here: after the if) and an invokedynamic followed */ class Indy{ - public Stream test(LocalDate endExclusive, Period step) { - long months = step.toTotalMonths(); - long days = step.getDays(); - int sign = months > 0 || days > 0 ? 1 : -1; - long steps = 200000 / (months + days); - return LongStream.rangeClosed(0, steps).mapToObj( - n -> endExclusive.plusDays(days * n)); + public IntStream test(IntStream s) { + int sign; + if (s.isParallel()) { + sign = 1; + } + return s.map(n -> n+42); } - } \ No newline at end of file From bc74bf541c3797656d5e75dc77b6dd5248357ece Mon Sep 17 00:00:00 2001 From: Markus Schmidt Date: Tue, 15 Aug 2023 10:36:20 +0200 Subject: [PATCH 12/16] that input was too simple.. --- shared-test-resources/bugfixes/Indy.class | Bin 1064 -> 1083 bytes shared-test-resources/bugfixes/Indy.java | 2 ++ 2 files changed, 2 insertions(+) diff --git a/shared-test-resources/bugfixes/Indy.class b/shared-test-resources/bugfixes/Indy.class index 1b83ecee8411bf2eeb26e8c39f3437f23313f6e7..4e5ccd49f98348a241eed9f6fb7e62fc4b6d4c33 100644 GIT binary patch delta 110 zcmWN`y%B;?5Jlm$`*7X^Mow1inHy84KK`uXk57IIPBbE$7b4T?dda8Dz5Ws5 B4hjGO delta 75 zcmdnZv4Uem2eSej10#bZgA|YyXJBBkVqgM71_n{>oeb=Z3^N&+C$DD~72yI4axic* Ya5G2)rI{HRIVV41)?(zI%+I0&0CvC$JOBUy diff --git a/shared-test-resources/bugfixes/Indy.java b/shared-test-resources/bugfixes/Indy.java index 2143e237efe..98441621cd4 100644 --- a/shared-test-resources/bugfixes/Indy.java +++ b/shared-test-resources/bugfixes/Indy.java @@ -9,6 +9,8 @@ public IntStream test(IntStream s) { int sign; if (s.isParallel()) { sign = 1; + }else{ + sign = -1; } return s.map(n -> n+42); } From 7047cdfa09c0031d379ecf3a55ceccd5dca065a6 Mon Sep 17 00:00:00 2001 From: Jonas Klauke Date: Fri, 15 Sep 2023 18:45:36 +0200 Subject: [PATCH 13/16] fixed that nrArgs can be -1 if the while condition is false but the -- instruction is still performed --- .../java/sootup/java/bytecode/frontend/AsmMethodSource.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java index 5b43a1771a1..a7ba0680728 100644 --- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java +++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java @@ -1394,7 +1394,8 @@ private void convertInvokeDynamicInsn(@Nonnull InvokeDynamicInsnNode insn) { oprs = new Operand[nrArgs + 1]; } if (oprs != null) { - while (nrArgs-- > 0) { + while (nrArgs > 0) { + nrArgs--; oprs[nrArgs] = operandStack.pop(types.get(nrArgs)); } if (!isStaticInvokeExpr) { From ee41bafa92304eb345dc52bb17ae410cd4d40dd4 Mon Sep 17 00:00:00 2001 From: Jonas Klauke Date: Mon, 16 Oct 2023 18:31:07 +0200 Subject: [PATCH 14/16] removed static invoke handling caused by wrongly adaption of soot code for SootUp. SootUp does not model lambda expressions as static method calls. --- .../java/bytecode/frontend/AsmMethodSource.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java index a7ba0680728..857b4d21349 100644 --- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java +++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java @@ -73,7 +73,6 @@ import sootup.core.jimple.common.expr.JInstanceOfExpr; import sootup.core.jimple.common.expr.JNewArrayExpr; import sootup.core.jimple.common.expr.JNewMultiArrayExpr; -import sootup.core.jimple.common.expr.JStaticInvokeExpr; import sootup.core.jimple.common.ref.*; import sootup.core.jimple.common.stmt.*; import sootup.core.jimple.javabytecode.stmt.JSwitchStmt; @@ -1387,20 +1386,12 @@ private void convertInvokeDynamicInsn(@Nonnull InvokeDynamicInsnNode insn) { List types = expr.getMethodSignature().getParameterTypes(); Operand[] oprs; int nrArgs = types.size(); - final boolean isStaticInvokeExpr = expr instanceof JStaticInvokeExpr; - if (isStaticInvokeExpr) { - oprs = (nrArgs == 0) ? null : new Operand[nrArgs]; - } else { - oprs = new Operand[nrArgs + 1]; - } + oprs = (nrArgs == 0) ? null : new Operand[nrArgs]; if (oprs != null) { while (nrArgs > 0) { nrArgs--; oprs[nrArgs] = operandStack.pop(types.get(nrArgs)); } - if (!isStaticInvokeExpr) { - oprs[oprs.length - 1] = operandStack.pop(); - } frame.mergeIn(currentLineNumber, oprs); } returnType = expr.getType(); From 884c62820ba90381069176975b5dfba68333c975 Mon Sep 17 00:00:00 2001 From: Jonas Klauke Date: Tue, 17 Oct 2023 17:48:24 +0200 Subject: [PATCH 15/16] removed unnecessary constructor in MethodHandle --- .../core/jimple/common/constant/MethodHandle.java | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/constant/MethodHandle.java b/sootup.core/src/main/java/sootup/core/jimple/common/constant/MethodHandle.java index fd1792c29e4..f26729b0a8c 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/constant/MethodHandle.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/constant/MethodHandle.java @@ -94,19 +94,7 @@ public MethodHandle( @Nonnull SootClassMemberSignature referenceSignature, int tag, @Nonnull Type type) { - this.kind = Kind.getKind(tag); - this.type = type; - this.referenceSignature = referenceSignature; - if ((this.isMethodRef() && !(referenceSignature instanceof MethodSignature)) - || (this.isFieldRef() && !(referenceSignature instanceof FieldSignature))) { - throw new IllegalArgumentException( - "Tag:" - + tag - + " " - + kind.valStr - + " does not match with the given signature:" - + referenceSignature.getClass()); - } + this(referenceSignature, Kind.getKind(tag), type); } public MethodHandle( From 1ed3ab1a3266190027c42bbd59b6495b0a3fda9f Mon Sep 17 00:00:00 2001 From: Jonas Klauke Date: Tue, 17 Oct 2023 17:48:40 +0200 Subject: [PATCH 16/16] added tests for MethodHandle --- .../jimple/common/constant/MethodHandle.java | 4 + .../common/constant/MethodHandleTest.java | 114 ++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 sootup.core/src/test/java/sootup/core/jimple/common/constant/MethodHandleTest.java diff --git a/sootup.core/src/main/java/sootup/core/jimple/common/constant/MethodHandle.java b/sootup.core/src/main/java/sootup/core/jimple/common/constant/MethodHandle.java index f26729b0a8c..8c02e3246f8 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/common/constant/MethodHandle.java +++ b/sootup.core/src/main/java/sootup/core/jimple/common/constant/MethodHandle.java @@ -148,6 +148,10 @@ public Type getType() { return type; } + public Kind getKind() { + return kind; + } + public SootClassMemberSignature getReferenceSignature() { return referenceSignature; } diff --git a/sootup.core/src/test/java/sootup/core/jimple/common/constant/MethodHandleTest.java b/sootup.core/src/test/java/sootup/core/jimple/common/constant/MethodHandleTest.java new file mode 100644 index 00000000000..e6db3b602dd --- /dev/null +++ b/sootup.core/src/test/java/sootup/core/jimple/common/constant/MethodHandleTest.java @@ -0,0 +1,114 @@ +package sootup.core.jimple.common.constant; + +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertThrows; + +import categories.Java8Test; +import java.util.Collections; +import junit.framework.TestCase; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import sootup.core.jimple.common.constant.MethodHandle.Kind; +import sootup.core.signatures.FieldSignature; +import sootup.core.signatures.MethodSignature; +import sootup.core.signatures.PackageName; +import sootup.core.types.ClassType; +import sootup.core.types.PrimitiveType.IntType; +import sootup.core.types.VoidType; + +@Category(Java8Test.class) +public class MethodHandleTest extends TestCase { + + @Test + public void testMethodHandle() { + assertEquals(Kind.REF_GET_FIELD.toString(), "REF_GET_FIELD"); + assertEquals(Kind.REF_GET_FIELD.getValueName(), "REF_GET_FIELD"); + assertEquals(Kind.REF_GET_FIELD.getValue(), 1); + + for (Kind currentKind : Kind.values()) { + assertEquals(currentKind, Kind.getKind(currentKind.getValueName())); + assertEquals(currentKind, Kind.getKind(currentKind.getValue())); + } + // not valid kinds + assertThrows(RuntimeException.class, () -> Kind.getKind(0)); + assertThrows(RuntimeException.class, () -> Kind.getKind("invalid")); + + assertTrue(MethodHandle.isMethodRef(Kind.REF_INVOKE_VIRTUAL.getValue())); + assertTrue(MethodHandle.isMethodRef(Kind.REF_INVOKE_STATIC.getValue())); + assertTrue(MethodHandle.isMethodRef(Kind.REF_INVOKE_SPECIAL.getValue())); + assertTrue(MethodHandle.isMethodRef(Kind.REF_INVOKE_CONSTRUCTOR.getValue())); + assertTrue(MethodHandle.isMethodRef(Kind.REF_INVOKE_INTERFACE.getValue())); + assertFalse(MethodHandle.isMethodRef(Kind.REF_GET_FIELD.getValue())); + assertFalse(MethodHandle.isMethodRef(Kind.REF_PUT_FIELD.getValue())); + assertFalse(MethodHandle.isMethodRef(Kind.REF_PUT_FIELD_STATIC.getValue())); + assertFalse(MethodHandle.isMethodRef(Kind.REF_GET_FIELD_STATIC.getValue())); + + assertFalse(MethodHandle.isFieldRef(Kind.REF_INVOKE_VIRTUAL.getValue())); + assertFalse(MethodHandle.isFieldRef(Kind.REF_INVOKE_STATIC.getValue())); + assertFalse(MethodHandle.isFieldRef(Kind.REF_INVOKE_SPECIAL.getValue())); + assertFalse(MethodHandle.isFieldRef(Kind.REF_INVOKE_CONSTRUCTOR.getValue())); + assertFalse(MethodHandle.isFieldRef(Kind.REF_INVOKE_INTERFACE.getValue())); + assertTrue(MethodHandle.isFieldRef(Kind.REF_GET_FIELD.getValue())); + assertTrue(MethodHandle.isFieldRef(Kind.REF_PUT_FIELD.getValue())); + assertTrue(MethodHandle.isFieldRef(Kind.REF_PUT_FIELD_STATIC.getValue())); + assertTrue(MethodHandle.isFieldRef(Kind.REF_GET_FIELD_STATIC.getValue())); + + ClassType classType = + new ClassType() { + @Override + public boolean isBuiltInClass() { + return false; + } + + @Override + public String getFullyQualifiedName() { + return "test.A"; + } + + @Override + public String getClassName() { + return "A"; + } + + @Override + public PackageName getPackageName() { + return new PackageName("test"); + } + }; + MethodSignature ms = + new MethodSignature(classType, "m1", Collections.emptyList(), VoidType.getInstance()); + FieldSignature fs = new FieldSignature(classType, "f", IntType.getInstance()); + + MethodHandle mhms = new MethodHandle(ms, Kind.REF_INVOKE_VIRTUAL.getValue(), classType); + MethodHandle mhfs = new MethodHandle(fs, Kind.REF_GET_FIELD, classType); + + // not valid Method handles + assertThrows( + IllegalArgumentException.class, + () -> new MethodHandle(fs, Kind.REF_INVOKE_CONSTRUCTOR, classType)); + assertThrows( + IllegalArgumentException.class, () -> new MethodHandle(ms, Kind.REF_GET_FIELD, classType)); + + assertTrue(mhms.isMethodRef()); + assertFalse(mhms.isFieldRef()); + + assertFalse(mhfs.isMethodRef()); + assertTrue(mhfs.isFieldRef()); + + assertEquals(mhfs.getType(), classType); + assertEquals( + mhfs.toString(), + "methodhandle: \"" + mhfs.getKind() + "\" " + mhfs.getReferenceSignature()); + + MethodHandle mhms2 = new MethodHandle(ms, Kind.REF_INVOKE_VIRTUAL.getValue(), classType); + assertTrue(mhfs.equals(mhfs)); + assertFalse(mhfs.equals(mhms)); + assertFalse(mhfs.equals(null)); + assertFalse(mhfs.equals(classType)); + assertFalse(mhfs.equals(mhms2)); + + assertEquals(mhfs.hashCode(), mhfs.hashCode()); + assertEquals(mhms.hashCode(), mhms2.hashCode()); + assertNotEquals(mhfs.hashCode(), mhms.hashCode()); + } +}