From 9275f0e079e325678bd40e1ad14405558398d313 Mon Sep 17 00:00:00 2001 From: Falk Howar <falk.howar@gmail.com> Date: Wed, 13 Sep 2023 21:33:03 +0200 Subject: [PATCH 1/8] remove string models, springboot examples work --- .../com/oracle/truffle/espresso/nodes/BytecodeNode.java | 9 +++++---- .../espresso/substitutions/Target_java_lang_String.java | 2 +- .../substitutions/Target_java_lang_StringBuffer.java | 5 +++-- .../substitutions/Target_java_lang_StringBuilder.java | 5 +++-- .../espresso/substitutions/Target_java_net_Socket.java | 2 +- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java index 8295b5c7982e..ef28557145f2 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java @@ -2136,11 +2136,12 @@ private void putPoolConstant(VirtualFrame frame, int top, char cpi, int opcode) } else if (constant instanceof StringConstant) { assert opcode == LDC || opcode == LDC_W; StaticObject internedString = pool.resolvedStringAt(cpi); - Meta meta = getMeta(); - StaticObject obj = meta.toGuestString(meta.toHostString(internedString)); - SPouT.markObjectWithIFTaint(obj); + // todo: if we do this as we did below then springboot will fail to start with IncompleteAnnotation exceptions + //Meta meta = getMeta(); + //StaticObject obj = meta.toGuestString(meta.toHostString(internedString)); + //SPouT.markObjectWithIFTaint(obj); //TODO: (annotate string and maybe clone?) - putObject(frame, top, obj); + putObject(frame, top, internedString); } else if (constant instanceof ClassConstant) { assert opcode == LDC || opcode == LDC_W; Klass klass = pool.resolvedKlassAt(getDeclaringKlass(), cpi); diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java index c7f143f40715..fe5e9c393d37 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java @@ -8,7 +8,7 @@ import java.util.Locale; -@EspressoSubstitutions +//@EspressoSubstitutions public final class Target_java_lang_String { @Substitution(hasReceiver = true) public static @JavaType(internalName = "Z") Object contains(@JavaType(String.class) StaticObject self, diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java index e2c3baa75e44..3404607d2234 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java @@ -5,7 +5,7 @@ import com.oracle.truffle.espresso.runtime.StaticObject; import tools.aqua.spout.SPouT; -@EspressoSubstitutions +//@EspressoSubstitutions public final class Target_java_lang_StringBuffer { @@ -13,7 +13,8 @@ public final class Target_java_lang_StringBuffer { * If we do not intercept the constructor, we get side effects from the length comparison in the trace that are * irrelevant for the symbolic encoding. */ - @Substitution(hasReceiver = true, methodName = "<init>") + //todo: leads to segfault when starting springboot + //@Substitution(hasReceiver = true, methodName = "<init>") public static void init_string( @JavaType(StringBuilder.class) StaticObject self, @JavaType(String.class) StaticObject other, diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java index 94a3e1c5edd2..a95ee2bb558c 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java @@ -5,7 +5,7 @@ import tools.aqua.spout.AnnotatedValue; import tools.aqua.spout.SPouT; -@EspressoSubstitutions +//@EspressoSubstitutions public final class Target_java_lang_StringBuilder { @@ -13,7 +13,8 @@ public final class Target_java_lang_StringBuilder { * If we do not intercept the constructor, we get side effects from the length comparison in the trace that are * irrelevant for the symbolic encoding. */ - @Substitution(hasReceiver = true, methodName = "<init>") + //todo: leads to segfault when starting springboot + //@Substitution(hasReceiver = true, methodName = "<init>") public static void init_string( @JavaType(StringBuilder.class) StaticObject self, @JavaType(String.class) StaticObject other, diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_net_Socket.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_net_Socket.java index 6f40ea123325..bfcd06f1f069 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_net_Socket.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_net_Socket.java @@ -5,7 +5,7 @@ @EspressoSubstitutions public final class Target_java_net_Socket { - @Substitution(methodName = "<init>") + //@Substitution(methodName = "<init>") public static void __init(@JavaType(String.class) Object server, @JavaType(internalName = "I") Object port, @Inject Meta meta) { SPouT.stopRecording("Networking not supported yet.", meta); } From 1c4f056cdcda12fc1b2954fbbbe037ca17148198 Mon Sep 17 00:00:00 2001 From: Falk Howar <falk.howar@gmail.com> Date: Tue, 3 Oct 2023 19:17:34 +0200 Subject: [PATCH 2/8] fix imoplementation of String.equals() --- .../truffle/espresso/descriptors/Symbol.java | 2 + .../oracle/truffle/espresso/meta/Meta.java | 2 + .../Target_java_lang_String.java | 2 +- .../Target_java_lang_StringBuffer.java | 2 +- .../Target_java_lang_StringBuilder.java | 2 +- .../src/tools/aqua/spout/SPouT.java | 54 ++++++++++++++----- 6 files changed, 49 insertions(+), 15 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java index 2d55af44fea8..373424cdf4c8 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java @@ -1117,6 +1117,8 @@ public static void ensureInitialized() { public static final Symbol<Signature> String_byte_array_int_int = StaticSymbols.putSignature(Type.java_lang_String, Type._byte_array, Type._int, Type._int); + public static final Symbol<Signature> _boolean_byte_array_byte_array = StaticSymbols.putSignature(Type._boolean, Type._byte_array, Type._byte_array); + public static final Symbol<Signature> _void_int_int_char_array_int = StaticSymbols.putSignature(Type._void, Type._int, Type._int, Type._char_array, Type._int); } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java index 5d88847061ae..6d52dc494f3f 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java @@ -838,6 +838,7 @@ public Meta(EspressoContext context) { java_lang_StringLatin1 = knownKlass(Type.java_lang_StringLatin1); java_lang_StringLatin1_newString = java_lang_StringLatin1.lookupMethod(getNames().getOrCreate("newString"), Signature.String_byte_array_int_int); + java_lang_StringLatin1_equals = java_lang_StringLatin1.lookupMethod(getNames().getOrCreate("equals"), Signature._boolean_byte_array_byte_array); java_lang_StringUTF16 = knownKlass(Type.java_lang_StringUTF16); java_lang_StringUTF16_newString = java_lang_StringUTF16.lookupMethod(getNames().getOrCreate("newString"), Signature.String_byte_array_int_int); @@ -1454,6 +1455,7 @@ private DiffVersionLoadHelper diff() { public final ObjectKlass java_lang_StringLatin1; public final Method java_lang_StringLatin1_newString; + public final Method java_lang_StringLatin1_equals; public final ObjectKlass java_lang_StringUTF16; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java index fe5e9c393d37..c7f143f40715 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java @@ -8,7 +8,7 @@ import java.util.Locale; -//@EspressoSubstitutions +@EspressoSubstitutions public final class Target_java_lang_String { @Substitution(hasReceiver = true) public static @JavaType(internalName = "Z") Object contains(@JavaType(String.class) StaticObject self, diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java index 3404607d2234..4da881108556 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java @@ -5,7 +5,7 @@ import com.oracle.truffle.espresso.runtime.StaticObject; import tools.aqua.spout.SPouT; -//@EspressoSubstitutions +@EspressoSubstitutions public final class Target_java_lang_StringBuffer { diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java index a95ee2bb558c..bef080496966 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java @@ -5,7 +5,7 @@ import tools.aqua.spout.AnnotatedValue; import tools.aqua.spout.SPouT; -//@EspressoSubstitutions +@EspressoSubstitutions public final class Target_java_lang_StringBuilder { diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java index c202d8be86cf..b83415112a43 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java +++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java @@ -1566,20 +1566,50 @@ public static StaticObject stringConcat(StaticObject self, StaticObject other, M } + // this is a faithful re-implementation of String.equals() + private static boolean stringEqualsConcrete(StaticObject self, StaticObject other, Meta meta) { + if (self == other) { + return true; + } + + if (!other.isString()) { + return false; + } + + boolean COMPACT_STRINGS = meta.java_lang_String_COMPACT_STRINGS.getBoolean(meta.java_lang_String.getStatics()); + Object this_coder = meta.java_lang_String_coder.getValue(self); + Object other_coder = meta.java_lang_String_coder.getValue(other); + + if (COMPACT_STRINGS && this_coder != other_coder) { + return false; + } + + Object this_value = meta.java_lang_String_value.getValue(self); + Object other_value = meta.java_lang_String_value.getValue(other); + return (boolean) meta.java_lang_StringLatin1_equals.invokeMethod(null, new Object[] {this_value, other_value}); + + } + @CompilerDirectives.TruffleBoundary public static Object stringEquals(StaticObject self, StaticObject other, Meta meta) { - String cSelf = meta.toHostString(self); - String cOther = meta.toHostString(other); - boolean areEqual = cSelf.equals(cOther); - if (!analyze || !self.hasAnnotations() && !other.hasAnnotations()) { - return areEqual; - } - Annotations a = analysis.stringEquals(cSelf, - cOther, - getStringAnnotations(self), - getStringAnnotations(other)); - if(a != null) return new AnnotatedValue(areEqual, a); - else return areEqual; + boolean areEqual = stringEqualsConcrete(self, other, meta); + if (!analyze) return areEqual; + if (self.hasAnnotations() || (!StaticObject.isNull(other) && other.hasAnnotations())) { + String cSelf = meta.toHostString(self); + String cOther = meta.toHostString(other); + Annotations a = analysis.stringEquals(cSelf, + cOther, + getStringAnnotations(self), + getStringAnnotations(other)); + if(a != null) { + return new AnnotatedValue(areEqual, a); + } + } + // todo: maybe this can be encoded? + if (self.hasAnnotations() && StaticObject.isNull(other)) { + log("not recording string == null"); + } + return areEqual; } @CompilerDirectives.TruffleBoundary From d365d6bd24cb239f63901f74fae94f12d5374f7f Mon Sep 17 00:00:00 2001 From: Falk Howar <falk.howar@gmail.com> Date: Tue, 3 Oct 2023 19:29:13 +0200 Subject: [PATCH 3/8] reversing changes from bug hunt --- .../com/oracle/truffle/espresso/nodes/BytecodeNode.java | 9 ++++----- .../substitutions/Target_java_lang_StringBuffer.java | 3 +-- .../substitutions/Target_java_lang_StringBuilder.java | 3 +-- .../espresso/substitutions/Target_java_net_Socket.java | 2 +- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java index ef28557145f2..a0fe6d7339a3 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java @@ -2136,11 +2136,10 @@ private void putPoolConstant(VirtualFrame frame, int top, char cpi, int opcode) } else if (constant instanceof StringConstant) { assert opcode == LDC || opcode == LDC_W; StaticObject internedString = pool.resolvedStringAt(cpi); - // todo: if we do this as we did below then springboot will fail to start with IncompleteAnnotation exceptions - //Meta meta = getMeta(); - //StaticObject obj = meta.toGuestString(meta.toHostString(internedString)); - //SPouT.markObjectWithIFTaint(obj); - //TODO: (annotate string and maybe clone?) + //TODO: (this is definitively not correct! Maybe clone properly and annotate?) + Meta meta = getMeta(); + StaticObject obj = meta.toGuestString(meta.toHostString(internedString)); + SPouT.markObjectWithIFTaint(obj); putObject(frame, top, internedString); } else if (constant instanceof ClassConstant) { assert opcode == LDC || opcode == LDC_W; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java index 4da881108556..e2c3baa75e44 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java @@ -13,8 +13,7 @@ public final class Target_java_lang_StringBuffer { * If we do not intercept the constructor, we get side effects from the length comparison in the trace that are * irrelevant for the symbolic encoding. */ - //todo: leads to segfault when starting springboot - //@Substitution(hasReceiver = true, methodName = "<init>") + @Substitution(hasReceiver = true, methodName = "<init>") public static void init_string( @JavaType(StringBuilder.class) StaticObject self, @JavaType(String.class) StaticObject other, diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java index bef080496966..94a3e1c5edd2 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java @@ -13,8 +13,7 @@ public final class Target_java_lang_StringBuilder { * If we do not intercept the constructor, we get side effects from the length comparison in the trace that are * irrelevant for the symbolic encoding. */ - //todo: leads to segfault when starting springboot - //@Substitution(hasReceiver = true, methodName = "<init>") + @Substitution(hasReceiver = true, methodName = "<init>") public static void init_string( @JavaType(StringBuilder.class) StaticObject self, @JavaType(String.class) StaticObject other, diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_net_Socket.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_net_Socket.java index bfcd06f1f069..6f40ea123325 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_net_Socket.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_net_Socket.java @@ -5,7 +5,7 @@ @EspressoSubstitutions public final class Target_java_net_Socket { - //@Substitution(methodName = "<init>") + @Substitution(methodName = "<init>") public static void __init(@JavaType(String.class) Object server, @JavaType(internalName = "I") Object port, @Inject Meta meta) { SPouT.stopRecording("Networking not supported yet.", meta); } From b309ddb75f402e2c7655fddf2ec3ad6722c5324c Mon Sep 17 00:00:00 2001 From: Falk Howar <falk.howar@gmail.com> Date: Tue, 3 Oct 2023 19:36:35 +0200 Subject: [PATCH 4/8] add check for active iflow analysis --- .../oracle/truffle/espresso/nodes/BytecodeNode.java | 13 +++++++++---- .../src/tools/aqua/spout/SPouT.java | 4 ++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java index a0fe6d7339a3..0081fd2a13ab 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java @@ -2137,10 +2137,15 @@ private void putPoolConstant(VirtualFrame frame, int top, char cpi, int opcode) assert opcode == LDC || opcode == LDC_W; StaticObject internedString = pool.resolvedStringAt(cpi); //TODO: (this is definitively not correct! Maybe clone properly and annotate?) - Meta meta = getMeta(); - StaticObject obj = meta.toGuestString(meta.toHostString(internedString)); - SPouT.markObjectWithIFTaint(obj); - putObject(frame, top, internedString); + if (SPouT.generateIFTaint()) { + Meta meta = getMeta(); + StaticObject obj = meta.toGuestString(meta.toHostString(internedString)); + SPouT.markObjectWithIFTaint(obj); + putObject(frame, top, obj); + } + else { + putObject(frame, top, internedString); + } } else if (constant instanceof ClassConstant) { assert opcode == LDC || opcode == LDC_W; Klass klass = pool.resolvedKlassAt(getDeclaringKlass(), cpi); diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java index b83415112a43..3f15d5dad26b 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java +++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java @@ -529,6 +529,10 @@ public static void markWithIFTaint(VirtualFrame frame, int top){ AnnotatedVM.putAnnotations(frame, top, a); } + public static boolean generateIFTaint() { + return (analyze && config.analyzeControlFlowTaint()); + } + public static void markObjectWithIFTaint(StaticObject obj) { if(!analyze || !config.analyzeControlFlowTaint()) return; if (obj == StaticObject.NULL) return; From dd694ea5300103047605ff26cb0754c48fedc639 Mon Sep 17 00:00:00 2001 From: Falk Howar <falk.howar@gmail.com> Date: Wed, 11 Oct 2023 09:53:17 +0200 Subject: [PATCH 5/8] bugfixes and more implementation of heap walker --- .../src/tools/aqua/spout/HeapWalker.java | 10 ++++++++-- .../src/tools/aqua/spout/SPouT.java | 7 ++++--- .../src/tools/aqua/spout/Trace.java | 2 +- .../src/tools/aqua/taint/TaintAction.java | 11 ++++++++++- .../src/tools/aqua/taint/TaintCheckAction.java | 9 +++++++-- 5 files changed, 30 insertions(+), 9 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/HeapWalker.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/HeapWalker.java index c171ee7bd028..44a1b15b0773 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/HeapWalker.java +++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/HeapWalker.java @@ -71,6 +71,10 @@ public void walk(EspressoLanguage lang) { visited.add(origin); while (!queue.isEmpty()) { StaticObject current = queue.poll(); + if (current.isString()) { + action.applyToString(current); + continue; + } action.applyToObject(current); //SPouT.log("Analyzing " + current.getKlass().getNameAsString() + " . " + current.toString()); ObjectKlass oClass = (ObjectKlass) current.getKlass(); @@ -113,18 +117,19 @@ private void processArray(StaticObject arr, EspressoLanguage lang, assert arr.isArray(); action.applyToArray(arr); Klass eClass = arr.getKlass().getElementalType(); - Object[] data = arr.unwrap(lang); if (eClass.isPrimitive()) { - for (int i=0; i<data.length; i++) { + for (int i=0; i<arr.length(lang); i++) { action.applyToPrimitiveArrayElement(arr, i); } } else if (eClass.getType() == Symbol.Type.java_lang_String) { + Object[] data = arr.unwrap(lang); for (Object e : data) { StaticObject str = (StaticObject) e; action.applyToString(str); } } else if (eClass.isArray()) { + Object[] data = arr.unwrap(lang); for (Object e : data) { StaticObject arr2 = (StaticObject) e; if (visited.contains(arr2)) continue; @@ -132,6 +137,7 @@ else if (eClass.getType() == Symbol.Type.java_lang_String) { processArray( arr2, lang, nextQueue, visited); } } else { + Object[] data = arr.unwrap(lang); for (Object e : data) { StaticObject obj2 = (StaticObject) e; if (visited.contains(obj2)) continue; diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java index 3f15d5dad26b..98b7cf4991e1 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java +++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java @@ -67,7 +67,7 @@ public class SPouT { - public static final boolean DEBUG = false; + public static final boolean DEBUG = true; private static boolean analyze = false, oldAnalyze = analyze; @@ -113,8 +113,8 @@ public static void endPath() { trace.printTrace(); } log("======================== END PATH [END]."); - log("[ENDOFTRACE]"); - //System.out.flush(); + System.out.println("[ENDOFTRACE]"); + System.out.flush(); } private static void stopAnalysis() { @@ -445,6 +445,7 @@ private static void checkTaintOnCall(Object[] args, Method method, Taint t, Espr } private static Object[] analyzeTaint(Object[] args, Method method, Taint t, EspressoLanguage lang) { + log("analyze taint on method " + method.getName()); int receiver = 0 + (method.isStatic() ? 0 : 1); KlassRef[] argTypes = method.getParameters(); int argCount = argTypes.length; diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/Trace.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/Trace.java index 4f1069ae591e..15e557d3d973 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/Trace.java +++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/Trace.java @@ -63,7 +63,7 @@ public void addElement(TraceElement tNew) { public void printTrace() { TraceElement cur = traceHead; while (cur != null) { - SPouT.log(cur.toString()); + System.out.println(cur.toString()); cur = cur.getNext(); } } diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/taint/TaintAction.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/taint/TaintAction.java index d91bb565c16a..c884dc935cab 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/taint/TaintAction.java +++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/taint/TaintAction.java @@ -43,7 +43,16 @@ public void applyToPrimitiveArrayElement(StaticObject obj, int i) { @Override public void applyToString(StaticObject obj) { - SPouT.log("currently not tainting strings s on heap"); + if (!config.hasTaintAnalysis()) return; + Annotations a = Annotations.objectAnnotation(obj); + Taint tOld = Annotations.annotation(a, config.getTaintIdx()); + if (a == null) { + a = Annotations.create(); + } + Taint tNew = ColorUtil.joinColors(tOld, taint); + SPouT.log("tainting string with " + tNew); + a.set(config.getTaintIdx(), tNew); + Annotations.setObjectAnnotation(obj, a); } @Override diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/taint/TaintCheckAction.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/taint/TaintCheckAction.java index 809ec663903e..0f436a756184 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/taint/TaintCheckAction.java +++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/taint/TaintCheckAction.java @@ -30,13 +30,13 @@ public TaintCheckAction(Config config, Taint taint) { @Override public void applyToPrimitiveField(StaticObject obj, Field f) { if (!config.hasTaintAnalysis()) return; + Annotations a = AnnotatedVM.getFieldAnnotation(obj, f); for (int color : ColorUtil.colorsIn(taint)) { SPouT.log("checking " + color + " taint on " + f.getKind().toString() + "-field " + f.getNameAsString() + " of " + obj.getKlass().getNameAsString() + " [" + obj.toString() + "]"); - Annotations a = AnnotatedVM.getFieldAnnotation(obj, f); taintAnalysis.checkTaint(a, color); } } @@ -48,7 +48,12 @@ public void applyToPrimitiveArrayElement(StaticObject obj, int i) { @Override public void applyToString(StaticObject obj) { - SPouT.log("currently not checking taint on strings s on heap"); + if (!config.hasTaintAnalysis()) return; + Annotations a = Annotations.objectAnnotation(obj); + for (int color : ColorUtil.colorsIn(taint)) { + SPouT.log("checking string for taint with color " + color); + taintAnalysis.checkTaint(a, color); + } } @Override From e68ae6db007c5278866f95243f83625b464e70f3 Mon Sep 17 00:00:00 2001 From: Falk Howar <falk.howar@gmail.com> Date: Tue, 17 Oct 2023 21:43:33 +0200 Subject: [PATCH 6/8] hook for methods invoked by reflection --- ...get_sun_reflect_NativeMethodAccessorImpl.java | 7 +++++++ .../src/tools/aqua/spout/Annotations.java | 3 ++- .../src/tools/aqua/spout/SPouT.java | 16 +++++++++++++--- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_reflect_NativeMethodAccessorImpl.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_reflect_NativeMethodAccessorImpl.java index 0b568e087119..e7909785956f 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_reflect_NativeMethodAccessorImpl.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_reflect_NativeMethodAccessorImpl.java @@ -34,6 +34,7 @@ import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.runtime.EspressoException; import com.oracle.truffle.espresso.runtime.StaticObject; +import tools.aqua.spout.SPouT; /** * This substitution is merely for performance reasons, to avoid the deep-dive to native. libjava @@ -340,7 +341,13 @@ public static Object checkAndWiden(Meta meta, StaticObject arg, Klass targetKlas Object result; try { + if (method.isPartOfAnalysis()) { + adjustedArgs = SPouT.processMethodCall(adjustedArgs, method, meta); + } result = method.invokeDirect(receiver, adjustedArgs); +// if (method.isPartOfAnalysis()) { +// result = SPouT.processReturnValue(result, method, meta); +// } } catch (EspressoException e) { throw meta.throwExceptionWithCause(meta.java_lang_reflect_InvocationTargetException, e.getGuestException()); } diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/Annotations.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/Annotations.java index ccfb027b5b6a..c86179b53413 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/Annotations.java +++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/Annotations.java @@ -61,7 +61,8 @@ public Object[] getAnnotations() { @SuppressWarnings("unchecked") public static <T> T annotation(Annotations a, int i) { - return a != null ? (T) a.annotations[i] : null; + if (a == null || i < 0 || a.annotations.length <= i) return null; + return (T) a.annotations[i]; } @SuppressWarnings("unchecked") diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java index 98b7cf4991e1..a818fd6c3697 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java +++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java @@ -139,6 +139,11 @@ public static boolean isPartOfAnalysis(Method method) { } } + @CompilerDirectives.TruffleBoundary + public static Object[] processMethodCall(Object[] args, Method method, Meta meta) { + return processMethodCall(args, method, meta.getLanguage(), meta.getSubstitutions().get(method)); + } + @CompilerDirectives.TruffleBoundary public static Object[] processMethodCall(Object[] args, Method method, EspressoLanguage lang, RootNode rn) { if (!analyze) return args; @@ -162,6 +167,11 @@ public static Object[] processMethodCall(Object[] args, Method method, EspressoL return args; } + @CompilerDirectives.TruffleBoundary + public static Object processReturnValue(Object result, Method method, Meta meta) { + return processReturnValue(result, method, meta.getLanguage(), meta.getSubstitutions().get(method)); + } + public static Object processReturnValue(Object result, Method method, EspressoLanguage lang, RootNode rn) { if (!analyze) return result; @@ -303,7 +313,7 @@ private static Object makeConcolic(Object obj, Symbol<Symbol.Type> type, Espress } private static Object[] analyzeConcolically(Object[] args, Method method, EspressoLanguage lang, RootNode rn) { - int receiver = 0 + (method.isStatic() ? 0 : 1); + int receiver = 0 + (method.isStatic() || args.length == method.getParameterCount() ? 0 : 1); Symbol<Symbol.Type>[] methodSignature = method.getParsedSignature(); int argCount = Signatures.parameterCount(methodSignature); CompilerAsserts.partialEvaluationConstant(argCount); @@ -425,7 +435,7 @@ private static Object sanitizeReturnValue(Object result, Method method, Taint t, @CompilerDirectives.TruffleBoundary private static void checkTaintOnCall(Object[] args, Method method, Taint t, EspressoLanguage lang) { - int receiver = 0 + (method.isStatic() ? 0 : 1); + int receiver = 0 + (method.isStatic() || args.length == method.getParameterCount() ? 0 : 1); KlassRef[] argTypes = method.getParameters(); int argCount = argTypes.length; CompilerAsserts.partialEvaluationConstant(argCount); @@ -446,7 +456,7 @@ private static void checkTaintOnCall(Object[] args, Method method, Taint t, Espr private static Object[] analyzeTaint(Object[] args, Method method, Taint t, EspressoLanguage lang) { log("analyze taint on method " + method.getName()); - int receiver = 0 + (method.isStatic() ? 0 : 1); + int receiver = 0 + (method.isStatic() || args.length == method.getParameterCount() ? 0 : 1); KlassRef[] argTypes = method.getParameters(); int argCount = argTypes.length; CompilerAsserts.partialEvaluationConstant(argCount); From 9baf08ca87c83df3008d421aadfd22acc4e724a2 Mon Sep 17 00:00:00 2001 From: Falk Howar <falk.howar@gmail.com> Date: Sun, 22 Oct 2023 18:48:16 +0300 Subject: [PATCH 7/8] more generic proposal for methods with concolic/taint models --- .../oracle/truffle/espresso/meta/Meta.java | 5 +- .../truffle/espresso/nodes/BytecodeNode.java | 6 +- .../concolic/ConcolicInvokeVirtualNode.java | 75 +++++++++++++++++++ .../Target_java_lang_String.java | 4 +- .../src/tools/aqua/spout/SPouT.java | 33 ++------ 5 files changed, 91 insertions(+), 32 deletions(-) create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/concolic/ConcolicInvokeVirtualNode.java diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java index 6d52dc494f3f..4b219e28ca80 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java @@ -57,7 +57,6 @@ import com.oracle.truffle.espresso.runtime.StaticObject; import com.oracle.truffle.espresso.substitutions.JavaType; import com.oracle.truffle.espresso.vm.InterpreterToVM; -import tools.aqua.spout.SPouT; /** * Introspection API to access the guest world from the host. Provides seamless conversions from @@ -840,6 +839,8 @@ public Meta(EspressoContext context) { java_lang_StringLatin1_newString = java_lang_StringLatin1.lookupMethod(getNames().getOrCreate("newString"), Signature.String_byte_array_int_int); java_lang_StringLatin1_equals = java_lang_StringLatin1.lookupMethod(getNames().getOrCreate("equals"), Signature._boolean_byte_array_byte_array); + java_lang_String_equals = java_lang_String.lookupMethod(getNames().getOrCreate("equals"), Signature._boolean_Object); + java_lang_StringUTF16 = knownKlass(Type.java_lang_StringUTF16); java_lang_StringUTF16_newString = java_lang_StringUTF16.lookupMethod(getNames().getOrCreate("newString"), Signature.String_byte_array_int_int); } @@ -1456,7 +1457,7 @@ private DiffVersionLoadHelper diff() { public final Method java_lang_StringLatin1_newString; public final Method java_lang_StringLatin1_equals; - + public final Method java_lang_String_equals; public final ObjectKlass java_lang_StringUTF16; public final Method java_lang_StringUTF16_newString; diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java index 0081fd2a13ab..8f438c5594fd 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java @@ -229,7 +229,6 @@ import static com.oracle.truffle.espresso.bytecode.Bytecodes.TABLESWITCH; import static com.oracle.truffle.espresso.bytecode.Bytecodes.WIDE; -import java.lang.invoke.SwitchPoint; import java.util.Arrays; import java.util.List; import java.util.Locale; @@ -298,6 +297,7 @@ import com.oracle.truffle.espresso.meta.ExceptionHandler; import com.oracle.truffle.espresso.meta.JavaKind; import com.oracle.truffle.espresso.meta.Meta; +import com.oracle.truffle.espresso.nodes.concolic.ConcolicInvokeVirtualNode; import com.oracle.truffle.espresso.nodes.helper.EspressoReferenceArrayStoreNode; import com.oracle.truffle.espresso.nodes.quick.BaseQuickNode; import com.oracle.truffle.espresso.nodes.quick.CheckCastQuickNode; @@ -342,7 +342,6 @@ import tools.aqua.spout.*; import tools.aqua.taint.PostDominatorAnalysis; -import tools.aqua.taint.TaintAnalysis; /** * Bytecode interpreter loop. @@ -2493,6 +2492,9 @@ private BaseQuickNode dispatchQuickened(int top, int curBCI, char cpi, int opcod } // @formatter:on } + if (resolved == getMeta().java_lang_String_equals) { + invoke = new ConcolicInvokeVirtualNode.StringEquals(resolved, top, curBCI, getMeta()); + } return invoke; } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/concolic/ConcolicInvokeVirtualNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/concolic/ConcolicInvokeVirtualNode.java new file mode 100644 index 000000000000..ed91255aa438 --- /dev/null +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/concolic/ConcolicInvokeVirtualNode.java @@ -0,0 +1,75 @@ +package com.oracle.truffle.espresso.nodes.concolic; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.espresso.descriptors.Signatures; +import com.oracle.truffle.espresso.descriptors.Types; +import com.oracle.truffle.espresso.impl.Method; +import com.oracle.truffle.espresso.meta.Meta; +import com.oracle.truffle.espresso.nodes.BytecodeNode; +import com.oracle.truffle.espresso.nodes.bytecodes.InvokeVirtual; +import com.oracle.truffle.espresso.nodes.bytecodes.InvokeVirtualNodeGen; +import com.oracle.truffle.espresso.nodes.quick.QuickNode; +import com.oracle.truffle.espresso.runtime.StaticObject; +import tools.aqua.spout.SPouT; + +public abstract class ConcolicInvokeVirtualNode extends QuickNode { + + final Method.MethodVersion method; + final int resultAt; + final boolean returnsPrimitiveType; + @Child InvokeVirtual.WithoutNullCheck invokeVirtual; + + abstract Object concolicAnalysis(Object concreteResult, Object[] args); + + public ConcolicInvokeVirtualNode(Method method, int top, int curBCI) { + super(top, curBCI); + assert !method.isStatic(); + this.method = method.getMethodVersion(); + this.resultAt = top - Signatures.slotsForParameters(method.getParsedSignature()) - 1; // -receiver + this.returnsPrimitiveType = Types.isPrimitive(Signatures.returnType(method.getParsedSignature())); + this.invokeVirtual = InvokeVirtualNodeGen.WithoutNullCheckNodeGen.create(method); + } + + @Override + public int execute(VirtualFrame frame) { + Object[] args = BytecodeNode.popArguments(frame, top, true, method.getMethod().getParsedSignature()); + nullCheck((StaticObject) args[0]); + Object result = invokeVirtual.execute(args); + result = concolicAnalysis(result, args); + if (!returnsPrimitiveType) { + getBytecodeNode().checkNoForeignObjectAssumption((StaticObject) result); + } + return (getResultAt() - top) + BytecodeNode.putKind(frame, getResultAt(), result, method.getMethod().getReturnKind()); + } + + @Override + public boolean removedByRedefintion() { + if (method.getRedefineAssumption().isValid()) { + return false; + } else { + return method.getMethod().isRemovedByRedefition(); + } + } + + private int getResultAt() { + return resultAt; + } + + + public static final class StringEquals extends ConcolicInvokeVirtualNode { + + private final Meta meta; + + public StringEquals(Method method, int top, int curBCI, Meta meta) { + super(method, top, curBCI); + this.meta = meta; + } + @Override + Object concolicAnalysis(Object concreteResult, Object[] args) { + SPouT.log("concolic virtual node"); + return SPouT.stringEquals( (StaticObject) args[0], (StaticObject) args[1], (boolean) concreteResult, meta); + } + } + + +} diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java index c7f143f40715..dbfdee8d43b2 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java @@ -31,7 +31,7 @@ public static void init(@JavaType(String.class) StaticObject self, @JavaType(Str @Inject Meta meta) { return SPouT.stringCompareTo(self, other, meta); } - +/* @Substitution(hasReceiver = true) public static @JavaType(internalName = "Z") Object equals( @JavaType(String.class) StaticObject self, @@ -39,7 +39,7 @@ public static void init(@JavaType(String.class) StaticObject self, @JavaType(Str @Inject Meta meta) { return SPouT.stringEquals(self, other, meta); } - +*/ @Substitution(hasReceiver = true) public static @JavaType(internalName = "C") Object charAt(@JavaType(String.class) StaticObject self, @JavaType(internalName = "I") Object index, diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java index a818fd6c3697..5e3118e86ca0 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java +++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java @@ -125,6 +125,10 @@ private static void stopAnalysis() { } } + public static boolean doAnalyze() { + return analyze; + } + // -------------------------------------------------------------------------- // // interception of method invocations @@ -1581,33 +1585,10 @@ public static StaticObject stringConcat(StaticObject self, StaticObject other, M } - // this is a faithful re-implementation of String.equals() - private static boolean stringEqualsConcrete(StaticObject self, StaticObject other, Meta meta) { - if (self == other) { - return true; - } - - if (!other.isString()) { - return false; - } - - boolean COMPACT_STRINGS = meta.java_lang_String_COMPACT_STRINGS.getBoolean(meta.java_lang_String.getStatics()); - Object this_coder = meta.java_lang_String_coder.getValue(self); - Object other_coder = meta.java_lang_String_coder.getValue(other); - - if (COMPACT_STRINGS && this_coder != other_coder) { - return false; - } - - Object this_value = meta.java_lang_String_value.getValue(self); - Object other_value = meta.java_lang_String_value.getValue(other); - return (boolean) meta.java_lang_StringLatin1_equals.invokeMethod(null, new Object[] {this_value, other_value}); - - } - + // TODO: the concrete result may have annotations!!! + // TODO: these methods should work like the other entrypoints and distribute / integrate analyses! @CompilerDirectives.TruffleBoundary - public static Object stringEquals(StaticObject self, StaticObject other, Meta meta) { - boolean areEqual = stringEqualsConcrete(self, other, meta); + public static Object stringEquals(StaticObject self, StaticObject other, boolean areEqual, Meta meta) { if (!analyze) return areEqual; if (self.hasAnnotations() || (!StaticObject.isNull(other) && other.hasAnnotations())) { String cSelf = meta.toHostString(self); From 943ce39fab9056646abc692d5afe46ec33945583 Mon Sep 17 00:00:00 2001 From: Falk Howar <falk.howar@gmail.com> Date: Tue, 16 Jan 2024 07:57:45 +0100 Subject: [PATCH 8/8] some more invoke aspects --- .../oracle/truffle/espresso/impl/Method.java | 14 +++++++++++ .../truffle/espresso/nodes/BytecodeNode.java | 7 ++++-- .../concolic/ConcolicInvokeVirtualNode.java | 12 +++++----- .../src/tools/aqua/spout/SPouT.java | 23 +++++++++++++++++++ 4 files changed, 48 insertions(+), 8 deletions(-) diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java index 53f00f7b1f6a..80f37965367b 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java @@ -1586,7 +1586,9 @@ public CodeAttribute getCodeAttribute() { } // endregion jdwp-specific + // spout private Boolean partOfAnalysis = null; + private Integer modelId = null; public boolean isPartOfAnalysis() { if (partOfAnalysis == null) { @@ -1594,4 +1596,16 @@ public boolean isPartOfAnalysis() { } return partOfAnalysis; } + + public boolean hasModel(Meta meta) { + if (modelId == null) { + modelId = SPouT.getModelId(this, meta); + } + return modelId != -1; + } + + public int getModelId() { + return modelId; + } + } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java index 8f438c5594fd..0ff4e7018b3d 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java @@ -2492,9 +2492,12 @@ private BaseQuickNode dispatchQuickened(int top, int curBCI, char cpi, int opcod } // @formatter:on } - if (resolved == getMeta().java_lang_String_equals) { - invoke = new ConcolicInvokeVirtualNode.StringEquals(resolved, top, curBCI, getMeta()); + + Meta meta = getMeta(); + if (resolved.hasModel(meta)) { + invoke = SPouT.injectModel(resolved, meta, top, curBCI); } + return invoke; } diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/concolic/ConcolicInvokeVirtualNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/concolic/ConcolicInvokeVirtualNode.java index ed91255aa438..2e2a87281e5f 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/concolic/ConcolicInvokeVirtualNode.java +++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/concolic/ConcolicInvokeVirtualNode.java @@ -14,6 +14,7 @@ public abstract class ConcolicInvokeVirtualNode extends QuickNode { + final Meta meta; final Method.MethodVersion method; final int resultAt; final boolean returnsPrimitiveType; @@ -21,13 +22,14 @@ public abstract class ConcolicInvokeVirtualNode extends QuickNode { abstract Object concolicAnalysis(Object concreteResult, Object[] args); - public ConcolicInvokeVirtualNode(Method method, int top, int curBCI) { + public ConcolicInvokeVirtualNode(Method method, int top, int curBCI, Meta meta) { super(top, curBCI); assert !method.isStatic(); this.method = method.getMethodVersion(); this.resultAt = top - Signatures.slotsForParameters(method.getParsedSignature()) - 1; // -receiver this.returnsPrimitiveType = Types.isPrimitive(Signatures.returnType(method.getParsedSignature())); this.invokeVirtual = InvokeVirtualNodeGen.WithoutNullCheckNodeGen.create(method); + this.meta = meta; } @Override @@ -58,12 +60,10 @@ private int getResultAt() { public static final class StringEquals extends ConcolicInvokeVirtualNode { - private final Meta meta; - - public StringEquals(Method method, int top, int curBCI, Meta meta) { - super(method, top, curBCI); - this.meta = meta; + public StringEquals(int top, int curBCI, Meta meta) { + super(meta.java_lang_String_equals, top, curBCI, meta); } + @Override Object concolicAnalysis(Object concreteResult, Object[] args) { SPouT.log("concolic virtual node"); diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java index 5e3118e86ca0..38cb228c54e3 100644 --- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java +++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java @@ -40,6 +40,8 @@ import com.oracle.truffle.espresso.meta.EspressoError; import com.oracle.truffle.espresso.meta.Meta; import com.oracle.truffle.espresso.nodes.BytecodeNode; +import com.oracle.truffle.espresso.nodes.concolic.ConcolicInvokeVirtualNode; +import com.oracle.truffle.espresso.nodes.quick.QuickNode; import com.oracle.truffle.espresso.runtime.EspressoContext; import com.oracle.truffle.espresso.runtime.StaticObject; import tools.aqua.concolic.ConcolicAnnotationAction; @@ -143,6 +145,27 @@ public static boolean isPartOfAnalysis(Method method) { } } + @CompilerDirectives.TruffleBoundary + public static int getModelId(Method method, Meta meta) { + Klass clazz = method.getDeclaringKlass(); + if (clazz == meta.java_lang_String) { + if (method == meta.java_lang_String_equals) { + return 0; + } + } + return -1; + } + + public static QuickNode injectModel(Method method, Meta meta, int top, int curBCI) { + switch (method.getModelId()) { + case 0: return new ConcolicInvokeVirtualNode.StringEquals(top, curBCI, getMeta()); + } + stopRecordingWithoutMeta("unknown model"); + // will not be reached + return null; + } + + @CompilerDirectives.TruffleBoundary public static Object[] processMethodCall(Object[] args, Method method, Meta meta) { return processMethodCall(args, method, meta.getLanguage(), meta.getSubstitutions().get(method));