diff --git a/regression/cbmc-java/assume1/Assume1.class b/regression/cbmc-java/assume1/Assume1.class new file mode 100644 index 00000000000..b9a49bc9971 Binary files /dev/null and b/regression/cbmc-java/assume1/Assume1.class differ diff --git a/regression/cbmc-java/assume1/Assume1.java b/regression/cbmc-java/assume1/Assume1.java new file mode 100644 index 00000000000..4de0afd025b --- /dev/null +++ b/regression/cbmc-java/assume1/Assume1.java @@ -0,0 +1,10 @@ +import org.cprover.CProver; + +class Assume1 +{ + static void foo(int x) + { + CProver.assume(x>3); + assert x>0; + } +} diff --git a/regression/cbmc-java/assume1/test.desc b/regression/cbmc-java/assume1/test.desc new file mode 100644 index 00000000000..1f80a1c1e86 --- /dev/null +++ b/regression/cbmc-java/assume1/test.desc @@ -0,0 +1,8 @@ +CORE +Assume1.class +--function Assume1.foo +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/assume2/Assume2.class b/regression/cbmc-java/assume2/Assume2.class new file mode 100644 index 00000000000..36e09875d7d Binary files /dev/null and b/regression/cbmc-java/assume2/Assume2.class differ diff --git a/regression/cbmc-java/assume2/Assume2.java b/regression/cbmc-java/assume2/Assume2.java new file mode 100644 index 00000000000..6991167bfb8 --- /dev/null +++ b/regression/cbmc-java/assume2/Assume2.java @@ -0,0 +1,10 @@ +import org.cprover.CProver; + +class Assume2 +{ + static void foo(int x) + { + CProver.assume(x>3); + assert x>4; + } +} diff --git a/regression/cbmc-java/assume2/test.desc b/regression/cbmc-java/assume2/test.desc new file mode 100644 index 00000000000..35a954116f8 --- /dev/null +++ b/regression/cbmc-java/assume2/test.desc @@ -0,0 +1,8 @@ +CORE +Assume2.class +--function Assume2.foo +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/assume3/Assume3.class b/regression/cbmc-java/assume3/Assume3.class new file mode 100644 index 00000000000..916ad4065fb Binary files /dev/null and b/regression/cbmc-java/assume3/Assume3.class differ diff --git a/regression/cbmc-java/assume3/Assume3.java b/regression/cbmc-java/assume3/Assume3.java new file mode 100644 index 00000000000..895deee9ca0 --- /dev/null +++ b/regression/cbmc-java/assume3/Assume3.java @@ -0,0 +1,10 @@ +import org.cprover.CProver; + +class Assume3 +{ + public static void main(String[] args) + { + CProver.assume(false); + assert false; + } +} diff --git a/regression/cbmc-java/assume3/test.desc b/regression/cbmc-java/assume3/test.desc new file mode 100644 index 00000000000..0ad8c00399f --- /dev/null +++ b/regression/cbmc-java/assume3/test.desc @@ -0,0 +1,8 @@ +CORE +Assume3.class + +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/covered1/covered1.class b/regression/cbmc-java/covered1/covered1.class new file mode 100644 index 00000000000..7cb91496b7d Binary files /dev/null and b/regression/cbmc-java/covered1/covered1.class differ diff --git a/regression/cbmc-java/covered1/covered1.java b/regression/cbmc-java/covered1/covered1.java new file mode 100644 index 00000000000..018e65336a6 --- /dev/null +++ b/regression/cbmc-java/covered1/covered1.java @@ -0,0 +1,37 @@ +public class covered1 +{ + // this is a variable + int x=1; + //these are two, one line off the first + int y=2; + int z=3; + //this is part of static init + static int z0=0; + + //another non-static + int a; + int b; + static boolean odd; + + static + { + odd=(z0+1)%2==0; + } + + covered1(int a, int b) + { + this.a=a*b; + this.b=a+b; + if(this.a==a) + z0++; + else + odd=!odd; + } + // at the back + int z1=2; + int z2=3; + int z3=4; + // + static int z4=5; + int z5=5; +} diff --git a/regression/cbmc-java/covered1/test.desc b/regression/cbmc-java/covered1/test.desc new file mode 100644 index 00000000000..32af766bdb7 --- /dev/null +++ b/regression/cbmc-java/covered1/test.desc @@ -0,0 +1,19 @@ +CORE +covered1.class +--cover location --json-ui --show-properties +^EXIT=0$ +^SIGNAL=0$ +.*\"coveredLines\": \"22\",$ +.*\"coveredLines\": \"4,6,7,23-25,31-33,36\",$ +.*\"coveredLines\": \"26\",$ +.*\"coveredLines\": \"28\",$ +.*\"coveredLines\": \"28\",$ +.*\"coveredLines\": \"28\",$ +.*\"coveredLines\": \"28\",$ +.*\"coveredLines\": \"29\",$ +.*\"coveredLines\": \"9,18\",$ +.*\"coveredLines\": \"18\",$ +.*\"coveredLines\": \"18\",$ +.*\"coveredLines\": \"18,35\",$ +-- +^warning: ignoring diff --git a/regression/strings-smoke-tests/Makefile b/regression/strings-smoke-tests/Makefile new file mode 100644 index 00000000000..c41ab1c5be8 --- /dev/null +++ b/regression/strings-smoke-tests/Makefile @@ -0,0 +1,9 @@ + +test: + @../test.pl -c ../../../src/cbmc/cbmc + +testfuture: + @../test.pl -c ../../../src/cbmc/cbmc -CF + +testall: + @../test.pl -c ../../../src/cbmc/cbmc -CFTK diff --git a/regression/strings-smoke-tests/java_append_char/test.desc b/regression/strings-smoke-tests/java_append_char/test.desc new file mode 100644 index 00000000000..0f1b3ae243f --- /dev/null +++ b/regression/strings-smoke-tests/java_append_char/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_append_char.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_append_char/test_append_char.class b/regression/strings-smoke-tests/java_append_char/test_append_char.class new file mode 100644 index 00000000000..00c40aef6f6 Binary files /dev/null and b/regression/strings-smoke-tests/java_append_char/test_append_char.class differ diff --git a/regression/strings-smoke-tests/java_append_char/test_append_char.java b/regression/strings-smoke-tests/java_append_char/test_append_char.java new file mode 100644 index 00000000000..3eec4f30abe --- /dev/null +++ b/regression/strings-smoke-tests/java_append_char/test_append_char.java @@ -0,0 +1,17 @@ +public class test_append_char +{ + public static void main(/*String[] args*/) + { + char[] diff = {'d', 'i', 'f', 'f'}; + char[] blue = {'b', 'l', 'u', 'e'}; + + StringBuilder buffer = new StringBuilder(); + + buffer.append(diff) + .append(blue); + + String tmp=buffer.toString(); + System.out.println(tmp); + assert tmp.equals("diffblue"); + } +} diff --git a/regression/strings-smoke-tests/java_append_int/test.desc b/regression/strings-smoke-tests/java_append_int/test.desc new file mode 100644 index 00000000000..e1455859470 --- /dev/null +++ b/regression/strings-smoke-tests/java_append_int/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_append_int.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_append_int/test_append_int.class b/regression/strings-smoke-tests/java_append_int/test_append_int.class new file mode 100644 index 00000000000..16948397e03 Binary files /dev/null and b/regression/strings-smoke-tests/java_append_int/test_append_int.class differ diff --git a/regression/strings-smoke-tests/java_append_int/test_append_int.java b/regression/strings-smoke-tests/java_append_int/test_append_int.java new file mode 100644 index 00000000000..963f3d7c063 --- /dev/null +++ b/regression/strings-smoke-tests/java_append_int/test_append_int.java @@ -0,0 +1,11 @@ +public class test_append_int +{ + public static void main(/*String[] args*/) + { + StringBuilder diffblue = new StringBuilder(); + diffblue.append("d"); + diffblue.append(4); + String s = diffblue.toString(); + assert s.equals("d4"); + } +} diff --git a/regression/strings-smoke-tests/java_append_object/test.desc b/regression/strings-smoke-tests/java_append_object/test.desc new file mode 100644 index 00000000000..5db2ac1db73 --- /dev/null +++ b/regression/strings-smoke-tests/java_append_object/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_append_object.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_append_object/test_append_object.class b/regression/strings-smoke-tests/java_append_object/test_append_object.class new file mode 100644 index 00000000000..ed6942a1fa6 Binary files /dev/null and b/regression/strings-smoke-tests/java_append_object/test_append_object.class differ diff --git a/regression/strings-smoke-tests/java_append_object/test_append_object.java b/regression/strings-smoke-tests/java_append_object/test_append_object.java new file mode 100644 index 00000000000..121690451ca --- /dev/null +++ b/regression/strings-smoke-tests/java_append_object/test_append_object.java @@ -0,0 +1,17 @@ +public class test_append_object +{ + public static void main(/*String[] args*/) + { + Object diff = "diff"; + Object blue = "blue"; + + StringBuilder buffer = new StringBuilder(); + + buffer.append(diff) + .append(blue); + + String tmp=buffer.toString(); + System.out.println(tmp); + assert tmp.equals("diffblue"); + } +} diff --git a/regression/strings-smoke-tests/java_append_string/test.desc b/regression/strings-smoke-tests/java_append_string/test.desc new file mode 100644 index 00000000000..18035539d58 --- /dev/null +++ b/regression/strings-smoke-tests/java_append_string/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_append_string.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_append_string/test_append_string.class b/regression/strings-smoke-tests/java_append_string/test_append_string.class new file mode 100644 index 00000000000..622e08467f9 Binary files /dev/null and b/regression/strings-smoke-tests/java_append_string/test_append_string.class differ diff --git a/regression/strings-smoke-tests/java_append_string/test_append_string.java b/regression/strings-smoke-tests/java_append_string/test_append_string.java new file mode 100644 index 00000000000..e7f961172fa --- /dev/null +++ b/regression/strings-smoke-tests/java_append_string/test_append_string.java @@ -0,0 +1,14 @@ +public class test_append_string +{ + public static void main(/*String[] args*/) + { + String di = new String("di"); + StringBuilder diff = new StringBuilder(); + diff.append(di); + diff.append("ff"); + System.out.println(diff); + String s = diff.toString(); + System.out.println(s); + assert s.equals("diff"); + } +} diff --git a/regression/strings-smoke-tests/java_case/test.desc b/regression/strings-smoke-tests/java_case/test.desc new file mode 100644 index 00000000000..e01a5054419 --- /dev/null +++ b/regression/strings-smoke-tests/java_case/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_case.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_case/test_case.class b/regression/strings-smoke-tests/java_case/test_case.class new file mode 100644 index 00000000000..9f7eaab446c Binary files /dev/null and b/regression/strings-smoke-tests/java_case/test_case.class differ diff --git a/regression/strings-smoke-tests/java_case/test_case.java b/regression/strings-smoke-tests/java_case/test_case.java new file mode 100644 index 00000000000..b3437a6f83e --- /dev/null +++ b/regression/strings-smoke-tests/java_case/test_case.java @@ -0,0 +1,12 @@ +public class test_case +{ + public static void main(/*String[] argv*/) + { + String s = new String("Ab"); + String l = s.toLowerCase(); + String u = s.toUpperCase(); + assert(l.equals("ab")); + assert(u.equals("AB")); + assert(s.equalsIgnoreCase("aB")); + } +} diff --git a/regression/strings-smoke-tests/java_char_array/test.desc b/regression/strings-smoke-tests/java_char_array/test.desc new file mode 100644 index 00000000000..ecce56c1ab8 --- /dev/null +++ b/regression/strings-smoke-tests/java_char_array/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_char_array.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_char_array/test_char_array.class b/regression/strings-smoke-tests/java_char_array/test_char_array.class new file mode 100644 index 00000000000..0d2056042ca Binary files /dev/null and b/regression/strings-smoke-tests/java_char_array/test_char_array.class differ diff --git a/regression/strings-smoke-tests/java_char_array/test_char_array.java b/regression/strings-smoke-tests/java_char_array/test_char_array.java new file mode 100644 index 00000000000..017fe704124 --- /dev/null +++ b/regression/strings-smoke-tests/java_char_array/test_char_array.java @@ -0,0 +1,13 @@ +public class test_char_array +{ + public static void main(/*String[] argv*/) + { + String s = "abc"; + char [] str = s.toCharArray(); + char c = str[2]; + char a = s.charAt(0); + assert(str.length == 3); + assert(a == 'a'); + assert(c == 'c'); + } +} diff --git a/regression/strings-smoke-tests/java_char_array_init/test.desc b/regression/strings-smoke-tests/java_char_array_init/test.desc new file mode 100644 index 00000000000..fc1cde2392c --- /dev/null +++ b/regression/strings-smoke-tests/java_char_array_init/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_init.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_char_array_init/test_init.class b/regression/strings-smoke-tests/java_char_array_init/test_init.class new file mode 100644 index 00000000000..48075eb9187 Binary files /dev/null and b/regression/strings-smoke-tests/java_char_array_init/test_init.class differ diff --git a/regression/strings-smoke-tests/java_char_array_init/test_init.java b/regression/strings-smoke-tests/java_char_array_init/test_init.java new file mode 100644 index 00000000000..8e0f656e3e8 --- /dev/null +++ b/regression/strings-smoke-tests/java_char_array_init/test_init.java @@ -0,0 +1,21 @@ +public class test_init { + + public static void main(/*String[] argv*/) + { + char [] str = new char[10]; + str[0] = 'H'; + str[1] = 'e'; + str[2] = 'l'; + str[3] = 'l'; + str[4] = 'o'; + String s = new String(str); + String t = new String(str,1,2); + + System.out.println(s.length()); + assert(s.length() == 10); + System.out.println(s); + System.out.println(t); + assert(t.equals("el")); + assert(s.startsWith("Hello")); + } +} diff --git a/regression/strings-smoke-tests/java_char_at/test.desc b/regression/strings-smoke-tests/java_char_at/test.desc new file mode 100644 index 00000000000..5bf29fc7a4d --- /dev/null +++ b/regression/strings-smoke-tests/java_char_at/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_char_at.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_char_at/test_char_at.class b/regression/strings-smoke-tests/java_char_at/test_char_at.class new file mode 100644 index 00000000000..de5fe888245 Binary files /dev/null and b/regression/strings-smoke-tests/java_char_at/test_char_at.class differ diff --git a/regression/strings-smoke-tests/java_char_at/test_char_at.java b/regression/strings-smoke-tests/java_char_at/test_char_at.java new file mode 100644 index 00000000000..3b8663d62ae --- /dev/null +++ b/regression/strings-smoke-tests/java_char_at/test_char_at.java @@ -0,0 +1,7 @@ +public class test_char_at { + + public static void main(/*String[] argv*/) { + String s = new String("abc"); + assert(s.charAt(2)=='c'); + } +} diff --git a/regression/strings-smoke-tests/java_code_point/test.desc b/regression/strings-smoke-tests/java_code_point/test.desc new file mode 100644 index 00000000000..012c7c3501b --- /dev/null +++ b/regression/strings-smoke-tests/java_code_point/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_code_point.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_code_point/test_code_point.class b/regression/strings-smoke-tests/java_code_point/test_code_point.class new file mode 100644 index 00000000000..1d5d2269325 Binary files /dev/null and b/regression/strings-smoke-tests/java_code_point/test_code_point.class differ diff --git a/regression/strings-smoke-tests/java_code_point/test_code_point.java b/regression/strings-smoke-tests/java_code_point/test_code_point.java new file mode 100644 index 00000000000..faf9a2051d5 --- /dev/null +++ b/regression/strings-smoke-tests/java_code_point/test_code_point.java @@ -0,0 +1,14 @@ +public class test_code_point +{ + public static void main(/*String[] argv*/) + { + String s = "!𐤇𐤄𐤋𐤋𐤅"; + assert(s.codePointAt(1) == 67847); + assert(s.codePointBefore(3) == 67847); + assert(s.codePointCount(1,5) >= 2); + assert(s.offsetByCodePoints(1,2) >= 3); + StringBuilder sb = new StringBuilder(); + sb.appendCodePoint(0x10907); + assert(s.charAt(1) == sb.charAt(0)); + } +} diff --git a/regression/strings-smoke-tests/java_compare/test.desc b/regression/strings-smoke-tests/java_compare/test.desc new file mode 100644 index 00000000000..38aa025f416 --- /dev/null +++ b/regression/strings-smoke-tests/java_compare/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_compare.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_compare/test_compare.class b/regression/strings-smoke-tests/java_compare/test_compare.class new file mode 100644 index 00000000000..3a807f4d203 Binary files /dev/null and b/regression/strings-smoke-tests/java_compare/test_compare.class differ diff --git a/regression/strings-smoke-tests/java_compare/test_compare.java b/regression/strings-smoke-tests/java_compare/test_compare.java new file mode 100644 index 00000000000..c052ed429bd --- /dev/null +++ b/regression/strings-smoke-tests/java_compare/test_compare.java @@ -0,0 +1,9 @@ +public class test_compare +{ + public static void main(/*String[] argv*/) + { + String s1 = "ab"; + String s2 = "aa"; + assert(s1.compareTo(s2) == 1); + } +} diff --git a/regression/strings-smoke-tests/java_concat/test.desc b/regression/strings-smoke-tests/java_concat/test.desc new file mode 100644 index 00000000000..fb784efd723 --- /dev/null +++ b/regression/strings-smoke-tests/java_concat/test.desc @@ -0,0 +1,8 @@ +FUTURE +test_concat.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 10.* SUCCESS$ +^\[.*assertion.2\].* line 11.* FAILURE$ +-- diff --git a/regression/strings-smoke-tests/java_concat/test_concat.class b/regression/strings-smoke-tests/java_concat/test_concat.class new file mode 100644 index 00000000000..e4143c15773 Binary files /dev/null and b/regression/strings-smoke-tests/java_concat/test_concat.class differ diff --git a/regression/strings-smoke-tests/java_concat/test_concat.java b/regression/strings-smoke-tests/java_concat/test_concat.java new file mode 100644 index 00000000000..b9909c723d4 --- /dev/null +++ b/regression/strings-smoke-tests/java_concat/test_concat.java @@ -0,0 +1,13 @@ +public class test_concat +{ + public static void main(/*String[] argv*/) + { + String s = new String("pi"); + int i = s.length(); + String t = new String("ppo"); + String u = s.concat(t); + char c = u.charAt(i); + assert(c == 'p'); + assert(c == 'o'); + } +} diff --git a/regression/strings-smoke-tests/java_contains/test.desc b/regression/strings-smoke-tests/java_contains/test.desc new file mode 100644 index 00000000000..2b96346d718 --- /dev/null +++ b/regression/strings-smoke-tests/java_contains/test.desc @@ -0,0 +1,8 @@ +FUTURE +test_contains.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 8.* SUCCESS$ +^\[.*assertion.2\].* line 9.* FAILURE$ +-- diff --git a/regression/strings-smoke-tests/java_contains/test_contains.class b/regression/strings-smoke-tests/java_contains/test_contains.class new file mode 100644 index 00000000000..adf0ece000a Binary files /dev/null and b/regression/strings-smoke-tests/java_contains/test_contains.class differ diff --git a/regression/strings-smoke-tests/java_contains/test_contains.java b/regression/strings-smoke-tests/java_contains/test_contains.java new file mode 100644 index 00000000000..5112c344c09 --- /dev/null +++ b/regression/strings-smoke-tests/java_contains/test_contains.java @@ -0,0 +1,11 @@ +public class test_contains +{ + public static void main(/*String[] argv*/) + { + String s = new String("Abc"); + String u = "bc"; + String t = "ab"; + assert(s.contains(u)); + assert(s.contains(t)); + } +} diff --git a/regression/strings-smoke-tests/java_delete/test.desc b/regression/strings-smoke-tests/java_delete/test.desc new file mode 100644 index 00000000000..27a1406cdb7 --- /dev/null +++ b/regression/strings-smoke-tests/java_delete/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_delete.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_delete/test_delete.class b/regression/strings-smoke-tests/java_delete/test_delete.class new file mode 100644 index 00000000000..f18891851b1 Binary files /dev/null and b/regression/strings-smoke-tests/java_delete/test_delete.class differ diff --git a/regression/strings-smoke-tests/java_delete/test_delete.java b/regression/strings-smoke-tests/java_delete/test_delete.java new file mode 100644 index 00000000000..13bd09cd075 --- /dev/null +++ b/regression/strings-smoke-tests/java_delete/test_delete.java @@ -0,0 +1,10 @@ +public class test_delete +{ + public static void main(/*String[] argv*/) + { + StringBuilder s = new StringBuilder("Abc"); + s.delete(1,2); + String str = s.toString(); + assert(str.equals("Ac")); + } +} diff --git a/regression/strings-smoke-tests/java_delete_char_at/test.desc b/regression/strings-smoke-tests/java_delete_char_at/test.desc new file mode 100644 index 00000000000..94ba56a2c54 --- /dev/null +++ b/regression/strings-smoke-tests/java_delete_char_at/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_delete_char_at.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_delete_char_at/test_delete_char_at.class b/regression/strings-smoke-tests/java_delete_char_at/test_delete_char_at.class new file mode 100644 index 00000000000..cfd8561e596 Binary files /dev/null and b/regression/strings-smoke-tests/java_delete_char_at/test_delete_char_at.class differ diff --git a/regression/strings-smoke-tests/java_delete_char_at/test_delete_char_at.java b/regression/strings-smoke-tests/java_delete_char_at/test_delete_char_at.java new file mode 100644 index 00000000000..94787c5283d --- /dev/null +++ b/regression/strings-smoke-tests/java_delete_char_at/test_delete_char_at.java @@ -0,0 +1,11 @@ +public class test_delete_char_at +{ + public static void main(/*String[] argv*/) + { + StringBuilder s = new StringBuilder(); + s.append("Abc"); + s.deleteCharAt(1); + String str = s.toString(); + assert(str.equals("Ac")); + } +} diff --git a/regression/strings-smoke-tests/java_empty/test.desc b/regression/strings-smoke-tests/java_empty/test.desc new file mode 100644 index 00000000000..9951c8a13ee --- /dev/null +++ b/regression/strings-smoke-tests/java_empty/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_empty.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_empty/test_empty.class b/regression/strings-smoke-tests/java_empty/test_empty.class new file mode 100644 index 00000000000..8e9a17d387e Binary files /dev/null and b/regression/strings-smoke-tests/java_empty/test_empty.class differ diff --git a/regression/strings-smoke-tests/java_empty/test_empty.java b/regression/strings-smoke-tests/java_empty/test_empty.java new file mode 100644 index 00000000000..47c335e16fa --- /dev/null +++ b/regression/strings-smoke-tests/java_empty/test_empty.java @@ -0,0 +1,8 @@ +public class test_empty +{ + public static void main(/*String[] argv*/) + { + String empty = ""; + assert(empty.isEmpty()); + } +} diff --git a/regression/strings-smoke-tests/java_endswith/test.desc b/regression/strings-smoke-tests/java_endswith/test.desc new file mode 100644 index 00000000000..0461a3e50e6 --- /dev/null +++ b/regression/strings-smoke-tests/java_endswith/test.desc @@ -0,0 +1,8 @@ +FUTURE +test_endswith.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 9.* SUCCESS$ +^\[.*assertion.2\].* line 10.* FAILURE$ +-- diff --git a/regression/strings-smoke-tests/java_endswith/test_endswith.class b/regression/strings-smoke-tests/java_endswith/test_endswith.class new file mode 100644 index 00000000000..1f86e94431d Binary files /dev/null and b/regression/strings-smoke-tests/java_endswith/test_endswith.class differ diff --git a/regression/strings-smoke-tests/java_endswith/test_endswith.java b/regression/strings-smoke-tests/java_endswith/test_endswith.java new file mode 100644 index 00000000000..f7729ef6a40 --- /dev/null +++ b/regression/strings-smoke-tests/java_endswith/test_endswith.java @@ -0,0 +1,12 @@ +public class test_endswith +{ + public static void main(/*String[] argv*/) + { + String s = new String("Abcd"); + String suff = "cd"; + String bad_suff = "bc"; + + assert(s.endsWith(suff)); + assert(s.endsWith(bad_suff)); + } +} diff --git a/regression/strings-smoke-tests/java_equal/test.desc b/regression/strings-smoke-tests/java_equal/test.desc new file mode 100644 index 00000000000..05f0f383230 --- /dev/null +++ b/regression/strings-smoke-tests/java_equal/test.desc @@ -0,0 +1,8 @@ +FUTURE +test_equal.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 8.* FAILURE$ +^\[.*assertion.2\].* line 9.* SUCCESS$ +-- diff --git a/regression/strings-smoke-tests/java_equal/test_equal.class b/regression/strings-smoke-tests/java_equal/test_equal.class new file mode 100644 index 00000000000..e0fc6db8aaf Binary files /dev/null and b/regression/strings-smoke-tests/java_equal/test_equal.class differ diff --git a/regression/strings-smoke-tests/java_equal/test_equal.java b/regression/strings-smoke-tests/java_equal/test_equal.java new file mode 100644 index 00000000000..a3acb0ebda5 --- /dev/null +++ b/regression/strings-smoke-tests/java_equal/test_equal.java @@ -0,0 +1,11 @@ +public class test_equal +{ + public static void main(String[] argv) + { + String s = new String("pi"); + String t = new String("po"); + String u = "po"; + assert(s.equals(t)); + assert(t.equals(u)); + } +} diff --git a/regression/strings-smoke-tests/java_float/test.desc b/regression/strings-smoke-tests/java_float/test.desc new file mode 100644 index 00000000000..427d1fca836 --- /dev/null +++ b/regression/strings-smoke-tests/java_float/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_float.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_float/test_float.class b/regression/strings-smoke-tests/java_float/test_float.class new file mode 100644 index 00000000000..e4448d41558 Binary files /dev/null and b/regression/strings-smoke-tests/java_float/test_float.class differ diff --git a/regression/strings-smoke-tests/java_float/test_float.java b/regression/strings-smoke-tests/java_float/test_float.java new file mode 100644 index 00000000000..d2791d5c343 --- /dev/null +++ b/regression/strings-smoke-tests/java_float/test_float.java @@ -0,0 +1,15 @@ +public class test_float +{ + public static void main(/*String[] arg*/) + { + float inf = 100.0f / 0.0f; + float minus_inf = -100.0f / 0.0f; + float nan = 0.0f / 0.0f; + String inf_string = Float.toString(inf); + String mininf_string = Float.toString(minus_inf); + String nan_string = Float.toString(nan); + assert(nan_string.equals("NaN")); + assert(inf_string.equals("Infinity")); + assert(mininf_string.equals("-Infinity")); + } +} diff --git a/regression/strings-smoke-tests/java_hash_code/test.desc b/regression/strings-smoke-tests/java_hash_code/test.desc new file mode 100644 index 00000000000..2db8d7116f9 --- /dev/null +++ b/regression/strings-smoke-tests/java_hash_code/test.desc @@ -0,0 +1,8 @@ +FUTURE +test_hash_code.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 8.* SUCCESS$ +^\[.*assertion.2\].* line 9.* FAILURE$ +-- diff --git a/regression/strings-smoke-tests/java_hash_code/test_hash_code.class b/regression/strings-smoke-tests/java_hash_code/test_hash_code.class new file mode 100644 index 00000000000..21bc5d96ca9 Binary files /dev/null and b/regression/strings-smoke-tests/java_hash_code/test_hash_code.class differ diff --git a/regression/strings-smoke-tests/java_hash_code/test_hash_code.java b/regression/strings-smoke-tests/java_hash_code/test_hash_code.java new file mode 100644 index 00000000000..d9f42b7ff9d --- /dev/null +++ b/regression/strings-smoke-tests/java_hash_code/test_hash_code.java @@ -0,0 +1,11 @@ +public class test_hash_code +{ + public static void main(/*String[] argv*/) + { + String s1 = "ab"; + String s2 = "ab"; + String s3 = "aa"; + assert(s1.hashCode() == s2.hashCode()); + assert(s1.hashCode() == s3.hashCode()); + } +} diff --git a/regression/strings-smoke-tests/java_index_of/test.desc b/regression/strings-smoke-tests/java_index_of/test.desc new file mode 100644 index 00000000000..f2fa825597d --- /dev/null +++ b/regression/strings-smoke-tests/java_index_of/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_index_of.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_index_of/test_index_of.class b/regression/strings-smoke-tests/java_index_of/test_index_of.class new file mode 100644 index 00000000000..1acb3335d57 Binary files /dev/null and b/regression/strings-smoke-tests/java_index_of/test_index_of.class differ diff --git a/regression/strings-smoke-tests/java_index_of/test_index_of.java b/regression/strings-smoke-tests/java_index_of/test_index_of.java new file mode 100644 index 00000000000..270267196c5 --- /dev/null +++ b/regression/strings-smoke-tests/java_index_of/test_index_of.java @@ -0,0 +1,10 @@ +public class test_index_of +{ + public static void main(/*String[] argv*/) + { + String s = "Abc"; + String bc = "bc"; + int i = s.indexOf(bc); + assert(i == 1); + } +} diff --git a/regression/strings-smoke-tests/java_index_of_char/test.desc b/regression/strings-smoke-tests/java_index_of_char/test.desc new file mode 100644 index 00000000000..63382a455f3 --- /dev/null +++ b/regression/strings-smoke-tests/java_index_of_char/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_index_of_char.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_index_of_char/test_index_of_char.class b/regression/strings-smoke-tests/java_index_of_char/test_index_of_char.class new file mode 100644 index 00000000000..f87a1026683 Binary files /dev/null and b/regression/strings-smoke-tests/java_index_of_char/test_index_of_char.class differ diff --git a/regression/strings-smoke-tests/java_index_of_char/test_index_of_char.java b/regression/strings-smoke-tests/java_index_of_char/test_index_of_char.java new file mode 100644 index 00000000000..6a5d3d60bd6 --- /dev/null +++ b/regression/strings-smoke-tests/java_index_of_char/test_index_of_char.java @@ -0,0 +1,10 @@ +public class test_index_of_char +{ + public static void main(/*String[] argv*/) + { + String s = "Abc"; + char c = 'c'; + int i = s.indexOf(c); + assert(i == 2); + } +} diff --git a/regression/strings-smoke-tests/java_insert_char/test.desc b/regression/strings-smoke-tests/java_insert_char/test.desc new file mode 100644 index 00000000000..77d3ce2ebd9 --- /dev/null +++ b/regression/strings-smoke-tests/java_insert_char/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_insert_char.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_insert_char/test_insert_char.class b/regression/strings-smoke-tests/java_insert_char/test_insert_char.class new file mode 100644 index 00000000000..481304a9f6d Binary files /dev/null and b/regression/strings-smoke-tests/java_insert_char/test_insert_char.class differ diff --git a/regression/strings-smoke-tests/java_insert_char/test_insert_char.java b/regression/strings-smoke-tests/java_insert_char/test_insert_char.java new file mode 100644 index 00000000000..ac6beb4ffcf --- /dev/null +++ b/regression/strings-smoke-tests/java_insert_char/test_insert_char.java @@ -0,0 +1,10 @@ +public class test_insert_char +{ + public static void main(/*String[] argv*/) + { + StringBuilder sb = new StringBuilder("ac"); + sb.insert(1, 'b'); + String s = sb.toString(); + assert(s.equals("abc")); + } +} diff --git a/regression/strings-smoke-tests/java_insert_char_array/test.desc b/regression/strings-smoke-tests/java_insert_char_array/test.desc new file mode 100644 index 00000000000..d48c601b61b --- /dev/null +++ b/regression/strings-smoke-tests/java_insert_char_array/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_insert_char_array.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_insert_char_array/test_insert_char_array.class b/regression/strings-smoke-tests/java_insert_char_array/test_insert_char_array.class new file mode 100644 index 00000000000..3c0b5329230 Binary files /dev/null and b/regression/strings-smoke-tests/java_insert_char_array/test_insert_char_array.class differ diff --git a/regression/strings-smoke-tests/java_insert_char_array/test_insert_char_array.java b/regression/strings-smoke-tests/java_insert_char_array/test_insert_char_array.java new file mode 100644 index 00000000000..2c2840df672 --- /dev/null +++ b/regression/strings-smoke-tests/java_insert_char_array/test_insert_char_array.java @@ -0,0 +1,14 @@ +public class test_insert_char_array +{ + public static void main(/*String[] argv*/) + { + StringBuilder sb = new StringBuilder("ad"); + char[] array = new char[2]; + array[0] = 'b'; + array[1] = 'c'; + sb.insert(1, array); + String s = sb.toString(); + System.out.println(s); + assert(s.equals("abcd")); + } +} diff --git a/regression/strings-smoke-tests/java_insert_int/test.desc b/regression/strings-smoke-tests/java_insert_int/test.desc new file mode 100644 index 00000000000..dc039fedbea --- /dev/null +++ b/regression/strings-smoke-tests/java_insert_int/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_insert_int.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_insert_int/test_insert_int.class b/regression/strings-smoke-tests/java_insert_int/test_insert_int.class new file mode 100644 index 00000000000..8b0121ec681 Binary files /dev/null and b/regression/strings-smoke-tests/java_insert_int/test_insert_int.class differ diff --git a/regression/strings-smoke-tests/java_insert_int/test_insert_int.java b/regression/strings-smoke-tests/java_insert_int/test_insert_int.java new file mode 100644 index 00000000000..b787141e51a --- /dev/null +++ b/regression/strings-smoke-tests/java_insert_int/test_insert_int.java @@ -0,0 +1,10 @@ +public class test_insert_int +{ + public static void main(/*String[] argv*/) + { + StringBuilder sb = new StringBuilder("ac"); + sb.insert(1, 42); + String s = sb.toString(); + assert(s.equals("a42c")); + } +} diff --git a/regression/strings-smoke-tests/java_insert_multiple/.test_insert.java.swp b/regression/strings-smoke-tests/java_insert_multiple/.test_insert.java.swp new file mode 100644 index 00000000000..5596a2c906d Binary files /dev/null and b/regression/strings-smoke-tests/java_insert_multiple/.test_insert.java.swp differ diff --git a/regression/strings-smoke-tests/java_insert_multiple/test.desc b/regression/strings-smoke-tests/java_insert_multiple/test.desc new file mode 100644 index 00000000000..983d416dd3b --- /dev/null +++ b/regression/strings-smoke-tests/java_insert_multiple/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_insert_multiple.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_insert_multiple/test_insert_multiple.class b/regression/strings-smoke-tests/java_insert_multiple/test_insert_multiple.class new file mode 100644 index 00000000000..17ced6ec67c Binary files /dev/null and b/regression/strings-smoke-tests/java_insert_multiple/test_insert_multiple.class differ diff --git a/regression/strings-smoke-tests/java_insert_multiple/test_insert_multiple.java b/regression/strings-smoke-tests/java_insert_multiple/test_insert_multiple.java new file mode 100644 index 00000000000..cce6881ca7d --- /dev/null +++ b/regression/strings-smoke-tests/java_insert_multiple/test_insert_multiple.java @@ -0,0 +1,11 @@ +public class test_insert_multiple +{ + public static void main(/*String[] argv*/) + { + StringBuilder sb = new StringBuilder("ad"); + sb.insert(1, 'c'); + sb.insert(1, "b"); + String s = sb.toString(); + assert(s.equals("abcd")); + } +} diff --git a/regression/strings-smoke-tests/java_insert_string/test.desc b/regression/strings-smoke-tests/java_insert_string/test.desc new file mode 100644 index 00000000000..b438d32d6d9 --- /dev/null +++ b/regression/strings-smoke-tests/java_insert_string/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_insert_string.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_insert_string/test_insert_string.class b/regression/strings-smoke-tests/java_insert_string/test_insert_string.class new file mode 100644 index 00000000000..39cc969a902 Binary files /dev/null and b/regression/strings-smoke-tests/java_insert_string/test_insert_string.class differ diff --git a/regression/strings-smoke-tests/java_insert_string/test_insert_string.java b/regression/strings-smoke-tests/java_insert_string/test_insert_string.java new file mode 100644 index 00000000000..7c161205131 --- /dev/null +++ b/regression/strings-smoke-tests/java_insert_string/test_insert_string.java @@ -0,0 +1,10 @@ +public class test_insert_string +{ + public static void main(/*String[] argv*/) + { + StringBuilder sb = new StringBuilder("ad"); + sb.insert(1, "bc"); + String s = sb.toString(); + assert(s.equals("abcd")); + } +} diff --git a/regression/strings-smoke-tests/java_int_to_string/test.desc b/regression/strings-smoke-tests/java_int_to_string/test.desc new file mode 100644 index 00000000000..a615a10f538 --- /dev/null +++ b/regression/strings-smoke-tests/java_int_to_string/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_int.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_int_to_string/test_int.class b/regression/strings-smoke-tests/java_int_to_string/test_int.class new file mode 100644 index 00000000000..eff0e5a422e Binary files /dev/null and b/regression/strings-smoke-tests/java_int_to_string/test_int.class differ diff --git a/regression/strings-smoke-tests/java_int_to_string/test_int.java b/regression/strings-smoke-tests/java_int_to_string/test_int.java new file mode 100644 index 00000000000..f46411ed166 --- /dev/null +++ b/regression/strings-smoke-tests/java_int_to_string/test_int.java @@ -0,0 +1,11 @@ +public class test_int +{ + public static void main(/*String[] argv*/) + { + String s = Integer.toString(12); + assert(s.equals("12")); + String t = Integer.toString(-23); + System.out.println(t); + assert(t.equals("-23")); + } +} diff --git a/regression/strings-smoke-tests/java_intern/test.desc b/regression/strings-smoke-tests/java_intern/test.desc new file mode 100644 index 00000000000..645e267029c --- /dev/null +++ b/regression/strings-smoke-tests/java_intern/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_intern.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 9.* SUCCESS$ +-- diff --git a/regression/strings-smoke-tests/java_intern/test_intern.class b/regression/strings-smoke-tests/java_intern/test_intern.class new file mode 100644 index 00000000000..894615c0a9a Binary files /dev/null and b/regression/strings-smoke-tests/java_intern/test_intern.class differ diff --git a/regression/strings-smoke-tests/java_intern/test_intern.java b/regression/strings-smoke-tests/java_intern/test_intern.java new file mode 100644 index 00000000000..7f9d5283597 --- /dev/null +++ b/regression/strings-smoke-tests/java_intern/test_intern.java @@ -0,0 +1,11 @@ +public class test_intern +{ + public static void main(/*String[] argv*/) + { + String s1 = "abc"; + String s3 = "abc"; + String x = s1.intern(); + String y = s3.intern(); + assert(x == y); + } +} diff --git a/regression/strings-smoke-tests/java_last_index_of/test.desc b/regression/strings-smoke-tests/java_last_index_of/test.desc new file mode 100644 index 00000000000..77bc5b7f18f --- /dev/null +++ b/regression/strings-smoke-tests/java_last_index_of/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_last_index_of.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_last_index_of/test_last_index_of.class b/regression/strings-smoke-tests/java_last_index_of/test_last_index_of.class new file mode 100644 index 00000000000..4455da4d179 Binary files /dev/null and b/regression/strings-smoke-tests/java_last_index_of/test_last_index_of.class differ diff --git a/regression/strings-smoke-tests/java_last_index_of/test_last_index_of.java b/regression/strings-smoke-tests/java_last_index_of/test_last_index_of.java new file mode 100644 index 00000000000..8b3a0904d5b --- /dev/null +++ b/regression/strings-smoke-tests/java_last_index_of/test_last_index_of.java @@ -0,0 +1,10 @@ +public class test_last_index_of +{ + public static void main(/*String[] argv*/) + { + String s = "abcab"; + String ab = "ab"; + int i = s.lastIndexOf(ab); + assert(i == 3); + } +} diff --git a/regression/strings-smoke-tests/java_last_index_of_char/test.desc b/regression/strings-smoke-tests/java_last_index_of_char/test.desc new file mode 100644 index 00000000000..3e9a3d4b547 --- /dev/null +++ b/regression/strings-smoke-tests/java_last_index_of_char/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_last_index_of_char.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_last_index_of_char/test_last_index_of_char.class b/regression/strings-smoke-tests/java_last_index_of_char/test_last_index_of_char.class new file mode 100644 index 00000000000..388717f4261 Binary files /dev/null and b/regression/strings-smoke-tests/java_last_index_of_char/test_last_index_of_char.class differ diff --git a/regression/strings-smoke-tests/java_last_index_of_char/test_last_index_of_char.java b/regression/strings-smoke-tests/java_last_index_of_char/test_last_index_of_char.java new file mode 100644 index 00000000000..029d59c9d68 --- /dev/null +++ b/regression/strings-smoke-tests/java_last_index_of_char/test_last_index_of_char.java @@ -0,0 +1,9 @@ +public class test_last_index_of_char +{ + public static void main(/*String[] argv*/) + { + String s = "abcab"; + int n = s.lastIndexOf('a'); + assert(n == 3); + } +} diff --git a/regression/strings-smoke-tests/java_length/test.desc b/regression/strings-smoke-tests/java_length/test.desc new file mode 100644 index 00000000000..913afbf13c7 --- /dev/null +++ b/regression/strings-smoke-tests/java_length/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_length.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_length/test_length.class b/regression/strings-smoke-tests/java_length/test_length.class new file mode 100644 index 00000000000..9273d09869b Binary files /dev/null and b/regression/strings-smoke-tests/java_length/test_length.class differ diff --git a/regression/strings-smoke-tests/java_length/test_length.java b/regression/strings-smoke-tests/java_length/test_length.java new file mode 100644 index 00000000000..4222414fa80 --- /dev/null +++ b/regression/strings-smoke-tests/java_length/test_length.java @@ -0,0 +1,9 @@ +public class test_length +{ + public static void main(/*String[] argv*/) + { + String s = new String("Abc"); + int l = s.length(); + assert(l == 3); + } +} diff --git a/regression/strings-smoke-tests/java_parseint/test.desc b/regression/strings-smoke-tests/java_parseint/test.desc new file mode 100644 index 00000000000..9cb70f5a957 --- /dev/null +++ b/regression/strings-smoke-tests/java_parseint/test.desc @@ -0,0 +1,8 @@ +FUTURE +test_parseint.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 7.* SUCCESS$ +^\[.*assertion.2\].* line 8.* FAILURE$ +-- diff --git a/regression/strings-smoke-tests/java_parseint/test_parseint.class b/regression/strings-smoke-tests/java_parseint/test_parseint.class new file mode 100644 index 00000000000..e1ffe0c7210 Binary files /dev/null and b/regression/strings-smoke-tests/java_parseint/test_parseint.class differ diff --git a/regression/strings-smoke-tests/java_parseint/test_parseint.java b/regression/strings-smoke-tests/java_parseint/test_parseint.java new file mode 100644 index 00000000000..f278f273675 --- /dev/null +++ b/regression/strings-smoke-tests/java_parseint/test_parseint.java @@ -0,0 +1,10 @@ +public class test_parseint +{ + public static void main(String[] argv) + { + String twelve = new String("12"); + int parsed = Integer.parseInt(twelve); + assert(parsed == 12); + assert(parsed != 12); + } +} diff --git a/regression/strings-smoke-tests/java_replace/test.desc b/regression/strings-smoke-tests/java_replace/test.desc new file mode 100644 index 00000000000..59c7d326a0b --- /dev/null +++ b/regression/strings-smoke-tests/java_replace/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_replace.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_replace/test_replace.class b/regression/strings-smoke-tests/java_replace/test_replace.class new file mode 100644 index 00000000000..d15509ee8ac Binary files /dev/null and b/regression/strings-smoke-tests/java_replace/test_replace.class differ diff --git a/regression/strings-smoke-tests/java_replace/test_replace.java b/regression/strings-smoke-tests/java_replace/test_replace.java new file mode 100644 index 00000000000..07e7ac036b9 --- /dev/null +++ b/regression/strings-smoke-tests/java_replace/test_replace.java @@ -0,0 +1,13 @@ +public class test_replace +{ + public static void main(/*String[] argv*/) + { + String s = new String("abcabd"); + String u = s.replace("d","z"); + System.out.println(u); + assert(u.equals("abcabz")); + String v = u.replace("ab","w"); + System.out.println(v); + assert(v.equals("wcwz")); + } +} diff --git a/regression/strings-smoke-tests/java_replace_char/test.desc b/regression/strings-smoke-tests/java_replace_char/test.desc new file mode 100644 index 00000000000..528d4eead6c --- /dev/null +++ b/regression/strings-smoke-tests/java_replace_char/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_replace_char.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_replace_char/test_replace_char.class b/regression/strings-smoke-tests/java_replace_char/test_replace_char.class new file mode 100644 index 00000000000..64626b3b09d Binary files /dev/null and b/regression/strings-smoke-tests/java_replace_char/test_replace_char.class differ diff --git a/regression/strings-smoke-tests/java_replace_char/test_replace_char.java b/regression/strings-smoke-tests/java_replace_char/test_replace_char.java new file mode 100644 index 00000000000..82a023924e2 --- /dev/null +++ b/regression/strings-smoke-tests/java_replace_char/test_replace_char.java @@ -0,0 +1,9 @@ +public class test_replace_char +{ + public static void main(/*String[] argv*/) + { + String s = new String("abcabd"); + String t = s.replace('b','m'); + assert(t.equals("amcamd")); + } +} diff --git a/regression/strings-smoke-tests/java_set_char_at/test.desc b/regression/strings-smoke-tests/java_set_char_at/test.desc new file mode 100644 index 00000000000..650e7712278 --- /dev/null +++ b/regression/strings-smoke-tests/java_set_char_at/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_set_char_at.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_set_char_at/test_set_char_at.class b/regression/strings-smoke-tests/java_set_char_at/test_set_char_at.class new file mode 100644 index 00000000000..6e843afbe2a Binary files /dev/null and b/regression/strings-smoke-tests/java_set_char_at/test_set_char_at.class differ diff --git a/regression/strings-smoke-tests/java_set_char_at/test_set_char_at.java b/regression/strings-smoke-tests/java_set_char_at/test_set_char_at.java new file mode 100644 index 00000000000..fd1d1fbf9e2 --- /dev/null +++ b/regression/strings-smoke-tests/java_set_char_at/test_set_char_at.java @@ -0,0 +1,13 @@ +public class test_set_char_at +{ + public static void main(/*String[] argv*/) + { + String s = new String("Abc"); + char c = s.charAt(1); + StringBuilder sb = new StringBuilder(s); + sb.setCharAt(1,'w'); + s = sb.toString(); + assert(s.equals("Awc")); + assert(s.charAt(2)=='c'); + } +} diff --git a/regression/strings-smoke-tests/java_set_length/test.desc b/regression/strings-smoke-tests/java_set_length/test.desc new file mode 100644 index 00000000000..ab59e459eb1 --- /dev/null +++ b/regression/strings-smoke-tests/java_set_length/test.desc @@ -0,0 +1,9 @@ +FUTURE +test_set_length.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 8.* SUCCESS$ +^\[.*assertion.2\].* line 9.* SUCCESS$ +^\[.*assertion.3\].* line 10.* FAILURE$ +-- diff --git a/regression/strings-smoke-tests/java_set_length/test_set_length.class b/regression/strings-smoke-tests/java_set_length/test_set_length.class new file mode 100644 index 00000000000..8cb9e416191 Binary files /dev/null and b/regression/strings-smoke-tests/java_set_length/test_set_length.class differ diff --git a/regression/strings-smoke-tests/java_set_length/test_set_length.java b/regression/strings-smoke-tests/java_set_length/test_set_length.java new file mode 100644 index 00000000000..5894b27beeb --- /dev/null +++ b/regression/strings-smoke-tests/java_set_length/test_set_length.java @@ -0,0 +1,12 @@ +public class test_set_length +{ + public static void main(/*String[] argv*/) + { + StringBuilder s = new StringBuilder("abc"); + s.setLength(10); + String t = s.toString(); + assert(t.startsWith("abc")); + assert(t.length() == 10); + assert(t.length() == 3); + } +} diff --git a/regression/strings-smoke-tests/java_starts_with/test.desc b/regression/strings-smoke-tests/java_starts_with/test.desc new file mode 100644 index 00000000000..5c5d85565c2 --- /dev/null +++ b/regression/strings-smoke-tests/java_starts_with/test.desc @@ -0,0 +1,8 @@ +FUTURE +test_starts_with.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 8.* SUCCESS$ +^\[.*assertion.2\].* line 9.* FAILURE$ +-- diff --git a/regression/strings-smoke-tests/java_starts_with/test_starts_with.class b/regression/strings-smoke-tests/java_starts_with/test_starts_with.class new file mode 100644 index 00000000000..da1decd8d35 Binary files /dev/null and b/regression/strings-smoke-tests/java_starts_with/test_starts_with.class differ diff --git a/regression/strings-smoke-tests/java_starts_with/test_starts_with.java b/regression/strings-smoke-tests/java_starts_with/test_starts_with.java new file mode 100644 index 00000000000..aba79d846c0 --- /dev/null +++ b/regression/strings-smoke-tests/java_starts_with/test_starts_with.java @@ -0,0 +1,11 @@ +public class test_starts_with +{ + public static void main(/*String[] argv*/) + { + String s = new String("Abcd"); + String pref = "Ab"; + String bad_pref = "bc"; + assert(s.startsWith(pref)); + assert(s.startsWith(bad_pref)); + } +} diff --git a/regression/strings-smoke-tests/java_string_builder_length/test.desc b/regression/strings-smoke-tests/java_string_builder_length/test.desc new file mode 100644 index 00000000000..ba9187109ed --- /dev/null +++ b/regression/strings-smoke-tests/java_string_builder_length/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_sb_length.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_string_builder_length/test_sb_length.class b/regression/strings-smoke-tests/java_string_builder_length/test_sb_length.class new file mode 100644 index 00000000000..cfc35874d26 Binary files /dev/null and b/regression/strings-smoke-tests/java_string_builder_length/test_sb_length.class differ diff --git a/regression/strings-smoke-tests/java_string_builder_length/test_sb_length.java b/regression/strings-smoke-tests/java_string_builder_length/test_sb_length.java new file mode 100644 index 00000000000..b616749ffb4 --- /dev/null +++ b/regression/strings-smoke-tests/java_string_builder_length/test_sb_length.java @@ -0,0 +1,9 @@ +public class test_sb_length +{ + public static void main(/*String[] argv*/) + { + StringBuilder x = new StringBuilder("abc"); + x.append("de"); + assert(x.length() == 5); + } +} diff --git a/regression/strings-smoke-tests/java_subsequence/test.desc b/regression/strings-smoke-tests/java_subsequence/test.desc new file mode 100644 index 00000000000..34585a7900d --- /dev/null +++ b/regression/strings-smoke-tests/java_subsequence/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_subsequence.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_subsequence/test_subsequence.class b/regression/strings-smoke-tests/java_subsequence/test_subsequence.class new file mode 100644 index 00000000000..0f8410939e1 Binary files /dev/null and b/regression/strings-smoke-tests/java_subsequence/test_subsequence.class differ diff --git a/regression/strings-smoke-tests/java_subsequence/test_subsequence.java b/regression/strings-smoke-tests/java_subsequence/test_subsequence.java new file mode 100644 index 00000000000..4d8d79cb381 --- /dev/null +++ b/regression/strings-smoke-tests/java_subsequence/test_subsequence.java @@ -0,0 +1,14 @@ +public class test_subsequence +{ + public static void main(/*String[] argv*/) + { + String abcdef = "AbcDef"; + CharSequence cde = abcdef.subSequence(2,5); + char c = cde.charAt(0); + char d = cde.charAt(1); + char e = cde.charAt(2); + assert(c == 'c'); + assert(d == 'D'); + assert(e == 'e'); + } +} diff --git a/regression/strings-smoke-tests/java_substring/test.desc b/regression/strings-smoke-tests/java_substring/test.desc new file mode 100644 index 00000000000..8a29460f529 --- /dev/null +++ b/regression/strings-smoke-tests/java_substring/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_substring.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings-smoke-tests/java_substring/test_substring.class b/regression/strings-smoke-tests/java_substring/test_substring.class new file mode 100644 index 00000000000..3ba0b60e7f2 Binary files /dev/null and b/regression/strings-smoke-tests/java_substring/test_substring.class differ diff --git a/regression/strings-smoke-tests/java_substring/test_substring.java b/regression/strings-smoke-tests/java_substring/test_substring.java new file mode 100644 index 00000000000..03a33fdbebd --- /dev/null +++ b/regression/strings-smoke-tests/java_substring/test_substring.java @@ -0,0 +1,14 @@ +public class test_substring +{ + public static void main(/*String[] argv*/) + { + String abcdef = "AbcDef"; + String cde = abcdef.substring(2,5); + char c = cde.charAt(0); + char d = cde.charAt(1); + char e = cde.charAt(2); + assert(c == 'c'); + assert(d == 'D'); + assert(e == 'e'); + } +} diff --git a/regression/strings-smoke-tests/java_trim/test.desc b/regression/strings-smoke-tests/java_trim/test.desc new file mode 100644 index 00000000000..c7a307c37ed --- /dev/null +++ b/regression/strings-smoke-tests/java_trim/test.desc @@ -0,0 +1,8 @@ +FUTURE +test_trim.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 6.* SUCCESS$ +^\[.*assertion.2\].* line 7.* FAILURE$ +-- diff --git a/regression/strings-smoke-tests/java_trim/test_trim.class b/regression/strings-smoke-tests/java_trim/test_trim.class new file mode 100644 index 00000000000..33b34714ae2 Binary files /dev/null and b/regression/strings-smoke-tests/java_trim/test_trim.class differ diff --git a/regression/strings-smoke-tests/java_trim/test_trim.java b/regression/strings-smoke-tests/java_trim/test_trim.java new file mode 100644 index 00000000000..20dd7ba2796 --- /dev/null +++ b/regression/strings-smoke-tests/java_trim/test_trim.java @@ -0,0 +1,9 @@ +public class test_trim +{ + public static void main(/*String[] argv*/) + { + String empty = " "; + assert(empty.trim().isEmpty()); + assert(empty.isEmpty()); + } +} diff --git a/regression/strings/RegexMatches01/test.desc b/regression/strings/RegexMatches01/test.desc index 45cc542b352..e4259466e6b 100644 --- a/regression/strings/RegexMatches01/test.desc +++ b/regression/strings/RegexMatches01/test.desc @@ -1,6 +1,6 @@ FUTURE RegexMatches01.class ---string-refine --unwind 100 +--refine-strings --unwind 100 ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/RegexMatches02/test.desc b/regression/strings/RegexMatches02/test.desc index 86353d9a54c..006922c3d6a 100644 --- a/regression/strings/RegexMatches02/test.desc +++ b/regression/strings/RegexMatches02/test.desc @@ -1,6 +1,6 @@ FUTURE RegexMatches02.class ---string-refine --unwind 100 +--refine-strings --unwind 100 ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/RegexSubstitution01/test.desc b/regression/strings/RegexSubstitution01/test.desc index bc7ed3648f3..ccf24b2e8fa 100644 --- a/regression/strings/RegexSubstitution01/test.desc +++ b/regression/strings/RegexSubstitution01/test.desc @@ -1,6 +1,6 @@ FUTURE RegexSubstitution01.class ---string-refine +--refine-strings ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/RegexSubstitution02/test.desc b/regression/strings/RegexSubstitution02/test.desc index 0645c3ac9b8..7064bcc0333 100644 --- a/regression/strings/RegexSubstitution02/test.desc +++ b/regression/strings/RegexSubstitution02/test.desc @@ -1,6 +1,6 @@ FUTURE RegexSubstitution02.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/RegexSubstitution03/test.desc b/regression/strings/RegexSubstitution03/test.desc index 20da1478b1a..4b0d5739c42 100644 --- a/regression/strings/RegexSubstitution03/test.desc +++ b/regression/strings/RegexSubstitution03/test.desc @@ -1,6 +1,6 @@ FUTURE RegexSubstitution03.class ---string-refine +--refine-strings ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/StaticCharMethods01/test.desc b/regression/strings/StaticCharMethods01/test.desc index 4b633e92bcf..a40f4534120 100644 --- a/regression/strings/StaticCharMethods01/test.desc +++ b/regression/strings/StaticCharMethods01/test.desc @@ -1,6 +1,6 @@ FUTURE StaticCharMethods01.class ---string-refine +--refine-strings ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/StaticCharMethods02/test.desc b/regression/strings/StaticCharMethods02/test.desc index 00aaaba8964..9366df6fa57 100644 --- a/regression/strings/StaticCharMethods02/test.desc +++ b/regression/strings/StaticCharMethods02/test.desc @@ -1,6 +1,6 @@ FUTURE StaticCharMethods02.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StaticCharMethods03/test.desc b/regression/strings/StaticCharMethods03/test.desc index 6f3d3bc5607..caba8503984 100644 --- a/regression/strings/StaticCharMethods03/test.desc +++ b/regression/strings/StaticCharMethods03/test.desc @@ -1,6 +1,6 @@ FUTURE StaticCharMethods03.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StaticCharMethods04/test.desc b/regression/strings/StaticCharMethods04/test.desc index 0c9484ef337..1f686c041c2 100644 --- a/regression/strings/StaticCharMethods04/test.desc +++ b/regression/strings/StaticCharMethods04/test.desc @@ -1,6 +1,6 @@ FUTURE StaticCharMethods04.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StaticCharMethods05/test.desc b/regression/strings/StaticCharMethods05/test.desc index 5b4a6b4b622..b21901ac84a 100644 --- a/regression/strings/StaticCharMethods05/test.desc +++ b/regression/strings/StaticCharMethods05/test.desc @@ -1,6 +1,6 @@ FUTURE StaticCharMethods05.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StaticCharMethods06/test.desc b/regression/strings/StaticCharMethods06/test.desc index 6f351b2c7cf..3caa6a7b878 100644 --- a/regression/strings/StaticCharMethods06/test.desc +++ b/regression/strings/StaticCharMethods06/test.desc @@ -1,6 +1,6 @@ FUTURE StaticCharMethods06.class ---string-refine +--refine-strings ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/StringBuilderAppend01/test.desc b/regression/strings/StringBuilderAppend01/test.desc index f1f89b629be..d0207fc9ea7 100644 --- a/regression/strings/StringBuilderAppend01/test.desc +++ b/regression/strings/StringBuilderAppend01/test.desc @@ -1,6 +1,6 @@ FUTURE StringBuilderAppend01.class ---string-refine +--refine-strings ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/StringBuilderAppend02/test.desc b/regression/strings/StringBuilderAppend02/test.desc index 1336c45c3d2..70357b670d8 100644 --- a/regression/strings/StringBuilderAppend02/test.desc +++ b/regression/strings/StringBuilderAppend02/test.desc @@ -1,6 +1,6 @@ FUTURE StringBuilderAppend02.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringBuilderCapLen01/test.desc b/regression/strings/StringBuilderCapLen01/test.desc index 05516f08da2..4186f2534ac 100644 --- a/regression/strings/StringBuilderCapLen01/test.desc +++ b/regression/strings/StringBuilderCapLen01/test.desc @@ -1,6 +1,6 @@ FUTURE StringBuilderCapLen01.class ---string-refine +--refine-strings ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/StringBuilderCapLen02/test.desc b/regression/strings/StringBuilderCapLen02/test.desc index 72a0bbd72c2..f9db006ed0b 100644 --- a/regression/strings/StringBuilderCapLen02/test.desc +++ b/regression/strings/StringBuilderCapLen02/test.desc @@ -1,6 +1,6 @@ FUTURE StringBuilderCapLen02.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringBuilderCapLen03/test.desc b/regression/strings/StringBuilderCapLen03/test.desc index 474bdc661ab..c35dfb33871 100644 --- a/regression/strings/StringBuilderCapLen03/test.desc +++ b/regression/strings/StringBuilderCapLen03/test.desc @@ -1,6 +1,6 @@ FUTURE StringBuilderCapLen03.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringBuilderCapLen04/test.desc b/regression/strings/StringBuilderCapLen04/test.desc index fa342b79518..78930851e45 100644 --- a/regression/strings/StringBuilderCapLen04/test.desc +++ b/regression/strings/StringBuilderCapLen04/test.desc @@ -1,6 +1,6 @@ FUTURE StringBuilderCapLen04.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringBuilderChars01/test.desc b/regression/strings/StringBuilderChars01/test.desc index 41dfe54abeb..48acfb25a5d 100644 --- a/regression/strings/StringBuilderChars01/test.desc +++ b/regression/strings/StringBuilderChars01/test.desc @@ -1,6 +1,6 @@ FUTURE StringBuilderChars01.class ---string-refine --unwind 100 +--refine-strings --unwind 100 ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/StringBuilderChars02/test.desc b/regression/strings/StringBuilderChars02/test.desc index 50e49d474bc..d9006ab74ba 100644 --- a/regression/strings/StringBuilderChars02/test.desc +++ b/regression/strings/StringBuilderChars02/test.desc @@ -1,6 +1,6 @@ FUTURE StringBuilderChars02.class ---string-refine --unwind 100 +--refine-strings --unwind 100 ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringBuilderChars03/test.desc b/regression/strings/StringBuilderChars03/test.desc index 23dda39df4e..d6f1cb4155c 100644 --- a/regression/strings/StringBuilderChars03/test.desc +++ b/regression/strings/StringBuilderChars03/test.desc @@ -1,6 +1,6 @@ FUTURE StringBuilderChars03.class ---string-refine --unwind 100 +--refine-strings --unwind 100 ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringBuilderChars04/test.desc b/regression/strings/StringBuilderChars04/test.desc index a68edd89395..37009795a48 100644 --- a/regression/strings/StringBuilderChars04/test.desc +++ b/regression/strings/StringBuilderChars04/test.desc @@ -1,6 +1,6 @@ FUTURE StringBuilderChars04.class ---string-refine --unwind 100 +--refine-strings --unwind 100 ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringBuilderChars05/test.desc b/regression/strings/StringBuilderChars05/test.desc index eeac328e02b..49aed9d48fd 100644 --- a/regression/strings/StringBuilderChars05/test.desc +++ b/regression/strings/StringBuilderChars05/test.desc @@ -1,6 +1,6 @@ FUTURE StringBuilderChars05.class ---string-refine --unwind 100 +--refine-strings --unwind 100 ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringBuilderChars06/test.desc b/regression/strings/StringBuilderChars06/test.desc index a3dc3712a5a..5ccf470590e 100644 --- a/regression/strings/StringBuilderChars06/test.desc +++ b/regression/strings/StringBuilderChars06/test.desc @@ -1,6 +1,6 @@ FUTURE StringBuilderChars06.class ---string-refine --unwind 100 +--refine-strings --unwind 100 ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringBuilderConstructors01/test.desc b/regression/strings/StringBuilderConstructors01/test.desc index 2c60f9bbbda..3e27d46c329 100644 --- a/regression/strings/StringBuilderConstructors01/test.desc +++ b/regression/strings/StringBuilderConstructors01/test.desc @@ -1,6 +1,6 @@ KNOWNBUG StringBuilderConstructors01.class ---string-refine +--refine-strings ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/StringBuilderConstructors02/test.desc b/regression/strings/StringBuilderConstructors02/test.desc index 5e951bc8079..f6c0cded34e 100644 --- a/regression/strings/StringBuilderConstructors02/test.desc +++ b/regression/strings/StringBuilderConstructors02/test.desc @@ -1,6 +1,6 @@ KNOWNBUG StringBuilderConstructors02.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringBuilderInsertDelete01/test.desc b/regression/strings/StringBuilderInsertDelete01/test.desc index 4c3000d6a97..b2f927ad3b7 100644 --- a/regression/strings/StringBuilderInsertDelete01/test.desc +++ b/regression/strings/StringBuilderInsertDelete01/test.desc @@ -1,6 +1,6 @@ FUTURE StringBuilderInsertDelete01.class ---string-refine +--refine-strings ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/StringBuilderInsertDelete02/test.desc b/regression/strings/StringBuilderInsertDelete02/test.desc index ae4d0ca5b81..1e67f7eb3c0 100644 --- a/regression/strings/StringBuilderInsertDelete02/test.desc +++ b/regression/strings/StringBuilderInsertDelete02/test.desc @@ -1,6 +1,6 @@ FUTURE StringBuilderInsertDelete02.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringBuilderInsertDelete03/test.desc b/regression/strings/StringBuilderInsertDelete03/test.desc index 3dfa92f0338..084038f4465 100644 --- a/regression/strings/StringBuilderInsertDelete03/test.desc +++ b/regression/strings/StringBuilderInsertDelete03/test.desc @@ -1,6 +1,6 @@ FUTURE StringBuilderInsertDelete03.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringCompare01/test.desc b/regression/strings/StringCompare01/test.desc index 52b1d6d084c..007a6f798a7 100644 --- a/regression/strings/StringCompare01/test.desc +++ b/regression/strings/StringCompare01/test.desc @@ -1,6 +1,6 @@ FUTURE StringCompare01.class ---string-refine +--refine-strings ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/StringCompare02/test.desc b/regression/strings/StringCompare02/test.desc index eb52d1f1a58..971e6a98c81 100644 --- a/regression/strings/StringCompare02/test.desc +++ b/regression/strings/StringCompare02/test.desc @@ -1,6 +1,6 @@ FUTURE StringCompare02.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringCompare03/test.desc b/regression/strings/StringCompare03/test.desc index bd0f3177acf..acc89c80c4a 100644 --- a/regression/strings/StringCompare03/test.desc +++ b/regression/strings/StringCompare03/test.desc @@ -1,6 +1,6 @@ FUTURE StringCompare03.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringCompare04/test.desc b/regression/strings/StringCompare04/test.desc index 88ecddbfcf6..3ea3cbd7592 100644 --- a/regression/strings/StringCompare04/test.desc +++ b/regression/strings/StringCompare04/test.desc @@ -1,6 +1,6 @@ FUTURE StringCompare04.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringCompare05/test.desc b/regression/strings/StringCompare05/test.desc index 1358a05a36b..ef6aac2b72e 100644 --- a/regression/strings/StringCompare05/test.desc +++ b/regression/strings/StringCompare05/test.desc @@ -1,6 +1,6 @@ FUTURE StringCompare05.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringConcatenation01/test.desc b/regression/strings/StringConcatenation01/test.desc index a229b504571..6465f209faa 100644 --- a/regression/strings/StringConcatenation01/test.desc +++ b/regression/strings/StringConcatenation01/test.desc @@ -1,6 +1,6 @@ KNOWNBUG StringConcatenation01.class ---string-refine +--refine-strings ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/StringConcatenation02/test.desc b/regression/strings/StringConcatenation02/test.desc index 0e1faf53d5e..e6ea2349af8 100644 --- a/regression/strings/StringConcatenation02/test.desc +++ b/regression/strings/StringConcatenation02/test.desc @@ -1,6 +1,6 @@ KNOWNBUG StringConcatenation02.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringConcatenation03/test.desc b/regression/strings/StringConcatenation03/test.desc index 3c01a4ee0a9..ecb497de375 100644 --- a/regression/strings/StringConcatenation03/test.desc +++ b/regression/strings/StringConcatenation03/test.desc @@ -1,6 +1,6 @@ FUTURE StringConcatenation03.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringConcatenation04/test.desc b/regression/strings/StringConcatenation04/test.desc index 3dbecf065ba..1425e609a3a 100644 --- a/regression/strings/StringConcatenation04/test.desc +++ b/regression/strings/StringConcatenation04/test.desc @@ -1,6 +1,6 @@ FUTURE StringConcatenation04.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringConstructors01/test.desc b/regression/strings/StringConstructors01/test.desc index ed57bdfdde5..b1465868c19 100644 --- a/regression/strings/StringConstructors01/test.desc +++ b/regression/strings/StringConstructors01/test.desc @@ -1,6 +1,6 @@ FUTURE StringConstructors01.class ---string-refine +--refine-strings ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/StringConstructors02/test.desc b/regression/strings/StringConstructors02/test.desc index e3904d1d557..37838aafbc9 100644 --- a/regression/strings/StringConstructors02/test.desc +++ b/regression/strings/StringConstructors02/test.desc @@ -1,6 +1,6 @@ FUTURE StringConstructors02.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringConstructors03/test.desc b/regression/strings/StringConstructors03/test.desc index 0caf75f41ea..10193fc66c2 100644 --- a/regression/strings/StringConstructors03/test.desc +++ b/regression/strings/StringConstructors03/test.desc @@ -1,6 +1,6 @@ FUTURE StringConstructors03.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringConstructors04/test.desc b/regression/strings/StringConstructors04/test.desc index 75364dcde22..2e6e88fa862 100644 --- a/regression/strings/StringConstructors04/test.desc +++ b/regression/strings/StringConstructors04/test.desc @@ -1,6 +1,6 @@ FUTURE StringConstructors04.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringConstructors05/test.desc b/regression/strings/StringConstructors05/test.desc index e74dfc73f6c..a3c6a6c0437 100644 --- a/regression/strings/StringConstructors05/test.desc +++ b/regression/strings/StringConstructors05/test.desc @@ -1,6 +1,6 @@ FUTURE StringConstructors05.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringIndexMethods01/test.desc b/regression/strings/StringIndexMethods01/test.desc index 005d4459f12..dc4c6f14324 100644 --- a/regression/strings/StringIndexMethods01/test.desc +++ b/regression/strings/StringIndexMethods01/test.desc @@ -1,6 +1,6 @@ FUTURE StringIndexMethods01.class ---string-refine +--refine-strings ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/StringIndexMethods02/test.desc b/regression/strings/StringIndexMethods02/test.desc index 28df14f0145..1114e980758 100644 --- a/regression/strings/StringIndexMethods02/test.desc +++ b/regression/strings/StringIndexMethods02/test.desc @@ -1,6 +1,6 @@ FUTURE StringIndexMethods02.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringIndexMethods03/test.desc b/regression/strings/StringIndexMethods03/test.desc index 02f9934726b..69d7e5d5745 100644 --- a/regression/strings/StringIndexMethods03/test.desc +++ b/regression/strings/StringIndexMethods03/test.desc @@ -1,6 +1,6 @@ FUTURE StringIndexMethods03.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringIndexMethods04/test.desc b/regression/strings/StringIndexMethods04/test.desc index cb94fecb6a6..0707dbe9105 100644 --- a/regression/strings/StringIndexMethods04/test.desc +++ b/regression/strings/StringIndexMethods04/test.desc @@ -1,6 +1,6 @@ FUTURE StringIndexMethods04.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringIndexMethods05/test.desc b/regression/strings/StringIndexMethods05/test.desc index cb43b009246..bfe98a03e7c 100644 --- a/regression/strings/StringIndexMethods05/test.desc +++ b/regression/strings/StringIndexMethods05/test.desc @@ -1,6 +1,6 @@ FUTURE StringIndexMethods05.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringMiscellaneous01/test.desc b/regression/strings/StringMiscellaneous01/test.desc index 050c3e99e90..624c8028cb3 100644 --- a/regression/strings/StringMiscellaneous01/test.desc +++ b/regression/strings/StringMiscellaneous01/test.desc @@ -1,6 +1,6 @@ FUTURE StringMiscellaneous01.class ---string-refine --unwind 30 +--refine-strings --unwind 30 ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/StringMiscellaneous02/test.desc b/regression/strings/StringMiscellaneous02/test.desc index 8f1a1d9475f..3fde950e418 100644 --- a/regression/strings/StringMiscellaneous02/test.desc +++ b/regression/strings/StringMiscellaneous02/test.desc @@ -1,6 +1,6 @@ FUTURE StringMiscellaneous02.class ---string-refine --unwind 30 +--refine-strings --unwind 30 ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringMiscellaneous03/test.desc b/regression/strings/StringMiscellaneous03/test.desc index 341867d536f..2a1a3f02739 100644 --- a/regression/strings/StringMiscellaneous03/test.desc +++ b/regression/strings/StringMiscellaneous03/test.desc @@ -1,6 +1,6 @@ FUTURE StringMiscellaneous03.class ---string-refine --unwind 30 +--refine-strings --unwind 30 ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringMiscellaneous04/test.desc b/regression/strings/StringMiscellaneous04/test.desc index 737ab3b0f8c..4c2c0491e5f 100644 --- a/regression/strings/StringMiscellaneous04/test.desc +++ b/regression/strings/StringMiscellaneous04/test.desc @@ -1,6 +1,6 @@ FUTURE StringMiscellaneous04.class ---string-refine --unwind 30 +--refine-strings --unwind 30 ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/StringStartEnd01/test.desc b/regression/strings/StringStartEnd01/test.desc index a5463d5b5ea..eba4f6eb2b0 100644 --- a/regression/strings/StringStartEnd01/test.desc +++ b/regression/strings/StringStartEnd01/test.desc @@ -1,6 +1,6 @@ KNOWNBUG StringStartEnd01.class ---string-refine --unwind 30 +--refine-strings --unwind 30 ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/StringStartEnd02/test.desc b/regression/strings/StringStartEnd02/test.desc index 8e623622f72..ff91ad0ce4d 100644 --- a/regression/strings/StringStartEnd02/test.desc +++ b/regression/strings/StringStartEnd02/test.desc @@ -1,6 +1,6 @@ KNOWNBUG StringStartEnd02.class ---string-refine --unwind 30 +--refine-strings --unwind 30 ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringStartEnd03/test.desc b/regression/strings/StringStartEnd03/test.desc index 2903ec98e3e..6b1695384ca 100644 --- a/regression/strings/StringStartEnd03/test.desc +++ b/regression/strings/StringStartEnd03/test.desc @@ -1,6 +1,6 @@ KNOWNBUG StringStartEnd03.class ---string-refine --unwind 15 +--refine-strings --unwind 15 ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringValueOf01/test.desc b/regression/strings/StringValueOf01/test.desc index 341f5e98975..c6098401ba0 100644 --- a/regression/strings/StringValueOf01/test.desc +++ b/regression/strings/StringValueOf01/test.desc @@ -1,6 +1,6 @@ FUTURE StringValueOf01.class ---string-refine +--refine-strings ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/StringValueOf02/test.desc b/regression/strings/StringValueOf02/test.desc index a10b398bf41..aa3fb97ba7c 100644 --- a/regression/strings/StringValueOf02/test.desc +++ b/regression/strings/StringValueOf02/test.desc @@ -1,6 +1,6 @@ FUTURE StringValueOf02.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringValueOf03/test.desc b/regression/strings/StringValueOf03/test.desc index 4ed709a2404..4c7357c2278 100644 --- a/regression/strings/StringValueOf03/test.desc +++ b/regression/strings/StringValueOf03/test.desc @@ -1,6 +1,6 @@ FUTURE StringValueOf03.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringValueOf04/test.desc b/regression/strings/StringValueOf04/test.desc index 0d8442e9de1..5cd66829b02 100644 --- a/regression/strings/StringValueOf04/test.desc +++ b/regression/strings/StringValueOf04/test.desc @@ -1,6 +1,6 @@ KNOWNBUG StringValueOf04.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringValueOf05/test.desc b/regression/strings/StringValueOf05/test.desc index f77cdef0b8e..3f5b25f9ce3 100644 --- a/regression/strings/StringValueOf05/test.desc +++ b/regression/strings/StringValueOf05/test.desc @@ -1,6 +1,6 @@ KNOWNBUG StringValueOf05.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringValueOf06/test.desc b/regression/strings/StringValueOf06/test.desc index 56551c4a14b..bf1c4048390 100644 --- a/regression/strings/StringValueOf06/test.desc +++ b/regression/strings/StringValueOf06/test.desc @@ -1,6 +1,6 @@ KNOWNBUG StringValueOf06.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringValueOf07/test.desc b/regression/strings/StringValueOf07/test.desc index 6dde9de229d..7ba53c21fb6 100644 --- a/regression/strings/StringValueOf07/test.desc +++ b/regression/strings/StringValueOf07/test.desc @@ -1,6 +1,6 @@ KNOWNBUG StringValueOf07.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringValueOf08/test.desc b/regression/strings/StringValueOf08/test.desc index 21d64075aaf..474c02ef13f 100644 --- a/regression/strings/StringValueOf08/test.desc +++ b/regression/strings/StringValueOf08/test.desc @@ -1,6 +1,6 @@ FUTURE StringValueOf08.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringValueOf09/test.desc b/regression/strings/StringValueOf09/test.desc index 4ff97a7caef..a63f7bc3e0c 100644 --- a/regression/strings/StringValueOf09/test.desc +++ b/regression/strings/StringValueOf09/test.desc @@ -1,6 +1,6 @@ FUTURE StringValueOf09.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/StringValueOf10/test.desc b/regression/strings/StringValueOf10/test.desc index 10e7f184189..3f8c5d6d60f 100644 --- a/regression/strings/StringValueOf10/test.desc +++ b/regression/strings/StringValueOf10/test.desc @@ -1,6 +1,6 @@ FUTURE StringValueOf10.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/SubString01/test.desc b/regression/strings/SubString01/test.desc index 8eea70cf458..975e4d2e0a7 100644 --- a/regression/strings/SubString01/test.desc +++ b/regression/strings/SubString01/test.desc @@ -1,6 +1,6 @@ KNOWNBUG SubString01.class ---string-refine +--refine-strings ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/SubString02/test.desc b/regression/strings/SubString02/test.desc index 063ce88f0f2..bdafa21bc63 100644 --- a/regression/strings/SubString02/test.desc +++ b/regression/strings/SubString02/test.desc @@ -1,6 +1,6 @@ KNOWNBUG SubString02.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/SubString03/test.desc b/regression/strings/SubString03/test.desc index f985329ce2d..961f1a92ce8 100644 --- a/regression/strings/SubString03/test.desc +++ b/regression/strings/SubString03/test.desc @@ -1,6 +1,6 @@ KNOWNBUG SubString03.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/TokenTest01/test.desc b/regression/strings/TokenTest01/test.desc index 02a11e8e392..122e6a8830a 100644 --- a/regression/strings/TokenTest01/test.desc +++ b/regression/strings/TokenTest01/test.desc @@ -1,6 +1,6 @@ FUTURE TokenTest01.class ---string-refine --unwind 30 +--refine-strings --unwind 30 ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/TokenTest02/test.desc b/regression/strings/TokenTest02/test.desc index 48e6b0c1ab6..6d1dabed602 100644 --- a/regression/strings/TokenTest02/test.desc +++ b/regression/strings/TokenTest02/test.desc @@ -1,6 +1,6 @@ FUTURE TokenTest02.class ---string-refine --unwind 15 +--refine-strings --unwind 15 ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/Validate01/test.desc b/regression/strings/Validate01/test.desc index e797b2735aa..649136a2956 100644 --- a/regression/strings/Validate01/test.desc +++ b/regression/strings/Validate01/test.desc @@ -1,6 +1,6 @@ FUTURE Validate01.class ---string-refine +--refine-strings ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/Validate02/test.desc b/regression/strings/Validate02/test.desc index a5a3a6f1d20..22251c38a95 100644 --- a/regression/strings/Validate02/test.desc +++ b/regression/strings/Validate02/test.desc @@ -1,6 +1,6 @@ FUTURE Validate02.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/bug-test-gen-095/test.class b/regression/strings/bug-test-gen-095/test.class new file mode 100644 index 00000000000..3895d218c3d Binary files /dev/null and b/regression/strings/bug-test-gen-095/test.class differ diff --git a/regression/strings/bug-test-gen-095/test.desc b/regression/strings/bug-test-gen-095/test.desc new file mode 100644 index 00000000000..a40f9e43402 --- /dev/null +++ b/regression/strings/bug-test-gen-095/test.desc @@ -0,0 +1,7 @@ +KNOWNBUG +test.class +--refine-strings +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/strings/bug-test-gen-095/test.java b/regression/strings/bug-test-gen-095/test.java new file mode 100644 index 00000000000..a6910527551 --- /dev/null +++ b/regression/strings/bug-test-gen-095/test.java @@ -0,0 +1,10 @@ +public class test +{ + public static void main(String[] args) + { + StringBuilder sb = new StringBuilder(args[0]); + sb.append("Z"); + String s = sb.toString(); + assert(s.equals("fg")); + } +} diff --git a/regression/strings/cprover-string-hack.h b/regression/strings/cprover-string-hack.h index 1ec17bca535..86af21533f8 100644 --- a/regression/strings/cprover-string-hack.h +++ b/regression/strings/cprover-string-hack.h @@ -1,18 +1,32 @@ -typedef struct __CPROVER_string { char *s; } __CPROVER_string; -//typedef struct __CPROVER_char { char c; } __CPROVER_char; -typedef unsigned char __CPROVER_char; +/*******************************************************************\ + +Module: Hack for C string tests + +Author: Romain Brenguier + +\*******************************************************************/ + +#ifndef CPROVER_ESSION_STRINGS_CPROVER_STRING_HACK_H +#define CPROVER_ESSION_STRINGS_CPROVER_STRING_HACK_H + +typedef struct __attribute__((__packed__)) __CPROVER_refined_string_type // NOLINT + { int length; char content[]; } __CPROVER_refined_string_type; +typedef __CPROVER_refined_string_type __CPROVER_string; //NOLINT /****************************************************************************** * CPROVER string functions ******************************************************************************/ /* returns s[p] */ -#define __CPROVER_char_at(s, p) __CPROVER_uninterpreted_string_char_at_func(s, p) +#define __CPROVER_char_at(s, p) \ + __CPROVER_uninterpreted_string_char_at_func(s, p) /* string equality */ -#define __CPROVER_string_equal(s1, s2) __CPROVER_uninterpreted_string_equal_func(s1, s2) +#define __CPROVER_string_equal(s1, s2) \ + __CPROVER_uninterpreted_string_equal_func(s1, s2) /* defines a string literal, e.g. __CPROVER_string_literal("foo") */ -#define __CPROVER_string_literal(s) __CPROVER_uninterpreted_string_literal_func(s) +#define __CPROVER_string_literal(s) \ + __CPROVER_uninterpreted_string_literal_func(s) /* defines a char literal, e.g. __CPROVER_char_literal("c"). NOTE: you * *must* use a C string literal as argument (i.e. double quotes "c", not @@ -20,30 +34,39 @@ typedef unsigned char __CPROVER_char; #define __CPROVER_char_literal(c) __CPROVER_uninterpreted_char_literal_func(c) /* produces the concatenation of s1 and s2 */ -#define __CPROVER_string_concat(s1, s2) __CPROVER_uninterpreted_string_concat_func(s1, s2) +#define __CPROVER_string_concat(s1, s2) \ + __CPROVER_uninterpreted_string_concat_func(s1, s2) /* return the length of s */ -#define __CPROVER_string_length(s) __CPROVER_uninterpreted_string_length_func(s) +#define __CPROVER_string_length(s) \ + __CPROVER_uninterpreted_string_length_func(s) /* extracts the substring between positions i and j (j not included) */ -#define __CPROVER_string_substring(s, i, j) __CPROVER_uninterpreted_string_substring_func(s, i, j) +#define __CPROVER_string_substring(s, i, j) \ + __CPROVER_uninterpreted_string_substring_func(s, i, j) /* test whether p is a prefix of s */ -#define __CPROVER_string_isprefix(p, s) __CPROVER_uninterpreted_string_is_prefix_func(p, s) +#define __CPROVER_string_isprefix(p, s) \ + __CPROVER_uninterpreted_string_is_prefix_func(p, s) /* test whether p is a suffix of s */ -#define __CPROVER_string_issuffix(p, s) __CPROVER_uninterpreted_string_is_suffix_func(p, s) +#define __CPROVER_string_issuffix(p, s) \ + __CPROVER_uninterpreted_string_is_suffix_func(p, s) /* test whether p contains s */ -#define __CPROVER_string_contains(p, s) __CPROVER_uninterpreted_string_contains_func(p, s) +#define __CPROVER_string_contains(p, s) \ + __CPROVER_uninterpreted_string_contains_func(p, s) /* first index where character c appears, -1 if not found */ -#define __CPROVER_string_index_of(s, c) __CPROVER_uninterpreted_string_index_of_func(s, c) +#define __CPROVER_string_index_of(s, c) \ + __CPROVER_uninterpreted_string_index_of_func(s, c) /* last index where character c appears */ -#define __CPROVER_string_last_index_of(s, c) __CPROVER_uninterpreted_string_last_index_of_func(s, c) +#define __CPROVER_string_last_index_of(s, c) \ + __CPROVER_uninterpreted_string_last_index_of_func(s, c) /* returns a new string obtained from s by setting s[p] = c */ -#define __CPROVER_char_set(s, p, c) __CPROVER_uninterpreted_string_char_set_func(s, p, c) +#define __CPROVER_char_set(s, p, c) \ + __CPROVER_uninterpreted_string_char_set_func(s, p, c) #define __CPROVER_string_copy(s) __CPROVER_uninterpreted_string_copy_func(s) @@ -54,19 +77,32 @@ typedef unsigned char __CPROVER_char; /****************************************************************************** * don't use these directly ******************************************************************************/ -extern __CPROVER_char __CPROVER_uninterpreted_string_char_at_func(__CPROVER_string str, int pos); -extern __CPROVER_bool __CPROVER_uninterpreted_string_equal_func(__CPROVER_string str1, __CPROVER_string str2); +extern char __CPROVER_uninterpreted_string_char_at_func( + __CPROVER_string str, int pos); +extern __CPROVER_bool __CPROVER_uninterpreted_string_equal_func( + __CPROVER_string str1, __CPROVER_string str2); extern __CPROVER_string __CPROVER_uninterpreted_string_literal_func(char * str); -extern __CPROVER_char __CPROVER_uninterpreted_char_literal_func(); -extern __CPROVER_string __CPROVER_uninterpreted_string_concat_func(__CPROVER_string str1, __CPROVER_string str2); +extern char __CPROVER_uninterpreted_char_literal_func(); +extern __CPROVER_string __CPROVER_uninterpreted_string_concat_func( + __CPROVER_string str1, __CPROVER_string str2); extern int __CPROVER_uninterpreted_string_length_func(__CPROVER_string str); -extern __CPROVER_string __CPROVER_uninterpreted_string_substring_func(__CPROVER_string str, int i, int j); -extern __CPROVER_bool __CPROVER_uninterpreted_string_is_prefix_func(__CPROVER_string pref, __CPROVER_string str); -extern __CPROVER_bool __CPROVER_uninterpreted_string_is_suffix_func(__CPROVER_string suff, __CPROVER_string str); -extern __CPROVER_bool __CPROVER_uninterpreted_string_contains_func(__CPROVER_string str1, __CPROVER_string str2); -extern int __CPROVER_uninterpreted_string_index_of_func(__CPROVER_string str, __CPROVER_char c); -extern int __CPROVER_uninterpreted_string_last_index_of_func(__CPROVER_string str, __CPROVER_char c); -extern __CPROVER_string __CPROVER_uninterpreted_string_char_set_func(__CPROVER_string str, int pos, __CPROVER_char c); -extern __CPROVER_string __CPROVER_uninterpreted_string_copy_func(__CPROVER_string str); +extern __CPROVER_string __CPROVER_uninterpreted_string_substring_func( + __CPROVER_string str, int i, int j); +extern __CPROVER_bool __CPROVER_uninterpreted_string_is_prefix_func( + __CPROVER_string pref, __CPROVER_string str); +extern __CPROVER_bool __CPROVER_uninterpreted_string_is_suffix_func( + __CPROVER_string suff, __CPROVER_string str); +extern __CPROVER_bool __CPROVER_uninterpreted_string_contains_func( + __CPROVER_string str1, __CPROVER_string str2); +extern int __CPROVER_uninterpreted_string_index_of_func( + __CPROVER_string str, char c); +extern int __CPROVER_uninterpreted_string_last_index_of_func( + __CPROVER_string str, char c); +extern __CPROVER_string __CPROVER_uninterpreted_string_char_set_func( + __CPROVER_string str, int pos, char c); +extern __CPROVER_string __CPROVER_uninterpreted_string_copy_func( + __CPROVER_string str); extern int __CPROVER_uninterpreted_string_parse_int_func(__CPROVER_string str); extern __CPROVER_string __CPROVER_uninterpreted_string_of_int_func(int i); + +#endif diff --git a/regression/strings/java_append_char/test.desc b/regression/strings/java_append_char/test.desc new file mode 100644 index 00000000000..f38fb748736 --- /dev/null +++ b/regression/strings/java_append_char/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_append_char.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 15.* FAILURE$ +-- diff --git a/regression/strings/java_append_char/test_append_char.class b/regression/strings/java_append_char/test_append_char.class new file mode 100644 index 00000000000..c0b1491423b Binary files /dev/null and b/regression/strings/java_append_char/test_append_char.class differ diff --git a/regression/strings/java_append_char/test_append_char.java b/regression/strings/java_append_char/test_append_char.java new file mode 100644 index 00000000000..90e9ab089a2 --- /dev/null +++ b/regression/strings/java_append_char/test_append_char.java @@ -0,0 +1,17 @@ +public class test_append_char +{ + public static void main(/*String[] args*/) + { + char[] diff = {'d', 'i', 'f', 'f'}; + char[] blue = {'b', 'l', 'u', 'e'}; + + StringBuilder buffer = new StringBuilder(); + + buffer.append(diff) + .append(blue); + + String tmp=buffer.toString(); + System.out.println(tmp); + assert(!tmp.equals("diffblue")); + } +} diff --git a/regression/strings/java_append_int/test.desc b/regression/strings/java_append_int/test.desc new file mode 100644 index 00000000000..d65eecf13f5 --- /dev/null +++ b/regression/strings/java_append_int/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_append_int.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 9.* FAILURE$ +-- diff --git a/regression/strings/java_append_int/test_append_int.class b/regression/strings/java_append_int/test_append_int.class new file mode 100644 index 00000000000..d9ee5046e7d Binary files /dev/null and b/regression/strings/java_append_int/test_append_int.class differ diff --git a/regression/strings/java_append_int/test_append_int.java b/regression/strings/java_append_int/test_append_int.java new file mode 100644 index 00000000000..cf550211ad7 --- /dev/null +++ b/regression/strings/java_append_int/test_append_int.java @@ -0,0 +1,11 @@ +public class test_append_int +{ + public static void main(/*String[] args*/) + { + StringBuilder diffblue = new StringBuilder(); + diffblue.append("d"); + diffblue.append(4); + String s = diffblue.toString(); + assert(!s.equals("d4")); + } +} diff --git a/regression/strings/java_append_object/test.desc b/regression/strings/java_append_object/test.desc new file mode 100644 index 00000000000..f15910bca93 --- /dev/null +++ b/regression/strings/java_append_object/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_append_object.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 15.* FAILURE$ +-- diff --git a/regression/strings/java_append_object/test_append_object.class b/regression/strings/java_append_object/test_append_object.class new file mode 100644 index 00000000000..fbfec51a3f5 Binary files /dev/null and b/regression/strings/java_append_object/test_append_object.class differ diff --git a/regression/strings/java_append_object/test_append_object.java b/regression/strings/java_append_object/test_append_object.java new file mode 100644 index 00000000000..e139a01679a --- /dev/null +++ b/regression/strings/java_append_object/test_append_object.java @@ -0,0 +1,17 @@ +public class test_append_object +{ + public static void main(/*String[] args*/) + { + Object diff = "diff"; + Object blue = "blue"; + + StringBuilder buffer = new StringBuilder(); + + buffer.append(diff) + .append(blue); + + String tmp=buffer.toString(); + System.out.println(tmp); + assert(!tmp.equals("diffblue")); + } +} diff --git a/regression/strings/java_append_string/test.desc b/regression/strings/java_append_string/test.desc new file mode 100644 index 00000000000..7b6ea8ccae7 --- /dev/null +++ b/regression/strings/java_append_string/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_append_string.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 12.* FAILURE$ +-- diff --git a/regression/strings/java_append_string/test_append_string.class b/regression/strings/java_append_string/test_append_string.class new file mode 100644 index 00000000000..f2cb5cf8bea Binary files /dev/null and b/regression/strings/java_append_string/test_append_string.class differ diff --git a/regression/strings/java_append_string/test_append_string.java b/regression/strings/java_append_string/test_append_string.java new file mode 100644 index 00000000000..54665da29cc --- /dev/null +++ b/regression/strings/java_append_string/test_append_string.java @@ -0,0 +1,14 @@ +public class test_append_string +{ + public static void main(/*String[] args*/) + { + String di = new String("di"); + StringBuilder diff = new StringBuilder(); + diff.append(di); + diff.append("ff"); + System.out.println(diff); + String s = diff.toString(); + System.out.println(s); + assert (!s.equals("diff")); + } +} diff --git a/regression/strings/java_case/test.desc b/regression/strings/java_case/test.desc index 9f48288c694..47db60a36d9 100644 --- a/regression/strings/java_case/test.desc +++ b/regression/strings/java_case/test.desc @@ -1,10 +1,7 @@ FUTURE test_case.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_case.java line 11: SUCCESS$ -^\[assertion.2\] assertion at file test_case.java line 12: SUCCESS$ -^\[assertion.3\] assertion at file test_case.java line 13: SUCCESS$ -^\[assertion.4\] assertion at file test_case.java line 14: FAILURE$ +^\[.*assertion.1\].* line 8.* FAILURE$ -- diff --git a/regression/strings/java_case/test_case.class b/regression/strings/java_case/test_case.class index 8579881de17..5887b496986 100644 Binary files a/regression/strings/java_case/test_case.class and b/regression/strings/java_case/test_case.class differ diff --git a/regression/strings/java_case/test_case.java b/regression/strings/java_case/test_case.java index ce3a51814c8..309abfc07b9 100644 --- a/regression/strings/java_case/test_case.java +++ b/regression/strings/java_case/test_case.java @@ -1,16 +1,12 @@ -public class test_case { - - public static void main(String[] argv) { - - String s = new String("AbcCdE"); - String l = s.toLowerCase(); - System.out.println(l); - - String u = s.toUpperCase(); - System.out.println(u); - assert(l.equals("abccde")); - assert(u.equals("ABCCDE")); - assert(s.equalsIgnoreCase("ABccDe")); - assert(!l.equals("abccde") || !u.equals("ABCCDE")); - } +public class test_case +{ + public static void main(/*String[] argv*/) + { + String s = new String("Ab"); + String l = s.toLowerCase(); + String u = s.toUpperCase(); + assert(!l.equals("ab") || + !u.equals("AB") || + !s.equalsIgnoreCase("aB")); + } } diff --git a/regression/strings/java_char_array/test.desc b/regression/strings/java_char_array/test.desc index 8282b808b84..62cc45997ba 100644 --- a/regression/strings/java_char_array/test.desc +++ b/regression/strings/java_char_array/test.desc @@ -1,9 +1,7 @@ FUTURE test_char_array.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_char_array.java line 11: SUCCESS$ -^\[assertion.2\] assertion at file test_char_array.java line 12: SUCCESS$ -^\[assertion.3\] assertion at file test_char_array.java line 13: FAILURE$ +^\[.*assertion.1\].* line 9.* FAILURE$ -- diff --git a/regression/strings/java_char_array/test_char_array.class b/regression/strings/java_char_array/test_char_array.class index 836942da134..38a7ecf41ed 100644 Binary files a/regression/strings/java_char_array/test_char_array.class and b/regression/strings/java_char_array/test_char_array.class differ diff --git a/regression/strings/java_char_array/test_char_array.java b/regression/strings/java_char_array/test_char_array.java index 3cfd4000d3a..96e250fb030 100644 --- a/regression/strings/java_char_array/test_char_array.java +++ b/regression/strings/java_char_array/test_char_array.java @@ -1,15 +1,13 @@ -public class test_char_array { - - public static void main(String[] argv) - { - String s = "abc"; - char [] str = s.toCharArray(); - int[] test = new int[312]; - char c = str[2]; - String t = argv[0]; - char d = t.charAt(0); - assert(str.length == 3); - assert(c == 'c'); - assert(c == d || d < 'a' || d > 'z' ); - } +public class test_char_array +{ + public static void main(/*String[] argv*/) + { + String s = "abc"; + char [] str = s.toCharArray(); + char c = str[2]; + char a = s.charAt(0); + assert(str.length != 3 || + a != 'a' || + c != 'c'); + } } diff --git a/regression/strings/java_char_array_init/test.desc b/regression/strings/java_char_array_init/test.desc index fe5ffae7238..24437881467 100644 --- a/regression/strings/java_char_array_init/test.desc +++ b/regression/strings/java_char_array_init/test.desc @@ -1,11 +1,7 @@ FUTURE test_init.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_init.java line 16: SUCCESS$ -^\[assertion.2\] assertion at file test_init.java line 17: SUCCESS$ -^\[assertion.3\] assertion at file test_init.java line 18: SUCCESS$ -^\[assertion.4\] assertion at file test_init.java line 20: SUCCESS$ -^\[assertion.5\] assertion at file test_init.java line 21: FAILURE$ +^\[.*assertion.1\].* line 14.* FAILURE$ -- diff --git a/regression/strings/java_char_array_init/test_init.class b/regression/strings/java_char_array_init/test_init.class index be3baee56bd..ff9c64510da 100644 Binary files a/regression/strings/java_char_array_init/test_init.class and b/regression/strings/java_char_array_init/test_init.class differ diff --git a/regression/strings/java_char_array_init/test_init.java b/regression/strings/java_char_array_init/test_init.java index 5f4e220844c..b27030b1306 100644 --- a/regression/strings/java_char_array_init/test_init.java +++ b/regression/strings/java_char_array_init/test_init.java @@ -1,23 +1,18 @@ public class test_init { - public static void main(String[] argv) - { - char [] str = new char[10]; - str[0] = 'H'; - str[1] = 'e'; - str[2] = 'l'; - str[3] = 'l'; - str[4] = 'o'; - String s = new String(str); - String t = new String(str,1,2); + public static void main(/*String[] argv*/) + { + char [] str = new char[10]; + str[0] = 'H'; + str[1] = 'e'; + str[2] = 'l'; + str[3] = 'l'; + str[4] = 'o'; + String s = new String(str); + String t = new String(str,1,2); - System.out.println(s); - System.out.println(s.length()); - assert(s.startsWith("Hello")); - assert(s.length() == 10); - assert(t.equals("el")); - String u = String.valueOf(str,3,2); - assert(u.equals("lo")); - assert(s.equals("Hello") || !t.equals("el") || !u.equals("lo")); - } + assert(s.length() != 10 || + !t.equals("el") || + !s.startsWith("Hello")); + } } diff --git a/regression/strings/java_char_at/test.desc b/regression/strings/java_char_at/test.desc index 6f206a0f22f..0226b19529e 100644 --- a/regression/strings/java_char_at/test.desc +++ b/regression/strings/java_char_at/test.desc @@ -1,9 +1,7 @@ FUTURE test_char_at.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_char_at.java line 11: SUCCESS$ -^\[assertion.2\] assertion at file test_char_at.java line 13: FAILURE$ -^\[assertion.3\] assertion at file test_char_at.java line 15: SUCCESS$ +^\[.*assertion.1\].* line 5.* FAILURE$ -- diff --git a/regression/strings/java_char_at/test_char_at.class b/regression/strings/java_char_at/test_char_at.class index 7d1f07fad7d..dc9ed32f19f 100644 Binary files a/regression/strings/java_char_at/test_char_at.class and b/regression/strings/java_char_at/test_char_at.class differ diff --git a/regression/strings/java_char_at/test_char_at.java b/regression/strings/java_char_at/test_char_at.java index 337c6524099..9ae02733fb8 100644 --- a/regression/strings/java_char_at/test_char_at.java +++ b/regression/strings/java_char_at/test_char_at.java @@ -1,17 +1,7 @@ public class test_char_at { - public static void main(String[] argv) { - String s = new String("Hello World!"); - char c = s.charAt(4); - StringBuilder sb = new StringBuilder(s); - sb.setCharAt(5,'-'); - s = sb.toString(); - - if(argv.length==1) - assert(c == 'o'); - else if(argv.length==2) - assert(c == 'p'); - else - assert(s.equals("Hello-World!")); - } + public static void main(/*String[] argv*/) { + String s = new String("abc"); + assert(s.charAt(2)!='c'); + } } diff --git a/regression/strings/java_code_point/test.desc b/regression/strings/java_code_point/test.desc index 35ca0cd6f4b..2b94f1fa0c0 100644 --- a/regression/strings/java_code_point/test.desc +++ b/regression/strings/java_code_point/test.desc @@ -1,11 +1,7 @@ FUTURE test_code_point.class ---string-refine -^EXIT=0$ +--refine-strings +^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_code_point.java line 5: SUCCESS$ -^\[assertion.2\] assertion at file test_code_point.java line 6: SUCCESS$ -^\[assertion.3\] assertion at file test_code_point.java line 7: SUCCESS$ -^\[assertion.4\] assertion at file test_code_point.java line 8: SUCCESS$ -^\[assertion.5\] assertion at file test_code_point.java line 11: SUCCESS$ +^\[.*assertion.1\].* line 8.* FAILURE$ -- diff --git a/regression/strings/java_code_point/test_code_point.class b/regression/strings/java_code_point/test_code_point.class index c257f0633ec..f2f5fbad63a 100644 Binary files a/regression/strings/java_code_point/test_code_point.class and b/regression/strings/java_code_point/test_code_point.class differ diff --git a/regression/strings/java_code_point/test_code_point.java b/regression/strings/java_code_point/test_code_point.java index c27a56f575c..345dc1fa08b 100644 --- a/regression/strings/java_code_point/test_code_point.java +++ b/regression/strings/java_code_point/test_code_point.java @@ -1,13 +1,14 @@ -public class test_code_point { - - public static void main(String[] argv) { - String s = "!𐤇𐤄𐤋𐤋𐤅"; - assert(s.codePointAt(1) == 67847); - assert(s.codePointBefore(3) == 67847); - assert(s.codePointCount(1,5) >= 2); - assert(s.offsetByCodePoints(1,2) >= 3); - StringBuilder sb = new StringBuilder(); - sb.appendCodePoint(0x10907); - assert(s.charAt(1) == sb.charAt(0)); - } +public class test_code_point +{ + public static void main(/*String[] argv*/) + { + String s = "!𐤇𐤄𐤋𐤋𐤅"; + StringBuilder sb = new StringBuilder(); + sb.appendCodePoint(0x10907); + assert(s.codePointAt(1) != 67847 || + s.codePointBefore(3) != 67847 || + s.codePointCount(1,5) < 2 || + s.offsetByCodePoints(1,2) < 3 || + s.charAt(1) != sb.charAt(0)); + } } diff --git a/regression/strings/java_compare/test.desc b/regression/strings/java_compare/test.desc index 517b208c3e4..e7444831e77 100644 --- a/regression/strings/java_compare/test.desc +++ b/regression/strings/java_compare/test.desc @@ -1,10 +1,7 @@ FUTURE test_compare.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_compare.java line 6: SUCCESS$ -^\[assertion.2\] assertion at file test_compare.java line 8: FAILURE$ -^\[assertion.3\] assertion at file test_compare.java line 11: SUCCESS$ -^\[assertion.4\] assertion at file test_compare.java line 12: FAILURE$ +^\[.*assertion.1\].* line 7.* FAILURE$ -- diff --git a/regression/strings/java_compare/test_compare.class b/regression/strings/java_compare/test_compare.class index 5616013c523..67f18914ea6 100644 Binary files a/regression/strings/java_compare/test_compare.class and b/regression/strings/java_compare/test_compare.class differ diff --git a/regression/strings/java_compare/test_compare.java b/regression/strings/java_compare/test_compare.java index 8c1d4b71a0c..0a535fd0bf3 100644 --- a/regression/strings/java_compare/test_compare.java +++ b/regression/strings/java_compare/test_compare.java @@ -1,18 +1,9 @@ -public class test_compare { - - public static void main(String[] argv) { - String s1 = "abc"; - String s2 = "aac"; - assert(s1.compareTo(s2) == 1); - - assert(s2.compareTo(argv[0]) != -1); - - String s3 = "abc"; - assert(s3.hashCode() == s1.hashCode()); - assert(s3.hashCode() == s2.hashCode()); - - /*String x = s1.intern(); - String y = s3.intern(); - assert(x == y);*/ - } +public class test_compare +{ + public static void main(/*String[] argv*/) + { + String s1 = "ab"; + String s2 = "aa"; + assert(s1.compareTo(s2) != 1); + } } diff --git a/regression/strings/java_concat/test.desc b/regression/strings/java_concat/test.desc index 8ef2898e0d7..fb784efd723 100644 --- a/regression/strings/java_concat/test.desc +++ b/regression/strings/java_concat/test.desc @@ -1,8 +1,8 @@ FUTURE test_concat.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_concat.java line 9: SUCCESS$ -^\[assertion.2\] assertion at file test_concat.java line 10: FAILURE$ +^\[.*assertion.1\].* line 10.* SUCCESS$ +^\[.*assertion.2\].* line 11.* FAILURE$ -- diff --git a/regression/strings/java_concat/test_concat.class b/regression/strings/java_concat/test_concat.class index a6d4008aa26..a69c05921f6 100644 Binary files a/regression/strings/java_concat/test_concat.class and b/regression/strings/java_concat/test_concat.class differ diff --git a/regression/strings/java_concat/test_concat.java b/regression/strings/java_concat/test_concat.java index d714ea89538..6bbe753b2e4 100644 --- a/regression/strings/java_concat/test_concat.java +++ b/regression/strings/java_concat/test_concat.java @@ -1,12 +1,13 @@ -public class test_concat { - - public static void main(String[] argv) { - String s = new String("pi"); - int i = s.length(); - String t = new String("ppo"); - String u = s.concat(t); - char c = u.charAt(i); - assert(c == 'p'); - assert(c == 'o'); - } +public class test_concat +{ + public static void main(/*String[] argv*/) + { + String s = new String("pi"); + int i = s.length(); + String t = new String("ppo"); + String u = s.concat(t); + char c = u.charAt(i); + assert(c == 'p'); + assert(c != 'p'); + } } diff --git a/regression/strings/java_contains/test.desc b/regression/strings/java_contains/test.desc index 4e7a3bd4f7d..bb4fadba9d3 100644 --- a/regression/strings/java_contains/test.desc +++ b/regression/strings/java_contains/test.desc @@ -1,8 +1,7 @@ FUTURE test_contains.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_contains.java line 7: SUCCESS$ -^\[assertion.2\] assertion at file test_contains.java line 8: FAILURE$ +^\[.*assertion.1\].* line 7.* FAILURE$ -- diff --git a/regression/strings/java_contains/test_contains.class b/regression/strings/java_contains/test_contains.class index 855ab828393..9bbccb03775 100644 Binary files a/regression/strings/java_contains/test_contains.class and b/regression/strings/java_contains/test_contains.class differ diff --git a/regression/strings/java_contains/test_contains.java b/regression/strings/java_contains/test_contains.java index fce2ee63047..6f4c60a1a2e 100644 --- a/regression/strings/java_contains/test_contains.java +++ b/regression/strings/java_contains/test_contains.java @@ -1,10 +1,9 @@ -public class test_contains { - - public static void main(String[] argv) { - String s = new String("Hello World!"); - String u = "o W"; - String t = "W o"; - assert(s.contains(u)); - assert(s.contains(t)); - } +public class test_contains +{ + public static void main(/*String[] argv*/) + { + String s = new String("Abc"); + String u = "bc"; + assert(!s.contains(u)); + } } diff --git a/regression/strings/java_delete/test.desc b/regression/strings/java_delete/test.desc index c6c608c0955..ff41e78b3df 100644 --- a/regression/strings/java_delete/test.desc +++ b/regression/strings/java_delete/test.desc @@ -1,8 +1,7 @@ FUTURE test_delete.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_delete.java line 11: SUCCESS$ -^\[assertion.2\] assertion at file test_delete.java line 12: FAILURE$ +^\[.*assertion.1\].* line 8.* FAILURE$ -- diff --git a/regression/strings/java_delete/test_delete.class b/regression/strings/java_delete/test_delete.class index 6d30024f108..7036ce13c90 100644 Binary files a/regression/strings/java_delete/test_delete.class and b/regression/strings/java_delete/test_delete.class differ diff --git a/regression/strings/java_delete/test_delete.java b/regression/strings/java_delete/test_delete.java index c91b16c5b89..ea846cd215a 100644 --- a/regression/strings/java_delete/test_delete.java +++ b/regression/strings/java_delete/test_delete.java @@ -1,15 +1,10 @@ -public class test_delete { - - public static void main(String[] argv) { - StringBuilder s = new StringBuilder(); - s.append("Hello World!"); - s.delete(4,6); - s.deleteCharAt(1); - - String str = s.toString(); - System.out.println(str); - assert(str.equals("HllWorld!")); - assert(!str.equals("HllWorld!")); - - } +public class test_delete +{ + public static void main(/*String[] argv*/) + { + StringBuilder s = new StringBuilder("Abc"); + s.delete(1,2); + String str = s.toString(); + assert(!str.equals("Ac")); + } } diff --git a/regression/strings/java_delete_char_at/test.desc b/regression/strings/java_delete_char_at/test.desc new file mode 100644 index 00000000000..0314c606e56 --- /dev/null +++ b/regression/strings/java_delete_char_at/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_delete_char_at.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 9.* FAILURE$ +-- diff --git a/regression/strings/java_delete_char_at/test_delete_char_at.class b/regression/strings/java_delete_char_at/test_delete_char_at.class new file mode 100644 index 00000000000..ed3148e2f7e Binary files /dev/null and b/regression/strings/java_delete_char_at/test_delete_char_at.class differ diff --git a/regression/strings/java_delete_char_at/test_delete_char_at.java b/regression/strings/java_delete_char_at/test_delete_char_at.java new file mode 100644 index 00000000000..5f2c995b56b --- /dev/null +++ b/regression/strings/java_delete_char_at/test_delete_char_at.java @@ -0,0 +1,11 @@ +public class test_delete_char_at +{ + public static void main(/*String[] argv*/) + { + StringBuilder s = new StringBuilder(); + s.append("Abc"); + s.deleteCharAt(1); + String str = s.toString(); + assert(!str.equals("Ac")); + } +} diff --git a/regression/strings/java_easychair/easychair.class b/regression/strings/java_easychair/easychair.class index e47900cc0b2..e6c5f66c42d 100644 Binary files a/regression/strings/java_easychair/easychair.class and b/regression/strings/java_easychair/easychair.class differ diff --git a/regression/strings/java_easychair/easychair.java b/regression/strings/java_easychair/easychair.java index 55ca2a31bb3..caed962fb46 100644 --- a/regression/strings/java_easychair/easychair.java +++ b/regression/strings/java_easychair/easychair.java @@ -1,34 +1,34 @@ -public class easychair { +public class easychair +{ + public static void main(String[] argv) + { + if(argv.length > 1) + { + String str = new String(argv[1]); + if(str.length() < 40) + { + // containing "/" and containing "EasyChair" + int lastSlash = str.lastIndexOf('/'); + if(lastSlash < 0) return ; - public static void main(String[] argv) { - if(argv.length > 1){ - String str = new String(argv[1]); - if(str.length() < 40){ - - // containing "/" and containing "EasyChair" - int lastSlash = str.lastIndexOf('/'); - if(lastSlash < 0) return ; - - String rest = str.substring(lastSlash + 1); - // warning: removed this because contains is not efficient at the moment - if(! rest.contains("EasyChair")) return ; - // (2) Check that str starts with "http://" - if(! str.startsWith("http://")) return ; - // (3) Take the string between "http://" and the last "/". - // if it starts with "www." strip the "www." off - String t = str.substring("http://".length(),lastSlash - "http://".length()); - if(t.startsWith("www.")) - t = t.substring("www.".length()); - - // - //(4) Check that after stripping we have either "live.com" - // or "google.com" - if(!t.equals("live.com") && !t.equals("google.com")) - return ; - // s survived all checks - assert(false); //return true; - } - } - } + String rest = str.substring(lastSlash + 1); + // warning: removed this because contains is not efficient at the moment + if(! rest.contains("EasyChair")) return ; + // (2) Check that str starts with "http://" + if(! str.startsWith("http://")) return ; + // (3) Take the string between "http://" and the last "/". + // if it starts with "www." strip the "www." off + String t = str.substring("http://".length(),lastSlash - "http://".length()); + if(t.startsWith("www.")) + t = t.substring("www.".length()); + //(4) Check that after stripping we have either "live.com" + // or "google.com" + if(!t.equals("live.com") && !t.equals("google.com")) + return ; + // s survived all checks + assert(false); //return true; + } + } + } } diff --git a/regression/strings/java_easychair/test.desc b/regression/strings/java_easychair/test.desc index 8680af72c5a..14418a7798e 100644 --- a/regression/strings/java_easychair/test.desc +++ b/regression/strings/java_easychair/test.desc @@ -1,7 +1,7 @@ -FUTURE +THOROUGH easychair.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file easychair.java line 29: FAILURE$ +^\[.*assertion.1\].* line 30.* FAILURE$ -- diff --git a/regression/strings/java_empty/test.desc b/regression/strings/java_empty/test.desc index cab514b80b5..44e8e1346a9 100644 --- a/regression/strings/java_empty/test.desc +++ b/regression/strings/java_empty/test.desc @@ -1,8 +1,7 @@ FUTURE test_empty.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_empty.java line 4: SUCCESS$ -^\[assertion.2\] assertion at file test_empty.java line 5: FAILURE$ +^\[.*assertion.1\].* line 6.* FAILURE$ -- diff --git a/regression/strings/java_empty/test_empty.class b/regression/strings/java_empty/test_empty.class index f0ced290ee3..147a2b628fe 100644 Binary files a/regression/strings/java_empty/test_empty.class and b/regression/strings/java_empty/test_empty.class differ diff --git a/regression/strings/java_empty/test_empty.java b/regression/strings/java_empty/test_empty.java index 2465fb16e41..18fde4a115e 100644 --- a/regression/strings/java_empty/test_empty.java +++ b/regression/strings/java_empty/test_empty.java @@ -1,7 +1,8 @@ -public class test_empty { - public static void main(String[] argv) { - String empty = " "; - assert(empty.trim().isEmpty()); - assert(empty.isEmpty()); - } +public class test_empty +{ + public static void main(/*String[] argv*/) + { + String empty = ""; + assert(!empty.isEmpty()); + } } diff --git a/regression/strings/java_endswith/test.desc b/regression/strings/java_endswith/test.desc new file mode 100644 index 00000000000..285e6ee103c --- /dev/null +++ b/regression/strings/java_endswith/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_endswith.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 7.* FAILURE$ +-- diff --git a/regression/strings/java_endswith/test_endswith.class b/regression/strings/java_endswith/test_endswith.class new file mode 100644 index 00000000000..e3d453c444f Binary files /dev/null and b/regression/strings/java_endswith/test_endswith.class differ diff --git a/regression/strings/java_endswith/test_endswith.java b/regression/strings/java_endswith/test_endswith.java new file mode 100644 index 00000000000..fabf6f8dde0 --- /dev/null +++ b/regression/strings/java_endswith/test_endswith.java @@ -0,0 +1,9 @@ +public class test_endswith +{ + public static void main(/*String[] argv*/) + { + String s = new String("Abcd"); + String suff = "cd"; + assert(!s.endsWith(suff)); + } +} diff --git a/regression/strings/java_equal/test.desc b/regression/strings/java_equal/test.desc index d66c30b26fe..bb61dcea8ed 100644 --- a/regression/strings/java_equal/test.desc +++ b/regression/strings/java_equal/test.desc @@ -1,8 +1,7 @@ FUTURE test_equal.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_equal.java line 7: FAILURE$ -^\[assertion.2\] assertion at file test_equal.java line 8: SUCCESS$ +^\[.*assertion.1\].* line 8.* FAILURE$ -- diff --git a/regression/strings/java_equal/test_equal.class b/regression/strings/java_equal/test_equal.class index 26ee19e6cb1..e0fc6db8aaf 100644 Binary files a/regression/strings/java_equal/test_equal.class and b/regression/strings/java_equal/test_equal.class differ diff --git a/regression/strings/java_equal/test_equal.java b/regression/strings/java_equal/test_equal.java index 151162a106d..e8c9ac7cb1a 100644 --- a/regression/strings/java_equal/test_equal.java +++ b/regression/strings/java_equal/test_equal.java @@ -1,10 +1,9 @@ -public class test_equal { - - public static void main(String[] argv) { - String s = new String("pi"); - String t = new String("po"); - String u = "po"; - assert(s.equals(t)); - assert(t.equals(u)); - } +public class test_equal +{ + public static void main(String[] argv) + { + String s = new String("pi"); + String t = new String("po"); + assert(!s.equals(t)); + } } diff --git a/regression/strings/java_float/test.desc b/regression/strings/java_float/test.desc index 955f0358eab..31404ae5e08 100644 --- a/regression/strings/java_float/test.desc +++ b/regression/strings/java_float/test.desc @@ -1,10 +1,7 @@ FUTURE test_float.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_float.java line 14: SUCCESS$ -^\[assertion.2\] assertion at file test_float.java line 15: SUCCESS$ -^\[assertion.3\] assertion at file test_float.java line 16: SUCCESS$ -^\[assertion.4\] assertion at file test_float.java line 17: FAILURE$ +^\[.*assertion.1\].* line 15.* FAILURE$ -- diff --git a/regression/strings/java_float/test_float.class b/regression/strings/java_float/test_float.class index 356d0e17871..00e8622e2ac 100644 Binary files a/regression/strings/java_float/test_float.class and b/regression/strings/java_float/test_float.class differ diff --git a/regression/strings/java_float/test_float.java b/regression/strings/java_float/test_float.java index e59c631d91e..312f1aeaf10 100644 --- a/regression/strings/java_float/test_float.java +++ b/regression/strings/java_float/test_float.java @@ -1,20 +1,17 @@ -public class test_float { - - public static void main(String[] arg) { - float inf = 100.0f / 0.0f; - float minus_inf = -100.0f / 0.0f; - float nan = 0.0f / 0.0f; - String inf_string = Float.toString(inf); - String mininf_string = Float.toString(minus_inf); - String nan_string = Float.toString(nan); - //String arg1 = arg[0]; - System.out.println(nan_string); - System.out.println(inf_string); - System.out.println(mininf_string); - assert(nan_string.equals("NaN")); - assert(inf_string.equals("Infinity")); - assert(mininf_string.equals("-Infinity")); - assert(!nan_string.equals("NaN") || !inf_string.equals("Infinity") - || !mininf_string.equals("-Infinity")); - } +public class test_float +{ + public static void main(/*String[] arg*/) + { + float inf = 100.0f / 0.0f; + float minus_inf = -100.0f / 0.0f; + float nan = 0.0f / 0.0f; + String inf_string = Float.toString(inf); + String mininf_string = Float.toString(minus_inf); + String nan_string = Float.toString(nan); + System.out.println(nan_string); + System.out.println(inf_string); + System.out.println(mininf_string); + assert(!nan_string.equals("NaN") || !inf_string.equals("Infinity") + || !mininf_string.equals("-Infinity")); + } } diff --git a/regression/strings/java_hash_code/test.desc b/regression/strings/java_hash_code/test.desc new file mode 100644 index 00000000000..4f786d42f80 --- /dev/null +++ b/regression/strings/java_hash_code/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_hash_code.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 7.* FAILURE$ +-- diff --git a/regression/strings/java_hash_code/test_hash_code.class b/regression/strings/java_hash_code/test_hash_code.class new file mode 100644 index 00000000000..d9b3e2b2f3d Binary files /dev/null and b/regression/strings/java_hash_code/test_hash_code.class differ diff --git a/regression/strings/java_hash_code/test_hash_code.java b/regression/strings/java_hash_code/test_hash_code.java new file mode 100644 index 00000000000..fbc15f0b4c2 --- /dev/null +++ b/regression/strings/java_hash_code/test_hash_code.java @@ -0,0 +1,9 @@ +public class test_hash_code +{ + public static void main(/*String[] argv*/) + { + String s1 = "ab"; + String s2 = "ab"; + assert(s1.hashCode() != s2.hashCode()); + } +} diff --git a/regression/strings/java_index_of/test.desc b/regression/strings/java_index_of/test.desc index daa6c32493b..28a0809f441 100644 --- a/regression/strings/java_index_of/test.desc +++ b/regression/strings/java_index_of/test.desc @@ -1,16 +1,7 @@ FUTURE test_index_of.class ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[assertion.1\] assertion at file test_index_of.java line 13: SUCCESS$ -^\[assertion.2\] assertion at file test_index_of.java line 14: FAILURE$ -^\[assertion.3\] assertion at file test_index_of.java line 17: SUCCESS$ -^\[assertion.4\] assertion at file test_index_of.java line 18: FAILURE$ -^\[assertion.5\] assertion at file test_index_of.java line 21: SUCCESS$ -^\[assertion.6\] assertion at file test_index_of.java line 22: FAILURE$ -^\[assertion.7\] assertion at file test_index_of.java line 25: SUCCESS$ -^\[assertion.8\] assertion at file test_index_of.java line 26: FAILURE$ -^\[assertion.9\] assertion at file test_index_of.java line 28: SUCCESS$ -^\[assertion.10\] assertion at file test_index_of.java line 29: SUCCESS$ +^\[.*assertion.1\].* line 8.* FAILURE$ -- diff --git a/regression/strings/java_index_of/test_index_of.class b/regression/strings/java_index_of/test_index_of.class index 8b3b7525f1a..cae397a79fb 100644 Binary files a/regression/strings/java_index_of/test_index_of.class and b/regression/strings/java_index_of/test_index_of.class differ diff --git a/regression/strings/java_index_of/test_index_of.java b/regression/strings/java_index_of/test_index_of.java index bbe06d279ec..b607ba79570 100644 --- a/regression/strings/java_index_of/test_index_of.java +++ b/regression/strings/java_index_of/test_index_of.java @@ -1,32 +1,10 @@ -public class test_index_of { - - public static void main(String[] argv) { - String s = "Hello World!"; - char c = 'o'; - int i = s.indexOf(c); - int j = s.lastIndexOf('o'); - int k = s.indexOf(c,5); - int l = s.lastIndexOf(c,5); - int m = s.indexOf("lo"); - int n = s.lastIndexOf("lo"); - if(argv.length == 1){ - assert(i == 4); - assert(i != 4); - } - else if(argv.length == 2){ - assert(j == 7); - assert(j != 7); - } - else if(argv.length == 3){ - assert(k == 7); - assert(k != 7); - } - else if(argv.length == 4){ - assert(l == 4); - assert(l != 4); - } else { - assert(m != 2); - assert(n != 2); - } - } +public class test_index_of +{ + public static void main(/*String[] argv*/) + { + String s = "Abc"; + String bc = "bc"; + int i = s.indexOf(bc); + assert(i != 1); + } } diff --git a/regression/strings/java_index_of_char/test.desc b/regression/strings/java_index_of_char/test.desc new file mode 100644 index 00000000000..30d179cbaaa --- /dev/null +++ b/regression/strings/java_index_of_char/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_index_of_char.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 8.* FAILURE$ +-- diff --git a/regression/strings/java_index_of_char/test_index_of_char.class b/regression/strings/java_index_of_char/test_index_of_char.class new file mode 100644 index 00000000000..bf4fa6e946e Binary files /dev/null and b/regression/strings/java_index_of_char/test_index_of_char.class differ diff --git a/regression/strings/java_index_of_char/test_index_of_char.java b/regression/strings/java_index_of_char/test_index_of_char.java new file mode 100644 index 00000000000..92d75b3b07d --- /dev/null +++ b/regression/strings/java_index_of_char/test_index_of_char.java @@ -0,0 +1,10 @@ +public class test_index_of_char +{ + public static void main(/*String[] argv*/) + { + String s = "Abc"; + char c = 'c'; + int i = s.indexOf(c); + assert(i != 2); + } +} diff --git a/regression/strings/java_insert/test_insert.class b/regression/strings/java_insert/test_insert.class deleted file mode 100644 index 5fa0f425061..00000000000 Binary files a/regression/strings/java_insert/test_insert.class and /dev/null differ diff --git a/regression/strings/java_insert/test_insert.java b/regression/strings/java_insert/test_insert.java deleted file mode 100644 index 6871a51716c..00000000000 --- a/regression/strings/java_insert/test_insert.java +++ /dev/null @@ -1,19 +0,0 @@ -public class test_insert { - - public static void main(String[] argv) { - int i = 123; - long j = 123; - char c = '/'; - boolean b = true; - StringBuilder sb = new StringBuilder("hello"); - sb.insert(2,i); - sb.insert(2,c); - sb.insert(2,j); - sb.insert(2,b); - sb.insert(2,"abc"); - String s = sb.toString(); - System.out.println(s); - assert(s.equals("heabctrue123/123llo")); - assert(!s.equals("heabctrue123/123llo")); - } -} diff --git a/regression/strings/java_insert/test_insert1.class b/regression/strings/java_insert/test_insert1.class deleted file mode 100644 index 80091936cea..00000000000 Binary files a/regression/strings/java_insert/test_insert1.class and /dev/null differ diff --git a/regression/strings/java_insert/test_insert1.java b/regression/strings/java_insert/test_insert1.java deleted file mode 100644 index 54e754302c5..00000000000 --- a/regression/strings/java_insert/test_insert1.java +++ /dev/null @@ -1,23 +0,0 @@ -public class test_insert1 { - - public static void main(String[] argv) { - int i = 123; - long j = 123; - char c = '/'; - boolean b = true; - StringBuilder sb = new StringBuilder("hello"); - sb.insert(2,i); - - /* - sb.insert(2,c); - sb.insert(2,j); - sb.insert(2,b); - sb.insert(2,"abc"); - */ - String s = sb.toString(); - System.out.println(s); - assert(s.equals("he123llo")); - //assert(s.equals("heabctrue123/123llo")); - //assert(!s.equals("heabctrue123/123llo")); - } -} diff --git a/regression/strings/java_insert_char/test.desc b/regression/strings/java_insert_char/test.desc new file mode 100644 index 00000000000..f5727a3a4ab --- /dev/null +++ b/regression/strings/java_insert_char/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_insert_char.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 8.* FAILURE$ +-- diff --git a/regression/strings/java_insert_char/test_insert_char.class b/regression/strings/java_insert_char/test_insert_char.class new file mode 100644 index 00000000000..fbf4a82070b Binary files /dev/null and b/regression/strings/java_insert_char/test_insert_char.class differ diff --git a/regression/strings/java_insert_char/test_insert_char.java b/regression/strings/java_insert_char/test_insert_char.java new file mode 100644 index 00000000000..3a83f03b332 --- /dev/null +++ b/regression/strings/java_insert_char/test_insert_char.java @@ -0,0 +1,10 @@ +public class test_insert_char +{ + public static void main(/*String[] argv*/) + { + StringBuilder sb = new StringBuilder("ac"); + sb.insert(1, 'b'); + String s = sb.toString(); + assert(!s.equals("abc")); + } +} diff --git a/regression/strings/java_insert_char_array/test.desc b/regression/strings/java_insert_char_array/test.desc new file mode 100644 index 00000000000..2432502ce3b --- /dev/null +++ b/regression/strings/java_insert_char_array/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_insert_char_array.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 12.* FAILURE$ +-- diff --git a/regression/strings/java_insert_char_array/test_insert_char_array.class b/regression/strings/java_insert_char_array/test_insert_char_array.class new file mode 100644 index 00000000000..bc1a23a7496 Binary files /dev/null and b/regression/strings/java_insert_char_array/test_insert_char_array.class differ diff --git a/regression/strings/java_insert_char_array/test_insert_char_array.java b/regression/strings/java_insert_char_array/test_insert_char_array.java new file mode 100644 index 00000000000..079dbd2fee6 --- /dev/null +++ b/regression/strings/java_insert_char_array/test_insert_char_array.java @@ -0,0 +1,14 @@ +public class test_insert_char_array +{ + public static void main(/*String[] argv*/) + { + StringBuilder sb = new StringBuilder("ad"); + char[] array = new char[2]; + array[0] = 'b'; + array[1] = 'c'; + sb.insert(1, array); + String s = sb.toString(); + System.out.println(s); + assert(!s.equals("abcd")); + } +} diff --git a/regression/strings/java_insert_int/test.desc b/regression/strings/java_insert_int/test.desc new file mode 100644 index 00000000000..2229d33b491 --- /dev/null +++ b/regression/strings/java_insert_int/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_insert_int.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 8.* FAILURE$ +-- diff --git a/regression/strings/java_insert_int/test_insert_int.class b/regression/strings/java_insert_int/test_insert_int.class new file mode 100644 index 00000000000..cd355c86546 Binary files /dev/null and b/regression/strings/java_insert_int/test_insert_int.class differ diff --git a/regression/strings/java_insert_int/test_insert_int.java b/regression/strings/java_insert_int/test_insert_int.java new file mode 100644 index 00000000000..15a7a2d53f6 --- /dev/null +++ b/regression/strings/java_insert_int/test_insert_int.java @@ -0,0 +1,10 @@ +public class test_insert_int +{ + public static void main(/*String[] argv*/) + { + StringBuilder sb = new StringBuilder("ac"); + sb.insert(1, 42); + String s = sb.toString(); + assert(!s.equals("a42c")); + } +} diff --git a/regression/strings/java_insert_multiple/test.desc b/regression/strings/java_insert_multiple/test.desc new file mode 100644 index 00000000000..497793cd650 --- /dev/null +++ b/regression/strings/java_insert_multiple/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_insert_multiple.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 9.* FAILURE$ +-- diff --git a/regression/strings/java_insert_multiple/test_insert_multiple.class b/regression/strings/java_insert_multiple/test_insert_multiple.class new file mode 100644 index 00000000000..d6b470a1f72 Binary files /dev/null and b/regression/strings/java_insert_multiple/test_insert_multiple.class differ diff --git a/regression/strings/java_insert_multiple/test_insert_multiple.java b/regression/strings/java_insert_multiple/test_insert_multiple.java new file mode 100644 index 00000000000..c976ddd807f --- /dev/null +++ b/regression/strings/java_insert_multiple/test_insert_multiple.java @@ -0,0 +1,11 @@ +public class test_insert_multiple +{ + public static void main(/*String[] argv*/) + { + StringBuilder sb = new StringBuilder("ad"); + sb.insert(1, 'c'); + sb.insert(1, "b"); + String s = sb.toString(); + assert(!s.equals("abcd")); + } +} diff --git a/regression/strings/java_insert_string/test.desc b/regression/strings/java_insert_string/test.desc new file mode 100644 index 00000000000..91e13cefab1 --- /dev/null +++ b/regression/strings/java_insert_string/test.desc @@ -0,0 +1,7 @@ +FUTURE +test_insert_string.class +--refine-strings +^EXIT=10$ +^SIGNAL=0$ +^\[.*assertion.1\].* line 8.* FAILURE$ +-- diff --git a/regression/strings/java_insert_string/test_insert_string.class b/regression/strings/java_insert_string/test_insert_string.class new file mode 100644 index 00000000000..be8f7ad0f79 Binary files /dev/null and b/regression/strings/java_insert_string/test_insert_string.class differ diff --git a/regression/strings/java_insert_string/test_insert_string.java b/regression/strings/java_insert_string/test_insert_string.java new file mode 100644 index 00000000000..028a348122b --- /dev/null +++ b/regression/strings/java_insert_string/test_insert_string.java @@ -0,0 +1,10 @@ +public class test_insert_string +{ + public static void main(/*String[] argv*/) + { + StringBuilder sb = new StringBuilder("ad"); + sb.insert(1, "bc"); + String s = sb.toString(); + assert(!s.equals("abcd")); + } +} diff --git a/regression/strings/java_int/test.desc b/regression/strings/java_int/test.desc deleted file mode 100644 index ae60dd78af0..00000000000 --- a/regression/strings/java_int/test.desc +++ /dev/null @@ -1,13 +0,0 @@ -FUTURE -test_int.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -^\[assertion.1\] assertion at file test_int.java line 8: SUCCESS$ -^\[assertion.2\] assertion at file test_int.java line 9: SUCCESS$ -^\[assertion.3\] assertion at file test_int.java line 12: SUCCESS$ -^\[assertion.4\] assertion at file test_int.java line 15: SUCCESS$ -^\[assertion.5\] assertion at file test_int.java line 18: SUCCESS$ -^\[assertion.6\] assertion at file test_int.java line 21: SUCCESS$ -^\[assertion.7\] assertion at file test_int.java line 23: FAILURE$ --- diff --git a/regression/strings/java_int/test_int.class b/regression/strings/java_int/test_int.class deleted file mode 100644 index 643d7eca09c..00000000000 Binary files a/regression/strings/java_int/test_int.class and /dev/null differ diff --git a/regression/strings/java_int/test_int.java b/regression/strings/java_int/test_int.java deleted file mode 100644 index 620ae638dce..00000000000 --- a/regression/strings/java_int/test_int.java +++ /dev/null @@ -1,25 +0,0 @@ -public class test_int { - - public static void main(String[] argv) { - String s = Integer.toString(2345); - char c = s.charAt(1); - char d = s.charAt(2); - char e = s.charAt(3); - assert(c == '3'); - assert(d == '4'); - - int i = Integer.parseInt("1234"); - assert(i == 1234); - - String t = Integer.toString(-2345); - assert(t.charAt(0) == '-'); - - int j = Integer.parseInt("-4231"); - assert(j == -4231); - - String u = Integer.toHexString(43981); - assert(u.equals("abcd")); - - assert(e == '2' || i < 1234 || t.charAt(0) != '-' || j != -4231 || !u.equals("abcd")); - } -} diff --git a/regression/strings/java_prefix/test.desc b/regression/strings/java_prefix/test.desc deleted file mode 100644 index 175f934ca1d..00000000000 --- a/regression/strings/java_prefix/test.desc +++ /dev/null @@ -1,10 +0,0 @@ -FUTURE -test_prefix.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -^\[assertion.1\] assertion at file test_prefix.java line 14: SUCCESS$ -^\[assertion.2\] assertion at file test_prefix.java line 16: FAILURE$ -^\[assertion.3\] assertion at file test_prefix.java line 18: SUCCESS$ -^\[assertion.4\] assertion at file test_prefix.java line 20: FAILURE$ --- diff --git a/regression/strings/java_prefix/test_prefix.class b/regression/strings/java_prefix/test_prefix.class deleted file mode 100644 index 6f5f4025932..00000000000 Binary files a/regression/strings/java_prefix/test_prefix.class and /dev/null differ diff --git a/regression/strings/java_prefix/test_prefix.java b/regression/strings/java_prefix/test_prefix.java deleted file mode 100644 index c9b5fa72fcf..00000000000 --- a/regression/strings/java_prefix/test_prefix.java +++ /dev/null @@ -1,23 +0,0 @@ -public class test_prefix { - - public static void main(String[] argv) { - String s = new String("Hello World!"); - //String t = new String("Hello"); - //String u = new String("Wello"); - String u = "Wello"; - boolean b = s.startsWith("Hello"); - //boolean c = s.startsWith("Wello"); - //boolean b = s.startsWith(t); - boolean c = s.startsWith(u); - boolean d = s.startsWith("lo",3); - if(argv.length == 1){ - assert(b); - } else if(argv.length == 2){ - assert(c); - } else if(argv.length == 3){ - assert(d); - } else if(argv.length == 4){ - assert(!d); - } - } -} diff --git a/regression/strings/java_replace/test.desc b/regression/strings/java_replace/test.desc deleted file mode 100644 index 1e89ebe37b4..00000000000 --- a/regression/strings/java_replace/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -FUTURE -test_replace.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -^\[assertion.1\] assertion at file test_replace.java line 6: SUCCESS$ -^\[assertion.2\] assertion at file test_replace.java line 8: FAILURE$ --- diff --git a/regression/strings/java_replace/test_replace.class b/regression/strings/java_replace/test_replace.class deleted file mode 100644 index c795826dc15..00000000000 Binary files a/regression/strings/java_replace/test_replace.class and /dev/null differ diff --git a/regression/strings/java_replace/test_replace.java b/regression/strings/java_replace/test_replace.java deleted file mode 100644 index 342bf9afddc..00000000000 --- a/regression/strings/java_replace/test_replace.java +++ /dev/null @@ -1,10 +0,0 @@ -public class test_replace { - - public static void main(String[] argv) { - String s = new String("Hello World!"); - String t = s.replace('o','u'); - assert(t.equals("Hellu Wurld!")); - System.out.println(t); - assert(!t.equals("Hellu Wurld!")); - } -} diff --git a/regression/strings/java_set_length/test.desc b/regression/strings/java_set_length/test.desc deleted file mode 100644 index 43f82a648fd..00000000000 --- a/regression/strings/java_set_length/test.desc +++ /dev/null @@ -1,9 +0,0 @@ -FUTURE -test_set_length.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -^\[assertion.1\] assertion at file test_set_length.java line 8: SUCCESS$ -^\[assertion.2\] assertion at file test_set_length.java line 9: SUCCESS$ -^\[assertion.3\] assertion at file test_set_length.java line 10: FAILURE$ --- diff --git a/regression/strings/java_set_length/test_set_length.class b/regression/strings/java_set_length/test_set_length.class deleted file mode 100644 index 8836640967a..00000000000 Binary files a/regression/strings/java_set_length/test_set_length.class and /dev/null differ diff --git a/regression/strings/java_set_length/test_set_length.java b/regression/strings/java_set_length/test_set_length.java deleted file mode 100644 index 97b20f2332d..00000000000 --- a/regression/strings/java_set_length/test_set_length.java +++ /dev/null @@ -1,12 +0,0 @@ -public class test_set_length { - - public static void main(String[] argv) { - - StringBuilder s = new StringBuilder("abc"); - s.setLength(10); - String t = s.toString(); - assert(t.startsWith("abc")); - assert(t.length() == 10); - assert(t.length() == 3); - } -} diff --git a/regression/strings/java_string_builder/test.desc b/regression/strings/java_string_builder/test.desc deleted file mode 100644 index 9712205b104..00000000000 --- a/regression/strings/java_string_builder/test.desc +++ /dev/null @@ -1,9 +0,0 @@ -FUTURE -test_string_builder.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -^\[assertion.1\] assertion at file test_string_builder.java line 11: SUCCESS$ -^\[assertion.2\] assertion at file test_string_builder.java line 12: SUCCESS$ -^\[assertion.3\] assertion at file test_string_builder.java line 13: FAILURE$ --- diff --git a/regression/strings/java_string_builder/test_string_builder.class b/regression/strings/java_string_builder/test_string_builder.class deleted file mode 100644 index 7a61d1f02be..00000000000 Binary files a/regression/strings/java_string_builder/test_string_builder.class and /dev/null differ diff --git a/regression/strings/java_string_builder/test_string_builder.java b/regression/strings/java_string_builder/test_string_builder.java deleted file mode 100644 index 1d76b34e9f8..00000000000 --- a/regression/strings/java_string_builder/test_string_builder.java +++ /dev/null @@ -1,16 +0,0 @@ -public class test_string_builder { - public static void main(String[] argv) { - if(argv.length > 2) { - StringBuilder tmp = new StringBuilder(); - tmp.append("prefix "); - tmp.append(argv[1]); - tmp.append(" middle ").append(argv[2]).append(" end"); - //StringBuilder tmp1 = tmp.append(argv[2]); - //tmp1.append(" end"); - String r = tmp.toString(); - assert(r.startsWith("pref")); - assert(r.endsWith("end")); - assert(r.startsWith("pr3f")); - } - } -} diff --git a/regression/strings/java_string_builder_insert/test.desc b/regression/strings/java_string_builder_insert/test.desc deleted file mode 100644 index 2655f846da1..00000000000 --- a/regression/strings/java_string_builder_insert/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -FUTURE -test_insert.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -^\[assertion.1\] assertion at file test_insert.java line 17: SUCCESS$ -^\[assertion.2\] assertion at file test_insert.java line 18: FAILURE$ --- diff --git a/regression/strings/java_string_builder_insert/test_insert.class b/regression/strings/java_string_builder_insert/test_insert.class deleted file mode 100644 index 69a32d7f93f..00000000000 Binary files a/regression/strings/java_string_builder_insert/test_insert.class and /dev/null differ diff --git a/regression/strings/java_string_builder_insert/test_insert.java b/regression/strings/java_string_builder_insert/test_insert.java deleted file mode 100644 index 1fac897c5ed..00000000000 --- a/regression/strings/java_string_builder_insert/test_insert.java +++ /dev/null @@ -1,20 +0,0 @@ -public class test_insert { - - public static void main(String[] argv) - { - char [] str = new char[5]; - str[0] = 'H'; - str[1] = 'e'; - str[2] = 'l'; - str[3] = 'l'; - str[4] = 'o'; - - - StringBuilder sb = new StringBuilder(" world"); - sb.insert(0,str); - String s = sb.toString(); - System.out.println(s); - assert(s.equals("Hello world")); - assert(!s.equals("Hello world")); - } -} diff --git a/regression/strings/java_string_builder_length/test.desc b/regression/strings/java_string_builder_length/test.desc deleted file mode 100644 index c4720992571..00000000000 --- a/regression/strings/java_string_builder_length/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -FUTURE -test_sb_length.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -\[assertion.1\] assertion at file test_sb_length.java line 6: SUCCESS$ -\[assertion.2\] assertion at file test_sb_length.java line 8: FAILURE$ --- diff --git a/regression/strings/java_string_builder_length/test_sb_length.class b/regression/strings/java_string_builder_length/test_sb_length.class deleted file mode 100644 index 586e8f71935..00000000000 Binary files a/regression/strings/java_string_builder_length/test_sb_length.class and /dev/null differ diff --git a/regression/strings/java_string_builder_length/test_sb_length.java b/regression/strings/java_string_builder_length/test_sb_length.java deleted file mode 100644 index 652b72cdc90..00000000000 --- a/regression/strings/java_string_builder_length/test_sb_length.java +++ /dev/null @@ -1,11 +0,0 @@ -public class test_sb_length { - public static void main(String[] argv) { - StringBuilder tmp = new StringBuilder("prefix"); - //tmp.append("prefix"); - tmp.append("end"); - assert(tmp.length() == 9); - if(argv.length > 1) { - assert(tmp.length() == 12); - } - } -} diff --git a/regression/strings/java_strlen/test.desc b/regression/strings/java_strlen/test.desc deleted file mode 100644 index b98e6f76f0a..00000000000 --- a/regression/strings/java_strlen/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -FUTURE -test_length.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -^\[assertion.1\] assertion at file test_length.java line 10: SUCCESS$ -^\[assertion.2\] assertion at file test_length.java line 11: FAILURE$ --- diff --git a/regression/strings/java_strlen/test_length.class b/regression/strings/java_strlen/test_length.class deleted file mode 100644 index 7f1c10c02ca..00000000000 Binary files a/regression/strings/java_strlen/test_length.class and /dev/null differ diff --git a/regression/strings/java_strlen/test_length.java b/regression/strings/java_strlen/test_length.java deleted file mode 100644 index 9410315db38..00000000000 --- a/regression/strings/java_strlen/test_length.java +++ /dev/null @@ -1,14 +0,0 @@ -public class test_length { - - public static void main(String[] argv) { - String s = new String("hello"); - if(argv.length > 1) { - String t = argv[1]; - int i = t.length(); - String u = t.concat(s); - char c = u.charAt(i); - assert(c == 'h'); - assert(c == 'o'); - } - } -} diff --git a/regression/strings/java_substring/test.desc b/regression/strings/java_substring/test.desc deleted file mode 100644 index bd54a8204fe..00000000000 --- a/regression/strings/java_substring/test.desc +++ /dev/null @@ -1,10 +0,0 @@ -FUTURE -test_substring.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -^\[assertion.1\] assertion at file test_substring.java line 12: SUCCESS$ -^\[assertion.2\] assertion at file test_substring.java line 13: FAILURE$ -^\[assertion.3\] assertion at file test_substring.java line 20: SUCCESS$ -^\[assertion.4\] assertion at file test_substring.java line 21: FAILURE$ --- diff --git a/regression/strings/java_substring/test_substring.class b/regression/strings/java_substring/test_substring.class deleted file mode 100644 index e6532aca43e..00000000000 Binary files a/regression/strings/java_substring/test_substring.class and /dev/null differ diff --git a/regression/strings/java_substring/test_substring.java b/regression/strings/java_substring/test_substring.java deleted file mode 100644 index 8a2ac883cca..00000000000 --- a/regression/strings/java_substring/test_substring.java +++ /dev/null @@ -1,27 +0,0 @@ -public class test_substring { - - public static void main(String[] argv) { - if(argv.length > 1) { - String t = argv[1]; - - if(t.length() == 6) { - String u = t.substring(2,4); - char c = u.charAt(1); - char d = t.charAt(3); - char e = t.charAt(4); - assert(c == d); - assert(c == e); - } - else if(t.length() == 5){ - CharSequence u = t.subSequence(2,4); - char c = u.charAt(1); - char d = t.charAt(3); - char e = t.charAt(4); - assert(c == d); - assert(c == e); - } - - - } - } -} diff --git a/regression/strings/java_suffix/test.desc b/regression/strings/java_suffix/test.desc deleted file mode 100644 index 2740e87d6e4..00000000000 --- a/regression/strings/java_suffix/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -FUTURE -test_suffix.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -^\[assertion.1\] assertion at file test_suffix.java line 12: SUCCESS$ -^\[assertion.2\] assertion at file test_suffix.java line 13: FAILURE$ --- diff --git a/regression/strings/java_suffix/test_suffix.class b/regression/strings/java_suffix/test_suffix.class deleted file mode 100644 index 557acd02653..00000000000 Binary files a/regression/strings/java_suffix/test_suffix.class and /dev/null differ diff --git a/regression/strings/java_suffix/test_suffix.java b/regression/strings/java_suffix/test_suffix.java deleted file mode 100644 index f61b0b8ba36..00000000000 --- a/regression/strings/java_suffix/test_suffix.java +++ /dev/null @@ -1,15 +0,0 @@ -public class test_suffix { - - public static void main(String[] argv) { - String s = new String("Hello World!"); - //String t = new String("Hello"); - //String u = new String("Wello"); - String u = "Wello!"; - boolean b = s.endsWith("World!"); - //boolean c = s.startsWith("Wello"); - //boolean b = s.startsWith(t); - boolean c = s.startsWith(u); - assert(b); - assert(c); - } -} diff --git a/regression/strings/java_trim/test.desc b/regression/strings/java_trim/test.desc deleted file mode 100644 index 7c0f1a87978..00000000000 --- a/regression/strings/java_trim/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -FUTURE -test_trim.class ---string-refine -^EXIT=10$ -^SIGNAL=0$ -^\[assertion.1\] assertion at file test_trim.java line 5: SUCCESS$ -^\[assertion.2\] assertion at file test_trim.java line 6: FAILURE$ --- diff --git a/regression/strings/java_trim/test_trim.class b/regression/strings/java_trim/test_trim.class deleted file mode 100644 index 8e6a923dcbc..00000000000 Binary files a/regression/strings/java_trim/test_trim.class and /dev/null differ diff --git a/regression/strings/java_trim/test_trim.java b/regression/strings/java_trim/test_trim.java deleted file mode 100644 index 8d8d41cb29a..00000000000 --- a/regression/strings/java_trim/test_trim.java +++ /dev/null @@ -1,8 +0,0 @@ -public class test_trim { - public static void main(String[] argv) { - String t = " a b c "; - String x = t.trim(); - assert(x.equals("a b c")); - assert(x.equals("abc ")); - } -} diff --git a/regression/strings/test1/test.desc b/regression/strings/test1/test.desc index b86ded86c18..2e0b38c3ae3 100644 --- a/regression/strings/test1/test.desc +++ b/regression/strings/test1/test.desc @@ -1,6 +1,6 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^\[main.assertion.1\] assertion c1 == c2: SUCCESS$ diff --git a/regression/strings/test2/test.desc b/regression/strings/test2/test.desc index b322a1d0d33..809cbcdaa29 100644 --- a/regression/strings/test2/test.desc +++ b/regression/strings/test2/test.desc @@ -1,6 +1,6 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^\[main.assertion.1\] assertion n == 5: SUCCESS$ diff --git a/regression/strings/test3.1/test.desc b/regression/strings/test3.1/test.desc index c88a62b6704..6fddff4c129 100644 --- a/regression/strings/test3.1/test.desc +++ b/regression/strings/test3.1/test.desc @@ -1,6 +1,6 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/test3.2/test.desc b/regression/strings/test3.2/test.desc index c88a62b6704..6fddff4c129 100644 --- a/regression/strings/test3.2/test.desc +++ b/regression/strings/test3.2/test.desc @@ -1,6 +1,6 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/test3.3/test.desc b/regression/strings/test3.3/test.desc index c88a62b6704..6fddff4c129 100644 --- a/regression/strings/test3.3/test.desc +++ b/regression/strings/test3.3/test.desc @@ -1,6 +1,6 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/test3.4/test.desc b/regression/strings/test3.4/test.desc index d88e1c83744..fc1cde2392c 100644 --- a/regression/strings/test3.4/test.desc +++ b/regression/strings/test3.4/test.desc @@ -1,7 +1,7 @@ FUTURE -test.c ---string-refine -^EXIT=10$ +test_init.class +--refine-strings +^EXIT=0$ ^SIGNAL=0$ -^VERIFICATION FAILED$ +^VERIFICATION SUCCESSFUL$ -- diff --git a/regression/strings/test3/test.desc b/regression/strings/test3/test.desc index 24ed719acc2..f6f9a63520a 100644 --- a/regression/strings/test3/test.desc +++ b/regression/strings/test3/test.desc @@ -1,6 +1,6 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^\[main.assertion.1\] assertion __CPROVER_string_length\(s\) == i \+ 5: SUCCESS$ diff --git a/regression/strings/test4/test.desc b/regression/strings/test4/test.desc index c88a62b6704..6fddff4c129 100644 --- a/regression/strings/test4/test.desc +++ b/regression/strings/test4/test.desc @@ -1,6 +1,6 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/strings/test5/test.desc b/regression/strings/test5/test.desc index d88e1c83744..303defd9de4 100644 --- a/regression/strings/test5/test.desc +++ b/regression/strings/test5/test.desc @@ -1,6 +1,6 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^VERIFICATION FAILED$ diff --git a/regression/strings/test_char_set/test.desc b/regression/strings/test_char_set/test.desc index 99f3cfd81de..360759faf98 100644 --- a/regression/strings/test_char_set/test.desc +++ b/regression/strings/test_char_set/test.desc @@ -1,8 +1,8 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[main.assertion.1\] assertion __CPROVER_string_equal\(t, __CPROVER_string_literal\("apc"\)): SUCCESS$ -^\[main.assertion.2\] assertion __CPROVER_string_equal\(t, __CPROVER_string_literal\("abc"\)): FAILURE$ +^\[.*assertion.1\].* SUCCESS$ +^\[.*assertion.2\].* FAILURE$ -- diff --git a/regression/strings/test_concat/test.desc b/regression/strings/test_concat/test.desc index 8df68c18bc3..317a4d1b4dd 100644 --- a/regression/strings/test_concat/test.desc +++ b/regression/strings/test_concat/test.desc @@ -1,6 +1,6 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^\[main.assertion.1\] assertion c == .p.: SUCCESS$ diff --git a/regression/strings/test_contains/test.desc b/regression/strings/test_contains/test.desc index f2414880794..b0e33ce2b43 100644 --- a/regression/strings/test_contains/test.desc +++ b/regression/strings/test_contains/test.desc @@ -1,6 +1,6 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^\[main.assertion.1\] assertion !__CPROVER_uninterpreted_string_contains_func\(t, __CPROVER_uninterpreted_string_literal_func\(\"3\"\)): SUCCESS$ diff --git a/regression/strings/test_equal/test.desc b/regression/strings/test_equal/test.desc index 5fbe05f8fdd..34297ec50f5 100644 --- a/regression/strings/test_equal/test.desc +++ b/regression/strings/test_equal/test.desc @@ -1,8 +1,8 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[main.assertion.1\] assertion __CPROVER_string_equal\(s, __CPROVER_string_literal\("pippo"\)): SUCCESS$ -^\[main.assertion.2\] assertion __CPROVER_string_equal\(s, __CPROVER_string_literal\("mippo"\)): FAILURE$ +^\[.*.assertion.1\].* SUCCESS$ +^\[.*.assertion.2\].* FAILURE$ -- diff --git a/regression/strings/test_index_of/test.desc b/regression/strings/test_index_of/test.desc index edc8e09c4ed..a2c12c3d259 100644 --- a/regression/strings/test_index_of/test.desc +++ b/regression/strings/test_index_of/test.desc @@ -1,6 +1,6 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^\[main.assertion.1\] assertion firstSlash == 3: SUCCESS$ diff --git a/regression/strings/test_int/test.desc b/regression/strings/test_int/test.desc index 8d78e11e71b..fcce43ca76c 100644 --- a/regression/strings/test_int/test.desc +++ b/regression/strings/test_int/test.desc @@ -1,6 +1,6 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^\[main.assertion.1\] assertion __CPROVER_char_at\(s,0\) == .1.: SUCCESS$ diff --git a/regression/strings/test_pass1/test.desc b/regression/strings/test_pass1/test.desc index 9bb75eda5b6..f2f54e69921 100644 --- a/regression/strings/test_pass1/test.desc +++ b/regression/strings/test_pass1/test.desc @@ -1,6 +1,6 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^\[main.assertion.1\] assertion __CPROVER_uninterpreted_string_equal_func\(t, __CPROVER_uninterpreted_string_literal_func\(\"a\"\)): SUCCESS diff --git a/regression/strings/test_pass_pc3/test.desc b/regression/strings/test_pass_pc3/test.desc index 3edb9f68f7a..f1f3d1618c8 100644 --- a/regression/strings/test_pass_pc3/test.desc +++ b/regression/strings/test_pass_pc3/test.desc @@ -1,6 +1,6 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^\[main.assertion.1\] assertion __CPROVER_string_length\(s3\) == 0: FAILURE$ diff --git a/regression/strings/test_prefix/test.desc b/regression/strings/test_prefix/test.desc index 6c62a2fa466..be0ed5dc69e 100644 --- a/regression/strings/test_prefix/test.desc +++ b/regression/strings/test_prefix/test.desc @@ -1,6 +1,6 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^\[main.assertion.1\] assertion b: SUCCESS$ diff --git a/regression/strings/test_strlen/test.desc b/regression/strings/test_strlen/test.desc index 30c3f4066ed..28ed1b7e698 100644 --- a/regression/strings/test_strlen/test.desc +++ b/regression/strings/test_strlen/test.desc @@ -1,6 +1,6 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^\[main.assertion.1\] assertion len_s == len_t: SUCCESS$ diff --git a/regression/strings/test_substring/test.desc b/regression/strings/test_substring/test.desc index a32376aca23..f0e4b5832b2 100644 --- a/regression/strings/test_substring/test.desc +++ b/regression/strings/test_substring/test.desc @@ -1,10 +1,10 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ -^\[main.assertion.1\] assertion __CPROVER_string_equal\(t,__CPROVER_string_literal\("cd"\)): SUCCESS$ -^\[main.assertion.2\] assertion __CPROVER_string_equal\(t,__CPROVER_string_literal\("cc"\)): FAILURE$ -^\[main.assertion.3\] assertion !__CPROVER_string_equal\(t,__CPROVER_string_literal\("bc"\)): SUCCESS$ -^\[main.assertion.4\] assertion !__CPROVER_string_equal\(t,__CPROVER_string_literal\("cd"\)): FAILURE$ +^\[.*assertion.1\].* SUCCESS$ +^\[.*assertion.2\].* FAILURE$ +^\[.*assertion.3\].* SUCCESS$ +^\[.*assertion.4\].* FAILURE$ -- diff --git a/regression/strings/test_suffix/test.desc b/regression/strings/test_suffix/test.desc index 9f425595434..e7e8c1e36be 100644 --- a/regression/strings/test_suffix/test.desc +++ b/regression/strings/test_suffix/test.desc @@ -1,6 +1,6 @@ FUTURE test.c ---string-refine +--refine-strings ^EXIT=10$ ^SIGNAL=0$ ^\[main.assertion.1\] assertion __CPROVER_string_issuffix\(__CPROVER_string_literal\("po"\),s\): SUCCESS$ diff --git a/scripts/bash-autocomplete/.gitignore b/scripts/bash-autocomplete/.gitignore new file mode 100644 index 00000000000..1e0acedc4f2 --- /dev/null +++ b/scripts/bash-autocomplete/.gitignore @@ -0,0 +1 @@ +cbmc.sh diff --git a/scripts/bash-autocomplete/Readme.md b/scripts/bash-autocomplete/Readme.md new file mode 100644 index 00000000000..00101d99159 --- /dev/null +++ b/scripts/bash-autocomplete/Readme.md @@ -0,0 +1,31 @@ +# CBMC Autocomplete Scripts for Bash +This directory contains an autocomplete script for bash. +## Installation +1. Compile cbmc and + +2. `cd scripts/bash-autocomplete` + +3. `./extract-switches.sh` + +4. Put the following at the end of you in your `~/.bashrc`, with the directories adapted to your directory structure: + ```bash + cbmcautocomplete=~/diffblue/cbmc/scripts/bash-autocomplete/cbmc.sh + if [ -f $cbmcautocomplete ]; then + . $cbmcautocomplete + fi + ``` +## Usage +As with the usual autocomplete in bash, start typing a switch to complete it, for example: +``` +cbmc --clas +``` +will complete to +``` +cbmc --classpath +``` + +## Features implemented + +* Completing all switches +* Completing values for `--cover`, `--mm` and `--arch` +* When completing a name of a file to analyze, only files with supported extensions are shown. diff --git a/scripts/bash-autocomplete/cbmc.sh.template b/scripts/bash-autocomplete/cbmc.sh.template new file mode 100644 index 00000000000..cbd64762b2d --- /dev/null +++ b/scripts/bash-autocomplete/cbmc.sh.template @@ -0,0 +1,43 @@ +#!/bin/bash +_cbmc_autocomplete() +{ + #list of all switches cbmc has. IMPORTANT: in the template file, this variable must be defined on line 5. + local switches="" + #word on which the cursor is + local cur=${COMP_WORDS[COMP_CWORD]} + #previous word (in case it is a switch with a parameter) + local prev=${COMP_WORDS[COMP_CWORD-1]} + + #check if the command before cursor is a switch that takes parameters, if yes, + #offer a choice of parameters + case "$prev" in + --cover) #for coverage we list the options explicitly + COMPREPLY=( $( compgen -W "assertion path branch location decision condition mcdc cover" -- $cur ) ) + return 0 + ;; + --mm) #for memory models we list the options explicitly + COMPREPLY=( $( compgen -W "sc tso pso" -- $cur ) ) + return 0 + ;; + --arch) #for architecture we list the options explicitly + COMPREPLY=( $( compgen -W "i386 x86_64" -- $cur ) ) + return 0 + ;; + -I|--classpath|-cp|--outfile|--existing-coverage|--graphml-cex) + #a switch that takes a file parameter of which we don't know an extension + #TODO probably we can do more for -I, --classpath, -cp + _filedir + return 0 + ;; + esac + + #complete a switch from a standard list, if the parameter under cursor starts with a hyphen + if [[ "$cur" == -* ]]; then + COMPREPLY=( $( compgen -W "$switches" -- $cur ) ) + return 0 + fi + + #if none of the above applies, offer directories and files that we can analyze + _filedir "@(class|jar|cpp|cc|c\+\+|ii|cxx|c|i|gb)" +} +complete -F _cbmc_autocomplete cbmc diff --git a/scripts/bash-autocomplete/extract_switches.sh b/scripts/bash-autocomplete/extract_switches.sh new file mode 100755 index 00000000000..e000b469bea --- /dev/null +++ b/scripts/bash-autocomplete/extract_switches.sh @@ -0,0 +1,48 @@ +#!/bin/bash +echo "Compiling the helper file to extract the raw list of parameters from cbmc" +g++ -c -MMD -MP -std=c++11 -Wall -I ../../src/ -ftrack-macro-expansion=0 -fno-diagnostics-show-caret switch_extractor_helper.c -o tmp.o 2> pragma.txt + +retval=$? + +#clean up compiled files, we don't need them. +rm tmp.o 2> /dev/null +rm tmp.d 2> /dev/null + +#check if compilation went fine +if [ $retval -ne 0 ]; then + echo "Problem compiling the helper file, parameter list not extracted." + exit 1; +fi + +echo "Converting the raw parameter list to the format required by autocomplete scripts" +rawstring=`sed "s/^.*pragma message: \(.*\)/\1/" pragma.txt` +#delete pragma file, we won't need it +rm pragma.txt 2> /dev/null + +#now the main bit, convert from raw format to a proper list of switches +cleanstring=`( + #extract 2-hyphen switches, such as --foo + #grep for '(foo)' expressions, and then use sed to remove parantheses and put '--' at the start + (echo $rawstring | grep -o "([^)]*)" | sed "s/^.\(.*\).$/--\1/") ; + #extract 1-hyphen switches, such as -F + #use sed to remove all (foo) expressions, then you're left with switches and ':', so grep the colons out and then use sed to include the '-' + (echo $rawstring | sed "s/([^)]*)//g" | grep -o "[a-zA-Z0-9]" | sed "s/\(.*\)/-\1/") + ) | tr '\n' ' '` + +#sanity check that there is only one line of output +if [ `echo $cleanstring | wc -l | awk '{print $1}'` -ne 1 ]; then + echo "Problem converting the parameter list to the correct format, I was expecting one line but either got 0 or >2. This is likely to be an error in this conversion script." + exit 1; +fi + +#sanity check that there are no dangerous characters +echo $cleanstring | grep -q "[^a-zA-Z0-9 -]" +if [ $? -eq 0 ]; then + echo "Problem converting the parameter list to the correct format, illegal characters detected. This is likely to be an error in this conversion script." + exit 1; +fi + +echo "Injecting the parameter list to the autocomplete file." +sed "5 s/.*/ local switches=\"$cleanstring\"/" cbmc.sh.template > cbmc.sh + +rm pragma.txt 2> /dev/null diff --git a/scripts/bash-autocomplete/switch_extractor_helper.c b/scripts/bash-autocomplete/switch_extractor_helper.c new file mode 100644 index 00000000000..4d9cc2e56fe --- /dev/null +++ b/scripts/bash-autocomplete/switch_extractor_helper.c @@ -0,0 +1,3 @@ +#include "cbmc/cbmc_parse_options.h" + +#pragma message CBMC_OPTIONS diff --git a/src/Makefile b/src/Makefile index cc2a5831d8e..6d2c3f0a8fd 100644 --- a/src/Makefile +++ b/src/Makefile @@ -84,4 +84,12 @@ glucose-download: @(cd ../glucose-syrup; patch -p1 < ../scripts/glucose-syrup-patch) @rm glucose-syrup.tgz -.PHONY: minisat2-download glucose-download +cprover-jar-build: + @echo "Building org.cprover.jar" + @(cd java_bytecode/library/; \ + mkdir -p target; \ + javac -d target/ `find src/ -name "*.java"`; \ + cd target; jar cf org.cprover.jar `find . -name "*.class"`; \ + mv org.cprover.jar ../../../) + +.PHONY: minisat2-download glucose-download cprover-jar-build diff --git a/src/cbmc/cbmc_parse_options.cpp b/src/cbmc/cbmc_parse_options.cpp index d2f1c178d8e..61678e03c03 100644 --- a/src/cbmc/cbmc_parse_options.cpp +++ b/src/cbmc/cbmc_parse_options.cpp @@ -24,6 +24,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include #include #include #include @@ -288,6 +289,16 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options) options.set_option("refine-arithmetic", true); } + if(cmdline.isset("refine-strings")) + { + options.set_option("refine-strings", true); + options.set_option("string-non-empty", cmdline.isset("string-non-empty")); + options.set_option("string-printable", cmdline.isset("string-printable")); + if(cmdline.isset("string-max-length")) + options.set_option( + "string-max-length", cmdline.get_value("string-max-length")); + } + if(cmdline.isset("max-node-refinement")) options.set_option( "max-node-refinement", @@ -811,6 +822,14 @@ bool cbmc_parse_optionst::process_goto_program( status() << "Partial Inlining" << eom; goto_partial_inline(goto_functions, ns, ui_message_handler); + + if(cmdline.isset("refine-strings")) + { + status() << "Preprocessing for string refinement" << eom; + string_refine_preprocesst( + symbol_table, goto_functions, ui_message_handler); + } + // remove returns, gcc vectors, complex remove_returns(symbol_table, goto_functions); remove_vector(symbol_table, goto_functions); @@ -1070,6 +1089,10 @@ void cbmc_parse_optionst::help() " --yices use Yices\n" " --z3 use Z3\n" " --refine use refinement procedure (experimental)\n" + " --refine-strings use string refinement (experimental)\n" + " --string-non-empty add constraint that strings are non empty (experimental)\n" // NOLINT(*) + " --string-printable add constraint that strings are printable (experimental)\n" // NOLINT(*) + " --string-max-length add constraint on the length of strings (experimental)\n" // NOLINT(*) " --outfile filename output formula to given file\n" " --arrays-uf-never never turn arrays into uninterpreted functions\n" // NOLINT(*) " --arrays-uf-always always turn arrays into uninterpreted functions\n" // NOLINT(*) diff --git a/src/cbmc/cbmc_parse_options.h b/src/cbmc/cbmc_parse_options.h index d95e60eb25b..4f43637234a 100644 --- a/src/cbmc/cbmc_parse_options.h +++ b/src/cbmc/cbmc_parse_options.h @@ -41,6 +41,10 @@ class optionst; "(no-sat-preprocessor)" \ "(no-pretty-names)(beautify)" \ "(dimacs)(refine)(max-node-refinement):(refine-arrays)(refine-arithmetic)"\ + "(refine-strings)" \ + "(string-non-empty)" \ + "(string-printable)" \ + "(string-max-length):" \ "(aig)(16)(32)(64)(LP64)(ILP64)(LLP64)(ILP32)(LP32)" \ "(little-endian)(big-endian)" \ "(show-goto-functions)(show-loops)" \ diff --git a/src/cbmc/cbmc_solvers.cpp b/src/cbmc/cbmc_solvers.cpp index 2fb47bf2396..41e029926e9 100644 --- a/src/cbmc/cbmc_solvers.cpp +++ b/src/cbmc/cbmc_solvers.cpp @@ -17,6 +17,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include #include #include #include @@ -159,6 +160,39 @@ cbmc_solverst::solvert* cbmc_solverst::get_bv_refinement() return new solvert(bv_refinement, prop); } +/*******************************************************************\ + +Function: cbmc_solverst::get_string_refinement + + Outputs: a solver for cbmc + + Purpose: the string refinement adds to the bit vector refinement + specifications for functions from the Java string library + +\*******************************************************************/ + +cbmc_solverst::solvert* cbmc_solverst::get_string_refinement() +{ + propt *prop; + prop=new satcheck_no_simplifiert(); + prop->set_message_handler(get_message_handler()); + + string_refinementt *string_refinement=new string_refinementt( + ns, *prop, MAX_NB_REFINEMENT); + string_refinement->set_ui(ui); + + string_refinement->do_concretizing=options.get_bool_option("trace"); + if(options.get_bool_option("string-max-length")) + string_refinement->set_max_string_length( + options.get_signed_int_option("string-max-length")); + if(options.get_bool_option("string-non-empty")) + string_refinement->enforce_non_empty_string(); + if(options.get_bool_option("string-printable")) + string_refinement->enforce_printable_characters(); + + return new solvert(string_refinement, prop); +} + cbmc_solverst::solvert* cbmc_solverst::get_smt1(smt1_dect::solvert solver) { no_beautification(); diff --git a/src/cbmc/cbmc_solvers.h b/src/cbmc/cbmc_solvers.h index 9bc51021039..f17f9b663bf 100644 --- a/src/cbmc/cbmc_solvers.h +++ b/src/cbmc/cbmc_solvers.h @@ -108,15 +108,17 @@ class cbmc_solverst:public messaget solvert *solver; if(options.get_bool_option("dimacs")) - solver = get_dimacs(); + solver=get_dimacs(); else if(options.get_bool_option("refine")) - solver = get_bv_refinement(); + solver=get_bv_refinement(); + else if(options.get_bool_option("refine-strings")) + solver=get_string_refinement(); else if(options.get_bool_option("smt1")) - solver = get_smt1(get_smt1_solver_type()); + solver=get_smt1(get_smt1_solver_type()); else if(options.get_bool_option("smt2")) - solver = get_smt2(get_smt2_solver_type()); + solver=get_smt2(get_smt2_solver_type()); else - solver = get_default(); + solver=get_default(); return std::unique_ptr(solver); } @@ -138,6 +140,7 @@ class cbmc_solverst:public messaget solvert *get_default(); solvert *get_dimacs(); solvert *get_bv_refinement(); + solvert *get_string_refinement(); solvert *get_smt1(smt1_dect::solvert solver); solvert *get_smt2(smt2_dect::solvert solver); diff --git a/src/goto-instrument/cover.cpp b/src/goto-instrument/cover.cpp index f2d17617ccd..7ed202c5565 100644 --- a/src/goto-instrument/cover.cpp +++ b/src/goto-instrument/cover.cpp @@ -13,9 +13,16 @@ Date: May 2016 #include #include +#include +#include #include #include +#include +#include +#include + +#include #include "cover.h" @@ -32,6 +39,11 @@ class basic_blockst if(next_is_target || it->is_target()) block_count++; + const irep_idt &line=it->source_location.get_line(); + if(!line.empty()) + block_line_cover_map[block_count] + .insert(unsafe_string2unsigned(id2string(line))); + block_map[it]=block_count; if(!it->source_location.is_nil() && @@ -39,7 +51,26 @@ class basic_blockst source_location_map[block_count]=it->source_location; next_is_target= +#if 0 + // Disabled for being too messy it->is_goto() || it->is_function_call() || it->is_assume(); +#else + it->is_goto() || it->is_function_call(); +#endif + } + + // create list of covered lines as CSV string and set as property of source + // location of basic block, compress to ranges if applicable + format_number_ranget format_lines; + for(const auto &cover_set : block_line_cover_map) + { + assert(!cover_set.second.empty()); + std::vector + line_list{cover_set.second.begin(), cover_set.second.end()}; + + std::string covered_lines=format_lines(line_list); + source_location_map[cover_set.first] + .set_basic_block_covered_lines(covered_lines); } } @@ -51,6 +82,11 @@ class basic_blockst typedef std::map source_location_mapt; source_location_mapt source_location_map; + // map block numbers to set of line numbers + typedef std::map > + block_line_cover_mapt; + block_line_cover_mapt block_line_cover_map; + inline unsigned operator[](goto_programt::const_targett t) { return block_map[t]; @@ -68,6 +104,111 @@ class basic_blockst } }; +/*******************************************************************\ + +Function: coverage_goalst::get_coverage + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool coverage_goalst::get_coverage_goals( + const std::string &coverage_file, + message_handlert &message_handler, + coverage_goalst &goals) +{ + jsont json; + source_locationt source_location; + + // check coverage file + if(parse_json(coverage_file, message_handler, json)) + { + messaget message(message_handler); + message.error() << coverage_file << " file is not a valid json file" + << messaget::eom; + return true; + } + + // make sure that we have an array of elements + if(!json.is_array()) + { + messaget message(message_handler); + message.error() << "expecting an array in the " << coverage_file + << " file, but got " + << json << messaget::eom; + return true; + } + + for(const auto &goal : json.array) + { + // get the file of each existing goal + irep_idt file=goal["file"].value; + source_location.set_file(file); + + // get the function of each existing goal + irep_idt function=goal["function"].value; + source_location.set_function(function); + + // get the lines array + if(goal["lines"].is_array()) + { + for(const auto &line_json : goal["lines"].array) + { + // get the line of each existing goal + irep_idt line=line_json["number"].value; + source_location.set_line(line); + goals.add_goal(source_location); + } + } + } + return false; +} + +/*******************************************************************\ + +Function: coverage_goalst::add_goal + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void coverage_goalst::add_goal(source_locationt goal) +{ + existing_goals.push_back(goal); +} + +/*******************************************************************\ + +Function: coverage_goalst::is_existing_goal + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool coverage_goalst::is_existing_goal(source_locationt source_location) const +{ + for(const auto &existing_loc : existing_goals) + { + if(source_location.get_file()==existing_loc.get_file() && + source_location.get_function()==existing_loc.get_function() && + source_location.get_line()==existing_loc.get_line()) + return true; + } + return false; +} + const char *as_string(coverage_criteriont c) { switch(c) @@ -299,7 +440,7 @@ std::set collect_mcdc_controlling_nested( const std::set &decisions) { // To obtain the 1st-level controlling conditions - std::set controlling = collect_mcdc_controlling(decisions); + std::set controlling=collect_mcdc_controlling(decisions); std::set result; // For each controlling condition, to check if it contains @@ -490,7 +631,7 @@ void remove_repetition(std::set &exprs) **/ for(auto &y : new_exprs) { - bool iden = true; + bool iden=true; for(auto &c : conditions) { std::set signs1=sign_of_expr(c, x); @@ -532,7 +673,7 @@ void remove_repetition(std::set &exprs) } // update the original ''exprs'' - exprs = new_exprs; + exprs=new_exprs; } /// To evaluate the value of expr ''src'', according to the atomic expr values @@ -667,7 +808,8 @@ bool is_mcdc_pair( if(diff_count==1) return true; - else return false; + else + return false; } /// To check if we can find the mcdc pair of the input ''expr_set'' regarding @@ -769,7 +911,8 @@ void minimize_mcdc_controlling( { controlling=new_controlling; } - else break; + else + break; } } @@ -832,8 +975,68 @@ std::set collect_decisions(const goto_programt::const_targett t) void instrument_cover_goals( const symbol_tablet &symbol_table, goto_programt &goto_program, - coverage_criteriont criterion) + coverage_criteriont criterion, + bool function_only) +{ + coverage_goalst goals; // empty already covered goals + instrument_cover_goals( + symbol_table, + goto_program, + criterion, + goals, + function_only, + false); +} + +/*******************************************************************\ + +Function: program_is_trivial + + Inputs: Program `goto_program` + + Outputs: Returns true if trivial + + Purpose: Call a goto_program trivial unless it has: + * Any declarations + * At least 2 branches + * At least 5 assignments + +\*******************************************************************/ + +bool program_is_trivial(const goto_programt &goto_program) +{ + unsigned long count_assignments=0, count_goto=0; + forall_goto_program_instructions(i_it, goto_program) + { + if(i_it->is_goto()) + { + if((++count_goto)>=2) + return false; + } + else if(i_it->is_assign()) + { + if((++count_assignments)>=5) + return false; + } + else if(i_it->is_decl()) + return false; + } + + return true; +} + +void instrument_cover_goals( + const symbol_tablet &symbol_table, + goto_programt &goto_program, + coverage_criteriont criterion, + const coverage_goalst &goals, + bool function_only, + bool ignore_trivial) { + // exclude trivial coverage goals of a goto program + if(ignore_trivial && program_is_trivial(goto_program)) + return; + const namespacet ns(symbol_table); basic_blockst basic_blocks(goto_program); std::set blocks_done; @@ -848,21 +1051,30 @@ void instrument_cover_goals( Forall_goto_program_instructions(i_it, goto_program) { + std::string curr_function = id2string(i_it->function); + + // if the --cover-function-only flag is set, then we only add coverage + // instrumentation for the entry function + bool cover_curr_function= + !function_only || + curr_function.find(config.main)!=std::string::npos; + switch(criterion) { case coverage_criteriont::ASSERTION: // turn into 'assert(false)' to avoid simplification - if(i_it->is_assert()) + if(i_it->is_assert() && cover_curr_function) { i_it->guard=false_exprt(); i_it->source_location.set(ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); + i_it->source_location.set_function(i_it->function); } break; case coverage_criteriont::COVER: // turn __CPROVER_cover(x) into 'assert(!x)' - if(i_it->is_function_call()) + if(i_it->is_function_call() && cover_curr_function) { const code_function_callt &code_function_call= to_code_function_call(i_it->code); @@ -879,6 +1091,7 @@ void instrument_cover_goals( i_it->source_location.set_comment(comment); i_it->source_location.set(ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); + i_it->source_location.set_function(i_it->function); } } else if(i_it->is_assert()) @@ -898,10 +1111,15 @@ void instrument_cover_goals( source_locationt source_location= basic_blocks.source_location_map[block_nr]; - if(!source_location.get_file().empty() && + // check whether the current goal already exists + if(!goals.is_existing_goal(source_location) && + !source_location.get_file().empty() && !source_location.is_built_in()) + cover_curr_function) { - std::string comment="block "+b; + std::string comment= + "function "+id2string(i_it->function)+" block "+b; + const irep_idt function=i_it->function; goto_program.insert_before_swap(i_it); i_it->make_assertion(false_exprt()); i_it->source_location=source_location; @@ -909,7 +1127,7 @@ void instrument_cover_goals( i_it->source_location.set( ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); - + i_it->source_location.set_function(function); i_it++; } } @@ -920,7 +1138,8 @@ void instrument_cover_goals( if(i_it->is_assert()) i_it->make_skip(); - if(i_it==goto_program.instructions.begin()) + if(i_it==goto_program.instructions.begin() && + cover_curr_function) { // we want branch coverage to imply 'entry point of function' // coverage @@ -935,6 +1154,7 @@ void instrument_cover_goals( t->source_location.set_comment(comment); t->source_location.set(ID_coverage_criterion, coverage_criterion); t->source_location.set_property_class(property_class); + t->source_location.set_function(i_it->function); } if(i_it->is_goto() && !i_it->guard.is_true() && @@ -948,6 +1168,7 @@ void instrument_cover_goals( exprt guard=i_it->guard; source_locationt source_location=i_it->source_location; + source_location.set_function(i_it->function); goto_program.insert_before_swap(i_it); i_it->make_assertion(not_exprt(guard)); @@ -973,7 +1194,7 @@ void instrument_cover_goals( i_it->make_skip(); // Conditions are all atomic predicates in the programs. - if(!i_it->source_location.is_built_in()) + if(cover_curr_function) { const std::set conditions=collect_conditions(i_it); @@ -984,12 +1205,14 @@ void instrument_cover_goals( const std::string c_string=from_expr(ns, "", c); const std::string comment_t="condition `"+c_string+"' true"; + const irep_idt function=i_it->function; goto_program.insert_before_swap(i_it); i_it->make_assertion(c); i_it->source_location=source_location; i_it->source_location.set_comment(comment_t); i_it->source_location.set(ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); + i_it->source_location.set_function(function); const std::string comment_f="condition `"+c_string+"' false"; goto_program.insert_before_swap(i_it); @@ -998,6 +1221,7 @@ void instrument_cover_goals( i_it->source_location.set_comment(comment_f); i_it->source_location.set(ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); + i_it->source_location.set_function(function); } for(std::size_t i=0; imake_skip(); // Decisions are maximal Boolean combinations of conditions. - if(!i_it->source_location.is_built_in()) + if(cover_curr_function) { const std::set decisions=collect_decisions(i_it); @@ -1021,12 +1245,14 @@ void instrument_cover_goals( const std::string d_string=from_expr(ns, "", d); const std::string comment_t="decision `"+d_string+"' true"; + const irep_idt function=i_it->function; goto_program.insert_before_swap(i_it); i_it->make_assertion(d); i_it->source_location=source_location; i_it->source_location.set_comment(comment_t); i_it->source_location.set(ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); + i_it->source_location.set_function(function); const std::string comment_f="decision `"+d_string+"' false"; goto_program.insert_before_swap(i_it); @@ -1035,6 +1261,7 @@ void instrument_cover_goals( i_it->source_location.set_comment(comment_f); i_it->source_location.set(ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); + i_it->source_location.set_function(function); } for(std::size_t i=0; isource_location.is_built_in()) + if(cover_curr_function) { const std::set conditions=collect_conditions(i_it); const std::set decisions=collect_decisions(i_it); std::set both; - std::set_union(conditions.begin(), conditions.end(), - decisions.begin(), decisions.end(), - inserter(both, both.end())); + std::set_union( + conditions.begin(), + conditions.end(), + decisions.begin(), + decisions.end(), + inserter(both, both.end())); const source_locationt source_location=i_it->source_location; @@ -1075,6 +1305,7 @@ void instrument_cover_goals( std::string p_string=from_expr(ns, "", p); std::string comment_t=description+" `"+p_string+"' true"; + const irep_idt function=i_it->function; goto_program.insert_before_swap(i_it); // i_it->make_assertion(p); i_it->make_assertion(not_exprt(p)); @@ -1082,6 +1313,7 @@ void instrument_cover_goals( i_it->source_location.set_comment(comment_t); i_it->source_location.set(ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); + i_it->source_location.set_function(function); std::string comment_f=description+" `"+p_string+"' false"; goto_program.insert_before_swap(i_it); @@ -1091,6 +1323,7 @@ void instrument_cover_goals( i_it->source_location.set_comment(comment_f); i_it->source_location.set(ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); + i_it->source_location.set_function(function); } std::set controlling; @@ -1108,6 +1341,7 @@ void instrument_cover_goals( std::string description= "MC/DC independence condition `"+p_string+"'"; + const irep_idt function=i_it->function; goto_program.insert_before_swap(i_it); i_it->make_assertion(not_exprt(p)); // i_it->make_assertion(p); @@ -1115,6 +1349,7 @@ void instrument_cover_goals( i_it->source_location.set_comment(description); i_it->source_location.set(ID_coverage_criterion, coverage_criterion); i_it->source_location.set_property_class(property_class); + i_it->source_location.set_function(function); } for(std::size_t i=0; ifirst==goto_functions.entry_point() || - f_it->first=="__CPROVER_initialize" || + f_it->first==(CPROVER_PREFIX "initialize") || f_it->second.is_hidden()) continue; - instrument_cover_goals(symbol_table, f_it->second.body, criterion); + instrument_cover_goals( + symbol_table, + f_it->second.body, + criterion, + goals, + function_only, + ignore_trivial); } } @@ -1154,76 +1398,16 @@ bool instrument_cover_goals( const cmdlinet &cmdline, const symbol_tablet &symbol_table, goto_functionst &goto_functions, - message_handlert &msgh) + coverage_criteriont criterion, + bool function_only) { - messaget msg(msgh); - std::list criteria_strings=cmdline.get_values("cover"); - std::set criteria; - bool keep_assertions=false; - - for(const auto &criterion_string : criteria_strings) - { - coverage_criteriont c; - - if(criterion_string=="assertion" || criterion_string=="assertions") - { - keep_assertions=true; - c=coverage_criteriont::ASSERTION; - } - else if(criterion_string=="path" || criterion_string=="paths") - c=coverage_criteriont::PATH; - else if(criterion_string=="branch" || criterion_string=="branches") - c=coverage_criteriont::BRANCH; - else if(criterion_string=="location" || criterion_string=="locations") - c=coverage_criteriont::LOCATION; - else if(criterion_string=="decision" || criterion_string=="decisions") - c=coverage_criteriont::DECISION; - else if(criterion_string=="condition" || criterion_string=="conditions") - c=coverage_criteriont::CONDITION; - else if(criterion_string=="mcdc") - c=coverage_criteriont::MCDC; - else if(criterion_string=="cover") - c=coverage_criteriont::COVER; - else - { - msg.error() << "unknown coverage criterion " - << '\'' << criterion_string << '\'' - << messaget::eom; - return true; - } - - criteria.insert(c); - } - - if(keep_assertions && criteria_strings.size()>1) - { - msg.error() << "assertion coverage cannot currently be used together with " - << "other coverage criteria" << messaget::eom; - return true; - } - - msg.status() << "Rewriting existing assertions as assumptions" - << messaget::eom; - - if(!keep_assertions) - { - // turn assertions (from generic checks) into assumptions - Forall_goto_functions(f_it, goto_functions) - { - goto_programt &body=f_it->second.body; - Forall_goto_program_instructions(i_it, body) - { - if(i_it->is_assert()) - i_it->type=goto_program_instruction_typet::ASSUME; - } - } - } - - msg.status() << "Instrumenting coverage goals" << messaget::eom; - - for(const auto &criterion : criteria) - instrument_cover_goals(symbol_table, goto_functions, criterion); - - goto_functions.update(); - return false; + // empty set of existing goals + coverage_goalst goals; + instrument_cover_goals( + symbol_table, + goto_functions, + criterion, + goals, + function_only, + false); } diff --git a/src/goto-instrument/cover.h b/src/goto-instrument/cover.h index 5a8872bc324..0400b583d23 100644 --- a/src/goto-instrument/cover.h +++ b/src/goto-instrument/cover.h @@ -15,27 +15,53 @@ Date: May 2016 #define CPROVER_GOTO_INSTRUMENT_COVER_H #include -#include + +class coverage_goalst +{ +public: + static bool get_coverage_goals( + const std::string &coverage, + message_handlert &message_handler, + coverage_goalst &goals); + void add_goal(source_locationt goal); + bool is_existing_goal(source_locationt source_location) const; + +private: + std::vector existing_goals; +}; enum class coverage_criteriont { LOCATION, BRANCH, DECISION, CONDITION, PATH, MCDC, ASSERTION, COVER }; +void instrument_cover_goals( + const symbol_tablet &symbol_table, + goto_functionst &goto_functions, + coverage_criteriont, + bool function_only=false); + void instrument_cover_goals( const symbol_tablet &symbol_table, goto_programt &goto_program, - coverage_criteriont); + coverage_criteriont, + bool function_only=false); void instrument_cover_goals( const symbol_tablet &symbol_table, goto_functionst &goto_functions, - coverage_criteriont); + coverage_criteriont, + const coverage_goalst &goals, + bool function_only=false, + bool ignore_trivial=false); bool instrument_cover_goals( const cmdlinet &cmdline, const symbol_tablet &symbol_table, - goto_functionst &goto_functions, - message_handlert &msgh); + goto_programt &goto_program, + coverage_criteriont, + const coverage_goalst &goals, + bool function_only=false, + bool ignore_trivial=false); #endif // CPROVER_GOTO_INSTRUMENT_COVER_H diff --git a/src/goto-instrument/dump_c.cpp b/src/goto-instrument/dump_c.cpp index fa9ebf63359..7e67a6bf5b1 100644 --- a/src/goto-instrument/dump_c.cpp +++ b/src/goto-instrument/dump_c.cpp @@ -148,7 +148,8 @@ void dump_ct::operator()(std::ostream &os) // we don't want to dump in full all definitions; in particular // do not dump anonymous types that are defined in system headers - if((!tag_added || symbol.is_type) && ignore(symbol)) + if((!tag_added || symbol.is_type) && + system_symbols.is_symbol_internal_symbol(symbol, system_headers)) continue; bool inserted=symbols_sorted.insert(name_str).second; @@ -317,7 +318,7 @@ void dump_ct::convert_compound( ns.lookup(to_symbol_type(type).get_identifier()); DATA_INVARIANT(symbol.is_type, "symbol expected to be type symbol"); - if(!ignore(symbol)) + if(!system_symbols.is_symbol_internal_symbol(symbol, system_headers)) convert_compound(symbol.type, unresolved, recursive, os); } else if(type.id()==ID_c_enum_tag) @@ -326,7 +327,7 @@ void dump_ct::convert_compound( ns.lookup(to_c_enum_tag_type(type).get_identifier()); DATA_INVARIANT(symbol.is_type, "symbol expected to be type symbol"); - if(!ignore(symbol)) + if(!system_symbols.is_symbol_internal_symbol(symbol, system_headers)) convert_compound(symbol.type, unresolved, recursive, os); } else if(type.id()==ID_array || type.id()==ID_pointer) @@ -581,195 +582,6 @@ void dump_ct::convert_compound_enum( os << ";\n\n"; } -#define ADD_TO_SYSTEM_LIBRARY(v, header) \ - for(size_t i=0; isecond); - return true; - } - - if(use_all_headers && - has_prefix(file_str, "/usr/include/")) - { - if(file_str.find("/bits/")==std::string::npos) - { - // Do not include transitive includes of system headers! - std::string::size_type prefix_len=std::string("/usr/include/").size(); - system_headers.insert(file_str.substr(prefix_len)); - } - - return true; - } - - return false; -} - void dump_ct::cleanup_decl( code_declt &decl, std::list &local_static, diff --git a/src/goto-instrument/dump_c_class.h b/src/goto-instrument/dump_c_class.h index 255cb88677e..3c6fab3e652 100644 --- a/src/goto-instrument/dump_c_class.h +++ b/src/goto-instrument/dump_c_class.h @@ -18,6 +18,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include class dump_ct { @@ -35,7 +36,7 @@ class dump_ct use_all_headers(use_all_headers) { if(use_system_headers) - init_system_library_map(); + system_symbols=system_library_symbolst(); } virtual ~dump_ct() @@ -57,9 +58,7 @@ class dump_ct std::set system_headers; - typedef std::unordered_map - system_library_mapt; - system_library_mapt system_library_map; + system_library_symbolst system_symbols; typedef std::unordered_map declared_enum_constants_mapt; @@ -89,7 +88,6 @@ class dump_ct std::string type_to_string(const typet &type); std::string expr_to_string(const exprt &expr); - bool ignore(const symbolt &symbol); bool ignore(const typet &type); static std::string indent(const unsigned n) diff --git a/src/goto-instrument/goto_instrument_parse_options.cpp b/src/goto-instrument/goto_instrument_parse_options.cpp index b807b21dc9a..92995c74252 100644 --- a/src/goto-instrument/goto_instrument_parse_options.cpp +++ b/src/goto-instrument/goto_instrument_parse_options.cpp @@ -539,7 +539,7 @@ int goto_instrument_parse_optionst::doit() if(cmdline.isset("interpreter")) { status() << "Starting interpreter" << eom; - interpreter(symbol_table, goto_functions); + interpreter(symbol_table, goto_functions, get_message_handler()); return 0; } diff --git a/src/goto-programs/Makefile b/src/goto-programs/Makefile index a66b408a3c9..d93c93d5b7d 100644 --- a/src/goto-programs/Makefile +++ b/src/goto-programs/Makefile @@ -57,6 +57,8 @@ SRC = basic_blocks.cpp \ slice_global_inits.cpp \ string_abstraction.cpp \ string_instrumentation.cpp \ + string_refine_preprocess.cpp \ + system_library_symbols.cpp \ vcd_goto_trace.cpp \ wp.cpp \ write_goto_binary.cpp \ diff --git a/src/goto-programs/builtin_functions.cpp b/src/goto-programs/builtin_functions.cpp index a5bf81a722d..a6baf87b433 100644 --- a/src/goto-programs/builtin_functions.cpp +++ b/src/goto-programs/builtin_functions.cpp @@ -701,17 +701,20 @@ void goto_convertt::do_java_new_array( t_p->source_location=location; // zero-initialize the data - exprt zero_element= - zero_initializer( - data.type().subtype(), - location, - ns, - get_message_handler()); - codet array_set(ID_array_set); - array_set.copy_to_operands(data, zero_element); - goto_programt::targett t_d=dest.add_instruction(OTHER); - t_d->code=array_set; - t_d->source_location=location; + if(!rhs.get_bool(ID_skip_initialize)) + { + exprt zero_element= + zero_initializer( + data.type().subtype(), + location, + ns, + get_message_handler()); + codet array_set(ID_array_set); + array_set.copy_to_operands(data, zero_element); + goto_programt::targett t_d=dest.add_instruction(OTHER); + t_d->code=array_set; + t_d->source_location=location; + } if(rhs.operands().size()>=2) { diff --git a/src/goto-programs/goto_trace.cpp b/src/goto-programs/goto_trace.cpp index 4485aed5151..2e6921cb3de 100644 --- a/src/goto-programs/goto_trace.cpp +++ b/src/goto-programs/goto_trace.cpp @@ -51,9 +51,10 @@ void goto_trace_stept::output( case goto_trace_stept::typet::SHARED_READ: out << "SHARED_READ"; break; case goto_trace_stept::typet::SHARED_WRITE: out << "SHARED WRITE"; break; case goto_trace_stept::typet::FUNCTION_CALL: out << "FUNCTION CALL"; break; - case goto_trace_stept::typet::FUNCTION_RETURN: - out << "FUNCTION RETURN"; break; - default: assert(false); + case goto_trace_stept::typet::FUNCTION_RETURN: out << "FUNCTION RETURN"; break; + default: + out << "unknown type: " << type << std::endl; + assert(false); } if(type==typet::ASSERT || type==typet::ASSUME || type==typet::GOTO) diff --git a/src/goto-programs/goto_trace.h b/src/goto-programs/goto_trace.h index 4c8a3accc8a..02f230e8943 100644 --- a/src/goto-programs/goto_trace.h +++ b/src/goto-programs/goto_trace.h @@ -83,6 +83,9 @@ class goto_trace_stept // we may choose to hide a step bool hidden; + // this is related to an internal expression + bool internal; + // we categorize enum class assignment_typet { STATE, ACTUAL_PARAMETER }; assignment_typet assignment_type; @@ -127,6 +130,7 @@ class goto_trace_stept step_nr(0), type(typet::NONE), hidden(false), + internal(false), assignment_type(assignment_typet::STATE), thread_nr(0), cond_value(false), @@ -174,6 +178,13 @@ class goto_tracet steps.push_back(step); } + // retrieves the final step in the trace for manipulation + // (used to fill a trace from code, hence non-const) + inline goto_trace_stept &get_last_step() + { + return steps.back(); + } + // delete all steps after (not including) s void trim_after(stepst::iterator s) { diff --git a/src/goto-programs/interpreter.cpp b/src/goto-programs/interpreter.cpp index 8a5c23f1a62..5e06c8ec2be 100644 --- a/src/goto-programs/interpreter.cpp +++ b/src/goto-programs/interpreter.cpp @@ -12,18 +12,65 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include +#include #include +#include #include #include +#include +#include +#include +#include +#include #include "interpreter.h" #include "interpreter_class.h" +#include "remove_returns.h" + +const size_t interpretert::npos=std::numeric_limits::max(); void interpretert::operator()() +{ + status() << "0- Initialize:" << eom; + initialize(true); + try + { + status() << "Type h for help\n" << eom; + + while(!done) + command(); + + status() << total_steps << "- Program End.\n" << eom; + } + catch (const char *e) + { + error() << e << "\n" << eom; + } + + while(!done) + command(); +} + +/*******************************************************************\ + +Function: interpretert::initialize + + Inputs: + + Outputs: + + Purpose: Initializes the memory map of the interpreter and + [optionally] runs up to the entry point (thus doing + the cprover initialization) + +\*******************************************************************/ + +void interpretert::initialize(bool init) { build_memory_map(); + total_steps=0; const goto_functionst::function_mapt::const_iterator main_it=goto_functions.function_map.find(goto_functionst::entry_point()); @@ -35,36 +82,54 @@ void interpretert::operator()() if(!goto_function.body_available()) throw "main has no body"; - PC=goto_function.body.instructions.begin(); + pc=goto_function.body.instructions.begin(); function=main_it; done=false; - - while(!done) + if(init) { + stack_depth=call_stack.size()+1; show_state(); - command(); - if(!done) + step(); + while(!done && (stack_depth<=call_stack.size()) && (stack_depth!=npos)) + { + show_state(); + step(); + } + while(!done && (call_stack.size()==0)) + { + show_state(); step(); + } + clear_input_flags(); + input_vars.clear(); } } +/// displays the current position of the pc and corresponding code void interpretert::show_state() { - std::cout << "\n----------------------------------------------------\n"; + if(!show) + return; + status() << "\n" + << total_steps+1 + << " ----------------------------------------------------\n"; - if(PC==function->second.body.instructions.end()) + if(pc==function->second.body.instructions.end()) { - std::cout << "End of function `" - << function->first << "'\n"; + status() << "End of function `" << function->first << "'\n"; } else function->second.body.output_instruction( - ns, function->first, std::cout, PC); + ns, + function->first, + status(), + pc); - std::cout << '\n'; + status() << eom; } +/// reads a user command and executes it. void interpretert::command() { #define BUFSIZE 100 @@ -76,42 +141,140 @@ void interpretert::command() } char ch=tolower(command[0]); - if(ch=='q') done=true; + else if(ch=='h') + { + status() + << "Interpreter help\n" + << "h: display this menu\n" + << "j: output json trace\n" + << "m: output memory dump\n" + << "o: output goto trace\n" + << "q: quit\n" + << "r: run until completion\n" + << "s#: step a number of instructions\n" + << "sa: step across a function\n" + << "so: step out of a function\n" + << eom; + } + else if(ch=='j') + { + jsont json_steps; + convert(ns, steps, json_steps); + ch=tolower(command[1]); + if(ch==' ') + { + std::ofstream file; + file.open(command+2); + if(file.is_open()) + { + json_steps.output(file); + file.close(); + return; + } + } + json_steps.output(result()); + } + else if(ch=='m') + { + ch=tolower(command[1]); + print_memory(ch=='i'); + } + else if(ch=='o') + { + ch=tolower(command[1]); + if(ch==' ') + { + std::ofstream file; + file.open(command+2); + if(file.is_open()) + { + steps.output(ns, file); + file.close(); + return; + } + } + steps.output(ns, result()); + } + else if(ch=='r') + { + ch=tolower(command[1]); + initialize(ch!='0'); + } + else if((ch=='s') || (ch==0)) + { + num_steps=1; + stack_depth=npos; + ch=tolower(command[1]); + if(ch=='e') + num_steps=npos; + else if(ch=='o') + stack_depth=call_stack.size(); + else if(ch=='a') + stack_depth=call_stack.size()+1; + else + { + num_steps=atoi(command+1); + if(num_steps==0) + num_steps=1; + } + while(!done && ((num_steps==npos) || ((num_steps--)>0))) + { + step(); + show_state(); + } + while(!done && (stack_depth<=call_stack.size()) && (stack_depth!=npos)) + { + step(); + show_state(); + } + return; + } + show_state(); } +/// executes a single step and updates the program counter void interpretert::step() { - if(PC==function->second.body.instructions.end()) + total_steps++; + if(pc==function->second.body.instructions.end()) { if(call_stack.empty()) done=true; else { - PC=call_stack.top().return_PC; + pc=call_stack.top().return_pc; function=call_stack.top().return_function; - stack_pointer=call_stack.top().old_stack_pointer; + // TODO: this increases memory size quite quickly. + // Should check alternatives call_stack.pop(); } return; } - next_PC=PC; - next_PC++; + next_pc=pc; + next_pc++; - switch(PC->type) + steps.add_step(goto_trace_stept()); + goto_trace_stept &trace_step=steps.get_last_step(); + trace_step.thread_nr=thread_id; + trace_step.pc=pc; + switch(pc->type) { case GOTO: + trace_step.type=goto_trace_stept::GOTO; execute_goto(); break; case ASSUME: + trace_step.type=goto_trace_stept::ASSUME; execute_assume(); break; case ASSERT: + trace_step.type=goto_trace_stept::ASSERT; execute_assert(); break; @@ -120,38 +283,46 @@ void interpretert::step() break; case DECL: + trace_step.type=goto_trace_stept::DECL; execute_decl(); break; case SKIP: case LOCATION: + trace_step.type=goto_trace_stept::LOCATION; + break; case END_FUNCTION: + trace_step.type=goto_trace_stept::FUNCTION_RETURN; break; case RETURN: + trace_step.type=goto_trace_stept::FUNCTION_RETURN; if(call_stack.empty()) throw "RETURN without call"; // NOLINT(readability/throw) - if(PC->code.operands().size()==1 && + if(pc->code.operands().size()==1 && call_stack.top().return_value_address!=0) { - std::vector rhs; - evaluate(PC->code.op0(), rhs); + mp_vectort rhs; + evaluate(pc->code.op0(), rhs); assign(call_stack.top().return_value_address, rhs); } - next_PC=function->second.body.instructions.end(); + next_pc=function->second.body.instructions.end(); break; case ASSIGN: + trace_step.type=goto_trace_stept::ASSIGNMENT; execute_assign(); break; case FUNCTION_CALL: + trace_step.type=goto_trace_stept::FUNCTION_CALL; execute_function_call(); break; case START_THREAD: + trace_step.type=goto_trace_stept::SPAWN; throw "START_THREAD not yet implemented"; // NOLINT(readability/throw) case END_THREAD: @@ -159,44 +330,89 @@ void interpretert::step() break; case ATOMIC_BEGIN: + trace_step.type=goto_trace_stept::ATOMIC_BEGIN; throw "ATOMIC_BEGIN not yet implemented"; // NOLINT(readability/throw) case ATOMIC_END: + trace_step.type=goto_trace_stept::ATOMIC_END; throw "ATOMIC_END not yet implemented"; // NOLINT(readability/throw) case DEAD: - throw "DEAD not yet implemented"; // NOLINT(readability/throw) - + trace_step.type=goto_trace_stept::DEAD; + break; + case THROW: + trace_step.type=goto_trace_stept::GOTO; + while(!done && (pc->type!=CATCH)) + { + if(pc==function->second.body.instructions.end()) + { + if(call_stack.empty()) + done=true; + else + { + pc=call_stack.top().return_pc; + function=call_stack.top().return_function; + call_stack.pop(); + } + } + else + { + next_pc=pc; + next_pc++; + } + } + break; + case CATCH: + break; default: throw "encountered instruction with undefined instruction type"; } - - PC=next_PC; + pc=next_pc; } +/// executes a goto instruction void interpretert::execute_goto() { - if(evaluate_boolean(PC->guard)) + if(evaluate_boolean(pc->guard)) { - if(PC->targets.empty()) + if(pc->targets.empty()) throw "taken goto without target"; - if(PC->targets.size()>=2) + if(pc->targets.size()>=2) throw "non-deterministic goto encountered"; - next_PC=PC->targets.front(); + next_pc=pc->targets.front(); } } +/// executes side effects of 'other' instructions void interpretert::execute_other() { - const irep_idt &statement=PC->code.get_statement(); - + const irep_idt &statement=pc->code.get_statement(); if(statement==ID_expression) { - assert(PC->code.operands().size()==1); - std::vector rhs; - evaluate(PC->code.op0(), rhs); + assert(pc->code.operands().size()==1); + mp_vectort rhs; + evaluate(pc->code.op0(), rhs); + } + else if(statement==ID_array_set) + { + mp_vectort tmp, rhs; + evaluate(pc->code.op1(), tmp); + mp_integer address=evaluate_address(pc->code.op0()); + size_t size=get_size(pc->code.op0().type()); + while(rhs.size()code.get_statement()==ID_decl); + assert(pc->code.get_statement()==ID_decl); +} + +/*******************************************************************\ + +Function: interpretert::get_component_id + + Inputs: an object and a memory offset + + Outputs: + + Purpose: retrieves the member at offset + +\*******************************************************************/ + +irep_idt interpretert::get_component_id( + const irep_idt &object, + unsigned offset) +{ + const symbolt &symbol=ns.lookup(object); + const typet real_type=ns.follow(symbol.type); + if(real_type.id()!=ID_struct) + throw "request for member of non-struct"; + + const struct_typet &struct_type=to_struct_type(real_type); + const struct_typet::componentst &components=struct_type.components(); + for(struct_typet::componentst::const_iterator it=components.begin(); + it!=components.end(); it++) + { + if(offset<=0) + return it->id(); + size_t size=get_size(it->type()); + offset-=size; + } + return object; +} + +/*******************************************************************\ + +Function: interpretert::get_type + + Inputs: + + Outputs: + + Purpose: returns the type object corresponding to id + +\*******************************************************************/ + +typet interpretert::get_type(const irep_idt &id) const +{ + dynamic_typest::const_iterator it=dynamic_types.find(id); + if(it==dynamic_types.end()) + return symbol_table.lookup(id).type; + return it->second; +} + +/*******************************************************************\ + +Function: interpretert::get_value + + Inputs: + + Outputs: + + Purpose: retrives the constant value at memory location offset + as an object of type type + +\*******************************************************************/ + +exprt interpretert::get_value( + const typet &type, + std::size_t offset, + bool use_non_det) +{ + const typet real_type=ns.follow(type); + if(real_type.id()==ID_struct) + { + exprt result=struct_exprt(real_type); + const struct_typet &struct_type=to_struct_type(real_type); + const struct_typet::componentst &components=struct_type.components(); + + // Retrieve the values for the individual members + result.reserve_operands(components.size()); + for(struct_typet::componentst::const_iterator it=components.begin(); + it!=components.end(); it++) + { + size_t size=get_size(it->type()); + const exprt operand=get_value(it->type(), offset); + offset+=size; + result.copy_to_operands(operand); + } + return result; + } + else if(real_type.id()==ID_array) + { + // Get size of array + exprt result=array_exprt(to_array_type(real_type)); + const exprt &size_expr=static_cast(type.find(ID_size)); + size_t subtype_size=get_size(type.subtype()); + std::size_t count; + if(size_expr.id()!=ID_constant) + { + count=base_address_to_actual_size(offset)/subtype_size; + } + else + { + mp_integer mp_count; + to_integer(size_expr, mp_count); + count=integer2size_t(mp_count); + } + + // Retrieve the value for each member in the array + result.reserve_operands(count); + for(unsigned i=0; i=0)) + return side_effect_expr_nondett(type); + mp_vectort rhs; + rhs.push_back(memory[offset].value); + return get_value(type, rhs); +} + +/*******************************************************************\ + + Function: interpretert::get_value + + Inputs: + + Outputs: + + Purpose: returns the value at offset in the form of type given a + memory buffer rhs which is typically a structured type + +\*******************************************************************/ + +exprt interpretert::get_value( + const typet &type, + mp_vectort &rhs, + std::size_t offset) +{ + const typet real_type=ns.follow(type); + assert(!rhs.empty()); + + if(real_type.id()==ID_struct) + { + exprt result=struct_exprt(real_type); + const struct_typet &struct_type=to_struct_type(real_type); + const struct_typet::componentst &components=struct_type.components(); + + // Retrieve the values for the individual members + result.reserve_operands(components.size()); + for(const struct_union_typet::componentt &expr : components) + { + size_t size=get_size(expr.type()); + const exprt operand=get_value(expr.type(), rhs, offset); + offset+=size; + result.copy_to_operands(operand); + } + return result; + } + else if(real_type.id()==ID_array) + { + exprt result(ID_constant, type); + const exprt &size_expr=static_cast(type.find(ID_size)); + + // Get size of array + size_t subtype_size=get_size(type.subtype()); + unsigned count; + if(unbounded_size(type)) + { + count=base_address_to_actual_size(offset)/subtype_size; + } + else + { + mp_integer mp_count; + to_integer(size_expr, mp_count); + count=integer2unsigned(mp_count); + } + + // Retrieve the value for each member in the array + result.reserve_operands(count); + for(unsigned i=0; i object count " << memory.size() << eom; + throw "interpreter: reading from invalid pointer"; + } + else if(real_type.id()==ID_string) + { + // Strings are currently encoded by their irep_idt ID. + return constant_exprt( + irep_idt(rhs[offset].to_long(), 0), + type); + } + // Retrieve value of basic data type + return from_integer(rhs[offset], type); } +/// executes the assign statement at the current pc value void interpretert::execute_assign() { const code_assignt &code_assign= - to_code_assign(PC->code); + to_code_assign(pc->code); - std::vector rhs; + mp_vectort rhs; evaluate(code_assign.rhs(), rhs); if(!rhs.empty()) { mp_integer address=evaluate_address(code_assign.lhs()); - unsigned size=get_size(code_assign.lhs().type()); + size_t size=get_size(code_assign.lhs().type()); if(size!=rhs.size()) - std::cout << "!! failed to obtain rhs (" - << rhs.size() << " vs. " - << size << ")\n"; + error() << "!! failed to obtain rhs (" + << rhs.size() << " vs. " + << size << ")\n" + << eom; else + { + goto_trace_stept &trace_step=steps.get_last_step(); assign(address, rhs); + trace_step.full_lhs=code_assign.lhs(); + + // TODO: need to look at other cases on ssa_exprt + // (dereference should be handled on ssa) + if(ssa_exprt::can_build_identifier(trace_step.full_lhs)) + { + trace_step.lhs_object=ssa_exprt(trace_step.full_lhs); + } + trace_step.full_lhs_value=get_value(trace_step.full_lhs.type(), rhs); + trace_step.lhs_object_value=trace_step.full_lhs_value; + } + } + else if(code_assign.rhs().id()==ID_side_effect) + { + side_effect_exprt side_effect=to_side_effect_expr(code_assign.rhs()); + if(side_effect.get_statement()==ID_nondet) + { + unsigned address=integer2unsigned(evaluate_address(code_assign.lhs())); + size_t size=get_size(code_assign.lhs().type()); + for(size_t i=0; i &rhs) + const mp_vectort &rhs) { - for(unsigned i=0; iguard)) + if(!evaluate_boolean(pc->guard)) throw "assumption failed"; } void interpretert::execute_assert() { - if(!evaluate_boolean(PC->guard)) - throw "assertion failed"; + if(!evaluate_boolean(pc->guard)) + { + if((target_assert==pc) || stop_on_assertion) + throw "program assertion reached"; + else if(show) + error() << "assertion failed at " << pc->location_number + << "\n" << eom; + } } void interpretert::execute_function_call() { const code_function_callt &function_call= - to_code_function_call(PC->code); + to_code_function_call(pc->code); // function to be called mp_integer a=evaluate_address(function_call.function()); @@ -270,8 +794,15 @@ void interpretert::execute_function_call() else if(a>=memory.size()) throw "out-of-range function call"; - const memory_cellt &cell=memory[integer2size_t(a)]; - const irep_idt &identifier=cell.identifier; + // Retrieve the empty last trace step struct we pushed for this step + // of the interpreter run to fill it with the corresponding data + goto_trace_stept &trace_step=steps.get_last_step(); + std::size_t address=integer2size_t(a); +#if 0 + const memory_cellt &cell=memory[address]; +#endif + const irep_idt &identifier=address_to_identifier(address); + trace_step.identifier=identifier; const goto_functionst::function_mapt::const_iterator f_it= goto_functions.function_map.find(identifier); @@ -289,7 +820,7 @@ void interpretert::execute_function_call() return_value_address=0; // values of the arguments - std::vector > argument_values; + std::vector argument_values; argument_values.resize(function_call.arguments().size()); @@ -303,7 +834,7 @@ void interpretert::execute_function_call() call_stack.push(stack_framet()); stack_framet &frame=call_stack.top(); - frame.return_PC=next_PC; + frame.return_pc=next_pc; frame.return_function=function; frame.old_stack_pointer=stack_pointer; frame.return_value_address=return_value_address; @@ -315,24 +846,7 @@ void interpretert::execute_function_call() for(const auto &id : locals) { const symbolt &symbol=ns.lookup(id); - unsigned size=get_size(symbol.type); - - if(size!=0) - { - frame.local_map[id]=stack_pointer; - - for(unsigned i=0; i=memory.size()) - memory.resize(address+1); - memory[address].value=0; - memory[address].identifier=id; - memory[address].offset=i; - } - - stack_pointer+=size; - } + frame.local_map[id]=integer2unsigned(build_memory_map(id, symbol.type)); } // assign the arguments @@ -342,7 +856,7 @@ void interpretert::execute_function_call() if(argument_values.size()second.body.instructions.begin(); + next_pc=f_it->second.body.instructions.begin(); } else - throw "no body for "+id2string(identifier); + { + list_input_varst::iterator it= + function_input_vars.find(function_call.function().get(ID_identifier)); + if(it!=function_input_vars.end()) + { + mp_vectort value; + assert(!it->second.empty()); + assert(!it->second.front().return_assignments.empty()); + evaluate(it->second.front().return_assignments.back().value, value); + if(return_value_address>0) + { + assign(return_value_address, value); + } + it->second.pop_front(); + return; + } + if(show) + error() << "no body for "+id2string(identifier) << eom; + } } +/// Creates a memory map of all static symbols in the program void interpretert::build_memory_map() { // put in a dummy for NULL memory.resize(1); - memory[0].offset=0; - memory[0].identifier="NULL-OBJECT"; + inverse_memory_map[0]="NULL-OBJECT"; + + num_dynamic_objects=0; + dynamic_types.clear(); // now do regular static symbols for(const auto &s : symbol_table.symbols) @@ -376,7 +911,7 @@ void interpretert::build_memory_map() void interpretert::build_memory_map(const symbolt &symbol) { - unsigned size=0; + size_t size=0; if(symbol.type.id()==ID_code) { @@ -389,22 +924,123 @@ void interpretert::build_memory_map(const symbolt &symbol) if(size!=0) { - unsigned address=memory.size(); + std::size_t address=memory.size(); memory.resize(address+size); memory_map[symbol.name]=address; + inverse_memory_map[address]=symbol.name; + } +} - for(unsigned i=0; i(type.find(ID_size)); + mp_vectort computed_size; + evaluate(size_expr, computed_size); + if(computed_size.size()==1 && + computed_size[0]>=0) + { + result() << "Concretized array with size " << computed_size[0] + << eom; + return array_typet(type.subtype(), + constant_exprt::integer_constant(computed_size[0].to_ulong())); + } + else { - memory_cellt &cell=memory[address+i]; - cell.identifier=symbol.name; - cell.offset=i; - cell.value=0; + error() << "Failed to concretize variable array" + << eom; } } + return type; +} + +/*******************************************************************\ + +Function: interpretert::build_memory_map + + Inputs: + + Outputs: Updates the memory map to include variable id if it does + not exist + + Purpose: Populates dynamic entries of the memory map + +\*******************************************************************/ + +mp_integer interpretert::build_memory_map( + const irep_idt &id, + const typet &type) +{ + typet alloc_type=concretize_type(type); + size_t size=get_size(alloc_type); + auto it=dynamic_types.find(id); + + if(it!=dynamic_types.end()) + { + std::size_t address=memory_map[id]; + std::size_t current_size=base_address_to_alloc_size(address); + // current size <= size already recorded + if(size<=current_size) + return memory_map[id]; + } + + // The current size is bigger then the one previously recorded + // in the memory map + + if(size==0) + size=1; // This is a hack to create existence + + std::size_t address=memory.size(); + memory.resize(address+size); + memory_map[id]=address; + inverse_memory_map[address]=id; + dynamic_types.insert(std::pair(id, alloc_type)); + + return address; } -unsigned interpretert::get_size(const typet &type) const +bool interpretert::unbounded_size(const typet &type) { + if(type.id()==ID_array) + { + const exprt &size=to_array_type(type).size(); + if(size.id()==ID_infinity) + return true; + return unbounded_size(type.subtype()); + } + else if(type.id()==ID_struct) + { + const auto &st=to_struct_type(type); + if(st.components().empty()) + return false; + return unbounded_size(st.components().back().type()); + } + return false; +} + +/*******************************************************************\ + +Function: interpretert::get_size + + Inputs: + type - a structured type + + Outputs: Size of the given type + + Purpose: Retrieves the actual size of the provided structured type. + Unbounded objects get allocated 2^32 address space each + (of a 2^64 sized space). + +\*******************************************************************/ + +size_t interpretert::get_size(const typet &type) +>>>>>>> fef1fed6b... update interpreter +{ + if(unbounded_size(type)) + return 2ULL << 32ULL; + if(type.id()==ID_struct) { const struct_typet::componentst &components= @@ -427,7 +1063,7 @@ unsigned interpretert::get_size(const typet &type) const const union_typet::componentst &components= to_union_type(type).components(); - unsigned max_size=0; + size_t max_size=0; for(const auto &comp : components) { @@ -443,26 +1079,96 @@ unsigned interpretert::get_size(const typet &type) const { const exprt &size_expr=static_cast(type.find(ID_size)); - unsigned subtype_size=get_size(type.subtype()); + size_t subtype_size=get_size(type.subtype()); - mp_integer i; - if(!to_integer(size_expr, i)) - return subtype_size*integer2unsigned(i); - else - return subtype_size; + mp_vectort i; + evaluate(size_expr, i); + if(i.size()==1) + { + // Go via the binary representation to reproduce any + // overflow behaviour. + exprt size_const=from_integer(i[0], size_expr.type()); + mp_integer size_mp; + assert(!to_integer(size_const, size_mp)); + return subtype_size*integer2unsigned(size_mp); + } + return subtype_size; } else if(type.id()==ID_symbol) { return get_size(ns.follow(type)); } + return 1; +} + +/******************************************************************* \ + +Function: interpretert::get_value + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +exprt interpretert::get_value(const irep_idt &id) +{ + // The dynamic type and the static symbol type may differ for VLAs, + // where the symbol carries a size expression and the dynamic type + // registry contains its actual length. + auto findit=dynamic_types.find(id); + typet get_type; + if(findit!=dynamic_types.end()) + get_type=findit->second; else - return 1; + get_type=symbol_table.lookup(id).type; + + symbol_exprt symbol_expr(id, get_type); + mp_integer whole_lhs_object_address=evaluate_address(symbol_expr); + + return get_value(get_type, integer2size_t(whole_lhs_object_address)); } void interpreter( const symbol_tablet &symbol_table, - const goto_functionst &goto_functions) + const goto_functionst &goto_functions, + message_handlert &message_handler) { - interpretert interpreter(symbol_table, goto_functions); + interpretert interpreter( + symbol_table, + goto_functions, + message_handler); interpreter(); } + +/*******************************************************************\ + +Function: interpretert::print_memory + + Inputs: + + Outputs: + + Purpose: Prints the current state of the memory map + Since messaget mdofifies class members, print functions are nonconst + +\*******************************************************************/ + +void interpretert::print_memory(bool input_flags) +{ + for(const auto &cell_address : memory) + { + std::size_t i=cell_address.first; + const memory_cellt &cell=cell_address.second; + const auto identifier=address_to_identifier(i); + const auto offset=address_to_offset(i); + debug() << identifier << "[" << offset << "]" + << "=" << cell.value << eom; + if(input_flags) + debug() << "(" << static_cast(cell.initialized) << ")" + << eom; + debug() << eom; + } +} diff --git a/src/goto-programs/interpreter.h b/src/goto-programs/interpreter.h index 20113a54fc6..8d598852b1a 100644 --- a/src/goto-programs/interpreter.h +++ b/src/goto-programs/interpreter.h @@ -12,10 +12,13 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_GOTO_PROGRAMS_INTERPRETER_H #define CPROVER_GOTO_PROGRAMS_INTERPRETER_H +#include + #include "goto_functions.h" void interpreter( const symbol_tablet &symbol_table, - const goto_functionst &goto_functions); + const goto_functionst &goto_functions, + message_handlert &message_handler); #endif // CPROVER_GOTO_PROGRAMS_INTERPRETER_H diff --git a/src/goto-programs/interpreter_class.h b/src/goto-programs/interpreter_class.h index 9938862bb92..4bda6846aab 100644 --- a/src/goto-programs/interpreter_class.h +++ b/src/goto-programs/interpreter_class.h @@ -15,47 +15,196 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include #include "goto_functions.h" +#include "goto_trace.h" +#include "json_goto_trace.h" +#include "util/message.h" -class interpretert +class interpretert:public messaget { public: interpretert( const symbol_tablet &_symbol_table, - const goto_functionst &_goto_functions): + const goto_functionst &_goto_functions, + message_handlert &_message_handler): + messaget(_message_handler), symbol_table(_symbol_table), ns(_symbol_table), - goto_functions(_goto_functions) + goto_functions(_goto_functions), + stop_on_assertion(false) { + show=true; } void operator()(); + void print_memory(bool input_flags); + + // An assertion that identifier 'id' carries value in some particular context. + // Used to record parameter (id) assignment (value) lists for function calls. + struct function_assignmentt + { + irep_idt id; + exprt value; + }; + + // A list of such assignments. + typedef std::vector function_assignmentst; + + typedef std::vector mp_vectort; + + // Maps an assignment id to the name of the parameter being assigned + typedef std::pair assignment_idt; + + // Identifies an expression before and after some change; + typedef std::pair diff_pairt; + + // Records a diff between an assignment pre and post conditions + typedef std::map side_effects_differencet; + + // A entry in the input_valuest map + typedef std::pair input_entryt; + + // List of the input variables with their corresponding initial values + typedef std::map input_valuest; + + // List of dynamically allocated symbols that are not in the symbol table + typedef std::map dynamic_typest; + + typedef std::map output_valuest; + output_valuest output_values; + + // An assignment list annotated with the calling context. + struct function_assignments_contextt + { + irep_idt calling_function; + function_assignmentst return_assignments; + function_assignmentst param_assignments; + }; + + // list_input_varst maps function identifiers onto a vector of [name = value] + // assignments per call to that function. + typedef std::list + function_assignments_contextst; + typedef std::map > + list_input_varst; + + const dynamic_typest &get_dynamic_types() { return dynamic_types; } protected: + struct trace_stack_entryt + { + irep_idt func_name; + mp_integer this_address; + irep_idt capture_symbol; + bool is_super_call; + std::vector param_values; + }; + typedef std::vector trace_stackt; + const symbol_tablet &symbol_table; + + // This is a cache so that we don't have to create it when a call needs it const namespacet ns; + const goto_functionst &goto_functions; - typedef std::unordered_map memory_mapt; + typedef std::unordered_map memory_mapt; + typedef std::map inverse_memory_mapt; memory_mapt memory_map; + inverse_memory_mapt inverse_memory_map; + + const inverse_memory_mapt::value_type &address_to_object_record( + std::size_t address) const + { + auto lower_bound=inverse_memory_map.lower_bound(address); + if(lower_bound->first!=address) + { + assert(lower_bound!=inverse_memory_map.begin()); + --lower_bound; + } + return *lower_bound; + } + + irep_idt address_to_identifier(std::size_t address) const + { + return address_to_object_record(address).second; + } + + std::size_t address_to_offset(std::size_t address) const + { + return address-(address_to_object_record(address).first); + } + + std::size_t base_address_to_alloc_size(std::size_t address) const + { + assert(address_to_offset(address)==0); + auto upper_bound=inverse_memory_map.upper_bound(address); + std::size_t next_alloc_address= + upper_bound==inverse_memory_map.end() ? + memory.size() : + upper_bound->first; + return next_alloc_address-address; + } + + std::size_t base_address_to_actual_size(std::size_t address) const + { + auto memory_iter=memory.find(address); + if(memory_iter==memory.end()) + return 0; + std::size_t ret=0; + std::size_t alloc_size=base_address_to_alloc_size(address); + while(memory_iter!=memory.end() && ret memoryt; - memoryt memory; + typedef sparse_vectort memoryt; + typedef std::map parameter_sett; + // mapping -> value + typedef std::pair struct_member_idt; + typedef std::map struct_valuest; + + // The memory is being annotated/reshaped even during reads + // (ie to find a read-before-write location) thus memory + // properties need to be mutable to avoid making all calls nonconst + mutable memoryt memory; std::size_t stack_pointer; void build_memory_map(); void build_memory_map(const symbolt &symbol); - unsigned get_size(const typet &type) const; + mp_integer build_memory_map(const irep_idt &id, const typet &type); + typet concretize_type(const typet &type); + bool unbounded_size(const typet &); + size_t get_size(const typet &type); + + irep_idt get_component_id(const irep_idt &object, unsigned offset); + typet get_type(const irep_idt &id) const; + exprt get_value( + const typet &type, + std::size_t offset=0, + bool use_non_det=false); + exprt get_value(const typet &type, mp_vectort &rhs, std::size_t offset=0); + exprt get_value(const irep_idt &id); + void step(); void execute_assert(); @@ -65,21 +214,30 @@ class interpretert void execute_function_call(); void execute_other(); void execute_decl(); + void clear_input_flags(); + + void allocate( + mp_integer address, + size_t size); void assign( mp_integer address, - const std::vector &rhs); + const mp_vectort &rhs); void read( mp_integer address, - std::vector &dest) const; + mp_vectort &dest) const; + + void read_unbounded( + mp_integer address, + mp_vectort &dest) const; - void command(); + virtual void command(); class stack_framet { public: - goto_programt::const_targett return_PC; + goto_programt::const_targett return_pc; goto_functionst::function_mapt::const_iterator return_function; mp_integer return_value_address; memory_mapt local_map; @@ -87,27 +245,56 @@ class interpretert }; typedef std::stack call_stackt; + call_stackt call_stack; + input_valuest input_vars; + list_input_varst function_input_vars; goto_functionst::function_mapt::const_iterator function; - goto_programt::const_targett PC, next_PC; + goto_programt::const_targett pc, next_pc, target_assert; + goto_tracet steps; bool done; + bool show; + bool stop_on_assertion; + static const size_t npos; + size_t num_steps; + size_t total_steps; + + dynamic_typest dynamic_types; + int num_dynamic_objects; + size_t stack_depth; + int thread_id; - bool evaluate_boolean(const exprt &expr) const + bool evaluate_boolean(const exprt &expr) { - std::vector v; + mp_vectort v; evaluate(expr, v); if(v.size()!=1) throw "invalid boolean value"; return v.front()!=0; } + bool count_type_leaves( + const typet &source_type, + mp_integer &result); + + bool byte_offset_to_memory_offset( + const typet &source_type, + mp_integer byte_offset, + mp_integer &result); + + bool memory_offset_to_byte_offset( + const typet &source_type, + mp_integer cell_offset, + mp_integer &result); + void evaluate( const exprt &expr, - std::vector &dest) const; + mp_vectort &dest); - mp_integer evaluate_address(const exprt &expr) const; + mp_integer evaluate_address(const exprt &expr, bool fail_quietly=false); + void initialize(bool init); void show_state(); }; diff --git a/src/goto-programs/interpreter_evaluate.cpp b/src/goto-programs/interpreter_evaluate.cpp index 43a072cfaf4..235955a2416 100644 --- a/src/goto-programs/interpreter_evaluate.cpp +++ b/src/goto-programs/interpreter_evaluate.cpp @@ -11,41 +11,394 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include #include #include #include +#include +#include #include "interpreter_class.h" +/// reads a memory address and loads it into the dest variable +/// marks cell as read before written if cell has never been written void interpretert::read( mp_integer address, - std::vector &dest) const + mp_vectort &dest) const { // copy memory region - for(auto &d : dest) + for(size_t i=0; i0) + cell.second.initialized=0; + } +} + +/*******************************************************************\ + +Function: interpretert::count_type_leaves + + Inputs: Type + + Outputs: Number of leaf primitive types; returns true on error + + Purpose: + +\*******************************************************************/ + +bool interpretert::count_type_leaves(const typet &ty, mp_integer &result) +{ + if(ty.id()==ID_struct) + { + result=0; + mp_integer subtype_count; + for(const auto &component : to_struct_type(ty).components()) + { + if(count_type_leaves(component.type(), subtype_count)) + return true; + result+=subtype_count; + } + return false; + } + else if(ty.id()==ID_array) + { + const auto &at=to_array_type(ty); + mp_vectort array_size_vec; + evaluate(at.size(), array_size_vec); + if(array_size_vec.size()!=1) + return true; + mp_integer subtype_count; + if(count_type_leaves(at.subtype(), subtype_count)) + return true; + result=array_size_vec[0]*subtype_count; + return false; + } + else + { + result=1; + return false; + } +} + +/*******************************************************************\ + +Function: interpretert::byte_offset_to_memory_offset + + Inputs: 'source_type', 'offset' (unit: bytes), + + Outputs: Offset into a vector of interpreter values; returns true on error + + Purpose: Supposing the caller has an mp_vector representing + a value with type 'source_type', this yields the offset into that + vector at which to find a value at *byte* address 'offset'. + We need this because the interpreter's memory map uses unlabelled + variable-width values -- for example, a C value { { 1, 2 }, 3, 4 } + of type struct { int x[2]; char y; unsigned long z; } + would be represented [1,2,3,4], with the source type needed alongside + to figure out which member is targeted by a byte-extract operation. + +\*******************************************************************/ + +bool interpretert::byte_offset_to_memory_offset( + const typet &source_type, + mp_integer offset, + mp_integer &result) +{ + if(source_type.id()==ID_struct) + { + const auto &st=to_struct_type(source_type); + const struct_typet::componentst &components=st.components(); + member_offset_iterator component_offsets(st, ns); + mp_integer previous_member_offsets=0; + for(; component_offsets->firstsecond!=-1 && + component_offsets->second<=offset; + ++component_offsets) + { + const auto &component_type=components[component_offsets->first].type(); + mp_integer component_byte_size=pointer_offset_size(component_type, ns); + if(component_byte_size<0) + return true; + if((component_offsets->second+component_byte_size)>offset) + { + mp_integer subtype_result; + bool ret=byte_offset_to_memory_offset( + component_type, + offset-(component_offsets->second), + subtype_result); + result=previous_member_offsets+subtype_result; + return ret; + } + else + { + mp_integer component_count; + if(count_type_leaves(component_type, component_count)) + return true; + previous_member_offsets+=component_count; + } + } + // Ran out of struct members, or struct contained a variable-length field. + return true; + } + else if(source_type.id()==ID_array) + { + const auto &at=to_array_type(source_type); + mp_vectort array_size_vec; + evaluate(at.size(), array_size_vec); + if(array_size_vec.size()!=1) + return true; + mp_integer array_size=array_size_vec[0]; + mp_integer elem_size_bytes=pointer_offset_size(at.subtype(), ns); + if(elem_size_bytes<=0) + return true; + mp_integer elem_size_leaves; + if(count_type_leaves(at.subtype(), elem_size_leaves)) + return true; + mp_integer this_idx=offset/elem_size_bytes; + if(this_idx>=array_size_vec[0]) + return true; + mp_integer subtype_result; + bool ret=byte_offset_to_memory_offset( + at.subtype(), + offset%elem_size_bytes, + subtype_result); + result=subtype_result+(elem_size_leaves*this_idx); + return ret; + } + else + { + result=0; + // Can't currently subdivide a primitive. + return offset!=0; + } +} + +/*******************************************************************\ + +Function: interpretert::memory_offset_to_byte_offset - ++address; + Inputs: An interpreter memory offset and the type to interpret that memory + + Outputs: The corresponding byte offset. Returns true on error + + Purpose: Similarly to the above, the interpreter's memory objects contain + mp_integers that represent variable-sized struct members. This + counts the size of type leaves to determine the byte offset + corresponding to a memory offset. + +\*******************************************************************/ + +bool interpretert::memory_offset_to_byte_offset( + const typet &source_type, + mp_integer cell_offset, + mp_integer &result) +{ + if(source_type.id()==ID_struct) + { + const auto &st=to_struct_type(source_type); + const struct_typet::componentst &components=st.components(); + member_offset_iterator offsets(st, ns); + mp_integer previous_member_sizes; + for(; offsets->firstsecond!=-1; ++offsets) + { + const auto &component_type=components[offsets->first].type(); + mp_integer component_count; + if(count_type_leaves(component_type, component_count)) + return true; + if(component_count>cell_offset) + { + mp_integer subtype_result; + bool ret=memory_offset_to_byte_offset( + component_type, + cell_offset, + subtype_result); + result=previous_member_sizes+subtype_result; + return ret; + } + else + { + cell_offset-=component_count; + mp_integer component_size=pointer_offset_size(component_type, ns); + if(component_size<0) + return true; + previous_member_sizes+=component_size; + } + } + // Ran out of members, or member of indefinite size + return true; + } + else if(source_type.id()==ID_array) + { + const auto &at=to_array_type(source_type); + mp_vectort array_size_vec; + evaluate(at.size(), array_size_vec); + if(array_size_vec.size()!=1) + return true; + mp_integer elem_size=pointer_offset_size(at.subtype(), ns); + if(elem_size==-1) + return true; + mp_integer elem_count; + if(count_type_leaves(at.subtype(), elem_count)) + return true; + mp_integer this_idx=cell_offset/elem_count; + if(this_idx>=array_size_vec[0]) + return true; + mp_integer subtype_result; + bool ret= + memory_offset_to_byte_offset(at.subtype(), + cell_offset%elem_count, + subtype_result); + result=subtype_result+(elem_size*this_idx); + return ret; + } + else + { + // Primitive type. + result=0; + return cell_offset!=0; } } void interpretert::evaluate( const exprt &expr, - std::vector &dest) const + mp_vectort &dest) { if(expr.id()==ID_constant) { if(expr.type().id()==ID_struct) { + dest.reserve(get_size(expr.type())); + bool error=false; + + forall_operands(it, expr) + { + if(it->type().id()==ID_code) + continue; + + size_t sub_size=get_size(it->type()); + if(sub_size==0) + continue; + + mp_vectort tmp; + evaluate(*it, tmp); + + if(tmp.size()==sub_size) + { + for(size_t i=0; itype().id()==ID_code) continue; - unsigned sub_size=get_size(it->type()); + size_t sub_size=get_size(it->type()); if(sub_size==0) continue; - std::vector tmp; + mp_vectort tmp; evaluate(*it, tmp); - if(tmp.size()==sub_size) + if(unbounded_size(it->type()) || tmp.size()==sub_size) { - for(unsigned i=0; i tmp0, tmp1; + mp_vectort tmp0, tmp1; evaluate(expr.op0(), tmp0); evaluate(expr.op1(), tmp1); @@ -151,7 +700,7 @@ void interpretert::evaluate( forall_operands(it, expr) { - std::vector tmp; + mp_vectort tmp; evaluate(*it, tmp); if(tmp.size()==1 && tmp.front()!=0) @@ -170,20 +719,20 @@ void interpretert::evaluate( if(expr.operands().size()!=3) throw "if expects three operands"; - std::vector tmp0, tmp1, tmp2; + mp_vectort tmp0, tmp1; evaluate(expr.op0(), tmp0); - evaluate(expr.op1(), tmp1); - evaluate(expr.op2(), tmp2); - if(tmp0.size()==1 && tmp1.size()==1 && tmp2.size()==1) + if(tmp0.size()==1) { - const mp_integer &op0=tmp0.front(); - const mp_integer &op1=tmp1.front(); - const mp_integer &op2=tmp2.front(); - - dest.push_back(op0!=0?op1:op2); + if(tmp0.front()!=0) + evaluate(expr.op1(), tmp1); + else + evaluate(expr.op2(), tmp1); } + if(tmp1.size()==1) + dest.push_back(tmp1.front()); + return; } else if(expr.id()==ID_and) @@ -195,7 +744,7 @@ void interpretert::evaluate( forall_operands(it, expr) { - std::vector tmp; + mp_vectort tmp; evaluate(*it, tmp); if(tmp.size()==1 && tmp.front()==0) @@ -214,7 +763,7 @@ void interpretert::evaluate( if(expr.operands().size()!=1) throw id2string(expr.id())+" expects one operand"; - std::vector tmp; + mp_vectort tmp; evaluate(expr.op0(), tmp); if(tmp.size()==1) @@ -228,7 +777,7 @@ void interpretert::evaluate( forall_operands(it, expr) { - std::vector tmp; + mp_vectort tmp; evaluate(*it, tmp); if(tmp.size()==1) result+=tmp.front(); @@ -260,7 +809,7 @@ void interpretert::evaluate( forall_operands(it, expr) { - std::vector tmp; + mp_vectort tmp; evaluate(*it, tmp); if(tmp.size()==1) { @@ -296,7 +845,7 @@ void interpretert::evaluate( if(expr.operands().size()!=2) throw "- expects two operands"; - std::vector tmp0, tmp1; + mp_vectort tmp0, tmp1; evaluate(expr.op0(), tmp0); evaluate(expr.op1(), tmp1); @@ -309,7 +858,7 @@ void interpretert::evaluate( if(expr.operands().size()!=2) throw "/ expects two operands"; - std::vector tmp0, tmp1; + mp_vectort tmp0, tmp1; evaluate(expr.op0(), tmp0); evaluate(expr.op1(), tmp1); @@ -322,7 +871,7 @@ void interpretert::evaluate( if(expr.operands().size()!=1) throw "unary- expects one operand"; - std::vector tmp0; + mp_vectort tmp0; evaluate(expr.op0(), tmp0); if(tmp0.size()==1) @@ -337,22 +886,137 @@ void interpretert::evaluate( dest.push_back(evaluate_address(expr.op0())); return; } + else if(expr.id()==ID_pointer_offset) + { + if(expr.operands().size()!=1) + throw "pointer_offset expects one operand"; + if(expr.op0().type().id()!=ID_pointer) + throw "pointer_offset expects a pointer operand"; + mp_vectort result; + evaluate(expr.op0(), result); + if(result.size()==1) + { + // Return the distance, in bytes, between the address returned + // and the beginning of the underlying object. + mp_integer address=result[0]; + if(address>0 && address0) + { + dest.insert(dest.end(), + extract_from.begin()+memory_offset.to_long(), + extract_from.begin()+(memory_offset+target_type_leaves).to_long()); + return; + } + } + } + } else if(expr.id()==ID_dereference || expr.id()==ID_index || expr.id()==ID_symbol || expr.id()==ID_member) { - mp_integer a=evaluate_address(expr); - dest.resize(get_size(expr.type())); - read(a, dest); - return; + mp_integer address=evaluate_address( + expr, + true); // fail quietly + if(address.is_zero() && expr.id()==ID_index) + { + // Try reading from a constant array: + mp_vectort idx; + evaluate(expr.op1(), idx); + if(idx.size()==1) + { + mp_integer read_from_index=idx[0]; + if(expr.op0().id()==ID_array) + { + const auto &ops=expr.op0().operands(); + assert(read_from_index.is_long()); + if(read_from_index>=0 && read_from_index tmp; + mp_vectort tmp; evaluate(expr.op0(), tmp); if(tmp.size()==1) @@ -378,38 +1042,90 @@ void interpretert::evaluate( dest.push_back(binary2integer(s, false)); return; } - else if(expr.type().id()==ID_bool) + else if((expr.type().id()==ID_bool) || (expr.type().id()==ID_c_bool)) { dest.push_back(value!=0); return; } } } - else if(expr.id()==ID_ashr) + else if(expr.id()==ID_array) { - if(expr.operands().size()!=2) - throw "ashr expects two operands"; - - std::vector tmp0, tmp1; - evaluate(expr.op0(), tmp0); - evaluate(expr.op1(), tmp1); - - if(tmp0.size()==1 && tmp1.size()==1) - dest.push_back(tmp0.front()/power(2, tmp1.front())); - + forall_operands(it, expr) + { + evaluate(*it, dest); + } return; } - - std::cout << "!! failed to evaluate expression: " - << from_expr(ns, function->first, expr) - << '\n'; + else if(expr.id()==ID_array_of) + { + const auto &ty=to_array_type(expr.type()); + std::vector size; + if(ty.size().id()==ID_infinity) + size.push_back(0); + else + evaluate(ty.size(), size); + if(size.size()==1) + { + std::size_t size_int=integer2size_t(size[0]); + for(std::size_t i=0; i where; + std::vector new_value; + evaluate(wexpr.where(), where); + evaluate(wexpr.new_value(), new_value); + const auto &subtype=expr.type().subtype(); + if(!new_value.empty() && where.size()==1 && !unbounded_size(subtype)) + { + // Ignore indices < 0, which the string solver sometimes produces + if(where[0]<0) + return; + std::size_t where_idx=integer2size_t(where[0]); + std::size_t subtype_size=get_size(subtype); + std::size_t need_size=(where_idx+1)*subtype_size; + if(dest.size()first, expr) << "\n" + << expr.id() << "[" << expr.type().id() << "]" + << eom; } -mp_integer interpretert::evaluate_address(const exprt &expr) const +mp_integer interpretert::evaluate_address( + const exprt &expr, + bool fail_quietly) { if(expr.id()==ID_symbol) { - const irep_idt &identifier=expr.get(ID_identifier); + const irep_idt &identifier= + is_ssa_expr(expr) ? + to_ssa_expr(expr).get_original_name() : + expr.get(ID_identifier); interpretert::memory_mapt::const_iterator m_it1= memory_map.find(identifier); @@ -425,13 +1141,16 @@ mp_integer interpretert::evaluate_address(const exprt &expr) const if(m_it2!=call_stack.top().local_map.end()) return m_it2->second; } + mp_integer address=memory.size(); + build_memory_map(to_symbol_expr(expr).get_identifier(), expr.type()); + return address; } else if(expr.id()==ID_dereference) { if(expr.operands().size()!=1) throw "dereference expects one operand"; - std::vector tmp0; + mp_vectort tmp0; evaluate(expr.op0(), tmp0); if(tmp0.size()==1) @@ -442,11 +1161,15 @@ mp_integer interpretert::evaluate_address(const exprt &expr) const if(expr.operands().size()!=2) throw "index expects two operands"; - std::vector tmp1; + mp_vectort tmp1; evaluate(expr.op1(), tmp1); if(tmp1.size()==1) - return evaluate_address(expr.op0())+tmp1.front(); + { + auto base=evaluate_address(expr.op0(), fail_quietly); + if(!base.is_zero()) + return base+tmp1.front(); + } } else if(expr.id()==ID_member) { @@ -469,12 +1192,44 @@ mp_integer interpretert::evaluate_address(const exprt &expr) const offset+=get_size(comp.type()); } - return evaluate_address(expr.op0())+offset; + auto base=evaluate_address(expr.op0(), fail_quietly); + if(!base.is_zero()) + return base+offset; } - - std::cout << "!! failed to evaluate address: " + else if(expr.id()==ID_byte_extract_little_endian || + expr.id()==ID_byte_extract_big_endian) + { + if(expr.operands().size()!=2) + throw "byte_extract should have two operands"; + mp_vectort extract_offset; + evaluate(expr.op1(), extract_offset); + mp_vectort extract_from; + evaluate(expr.op0(), extract_from); + if(extract_offset.size()==1 && !extract_from.empty()) + { + mp_integer memory_offset; + if(!byte_offset_to_memory_offset(expr.op0().type(), + extract_offset[0], memory_offset)) + return evaluate_address(expr.op0(), fail_quietly)+memory_offset; + } + } + else if(expr.id()==ID_if) + { + mp_vectort result; + if_exprt address_cond( + expr.op0(), + address_of_exprt(expr.op1()), + address_of_exprt(expr.op2())); + evaluate(address_cond, result); + if(result.size()==1) + return result[0]; + } + if(!fail_quietly) + { + error() << "!! failed to evaluate address: " << from_expr(ns, function->first, expr) - << '\n'; + << eom; + } return 0; } diff --git a/src/goto-programs/json_goto_trace.cpp b/src/goto-programs/json_goto_trace.cpp index ddc9f44ad3b..40ed6f29c30 100644 --- a/src/goto-programs/json_goto_trace.cpp +++ b/src/goto-programs/json_goto_trace.cpp @@ -59,6 +59,7 @@ void convert( json_failure["stepType"]=json_stringt("failure"); json_failure["hidden"]=jsont::json_boolean(step.hidden); + json_failure["internal"]=jsont::json_boolean(step.internal); json_failure["thread"]=json_numbert(std::to_string(step.thread_nr)); json_failure["reason"]=json_stringt(id2string(step.comment)); json_failure["property"]=json_stringt(id2string(property_id)); @@ -109,6 +110,7 @@ void convert( json_assignment["value"]=full_lhs_value; json_assignment["lhs"]=json_stringt(full_lhs_string); json_assignment["hidden"]=jsont::json_boolean(step.hidden); + json_assignment["internal"]=jsont::json_boolean(step.internal); json_assignment["thread"]=json_numbert(std::to_string(step.thread_nr)); json_assignment["assignmentType"]= @@ -126,6 +128,7 @@ void convert( json_output["stepType"]=json_stringt("output"); json_output["hidden"]=jsont::json_boolean(step.hidden); + json_output["internal"]=jsont::json_boolean(step.internal); json_output["thread"]=json_numbert(std::to_string(step.thread_nr)); json_output["outputID"]=json_stringt(id2string(step.io_id)); @@ -150,6 +153,7 @@ void convert( json_input["stepType"]=json_stringt("input"); json_input["hidden"]=jsont::json_boolean(step.hidden); + json_input["internal"]=jsont::json_boolean(step.internal); json_input["thread"]=json_numbert(std::to_string(step.thread_nr)); json_input["inputID"]=json_stringt(id2string(step.io_id)); @@ -178,6 +182,7 @@ void convert( json_call_return["stepType"]=json_stringt(tag); json_call_return["hidden"]=jsont::json_boolean(step.hidden); + json_call_return["internal"]=jsont::json_boolean(step.internal); json_call_return["thread"]=json_numbert(std::to_string(step.thread_nr)); const symbolt &symbol=ns.lookup(step.identifier); @@ -201,6 +206,7 @@ void convert( json_objectt &json_location_only=dest_array.push_back().make_object(); json_location_only["stepType"]=json_stringt("location-only"); json_location_only["hidden"]=jsont::json_boolean(step.hidden); + json_location_only["internal"]=jsont::json_boolean(step.internal); json_location_only["thread"]= json_numbert(std::to_string(step.thread_nr)); json_location_only["sourceLocation"]=json_location; diff --git a/src/goto-programs/remove_instanceof.cpp b/src/goto-programs/remove_instanceof.cpp index ec895ff800d..8a033668f6a 100644 --- a/src/goto-programs/remove_instanceof.cpp +++ b/src/goto-programs/remove_instanceof.cpp @@ -122,6 +122,7 @@ void remove_instanceoft::lower_instanceof( newinst->make_assignment(); newinst->code=code_assignt(newsym.symbol_expr(), object_clsid); newinst->source_location=this_inst->source_location; + newinst->function=this_inst->function; // Insert the check instruction after the existing one. // This will briefly be ill-formed (use before def of diff --git a/src/goto-programs/show_properties.cpp b/src/goto-programs/show_properties.cpp index a052a8aaecb..9afa3f99eba 100644 --- a/src/goto-programs/show_properties.cpp +++ b/src/goto-programs/show_properties.cpp @@ -109,6 +109,10 @@ void show_properties_json( json_properties.push_back(jsont()).make_object(); json_property["name"]=json_stringt(id2string(property_id)); json_property["class"]=json_stringt(id2string(property_class)); + if(!source_location.get_basic_block_covered_lines().empty()) + json_property["coveredLines"]= + json_stringt( + id2string(source_location.get_basic_block_covered_lines())); json_property["sourceLocation"]=json(source_location); json_property["description"]=json_stringt(id2string(description)); json_property["expression"]= diff --git a/src/goto-programs/string_refine_preprocess.cpp b/src/goto-programs/string_refine_preprocess.cpp new file mode 100644 index 00000000000..8b491bab0ab --- /dev/null +++ b/src/goto-programs/string_refine_preprocess.cpp @@ -0,0 +1,1404 @@ +/*******************************************************************\ + +Module: Preprocess a goto-programs so that calls to the java String + library are recognized by the string solver + +Author: Romain Brenguier + +Date: September 2016 + +\*******************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "string_refine_preprocess.h" + +/*******************************************************************\ + +Function: string_refine_preprocesst::check_java_type + + Inputs: a type and a string + + Outputs: Boolean telling whether the type is a struct with the given + tag or a symbolic type with the tag prefixed by "java::" + +\*******************************************************************/ + +bool string_refine_preprocesst::check_java_type( + const typet &type, const std::string &tag) +{ + if(type.id()==ID_symbol) + { + irep_idt tag_id=to_symbol_type(type).get_identifier(); + return tag_id=="java::"+tag; + } + else if(type.id()==ID_struct) + { + irep_idt tag_id=to_struct_type(type).get_tag(); + return tag_id==tag; + } + return false; +} +/*******************************************************************\ + +Function: string_refine_preprocesst::is_java_string_pointer_type + + Inputs: a type + + Outputs: Boolean telling whether the type is that of java string pointers + +\*******************************************************************/ + +bool string_refine_preprocesst::is_java_string_pointer_type(const typet &type) +{ + if(type.id()==ID_pointer) + { + const pointer_typet &pt=to_pointer_type(type); + const typet &subtype=pt.subtype(); + return is_java_string_type(subtype); + } + return false; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::is_java_string_type + + Inputs: a type + + Outputs: Boolean telling whether the type is that of java string + +\*******************************************************************/ + +bool string_refine_preprocesst::is_java_string_type(const typet &type) +{ + return check_java_type(type, "java.lang.String"); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::is_java_string_builder_type + + Inputs: a type + + Outputs: Boolean telling whether the type is that of java string builder + +\*******************************************************************/ + +bool string_refine_preprocesst::is_java_string_builder_type(const typet &type) +{ + return check_java_type(type, "java.lang.StringBuilder"); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::is_java_string_builder_pointer_type + + Inputs: a type + + Outputs: Boolean telling whether the type is that of java StringBuilder + pointers + +\*******************************************************************/ + +bool string_refine_preprocesst::is_java_string_builder_pointer_type( + const typet &type) +{ + if(type.id()==ID_pointer) + { + const pointer_typet &pt=to_pointer_type(type); + const typet &subtype=pt.subtype(); + return is_java_string_builder_type(subtype); + } + return false; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::is_java_char_sequence_type + + Inputs: a type + + Outputs: Boolean telling whether the type is that of java char sequence + +\*******************************************************************/ + +bool string_refine_preprocesst::is_java_char_sequence_type(const typet &type) +{ + return check_java_type(type, "java.lang.CharSequence"); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::is_java_char_sequence_pointer_type + + Inputs: a type + + Outputs: Boolean telling whether the type is that of a pointer + to a java char sequence + +\*******************************************************************/ + +bool string_refine_preprocesst::is_java_char_sequence_pointer_type( + const typet &type) +{ + if(type.id()==ID_pointer) + { + const pointer_typet &pt=to_pointer_type(type); + const typet &subtype=pt.subtype(); + return is_java_char_sequence_type(subtype); + } + return false; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::is_java_char_array_type + + Inputs: a type + + Outputs: Boolean telling whether the type is that of java char array + +\*******************************************************************/ + +bool string_refine_preprocesst::is_java_char_array_type(const typet &type) +{ + return check_java_type(type, "array[char]"); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::is_java_char_array_pointer_type + + Inputs: a type + + Outputs: Boolean telling whether the type is that of a pointer + to a java char array + +\*******************************************************************/ + +bool string_refine_preprocesst::is_java_char_array_pointer_type( + const typet &type) +{ + if(type.id()==ID_pointer) + { + const pointer_typet &pt=to_pointer_type(type); + const typet &subtype=pt.subtype(); + return is_java_char_array_type(subtype); + } + return false; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::fresh_array + + Inputs: + type - an array type + location - a location in the program + + Outputs: a new symbol + + Purpose: add a symbol with static lifetime and name containing + `cprover_string_array` and given type + +\*******************************************************************/ + +symbol_exprt string_refine_preprocesst::fresh_array( + const typet &type, const source_locationt &location) +{ + symbolt array_symbol=get_fresh_aux_symbol( + type, + "cprover_string_array", + "cprover_string_array", + location, + ID_java, + symbol_table); + array_symbol.is_static_lifetime=true; + return array_symbol.symbol_expr(); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::fresh_string + + Inputs: + type - a type for refined strings + location - a location in the program + + Outputs: a new symbol + + Purpose: add a symbol with static lifetime and name containing + `cprover_string` and given type + +\*******************************************************************/ + +symbol_exprt string_refine_preprocesst::fresh_string( + const typet &type, const source_locationt &location) +{ + symbolt array_symbol=get_fresh_aux_symbol( + type, "cprover_string", "cprover_string", location, ID_java, symbol_table); + array_symbol.is_static_lifetime=true; + return array_symbol.symbol_expr(); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::declare_function + + Inputs: a name and a type + + Purpose: declare a function with the given name and type + +\*******************************************************************/ + +void string_refine_preprocesst::declare_function( + irep_idt function_name, const typet &type) +{ + auxiliary_symbolt func_symbol; + func_symbol.base_name=function_name; + func_symbol.is_static_lifetime=false; + func_symbol.mode=ID_java; + func_symbol.name=function_name; + func_symbol.type=type; + symbol_table.add(func_symbol); + goto_functions.function_map[function_name]; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::get_data_and_length_type_of_char_array + + Inputs: an expression, a reference to a data type and a reference to a + length type + + Purpose: assuming the expression is a char array, figure out what + the types for length and data are and put them into the references + given as argument + +\*******************************************************************/ + +void string_refine_preprocesst::get_data_and_length_type_of_char_array( + const exprt &expr, typet &data_type, typet &length_type) +{ + typet object_type=ns.follow(expr.type()); + assert(object_type.id()==ID_struct); + const struct_typet &struct_type=to_struct_type(object_type); + for(auto component : struct_type.components()) + if(component.get_name()=="length") + length_type=component.type(); + else if(component.get_name()=="data") + data_type=component.type(); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::get_data_and_length_type_of_string + + Inputs: an expression, a reference to a data type and a reference to a + length type + + Purpose: assuming the expression is a java string, figure out what + the types for length and data are and put them into the references + given as argument + +\*******************************************************************/ + +void string_refine_preprocesst::get_data_and_length_type_of_string( + const exprt &expr, typet &data_type, typet &length_type) +{ + assert(is_java_string_type(expr.type()) || + is_java_string_builder_type(expr.type()) || + is_java_char_sequence_type(expr.type())); + typet object_type=ns.follow(expr.type()); + const struct_typet &struct_type=to_struct_type(object_type); + for(const auto &component : struct_type.components()) + if(component.get_name()=="length") + length_type=component.type(); + else if(component.get_name()=="data") + data_type=component.type(); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::make_cprover_string_assign + + Inputs: a goto_program, a position in this program, an expression and a + location + + Outputs: an expression + + Purpose: Introduce a temporary variable for cprover strings; + returns the cprover_string corresponding to rhs if it is a string + pointer and the original rhs otherwise. + +\*******************************************************************/ + +exprt string_refine_preprocesst::make_cprover_string_assign( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &rhs, + const source_locationt &location) +{ + if(implements_java_char_sequence(rhs.type())) + { + // We do the following assignments: + // 1 length= *(rhs->length) + // 2 cprover_string_array = *(rhs->data) + // 3 cprover_string = { length; cprover_string_array } + + dereference_exprt deref(rhs, rhs.type().subtype()); + typet data_type, length_type; + get_data_and_length_type_of_string(deref, data_type, length_type); + std::list assignments; + + // 1) cprover_string_length= *(rhs->length) + symbolt sym_length=get_fresh_aux_symbol( + length_type, + "cprover_string_length", + "cprover_string_length", + location, + ID_java, + symbol_table); + symbol_exprt cprover_length=sym_length.symbol_expr(); + member_exprt length(deref, "length", length_type); + assignments.emplace_back(cprover_length, length); + + // 2) cprover_string_array = *(rhs->data) + symbol_exprt array_lhs=fresh_array(data_type.subtype(), location); + member_exprt data(deref, "data", data_type); + dereference_exprt deref_data(data, data_type.subtype()); + assignments.emplace_back(array_lhs, deref_data); + + // 3) cprover_string = { cprover_string_length; cprover_string_array } + // This assignment is useful for finding witnessing strings for counter + // examples + refined_string_typet ref_type(length_type, java_char_type()); + string_exprt new_rhs(cprover_length, array_lhs, ref_type); + + symbol_exprt lhs=fresh_string(new_rhs.type(), location); + assignments.emplace_back(lhs, new_rhs); + + insert_assignments( + goto_program, target, target->function, location, assignments); + target=goto_program.insert_after(target); + return new_rhs; + } + else if(rhs.id()==ID_typecast && + implements_java_char_sequence(rhs.op0().type())) + { + exprt new_rhs=make_cprover_string_assign( + goto_program, target, rhs.op0(), location); + return typecast_exprt(new_rhs, rhs.type()); + } + else + return rhs; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::make_cprover_char_array_assign + + Inputs: a goto_program, a position in this program, an expression of + type char array pointer and a location + + Outputs: a string expression + + Purpose: Introduce a temporary variable for cprover strings; + returns the cprover_string corresponding to rhs + +\*******************************************************************/ + +string_exprt string_refine_preprocesst::make_cprover_char_array_assign( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &rhs, + const source_locationt &location) +{ + assert(is_java_char_array_pointer_type(rhs.type())); + + // We do the following assignments: + // deref=*(rhs->data) + // array= typecast(&deref); + // string={ rhs->length; array } + + dereference_exprt deref(rhs, rhs.type().subtype()); + typet length_type, data_type; + get_data_and_length_type_of_char_array(deref, data_type, length_type); + assert(data_type.id()==ID_pointer); + typet char_type=to_pointer_type(data_type).subtype(); + + refined_string_typet ref_type(length_type, java_char_type()); + typet content_type=ref_type.get_content_type(); + std::list assignments; + + // deref=*(rhs->data) + member_exprt array_rhs(deref, "data", data_type); + dereference_exprt deref_array(array_rhs, data_type.subtype()); + symbolt sym_lhs_deref=get_fresh_aux_symbol( + data_type.subtype(), + "char_array_assign$deref", + "char_array_assign$deref", + location, + ID_java, + symbol_table); + symbol_exprt lhs_deref=sym_lhs_deref.symbol_expr(); + assignments.emplace_back(lhs_deref, deref_array); + + // array=convert_pointer_to_char_array(*rhs->data) + declare_function(ID_cprover_string_array_of_char_pointer_func, content_type); + function_application_exprt fun_app(symbol_exprt( + ID_cprover_string_array_of_char_pointer_func), content_type); + fun_app.arguments().push_back(deref_array); + symbol_exprt array=fresh_array(content_type, location); + assignments.emplace_back(array, fun_app); + + // string={ rhs->length; string_array } + string_exprt new_rhs(get_length(deref, length_type), array, ref_type); + symbol_exprt lhs=fresh_string(ref_type, location); + assignments.emplace_back(lhs, new_rhs); + + insert_assignments( + goto_program, target, target->function, location, assignments); + target=goto_program.insert_after(target); + return new_rhs; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::make_normal_assign + + Inputs: a goto_program, a position in this program, an expression lhs, + a function type, a function name, a vector of arguments, a location + and a signature + + Purpose: replace the current instruction by: + > lhs=function_name(arguments) : return_type @ location + If given, signature can force String conversion of given arguments. + The convention for signature is one character by argument + and 'S' denotes string. + +\*******************************************************************/ + +void string_refine_preprocesst::make_normal_assign( + goto_programt &goto_program, + goto_programt::targett target, + const exprt &lhs, + const code_typet &function_type, + const irep_idt &function_name, + const exprt::operandst &arguments, + const source_locationt &location, + const std::string &signature) +{ + function_application_exprt rhs( + symbol_exprt(function_name), function_type.return_type()); + rhs.add_source_location()=location; + declare_function(function_name, function_type); + + exprt::operandst processed_arguments=process_arguments( + goto_program, target, arguments, location, signature); + rhs.arguments()=processed_arguments; + + code_assignt assignment(lhs, rhs); + assignment.add_source_location()=location; + target->make_assignment(); + target->code=assignment; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::insert_assignments + + Inputs: a goto_program, a position in this program, a list of assignments + + Purpose: add the assignments to the program in the order they are given + +\*******************************************************************/ + +void string_refine_preprocesst::insert_assignments( + goto_programt &goto_program, + goto_programt::targett &target, + irep_idt function, + source_locationt location, + const std::list &va) +{ + if(va.empty()) + return; + + auto i=va.begin(); + target->make_assignment(); + target->code=*i; + target->function=function; + target->source_location=location; + for(i++; i!=va.end(); i++) + { + target=goto_program.insert_after(target); + target->make_assignment(); + target->code=*i; + target->function=function; + target->source_location=location; + } +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::make_string_assign + + Inputs: a goto_program, a position in this program, an expression lhs, + a function type, a function name, a vector of arguments, a location + and a signature + + Purpose: replace the current instruction by: + > lhs=malloc(String *) + > lhs->length=function_name_length(arguments) + > tmp_data=function_name_data(arguments) + > lhs->data=&tmp_data + +\*******************************************************************/ + +void string_refine_preprocesst::make_string_assign( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &lhs, + const code_typet &function_type, + const irep_idt &function_name, + const exprt::operandst &arguments, + const source_locationt &location, + const std::string &signature) +{ + assert(implements_java_char_sequence(function_type.return_type())); + dereference_exprt deref(lhs, lhs.type().subtype()); + typet object_type=ns.follow(deref.type()); + exprt object_size=size_of_expr(object_type, ns); + typet length_type, data_type; + get_data_and_length_type_of_string(deref, data_type, length_type); + + std::string fnamel=id2string(function_name)+"_length"; + std::string fnamed=id2string(function_name)+"_data"; + declare_function(fnamel, length_type); + declare_function(fnamed, data_type); + function_application_exprt rhs_length(symbol_exprt(fnamel), length_type); + function_application_exprt rhs_data( + symbol_exprt(fnamed), data_type.subtype()); + + exprt::operandst processed_arguments=process_arguments( + goto_program, target, arguments, location, signature); + rhs_length.arguments()=processed_arguments; + rhs_data.arguments()=processed_arguments; + + symbolt sym_length=get_fresh_aux_symbol( + length_type, "length", "length", location, ID_java, symbol_table); + symbol_exprt tmp_length=sym_length.symbol_expr(); + symbol_exprt tmp_array=fresh_array(data_type.subtype(), location); + member_exprt lhs_length(deref, "length", length_type); + member_exprt lhs_data(deref, "data", tmp_array.type()); + + // lhs=malloc(String *) + assert(object_size.is_not_nil()); // got nil object_size + side_effect_exprt malloc_expr(ID_malloc); + malloc_expr.copy_to_operands(object_size); + malloc_expr.type()=pointer_typet(object_type); + malloc_expr.add_source_location()=location; + + refined_string_typet ref_type(length_type, data_type.subtype().subtype()); + string_exprt str(tmp_length, tmp_array, ref_type); + symbol_exprt cprover_string_sym=fresh_string(ref_type, location); + + std::list assigns; + assigns.emplace_back(lhs, malloc_expr); + assigns.emplace_back(tmp_length, rhs_length); + assigns.emplace_back(lhs_length, tmp_length); + assigns.emplace_back(tmp_array, rhs_data); + assigns.emplace_back(cprover_string_sym, str); + assigns.emplace_back(lhs_data, address_of_exprt(tmp_array)); + insert_assignments(goto_program, target, target->function, location, assigns); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::make_string_function + + Inputs: a position in a goto program, a function name, an expression lhs, + a function type, name, arguments, a location and a signature string + + Purpose: at the current position replace `lhs=s.some_function(x,...)` + by `lhs=function_name(s,x,...)`; + +\*******************************************************************/ + +void string_refine_preprocesst::make_string_function( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &lhs, + const code_typet &function_type, + const irep_idt &function_name, + const exprt::operandst &arguments, + const source_locationt &location, + const std::string &signature) +{ + if(signature.length()>0) + { + if(signature.back()=='S') + { + code_typet ft=function_type; + ft.return_type()=jls_ptr; + typecast_exprt lhs2(lhs, jls_ptr); + + make_string_assign( + goto_program, + target, + lhs2, + ft, + function_name, + arguments, + location, + signature); + } + else + make_normal_assign( + goto_program, + target, + lhs, + function_type, + function_name, + arguments, + location, + signature); + } + else if(implements_java_char_sequence(function_type.return_type())) + make_string_assign( + goto_program, + target, + lhs, + function_type, + function_name, + arguments, + location, + signature); + else + make_normal_assign( + goto_program, + target, + lhs, + function_type, + function_name, + arguments, + location, + signature); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::make_string_function + + Inputs: a position in a goto program, a function name and two Boolean options + + Purpose: at the current position replace `lhs=s.some_function(x,...)` + by `lhs=function_name(s,x,...)`; + option `assign_first_arg` uses `s` instead of `lhs` in the resulting + expression, Warning : it assumes that `s` is string-like + option `skip_first_arg`, removes `s` from the arguments, ie `x` is + the first one; + arguments that are string (TODO: and char array) are replaced + by string_exprt + +\*******************************************************************/ + +void string_refine_preprocesst::make_string_function( + goto_programt &goto_program, + goto_programt::targett &target, + const irep_idt &function_name, + const std::string &signature, + bool assign_first_arg, + bool skip_first_arg) +{ + code_function_callt &function_call=to_code_function_call(target->code); + code_typet function_type=to_code_type(function_call.function().type()); + code_typet new_type; + const source_locationt &loc=function_call.source_location(); + declare_function(function_name, function_type); + function_application_exprt rhs; + std::vector args; + if(assign_first_arg) + { + assert(!function_call.arguments().empty()); + rhs.type()=function_call.arguments()[0].type(); + } + else + rhs.type()=function_type.return_type(); + rhs.add_source_location()=function_call.source_location(); + rhs.function()=symbol_exprt(function_name); + + std::size_t start_index=skip_first_arg?1:0; + for(std::size_t i=start_index; i tmp=function_name(x,...) + > s->data=tmp.data + > s->length=tmp.length + > r=s + +\*******************************************************************/ + +void string_refine_preprocesst::make_string_function_side_effect( + goto_programt &goto_program, + goto_programt::targett &target, + const irep_idt &function_name, + const std::string &signature) +{ + // Cannot use const & here + code_function_callt function_call=to_code_function_call(target->code); + source_locationt loc=function_call.source_location(); + std::list assignments; + const exprt &lhs=function_call.lhs(); + assert(!function_call.arguments().empty()); + const exprt &s=function_call.arguments()[0]; + code_typet function_type=to_code_type(function_call.type()); + + function_type.return_type()=s.type(); + + if(lhs.is_not_nil()) + { + symbol_exprt tmp_string=fresh_string(lhs.type(), loc); + + make_string_assign( + goto_program, + target, + tmp_string, + function_type, + function_name, + function_call.arguments(), + loc, + signature); + dereference_exprt deref_lhs(s, s.type().subtype()); + typet data_type, length_type; + get_data_and_length_type_of_string(deref_lhs, data_type, length_type); + member_exprt lhs_data(deref_lhs, "data", data_type); + member_exprt lhs_length(deref_lhs, "length", length_type); + dereference_exprt deref_rhs(tmp_string, s.type().subtype()); + member_exprt rhs_data(deref_rhs, "data", data_type); + member_exprt rhs_length(deref_rhs, "length", length_type); + assignments.emplace_back(lhs_length, rhs_length); + assignments.emplace_back(lhs_data, rhs_data); + assignments.emplace_back(lhs, s); + target=goto_program.insert_after(target); + insert_assignments( + goto_program, target, target->function, loc, assignments); + } + else + { + make_string_function( + goto_program, target, function_name, signature, true, false); + } +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::build_function_application + + Inputs: a function name, a type, a location and a vector of arguments + + Outputs: a function application expression + + Purpose: declare a function and construct an function application expression + with the given function name, type, location and arguments + +\*******************************************************************/ + +function_application_exprt + string_refine_preprocesst::build_function_application( + const irep_idt &function_name, + const typet &type, + const source_locationt &location, + const exprt::operandst &arguments) +{ + declare_function(function_name, type); + function_application_exprt function_app(symbol_exprt(function_name), type); + function_app.add_source_location()=location; + for(const auto &arg : arguments) + function_app.arguments().push_back(arg); + + return function_app; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::make_to_char_array_function + + Inputs: a goto program and a position in that goto program + + Purpose: at the given position replace `return_tmp0=s.toCharArray()` with: + > return_tmp0 = malloc(array[char]); + > return_tmp0->data=&((s->data)[0]) + > return_tmp0->length=s->length + +\*******************************************************************/ + +void string_refine_preprocesst::make_to_char_array_function( + goto_programt &goto_program, goto_programt::targett &target) +{ + const code_function_callt &function_call=to_code_function_call(target->code); + source_locationt location=function_call.source_location(); + + assert(!function_call.arguments().empty()); + const exprt &string_argument=function_call.arguments()[0]; + assert(is_java_string_pointer_type(string_argument.type())); + + typet deref_type=function_call.lhs().type().subtype(); + const exprt &lhs=function_call.lhs(); + dereference_exprt deref_lhs(lhs, deref_type); + + dereference_exprt deref(string_argument, string_argument.type().subtype()); + typet length_type, data_type; + get_data_and_length_type_of_string(deref, data_type, length_type); + std::list assignments; + + // lhs=malloc(array[char]) + typet object_type=ns.follow(deref_type); + exprt object_size=size_of_expr(object_type, ns); + + if(object_size.is_nil()) + debug() << "string_refine_preprocesst::make_to_char_array_function " + << "got nil object_size" << eom; + + side_effect_exprt malloc_expr(ID_malloc); + malloc_expr.copy_to_operands(object_size); + malloc_expr.type()=pointer_typet(object_type); + malloc_expr.add_source_location()=location; + assignments.emplace_back(lhs, malloc_expr); + + + // &((s->data)[0]) + exprt rhs_data=get_data(deref, data_type); + dereference_exprt rhs_array(rhs_data, data_type.subtype()); + exprt first_index=from_integer(0, java_int_type()); + index_exprt first_element(rhs_array, first_index, java_char_type()); + address_of_exprt rhs_pointer(first_element); + + // return_tmp0->data=&((s->data)[0]) + exprt lhs_data=get_data(deref_lhs, data_type); + assignments.emplace_back(lhs_data, rhs_pointer); + + // return_tmp0->length=s->length + exprt rhs_length=get_length(deref, length_type); + exprt lhs_length=get_length(deref_lhs, length_type); + assignments.emplace_back(lhs_length, rhs_length); + insert_assignments( + goto_program, target, target->function, location, assignments); +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::process_arguments + + Inputs: a goto program, a position, a list of expressions, a location and a + signature + + Outputs: a list of expressions + + Purpose: for each expression that is a string or that is at a position with + an 'S' character in the signature, we declare a new `cprover_string` + whose contents is deduced from the expression and replace the + expression by this cprover_string in the output list; + in the other case the expression is kept as is for the output list. + +\*******************************************************************/ + +exprt::operandst string_refine_preprocesst::process_arguments( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt::operandst &arguments, + const source_locationt &location, + const std::string &signature) +{ + exprt::operandst new_arguments; + + for(std::size_t i=0; isecond; + else + return ""; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::replace_string_calls + + Inputs: a function in a goto_program + + Purpose: goes through the instructions, replace function calls to string + function by equivalent instructions using functions defined + for the string solver, replace string literals by string + expressions of the type used by the string solver + TODO: the current implementation is only for java functions, + we should add support for other languages + +\*******************************************************************/ + +void string_refine_preprocesst::replace_string_calls( + goto_functionst::function_mapt::iterator f_it) +{ + goto_programt &goto_program=f_it->second.body; + + Forall_goto_program_instructions(target, goto_program) + { + if(target->is_function_call()) + { + code_function_callt &function_call=to_code_function_call(target->code); + + if(function_call.function().id()==ID_symbol) + { + const irep_idt &function_id= + to_symbol_expr(function_call.function()).get_identifier(); + std::string signature=function_signature(function_id); + + auto it=string_functions.find(function_id); + if(it!=string_functions.end()) + make_string_function( + goto_program, target, it->second, signature, false, false); + + it=side_effect_functions.find(function_id); + if(it!=side_effect_functions.end()) + make_string_function_side_effect( + goto_program, target, it->second, signature); + + it=string_function_calls.find(function_id); + if(it!=string_function_calls.end()) + make_string_function_call( + goto_program, target, it->second, signature); + + if(function_id==irep_idt("java::java.lang.String.toCharArray:()[C")) + make_to_char_array_function(goto_program, target); + } + } + else + { + if(target->is_assign()) + { + // In assignments we replace string literals and C string functions + code_assignt assignment=to_code_assign(target->code); + + exprt new_rhs=assignment.rhs(); + code_assignt new_assignment(assignment.lhs(), new_rhs); + + if(new_rhs.id()==ID_function_application) + { + function_application_exprt f=to_function_application_expr(new_rhs); + const exprt &name=f.function(); + assert(name.id()==ID_symbol); + const irep_idt &id=to_symbol_expr(name).get_identifier(); + auto it=c_string_functions.find(id); + if(it!=c_string_functions.end()) + { + declare_function(it->second, f.type()); + f.function()=symbol_exprt(it->second); + new_assignment=code_assignt(assignment.lhs(), f); + } + } + + new_assignment.add_source_location()=assignment.source_location(); + target->make_assignment(); + target->code=new_assignment; + } + } + } + return; +} + +/*******************************************************************\ + +Function: string_refine_preprocesst::initialize_string_function_table + + Purpose: fill maps with correspondance from java method names to cprover + functions + +\*******************************************************************/ + +void string_refine_preprocesst::initialize_string_function_table() +{ + string_functions["java::java.lang.String.codePointAt:(I)I"]= + ID_cprover_string_code_point_at_func; + string_functions["java::java.lang.String.codePointBefore:(I)I"]= + ID_cprover_string_code_point_before_func; + string_functions["java::java.lang.String.codePointCount:(II)I"]= + ID_cprover_string_code_point_count_func; + string_functions["java::java.lang.String.offsetByCodePoints:(II)I"]= + ID_cprover_string_offset_by_code_point_func; + string_functions["java::java.lang.String.hashCode:()I"]= + ID_cprover_string_hash_code_func; + string_functions["java::java.lang.String.indexOf:(I)I"]= + ID_cprover_string_index_of_func; + string_functions["java::java.lang.String.indexOf:(II)I"]= + ID_cprover_string_index_of_func; + string_functions["java::java.lang.String.indexOf:(Ljava/lang/String;)I"]= + ID_cprover_string_index_of_func; + string_functions["java::java.lang.String.indexOf:(Ljava/lang/String;I)I"]= + ID_cprover_string_index_of_func; + string_functions["java::java.lang.String.lastIndexOf:(I)I"]= + ID_cprover_string_last_index_of_func; + string_functions["java::java.lang.String.lastIndexOf:(II)I"]= + ID_cprover_string_last_index_of_func; + string_functions + ["java::java.lang.String.lastIndexOf:(Ljava/lang/String;)I"]= + ID_cprover_string_last_index_of_func; + string_functions + ["java::java.lang.String.lastIndexOf:(Ljava/lang/String;I)I"]= + ID_cprover_string_last_index_of_func; + string_functions + ["java::java.lang.String.concat:(Ljava/lang/String;)Ljava/lang/String;"]= + ID_cprover_string_concat_func; + string_functions["java::java.lang.String.length:()I"]= + ID_cprover_string_length_func; + string_functions["java::java.lang.StringBuilder.length:()I"]= + ID_cprover_string_length_func; + string_functions["java::java.lang.String.equals:(Ljava/lang/Object;)Z"]= + ID_cprover_string_equal_func; + string_functions + ["java::java.lang.String.equalsIgnoreCase:(Ljava/lang/String;)Z"]= + ID_cprover_string_equals_ignore_case_func; + string_functions["java::java.lang.String.startsWith:(Ljava/lang/String;)Z"]= + ID_cprover_string_startswith_func; + string_functions + ["java::java.lang.String.startsWith:(Ljava/lang/String;I)Z"]= + ID_cprover_string_startswith_func; + string_functions["java::java.lang.String.endsWith:(Ljava/lang/String;)Z"]= + ID_cprover_string_endswith_func; + string_functions["java::java.lang.String.substring:(II)Ljava/lang/String;"]= + ID_cprover_string_substring_func; + string_functions["java::java.lang.String.substring:(II)Ljava/lang/String;"]= + ID_cprover_string_substring_func; + string_functions["java::java.lang.String.substring:(I)Ljava/lang/String;"]= + ID_cprover_string_substring_func; + string_functions + ["java::java.lang.StringBuilder.substring:(II)Ljava/lang/String;"]= + ID_cprover_string_substring_func; + string_functions + ["java::java.lang.StringBuilder.substring:(I)Ljava/lang/String;"]= + ID_cprover_string_substring_func; + string_functions + ["java::java.lang.String.subSequence:(II)Ljava/lang/CharSequence;"]= + ID_cprover_string_substring_func; + string_functions["java::java.lang.String.trim:()Ljava/lang/String;"]= + ID_cprover_string_trim_func; + string_functions["java::java.lang.String.toLowerCase:()Ljava/lang/String;"]= + ID_cprover_string_to_lower_case_func; + string_functions["java::java.lang.String.toUpperCase:()Ljava/lang/String;"]= + ID_cprover_string_to_upper_case_func; + string_functions["java::java.lang.String.replace:(CC)Ljava/lang/String;"]= + ID_cprover_string_replace_func; + string_functions + ["java::java.lang.String.contains:(Ljava/lang/CharSequence;)Z"]= + ID_cprover_string_contains_func; + string_functions["java::java.lang.String.compareTo:(Ljava/lang/String;)I"]= + ID_cprover_string_compare_to_func; + string_functions["java::java.lang.String.intern:()Ljava/lang/String;"]= + ID_cprover_string_intern_func; + string_functions["java::java.lang.String.isEmpty:()Z"]= + ID_cprover_string_is_empty_func; + string_functions["java::java.lang.String.charAt:(I)C"]= + ID_cprover_string_char_at_func; + string_functions["java::java.lang.StringBuilder.charAt:(I)C"]= + ID_cprover_string_char_at_func; + string_functions["java::java.lang.CharSequence.charAt:(I)C"]= + ID_cprover_string_char_at_func; + string_functions + ["java::java.lang.StringBuilder.toString:()Ljava/lang/String;"]= + ID_cprover_string_copy_func; + + string_functions["java::java.lang.String.valueOf:(F)Ljava/lang/String;"]= + ID_cprover_string_of_float_func; + string_functions["java::java.lang.Float.toString:(F)Ljava/lang/String;"]= + ID_cprover_string_of_float_func; + string_functions["java::java.lang.Integer.toString:(I)Ljava/lang/String;"]= + ID_cprover_string_of_int_func; + string_functions["java::java.lang.String.valueOf:(I)Ljava/lang/String;"]= + ID_cprover_string_of_int_func; + string_functions["java::java.lang.Integer.toHexString:(I)Ljava/lang/String;"]= + ID_cprover_string_of_int_hex_func; + string_functions["java::java.lang.String.valueOf:(L)Ljava/lang/String;"]= + ID_cprover_string_of_long_func; + string_functions["java::java.lang.String.valueOf:(D)Ljava/lang/String;"]= + ID_cprover_string_of_double_func; + string_functions["java::java.lang.String.valueOf:(Z)Ljava/lang/String;"]= + ID_cprover_string_of_bool_func; + string_functions["java::java.lang.String.valueOf:(C)Ljava/lang/String;"]= + ID_cprover_string_of_char_func; + string_functions["java::java.lang.Integer.parseInt:(Ljava/lang/String;)I"]= + ID_cprover_string_parse_int_func; + + side_effect_functions + ["java::java.lang.StringBuilder.append:(Ljava/lang/String;)" + "Ljava/lang/StringBuilder;"]= + ID_cprover_string_concat_func; + side_effect_functions["java::java.lang.StringBuilder.setCharAt:(IC)V"]= + ID_cprover_string_char_set_func; + side_effect_functions + ["java::java.lang.StringBuilder.append:(I)Ljava/lang/StringBuilder;"]= + ID_cprover_string_concat_int_func; + side_effect_functions + ["java::java.lang.StringBuilder.append:(J)Ljava/lang/StringBuilder;"]= + ID_cprover_string_concat_long_func; + side_effect_functions + ["java::java.lang.StringBuilder.append:(Z)Ljava/lang/StringBuilder;"]= + ID_cprover_string_concat_bool_func; + side_effect_functions + ["java::java.lang.StringBuilder.append:(C)Ljava/lang/StringBuilder;"]= + ID_cprover_string_concat_char_func; + side_effect_functions + ["java::java.lang.StringBuilder.append:(D)Ljava/lang/StringBuilder;"]= + ID_cprover_string_concat_double_func; + side_effect_functions + ["java::java.lang.StringBuilder.append:(F)Ljava/lang/StringBuilder;"]= + ID_cprover_string_concat_float_func; + side_effect_functions + ["java::java.lang.StringBuilder.appendCodePoint:(I)" + "Ljava/lang/StringBuilder;"]= + ID_cprover_string_concat_code_point_func; + side_effect_functions + ["java::java.lang.StringBuilder.delete:(II)Ljava/lang/StringBuilder;"]= + ID_cprover_string_delete_func; + side_effect_functions + ["java::java.lang.StringBuilder.deleteCharAt:(I)Ljava/lang/StringBuilder;"]= + ID_cprover_string_delete_char_at_func; + side_effect_functions + ["java::java.lang.StringBuilder.insert:(ILjava/lang/String;)" + "Ljava/lang/StringBuilder;"]= + ID_cprover_string_insert_func; + side_effect_functions + ["java::java.lang.StringBuilder.insert:(II)Ljava/lang/StringBuilder;"]= + ID_cprover_string_insert_int_func; + side_effect_functions + ["java::java.lang.StringBuilder.insert:(IJ)Ljava/lang/StringBuilder;"]= + ID_cprover_string_insert_long_func; + side_effect_functions + ["java::java.lang.StringBuilder.insert:(IC)Ljava/lang/StringBuilder;"]= + ID_cprover_string_insert_char_func; + side_effect_functions + ["java::java.lang.StringBuilder.insert:(IZ)Ljava/lang/StringBuilder;"]= + ID_cprover_string_insert_bool_func; + side_effect_functions + ["java::java.lang.StringBuilder.setLength:(I)V"]= + ID_cprover_string_set_length_func; + + + + side_effect_functions + ["java::java.lang.StringBuilder.append:([C)" + "Ljava/lang/StringBuilder;"]= + ID_cprover_string_concat_func; + side_effect_functions + ["java::java.lang.StringBuilder.insert:(I[CII)Ljava/lang/StringBuilder;"]= + ID_cprover_string_insert_func; + side_effect_functions + ["java::java.lang.StringBuilder.insert:(I[C)Ljava/lang/StringBuilder;"]= + ID_cprover_string_insert_func; + // TODO clean irep ids from insert_char_array etc... + + string_function_calls + ["java::java.lang.String.:(Ljava/lang/String;)V"]= + ID_cprover_string_copy_func; + string_function_calls + ["java::java.lang.String.:(Ljava/lang/StringBuilder;)V"]= + ID_cprover_string_copy_func; + string_function_calls + ["java::java.lang.StringBuilder.:(Ljava/lang/String;)V"]= + ID_cprover_string_copy_func; + string_function_calls["java::java.lang.String.:()V"]= + ID_cprover_string_empty_string_func; + string_function_calls["java::java.lang.StringBuilder.:()V"]= + ID_cprover_string_empty_string_func; + + string_function_calls["java::java.lang.String.:([C)V"]= + ID_cprover_string_copy_func; + string_function_calls["java::java.lang.String.:([CII)V"]= + ID_cprover_string_copy_func; + + string_functions + ["java::java.lang.String.valueOf:([CII)Ljava/lang/String;"]= + ID_cprover_string_copy_func; + string_functions + ["java::java.lang.String.valueOf:([C)Ljava/lang/String;"]= + ID_cprover_string_copy_func; + string_functions + ["java::java.lang.String.copyValueOf:([CII)Ljava/lang/String;"]= + ID_cprover_string_copy_func; + string_functions + ["java::java.lang.String.copyValueOf:([C)Ljava/lang/String;"]= + ID_cprover_string_copy_func; + + c_string_functions["__CPROVER_uninterpreted_string_literal_func"]= + ID_cprover_string_literal_func; + c_string_functions["__CPROVER_uninterpreted_string_char_at_func"]= + ID_cprover_string_char_at_func; + c_string_functions["__CPROVER_uninterpreted_string_equal_func"]= + ID_cprover_string_equal_func; + c_string_functions["__CPROVER_uninterpreted_string_concat_func"]= + ID_cprover_string_concat_func; + c_string_functions["__CPROVER_uninterpreted_string_length_func"]= + ID_cprover_string_length_func; + c_string_functions["__CPROVER_uninterpreted_string_substring_func"]= + ID_cprover_string_substring_func; + c_string_functions["__CPROVER_uninterpreted_string_is_prefix_func"]= + ID_cprover_string_is_prefix_func; + c_string_functions["__CPROVER_uninterpreted_string_is_suffix_func"]= + ID_cprover_string_is_suffix_func; + c_string_functions["__CPROVER_uninterpreted_string_contains_func"]= + ID_cprover_string_contains_func; + c_string_functions["__CPROVER_uninterpreted_string_index_of_func"]= + ID_cprover_string_index_of_func; + c_string_functions["__CPROVER_uninterpreted_string_last_index_of_func"]= + ID_cprover_string_last_index_of_func; + c_string_functions["__CPROVER_uninterpreted_string_char_set_func"]= + ID_cprover_string_char_set_func; + c_string_functions["__CPROVER_uninterpreted_string_copy_func"]= + ID_cprover_string_copy_func; + c_string_functions["__CPROVER_uninterpreted_string_parse_int_func"]= + ID_cprover_string_parse_int_func; + c_string_functions["__CPROVER_uninterpreted_string_of_int_func"]= + ID_cprover_string_of_int_func; + + signatures["java::java.lang.String.equals:(Ljava/lang/Object;)Z"]="SSZ"; + signatures["java::java.lang.String.contains:(Ljava/lang/CharSequence;)Z"]= + "SSZ"; + signatures["java::java.lang.StringBuilder.insert:(IZ)" + "Ljava/lang/StringBuilder;"]="SIZS"; + signatures["java::java.lang.StringBuilder.insert:(IJ)" + "Ljava/lang/StringBuilder;"]="SIJS"; + signatures["java::java.lang.StringBuilder.insert:(II)" + "Ljava/lang/StringBuilder;"]="SIIS"; + signatures["java::java.lang.StringBuilder.insert:(IC)" + "Ljava/lang/StringBuilder;"]="SICS"; + signatures["java::java.lang.StringBuilder.insert:(ILjava/lang/String;)" + "Ljava/lang/StringBuilder;"]="SISS"; + signatures["java::java.lang.StringBuilder.insert:(ILjava/lang/String;)" + "Ljava/lang/StringBuilder;"]="SISS"; + signatures["java::java.lang.StringBuilder.insert:(I[C)" + "Ljava/lang/StringBuilder;"]="SI[S"; + signatures["java::java.lang.String.intern:()Ljava/lang/String;"]="SV"; +} + +/*******************************************************************\ + +Constructor: string_refine_preprocesst::string_refine_preprocesst + + Inputs: a symbol table, goto functions, a message handler + + Purpose: process the goto function by replacing calls to string functions + +\*******************************************************************/ + +string_refine_preprocesst::string_refine_preprocesst( + symbol_tablet &_symbol_table, + goto_functionst &_goto_functions, + message_handlert &_message_handler): + messaget(_message_handler), + ns(_symbol_table), + symbol_table(_symbol_table), + goto_functions(_goto_functions), + next_symbol_id(0), + jls_ptr(symbol_typet("java::java.lang.String")) +{ + initialize_string_function_table(); + Forall_goto_functions(it, goto_functions) + replace_string_calls(it); +} diff --git a/src/goto-programs/string_refine_preprocess.h b/src/goto-programs/string_refine_preprocess.h new file mode 100644 index 00000000000..5ae398b757a --- /dev/null +++ b/src/goto-programs/string_refine_preprocess.h @@ -0,0 +1,198 @@ +/*******************************************************************\ + +Module: Preprocess a goto-programs so that calls to the java String + library are recognized by the PASS algorithm + +Author: Romain Brenguier + +Date: September 2016 + +\*******************************************************************/ + +#ifndef CPROVER_GOTO_PROGRAMS_STRING_REFINE_PREPROCESS_H +#define CPROVER_GOTO_PROGRAMS_STRING_REFINE_PREPROCESS_H + +#include +#include +#include + +class string_refine_preprocesst:public messaget +{ + public: + string_refine_preprocesst( + symbol_tablet &, goto_functionst &, message_handlert &); + + private: + namespacet ns; + symbol_tablet & symbol_table; + goto_functionst & goto_functions; + + typedef std::unordered_map id_mapt; + typedef std::unordered_map expr_mapt; + + // Map name of Java string functions to there equivalent in the solver + id_mapt side_effect_functions; + id_mapt string_functions; + id_mapt c_string_functions; + id_mapt string_function_calls; + + std::unordered_map signatures; + + // unique id for each newly created symbols + int next_symbol_id; + + void initialize_string_function_table(); + + static bool check_java_type(const typet &type, const std::string &tag); + + static bool is_java_string_pointer_type(const typet &type); + + static bool is_java_string_type(const typet &type); + + static bool is_java_string_builder_type(const typet &type); + + static bool is_java_string_builder_pointer_type(const typet &type); + + static bool is_java_char_sequence_type(const typet &type); + + static bool is_java_char_sequence_pointer_type(const typet &type); + + static bool is_java_char_array_type(const typet &type); + + static bool is_java_char_array_pointer_type(const typet &type); + + static bool implements_java_char_sequence(const typet &type) + { + return + is_java_char_sequence_pointer_type(type) || + is_java_string_builder_pointer_type(type) || + is_java_string_pointer_type(type); + } + + symbol_exprt fresh_array( + const typet &type, const source_locationt &location); + symbol_exprt fresh_string( + const typet &type, const source_locationt &location); + + // get the data member of a java string + static exprt get_data(const exprt &string, const typet &data_type) + { + return member_exprt(string, "data", data_type); + } + + // get the length member of a java string + exprt get_length(const exprt &string, const typet &length_type) + { + return member_exprt(string, "length", length_type); + } + + // type of pointers to string + pointer_typet jls_ptr; + exprt replace_string(const exprt &in); + exprt replace_string_in_assign(const exprt &in); + + void insert_assignments( + goto_programt &goto_program, + goto_programt::targett &target, + irep_idt function, + source_locationt location, + const std::list &va); + + exprt replace_string_pointer(const exprt &in); + + // Replace string builders by expression of the mapping and make + // assignments for strings as string_exprt + exprt::operandst process_arguments( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt::operandst &arguments, + const source_locationt &location, + const std::string &signature=""); + + // Signature of the named function if it is defined in the signature map, + // empty string otherwise + std::string function_signature(const irep_idt &function_id); + + void declare_function(irep_idt function_name, const typet &type); + + void get_data_and_length_type_of_string( + const exprt &expr, typet &data_type, typet &length_type); + + void get_data_and_length_type_of_char_array( + const exprt &expr, typet &data_type, typet &length_type); + + function_application_exprt build_function_application( + const irep_idt &function_name, + const typet &type, + const source_locationt &location, + const exprt::operandst &arguments); + + void make_normal_assign( + goto_programt &goto_program, + goto_programt::targett target, + const exprt &lhs, + const code_typet &function_type, + const irep_idt &function_name, + const exprt::operandst &arguments, + const source_locationt &location, + const std::string &signature=""); + + void make_string_assign( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &lhs, + const code_typet &function_type, + const irep_idt &function_name, + const exprt::operandst &arguments, + const source_locationt &location, + const std::string &signature); + + exprt make_cprover_string_assign( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &rhs, + const source_locationt &location); + + string_exprt make_cprover_char_array_assign( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &rhs, + const source_locationt &location); + + void make_string_function( + goto_programt &goto_program, + goto_programt::targett &target, + const irep_idt &function_name, + const std::string &signature, + bool assign_first_arg=false, + bool skip_first_arg=false); + + void make_string_function( + goto_programt &goto_program, + goto_programt::targett &target, + const exprt &lhs, + const code_typet &function_type, + const irep_idt &function_name, + const exprt::operandst &arguments, + const source_locationt &location, + const std::string &signature); + + void make_string_function_call( + goto_programt &goto_program, + goto_programt::targett &target, + const irep_idt &function_name, + const std::string &signature); + + void make_string_function_side_effect( + goto_programt &goto_program, + goto_programt::targett &target, + const irep_idt &function_name, + const std::string &signature); + + void make_to_char_array_function( + goto_programt &goto_program, goto_programt::targett &); + + void replace_string_calls(goto_functionst::function_mapt::iterator f_it); +}; + +#endif diff --git a/src/goto-programs/system_library_symbols.cpp b/src/goto-programs/system_library_symbols.cpp new file mode 100644 index 00000000000..7e885a8f150 --- /dev/null +++ b/src/goto-programs/system_library_symbols.cpp @@ -0,0 +1,364 @@ +/*******************************************************************\ + +Module: Goto Programs + +Author: Thomas Kiley + +\*******************************************************************/ + +#include "system_library_symbols.h" +#include +#include +#include +#include + +system_library_symbolst::system_library_symbolst() +{ + init_system_library_map(); +} + +/*******************************************************************\ + +Function: system_library_symbolst::init_system_library_map + +Inputs: + +Outputs: + +Purpose: To generate a map of header file names -> list of symbols + The symbol names are reserved as the header and source files + will be compiled in to the goto program. + +\*******************************************************************/ + +void system_library_symbolst::init_system_library_map() +{ + // ctype.h + std::list ctype_syms= + { + "isalnum", "isalpha", "isblank", "iscntrl", "isdigit", "isgraph", + "islower", "isprint", "ispunct", "isspace", "isupper", "isxdigit", + "tolower", "toupper" + }; + add_to_system_library("ctype.h", ctype_syms); + + // fcntl.h + std::list fcntl_syms= + { + "creat", "fcntl", "open" + }; + add_to_system_library("fcntl.h", fcntl_syms); + + // locale.h + std::list locale_syms= + { + "setlocale" + }; + add_to_system_library("locale.h", locale_syms); + + // math.h + std::list math_syms= + { + "acos", "acosh", "asin", "asinh", "atan", "atan2", "atanh", + "cbrt", "ceil", "copysign", "cos", "cosh", "erf", "erfc", "exp", + "exp2", "expm1", "fabs", "fdim", "floor", "fma", "fmax", "fmin", + "fmod", "fpclassify", "fpclassifyl", "fpclassifyf", "frexp", + "hypot", "ilogb", "isfinite", "isinf", "isinff", "isinfl", + "isnan", "isnanf", "isnanl", "isnormal", "j0", "j1", "jn", + "ldexp", "lgamma", "llrint", "llround", "log", "log10", "log1p", + "log2", "logb", "lrint", "lround", "modf", "nan", "nearbyint", + "nextafter", "pow", "remainder", "remquo", "rint", "round", + "scalbln", "scalbn", "signbit", "sin", "sinh", "sqrt", "tan", + "tanh", "tgamma", "trunc", "y0", "y1", "yn" + }; + add_to_system_library("math.h", math_syms); + + // for some reason the math functions can sometimes be prefixed with + // a double underscore + std::list underscore_math_syms; + for(const irep_idt &math_sym : math_syms) + { + std::ostringstream underscore_id; + underscore_id << "__" << math_sym; + underscore_math_syms.push_back(irep_idt(underscore_id.str())); + } + add_to_system_library("math.h", underscore_math_syms); + + // pthread.h + std::list pthread_syms= + { + "pthread_cleanup_pop", "pthread_cleanup_push", + "pthread_cond_broadcast", "pthread_cond_destroy", + "pthread_cond_init", "pthread_cond_signal", + "pthread_cond_timedwait", "pthread_cond_wait", "pthread_create", + "pthread_detach", "pthread_equal", "pthread_exit", + "pthread_getspecific", "pthread_join", "pthread_key_delete", + "pthread_mutex_destroy", "pthread_mutex_init", + "pthread_mutex_lock", "pthread_mutex_trylock", + "pthread_mutex_unlock", "pthread_once", "pthread_rwlock_destroy", + "pthread_rwlock_init", "pthread_rwlock_rdlock", + "pthread_rwlock_unlock", "pthread_rwlock_wrlock", + "pthread_rwlockattr_destroy", "pthread_rwlockattr_getpshared", + "pthread_rwlockattr_init", "pthread_rwlockattr_setpshared", + "pthread_self", "pthread_setspecific", + /* non-public struct types */ + "tag-__pthread_internal_list", "tag-__pthread_mutex_s", + "pthread_mutex_t" + }; + add_to_system_library("pthread.h", pthread_syms); + + // setjmp.h + std::list setjmp_syms= + { + "_longjmp", "_setjmp", "longjmp", "longjmperror", "setjmp", + "siglongjmp", "sigsetjmp" + }; + add_to_system_library("setjmp.h", setjmp_syms); + + // stdio.h + std::list stdio_syms= + { + "asprintf", "clearerr", "fclose", "fdopen", "feof", "ferror", + "fflush", "fgetc", "fgetln", "fgetpos", "fgets", "fgetwc", + "fgetws", "fileno", "fopen", "fprintf", "fpurge", "fputc", + "fputs", "fputwc", "fputws", "fread", "freopen", "fropen", + "fscanf", "fseek", "fsetpos", "ftell", "funopen", "fwide", + "fwopen", "fwprintf", "fwrite", "getc", "getchar", "getdelim", + "getline", "gets", "getw", "getwc", "getwchar", "mkdtemp", + "mkstemp", "mktemp", "perror", "printf", "putc", "putchar", + "puts", "putw", "putwc", "putwchar", "remove", "rewind", "scanf", + "setbuf", "setbuffer", "setlinebuf", "setvbuf", "snprintf", + "sprintf", "sscanf", "swprintf", "sys_errlist", + "sys_nerr", "tempnam", "tmpfile", "tmpnam", "ungetc", "ungetwc", + "vasprintf", "vfprintf", "vfscanf", "vfwprintf", "vprintf", + "vscanf", "vsnprintf", "vsprintf", "vsscanf", "vswprintf", + "vwprintf", "wprintf", + /* non-public struct types */ + "tag-__sFILE", "tag-__sbuf", // OS X + "tag-_IO_FILE", "tag-_IO_marker", // Linux + }; + add_to_system_library("stdio.h", stdio_syms); + + // stdlib.h + std::list stdlib_syms= + { + "abort", "abs", "atexit", "atof", "atoi", "atol", "atoll", + "bsearch", "calloc", "div", "exit", "free", "getenv", "labs", + "ldiv", "llabs", "lldiv", "malloc", "mblen", "mbstowcs", "mbtowc", + "qsort", "rand", "realloc", "srand", "strtod", "strtof", "strtol", + "strtold", "strtoll", "strtoul", "strtoull", "system", "wcstombs", + "wctomb" + }; + add_to_system_library("stdlib.h", stdlib_syms); + + // string.h + std::list string_syms= + { + "memset", "strcasecmp", "strcat", "strchr", "strcmp", "strcpy", + "strcspn", "strdup", "strerror", "strlen", "strncasecmp", + "strncat", "strncmp", "strncpy", "strpbrk", "strrchr", "strspn", + "strstr", "strtok" + }; + add_to_system_library("string.h", string_syms); + + // time.h + std::list time_syms= + { + "asctime", "asctime_r", "ctime", "ctime_r", "difftime", "gmtime", + "gmtime_r", "localtime", "localtime_r", "mktime", "strftime", + /* non-public struct types */ + "tag-timespec", "tag-timeval", "tag-tm" + }; + add_to_system_library("time.h", time_syms); + + // unistd.h + std::list unistd_syms= + { + "_exit", "access", "alarm", "chdir", "chown", "close", "dup", + "dup2", "execl", "execle", "execlp", "execv", "execve", "execvp", + "fork", "fpathconf", "getcwd", "getegid", "geteuid", "getgid", + "getgroups", "getlogin", "getpgrp", "getpid", "getppid", "getuid", + "isatty", "link", "lseek", "pathconf", "pause", "pipe", "read", + "rmdir", "setgid", "setpgid", "setsid", "setuid", "sleep", + "sysconf", "tcgetpgrp", "tcsetpgrp", "ttyname", "ttyname_r", + "unlink", "write" + }; + add_to_system_library("unistd.h", unistd_syms); + + // sys/select.h + std::list sys_select_syms= + { + "select", + /* non-public struct types */ + "fd_set" + }; + add_to_system_library("sys/select.h", sys_select_syms); + + // sys/socket.h + std::list sys_socket_syms= + { + "accept", "bind", "connect", + /* non-public struct types */ + "tag-sockaddr" + }; + add_to_system_library("sys/socket.h", sys_socket_syms); + + // sys/stat.h + std::list sys_stat_syms= + { + "fstat", "lstat", "stat", + /* non-public struct types */ + "tag-stat" + }; + add_to_system_library("sys/stat.h", sys_stat_syms); + + std::list fenv_syms= + { + "fenv_t", "fexcept_t", "feclearexcept", "fegetexceptflag", + "feraiseexcept", "fesetexceptflag", "fetestexcept", + "fegetround", "fesetround", "fegetenv", "feholdexcept", + "fesetenv", "feupdateenv" + }; + add_to_system_library("fenv.h", fenv_syms); + + std::list errno_syms= + { + "__error", "__errno_location", "__errno" + }; + add_to_system_library("errno.c", errno_syms); + + std::list noop_syms= + { + "__noop" + }; + add_to_system_library("noop.c", noop_syms); + +#if 0 + // sys/types.h + std::list sys_types_syms= + { + }; + add_to_system_library("sys/types.h", sys_types_syms); +#endif + + // sys/wait.h + std::list sys_wait_syms= + { + "wait", "waitpid" + }; + add_to_system_library("sys/wait.h", sys_wait_syms); +} + +/*******************************************************************\ + +Function: system_library_symbolst::add_to_system_library + +Inputs: + header_file - the name of the header file the symbol came from + symbols - a list of the names of the symbols in the header file + +Outputs: + +Purpose: To add the symbols from a specific header file to the + system library map. The symbol is used as the key so that + we can easily look up symbols. + +\*******************************************************************/ + +void system_library_symbolst::add_to_system_library( + irep_idt header_file, + std::list symbols) +{ + for(const irep_idt &symbol : symbols) + { + system_library_map[symbol]=header_file; + } +} + + +/*******************************************************************\ + +Function: system_library_symbolst::is_symbol_internal_symbol + +Inputs: + symbol - the symbol to check + +Outputs: True if the symbol is an internal symbol. If specific system + headers need to be included, the out_system_headers will contain + the headers. + +Purpose: To find out if a symbol is an internal symbol. + +\*******************************************************************/ + +bool system_library_symbolst::is_symbol_internal_symbol( + const symbolt &symbol, + std::set &out_system_headers) const +{ + const std::string &name_str=id2string(symbol.name); + + if(has_prefix(name_str, CPROVER_PREFIX) || + name_str=="__func__" || + name_str=="__FUNCTION__" || + name_str=="__PRETTY_FUNCTION__" || + name_str=="argc'" || + name_str=="argv'" || + name_str=="envp'" || + name_str=="envp_size'") + return true; + + // exclude nondet instructions + if(has_prefix(name_str, "nondet_")) + return true; + + if(has_prefix(name_str, "__VERIFIER")) + return true; + + if(has_suffix(name_str, "$object")) + return true; + + const std::string &file_str=id2string(symbol.location.get_file()); + + // don't dump internal GCC builtins + if(has_prefix(file_str, "gcc_builtin_headers_") && + has_prefix(name_str, "__builtin_")) + return true; + + if(name_str=="__builtin_va_start" || + name_str=="__builtin_va_end" || + symbol.name==ID_gcc_builtin_va_arg) + { + out_system_headers.insert("stdarg.h"); + return true; + } + + // don't dump asserts + else if(name_str=="__assert_fail" || + name_str=="_assert" || + name_str=="__assert_c99" || + name_str=="_wassert") + return true; + + const auto &it=system_library_map.find(symbol.name); + + if(it!=system_library_map.end()) + { + out_system_headers.insert(id2string(it->second)); + return true; + } + + if(use_all_headers && + has_prefix(file_str, "/usr/include/")) + { + if(file_str.find("/bits/")==std::string::npos) + { + // Do not include transitive includes of system headers! + std::string::size_type prefix_len=std::string("/usr/include/").size(); + out_system_headers.insert(file_str.substr(prefix_len)); + } + + return true; + } + + return false; +} diff --git a/src/goto-programs/system_library_symbols.h b/src/goto-programs/system_library_symbols.h new file mode 100644 index 00000000000..9438e052a76 --- /dev/null +++ b/src/goto-programs/system_library_symbols.h @@ -0,0 +1,38 @@ +/*******************************************************************\ + +Module: Goto Programs + +Author: Thomas Kiley + +\*******************************************************************/ + +#ifndef CPROVER_GOTO_PROGRAMS_SYSTEM_LIBRARY_SYMBOLS_H +#define CPROVER_GOTO_PROGRAMS_SYSTEM_LIBRARY_SYMBOLS_H + +#include +#include +#include +#include + +class symbolt; + +class system_library_symbolst +{ +public: + system_library_symbolst(); + + bool is_symbol_internal_symbol( + const symbolt &symbol, + std::set &out_system_headers) const; + +private: + void init_system_library_map(); + + void add_to_system_library( + irep_idt header_file, + std::list symbols); + + std::map system_library_map; +}; + +#endif // CPROVER_GOTO_PROGRAMS_SYSTEM_LIBRARY_SYMBOLS_H diff --git a/src/goto-symex/build_goto_trace.cpp b/src/goto-symex/build_goto_trace.cpp index 7b6a367f6b2..8bee16c6bd1 100644 --- a/src/goto-symex/build_goto_trace.cpp +++ b/src/goto-symex/build_goto_trace.cpp @@ -109,6 +109,86 @@ exprt adjust_lhs_object( return nil_exprt(); } +/*******************************************************************\ + +Function: set_internal_dynamic_object + + Inputs: + + Outputs: + + Purpose: set internal field for variable assignment related to + dynamic_object[0-9] and dynamic_[0-9]_array. + +\*******************************************************************/ + +void set_internal_dynamic_object( + const exprt &expr, + goto_trace_stept &goto_trace_step, + const namespacet &ns) +{ + if(expr.id()==ID_symbol) + { + const irep_idt &id=to_ssa_expr(expr).get_original_name(); + const symbolt *symbol; + if(!ns.lookup(id, symbol)) + { + bool result=symbol->type.get_bool("#dynamic"); + if(result) + goto_trace_step.internal=true; + } + } + else + { + forall_operands(it, expr) + set_internal_dynamic_object(*it, goto_trace_step, ns); + } +} + +/*******************************************************************\ + +Function: update_internal_field + + Inputs: + + Outputs: + + Purpose: set internal for variables assignments related to + dynamic_object and CPROVER internal functions + (e.g., __CPROVER_initialize) + +\*******************************************************************/ + +void update_internal_field( + const symex_target_equationt::SSA_stept &SSA_step, + goto_trace_stept &goto_trace_step, + const namespacet &ns) +{ + // set internal for dynamic_object in both lhs and rhs expressions + set_internal_dynamic_object(SSA_step.ssa_lhs, goto_trace_step, ns); + set_internal_dynamic_object(SSA_step.ssa_rhs, goto_trace_step, ns); + + // set internal field to CPROVER functions (e.g., __CPROVER_initialize) + if(SSA_step.is_function_call()) + { + if(SSA_step.source.pc->source_location.as_string().empty()) + goto_trace_step.internal=true; + } + + // set internal field to input and output steps + if(goto_trace_step.type==goto_trace_stept::OUTPUT || + goto_trace_step.type==goto_trace_stept::INPUT) + { + goto_trace_step.internal=true; + } + + // set internal field to _start function-return step + if(SSA_step.source.pc->function==goto_functionst::entry_point()) + { + goto_trace_step.internal=true; + } +} + void build_goto_trace( const symex_target_equationt &target, symex_target_equationt::SSA_stepst::const_iterator end_step, @@ -214,6 +294,9 @@ void build_goto_trace( goto_trace_step.formatted=SSA_step.formatted; goto_trace_step.identifier=SSA_step.identifier; + // update internal field for specific variables in the counterexample + update_internal_field(SSA_step, goto_trace_step, ns); + goto_trace_step.assignment_type= (it->is_assignment()&& (SSA_step.assignment_type== diff --git a/src/java_bytecode/character_refine_preprocess.cpp b/src/java_bytecode/character_refine_preprocess.cpp index 912ea2ab131..435895f7aaf 100644 --- a/src/java_bytecode/character_refine_preprocess.cpp +++ b/src/java_bytecode/character_refine_preprocess.cpp @@ -17,12 +17,21 @@ Date: March 2017 #include #include "character_refine_preprocess.h" -/// converts based on a function on expressions -/// \param expr_function: A reference to a function on expressions -/// \param target: A position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_char_function + + Inputs: + expr_function - A reference to a function on expressions + target - A position in a goto program + + Purpose: converts based on a function on expressions + +\*******************************************************************/ + codet character_refine_preprocesst::convert_char_function( exprt (*expr_function)(const exprt &chr, const typet &type), - conversion_input &target) + conversion_inputt &target) { const code_function_callt &function_call=target; assert(function_call.arguments().size()==1); @@ -32,12 +41,22 @@ codet character_refine_preprocesst::convert_char_function( return code_assignt(result, expr_function(arg, type)); } -/// The returned expression is true when the first argument is in the interval -/// defined by the lower and upper bounds (included) -/// \param arg: Expression we want to bound -/// \param lower_bound: Integer lower bound -/// \param upper_bound: Integer upper bound -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::in_interval_expr + + Inputs: + arg - Expression we want to bound + lower_bound - Integer lower bound + upper_bound - Integer upper bound + + Outputs: A Boolean expression + + Purpose: The returned expression is true when the first argument is in the + interval defined by the lower and upper bounds (included) + +\*******************************************************************/ + exprt character_refine_preprocesst::in_interval_expr( const exprt &chr, const mp_integer &lower_bound, @@ -48,11 +67,21 @@ exprt character_refine_preprocesst::in_interval_expr( binary_relation_exprt(chr, ID_le, from_integer(upper_bound, chr.type()))); } -/// The returned expression is true when the given character is equal to one of -/// the element in the list -/// \param chr: An expression of type character -/// \param list: A list of integer representing unicode characters -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::in_list_expr + + Inputs: + chr - An expression of type character + list - A list of integer representing unicode characters + + Outputs: A Boolean expression + + Purpose: The returned expression is true when the given character + is equal to one of the element in the list + +\*******************************************************************/ + exprt character_refine_preprocesst::in_list_expr( const exprt &chr, const std::list &list) { @@ -62,11 +91,21 @@ exprt character_refine_preprocesst::in_list_expr( return disjunction(ops); } -/// Determines the number of char values needed to represent the specified -/// character (Unicode code point). -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A integer expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_char_count + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A integer expression of the given type + + Purpose: Determines the number of char values needed to represent + the specified character (Unicode code point). + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_char_count( const exprt &chr, const typet &type) { @@ -75,36 +114,76 @@ exprt character_refine_preprocesst::expr_of_char_count( return if_exprt(small, from_integer(1, type), from_integer(2, type)); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.charCount:(I)I -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_char_count(conversion_input &target) +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_char_count + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.charCount:(I)I + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_char_count( + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_char_count, target); } -/// Casts the given expression to the given type -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_char_value + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Casts the given expression to the given type + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_char_value( const exprt &chr, const typet &type) { return typecast_exprt(chr, type); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.charValue:()C -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_char_value(conversion_input &target) +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_char_value + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.charValue:()C + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_char_value( + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_char_value, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.compare:(CC)I -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_compare(conversion_input &target) +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_compare + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.compare:(CC)I + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_compare(conversion_inputt &target) { const code_function_callt &function_call=target; assert(function_call.arguments().size()==2); @@ -123,10 +202,20 @@ codet character_refine_preprocesst::convert_compare(conversion_input &target) } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.digit:(CI)I -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_digit_char(conversion_input &target) +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_digit_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.digit:(CI)I + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_digit_char( + conversion_inputt &target) { const code_function_callt &function_call=target; assert(function_call.arguments().size()==2); @@ -196,109 +285,202 @@ codet character_refine_preprocesst::convert_digit_char(conversion_input &target) return code_assignt(result, tc_expr); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.digit:(II)I -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_digit_int(conversion_input &target) +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_char_is_digit_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.digit:(II)I + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_digit_int(conversion_inputt &target) { return convert_digit_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.forDigit:(II)I -/// -/// TODO: For now the radix argument is ignored -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_for_digit(conversion_input &target) +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_for_digit + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.forDigit:(II)C + + TODO: For now the radix argument is ignored + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_for_digit(conversion_inputt &target) { const code_function_callt &function_call=target; assert(function_call.arguments().size()==2); const exprt &digit=function_call.arguments()[0]; const exprt &result=function_call.lhs(); const typet &type=result.type(); + typecast_exprt casted_digit(digit, type); exprt d10=from_integer(10, type); - binary_relation_exprt small(digit, ID_le, d10); - plus_exprt value1(digit, from_integer('0', type)); - minus_exprt value2(plus_exprt(digit, from_integer('a', digit.type())), d10); + binary_relation_exprt small(casted_digit, ID_le, d10); + plus_exprt value1(casted_digit, from_integer('0', type)); + plus_exprt value2(minus_exprt(casted_digit, d10), from_integer('a', type)); return code_assignt(result, if_exprt(small, value1, value2)); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.getDirectionality:(C)I -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_get_directionality_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.getDirectionality:(C)I + +\*******************************************************************/ + codet character_refine_preprocesst::convert_get_directionality_char( - conversion_input &target) + conversion_inputt &target) { // TODO: This is unimplemented for now as it requires analyzing // the UnicodeData file to find characters directionality. return target; } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.getDirectionality:(I)I -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_char_is_digit_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.getDirectionality:(I)I + +\*******************************************************************/ + codet character_refine_preprocesst::convert_get_directionality_int( - conversion_input &target) + conversion_inputt &target) { return convert_get_directionality_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.getNumericValue:(C)I -/// -/// TODO: For now this is only for ASCII characters +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_get_numeric_value_char + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.getNumericValue:(C)I + + TODO: For now this is only for ASCII characters + +\*******************************************************************/ + codet character_refine_preprocesst::convert_get_numeric_value_char( - conversion_input &target) + conversion_inputt &target) { return convert_digit_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.getNumericValue:(C)I -/// -/// TODO: For now this is only for ASCII characters -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_get_numeric_value_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.getNumericValue:(C)I + + TODO: For now this is only for ASCII characters + +\*******************************************************************/ + codet character_refine_preprocesst::convert_get_numeric_value_int( - conversion_input &target) + conversion_inputt &target) { return convert_digit_int(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.getType:(C)I -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_get_type_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.getType:(C)I + +\*******************************************************************/ + codet character_refine_preprocesst::convert_get_type_char( - conversion_input &target) + conversion_inputt &target) { // TODO: This is unimplemented for now as it requires analyzing // the UnicodeData file to categorize characters. return target; } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.getType:(I)I -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_get_type_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.getType:(I)I + +\*******************************************************************/ + codet character_refine_preprocesst::convert_get_type_int( - conversion_input &target) + conversion_inputt &target) { return convert_get_type_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.hashCode:()I -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_hash_code(conversion_input &target) +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_hash_code + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.hashCode:()I + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_hash_code(conversion_inputt &target) { return convert_char_value(target); } -/// Returns the leading surrogate (a high surrogate code unit) of the surrogate -/// pair representing the specified supplementary character (Unicode code point) -/// in the UTF-16 encoding. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_high_surrogate + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Returns the leading surrogate (a high surrogate code unit) + of the surrogate pair representing the specified + supplementary character (Unicode code point) in the UTF-16 + encoding. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_high_surrogate( const exprt &chr, const typet &type) { @@ -310,43 +492,84 @@ exprt character_refine_preprocesst::expr_of_high_surrogate( return high_surrogate; } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.highSurrogate:(C)Z +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_high_surrogate + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.highSurrogate:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_high_surrogate( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_high_surrogate, target); } -/// Determines if the specified character is an ASCII lowercase character. -/// \param chr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_ascii_lower_case + + Inputs: + chr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the specified character is an ASCII lowercase + character. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_ascii_lower_case( const exprt &chr, const typet &type) { return in_interval_expr(chr, 'a', 'z'); } -/// Determines if the specified character is an ASCII uppercase character. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_ascii_upper_case + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the specified character is an ASCII uppercase + character. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_ascii_upper_case( const exprt &chr, const typet &type) { return in_interval_expr(chr, 'A', 'Z'); } -/// Determines if the specified character is a letter. -/// -/// TODO: for now this is only for ASCII characters, the -/// following unicode categories are not yet considered: -/// TITLECASE_LETTER MODIFIER_LETTER OTHER_LETTER LETTER_NUMBER -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_letter + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Determines if the specified character is a letter. + + TODO: for now this is only for ASCII characters, the + following unicode categories are not yet considered: + TITLECASE_LETTER MODIFIER_LETTER OTHER_LETTER LETTER_NUMBER + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_letter( const exprt &chr, const typet &type) { @@ -355,38 +578,68 @@ exprt character_refine_preprocesst::expr_of_is_letter( expr_of_is_ascii_lower_case(chr, type)); } -/// Determines if the specified character (Unicode code point) is alphabetic. -/// -/// TODO: for now this is only for ASCII characters, the -/// following unicode categorise are not yet considered: -/// TITLECASE_LETTER MODIFIER_LETTER OTHER_LETTER LETTER_NUMBER -/// and contributory property Other_Alphabetic as defined by the -/// Unicode Standard. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_alphabetic + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Determines if the specified character (Unicode code point) + is alphabetic. + + TODO: for now this is only for ASCII characters, the + following unicode categorise are not yet considered: + TITLECASE_LETTER MODIFIER_LETTER OTHER_LETTER LETTER_NUMBER + and contributory property Other_Alphabetic as defined by the + Unicode Standard. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_alphabetic( const exprt &chr, const typet &type) { return expr_of_is_letter(chr, type); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isAlphabetic:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_alphabetic + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isAlphabetic:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_alphabetic( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_alphabetic, target); } -/// Determines whether the specified character (Unicode code point) is in the -/// Basic Multilingual Plane (BMP). Such code points can be represented using a -/// single char. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_bmp_code_point + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines whether the specified character (Unicode code + point) is in the Basic Multilingual Plane (BMP). Such code + points can be represented using a single char. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_bmp_code_point( const exprt &chr, const typet &type) { @@ -394,20 +647,39 @@ exprt character_refine_preprocesst::expr_of_is_bmp_code_point( return is_bmp; } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isBmpCodePoint:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_bmp_code_point + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isBmpCodePoint:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_bmp_code_point( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_bmp_code_point, target); } -/// Determines if a character is defined in Unicode. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_for_is_defined + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Determines if a character is defined in Unicode. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_defined( const exprt &chr, const typet &type) { @@ -439,39 +711,67 @@ exprt character_refine_preprocesst::expr_of_is_defined( return not_exprt(disjunction(intervals)); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isDefined:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_defined_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isDefined:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_defined_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_defined, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isDefined:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_char_is_digit_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isDefined:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_defined_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_defined_char(target); } -/// Determines if the specified character is a digit. A character is a digit if -/// its general category type, provided by Character.getType(ch), is -/// DECIMAL_DIGIT_NUMBER. -/// -/// TODO: for now we only support these ranges of digits: -/// '\u0030' through '\u0039', ISO-LATIN-1 digits ('0' through '9') -/// '\u0660' through '\u0669', Arabic-Indic digits -/// '\u06F0' through '\u06F9', Extended Arabic-Indic digits -/// '\u0966' through '\u096F', Devanagari digits -/// '\uFF10' through '\uFF19', Fullwidth digits -/// Many other character ranges contain digits as well. -/// \param chr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_digit + + Inputs: + chr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Determines if the specified character is a digit. + A character is a digit if its general category type, + provided by Character.getType(ch), is DECIMAL_DIGIT_NUMBER. + + TODO: for now we only support these ranges of digits: + '\u0030' through '\u0039', ISO-LATIN-1 digits ('0' through '9') + '\u0660' through '\u0669', Arabic-Indic digits + '\u06F0' through '\u06F9', Extended Arabic-Indic digits + '\u0966' through '\u096F', Devanagari digits + '\uFF10' through '\uFF19', Fullwidth digits + Many other character ranges contain digits as well. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_digit( const exprt &chr, const typet &type) { @@ -486,54 +786,104 @@ exprt character_refine_preprocesst::expr_of_is_digit( return digit; } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isDigit:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_digit_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isDigit:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_digit_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_digit, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.digit:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_digit_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.digit:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_digit_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_digit_char(target); } -/// Determines if the given char value is a Unicode high-surrogate code unit -/// (also known as leading-surrogate code unit). -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_high_surrogate + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the given char value is a Unicode + high-surrogate code unit (also known as leading-surrogate + code unit). + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_high_surrogate( const exprt &chr, const typet &type) { return in_interval_expr(chr, 0xD800, 0xDBFF); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isHighSurrogate:(C)Z -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_is_high_surrogate( - conversion_input &target) -{ +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_high_surrogate + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isHighSurrogate:(C)Z + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_is_high_surrogate( + conversion_inputt &target) +{ return convert_char_function( &character_refine_preprocesst::expr_of_is_high_surrogate, target); } -/// Determines if the character is one of ignorable in a Java identifier, that -/// is, it is in one of these ranges: '\u0000' through '\u0008' '\u000E' through -/// '\u001B' '\u007F' through '\u009F' -/// -/// TODO: For now, we ignore the FORMAT general category value -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_identifier_ignorable + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the character is one of ignorable in a Java + identifier, that is, it is in one of these ranges: + '\u0000' through '\u0008' + '\u000E' through '\u001B' + '\u007F' through '\u009F' + + TODO: For now, we ignore the FORMAT general category value + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_identifier_ignorable( const exprt &chr, const typet &type) { @@ -545,34 +895,63 @@ exprt character_refine_preprocesst::expr_of_is_identifier_ignorable( return ignorable; } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isIdentifierIgnorable:(C)Z -/// -/// TODO: For now, we ignore the FORMAT general category value -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_identifier_ignorable_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method + Character.isIdentifierIgnorable:(C)Z + + TODO: For now, we ignore the FORMAT general category value + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_identifier_ignorable_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_identifier_ignorable, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isIdentifierIgnorable:(I)Z -/// -/// TODO: For now, we ignore the FORMAT general category value -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_identifier_ignorable_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method + Character.isIdentifierIgnorable:(I)Z + + TODO: For now, we ignore the FORMAT general category value + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_identifier_ignorable_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_identifier_ignorable_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isIdeographic:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_ideographic + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isIdeographic:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_ideographic( - conversion_input &target) + conversion_inputt &target) { const code_function_callt &function_call=target; assert(function_call.arguments().size()==1); @@ -582,11 +961,20 @@ codet character_refine_preprocesst::convert_is_ideographic( return code_assignt(result, is_ideograph); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isISOControl:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_ISO_control_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isISOControl:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_ISO_control_char( - conversion_input &target) + conversion_inputt &target) { const code_function_callt &function_call=target; assert(function_call.arguments().size()==1); @@ -597,154 +985,290 @@ codet character_refine_preprocesst::convert_is_ISO_control_char( return code_assignt(result, iso); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isISOControl:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_ISO_control_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isISOControl:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_ISO_control_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_ISO_control_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isJavaIdentifierPart:(C)Z -/// -/// TODO: For now we do not allow currency symbol, connecting punctuation, -/// combining mark, non-spacing mark -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_java_identifier_part_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isJavaIdentifierPart:(C)Z + + TODO: For now we do not allow currency symbol, connecting punctuation, + combining mark, non-spacing mark + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_java_identifier_part_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_unicode_identifier_part, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method isJavaIdentifierPart:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_java_identifier_part_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method isJavaIdentifierPart:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_java_identifier_part_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_unicode_identifier_part_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method isJavaIdentifierStart:(C)Z -/// -/// TODO: For now we only allow letters and letter numbers. -/// The java specification for this function is not precise on the -/// other characters. -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_java_identifier_start_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method isJavaIdentifierStart:(C)Z + + TODO: For now we only allow letters and letter numbers. + The java specification for this function is not precise on the + other characters. + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_java_identifier_start_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( - &character_refine_preprocesst::expr_of_is_unicode_identifier_start, target); + &character_refine_preprocesst::expr_of_is_unicode_identifier_part, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method isJavaIdentifierStart:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_char_is_digit_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method isJavaIdentifierStart:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_java_identifier_start_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_java_identifier_start_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isJavaLetter:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_java_letter + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isJavaLetter:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_java_letter( - conversion_input &target) + conversion_inputt &target) { return convert_is_java_identifier_start_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method isJavaLetterOrDigit:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_java_letter_or_digit + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method isJavaLetterOrDigit:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_java_letter_or_digit( - conversion_input &target) + conversion_inputt &target) { return convert_is_java_identifier_part_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isLetter:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_letter_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isLetter:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_letter_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_letter, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isLetter:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_letter_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isLetter:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_letter_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_letter_char(target); } -/// Determines if the specified character is a letter or digit. -/// \param chr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_letter_or_digit + + Inputs: + chr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Determines if the specified character is a letter or digit. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_letter_or_digit( const exprt &chr, const typet &type) { return or_exprt(expr_of_is_letter(chr, type), expr_of_is_digit(chr, type)); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isLetterOrDigit:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_letter_or_digit_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isLetterOrDigit:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_letter_or_digit_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_digit, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isLetterOrDigit:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_letter_or_digit_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isLetterOrDigit:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_letter_or_digit_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_letter_or_digit_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isLowerCase:(C)Z -/// -/// TODO: For now we only consider ASCII characters -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_lower_case_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isLowerCase:(C)Z + + TODO: For now we only consider ASCII characters + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_lower_case_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_ascii_lower_case, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isLowerCase:(I)Z -/// -/// TODO: For now we only consider ASCII characters -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_lower_case_int() + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isLowerCase:(I)Z + + TODO: For now we only consider ASCII characters + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_lower_case_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_lower_case_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isLowSurrogate:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_low_surrogate + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isLowSurrogate:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_low_surrogate( - conversion_input &target) + conversion_inputt &target) { const code_function_callt &function_call=target; assert(function_call.arguments().size()==1); @@ -754,55 +1278,103 @@ codet character_refine_preprocesst::convert_is_low_surrogate( return code_assignt(result, is_low_surrogate); } -/// Determines whether the character is mirrored according to the Unicode -/// specification. -/// -/// TODO: For now only ASCII characters are considered -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_mirrored + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Determines whether the character is mirrored according to + the Unicode specification. + + TODO: For now only ASCII characters are considered + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_mirrored( const exprt &chr, const typet &type) { return in_list_expr(chr, {0x28, 0x29, 0x3C, 0x3E, 0x5B, 0x5D, 0x7B, 0x7D}); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isMirrored:(C)Z -/// -/// TODO: For now only ASCII characters are considered -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_mirrored_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isMirrored:(C)Z + + TODO: For now only ASCII characters are considered + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_mirrored_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_mirrored, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isMirrored:(I)Z -/// -/// TODO: For now only ASCII characters are considered -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_mirrored_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isMirrored:(I)Z + + TODO: For now only ASCII characters are considered + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_mirrored_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_mirrored_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isSpace:(C)Z -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_is_space(conversion_input &target) +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_space + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isSpace:(C)Z + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_is_space(conversion_inputt &target) { return convert_is_whitespace_char(target); } -/// Determines if the specified character is white space according to Unicode -/// (SPACE_SEPARATOR, LINE_SEPARATOR, or PARAGRAPH_SEPARATOR) -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_space_char + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the specified character is white space + according to Unicode (SPACE_SEPARATOR, LINE_SEPARATOR, or + PARAGRAPH_SEPARATOR) + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_space_char( const exprt &chr, const typet &type) { @@ -813,71 +1385,138 @@ exprt character_refine_preprocesst::expr_of_is_space_char( return or_exprt(condition0, condition1); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isSpaceChar:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_space_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isSpaceChar:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_space_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_space_char, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isSpaceChar:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_space_char_int() + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isSpaceChar:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_space_char_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_space_char(target); } -/// Determines whether the specified character (Unicode code point) is in the -/// supplementary character range. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_supplementary_code_point + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines whether the specified character (Unicode code + point) is in the supplementary character range. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_supplementary_code_point( const exprt &chr, const typet &type) { return binary_relation_exprt(chr, ID_gt, from_integer(0xFFFF, chr.type())); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isSupplementaryCodePoint:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_supplementary_code_point + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method + Character.isSupplementaryCodePoint:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_supplementary_code_point( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_supplementary_code_point, target); } -/// Determines if the given char value is a Unicode surrogate code unit. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_surrogate + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the given char value is a Unicode surrogate + code unit. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_surrogate( const exprt &chr, const typet &type) { return in_interval_expr(chr, 0xD800, 0xDFFF); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isSurrogate:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_surrogate + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isSurrogate:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_surrogate( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_surrogate, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isSurrogatePair:(CC)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_surrogate_pair + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isSurrogatePair:(CC)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_surrogate_pair( - conversion_input &target) + conversion_inputt &target) { const code_function_callt &function_call=target; assert(function_call.arguments().size()==2); @@ -889,10 +1528,20 @@ codet character_refine_preprocesst::convert_is_surrogate_pair( return code_assignt(result, and_exprt(is_high_surrogate, is_low_surrogate)); } -/// Determines if the specified character is a titlecase character. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_title_case + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the specified character is a titlecase character. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_title_case( const exprt &chr, const typet &type) { @@ -906,30 +1555,58 @@ exprt character_refine_preprocesst::expr_of_is_title_case( return disjunction(conditions); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isTitleCase:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_title_case_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isTitleCase:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_title_case_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_title_case, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isTitleCase:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_title_case_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isTitleCase:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_title_case_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_title_case_char(target); } -/// Determines if the specified character is in the LETTER_NUMBER category of -/// Unicode -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_letter_number + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the specified character is in the LETTER_NUMBER + category of Unicode + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_letter_number( const exprt &chr, const typet &type) { @@ -950,13 +1627,23 @@ exprt character_refine_preprocesst::expr_of_is_letter_number( } -/// Determines if the character may be part of a Unicode identifier. -/// -/// TODO: For now we do not allow connecting punctuation, combining mark, -/// non-spacing mark -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_unicode_identifier_part + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the character may be part of a Unicode identifier. + + TODO: For now we do not allow connecting punctuation, combining mark, + non-spacing mark + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_unicode_identifier_part( const exprt &chr, const typet &type) { @@ -967,30 +1654,60 @@ exprt character_refine_preprocesst::expr_of_is_unicode_identifier_part( return disjunction(conditions); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isUnicodeIdentifierPart:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_unicode_identifier_part_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method + Character.isUnicodeIdentifierPart:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_unicode_identifier_part_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_unicode_identifier_part, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isUnicodeIdentifierPart:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_unicode_identifier_part_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method + Character.isUnicodeIdentifierPart:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_unicode_identifier_part_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_unicode_identifier_part_char(target); } -/// Determines if the specified character is permissible as the first character -/// in a Unicode identifier. -/// \param chr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_unicode_identifier_start + + Inputs: + chr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the specified character is permissible as the + first character in a Unicode identifier. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_unicode_identifier_start( const exprt &chr, const typet &type) { @@ -998,75 +1715,145 @@ exprt character_refine_preprocesst::expr_of_is_unicode_identifier_start( expr_of_is_letter(chr, type), expr_of_is_letter_number(chr, type)); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isUnicodeIdentifierStart:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_unicode_identifier_start_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method + Character.isUnicodeIdentifierStart:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_unicode_identifier_start_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_unicode_identifier_start, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isUnicodeIdentifierStart:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_unicode_identifier_start_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method + Character.isUnicodeIdentifierStart:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_unicode_identifier_start_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_unicode_identifier_start_char(target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isUpperCase:(C)Z -/// -/// TODO: For now we only consider ASCII characters -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_upper_case_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isUpperCase:(C)Z + + TODO: For now we only consider ASCII characters + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_upper_case_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_ascii_upper_case, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isUpperCase:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_upper_case_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isUpperCase:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_upper_case_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_upper_case_char(target); } -/// Determines whether the specified code point is a valid Unicode code point -/// value. That is, in the range of integers from 0 to 0x10FFFF -/// \param chr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_valid_code_point + + Inputs: + chr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines whether the specified code point is a valid + Unicode code point value. + That is, in the range of integers from 0 to 0x10FFFF + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_valid_code_point( const exprt &chr, const typet &type) { return binary_relation_exprt(chr, ID_le, from_integer(0x10FFFF, chr.type())); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isValidCodePoint:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_valid_code_point + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isValidCodePoint:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_valid_code_point( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_valid_code_point, target); } -/// Determines if the specified character is white space according to Java. It -/// is the case when it one of the following: * a Unicode space character -/// (SPACE_SEPARATOR, LINE_SEPARATOR, or PARAGRAPH_SEPARATOR) but is not also a -/// non-breaking space ('\u00A0', '\u2007', '\u202F'). * it is one of these: -/// U+0009 U+000A U+000B U+000C U+000D U+001C U+001D U+001E U+001F -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A Boolean expression +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_is_whitespace + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A Boolean expression + + Purpose: Determines if the specified character is white space according + to Java. It is the case when it one of the following: + * a Unicode space character (SPACE_SEPARATOR, LINE_SEPARATOR, or + PARAGRAPH_SEPARATOR) but is not also a non-breaking space + ('\u00A0', '\u2007', '\u202F'). + * it is one of these: U+0009 U+000A U+000B U+000C U+000D + U+001C U+001D U+001E U+001F + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_is_whitespace( const exprt &chr, const typet &type) { @@ -1081,31 +1868,60 @@ exprt character_refine_preprocesst::expr_of_is_whitespace( return disjunction(conditions); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isWhitespace:(C)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_whitespace_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isWhitespace:(C)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_whitespace_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_is_whitespace, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.isWhitespace:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_is_whitespace_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.isWhitespace:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_is_whitespace_int( - conversion_input &target) + conversion_inputt &target) { return convert_is_whitespace_char(target); } -/// Returns the trailing surrogate (a low surrogate code unit) of the surrogate -/// pair representing the specified supplementary character (Unicode code point) -/// in the UTF-16 encoding. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A integer expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_low_surrogate + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A integer expression of the given type + + Purpose: Returns the trailing surrogate (a low surrogate code unit) + of the surrogate pair representing the specified + supplementary character (Unicode code point) in the UTF-16 + encoding. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_low_surrogate( const exprt &chr, const typet &type) { @@ -1114,21 +1930,40 @@ exprt character_refine_preprocesst::expr_of_low_surrogate( return plus_exprt(uDC00, mod_exprt(chr, u0400)); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.lowSurrogate:(I)Z -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_low_surrogate + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.lowSurrogate:(I)Z + +\*******************************************************************/ + codet character_refine_preprocesst::convert_low_surrogate( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_low_surrogate, target); } -/// Returns the value obtained by reversing the order of the bytes in the -/// specified char value. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A character expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_reverse_bytes + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A character expression of the given type + + Purpose: Returns the value obtained by reversing the order of the + bytes in the specified char value. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_reverse_bytes( const exprt &chr, const typet &type) { @@ -1137,24 +1972,45 @@ exprt character_refine_preprocesst::expr_of_reverse_bytes( return plus_exprt(first_byte, second_byte); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.reverseBytes:(C)C -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_reverse_bytes + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.reverseBytes:(C)C + +\*******************************************************************/ + codet character_refine_preprocesst::convert_reverse_bytes( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_reverse_bytes, target); } -/// Converts the specified character (Unicode code point) to its UTF-16 -/// representation stored in a char array. If the specified code point is a BMP -/// (Basic Multilingual Plane or Plane 0) value, the resulting char array has -/// the same value as codePoint. If the specified code point is a supplementary -/// code point, the resulting char array has the corresponding surrogate pair. -/// \param expr: An expression of type character -/// \param type: A type for the output -/// \return A character array expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_to_chars + + Inputs: + expr - An expression of type character + type - A type for the output + + Outputs: A character array expression of the given type + + Purpose: Converts the specified character (Unicode code point) to + its UTF-16 representation stored in a char array. + If the specified code point is a BMP (Basic Multilingual + Plane or Plane 0) value, the resulting char array has the + same value as codePoint. + If the specified code point is a supplementary code point, + the resulting char array has the corresponding surrogate pair. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_to_chars( const exprt &chr, const typet &type) { @@ -1170,20 +2026,38 @@ exprt character_refine_preprocesst::expr_of_to_chars( return if_exprt(expr_of_is_bmp_code_point(chr, type), case1, case2); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.toChars:(I)[C -/// \param target: a position in a goto program -codet character_refine_preprocesst::convert_to_chars(conversion_input &target) +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_to_chars + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.toChars:(I)[C + +\*******************************************************************/ + +codet character_refine_preprocesst::convert_to_chars(conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_to_chars, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.toCodePoint:(CC)I -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_to_code_point + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.toCodePoint:(CC)I + +\*******************************************************************/ + codet character_refine_preprocesst::convert_to_code_point( - conversion_input &target) + conversion_inputt &target) { const code_function_callt &function_call=target; assert(function_call.arguments().size()==2); @@ -1207,14 +2081,24 @@ codet character_refine_preprocesst::convert_to_code_point( return code_assignt(result, pair_value); } -/// Converts the character argument to lowercase. -/// -/// TODO: For now we only consider ASCII characters but ultimately -/// we should use case mapping information from the -/// UnicodeData file -/// \param chr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_to_lower_case + + Inputs: + chr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Converts the character argument to lowercase. + + TODO: For now we only consider ASCII characters but ultimately + we should use case mapping information from the + UnicodeData file + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_to_lower_case( const exprt &chr, const typet &type) { @@ -1225,29 +2109,57 @@ exprt character_refine_preprocesst::expr_of_to_lower_case( return res; } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.toLowerCase:(C)C -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_to_lower_case_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.toLowerCase:(C)C + +\*******************************************************************/ + codet character_refine_preprocesst::convert_to_lower_case_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_to_lower_case, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.toLowerCase:(I)I -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_to_lower_case_int() + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.toLowerCase:(I)I + +\*******************************************************************/ + codet character_refine_preprocesst::convert_to_lower_case_int( - conversion_input &target) + conversion_inputt &target) { return convert_to_lower_case_char(target); } -/// Converts the character argument to titlecase. -/// \param chr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_to_title_case + + Inputs: + chr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Converts the character argument to titlecase. + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_to_title_case( const exprt &chr, const typet &type) { @@ -1281,33 +2193,61 @@ exprt character_refine_preprocesst::expr_of_to_title_case( return res; } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.toTitleCase:(C)C -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_to_title_case_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.toTitleCase:(C)C + +\*******************************************************************/ + codet character_refine_preprocesst::convert_to_title_case_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_to_title_case, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.toTitleCase:(I)I -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_to_title_case_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.toTitleCase:(I)I + +\*******************************************************************/ + codet character_refine_preprocesst::convert_to_title_case_int( - conversion_input &target) + conversion_inputt &target) { return convert_to_title_case_char(target); } -/// Converts the character argument to uppercase. -/// -/// TODO: For now we only consider ASCII characters but ultimately -/// we should use case mapping information from the -/// UnicodeData file -/// \param chr: An expression of type character -/// \param type: A type for the output -/// \return An expression of the given type +/*******************************************************************\ + +Function: character_refine_preprocesst::expr_of_to_upper_case + + Inputs: + chr - An expression of type character + type - A type for the output + + Outputs: An expression of the given type + + Purpose: Converts the character argument to uppercase. + + TODO: For now we only consider ASCII characters but ultimately + we should use case mapping information from the + UnicodeData file + +\*******************************************************************/ + exprt character_refine_preprocesst::expr_of_to_upper_case( const exprt &chr, const typet &type) { @@ -1318,31 +2258,60 @@ exprt character_refine_preprocesst::expr_of_to_upper_case( return res; } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.toUpperCase:(C)C -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_to_upper_case_char + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.toUpperCase:(C)C + +\*******************************************************************/ + codet character_refine_preprocesst::convert_to_upper_case_char( - conversion_input &target) + conversion_inputt &target) { return convert_char_function( &character_refine_preprocesst::expr_of_to_upper_case, target); } -/// Converts function call to an assignment of an expression corresponding to -/// the java method Character.toUpperCase:(I)I -/// \param target: a position in a goto program +/*******************************************************************\ + +Function: character_refine_preprocesst::convert_to_upper_case_int + + Inputs: + target - a position in a goto program + + Purpose: Converts function call to an assignment of an expression + corresponding to the java method Character.toUpperCase:(I)I + +\*******************************************************************/ + codet character_refine_preprocesst::convert_to_upper_case_int( - conversion_input &target) + conversion_inputt &target) { return convert_to_upper_case_char(target); } -/// replace function calls to functions of the Character by an affectation if -/// possible, returns the same code otherwise. For this method to have an effect -/// initialize_conversion_table must have been called before. -/// \param code: the code of a function call -/// \return code where character function call get replaced by an simple -/// instruction +/*******************************************************************\ + +Function: character_refine_preprocesst::replace_character_call + + Inputs: + code - the code of a function call + + Outputs: code where character function call get replaced by + an simple instruction + + Purpose: replace function calls to functions of the Character by + an affectation if possible, returns the same code otherwise. + For this method to have an effect initialize_conversion_table + must have been called before. + +\*******************************************************************/ + codet character_refine_preprocesst::replace_character_call( const code_function_callt &code) const { @@ -1358,7 +2327,15 @@ codet character_refine_preprocesst::replace_character_call( return code; } -/// fill maps with correspondance from java method names to conversion functions +/*******************************************************************\ + +Function: character_refine_preprocesst::initialize_conversion_table + + Purpose: fill maps with correspondance from java method names to + conversion functions + +\*******************************************************************/ + void character_refine_preprocesst::initialize_conversion_table() { // All methods are listed here in alphabetic order diff --git a/src/java_bytecode/character_refine_preprocess.h b/src/java_bytecode/character_refine_preprocess.h index afef65eb8dc..2f41b2ec932 100644 --- a/src/java_bytecode/character_refine_preprocess.h +++ b/src/java_bytecode/character_refine_preprocess.h @@ -30,122 +30,123 @@ class character_refine_preprocesst:public messaget codet replace_character_call(const code_function_callt &call) const; private: - typedef const code_function_callt &conversion_input; - typedef codet (*conversion_functiont)(conversion_input &target); + typedef const code_function_callt &conversion_inputt; + typedef codet (*conversion_functiont)(conversion_inputt &target); // A table tells us what method to call for each java method signature std::unordered_map conversion_table; // Conversion functions static exprt expr_of_char_count(const exprt &chr, const typet &type); - static codet convert_char_count(conversion_input &target); + static codet convert_char_count(conversion_inputt &target); static exprt expr_of_char_value(const exprt &chr, const typet &type); - static codet convert_char_value(conversion_input &target); - static codet convert_compare(conversion_input &target); - static codet convert_digit_char(conversion_input &target); - static codet convert_digit_int(conversion_input &target); - static codet convert_for_digit(conversion_input &target); - static codet convert_get_directionality_char(conversion_input &target); - static codet convert_get_directionality_int(conversion_input &target); - static codet convert_get_numeric_value_char(conversion_input &target); - static codet convert_get_numeric_value_int(conversion_input &target); - static codet convert_get_type_char(conversion_input &target); - static codet convert_get_type_int(conversion_input &target); - static codet convert_hash_code(conversion_input &target); + static codet convert_char_value(conversion_inputt &target); + static codet convert_compare(conversion_inputt &target); + static codet convert_digit_char(conversion_inputt &target); + static codet convert_digit_int(conversion_inputt &target); + static codet convert_for_digit(conversion_inputt &target); + static codet convert_get_directionality_char(conversion_inputt &target); + static codet convert_get_directionality_int(conversion_inputt &target); + static codet convert_get_numeric_value_char(conversion_inputt &target); + static codet convert_get_numeric_value_int(conversion_inputt &target); + static codet convert_get_type_char(conversion_inputt &target); + static codet convert_get_type_int(conversion_inputt &target); + static codet convert_hash_code(conversion_inputt &target); static exprt expr_of_high_surrogate(const exprt &chr, const typet &type); - static codet convert_high_surrogate(conversion_input &target); + static codet convert_high_surrogate(conversion_inputt &target); static exprt expr_of_is_alphabetic(const exprt &chr, const typet &type); - static codet convert_is_alphabetic(conversion_input &target); + static codet convert_is_alphabetic(conversion_inputt &target); static exprt expr_of_is_bmp_code_point(const exprt &chr, const typet &type); - static codet convert_is_bmp_code_point(conversion_input &target); + static codet convert_is_bmp_code_point(conversion_inputt &target); static exprt expr_of_is_defined(const exprt &chr, const typet &type); - static codet convert_is_defined_char(conversion_input &target); - static codet convert_is_defined_int(conversion_input &target); + static codet convert_is_defined_char(conversion_inputt &target); + static codet convert_is_defined_int(conversion_inputt &target); static exprt expr_of_is_digit(const exprt &chr, const typet &type); - static codet convert_is_digit_char(conversion_input &target); - static codet convert_is_digit_int(conversion_input &target); + static codet convert_is_digit_char(conversion_inputt &target); + static codet convert_is_digit_int(conversion_inputt &target); static exprt expr_of_is_high_surrogate(const exprt &chr, const typet &type); - static codet convert_is_high_surrogate(conversion_input &target); + static codet convert_is_high_surrogate(conversion_inputt &target); static exprt expr_of_is_identifier_ignorable( const exprt &chr, const typet &type); - static codet convert_is_identifier_ignorable_char(conversion_input &target); - static codet convert_is_identifier_ignorable_int(conversion_input &target); - static codet convert_is_ideographic(conversion_input &target); - static codet convert_is_ISO_control_char(conversion_input &target); - static codet convert_is_ISO_control_int(conversion_input &target); - static codet convert_is_java_identifier_part_char(conversion_input &target); - static codet convert_is_java_identifier_part_int(conversion_input &target); - static codet convert_is_java_identifier_start_char(conversion_input &target); - static codet convert_is_java_identifier_start_int(conversion_input &target); - static codet convert_is_java_letter(conversion_input &target); - static codet convert_is_java_letter_or_digit(conversion_input &target); + static codet convert_is_identifier_ignorable_char(conversion_inputt &target); + static codet convert_is_identifier_ignorable_int(conversion_inputt &target); + static codet convert_is_ideographic(conversion_inputt &target); + static codet convert_is_ISO_control_char(conversion_inputt &target); + static codet convert_is_ISO_control_int(conversion_inputt &target); + static codet convert_is_java_identifier_part_char(conversion_inputt &target); + static codet convert_is_java_identifier_part_int(conversion_inputt &target); + static codet convert_is_java_identifier_start_char(conversion_inputt &target); + static codet convert_is_java_identifier_start_int(conversion_inputt &target); + static codet convert_is_java_letter(conversion_inputt &target); + static codet convert_is_java_letter_or_digit(conversion_inputt &target); static exprt expr_of_is_letter(const exprt &chr, const typet &type); - static codet convert_is_letter_char(conversion_input &target); - static codet convert_is_letter_int(conversion_input &target); + static codet convert_is_letter_char(conversion_inputt &target); + static codet convert_is_letter_int(conversion_inputt &target); static exprt expr_of_is_letter_or_digit(const exprt &chr, const typet &type); - static codet convert_is_letter_or_digit_char(conversion_input &target); - static codet convert_is_letter_or_digit_int(conversion_input &target); + static codet convert_is_letter_or_digit_char(conversion_inputt &target); + static codet convert_is_letter_or_digit_int(conversion_inputt &target); static exprt expr_of_is_ascii_lower_case(const exprt &chr, const typet &type); - static codet convert_is_lower_case_char(conversion_input &target); - static codet convert_is_lower_case_int(conversion_input &target); - static codet convert_is_low_surrogate(conversion_input &target); + static codet convert_is_lower_case_char(conversion_inputt &target); + static codet convert_is_lower_case_int(conversion_inputt &target); + static codet convert_is_low_surrogate(conversion_inputt &target); static exprt expr_of_is_mirrored(const exprt &chr, const typet &type); - static codet convert_is_mirrored_char(conversion_input &target); - static codet convert_is_mirrored_int(conversion_input &target); - static codet convert_is_space(conversion_input &target); + static codet convert_is_mirrored_char(conversion_inputt &target); + static codet convert_is_mirrored_int(conversion_inputt &target); + static codet convert_is_space(conversion_inputt &target); static exprt expr_of_is_space_char(const exprt &chr, const typet &type); - static codet convert_is_space_char(conversion_input &target); - static codet convert_is_space_char_int(conversion_input &target); + static codet convert_is_space_char(conversion_inputt &target); + static codet convert_is_space_char_int(conversion_inputt &target); static exprt expr_of_is_supplementary_code_point( const exprt &chr, const typet &type); - static codet convert_is_supplementary_code_point(conversion_input &target); + static codet convert_is_supplementary_code_point(conversion_inputt &target); static exprt expr_of_is_surrogate(const exprt &chr, const typet &type); - static codet convert_is_surrogate(conversion_input &target); - static codet convert_is_surrogate_pair(conversion_input &target); + static codet convert_is_surrogate(conversion_inputt &target); + static codet convert_is_surrogate_pair(conversion_inputt &target); static exprt expr_of_is_title_case(const exprt &chr, const typet &type); - static codet convert_is_title_case_char(conversion_input &target); - static codet convert_is_title_case_int(conversion_input &target); + static codet convert_is_title_case_char(conversion_inputt &target); + static codet convert_is_title_case_int(conversion_inputt &target); static exprt expr_of_is_letter_number(const exprt &chr, const typet &type); static exprt expr_of_is_unicode_identifier_part( const exprt &chr, const typet &type); static codet convert_is_unicode_identifier_part_char( - conversion_input &target); - static codet convert_is_unicode_identifier_part_int(conversion_input &target); + conversion_inputt &target); + static codet convert_is_unicode_identifier_part_int( + conversion_inputt &target); static exprt expr_of_is_unicode_identifier_start( const exprt &chr, const typet &type); static codet convert_is_unicode_identifier_start_char( - conversion_input &target); + conversion_inputt &target); static codet convert_is_unicode_identifier_start_int( - conversion_input &target); + conversion_inputt &target); static exprt expr_of_is_ascii_upper_case(const exprt &chr, const typet &type); - static codet convert_is_upper_case_char(conversion_input &target); - static codet convert_is_upper_case_int(conversion_input &target); + static codet convert_is_upper_case_char(conversion_inputt &target); + static codet convert_is_upper_case_int(conversion_inputt &target); static exprt expr_of_is_valid_code_point(const exprt &chr, const typet &type); - static codet convert_is_valid_code_point(conversion_input &target); + static codet convert_is_valid_code_point(conversion_inputt &target); static exprt expr_of_is_whitespace(const exprt &chr, const typet &type); - static codet convert_is_whitespace_char(conversion_input &target); - static codet convert_is_whitespace_int(conversion_input &target); + static codet convert_is_whitespace_char(conversion_inputt &target); + static codet convert_is_whitespace_int(conversion_inputt &target); static exprt expr_of_low_surrogate(const exprt &chr, const typet &type); - static codet convert_low_surrogate(conversion_input &target); + static codet convert_low_surrogate(conversion_inputt &target); static exprt expr_of_reverse_bytes(const exprt &chr, const typet &type); - static codet convert_reverse_bytes(conversion_input &target); + static codet convert_reverse_bytes(conversion_inputt &target); static exprt expr_of_to_chars(const exprt &chr, const typet &type); - static codet convert_to_chars(conversion_input &target); - static codet convert_to_code_point(conversion_input &target); + static codet convert_to_chars(conversion_inputt &target); + static codet convert_to_code_point(conversion_inputt &target); static exprt expr_of_to_lower_case(const exprt &chr, const typet &type); - static codet convert_to_lower_case_char(conversion_input &target); - static codet convert_to_lower_case_int(conversion_input &target); + static codet convert_to_lower_case_char(conversion_inputt &target); + static codet convert_to_lower_case_int(conversion_inputt &target); static exprt expr_of_to_title_case(const exprt &chr, const typet &type); - static codet convert_to_title_case_char(conversion_input &target); - static codet convert_to_title_case_int(conversion_input &target); + static codet convert_to_title_case_char(conversion_inputt &target); + static codet convert_to_title_case_int(conversion_inputt &target); static exprt expr_of_to_upper_case(const exprt &chr, const typet &type); - static codet convert_to_upper_case_char(conversion_input &target); - static codet convert_to_upper_case_int(conversion_input &target); + static codet convert_to_upper_case_char(conversion_inputt &target); + static codet convert_to_upper_case_int(conversion_inputt &target); // Helper functions static codet convert_char_function( exprt (*expr_function)(const exprt &chr, const typet &type), - conversion_input &target); + conversion_inputt &target); static exprt in_interval_expr( const exprt &chr, const mp_integer &lower_bound, diff --git a/src/java_bytecode/java_bytecode_convert_class.cpp b/src/java_bytecode/java_bytecode_convert_class.cpp index 05b4e44e47b..34f7082ea25 100644 --- a/src/java_bytecode/java_bytecode_convert_class.cpp +++ b/src/java_bytecode/java_bytecode_convert_class.cpp @@ -53,7 +53,16 @@ class java_bytecode_convert_classt:public messaget convert(parse_tree.parsed_class); else if(string_refinement_enabled && parse_tree.parsed_class.name=="java.lang.String") - add_string_type(); + add_string_type("java.lang.String"); + else if(string_refinement_enabled && + parse_tree.parsed_class.name=="java.lang.StringBuilder") + add_string_type("java.lang.StringBuilder"); + else if(string_refinement_enabled && + parse_tree.parsed_class.name=="java.lang.CharSequence") + add_string_type("java.lang.CharSequence"); + else if(string_refinement_enabled && + parse_tree.parsed_class.name=="java.lang.StringBuffer") + add_string_type("java.lang.StringBuffer"); else generate_class_stub(parse_tree.parsed_class.name); } @@ -75,7 +84,7 @@ class java_bytecode_convert_classt:public messaget void generate_class_stub(const irep_idt &class_name); void add_array_types(); - void add_string_type(); + void add_string_type(const irep_idt &class_name); }; void java_bytecode_convert_classt::convert(const classt &c) @@ -349,10 +358,11 @@ bool java_bytecode_convert_class( /// Implements the java.lang.String type in the case that we provide an internal /// implementation. -void java_bytecode_convert_classt::add_string_type() +/// \param class_name: a name for the class such as "java.lang.String" +void java_bytecode_convert_classt::add_string_type(const irep_idt &class_name) { class_typet string_type; - string_type.set_tag("java.lang.String"); + string_type.set_tag(class_name); string_type.components().resize(3); string_type.components()[0].set_name("@java.lang.Object"); string_type.components()[0].set_pretty_name("@java.lang.Object"); @@ -370,8 +380,8 @@ void java_bytecode_convert_classt::add_string_type() string_type.add_base(symbol_typet("java::java.lang.Object")); symbolt string_symbol; - string_symbol.name="java::java.lang.String"; - string_symbol.base_name="java.lang.String"; + string_symbol.name="java::"+id2string(class_name); + string_symbol.base_name=id2string(class_name); string_symbol.type=string_type; string_symbol.is_type=true; @@ -383,8 +393,8 @@ void java_bytecode_convert_classt::add_string_type() symbolt string_equals_symbol; string_equals_symbol.name= "java::java.lang.String.equals:(Ljava/lang/Object;)Z"; - string_equals_symbol.base_name="java.lang.String.equals"; - string_equals_symbol.pretty_name="java.lang.String.equals"; + string_equals_symbol.base_name=id2string(class_name)+".equals"; + string_equals_symbol.pretty_name=id2string(class_name)+".equals"; string_equals_symbol.mode=ID_java; code_typet string_equals_type; diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index b0b296c9cfd..6da2bad7129 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -1070,6 +1070,25 @@ codet java_bytecode_convert_methodt::convert_instructions( get_message_handler()); } } + // replace calls to CProver.assume + else if(statement=="invokestatic" && + id2string(arg0.get(ID_identifier))== + "java::org.cprover.CProver.assume:(Z)V") + { + const code_typet &code_type=to_code_type(arg0.type()); + // sanity check: function has the right number of args + assert(code_type.parameters().size()==1); + + exprt operand = pop(1)[0]; + // we may need to adjust the type of the argument + if(operand.type()!=bool_typet()) + operand.make_typecast(bool_typet()); + + c=code_assumet(operand); + source_locationt loc=i_it->source_location; + loc.set_function(method_id); + c.add_source_location()=loc; + } else if(statement=="invokeinterface" || statement=="invokespecial" || statement=="invokevirtual" || diff --git a/src/java_bytecode/java_bytecode_language.cpp b/src/java_bytecode/java_bytecode_language.cpp index 85205c7525d..b7b97f32b14 100644 --- a/src/java_bytecode/java_bytecode_language.cpp +++ b/src/java_bytecode/java_bytecode_language.cpp @@ -35,7 +35,7 @@ Author: Daniel Kroening, kroening@kroening.com void java_bytecode_languaget::get_language_options(const cmdlinet &cmd) { assume_inputs_non_null=cmd.isset("java-assume-inputs-non-null"); - string_refinement_enabled=cmd.isset("string-refine"); + string_refinement_enabled=cmd.isset("refine-strings"); if(cmd.isset("java-max-input-array-length")) max_nondet_array_length= std::stoi(cmd.get_value("java-max-input-array-length")); diff --git a/src/java_bytecode/java_entry_point.cpp b/src/java_bytecode/java_entry_point.cpp index 3e2496d1444..e7445b11b85 100644 --- a/src/java_bytecode/java_entry_point.cpp +++ b/src/java_bytecode/java_entry_point.cpp @@ -142,11 +142,19 @@ void java_static_lifetime_init( it->second.type.id()==ID_code && it->second.mode==ID_java) { - code_function_callt function_call; - function_call.lhs()=nil_exprt(); - function_call.function()=it->second.symbol_expr(); - function_call.add_source_location()=source_location; - code_block.add(function_call); + const irep_idt symbol_name= + it->second.symbol_expr().get_identifier(); + const std::string &symbol_str=id2string(symbol_name); + const std::string suffix(".:()V"); + assert(has_suffix(symbol_str, suffix)); + const std::string class_symbol_name= + symbol_str.substr(0, symbol_str.size()-suffix.size()); + const symbolt &class_symbol=symbol_table.lookup(class_symbol_name); + clinits.push_back( + { + it->second.symbol_expr(), + class_symbol.type.get_bool(ID_enumeration) + }); } } } diff --git a/src/java_bytecode/library/src/org/cprover/CProver.java b/src/java_bytecode/library/src/org/cprover/CProver.java new file mode 100644 index 00000000000..72c3eeb1d70 --- /dev/null +++ b/src/java_bytecode/library/src/org/cprover/CProver.java @@ -0,0 +1,11 @@ +package org.cprover; + +public final class CProver +{ + public static boolean enableAssume=true; + public static void assume(boolean condition) + { + if(enableAssume) + throw new RuntimeException("Cannot execute program with CProver.assume()"); + } +} diff --git a/src/solvers/Makefile b/src/solvers/Makefile index 108718ccb75..3f3465277a3 100644 --- a/src/solvers/Makefile +++ b/src/solvers/Makefile @@ -158,6 +158,17 @@ SRC = $(BOOLEFORCE_SRC) \ refinement/bv_refinement_loop.cpp \ refinement/refine_arithmetic.cpp \ refinement/refine_arrays.cpp \ + refinement/string_refinement.cpp \ + refinement/string_constraint_generator_code_points.cpp \ + refinement/string_constraint_generator_comparison.cpp \ + refinement/string_constraint_generator_concat.cpp \ + refinement/string_constraint_generator_constants.cpp \ + refinement/string_constraint_generator_indexof.cpp \ + refinement/string_constraint_generator_insert.cpp \ + refinement/string_constraint_generator_main.cpp \ + refinement/string_constraint_generator_testing.cpp \ + refinement/string_constraint_generator_transformation.cpp \ + refinement/string_constraint_generator_valueof.cpp \ sat/cnf.cpp \ sat/cnf_clause_list.cpp \ sat/dimacs_cnf.cpp \ diff --git a/src/solvers/refinement/refined_string_type.cpp b/src/solvers/refinement/refined_string_type.cpp deleted file mode 100644 index dd91489e8fd..00000000000 --- a/src/solvers/refinement/refined_string_type.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/********************************************************************\ - -Module: Type for string expressions used by the string solver. - These string expressions contain a field `length`, of type - `index_type`, a field `content` of type `content_type`. - This module also defines functions to recognise the C and java - string types. - -Author: Romain Brenguier, romain.brenguier@diffblue.com - -\*******************************************************************/ - -/// \file -/// Type for string expressions used by the string solver. These string -/// expressions contain a field `length`, of type `index_type`, a field -/// `content` of type `content_type`. This module also defines functions to -/// recognise the C and java string types. - -#include - -#include "refined_string_type.h" - -refined_string_typet::refined_string_typet( - const typet &index_type, const typet &char_type) -{ - infinity_exprt infinite_index(index_type); - array_typet char_array(char_type, infinite_index); - components().emplace_back("length", index_type); - components().emplace_back("content", char_array); -} - -/// \par parameters: a type -/// \return Boolean telling whether the type is that of C strings -bool refined_string_typet::is_c_string_type(const typet &type) -{ - return - type.id()==ID_struct && - to_struct_type(type).get_tag()==CPROVER_PREFIX"string"; -} - -/// \par parameters: a type -/// \return Boolean telling whether the type is that of java string pointers -bool refined_string_typet::is_java_string_pointer_type(const typet &type) -{ - if(type.id()==ID_pointer) - { - const pointer_typet &pt=to_pointer_type(type); - const typet &subtype=pt.subtype(); - return is_java_string_type(subtype); - } - return false; -} - -/// \par parameters: a type -/// \return Boolean telling whether the type is that of java string -bool refined_string_typet::is_java_string_type(const typet &type) -{ - if(type.id()==ID_symbol) - { - irep_idt tag=to_symbol_type(type).get_identifier(); - return tag=="java::java.lang.String"; - } - else if(type.id()==ID_struct) - { - irep_idt tag=to_struct_type(type).get_tag(); - return tag=="java.lang.String"; - } - return false; -} - -/// \par parameters: a type -/// \return Boolean telling whether the type is that of java string builder -bool refined_string_typet::is_java_string_builder_type(const typet &type) -{ - if(type.id()==ID_pointer) - { - const pointer_typet &pt=to_pointer_type(type); - const typet &subtype=pt.subtype(); - if(subtype.id()==ID_struct) - { - irep_idt tag=to_struct_type(subtype).get_tag(); - return tag=="java.lang.StringBuilder"; - } - } - return false; -} - -/// \par parameters: a type -/// \return Boolean telling whether the type is that of java char sequence -bool refined_string_typet::is_java_char_sequence_type(const typet &type) -{ - if(type.id()==ID_pointer) - { - const pointer_typet &pt=to_pointer_type(type); - const typet &subtype=pt.subtype(); - if(subtype.id()==ID_struct) - { - const irep_idt &tag=to_struct_type(subtype).get_tag(); - return tag=="java.lang.CharSequence"; - } - } - return false; -} diff --git a/src/solvers/refinement/string_constraint.h b/src/solvers/refinement/string_constraint.h index 27a6a87a5a8..c83d63cc69a 100644 --- a/src/solvers/refinement/string_constraint.h +++ b/src/solvers/refinement/string_constraint.h @@ -22,7 +22,7 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com #include #include -#include +#include class string_constraintt: public exprt { @@ -55,7 +55,6 @@ class string_constraintt: public exprt return operands()[4]; } - private: string_constraintt(); diff --git a/src/solvers/refinement/string_constraint_generator.h b/src/solvers/refinement/string_constraint_generator.h index 84732931d70..bb2b05b90b5 100644 --- a/src/solvers/refinement/string_constraint_generator.h +++ b/src/solvers/refinement/string_constraint_generator.h @@ -20,29 +20,29 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com #ifndef CPROVER_SOLVERS_REFINEMENT_STRING_CONSTRAINT_GENERATOR_H #define CPROVER_SOLVERS_REFINEMENT_STRING_CONSTRAINT_GENERATOR_H +#include #include -#include +#include +#include #include class string_constraint_generatort { public: // This module keeps a list of axioms. It has methods which generate - // string constraints for different string funcitons and add them + // string constraints for different string functions and add them // to the axiom list. string_constraint_generatort(): - mode(ID_unknown) + max_string_length(std::numeric_limits::max()), + force_printable_characters(false) { } - void set_mode(irep_idt _mode) - { - // only C and java modes supported - assert((_mode==ID_java) || (_mode==ID_C)); - mode=_mode; - } + // Constraints on the maximal length of strings + size_t max_string_length; - irep_idt &get_mode() { return mode; } + // Should we add constraints on the characters + bool force_printable_characters; // Axioms are of three kinds: universally quantified string constraint, // not contains string constraints and simple formulas. @@ -72,21 +72,22 @@ class string_constraint_generatort symbol_exprt fresh_univ_index(const irep_idt &prefix, const typet &type); symbol_exprt fresh_boolean(const irep_idt &prefix); string_exprt fresh_string(const refined_string_typet &type); + string_exprt get_string_expr(const exprt &expr); + string_exprt convert_java_string_to_string_exprt( + const exprt &underlying); + plus_exprt plus_exprt_with_overflow_check(const exprt &op1, const exprt &op2); - // We maintain a map from symbols to strings. - std::map symbol_to_string; + // Maps unresolved symbols to the string_exprt that was created for them + std::map unresolved_symbols; - string_exprt find_or_add_string_of_symbol(const symbol_exprt &sym); + // Set of strings that have been created by the generator + std::set created_strings; - void assign_to_symbol( - const symbol_exprt &sym, const string_exprt &expr) - { - symbol_to_string[sym.get_identifier()]=expr; - } + string_exprt find_or_add_string_of_symbol( + const symbol_exprt &sym, + const refined_string_typet &ref_type); - string_exprt add_axioms_for_string_expr(const exprt &expr); - void set_string_symbol_equal_to_expr( - const symbol_exprt &sym, const exprt &str); + string_exprt add_axioms_for_refined_string(const exprt &expr); exprt add_axioms_for_function_application( const function_application_exprt &expr); @@ -103,8 +104,11 @@ class string_constraint_generatort const std::size_t MAX_FLOAT_LENGTH=15; const std::size_t MAX_DOUBLE_LENGTH=30; + std::map function_application_cache; + static irep_idt extract_java_string(const symbol_exprt &s); + void add_default_axioms(const string_exprt &s); exprt axiom_for_is_positive_index(const exprt &x); // The following functions add axioms for the returned value @@ -124,6 +128,9 @@ class string_constraint_generatort // The specification is partial: the actual value is not actually computed // but we ensure that hash codes of equal strings are equal. exprt add_axioms_for_hash_code(const function_application_exprt &f); + // To each string on which hash_code was called we associate a symbol + // representing the return value of the hash_code function. + std::map hash_code_of_string; exprt add_axioms_for_is_empty(const function_application_exprt &f); exprt add_axioms_for_is_prefix( @@ -231,7 +238,9 @@ class string_constraint_generatort // the start for negative number string_exprt add_axioms_from_float(const function_application_exprt &f); string_exprt add_axioms_from_float( - const exprt &f, bool double_precision=false); + const exprt &f, + const refined_string_typet &ref_type, + bool double_precision); // Add axioms corresponding to the String.valueOf(D) java function // TODO: the specifications is only partial @@ -260,6 +269,7 @@ class string_constraint_generatort string_exprt add_axioms_for_code_point( const exprt &code_point, const refined_string_typet &ref_type); string_exprt add_axioms_for_java_char_array(const exprt &char_array); + exprt add_axioms_for_char_pointer(const function_application_exprt &fun); string_exprt add_axioms_for_if(const if_exprt &expr); exprt add_axioms_for_char_literal(const function_application_exprt &f); @@ -277,6 +287,8 @@ class string_constraint_generatort const function_application_exprt &f); exprt add_axioms_for_parse_int(const function_application_exprt &f); + exprt add_axioms_for_correct_number_format( + const string_exprt &str, std::size_t max_size=10); exprt add_axioms_for_to_char_array(const function_application_exprt &f); exprt add_axioms_for_compare_to(const function_application_exprt &f); @@ -285,6 +297,9 @@ class string_constraint_generatort // string pointers symbol_exprt add_axioms_for_intern(const function_application_exprt &f); + // Pool used for the intern method + std::map intern_of_string; + // Tells which language is used. C and Java are supported irep_idt mode; @@ -300,14 +315,8 @@ class string_constraint_generatort exprt int_of_hex_char(const exprt &chr) const; exprt is_high_surrogate(const exprt &chr) const; exprt is_low_surrogate(const exprt &chr) const; - static exprt character_equals_ignore_case( + exprt character_equals_ignore_case( exprt char1, exprt char2, exprt char_a, exprt char_A, exprt char_Z); - - // Pool used for the intern method - std::map pool; - - // Used to determine whether hashcode should be equal - std::map hash; }; #endif diff --git a/src/solvers/refinement/string_constraint_generator_code_points.cpp b/src/solvers/refinement/string_constraint_generator_code_points.cpp index 6bf8e035ad5..ad44469d51e 100644 --- a/src/solvers/refinement/string_constraint_generator_code_points.cpp +++ b/src/solvers/refinement/string_constraint_generator_code_points.cpp @@ -127,17 +127,18 @@ exprt string_constraint_generatort::add_axioms_for_code_point_at( { typet return_type=f.type(); assert(return_type.id()==ID_signedbv); - string_exprt str=add_axioms_for_string_expr(args(f, 2)[0]); + string_exprt str=get_string_expr(args(f, 2)[0]); const exprt &pos=args(f, 2)[1]; symbol_exprt result=fresh_symbol("char", return_type); exprt index1=from_integer(1, str.length().type()); const exprt &char1=str[pos]; - const exprt &char2=str[plus_exprt(pos, index1)]; + const exprt &char2=str[plus_exprt_with_overflow_check(pos, index1)]; exprt char1_as_int=typecast_exprt(char1, return_type); exprt char2_as_int=typecast_exprt(char2, return_type); exprt pair=pair_value(char1_as_int, char2_as_int, return_type); - exprt is_low=is_low_surrogate(str[plus_exprt(pos, index1)]); + exprt is_low=is_low_surrogate( + str[plus_exprt_with_overflow_check(pos, index1)]); exprt return_pair=and_exprt(is_high_surrogate(str[pos]), is_low); axioms.push_back(implies_exprt(return_pair, equal_exprt(result, pair))); @@ -158,7 +159,7 @@ exprt string_constraint_generatort::add_axioms_for_code_point_before( typet return_type=f.type(); assert(return_type.id()==ID_signedbv); symbol_exprt result=fresh_symbol("char", return_type); - string_exprt str=add_axioms_for_string_expr(args[0]); + string_exprt str=get_string_expr(args[0]); const exprt &char1= str[minus_exprt(args[1], from_integer(2, str.length().type()))]; @@ -185,7 +186,7 @@ exprt string_constraint_generatort::add_axioms_for_code_point_before( exprt string_constraint_generatort::add_axioms_for_code_point_count( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 3)[0]); + string_exprt str=get_string_expr(args(f, 3)[0]); const exprt &begin=args(f, 3)[1]; const exprt &end=args(f, 3)[2]; const typet &return_type=f.type(); @@ -207,14 +208,15 @@ exprt string_constraint_generatort::add_axioms_for_code_point_count( exprt string_constraint_generatort::add_axioms_for_offset_by_code_point( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 3)[0]); + string_exprt str=get_string_expr(args(f, 3)[0]); const exprt &index=args(f, 3)[1]; const exprt &offset=args(f, 3)[2]; const typet &return_type=f.type(); symbol_exprt result=fresh_symbol("offset_by_code_point", return_type); - exprt minimum=plus_exprt(index, offset); - exprt maximum=plus_exprt(index, plus_exprt(offset, offset)); + exprt minimum=plus_exprt_with_overflow_check(index, offset); + exprt maximum=plus_exprt_with_overflow_check( + index, plus_exprt_with_overflow_check(offset, offset)); axioms.push_back(binary_relation_exprt(result, ID_le, maximum)); axioms.push_back(binary_relation_exprt(result, ID_ge, minimum)); diff --git a/src/solvers/refinement/string_constraint_generator_comparison.cpp b/src/solvers/refinement/string_constraint_generator_comparison.cpp index fbb64c55d68..c6ec1f20d79 100644 --- a/src/solvers/refinement/string_constraint_generator_comparison.cpp +++ b/src/solvers/refinement/string_constraint_generator_comparison.cpp @@ -13,8 +13,10 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com #include -/// add axioms stating that the result is true exactly when the strings -/// represented by the arguments are equal +/// Add axioms stating that the result is true exactly when the strings +/// represented by the arguments are equal. the variable ending in +/// `witness_unequal` is -1 if the length differs or an index at +/// which the strings are different /// \par parameters: function application with two string arguments /// \return a expression of Boolean type exprt string_constraint_generatort::add_axioms_for_equals( @@ -24,8 +26,8 @@ exprt string_constraint_generatort::add_axioms_for_equals( symbol_exprt eq=fresh_boolean("equal"); typecast_exprt tc_eq(eq, f.type()); - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); - string_exprt s2=add_axioms_for_string_expr(args(f, 2)[1]); + string_exprt s1=get_string_expr(args(f, 2)[0]); + string_exprt s2=get_string_expr(args(f, 2)[1]); typet index_type=s1.length().type(); // We want to write: @@ -49,9 +51,10 @@ exprt string_constraint_generatort::add_axioms_for_equals( binary_relation_exprt(witness, ID_lt, s1.length()), binary_relation_exprt(witness, ID_ge, zero)); and_exprt witnessing(bound_witness, notequal_exprt(s1[witness], s2[witness])); - implies_exprt a3( - not_exprt(eq), - or_exprt(notequal_exprt(s1.length(), s2.length()), witnessing)); + and_exprt diff_length( + notequal_exprt(s1.length(), s2.length()), + equal_exprt(witness, from_integer(-1, index_type))); + implies_exprt a3(not_exprt(eq), or_exprt(diff_length, witnessing)); axioms.push_back(a3); return tc_eq; @@ -79,8 +82,13 @@ exprt string_constraint_generatort::character_equals_ignore_case( // p3 : (is_up2&&'a'-'A'+char2=char1) equal_exprt p1(char1, char2); minus_exprt diff=minus_exprt(char_a, char_A); - and_exprt p2(is_upper_case_1, equal_exprt(plus_exprt(diff, char1), char2)); - and_exprt p3(is_upper_case_2, equal_exprt(plus_exprt(diff, char2), char1)); + + // Overflow is not a problem here because is_upper_case conditions + // ensure that we are within a safe range. + and_exprt p2(is_upper_case_1, + equal_exprt(plus_exprt(diff, char1), char2)); + and_exprt p3(is_upper_case_2, + equal_exprt(plus_exprt(diff, char2), char1)); return or_exprt(or_exprt(p1, p2), p3); } @@ -94,8 +102,8 @@ exprt string_constraint_generatort::add_axioms_for_equals_ignore_case( symbol_exprt eq=fresh_boolean("equal_ignore_case"); typecast_exprt tc_eq(eq, f.type()); - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); - string_exprt s2=add_axioms_for_string_expr(args(f, 2)[1]); + string_exprt s1=get_string_expr(args(f, 2)[0]); + string_exprt s2=get_string_expr(args(f, 2)[1]); typet char_type=to_refined_string_type(s1.type()).get_char_type(); exprt char_a=constant_char('a', char_type); exprt char_A=constant_char('A', char_type); @@ -143,37 +151,35 @@ exprt string_constraint_generatort::add_axioms_for_equals_ignore_case( exprt string_constraint_generatort::add_axioms_for_hash_code( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 1)[0]); + string_exprt str=get_string_expr(args(f, 1)[0]); typet return_type=f.type(); typet index_type=str.length().type(); - // initialisation of the missing pool variable - std::map::iterator it; - for(it=symbol_to_string.begin(); it!=symbol_to_string.end(); it++) - if(hash.find(it->second)==hash.end()) - hash[it->second]=fresh_symbol("hash", return_type); + auto pair=hash_code_of_string.insert( + std::make_pair(str, fresh_symbol("hash", return_type))); + exprt hash=pair.first->second; // for each string s. either: // c1: hash(str)=hash(s) // c2: |str|!=|s| - // c3: (|str|==|s| &&exists i<|s|. s[i]!=str[i]) + // c3: (|str|==|s| && exists i<|s|. s[i]!=str[i]) // WARNING: the specification may be incomplete - for(it=symbol_to_string.begin(); it!=symbol_to_string.end(); it++) + for(auto it : hash_code_of_string) { symbol_exprt i=fresh_exist_index("index_hash", index_type); - equal_exprt c1(hash[it->second], hash[str]); - not_exprt c2(equal_exprt(it->second.length(), str.length())); + equal_exprt c1(it.second, hash); + not_exprt c2(equal_exprt(it.first.length(), str.length())); and_exprt c3( - equal_exprt(it->second.length(), str.length()), + equal_exprt(it.first.length(), str.length()), and_exprt( - not_exprt(equal_exprt(str[i], it->second[i])), + not_exprt(equal_exprt(str[i], it.first[i])), and_exprt( str.axiom_for_is_strictly_longer_than(i), axiom_for_is_positive_index(i)))); axioms.push_back(or_exprt(c1, or_exprt(c2, c3))); } - return hash[str]; + return hash; } /// add axioms corresponding to the String.compareTo java function @@ -182,8 +188,8 @@ exprt string_constraint_generatort::add_axioms_for_hash_code( exprt string_constraint_generatort::add_axioms_for_compare_to( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); - string_exprt s2=add_axioms_for_string_expr(args(f, 2)[1]); + string_exprt s1=get_string_expr(args(f, 2)[0]); + string_exprt s2=get_string_expr(args(f, 2)[1]); const typet &return_type=f.type(); symbol_exprt res=fresh_symbol("compare_to", return_type); typet index_type=s1.length().type(); @@ -194,12 +200,12 @@ exprt string_constraint_generatort::add_axioms_for_compare_to( // a1 : res==0 => |s1|=|s2| // a2 : forall i<|s1|. s1[i]==s2[i] // a3 : exists x. - // res!=0 ==> x> 0 && - // ((|s1| <= |s2| &&x<|s1|) || (|s1| >= |s2| &&x<|s2|) - // &&res=s1[x]-s2[x] ) - // || cond2: - // (|s1|<|s2| &&x=|s1|) || (|s1| > |s2| &&x=|s2|) &&res=|s1|-|s2|) - // a4 : forall i s1[i]=s2[i] + // res!=0 ==> x > 0 + // && ((|s1| <= |s2| && x<|s1|) || (|s1| >= |s2| &&x<|s2|) + // && res=s1[x]-s2[x] ) + // || cond2: + // (|s1|<|s2| &&x=|s1|) || (|s1| > |s2| &&x=|s2|) &&res=|s1|-|s2|) + // a4 : forall i' s1[i]=s2[i] assert(return_type.id()==ID_signedbv); @@ -242,7 +248,9 @@ exprt string_constraint_generatort::add_axioms_for_compare_to( or_exprt(cond1, cond2))); axioms.push_back(a3); - string_constraintt a4(i, x, not_exprt(res_null), equal_exprt(s1[i], s2[i])); + symbol_exprt i2=fresh_univ_index("QA_compare_to", index_type); + string_constraintt a4( + i2, x, not_exprt(res_null), equal_exprt(s1[i2], s2[i2])); axioms.push_back(a4); return res; @@ -255,15 +263,15 @@ exprt string_constraint_generatort::add_axioms_for_compare_to( symbol_exprt string_constraint_generatort::add_axioms_for_intern( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 1)[0]); + string_exprt str=get_string_expr(args(f, 1)[0]); + // For now we only enforce content equality and not pointer equality const typet &return_type=f.type(); + typet index_type=str.length().type(); - // initialisation of the missing pool variable - std::map::iterator it; - for(it=symbol_to_string.begin(); it!=symbol_to_string.end(); it++) - if(pool.find(it->second)==pool.end()) - pool[it->second]=fresh_symbol("pool", return_type); + auto pair=intern_of_string.insert( + std::make_pair(str, fresh_symbol("pool", return_type))); + symbol_exprt intern=pair.first->second; // intern(str)=s_0 || s_1 || ... // for each string s. @@ -271,30 +279,30 @@ symbol_exprt string_constraint_generatort::add_axioms_for_intern( // || (|str|==|s| &&exists i<|s|. s[i]!=str[i]) exprt disj=false_exprt(); - for(it=symbol_to_string.begin(); it!=symbol_to_string.end(); it++) + for(auto it : intern_of_string) disj=or_exprt( - disj, equal_exprt(pool[str], symbol_exprt(it->first, return_type))); + disj, equal_exprt(intern, it.second)); axioms.push_back(disj); // WARNING: the specification may be incomplete or incorrect - for(it=symbol_to_string.begin(); it!=symbol_to_string.end(); it++) - if(it->second!=str) + for(auto it : intern_of_string) + if(it.second!=str) { symbol_exprt i=fresh_exist_index("index_intern", index_type); axioms.push_back( or_exprt( - equal_exprt(pool[it->second], pool[str]), + equal_exprt(it.second, intern), or_exprt( - not_exprt(str.axiom_for_has_same_length_as(it->second)), + not_exprt(str.axiom_for_has_same_length_as(it.first)), and_exprt( - str.axiom_for_has_same_length_as(it->second), + str.axiom_for_has_same_length_as(it.first), and_exprt( - not_exprt(equal_exprt(str[i], it->second[i])), + not_exprt(equal_exprt(str[i], it.first[i])), and_exprt(str.axiom_for_is_strictly_longer_than(i), axiom_for_is_positive_index(i))))))); } - return pool[str]; + return intern; } diff --git a/src/solvers/refinement/string_constraint_generator_concat.cpp b/src/solvers/refinement/string_constraint_generator_concat.cpp index 4d0a5b47151..311427ec771 100644 --- a/src/solvers/refinement/string_constraint_generator_concat.cpp +++ b/src/solvers/refinement/string_constraint_generator_concat.cpp @@ -30,8 +30,8 @@ string_exprt string_constraint_generatort::add_axioms_for_concat( // a4 : forall i<|s1|. res[i]=s1[i] // a5 : forall i<|s2|. res[i+|s1|]=s2[i] - exprt a1=res.axiom_for_has_length( - plus_exprt(s1.length(), s2.length())); + equal_exprt a1( + res.length(), plus_exprt_with_overflow_check(s1.length(), s2.length())); axioms.push_back(a1); axioms.push_back(s1.axiom_for_is_shorter_than(res)); axioms.push_back(s2.axiom_for_is_shorter_than(res)); @@ -58,8 +58,8 @@ string_exprt string_constraint_generatort::add_axioms_for_concat( const function_application_exprt::argumentst &args=f.arguments(); assert(args.size()==2); - string_exprt s1=add_axioms_for_string_expr(args[0]); - string_exprt s2=add_axioms_for_string_expr(args[1]); + string_exprt s1=get_string_expr(args[0]); + string_exprt s2=get_string_expr(args[1]); return add_axioms_for_concat(s1, s2); } @@ -72,7 +72,7 @@ string_exprt string_constraint_generatort::add_axioms_for_concat_int( const function_application_exprt &f) { const refined_string_typet &ref_type=to_refined_string_type(f.type()); - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); + string_exprt s1=get_string_expr(args(f, 2)[0]); string_exprt s2=add_axioms_from_int( args(f, 2)[1], MAX_INTEGER_LENGTH, ref_type); return add_axioms_for_concat(s1, s2); @@ -86,7 +86,7 @@ string_exprt string_constraint_generatort::add_axioms_for_concat_long( const function_application_exprt &f) { const refined_string_typet &ref_type=to_refined_string_type(f.type()); - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); + string_exprt s1=get_string_expr(args(f, 2)[0]); string_exprt s2=add_axioms_from_int(args(f, 2)[1], MAX_LONG_LENGTH, ref_type); return add_axioms_for_concat(s1, s2); } @@ -97,7 +97,7 @@ string_exprt string_constraint_generatort::add_axioms_for_concat_long( string_exprt string_constraint_generatort::add_axioms_for_concat_bool( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); + string_exprt s1=get_string_expr(args(f, 2)[0]); const refined_string_typet &ref_type=to_refined_string_type(s1.type()); string_exprt s2=add_axioms_from_bool(args(f, 2)[1], ref_type); return add_axioms_for_concat(s1, s2); @@ -110,7 +110,7 @@ string_exprt string_constraint_generatort::add_axioms_for_concat_bool( string_exprt string_constraint_generatort::add_axioms_for_concat_char( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); + string_exprt s1=get_string_expr(args(f, 2)[0]); const refined_string_typet &ref_type=to_refined_string_type(s1.type()); string_exprt s2=add_axioms_from_char(args(f, 2)[1], ref_type); return add_axioms_for_concat(s1, s2); @@ -123,9 +123,10 @@ string_exprt string_constraint_generatort::add_axioms_for_concat_char( string_exprt string_constraint_generatort::add_axioms_for_concat_double( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); - string_exprt s2=add_axioms_from_float( - args(f, 2)[1], MAX_DOUBLE_LENGTH); + string_exprt s1=get_string_expr(args(f, 2)[0]); + assert(refined_string_typet::is_refined_string_type(f.type())); + refined_string_typet ref_type=to_refined_string_type(f.type()); + string_exprt s2=add_axioms_from_float(args(f, 2)[1], ref_type, true); return add_axioms_for_concat(s1, s2); } @@ -136,8 +137,10 @@ string_exprt string_constraint_generatort::add_axioms_for_concat_double( string_exprt string_constraint_generatort::add_axioms_for_concat_float( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); - string_exprt s2=add_axioms_from_float(args(f, 2)[1], MAX_FLOAT_LENGTH); + string_exprt s1=get_string_expr(args(f, 2)[0]); + assert(refined_string_typet::is_refined_string_type(f.type())); + refined_string_typet ref_type=to_refined_string_type(f.type()); + string_exprt s2=add_axioms_from_float(args(f, 2)[1], ref_type, false); return add_axioms_for_concat(s1, s2); } @@ -148,7 +151,7 @@ string_exprt string_constraint_generatort::add_axioms_for_concat_float( string_exprt string_constraint_generatort::add_axioms_for_concat_code_point( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); + string_exprt s1=get_string_expr(args(f, 2)[0]); const refined_string_typet &ref_type=to_refined_string_type(s1.type()); string_exprt s2=add_axioms_for_code_point(args(f, 2)[1], ref_type); return add_axioms_for_concat(s1, s2); diff --git a/src/solvers/refinement/string_constraint_generator_constants.cpp b/src/solvers/refinement/string_constraint_generator_constants.cpp index 3c05aaf5440..c5fb56658fb 100644 --- a/src/solvers/refinement/string_constraint_generator_constants.cpp +++ b/src/solvers/refinement/string_constraint_generator_constants.cpp @@ -69,9 +69,13 @@ string_exprt string_constraint_generatort::add_axioms_for_empty_string( const function_application_exprt &f) { assert(f.arguments().empty()); + assert(refined_string_typet::is_refined_string_type(f.type())); const refined_string_typet &ref_type=to_refined_string_type(f.type()); - string_exprt res=fresh_string(ref_type); - axioms.push_back(res.axiom_for_has_length(0)); + exprt size=from_integer(0, ref_type.get_index_type()); + const array_typet &content_type=ref_type.get_content_type(); + array_of_exprt empty_array( + from_integer(0, ref_type.get_content_type().subtype()), content_type); + string_exprt res(size, empty_array, ref_type); return res; } @@ -100,7 +104,8 @@ string_exprt string_constraint_generatort::add_axioms_from_literal( else { // Java string constant - assert(refined_string_typet::is_unrefined_string_type(arg.type())); + assert(false); // TODO: Check if used. On the contrary, discard else. + assert(arg.id()==ID_symbol); const exprt &s=arg.op0(); // It seems the value of the string is lost, diff --git a/src/solvers/refinement/string_constraint_generator_indexof.cpp b/src/solvers/refinement/string_constraint_generator_indexof.cpp index d32be2e3570..59b7395188d 100644 --- a/src/solvers/refinement/string_constraint_generator_indexof.cpp +++ b/src/solvers/refinement/string_constraint_generator_indexof.cpp @@ -79,15 +79,16 @@ exprt string_constraint_generatort::add_axioms_for_index_of_string( symbol_exprt contains=fresh_boolean("contains_substring"); // We add axioms: - // a1 : contains => |substring|>=offset>=from_index + // a1 : contains => |str|-|substring|>=offset>=from_index // a2 : !contains => offset=-1 - // a3 : forall 0 <= witness str[witness+offset]=substring[witness] + // a3 : forall 0<=witness<|substring|. + // contains => str[witness+offset]=substring[witness] implies_exprt a1( contains, and_exprt( - str.axiom_for_is_longer_than(plus_exprt(substring.length(), offset)), + str.axiom_for_is_longer_than(plus_exprt_with_overflow_check( + substring.length(), offset)), binary_relation_exprt(offset, ID_ge, from_index))); axioms.push_back(a1); @@ -125,7 +126,8 @@ exprt string_constraint_generatort::add_axioms_for_last_index_of_string( implies_exprt a1( contains, and_exprt( - str.axiom_for_is_longer_than(plus_exprt(substring.length(), offset)), + str.axiom_for_is_longer_than( + plus_exprt_with_overflow_check(substring.length(), offset)), binary_relation_exprt(offset, ID_le, from_index))); axioms.push_back(a1); @@ -150,7 +152,7 @@ exprt string_constraint_generatort::add_axioms_for_index_of( const function_application_exprt &f) { const function_application_exprt::argumentst &args=f.arguments(); - string_exprt str=add_axioms_for_string_expr(args[0]); + string_exprt str=get_string_expr(args[0]); const exprt &c=args[1]; const refined_string_typet &ref_type=to_refined_string_type(str.type()); assert(f.type()==ref_type.get_index_type()); @@ -163,14 +165,17 @@ exprt string_constraint_generatort::add_axioms_for_index_of( else assert(false); - if(refined_string_typet::is_java_string_pointer_type(c.type())) + if(c.type().id()==ID_unsignedbv || c.type().id()==ID_signedbv) { - string_exprt sub=add_axioms_for_string_expr(c); - return add_axioms_for_index_of_string(str, sub, from_index); - } - else return add_axioms_for_index_of( str, typecast_exprt(c, ref_type.get_char_type()), from_index); + } + else + { + assert(refined_string_typet::is_refined_string_type(c.type())); + string_exprt sub=get_string_expr(c); + return add_axioms_for_index_of_string(str, sub, from_index); + } } exprt string_constraint_generatort::add_axioms_for_last_index_of( @@ -190,7 +195,7 @@ exprt string_constraint_generatort::add_axioms_for_last_index_of( exprt index1=from_integer(1, index_type); exprt minus1=from_integer(-1, index_type); - exprt from_index_plus_one=plus_exprt(from_index, index1); + exprt from_index_plus_one=plus_exprt_with_overflow_check(from_index, index1); and_exprt a1( binary_relation_exprt(index, ID_ge, minus1), binary_relation_exprt(index, ID_lt, from_index_plus_one)); @@ -235,7 +240,7 @@ exprt string_constraint_generatort::add_axioms_for_last_index_of( const function_application_exprt &f) { const function_application_exprt::argumentst &args=f.arguments(); - string_exprt str=add_axioms_for_string_expr(args[0]); + string_exprt str=get_string_expr(args[0]); exprt c=args[1]; const refined_string_typet &ref_type=to_refined_string_type(str.type()); exprt from_index; @@ -248,12 +253,14 @@ exprt string_constraint_generatort::add_axioms_for_last_index_of( else assert(false); - if(refined_string_typet::is_java_string_pointer_type(c.type())) + if(c.type().id()==ID_unsignedbv || c.type().id()==ID_signedbv) { - string_exprt sub=add_axioms_for_string_expr(c); - return add_axioms_for_last_index_of_string(str, sub, from_index); - } - else return add_axioms_for_last_index_of( str, typecast_exprt(c, ref_type.get_char_type()), from_index); + } + else + { + string_exprt sub=get_string_expr(c); + return add_axioms_for_last_index_of_string(str, sub, from_index); + } } diff --git a/src/solvers/refinement/string_constraint_generator_insert.cpp b/src/solvers/refinement/string_constraint_generator_insert.cpp index f757317121e..04e2fa3023d 100644 --- a/src/solvers/refinement/string_constraint_generator_insert.cpp +++ b/src/solvers/refinement/string_constraint_generator_insert.cpp @@ -26,16 +26,40 @@ string_exprt string_constraint_generatort::add_axioms_for_insert( return add_axioms_for_concat(concat1, suf); } -/// add axioms corresponding to the StringBuilder.insert(String) java function -/// \par parameters: function application with three arguments: two strings and -/// an index -/// \return a new string expression +/*******************************************************************\ + +Function: string_constraint_generatort::add_axioms_for_insert + + Inputs: function application with three arguments: two strings and an index + + Outputs: a new string expression + + Purpose: add axioms corresponding to the + StringBuilder.insert(int, CharSequence) + and StringBuilder.insert(int, CharSequence, int, int) + java functions + +\*******************************************************************/ + string_exprt string_constraint_generatort::add_axioms_for_insert( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 3)[0]); - string_exprt s2=add_axioms_for_string_expr(args(f, 3)[2]); - return add_axioms_for_insert(s1, s2, args(f, 3)[1]); + assert(f.arguments().size()>=3); + string_exprt s1=get_string_expr(f.arguments()[0]); + string_exprt s2=get_string_expr(f.arguments()[2]); + const exprt &offset=f.arguments()[1]; + if(f.arguments().size()==5) + { + const exprt &start=f.arguments()[3]; + const exprt &end=f.arguments()[4]; + string_exprt substring=add_axioms_for_substring(s2, start, end); + return add_axioms_for_insert(s1, substring, offset); + } + else + { + assert(f.arguments().size()==3); + return add_axioms_for_insert(s1, s2, offset); + } } /// add axioms corresponding to the StringBuilder.insert(I) java function @@ -47,7 +71,7 @@ string_exprt string_constraint_generatort::add_axioms_for_insert_int( const function_application_exprt &f) { const refined_string_typet &ref_type=to_refined_string_type(f.type()); - string_exprt s1=add_axioms_for_string_expr(args(f, 3)[0]); + string_exprt s1=get_string_expr(args(f, 3)[0]); string_exprt s2=add_axioms_from_int( args(f, 3)[2], MAX_INTEGER_LENGTH, ref_type); return add_axioms_for_insert(s1, s2, args(f, 3)[1]); @@ -62,7 +86,7 @@ string_exprt string_constraint_generatort::add_axioms_for_insert_long( const function_application_exprt &f) { const refined_string_typet &ref_type=to_refined_string_type(f.type()); - string_exprt s1=add_axioms_for_string_expr(args(f, 3)[0]); + string_exprt s1=get_string_expr(args(f, 3)[0]); string_exprt s2=add_axioms_from_int(args(f, 3)[2], MAX_LONG_LENGTH, ref_type); return add_axioms_for_insert(s1, s2, args(f, 3)[1]); } @@ -76,7 +100,7 @@ string_exprt string_constraint_generatort::add_axioms_for_insert_bool( const function_application_exprt &f) { const refined_string_typet &ref_type=to_refined_string_type(f.type()); - string_exprt s1=add_axioms_for_string_expr(args(f, 3)[0]); + string_exprt s1=get_string_expr(args(f, 3)[0]); string_exprt s2=add_axioms_from_bool(args(f, 3)[2], ref_type); return add_axioms_for_insert(s1, s2, args(f, 3)[1]); } @@ -89,7 +113,7 @@ string_exprt string_constraint_generatort::add_axioms_for_insert_bool( string_exprt string_constraint_generatort::add_axioms_for_insert_char( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 3)[0]); + string_exprt s1=get_string_expr(args(f, 3)[0]); const refined_string_typet &ref_type=to_refined_string_type(s1.type()); string_exprt s2=add_axioms_from_char(args(f, 3)[2], ref_type); return add_axioms_for_insert(s1, s2, args(f, 3)[1]); @@ -103,8 +127,9 @@ string_exprt string_constraint_generatort::add_axioms_for_insert_char( string_exprt string_constraint_generatort::add_axioms_for_insert_double( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 3)[0]); - string_exprt s2=add_axioms_from_float(args(f, 3)[2]); + string_exprt s1=get_string_expr(args(f, 3)[0]); + const refined_string_typet &ref_type=to_refined_string_type(s1.type()); + string_exprt s2=add_axioms_from_float(args(f, 3)[2], ref_type, true); return add_axioms_for_insert(s1, s2, args(f, 3)[1]); } @@ -116,8 +141,9 @@ string_exprt string_constraint_generatort::add_axioms_for_insert_double( string_exprt string_constraint_generatort::add_axioms_for_insert_float( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 3)[0]); - string_exprt s2=add_axioms_from_float(args(f, 3)[2]); + string_exprt s1=get_string_expr(args(f, 3)[0]); + const refined_string_typet &ref_type=to_refined_string_type(s1.type()); + string_exprt s2=add_axioms_from_float(args(f, 3)[2], ref_type, false); return add_axioms_for_insert(s1, s2, args(f, 3)[1]); } @@ -145,7 +171,7 @@ string_exprt string_constraint_generatort::add_axioms_for_insert_char_array( offset=from_integer(0, count.type()); } - string_exprt str=add_axioms_for_string_expr(f.arguments()[0]); + string_exprt str=get_string_expr(f.arguments()[0]); const exprt &length=f.arguments()[2]; const exprt &data=f.arguments()[3]; string_exprt arr=add_axioms_from_char_array( diff --git a/src/solvers/refinement/string_constraint_generator_main.cpp b/src/solvers/refinement/string_constraint_generator_main.cpp index b0b48df18bd..00b38f444ef 100644 --- a/src/solvers/refinement/string_constraint_generator_main.cpp +++ b/src/solvers/refinement/string_constraint_generator_main.cpp @@ -23,6 +23,7 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com #include #include #include +#include unsigned string_constraint_generatort::next_symbol_id=1; @@ -82,64 +83,204 @@ symbol_exprt string_constraint_generatort::fresh_boolean( return b; } -/// construct a string expression whose length and content are new variables -/// \par parameters: a type for string -/// \return a string expression +/// Create a plus expression while adding extra constraints to +/// axioms in order to prevent overflows. +/// \par op1: First term of the sum +/// \par op2: Second term of the sum +/// \return A plus expression representing the sum of the arguments +plus_exprt string_constraint_generatort::plus_exprt_with_overflow_check( + const exprt &op1, const exprt &op2) +{ + plus_exprt sum(plus_exprt(op1, op2)); + + exprt zero=from_integer(0, op1.type()); + + binary_relation_exprt neg1(op1, ID_lt, zero); + binary_relation_exprt neg2(op2, ID_lt, zero); + binary_relation_exprt neg_sum(sum, ID_lt, zero); + + // We prevent overflows by adding the following constraint: + // If the signs of the two operands are the same, then the sign of the sum + // should also be the same. + implies_exprt no_overflow(equal_exprt(neg1, neg2), + equal_exprt(neg1, neg_sum)); + + axioms.push_back(no_overflow); + + return sum; +} + +/*******************************************************************\ + +Function: string_constraint_generatort::fresh_string + + Inputs: a type for string + + Outputs: a string expression + + Purpose: construct a string expression whose length and content are new + variables + +\*******************************************************************/ + +>>>>>>> bdbeaf586... Many corrections in string refinement string_exprt string_constraint_generatort::fresh_string( const refined_string_typet &type) { - symbol_exprt length= - fresh_symbol("string_length", type.get_index_type()); + symbol_exprt length=fresh_symbol("string_length", type.get_index_type()); symbol_exprt content=fresh_symbol("string_content", type.get_content_type()); - return string_exprt(length, content, type); + string_exprt str(length, content, type); + created_strings.insert(str); + return str; } -/// obtain a refined string expression corresponding to string variable of -/// string function call -/// \par parameters: an expression of type string -/// \return a string expression that is linked to the argument through axioms -/// that are added to the list -string_exprt string_constraint_generatort::add_axioms_for_string_expr( - const exprt &unrefined_string) +/// casts an expression to a string expression, or fetches the actual +/// string_exprt in the case of a symbol. +/// \par parameters: an expression of refined string type +/// \return a string expression +string_exprt string_constraint_generatort::get_string_expr(const exprt &expr) { - string_exprt s; + assert(refined_string_typet::is_refined_string_type(expr.type())); - if(unrefined_string.id()==ID_function_application) + if(expr.id()==ID_symbol) + { + return find_or_add_string_of_symbol( + to_symbol_expr(expr), + to_refined_string_type(expr.type())); + } + else { - exprt res=add_axioms_for_function_application( - to_function_application_expr(unrefined_string)); - s=to_string_expr(res); + return to_string_expr(expr); } - else if(unrefined_string.id()==ID_symbol) - s=find_or_add_string_of_symbol(to_symbol_expr(unrefined_string)); - else if(unrefined_string.id()==ID_address_of) +} + +/*******************************************************************\ + +Function: string_constraint_generatort::convert_java_string_to_string_exprt + + Inputs: a java string + + Outputs: a string expression + + Purpose: create a new string_exprt as a conversion of a java string + +\*******************************************************************/ + +string_exprt string_constraint_generatort::convert_java_string_to_string_exprt( + const exprt &jls) +{ + assert(jls.id()==ID_struct); + + exprt length(to_struct_expr(jls).op1()); + // TODO: Add assertion on the type. + // assert(length.type()==refined_string_typet::index_type()); + exprt java_content(to_struct_expr(jls).op2()); + if(java_content.id()==ID_address_of) { - assert(unrefined_string.op0().id()==ID_symbol); - s=find_or_add_string_of_symbol(to_symbol_expr(unrefined_string.op0())); + java_content=to_address_of_expr(java_content).object(); } - else if(unrefined_string.id()==ID_if) - s=add_axioms_for_if(to_if_expr(unrefined_string)); - else if(unrefined_string.id()==ID_nondet_symbol || - unrefined_string.id()==ID_struct) + else { - // TODO: for now we ignore non deterministic symbols and struct + java_content=dereference_exprt(java_content, java_content.type()); } - else if(unrefined_string.id()==ID_typecast) + + refined_string_typet type(java_int_type(), java_char_type()); + + return string_exprt(length, java_content, type); +} + +/*******************************************************************\ + +Function: string_constraint_generatort::add_default_constraints + + Inputs: + s - a string expression + + Outputs: a string expression that is linked to the argument through + axioms that are added to the list + + Purpose: adds standard axioms about the length of the string and + its content: + * its length should be positive + * it should not exceed max_string_length + * if force_printable_characters is true then all characters + should belong to the range of ASCII characters between ' ' and '~' + + +\*******************************************************************/ + +void string_constraint_generatort::add_default_axioms( + const string_exprt &s) +{ + s.axiom_for_is_longer_than(from_integer(0, s.length().type())); + if(max_string_length!=std::numeric_limits::max()) + axioms.push_back(s.axiom_for_is_shorter_than(max_string_length)); + + if(force_printable_characters) { - exprt arg=to_typecast_expr(unrefined_string).op(); - exprt res=add_axioms_for_string_expr(arg); - s=to_string_expr(res); + symbol_exprt qvar=fresh_univ_index("printable", s.length().type()); + exprt chr=s[qvar]; + and_exprt printable( + binary_relation_exprt(chr, ID_ge, from_integer(' ', chr.type())), + binary_relation_exprt(chr, ID_le, from_integer('~', chr.type()))); + string_constraintt sc(qvar, s.length(), printable); + axioms.push_back(sc); + } +} + +/*******************************************************************\ + +Function: string_constraint_generatort::add_axioms_for_refined_string + + Inputs: an expression of refined string type + + Outputs: a string expression that is linked to the argument through + axioms that are added to the list + + Purpose: obtain a refined string expression corresponding to a expression + of type string + +\*******************************************************************/ + +string_exprt string_constraint_generatort::add_axioms_for_refined_string( + const exprt &string) +>>>>>>> bdbeaf586... Many corrections in string refinement +{ + assert(refined_string_typet::is_refined_string_type(string.type())); + refined_string_typet type=to_refined_string_type(string.type()); + + // Function applications should have been removed before + assert(string.id()!=ID_function_application); + + if(string.id()==ID_symbol) + { + const symbol_exprt &sym=to_symbol_expr(string); + string_exprt s=find_or_add_string_of_symbol(sym, type); + add_default_axioms(s); + return s; + } + else if(string.id()==ID_nondet_symbol) + { + string_exprt s=fresh_string(type); + add_default_axioms(s); + return s; + } + else if(string.id()==ID_if) + { + return add_axioms_for_if(to_if_expr(string)); + } + else if(string.id()==ID_struct) + { + const string_exprt &s=to_string_expr(string); + add_default_axioms(s); + return s; } else { - throw "add_axioms_for_string_expr:\n"+unrefined_string.pretty()+ + throw "add_axioms_for_refined_string:\n"+string.pretty()+ "\nwhich is not a function application, "+ - "a symbol or an if expression"; + "a symbol, a struct or an if expression"; } - - axioms.push_back( - s.axiom_for_is_longer_than(from_integer(0, s.length().type()))); - return s; } /// add axioms for an if expression which should return a string @@ -149,11 +290,11 @@ string_exprt string_constraint_generatort::add_axioms_for_if( const if_exprt &expr) { assert( - refined_string_typet::is_unrefined_string_type(expr.true_case().type())); - string_exprt t=add_axioms_for_string_expr(expr.true_case()); + refined_string_typet::is_refined_string_type(expr.true_case().type())); + string_exprt t=get_string_expr(expr.true_case()); assert( - refined_string_typet::is_unrefined_string_type(expr.false_case().type())); - string_exprt f=add_axioms_for_string_expr(expr.false_case()); + refined_string_typet::is_refined_string_type(expr.false_case().type())); + string_exprt f=get_string_expr(expr.false_case()); const refined_string_typet &ref_type=to_refined_string_type(t.type()); const typet &index_type=ref_type.get_index_type(); string_exprt res=fresh_string(ref_type); @@ -179,12 +320,11 @@ string_exprt string_constraint_generatort::add_axioms_for_if( /// \par parameters: a symbol expression /// \return a string expression string_exprt string_constraint_generatort::find_or_add_string_of_symbol( - const symbol_exprt &sym) + const symbol_exprt &sym, const refined_string_typet &ref_type) { irep_idt id=sym.get_identifier(); - const refined_string_typet &ref_type=to_refined_string_type(sym.type()); string_exprt str=fresh_string(ref_type); - auto entry=symbol_to_string.insert(std::make_pair(id, str)); + auto entry=unresolved_symbols.insert(std::make_pair(id, str)); return entry.first->second; } @@ -202,125 +342,179 @@ exprt string_constraint_generatort::add_axioms_for_function_application( const irep_idt &id=is_ssa_expr(name)?to_ssa_expr(name).get_object_name(): to_symbol_expr(name).get_identifier(); + std::string str_id(id.c_str()); + + size_t pos=str_id.find("func_length"); + if(pos!=std::string::npos) + { + function_application_exprt new_expr(expr); + // TODO: This part needs some improvement. + // Stripping the symbol name is not a very robust process. + new_expr.function() = symbol_exprt(str_id.substr(0, pos+4)); + new_expr.type() = refined_string_typet(java_int_type(), java_char_type()); + + auto res_it=function_application_cache.insert(std::make_pair(new_expr, + nil_exprt())); + if(res_it.second) + { + string_exprt res=to_string_expr( + add_axioms_for_function_application(new_expr)); + res_it.first->second=res; + return res.length(); + } + else + return to_string_expr(res_it.first->second).length(); + } + + pos = str_id.find("func_data"); + if(pos!=std::string::npos) + { + function_application_exprt new_expr(expr); + new_expr.function() = symbol_exprt(str_id.substr(0, pos+4)); + new_expr.type() = refined_string_typet(java_int_type(), java_char_type()); + + auto res_it=function_application_cache.insert(std::make_pair(new_expr, + nil_exprt())); + if(res_it.second) + { + string_exprt res=to_string_expr( + add_axioms_for_function_application(new_expr)); + res_it.first->second=res; + return res.content(); + } + else + return to_string_expr(res_it.first->second).content(); + } + // TODO: improve efficiency of this test by either ordering test by frequency // or using a map + auto res_it=function_application_cache.find(expr); + if(res_it!=function_application_cache.end() && res_it->second!=nil_exprt()) + return res_it->second; + + exprt res; + if(id==ID_cprover_char_literal_func) - return add_axioms_for_char_literal(expr); + res=add_axioms_for_char_literal(expr); else if(id==ID_cprover_string_length_func) - return add_axioms_for_length(expr); + res=add_axioms_for_length(expr); else if(id==ID_cprover_string_equal_func) - return add_axioms_for_equals(expr); + res=add_axioms_for_equals(expr); else if(id==ID_cprover_string_equals_ignore_case_func) - return add_axioms_for_equals_ignore_case(expr); + res=add_axioms_for_equals_ignore_case(expr); else if(id==ID_cprover_string_is_empty_func) - return add_axioms_for_is_empty(expr); + res=add_axioms_for_is_empty(expr); else if(id==ID_cprover_string_char_at_func) - return add_axioms_for_char_at(expr); + res=add_axioms_for_char_at(expr); else if(id==ID_cprover_string_is_prefix_func) - return add_axioms_for_is_prefix(expr); + res=add_axioms_for_is_prefix(expr); else if(id==ID_cprover_string_is_suffix_func) - return add_axioms_for_is_suffix(expr); + res=add_axioms_for_is_suffix(expr); else if(id==ID_cprover_string_startswith_func) - return add_axioms_for_is_prefix(expr, true); + res=add_axioms_for_is_prefix(expr, true); else if(id==ID_cprover_string_endswith_func) - return add_axioms_for_is_suffix(expr, true); + res=add_axioms_for_is_suffix(expr, true); else if(id==ID_cprover_string_contains_func) - return add_axioms_for_contains(expr); + res=add_axioms_for_contains(expr); else if(id==ID_cprover_string_hash_code_func) - return add_axioms_for_hash_code(expr); + res=add_axioms_for_hash_code(expr); else if(id==ID_cprover_string_index_of_func) - return add_axioms_for_index_of(expr); + res=add_axioms_for_index_of(expr); else if(id==ID_cprover_string_last_index_of_func) - return add_axioms_for_last_index_of(expr); + res=add_axioms_for_last_index_of(expr); else if(id==ID_cprover_string_parse_int_func) - return add_axioms_for_parse_int(expr); + res=add_axioms_for_parse_int(expr); else if(id==ID_cprover_string_to_char_array_func) - return add_axioms_for_to_char_array(expr); + res=add_axioms_for_to_char_array(expr); else if(id==ID_cprover_string_code_point_at_func) - return add_axioms_for_code_point_at(expr); + res=add_axioms_for_code_point_at(expr); else if(id==ID_cprover_string_code_point_before_func) - return add_axioms_for_code_point_before(expr); + res=add_axioms_for_code_point_before(expr); else if(id==ID_cprover_string_code_point_count_func) - return add_axioms_for_code_point_count(expr); + res=add_axioms_for_code_point_count(expr); else if(id==ID_cprover_string_offset_by_code_point_func) - return add_axioms_for_offset_by_code_point(expr); + res=add_axioms_for_offset_by_code_point(expr); else if(id==ID_cprover_string_compare_to_func) - return add_axioms_for_compare_to(expr); + res=add_axioms_for_compare_to(expr); else if(id==ID_cprover_string_literal_func) - return add_axioms_from_literal(expr); + res=add_axioms_from_literal(expr); else if(id==ID_cprover_string_concat_func) - return add_axioms_for_concat(expr); + res=add_axioms_for_concat(expr); else if(id==ID_cprover_string_concat_int_func) - return add_axioms_for_concat_int(expr); + res=add_axioms_for_concat_int(expr); else if(id==ID_cprover_string_concat_long_func) - return add_axioms_for_concat_long(expr); + res=add_axioms_for_concat_long(expr); else if(id==ID_cprover_string_concat_bool_func) - return add_axioms_for_concat_bool(expr); + res=add_axioms_for_concat_bool(expr); else if(id==ID_cprover_string_concat_char_func) - return add_axioms_for_concat_char(expr); + res=add_axioms_for_concat_char(expr); else if(id==ID_cprover_string_concat_double_func) - return add_axioms_for_concat_double(expr); + res=add_axioms_for_concat_double(expr); else if(id==ID_cprover_string_concat_float_func) - return add_axioms_for_concat_float(expr); + res=add_axioms_for_concat_float(expr); else if(id==ID_cprover_string_concat_code_point_func) - return add_axioms_for_concat_code_point(expr); + res=add_axioms_for_concat_code_point(expr); else if(id==ID_cprover_string_insert_func) - return add_axioms_for_insert(expr); + res=add_axioms_for_insert(expr); else if(id==ID_cprover_string_insert_int_func) - return add_axioms_for_insert_int(expr); + res=add_axioms_for_insert_int(expr); else if(id==ID_cprover_string_insert_long_func) - return add_axioms_for_insert_long(expr); + res=add_axioms_for_insert_long(expr); else if(id==ID_cprover_string_insert_bool_func) - return add_axioms_for_insert_bool(expr); + res=add_axioms_for_insert_bool(expr); else if(id==ID_cprover_string_insert_char_func) - return add_axioms_for_insert_char(expr); + res=add_axioms_for_insert_char(expr); else if(id==ID_cprover_string_insert_double_func) - return add_axioms_for_insert_double(expr); + res=add_axioms_for_insert_double(expr); else if(id==ID_cprover_string_insert_float_func) - return add_axioms_for_insert_float(expr); + res=add_axioms_for_insert_float(expr); +#if 0 else if(id==ID_cprover_string_insert_char_array_func) - return add_axioms_for_insert_char_array(expr); + res=add_axioms_for_insert_char_array(expr); +#endif else if(id==ID_cprover_string_substring_func) - return add_axioms_for_substring(expr); + res=add_axioms_for_substring(expr); else if(id==ID_cprover_string_trim_func) - return add_axioms_for_trim(expr); + res=add_axioms_for_trim(expr); else if(id==ID_cprover_string_to_lower_case_func) - return add_axioms_for_to_lower_case(expr); + res=add_axioms_for_to_lower_case(expr); else if(id==ID_cprover_string_to_upper_case_func) - return add_axioms_for_to_upper_case(expr); + res=add_axioms_for_to_upper_case(expr); else if(id==ID_cprover_string_char_set_func) - return add_axioms_for_char_set(expr); + res=add_axioms_for_char_set(expr); else if(id==ID_cprover_string_value_of_func) - return add_axioms_for_value_of(expr); + res=add_axioms_for_value_of(expr); else if(id==ID_cprover_string_empty_string_func) - return add_axioms_for_empty_string(expr); + res=add_axioms_for_empty_string(expr); else if(id==ID_cprover_string_copy_func) - return add_axioms_for_copy(expr); + res=add_axioms_for_copy(expr); else if(id==ID_cprover_string_of_int_func) - return add_axioms_from_int(expr); + res=add_axioms_from_int(expr); else if(id==ID_cprover_string_of_int_hex_func) - return add_axioms_from_int_hex(expr); + res=add_axioms_from_int_hex(expr); else if(id==ID_cprover_string_of_float_func) - return add_axioms_from_float(expr); + res=add_axioms_from_float(expr); else if(id==ID_cprover_string_of_double_func) - return add_axioms_from_double(expr); + res=add_axioms_from_double(expr); else if(id==ID_cprover_string_of_long_func) - return add_axioms_from_long(expr); + res=add_axioms_from_long(expr); else if(id==ID_cprover_string_of_bool_func) - return add_axioms_from_bool(expr); + res=add_axioms_from_bool(expr); else if(id==ID_cprover_string_of_char_func) - return add_axioms_from_char(expr); - else if(id==ID_cprover_string_of_char_array_func) - return add_axioms_from_char_array(expr); + res=add_axioms_from_char(expr); else if(id==ID_cprover_string_set_length_func) - return add_axioms_for_set_length(expr); + res=add_axioms_for_set_length(expr); else if(id==ID_cprover_string_delete_func) - return add_axioms_for_delete(expr); + res=add_axioms_for_delete(expr); else if(id==ID_cprover_string_delete_char_at_func) - return add_axioms_for_delete_char_at(expr); + res=add_axioms_for_delete_char_at(expr); else if(id==ID_cprover_string_replace_func) - return add_axioms_for_replace(expr); + res=add_axioms_for_replace(expr); + else if(id==ID_cprover_string_intern_func) + res=add_axioms_for_intern(expr); + else if(id==ID_cprover_string_array_of_char_pointer_func) + res=add_axioms_for_char_pointer(expr); else { std::string msg( @@ -328,29 +522,32 @@ exprt string_constraint_generatort::add_axioms_for_function_application( msg+=id2string(id); throw msg; } + function_application_cache[expr]=res; + return res; } /// add axioms to say that the returned string expression is equal to the /// argument of the function application /// \par parameters: function application with one argument, which is a string +/// or three arguments: string, integer offset and count /// \return a new string expression string_exprt string_constraint_generatort::add_axioms_for_copy( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 1)[0]); - const refined_string_typet &ref_type=to_refined_string_type(s1.type()); - string_exprt res=fresh_string(ref_type); - - // We add axioms: - // a1 : |res|=|s1| - // a2 : forall i<|s1|. s1[i]=res[i] - - axioms.push_back(res.axiom_for_has_same_length_as(s1)); - - symbol_exprt idx=fresh_univ_index("QA_index_copy", ref_type.get_index_type()); - string_constraintt a2(idx, s1.length(), equal_exprt(s1[idx], res[idx])); - axioms.push_back(a2); - return res; + const auto &args=f.arguments(); + if(args.size()==1) + { + string_exprt s1=get_string_expr(args[0]); + return s1; + } + else + { + assert(args.size()==3); + string_exprt s1=get_string_expr(args[0]); + exprt offset=args[1]; + exprt count=args[2]; + return add_axioms_for_substring(s1, offset, plus_exprt(offset, count)); + } } /// add axioms corresponding to the String.valueOf([C) java function @@ -370,13 +567,36 @@ string_exprt string_constraint_generatort::add_axioms_for_java_char_array( return res; } -/// add axioms corresponding to the String.length java function -/// \par parameters: function application with one string argument -/// \return a string expression of index type +/// for an expression of the form `array[0]` returns `array` +/// \par parameters: an expression of type char +/// \return an array expression +exprt string_constraint_generatort::add_axioms_for_char_pointer( + const function_application_exprt &fun) +{ + exprt char_pointer=args(fun, 1)[0]; + if(char_pointer.id()==ID_index) + return char_pointer.op0(); + // TODO: we do not know what to do in the other cases + assert(false); +} + +/*******************************************************************\ + +Function: string_constraint_generatort::add_axioms_for_length + + Inputs: function application with one string argument + + Outputs: a string expression of index type + + Purpose: add axioms corresponding to the String.length java function + +\*******************************************************************/ + +>>>>>>> bdbeaf586... Many corrections in string refinement exprt string_constraint_generatort::add_axioms_for_length( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 1)[0]); + string_exprt str=get_string_expr(args(f, 1)[0]); return str.length(); } @@ -393,6 +613,7 @@ string_exprt string_constraint_generatort::add_axioms_from_char_array( const exprt &offset, const exprt &count) { + assert(false); // deprecated, we should use add_axioms_for_substring instead const typet &char_type=to_array_type(data.type()).subtype(); const typet &index_type=length.type(); refined_string_typet ref_type(index_type, char_type); @@ -405,7 +626,7 @@ string_exprt string_constraint_generatort::add_axioms_from_char_array( symbol_exprt qvar=fresh_univ_index("QA_string_of_char_array", index_type); exprt char_in_tab=data; assert(char_in_tab.id()==ID_index); - char_in_tab.op1()=plus_exprt(qvar, offset); + char_in_tab.op1()=plus_exprt_with_overflow_check(qvar, offset); string_constraintt a1(qvar, count, equal_exprt(str[qvar], char_in_tab)); axioms.push_back(a1); @@ -422,6 +643,7 @@ string_exprt string_constraint_generatort::add_axioms_from_char_array( string_exprt string_constraint_generatort::add_axioms_from_char_array( const function_application_exprt &f) { + assert(false); // deprecated, we should use add_axioms_for_substring instead exprt offset; exprt count; if(f.arguments().size()==4) @@ -485,7 +707,7 @@ exprt string_constraint_generatort::add_axioms_for_char_literal( exprt string_constraint_generatort::add_axioms_for_char_at( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 2)[0]); + string_exprt str=get_string_expr(args(f, 2)[0]); const refined_string_typet &ref_type=to_refined_string_type(str.type()); symbol_exprt char_sym=fresh_symbol("char", ref_type.get_char_type()); axioms.push_back(equal_exprt(char_sym, str[args(f, 2)[1]])); @@ -498,18 +720,6 @@ exprt string_constraint_generatort::add_axioms_for_char_at( exprt string_constraint_generatort::add_axioms_for_to_char_array( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 1)[0]); + string_exprt str=get_string_expr(args(f, 1)[0]); return str.content(); } - -/// add a correspondence to make sure the symbol points to the same string as -/// the second argument -/// \par parameters: a symbol and a string -void string_constraint_generatort::set_string_symbol_equal_to_expr( - const symbol_exprt &sym, const exprt &str) -{ - if(str.id()==ID_symbol) - assign_to_symbol(sym, find_or_add_string_of_symbol(to_symbol_expr(str))); - else - assign_to_symbol(sym, add_axioms_for_string_expr(str)); -} diff --git a/src/solvers/refinement/string_constraint_generator_testing.cpp b/src/solvers/refinement/string_constraint_generator_testing.cpp index dc28a5198e9..16a9d4b3ea0 100644 --- a/src/solvers/refinement/string_constraint_generator_testing.cpp +++ b/src/solvers/refinement/string_constraint_generator_testing.cpp @@ -24,15 +24,15 @@ exprt string_constraint_generatort::add_axioms_for_is_prefix( // We add axioms: // a1 : isprefix => |str| >= |prefix|+offset - // a2 : forall 0<=qvar - // s0[witness+offset]=s2[witness] - // a3 : !isprefix => |str| < |prefix|+offset - // || (|str| >= |prefix|+offset &&0<=witness<|prefix| - // &&str[witness+ofsset]!=prefix[witness]) + // a2 : forall 0<=qvar<|prefix|. isprefix => s0[witness+offset]=s2[witness] + // a3 : !isprefix => + // |str|<|prefix|+offset || + // (0<=witness<|prefix| && str[witness+offset]!=prefix[witness]) implies_exprt a1( isprefix, - str.axiom_for_is_longer_than(plus_exprt(prefix.length(), offset))); + str.axiom_for_is_longer_than(plus_exprt_with_overflow_check( + prefix.length(), offset))); axioms.push_back(a1); symbol_exprt qvar=fresh_univ_index("QA_isprefix", index_type); @@ -40,7 +40,8 @@ exprt string_constraint_generatort::add_axioms_for_is_prefix( qvar, prefix.length(), isprefix, - equal_exprt(str[plus_exprt(qvar, offset)], prefix[qvar])); + equal_exprt(str[plus_exprt_with_overflow_check(qvar, offset)], + prefix[qvar])); axioms.push_back(a2); symbol_exprt witness=fresh_exist_index("witness_not_isprefix", index_type); @@ -48,14 +49,13 @@ exprt string_constraint_generatort::add_axioms_for_is_prefix( axiom_for_is_positive_index(witness), and_exprt( prefix.axiom_for_is_strictly_longer_than(witness), - notequal_exprt(str[plus_exprt(witness, offset)], prefix[witness]))); + notequal_exprt(str[plus_exprt_with_overflow_check(witness, offset)], + prefix[witness]))); or_exprt s0_notpref_s1( not_exprt( - str.axiom_for_is_longer_than(plus_exprt(prefix.length(), offset))), - and_exprt( - witness_diff, str.axiom_for_is_longer_than( - plus_exprt(prefix.length(), offset)))); + plus_exprt_with_overflow_check(prefix.length(), offset))), + witness_diff); implies_exprt a3(not_exprt(isprefix), s0_notpref_s1); axioms.push_back(a3); @@ -73,8 +73,8 @@ exprt string_constraint_generatort::add_axioms_for_is_prefix( { const function_application_exprt::argumentst &args=f.arguments(); assert(f.type()==bool_typet() || f.type().id()==ID_c_bool); - string_exprt s0=add_axioms_for_string_expr(args[swap_arguments?1:0]); - string_exprt s1=add_axioms_for_string_expr(args[swap_arguments?0:1]); + string_exprt s0=get_string_expr(args[swap_arguments?1:0]); + string_exprt s1=get_string_expr(args[swap_arguments?0:1]); exprt offset; if(args.size()==2) offset=from_integer(0, s0.length().type()); @@ -97,7 +97,7 @@ exprt string_constraint_generatort::add_axioms_for_is_empty( // a2 : s0 => is_empty symbol_exprt is_empty=fresh_boolean("is_empty"); - string_exprt s0=add_axioms_for_string_expr(args(f, 1)[0]); + string_exprt s0=get_string_expr(args(f, 1)[0]); axioms.push_back(implies_exprt(is_empty, s0.axiom_for_has_length(0))); axioms.push_back(implies_exprt(s0.axiom_for_has_length(0), is_empty)); return typecast_exprt(is_empty, f.type()); @@ -118,8 +118,8 @@ exprt string_constraint_generatort::add_axioms_for_is_suffix( symbol_exprt issuffix=fresh_boolean("issuffix"); typecast_exprt tc_issuffix(issuffix, f.type()); - string_exprt s0=add_axioms_for_string_expr(args[swap_arguments?1:0]); - string_exprt s1=add_axioms_for_string_expr(args[swap_arguments?0:1]); + string_exprt s0=get_string_expr(args[swap_arguments?1:0]); + string_exprt s1=get_string_expr(args[swap_arguments?0:1]); const typet &index_type=s0.length().type(); // We add axioms: @@ -127,7 +127,7 @@ exprt string_constraint_generatort::add_axioms_for_is_suffix( // a2 : forall witness s1[witness]=s0[witness + s0.length-s1.length] // a3 : !issuffix => - // s1.length > s0.length + // (s1.length > s0.length && witness=-1) // || (s1.length > witness>=0 // &&s1[witness]!=s0[witness + s0.length-s1.length] @@ -145,7 +145,8 @@ exprt string_constraint_generatort::add_axioms_for_is_suffix( exprt shifted=plus_exprt( witness, minus_exprt(s1.length(), s0.length())); or_exprt constr3( - s0.axiom_for_is_strictly_longer_than(s1), + and_exprt(s0.axiom_for_is_strictly_longer_than(s1), + equal_exprt(witness, from_integer(-1, index_type))), and_exprt( notequal_exprt(s0[witness], s1[shifted]), and_exprt( @@ -166,9 +167,10 @@ exprt string_constraint_generatort::add_axioms_for_contains( assert(f.type()==bool_typet() || f.type().id()==ID_c_bool); symbol_exprt contains=fresh_boolean("contains"); typecast_exprt tc_contains(contains, f.type()); - string_exprt s0=add_axioms_for_string_expr(args(f, 2)[0]); - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[1]); - const typet &index_type=s0.type(); + string_exprt s0=get_string_expr(args(f, 2)[0]); + string_exprt s1=get_string_expr(args(f, 2)[1]); + const refined_string_typet ref_type=to_refined_string_type(s0.type()); + const typet &index_type=ref_type.get_index_type(); // We add axioms: // a1 : contains => s0.length >= s1.length diff --git a/src/solvers/refinement/string_constraint_generator_transformation.cpp b/src/solvers/refinement/string_constraint_generator_transformation.cpp index 01395b25cc1..6db591e8cf4 100644 --- a/src/solvers/refinement/string_constraint_generator_transformation.cpp +++ b/src/solvers/refinement/string_constraint_generator_transformation.cpp @@ -24,7 +24,7 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com string_exprt string_constraint_generatort::add_axioms_for_set_length( const function_application_exprt &f) { - string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); + string_exprt s1=get_string_expr(args(f, 2)[0]); exprt k=args(f, 2)[1]; const refined_string_typet &ref_type=to_refined_string_type(s1.type()); string_exprt res=fresh_string(ref_type); @@ -63,7 +63,7 @@ string_exprt string_constraint_generatort::add_axioms_for_substring( { const function_application_exprt::argumentst &args=f.arguments(); assert(args.size()>=2); - string_exprt str=add_axioms_for_string_expr(args[0]); + string_exprt str=get_string_expr(args[0]); exprt i(args[1]); exprt j; if(args.size()==3) @@ -89,7 +89,6 @@ string_exprt string_constraint_generatort::add_axioms_for_substring( { const refined_string_typet &ref_type=to_refined_string_type(str.type()); const typet &index_type=ref_type.get_index_type(); - symbol_exprt idx=fresh_exist_index("index_substring", index_type); assert(start.type()==index_type); assert(end.type()==index_type); string_exprt res=fresh_string(ref_type); @@ -112,8 +111,11 @@ string_exprt string_constraint_generatort::add_axioms_for_substring( // Warning: check what to do if the string is not long enough axioms.push_back(str.axiom_for_is_longer_than(end)); - string_constraintt a4( - idx, res.length(), equal_exprt(res[idx], str[plus_exprt(start, idx)])); + symbol_exprt idx=fresh_univ_index("QA_index_substring", index_type); + string_constraintt a4(idx, + res.length(), + equal_exprt(res[idx], + str[plus_exprt_with_overflow_check(start, idx)])); axioms.push_back(a4); return res; } @@ -124,7 +126,7 @@ string_exprt string_constraint_generatort::add_axioms_for_substring( string_exprt string_constraint_generatort::add_axioms_for_trim( const function_application_exprt &expr) { - string_exprt str=add_axioms_for_string_expr(args(expr, 1)[0]); + string_exprt str=get_string_expr(args(expr, 1)[0]); const refined_string_typet &ref_type=to_refined_string_type(str.type()); const typet &index_type=ref_type.get_index_type(); string_exprt res=fresh_string(ref_type); @@ -143,7 +145,8 @@ string_exprt string_constraint_generatort::add_axioms_for_trim( // a8 : forall n<|s1|, s[idx+n]=s1[n] // a9 : (s[m]>' ' &&s[m+|s1|-1]>' ') || m=|s| - exprt a1=str.axiom_for_is_longer_than(plus_exprt(idx, res.length())); + exprt a1=str.axiom_for_is_longer_than( + plus_exprt_with_overflow_check(idx, res.length())); axioms.push_back(a1); binary_relation_exprt a2(idx, ID_ge, from_integer(0, index_type)); @@ -165,7 +168,8 @@ string_exprt string_constraint_generatort::add_axioms_for_trim( axioms.push_back(a6); symbol_exprt n2=fresh_univ_index("QA_index_trim2", index_type); - minus_exprt bound(str.length(), plus_exprt(idx, res.length())); + minus_exprt bound(str.length(), plus_exprt_with_overflow_check(idx, + res.length())); binary_relation_exprt eqn2( str[plus_exprt(idx, plus_exprt(res.length(), n2))], ID_le, @@ -180,7 +184,8 @@ string_exprt string_constraint_generatort::add_axioms_for_trim( axioms.push_back(a8); minus_exprt index_before( - plus_exprt(idx, res.length()), from_integer(1, index_type)); + plus_exprt_with_overflow_check(idx, res.length()), + from_integer(1, index_type)); binary_relation_exprt no_space_before(str[index_before], ID_gt, space_char); or_exprt a9( equal_exprt(idx, str.length()), @@ -197,7 +202,7 @@ string_exprt string_constraint_generatort::add_axioms_for_trim( string_exprt string_constraint_generatort::add_axioms_for_to_lower_case( const function_application_exprt &expr) { - string_exprt str=add_axioms_for_string_expr(args(expr, 1)[0]); + string_exprt str=get_string_expr(args(expr, 1)[0]); const refined_string_typet &ref_type=to_refined_string_type(str.type()); const typet &char_type=ref_type.get_char_type(); const typet &index_type=ref_type.get_index_type(); @@ -241,7 +246,7 @@ string_exprt string_constraint_generatort::add_axioms_for_to_lower_case( string_exprt string_constraint_generatort::add_axioms_for_to_upper_case( const function_application_exprt &expr) { - string_exprt str=add_axioms_for_string_expr(args(expr, 1)[0]); + string_exprt str=get_string_expr(args(expr, 1)[0]); const refined_string_typet &ref_type=to_refined_string_type(str.type()); const typet &char_type=ref_type.get_char_type(); const typet &index_type=ref_type.get_index_type(); @@ -288,7 +293,7 @@ string_exprt string_constraint_generatort::add_axioms_for_to_upper_case( string_exprt string_constraint_generatort::add_axioms_for_char_set( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 3)[0]); + string_exprt str=get_string_expr(args(f, 3)[0]); const refined_string_typet &ref_type=to_refined_string_type(str.type()); string_exprt res=fresh_string(ref_type); with_exprt sarrnew(str.content(), args(f, 3)[1], args(f, 3)[2]); @@ -313,7 +318,7 @@ string_exprt string_constraint_generatort::add_axioms_for_char_set( string_exprt string_constraint_generatort::add_axioms_for_replace( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 3)[0]); + string_exprt str=get_string_expr(args(f, 3)[0]); const refined_string_typet &ref_type=to_refined_string_type(str.type()); const exprt &old_char=args(f, 3)[1]; const exprt &new_char=args(f, 3)[2]; @@ -347,10 +352,12 @@ string_exprt string_constraint_generatort::add_axioms_for_replace( string_exprt string_constraint_generatort::add_axioms_for_delete_char_at( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 2)[0]); + string_exprt str=get_string_expr(args(f, 2)[0]); exprt index_one=from_integer(1, str.length().type()); return add_axioms_for_delete( - str, args(f, 2)[1], plus_exprt(args(f, 2)[1], index_one)); + str, + args(f, 2)[1], + plus_exprt_with_overflow_check(args(f, 2)[1], index_one)); } /// add axioms stating that the returned string corresponds to the input one @@ -376,6 +383,6 @@ string_exprt string_constraint_generatort::add_axioms_for_delete( string_exprt string_constraint_generatort::add_axioms_for_delete( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 3)[0]); + string_exprt str=get_string_expr(args(f, 3)[0]); return add_axioms_for_delete(str, args(f, 3)[1], args(f, 3)[2]); } diff --git a/src/solvers/refinement/string_constraint_generator_valueof.cpp b/src/solvers/refinement/string_constraint_generator_valueof.cpp index 6fe11ca6c18..5d9900264d6 100644 --- a/src/solvers/refinement/string_constraint_generator_valueof.cpp +++ b/src/solvers/refinement/string_constraint_generator_valueof.cpp @@ -40,7 +40,8 @@ string_exprt string_constraint_generatort::add_axioms_from_long( string_exprt string_constraint_generatort::add_axioms_from_float( const function_application_exprt &f) { - return add_axioms_from_float(args(f, 1)[0], false); + const refined_string_typet &ref_type=to_refined_string_type(f.type()); + return add_axioms_from_float(args(f, 1)[0], ref_type, false); } /// add axioms corresponding to the String.valueOf(D) java function @@ -49,7 +50,8 @@ string_exprt string_constraint_generatort::add_axioms_from_float( string_exprt string_constraint_generatort::add_axioms_from_double( const function_application_exprt &f) { - return add_axioms_from_float(args(f, 1)[0], true); + const refined_string_typet &ref_type=to_refined_string_type(f.type()); + return add_axioms_from_float(args(f, 1)[0], ref_type, true); } /// add axioms corresponding to the String.valueOf(F) java function Warning: we @@ -59,13 +61,12 @@ string_exprt string_constraint_generatort::add_axioms_from_double( /// double precision /// \return a new string expression string_exprt string_constraint_generatort::add_axioms_from_float( - const exprt &f, bool double_precision) + const exprt &f, const refined_string_typet &ref_type, bool double_precision) { - const refined_string_typet &ref_type=to_refined_string_type(f.type()); + string_exprt res=fresh_string(ref_type); const typet &index_type=ref_type.get_index_type(); const typet &char_type=ref_type.get_char_type(); - string_exprt res=fresh_string(ref_type); - const exprt &index24=from_integer(24, ref_type.get_index_type()); + const exprt &index24=from_integer(24, index_type); axioms.push_back(res.axiom_for_is_shorter_than(index24)); string_exprt magnitude=fresh_string(ref_type); @@ -247,13 +248,22 @@ string_exprt string_constraint_generatort::add_axioms_from_int( axioms.push_back(a1); exprt chr=res[0]; - exprt starts_with_minus=equal_exprt(chr, minus_char); - exprt starts_with_digit=and_exprt( + equal_exprt starts_with_minus(chr, minus_char); + and_exprt starts_with_digit( binary_relation_exprt(chr, ID_ge, zero_char), binary_relation_exprt(chr, ID_le, nine_char)); or_exprt a2(starts_with_digit, starts_with_minus); axioms.push_back(a2); + // These are constraints to detect number that requiere the maximum number + // of digits + exprt smallest_with_max_digits= + from_integer(smallest_by_digit(max_size-1), type); + binary_relation_exprt big_negative( + i, ID_le, unary_minus_exprt(smallest_with_max_digits)); + binary_relation_exprt big_positive(i, ID_ge, smallest_with_max_digits); + or_exprt requieres_max_digits(big_negative, big_positive); + for(size_t size=1; size<=max_size; size++) { // For each possible size, we add axioms: @@ -311,13 +321,18 @@ string_exprt string_constraint_generatort::add_axioms_from_int( axioms.push_back(a6); } - // we have to be careful when exceeding the maximal size of integers + // when the size is close to the maximum, either the number is very big + // or it is negative + if(size==max_size-1) + { + implies_exprt a7(premise, or_exprt(requieres_max_digits, + starts_with_minus)); + axioms.push_back(a7); + } + // when we reach the maximal size the number is very big in the negative if(size==max_size) { - exprt smallest_with_10_digits=from_integer( - smallest_by_digit(max_size), type); - binary_relation_exprt big(i, ID_ge, smallest_with_10_digits); - implies_exprt a7(premise, big); + implies_exprt a7(premise, and_exprt(starts_with_minus, big_negative)); axioms.push_back(a7); } } @@ -466,13 +481,68 @@ string_exprt string_constraint_generatort::add_axioms_for_value_of( } } -/// add axioms corresponding to the Integer.parseInt java function +/// add axioms making the return value true if the given string is +/// a correct number /// \par parameters: function application with one string expression -/// \return an integer expression +/// \return an boolean expression +exprt string_constraint_generatort::add_axioms_for_correct_number_format( + const string_exprt &str, std::size_t max_size) +{ + symbol_exprt correct=fresh_boolean("correct_number_format"); + const refined_string_typet &ref_type=to_refined_string_type(str.type()); + const typet &char_type=ref_type.get_char_type(); + const typet &index_type=ref_type.get_index_type(); + exprt zero_char=constant_char('0', char_type); + exprt nine_char=constant_char('9', char_type); + exprt minus_char=constant_char('-', char_type); + exprt plus_char=constant_char('+', char_type); + + exprt chr=str[0]; + equal_exprt starts_with_minus(chr, minus_char); + equal_exprt starts_with_plus(chr, plus_char); + and_exprt starts_with_digit( + binary_relation_exprt(chr, ID_ge, zero_char), + binary_relation_exprt(chr, ID_le, nine_char)); + + or_exprt correct_first( + or_exprt(starts_with_minus, starts_with_plus), starts_with_digit); + exprt has_first=str.axiom_for_is_longer_than(from_integer(1, index_type)); + implies_exprt a1(correct, and_exprt(has_first, correct_first)); + axioms.push_back(a1); + + exprt not_too_long=str.axiom_for_is_shorter_than(max_size); + axioms.push_back(not_too_long); + + symbol_exprt qvar=fresh_univ_index("number_format", index_type); + + and_exprt is_digit( + binary_relation_exprt(str[qvar], ID_ge, zero_char), + binary_relation_exprt(str[qvar], ID_le, nine_char)); + + string_constraintt a2( + qvar, from_integer(1, index_type), str.length(), correct, is_digit); + + axioms.push_back(a2); + return correct; +} + +/*******************************************************************\ + +Function: string_constraint_generatort::add_axioms_for_parse_int + + Inputs: function application with one string expression + + Outputs: an integer expression + + Purpose: add axioms corresponding to the Integer.parseInt java function + +\*******************************************************************/ + +>>>>>>> bdbeaf586... Many corrections in string refinement exprt string_constraint_generatort::add_axioms_for_parse_int( const function_application_exprt &f) { - string_exprt str=add_axioms_for_string_expr(args(f, 1)[0]); + string_exprt str=get_string_expr(args(f, 1)[0]); const typet &type=f.type(); symbol_exprt i=fresh_symbol("parsed_int", type); const refined_string_typet &ref_type=to_refined_string_type(str.type()); @@ -488,6 +558,10 @@ exprt string_constraint_generatort::add_axioms_for_parse_int( exprt starts_with_plus=equal_exprt(chr, plus_char); exprt starts_with_digit=binary_relation_exprt(chr, ID_ge, zero_char); + // TODO: we should throw an exception when this does not hold: + exprt correct=add_axioms_for_correct_number_format(str); + axioms.push_back(correct); + for(unsigned size=1; size<=10; size++) { exprt sum=from_integer(0, type); diff --git a/src/solvers/refinement/string_refinement.cpp b/src/solvers/refinement/string_refinement.cpp index 36f619b8add..20fdaf971f6 100644 --- a/src/solvers/refinement/string_refinement.cpp +++ b/src/solvers/refinement/string_refinement.cpp @@ -18,42 +18,114 @@ Author: Alberto Griggio, alberto.griggio@gmail.com /// Ghosh. #include +#include #include #include #include +#include +#include #include #include #include +#include + +/*******************************************************************\ + +Constructor: string_refinementt + + Inputs: a namespace, a decision procedure, a bound on the number + of refinements and a boolean flag `concretize_result` + + Purpose: refinement_bound is a bound on the number of refinement allowed. + if `concretize_result` is set to true, at the end of the decision + procedure, the solver try to find a concrete value for each + character + +\*******************************************************************/ string_refinementt::string_refinementt( - const namespacet &_ns, propt &_prop, unsigned refinement_bound): + const namespacet &_ns, + propt &_prop, + unsigned refinement_bound): supert(_ns, _prop), use_counter_example(false), - initial_loop_bound(refinement_bound) + do_concretizing(false), + initial_loop_bound(refinement_bound), + non_empty_string(false) { } -/// determine which language should be used -void string_refinementt::set_mode() +/*******************************************************************\ + +Function: string_refinementt::set_max_string_length + + Inputs: + i - maximum length which is allowed for strings. + by default the strings length has no other limit + than the maximal integer according to the type of their + length, for instance 2^31-1 for Java. + + Purpose: Add constraints on the size of strings used in the + program. + +\*******************************************************************/ + +void string_refinementt::set_max_string_length(size_t i) { - debug() << "initializing mode" << eom; - symbolt init=ns.lookup(irep_idt(CPROVER_PREFIX"initialize")); - irep_idt mode=init.mode; - debug() << "mode detected as " << mode << eom; - generator.set_mode(mode); + generator.max_string_length=i; +} + +/*******************************************************************\ + +Function: string_refinementt::set_max_string_length + + Purpose: Add constraints on the size of nondet character arrays + to ensure they have length at least 1 + +\*******************************************************************/ + +void string_refinementt::enforce_non_empty_string() +{ + non_empty_string=true; +} + +/*******************************************************************\ + +Function: string_refinementt::enforce_printable_characters + + Purpose: Add constraints on characters used in the program + to ensure they are printable + +\*******************************************************************/ + +void string_refinementt::enforce_printable_characters() +{ + generator.force_printable_characters=true; } /// display the current index set, for debugging void string_refinementt::display_index_set() { + std::size_t count=0; + std::size_t count_current=0; for(const auto &i : index_set) { const exprt &s=i.first; - debug() << "IS(" << from_expr(s) << ")=={"; + debug() << "IS(" << from_expr(s) << ")=={" << eom; for(auto j : i.second) - debug() << from_expr(j) << "; "; + { + if(current_index_set[i.first].find(j)!=current_index_set[i.first].end()) + { + count_current++; + debug() << "**"; + } + debug() << " " << from_expr(j) << ";" << eom; + count++; + } debug() << "}" << eom; } + debug() << count << " elements in index set (" << count_current + << " newly added)" << eom; } /// compute the index set for all formulas, instantiate the formulas with the @@ -86,115 +158,330 @@ void string_refinementt::add_instantiations() /// if the expression is a function application, we convert it using our own /// convert_function_application method -/// \par parameters: an expression -/// \return a literal -literalt string_refinementt::convert_rest(const exprt &expr) +/// keeps a map of symbols to expressions, such as none of the mapped +/// values exist as a key +/// \par parameters: a symbol and the expression to map it to +void string_refinementt::add_symbol_to_symbol_map +(const exprt &lhs, const exprt &rhs) { - if(expr.id()==ID_function_application) + assert(lhs.id()==ID_symbol); + + // We insert the mapped value of the rhs, if it exists. + auto it=symbol_resolve.find(rhs); + const exprt &new_rhs=it!=symbol_resolve.end()?it->second:rhs; + + symbol_resolve[lhs]=new_rhs; + reverse_symbol_resolve[new_rhs].push_back(lhs); + + std::list symbols_to_update_with_new_rhs(reverse_symbol_resolve[rhs]); + for(exprt item : symbols_to_update_with_new_rhs) { - // can occur in __CPROVER_assume - bvt bv=convert_function_application(to_function_application_expr(expr)); - assert(bv.size()==1); - return bv[0]; + symbol_resolve[item]=new_rhs; + reverse_symbol_resolve[new_rhs].push_back(item); } - else +} + +/*******************************************************************\ + +Function: string_refinementt::set_char_array_equality() + + Inputs: the rhs and lhs of an equality over character arrays + + Purpose: add axioms if the rhs is a character array + +\*******************************************************************/ + +void string_refinementt::set_char_array_equality( + const exprt &lhs, const exprt &rhs) +{ + assert(lhs.id()==ID_symbol); + + if(rhs.id()==ID_array && rhs.type().id()==ID_array) { - return supert::convert_rest(expr); + const typet &index_type=to_array_type(rhs.type()).size().type(); + for(size_t i=0, ilim=rhs.operands().size(); i!=ilim; ++i) + { + // Introduce axioms to map symbolic rhs to its char array. + index_exprt arraycell(rhs, from_integer(i, index_type)); + equal_exprt arrayeq(arraycell, rhs.operands()[i]); + add_lemma(arrayeq, false); +#if 0 + generator.axioms.push_back(arrayeq); +#endif + } } + // At least for Java (as it is currently pre-processed), we need not consider + // other cases, because all character arrays find themselves on the rhs of an + // equality. Note that this might not be the case for other languages. } -/// if the expression as string type, look up for the string in the list of -/// string symbols that we maintain, and convert it; otherwise use the method of -/// the parent class -/// \par parameters: an expression -/// \return a bitvector -bvt string_refinementt::convert_symbol(const exprt &expr) +/// remove functions applications and create the necessary axioms +/// \par parameters: an expression containing function applications +/// \return an epression containing no function application +exprt string_refinementt::substitute_function_applications(exprt expr) { - const typet &type=expr.type(); - const irep_idt &identifier=expr.get(ID_identifier); - assert(!identifier.empty()); + for(size_t i=0; igenerator.max_string_length? + generator.max_string_length:concretize_limit; + exprt content_expr=str.content(); + for(size_t i=0; i &pair : non_string_axioms) + { + replace_expr(symbol_resolve, pair.first); + debug() << "super::set_to " << from_expr(pair.first) << eom; + supert::set_to(pair.first, pair.second); + } + + for(exprt &axiom : generator.axioms) + { + replace_expr(symbol_resolve, axiom); if(axiom.id()==ID_string_constraint) { string_constraintt c=to_string_constraint(axiom); @@ -223,6 +521,7 @@ decision_proceduret::resultt string_refinementt::dec_solve() { add_lemma(axiom); } + } initial_index_set(universal_axioms); update_index_set(cur); @@ -243,6 +542,7 @@ decision_proceduret::resultt string_refinementt::dec_solve() else { debug() << "check_SAT: the model is correct" << eom; + concretize_lengths(); return D_SATISFIABLE; } @@ -259,7 +559,13 @@ decision_proceduret::resultt string_refinementt::dec_solve() if(current_index_set.empty()) { debug() << "current index set is empty" << eom; - return D_SATISFIABLE; + if(do_concretizing) + { + concretize_results(); + do_concretizing=false; + } + else + return D_SATISFIABLE; } display_index_set(); @@ -294,148 +600,477 @@ bvt string_refinementt::convert_bool_bv(const exprt &boole, const exprt &orig) return ret; } -/// add the given lemma to the solver -/// \par parameters: a lemma -void string_refinementt::add_lemma(const exprt &lemma, bool add_to_index_set) +/*******************************************************************\ + +Function: string_refinementt::add_lemma + + Inputs: a lemma and Boolean value stating whether the lemma should + be added to the index set. + + Purpose: add the given lemma to the solver + +\*******************************************************************/ + +void string_refinementt::add_lemma( + const exprt &lemma, bool _simplify, bool add_to_index_set) { if(!seen_instances.insert(lemma).second) return; - if(lemma.is_true()) + if(add_to_index_set) + cur.push_back(lemma); + + exprt simple_lemma=lemma; + if(_simplify) + simplify(simple_lemma, ns); + + if(simple_lemma.is_true()) { +#if 0 debug() << "string_refinementt::add_lemma : tautology" << eom; +#endif return; } - debug() << "adding lemma " << from_expr(lemma) << eom; + debug() << "adding lemma " << from_expr(simple_lemma) << eom; - prop.l_set_to_true(convert(lemma)); - if(add_to_index_set) - cur.push_back(lemma); + prop.l_set_to_true(convert(simple_lemma)); } -/// convert the content of a string to a more readable representation. This -/// should only be used for debbuging. -/// \par parameters: a constant array expression and a integer expression -/// \return a string -std::string string_refinementt::string_of_array( - const exprt &arr, const exprt &size) const +/*******************************************************************\ + +Function: string_refinementt::get_array + + Inputs: an expression representing an array and an expression + representing an integer + + Outputs: an array expression or an array_of_exprt + + Purpose: get a model of an array and put it in a certain form. + If the size cannot be obtained or if it is too big, return an + empty array. + +\*******************************************************************/ + +exprt string_refinementt::get_array(const exprt &arr, const exprt &size) const { - if(size.id()!=ID_constant) - return "string of unknown size"; + exprt arr_val=get_array(arr); + exprt size_val=supert::get(size); + size_val=simplify_expr(size_val, ns); + typet char_type=arr.type().subtype(); + typet index_type=size.type(); + array_typet empty_ret_type(char_type, from_integer(0, index_type)); + array_of_exprt empty_ret(from_integer(0, char_type), empty_ret_type); + + if(size_val.id()!=ID_constant) + { +#if 0 + debug() << "(sr::get_array) string of unknown size: " + << from_expr(size_val) << eom; +#endif + return empty_ret; + } + unsigned n; - if(to_unsigned_integer(to_constant_expr(size), n)) - n=0; + if(to_unsigned_integer(to_constant_expr(size_val), n)) + { +#if 0 + debug() << "(sr::get_array) size is not valid" << eom; +#endif + return empty_ret; + } + + array_typet ret_type(char_type, from_integer(n, index_type)); + array_exprt ret(ret_type); + + if(n>generator.max_string_length) + { +#if 0 + debug() << "(sr::get_array) long string (size=" << n << ")" << eom; +#endif + return empty_ret; + } - if(n>MAX_CONCRETE_STRING_SIZE) - return "very long string"; if(n==0) - return "\"\""; + { +#if 0 + debug() << "(sr::get_array) empty string" << eom; +#endif + return empty_ret; + } - std::ostringstream buf; - buf << "\""; - exprt val=get(arr); + std::vector concrete_array(n); - if(val.id()=="array-list") + if(arr_val.id()=="array-list") { - for(size_t i=0; i(c); + exprt value=arr_val.operands()[i*2+1]; + to_unsigned_integer(to_constant_expr(value), concrete_array[idx]); } } } } + else if(arr_val.id()==ID_array) + { + for(size_t i=0; i=32) + result << (unsigned char) c; + else + { + result << "\\u" << std::hex << std::setw(4) << std::setfill('0') + << (unsigned int) c; + } + } + + return result.str(); +} + +/*******************************************************************\ + +Function: string_refinementt::fill_model + + Purpose: Fill in `current_model` by mapping the variables created by + the solver to constant expressions given by the current model + +\*******************************************************************/ - for(size_t i=0; i violated; @@ -444,21 +1079,28 @@ bool string_refinementt::check_axioms() for(size_t i=0; i string_refinementt::map_representation_of_sum( /// times given by the corresponding integer in the map. For a map x -> 2, y /// -> -1 would give an expression $x + x - y$. exprt string_refinementt::sum_over_map( - std::map &m, bool negated) const + std::map &m, const typet &type, bool negated) const { exprt sum=nil_exprt(); mp_integer constants=0; typet index_type; if(m.empty()) - return nil_exprt(); + return from_integer(0, type); else index_type=m.begin()->first.type(); @@ -604,12 +1245,20 @@ exprt string_refinementt::sum_over_map( default: if(second>1) { - for(int i=0; isecond; i--) + if(sum.is_nil()) + sum=unary_minus_exprt(t); + else + sum=minus_exprt(sum, t); + for(int i=-1; i>second; i--) sum=minus_exprt(sum, t); } } @@ -628,7 +1277,7 @@ exprt string_refinementt::sum_over_map( exprt string_refinementt::simplify_sum(const exprt &f) const { std::map map=map_representation_of_sum(f); - return sum_over_map(map); + return sum_over_map(map, f.type()); } /// \par parameters: a symbol qvar, an expression val, an expression f @@ -665,7 +1314,7 @@ exprt string_refinementt::compute_inverse_function( } elems.erase(it); - return sum_over_map(elems, neg); + return sum_over_map(elems, f.type(), neg); } @@ -687,9 +1336,18 @@ class find_qvar_visitort: public const_expr_visitort } }; -/// looks for the symbol and return true if it is found -/// \par parameters: an index expression and a symbol qvar -/// \return a Boolean +/*******************************************************************\ + +Function: find_qvar + + Inputs: an index expression and a symbol qvar + + Outputs: a Boolean + + Purpose: look for the symbol and return true if it is found + +\*******************************************************************/ + static bool find_qvar(const exprt index, const symbol_exprt &qvar) { find_qvar_visitort v2(qvar); @@ -715,9 +1373,37 @@ void string_refinementt::update_index_set(const std::vector &cur) update_index_set(axiom); } -/// add to the index set all the indices that appear in the formula and the -/// upper bound minus one -/// \par parameters: a string constraint +/*******************************************************************\ + +Function: string_refinementt::initial_index_set + + Inputs: a string constraint + + Purpose: add to the index set all the indices that appear in the formula + and the upper bound minus one + +\*******************************************************************/ +void string_refinementt::add_to_index_set(const exprt &s, exprt i) +{ + simplify(i, ns); + if(i.id()==ID_constant) + { + mp_integer mpi; + to_integer(i, mpi); + if(mpi<0) + { + debug() << "add_to_index_set : ignoring negative number " << mpi << eom; + return; + } + } + if(index_set[s].insert(i).second) + { + debug() << "adding to index set of " << from_expr(s) + << ": " << from_expr(i) << eom; + current_index_set[s].insert(i); + } +} + void string_refinementt::initial_index_set(const string_constraintt &axiom) { symbol_exprt qvar=axiom.univ_var(); @@ -738,8 +1424,7 @@ void string_refinementt::initial_index_set(const string_constraintt &axiom) // if cur is of the form s[i] and no quantified variable appears in i if(!has_quant_var) { - current_index_set[s].insert(i); - index_set[s].insert(i); + add_to_index_set(s, i); } else { @@ -749,8 +1434,7 @@ void string_refinementt::initial_index_set(const string_constraintt &axiom) axiom.upper_bound(), from_integer(1, axiom.upper_bound().type())); replace_expr(qvar, kminus1, e); - current_index_set[s].insert(e); - index_set[s].insert(e); + add_to_index_set(s, e); } } else @@ -776,12 +1460,7 @@ void string_refinementt::update_index_set(const exprt &formula) const exprt &i=cur.op1(); assert(s.type().id()==ID_array); exprt simplified=simplify_sum(i); - if(index_set[s].insert(simplified).second) - { - debug() << "adding to index set of " << from_expr(s) - << ": " << from_expr(simplified) << eom; - current_index_set[s].insert(simplified); - } + add_to_index_set(s, simplified); } else { @@ -828,14 +1507,21 @@ exprt find_index(const exprt &expr, const exprt &str) catch (exprt i) { return i; } } +/*******************************************************************\ + +Function: string_refinementt::instantiate + + Inputs: a universally quantified formula `axiom`, an array of char + variable `str`, and an index expression `val`. + + Outputs: substitute `qvar` the universally quantified variable of `axiom`, by + an index `val`, in `axiom`, so that the index used for `str` equals + `val`. For instance, if `axiom` corresponds to + $\forall q. s[q+x]='a' && t[q]='b'$, `instantiate(axom,s,v)` + would return an expression for $s[v]='a' && t[v-x]='b'$. + +\*******************************************************************/ -/// \par parameters: an universaly quantified formula `axiom`, an array of char -/// variable `str`, and an index expression `val`. -/// \return substitute `qvar` the universaly quantified variable of `axiom`, by -/// an index `val`, in `axiom`, so that the index used for `str` equals `val`. -/// For instance, if `axiom` corresponds to $\forall q. s[q+x]='a' && -/// t[q]='b'$, `instantiate(axom,s,v)` would return an expression for -/// $s[v]='a' && t[v-x]='b'$. exprt string_refinementt::instantiate( const string_constraintt &axiom, const exprt &str, const exprt &val) { @@ -857,6 +1543,17 @@ exprt string_refinementt::instantiate( return implies_exprt(bounds, instance); } +/*******************************************************************\ + +Function: string_refinementt::instantiate_not_contains + + Inputs: a quantified formula representing `not_contains`, and a + list to which to add the created lemmas to + + Purpose: instantiate a quantified formula representing `not_contains` + by substituting the quantifiers and generating axioms + +\*******************************************************************/ void string_refinementt::instantiate_not_contains( const string_not_contains_constraintt &axiom, std::list &new_lemmas) @@ -908,3 +1605,76 @@ void string_refinementt::instantiate_not_contains( new_lemmas.push_back(witness_bounds); } } + +/*******************************************************************\ + +Function: string_refinementt::substitute_array_lists() + + Inputs: an expression containing array-list expressions + + Outputs: an epression containing no array-list + + Purpose: replace array-lists by 'with' expressions + +\*******************************************************************/ + +exprt string_refinementt::substitute_array_lists(exprt expr) const +{ + for(size_t i=0; i=2); + typet &char_type=expr.operands()[1].type(); + array_typet arr_type(char_type, infinity_exprt(char_type)); + array_of_exprt new_arr(from_integer(0, char_type), + arr_type); + + with_exprt ret_expr(new_arr, + expr.operands()[0], + expr.operands()[1]); + + for(size_t i=2; isecond); + } + + ecopy=supert::get(ecopy); + + return substitute_array_lists(ecopy); +} diff --git a/src/solvers/refinement/string_refinement.h b/src/solvers/refinement/string_refinement.h index aa28f8a0c96..d4f7cba7c01 100644 --- a/src/solvers/refinement/string_refinement.h +++ b/src/solvers/refinement/string_refinement.h @@ -2,7 +2,7 @@ Module: String support via creating string constraints and progressively instantiating the universal constraints as needed. - The procedure is described in the PASS paper at HVC'13: + The procedure is described in the PASS paper at HVC'13: "PASS: String Solving with Parameterized Array and Interval Automaton" by Guodong Li and Indradeep Ghosh @@ -21,43 +21,46 @@ Author: Alberto Griggio, alberto.griggio@gmail.com #define CPROVER_SOLVERS_REFINEMENT_STRING_REFINEMENT_H #include +#include #include #include -// Defines a limit on the string witnesses we will output. -// Longer strings are still concidered possible by the solver but -// it will not output them. -#define MAX_CONCRETE_STRING_SIZE 500 - #define MAX_NB_REFINEMENT 100 class string_refinementt: public bv_refinementt { public: - // refinement_bound is a bound on the number of refinement allowed string_refinementt( - const namespacet &_ns, propt &_prop, unsigned refinement_bound); + const namespacet &_ns, + propt &_prop, + unsigned refinement_bound); void set_mode(); // Should we use counter examples at each iteration? bool use_counter_example; - virtual std::string decision_procedure_text() const + // Should we concretize strings when the solver finished + bool do_concretizing; + + void set_max_string_length(size_t i); + void enforce_non_empty_string(); + void enforce_printable_characters(); + + virtual std::string decision_procedure_text() const override { return "string refinement loop with "+prop.solver_text(); } static exprt is_positive(const exprt &x); + exprt get(const exprt &expr) const override; + protected: typedef std::set expr_sett; + typedef std::list exprt_listt; - virtual bvt convert_symbol(const exprt &expr); - virtual bvt convert_function_application( - const function_application_exprt &expr); - - decision_proceduret::resultt dec_solve(); + decision_proceduret::resultt dec_solve() override; bvt convert_bool_bv(const exprt &boole, const exprt &orig); @@ -69,6 +72,9 @@ class string_refinementt: public bv_refinementt string_constraint_generatort generator; + bool non_empty_string; + expr_sett nondet_arrays; + // Simple constraints that have been given to the solver expr_sett seen_instances; @@ -83,23 +89,44 @@ class string_refinementt: public bv_refinementt // Warning: this is indexed by array_expressions and not string expressions std::map current_index_set; std::map index_set; + replace_mapt symbol_resolve; + std::map reverse_symbol_resolve; + std::list> non_string_axioms; - void display_index_set(); + // Valuation in the current model of the symbols that have been created + // by the solver + replace_mapt current_model; - void add_lemma(const exprt &lemma, bool add_to_index_set=true); + void add_equivalence(const irep_idt & lhs, const exprt & rhs); - bool boolbv_set_equality_to_true(const equal_exprt &expr); + void display_index_set(); - literalt convert_rest(const exprt &expr); + void add_lemma(const exprt &lemma, + bool simplify=true, + bool add_to_index_set=true); - void add_instantiations(); + exprt substitute_function_applications(exprt expr); + typet substitute_java_string_types(typet type); + exprt substitute_java_strings(exprt expr); + exprt substitute_array_with_expr(const exprt &expr, const exprt &index) const; + void substitute_array_access(exprt &expr) const; + void add_symbol_to_symbol_map(const exprt &lhs, const exprt &rhs); + bool is_char_array(const typet &type) const; + bool add_axioms_for_string_assigns(const exprt &lhs, const exprt &rhs); + void set_to(const exprt &expr, bool value) override; + void add_instantiations(); + void add_negation_of_constraint_to_solver( + const string_constraintt &axiom, supert &solver); + void fill_model(); bool check_axioms(); + void set_char_array_equality(const exprt &lhs, const exprt &rhs); void update_index_set(const exprt &formula); void update_index_set(const std::vector &cur); void initial_index_set(const string_constraintt &axiom); void initial_index_set(const std::vector &string_axioms); + void add_to_index_set(const exprt &s, exprt i); exprt instantiate( const string_constraintt &axiom, const exprt &str, const exprt &val); @@ -108,17 +135,28 @@ class string_refinementt: public bv_refinementt const string_not_contains_constraintt &axiom, std::list &new_lemmas); + exprt substitute_array_lists(exprt) const; + exprt compute_inverse_function( const exprt &qvar, const exprt &val, const exprt &f); std::map map_representation_of_sum(const exprt &f) const; - exprt sum_over_map(std::map &m, bool negated=false) const; + exprt sum_over_map( + std::map &m, const typet &type, bool negated=false) const; exprt simplify_sum(const exprt &f) const; - exprt get_array(const exprt &arr, const exprt &size); + void concretize_string(const exprt &expr); + void concretize_results(); + void concretize_lengths(); + + // Length of char arrays found during concretization + std::map found_length; + + exprt get_array(const exprt &arr, const exprt &size) const; + exprt get_array(const exprt &arr) const; - std::string string_of_array(const exprt &arr, const exprt &size) const; + std::string string_of_array(const array_exprt &arr); }; #endif diff --git a/src/util/Makefile b/src/util/Makefile index d5030ef2a48..6a94cabdb88 100644 --- a/src/util/Makefile +++ b/src/util/Makefile @@ -17,6 +17,7 @@ SRC = arith_tools.cpp \ find_symbols.cpp \ fixedbv.cpp \ format_constant.cpp \ + format_number_range.cpp \ fresh_symbol.cpp \ get_base_name.cpp \ get_module.cpp \ @@ -42,6 +43,7 @@ SRC = arith_tools.cpp \ message.cpp \ mp_arith.cpp \ namespace.cpp \ + nondet_ifthenelse.cpp \ options.cpp \ parse_options.cpp \ parser.cpp \ @@ -51,6 +53,7 @@ SRC = arith_tools.cpp \ rational.cpp \ rational_tools.cpp \ ref_expr_set.cpp \ + refined_string_type.cpp \ rename.cpp \ rename_symbol.cpp \ replace_expr.cpp \ diff --git a/src/util/format_number_range.cpp b/src/util/format_number_range.cpp new file mode 100644 index 00000000000..cca3bbf154c --- /dev/null +++ b/src/util/format_number_range.cpp @@ -0,0 +1,122 @@ +/*******************************************************************\ + +Module: Format vector of numbers into a compressed range + +Author: Daniel Kroening, kroening@kroening.com + +\*******************************************************************/ + +#include +#include +#include + +#include "format_number_range.h" + +/*******************************************************************\ + +Function: format_number_range::operator() + + Inputs: vector of numbers + + Outputs: string of compressed number range representation + + Purpose: create shorter representation for output + +\*******************************************************************/ + +std::string format_number_ranget::operator()(std::vector &numbers) +{ + std::string number_range; + std::sort(numbers.begin(), numbers.end()); + unsigned end_number=numbers.back(); + if(numbers.front()==end_number) + number_range=std::to_string(end_number); // only single number + else + { + bool next=true; + bool first=true; + bool range=false; + unsigned start_number=numbers.front(); + unsigned last_number=start_number; + + for(const auto &number : numbers) + { + if(next) + { + next=false; + start_number=number; + last_number=number; + } + // advance one forward + else + { + if(number==last_number+1 && !(number==end_number)) + { + last_number++; + if(last_number>start_number+1) + range=true; + } + // end this block range + else + { + if(first) + first=false; + else + number_range+=","; + if(last_number>start_number) + { + if(range) + { + if(number==end_number && number==last_number+1) + number_range+= + std::to_string(start_number)+"-"+std::to_string(end_number); + else if(number==end_number) + number_range+= + std::to_string(start_number)+"-"+std::to_string(last_number)+ + ","+std::to_string(end_number); + else + number_range+= + std::to_string(start_number)+"-"+std::to_string(last_number); + } + else + { + if(number!=end_number) + number_range+= + std::to_string(start_number)+","+std::to_string(last_number); + else + { + if(start_number+1==last_number && last_number+1==number) + number_range+= + std::to_string(start_number)+"-"+std::to_string(end_number); + else + number_range+= + std::to_string(start_number)+ + ","+std::to_string(last_number)+ + ","+std::to_string(end_number); + } + } + start_number=number; + last_number=number; + range=false; + continue; + } + else + { + if(number!=end_number) + number_range+=std::to_string(start_number); + else + number_range+=std::to_string(start_number)+","+ + std::to_string(end_number); + start_number=number; + last_number=number; + range=false; + continue; // already set next start number + } + next=true; + } + } + } + } + assert(!number_range.empty()); + return number_range; +} diff --git a/src/util/format_number_range.h b/src/util/format_number_range.h new file mode 100644 index 00000000000..7ff016e9c4d --- /dev/null +++ b/src/util/format_number_range.h @@ -0,0 +1,21 @@ +/*******************************************************************\ + +Module: Format vector of numbers into a compressed range + +Author: Daniel Kroening, kroening@kroening.com + +\*******************************************************************/ + +#ifndef CPROVER_UTIL_FORMAT_NUMBER_RANGE_H +#define CPROVER_UTIL_FORMAT_NUMBER_RANGE_H + +#include +#include + +class format_number_ranget +{ +public: + std::string operator()(std::vector &); +}; + +#endif // CPROVER_UTIL_FORMAT_NUMBER_RANGE_H diff --git a/src/util/irep_ids.def b/src/util/irep_ids.def index e31eceb1e98..70bca4bff5f 100644 --- a/src/util/irep_ids.def +++ b/src/util/irep_ids.def @@ -810,6 +810,8 @@ IREP_ID_ONE(cprover_string_to_upper_case_func) IREP_ID_ONE(cprover_string_trim_func) IREP_ID_ONE(cprover_string_value_of_func) IREP_ID_ONE(array_replace) +IREP_ID_ONE(basic_block_covered_lines) +IREP_ID_ONE(cprover_string_array_of_char_pointer_func) #undef IREP_ID_ONE #undef IREP_ID_TWO diff --git a/src/util/json_expr.cpp b/src/util/json_expr.cpp index 511e37ef681..90d9846b07c 100644 --- a/src/util/json_expr.cpp +++ b/src/util/json_expr.cpp @@ -17,9 +17,65 @@ Author: Peter Schrammel #include "fixedbv.h" #include "std_expr.h" #include "config.h" +#include "identifier.h" #include "json_expr.h" +/*******************************************************************\ + +Function: simplify_json_expr + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +static exprt simplify_json_expr( + const exprt &src, + const namespacet &ns) +{ + if(src.id()==ID_constant) + { + const typet &type=ns.follow(src.type()); + + if(type.id()==ID_pointer) + { + const irep_idt &value=to_constant_expr(src).get_value(); + + if(value!=ID_NULL && + (value!=std::string(value.size(), '0') || + !config.ansi_c.NULL_is_zero) && + src.operands().size()==1 && + src.op0().id()!=ID_constant) + // try to simplify the constant pointer + return simplify_json_expr(src.op0(), ns); + } + } + else if(src.id()==ID_address_of && + src.operands().size()==1 && + src.op0().id()==ID_member && + id2string(to_member_expr( + src.op0()).get_component_name()).find("@")!=std::string::npos) + { + // simplify things of the form &member_expr(object, @class_identifier) + return simplify_json_expr(src.op0(), ns); + } + else if(src.id()==ID_member && + src.operands().size()==1 && + id2string( + to_member_expr(src).get_component_name()) + .find("@")!=std::string::npos) + { + // simplify things of the form member_expr(object, @class_identifier) + return simplify_json_expr(src.op0(), ns); + } + + return src; +} + json_objectt json(const source_locationt &location) { json_objectt result; @@ -229,9 +285,19 @@ json_objectt json( else if(type.id()==ID_pointer) { result["name"]=json_stringt("pointer"); - result["binary"]=json_stringt(expr.get_string(ID_value)); - if(expr.get(ID_value)==ID_NULL) + exprt simpl_expr=simplify_json_expr(expr, ns); + if(simpl_expr.get(ID_value)==ID_NULL || + // remove typecast on NULL + (simpl_expr.id()==ID_constant && simpl_expr.type().id()==ID_pointer && + simpl_expr.op0().get(ID_value)==ID_NULL)) result["data"]=json_stringt("NULL"); + else if(simpl_expr.id()==ID_symbol) + { + const irep_idt &ptr_id=to_symbol_expr(simpl_expr).get_identifier(); + identifiert identifier(id2string(ptr_id)); + assert(!identifier.components.empty()); + result["data"]=json_stringt(identifier.components.back()); + } } else if(type.id()==ID_bool) { diff --git a/src/util/mp_arith.cpp b/src/util/mp_arith.cpp index 980284ffcd8..e79d58f63e9 100644 --- a/src/util/mp_arith.cpp +++ b/src/util/mp_arith.cpp @@ -18,6 +18,9 @@ Author: Daniel Kroening, kroening@kroening.com #include "mp_arith.h" #include "arith_tools.h" +typedef BigInt::ullong_t ullong_t; // NOLINT(readability/identifiers) +typedef BigInt::llong_t llong_t; // NOLINT(readability/identifiers) + mp_integer operator>>(const mp_integer &a, const mp_integer &b) { mp_integer power=::power(2, b); @@ -207,3 +210,277 @@ unsigned integer2unsigned(const mp_integer &n) assert(ull <= std::numeric_limits::max()); return (unsigned)ull; } + +/*******************************************************************\ + +Function: bitwise_or + + Inputs: + + Outputs: + + Purpose: bitwise or + bitwise operations only make sense on native objects, hence the + largest object size should be the largest available c++ integer + size (currently long long) + +\*******************************************************************/ + +mp_integer bitwise_or(const mp_integer &a, const mp_integer &b) +{ + ullong_t result=a.to_ulong()|b.to_ulong(); + return result; +} + +/*******************************************************************\ + +Function: bitwise_and + + Inputs: + + Outputs: + + Purpose: bitwise and + bitwise operations only make sense on native objects, hence the + largest object size should be the largest available c++ integer + size (currently long long) + +\*******************************************************************/ + +mp_integer bitwise_and(const mp_integer &a, const mp_integer &b) +{ + ullong_t result=a.to_ulong()&b.to_ulong(); + return result; +} + +/*******************************************************************\ + +Function: bitwise_xor + + Inputs: + + Outputs: + + Purpose: bitwise xor + bitwise operations only make sense on native objects, hence the + largest object size should be the largest available c++ integer + size (currently long long) + +\*******************************************************************/ + +mp_integer bitwise_xor(const mp_integer &a, const mp_integer &b) +{ + ullong_t result=a.to_ulong()^b.to_ulong(); + return result; +} + +/*******************************************************************\ + +Function: bitwise_neg + + Inputs: + + Outputs: + + Purpose: bitwise negation + bitwise operations only make sense on native objects, hence the + largest object size should be the largest available c++ integer + size (currently long long) + +\*******************************************************************/ + +mp_integer bitwise_neg(const mp_integer &a) +{ + ullong_t result=~a.to_ulong(); + return result; +} + +/*******************************************************************\ + +Function: arith_left_shift + + Inputs: + + Outputs: + + Purpose: arithmetic left shift + bitwise operations only make sense on native objects, hence the + largest object size should be the largest available c++ integer + size (currently long long) + +\*******************************************************************/ + +mp_integer arith_left_shift( + const mp_integer &a, + const mp_integer &b, + std::size_t true_size) +{ + ullong_t shift=b.to_ulong(); + if(shift>true_size && a!=mp_integer(0)) + throw "shift value out of range"; + + llong_t result=a.to_long()<true_size) + throw "shift value out of range"; + + llong_t sign=(1<<(true_size-1))&number; + llong_t pad=(sign==0) ? 0 : ~((1<<(true_size-shift))-1); + llong_t result=(number >> shift)|pad; + return result; +} + +/*******************************************************************\ + +Function: logic_left_shift + + Inputs: + + Outputs: + + Purpose: logic left shift + bitwise operations only make sense on native objects, hence the + largest object size should be the largest available c++ integer + size (currently long long) + +\*******************************************************************/ + +mp_integer logic_left_shift( + const mp_integer &a, + const mp_integer &b, + std::size_t true_size) +{ + ullong_t shift=b.to_ulong(); + if(shift>true_size && a!=mp_integer(0)) + throw "shift value out of range"; + llong_t result=a.to_long()<true_size) + throw "shift value out of range"; + + ullong_t result=((ullong_t)a.to_long()) >> shift; + return result; +} + +/*******************************************************************\ + +Function: rotate_right + + Inputs: + + Outputs: + + Purpose: rotates right (MSB=LSB) + bitwise operations only make sense on native objects, hence the + largest object size should be the largest available c++ integer + size (currently long long) + +\*******************************************************************/ + +mp_integer rotate_right( + const mp_integer &a, + const mp_integer &b, + std::size_t true_size) +{ + ullong_t number=a.to_ulong(); + ullong_t shift=b.to_ulong(); + if(shift>true_size) + throw "shift value out of range"; + + ullong_t revShift=true_size-shift; + ullong_t filter=1<<(true_size-1); + ullong_t result=(number >> shift)|((number<true_size) + throw "shift value out of range"; + + ullong_t revShift=true_size-shift; + ullong_t filter=1<<(true_size-1); + ullong_t result=((number<> revShift); + return result; +} diff --git a/src/util/mp_arith.h b/src/util/mp_arith.h index eede5855b75..7cc4dd7dfad 100644 --- a/src/util/mp_arith.h +++ b/src/util/mp_arith.h @@ -21,6 +21,28 @@ typedef BigInt mp_integer; std::ostream &operator<<(std::ostream &, const mp_integer &); mp_integer operator>>(const mp_integer &, const mp_integer &); mp_integer operator<<(const mp_integer &, const mp_integer &); +mp_integer bitwise_or(const mp_integer &, const mp_integer &); +mp_integer bitwise_and(const mp_integer &, const mp_integer &); +mp_integer bitwise_xor(const mp_integer &, const mp_integer &); +mp_integer bitwise_neg(const mp_integer &); + +mp_integer arith_left_shift( + const mp_integer &, const mp_integer &, std::size_t true_size); + +mp_integer arith_right_shift( + const mp_integer &, const mp_integer &, std::size_t true_size); + +mp_integer logic_left_shift( + const mp_integer &, const mp_integer &, std::size_t true_size); + +mp_integer logic_right_shift( + const mp_integer &, const mp_integer &, std::size_t true_size); + +mp_integer rotate_right( + const mp_integer &, const mp_integer &, std::size_t true_size); + +mp_integer rotate_left( + const mp_integer &, const mp_integer &, std::size_t true_size); const std::string integer2string(const mp_integer &, unsigned base=10); const mp_integer string2integer(const std::string &, unsigned base=10); @@ -29,5 +51,6 @@ const mp_integer binary2integer(const std::string &, bool is_signed); mp_integer::ullong_t integer2ulong(const mp_integer &); std::size_t integer2size_t(const mp_integer &); unsigned integer2unsigned(const mp_integer &); +const mp_integer mp_zero=string2integer("0"); #endif // CPROVER_UTIL_MP_ARITH_H diff --git a/src/util/refined_string_type.cpp b/src/util/refined_string_type.cpp new file mode 100644 index 00000000000..84b628c4918 --- /dev/null +++ b/src/util/refined_string_type.cpp @@ -0,0 +1,40 @@ +/********************************************************************\ + +Module: Type for string expressions used by the string solver. + These string expressions contain a field `length`, of type + `index_type`, a field `content` of type `content_type`. + This module also defines functions to recognise the C and java + string types. + +Author: Romain Brenguier, romain.brenguier@diffblue.com + +\*******************************************************************/ + +/// \file +/// Type for string expressions used by the string solver. These string +/// expressions contain a field `length`, of type `index_type`, a field +/// `content` of type `content_type`. This module also defines functions to +/// recognise the C and java string types. + +#include + +#include "refined_string_type.h" + +refined_string_typet::refined_string_typet( + const typet &index_type, const typet &char_type) +{ + infinity_exprt infinite_index(index_type); + array_typet char_array(char_type, infinite_index); + components().emplace_back("length", index_type); + components().emplace_back("content", char_array); + set_tag(CPROVER_PREFIX"refined_string_type"); +} + +/// \par parameters: a type +/// \return Boolean telling whether the input is a refined string type +bool refined_string_typet::is_refined_string_type(const typet &type) +{ + return + type.id()==ID_struct && + to_struct_type(type).get_tag()==CPROVER_PREFIX"refined_string_type"; +} diff --git a/src/solvers/refinement/refined_string_type.h b/src/util/refined_string_type.h similarity index 60% rename from src/solvers/refinement/refined_string_type.h rename to src/util/refined_string_type.h index 4d5e11afa84..efa8a0987ec 100644 --- a/src/solvers/refinement/refined_string_type.h +++ b/src/util/refined_string_type.h @@ -16,8 +16,8 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com /// `content` of type `content_type`. This module also defines functions to /// recognise the C and java string types. -#ifndef CPROVER_SOLVERS_REFINEMENT_REFINED_STRING_TYPE_H -#define CPROVER_SOLVERS_REFINEMENT_REFINED_STRING_TYPE_H +#ifndef CPROVER_UTIL_REFINED_STRING_TYPE_H +#define CPROVER_UTIL_REFINED_STRING_TYPE_H #include #include @@ -39,41 +39,16 @@ class refined_string_typet: public struct_typet const typet &get_char_type() const { - assert(components().size()==2); - return components()[0].type(); + return get_content_type().subtype(); } const typet &get_index_type() const { - return get_content_type().size().type(); - } - - // For C the unrefined string type is __CPROVER_string, for java it is a - // pointer to a struct with tag java.lang.String - - static bool is_c_string_type(const typet &type); - - static bool is_java_string_pointer_type(const typet &type); - - static bool is_java_string_type(const typet &type); - - static bool is_java_string_builder_type(const typet &type); - - static bool is_java_char_sequence_type(const typet &type); - - static bool is_unrefined_string_type(const typet &type) - { - return ( - is_c_string_type(type) || - is_java_string_pointer_type(type) || - is_java_string_builder_type(type) || - is_java_char_sequence_type(type)); + assert(components().size()==2); + return components()[0].type(); } - static bool is_unrefined_string(const exprt &expr) - { - return (is_unrefined_string_type(expr.type())); - } + static bool is_refined_string_type(const typet &type); constant_exprt index_of_int(int i) const { @@ -81,9 +56,10 @@ class refined_string_typet: public struct_typet } }; -const refined_string_typet &to_refined_string_type(const typet &type) +extern inline const refined_string_typet &to_refined_string_type( + const typet &type) { - assert(type.id()==ID_struct); + assert(refined_string_typet::is_refined_string_type(type)); return static_cast(type); } diff --git a/src/util/source_location.h b/src/util/source_location.h index 4186f3e35e2..95bef820ae9 100644 --- a/src/util/source_location.h +++ b/src/util/source_location.h @@ -75,6 +75,11 @@ class source_locationt:public irept return get(ID_java_bytecode_index); } + const irep_idt &get_basic_block_covered_lines() const + { + return get(ID_basic_block_covered_lines); + } + void set_file(const irep_idt &file) { set(ID_file, file); @@ -130,6 +135,11 @@ class source_locationt:public irept set(ID_java_bytecode_index, index); } + void set_basic_block_covered_lines(const irep_idt &covered_lines) + { + return set(ID_basic_block_covered_lines, covered_lines); + } + void set_hide() { set(ID_hide, true); diff --git a/src/util/sparse_vector.h b/src/util/sparse_vector.h new file mode 100644 index 00000000000..193e9a68a01 --- /dev/null +++ b/src/util/sparse_vector.h @@ -0,0 +1,62 @@ +/*******************************************************************\ + +Module: Sparse Vectors + +Author: Romain Brenguier + +\*******************************************************************/ + +#ifndef CPROVER_UTIL_SPARSE_VECTOR_H +#define CPROVER_UTIL_SPARSE_VECTOR_H + +#include +#include +#include + +template class sparse_vectort +{ +protected: + typedef std::map underlyingt; + underlyingt underlying; + uint64_t _size; + +public: + sparse_vectort() : + _size(0) {} + + const T &operator[](uint64_t idx) const + { + assert(idx<_size && "index out of range"); + return underlying[idx]; + } + + T &operator[](uint64_t idx) + { + assert(idx<_size && "index out of range"); + return underlying[idx]; + } + + uint64_t size() const + { + return _size; + } + + void resize(uint64_t new_size) + { + assert(new_size>=_size && "sparse vector can't be shrunk (yet)"); + _size=new_size; + } + + typedef typename underlyingt::iterator iteratort; + typedef typename underlyingt::const_iterator const_iteratort; + + iteratort begin() { return underlying.begin(); } + const_iteratort begin() const { return underlying.begin(); } + + iteratort end() { return underlying.end(); } + const_iteratort end() const { return underlying.end(); } + + const_iteratort find(uint64_t idx) { return underlying.find(idx); } +}; + +#endif // CPROVER_UTIL_SPARSE_VECTOR_H diff --git a/src/util/ssa_expr.cpp b/src/util/ssa_expr.cpp index feb37fe84ca..77f2c43bbb5 100644 --- a/src/util/ssa_expr.cpp +++ b/src/util/ssa_expr.cpp @@ -67,6 +67,19 @@ static void build_ssa_identifier_rec( assert(false); } +/// Used to determine whether or not an identifier can be built +/// before trying and getting an exception +bool ssa_exprt::can_build_identifier(const exprt &expr) +{ + if(expr.id()==ID_symbol) + return true; + else if(expr.id()==ID_member || + expr.id()==ID_index) + return can_build_identifier(expr.op0()); + else + return false; +} + std::pair ssa_exprt::build_identifier( const exprt &expr, const irep_idt &l0, diff --git a/src/util/ssa_expr.h b/src/util/ssa_expr.h index 61cbc566ef1..63e6dfaf7d7 100644 --- a/src/util/ssa_expr.h +++ b/src/util/ssa_expr.h @@ -65,7 +65,7 @@ class ssa_exprt:public symbol_exprt const irep_idt get_l1_object_identifier() const { - #if 0 + #if 1 return get_l1_object().get_identifier(); #else // the above is the clean version, this is the fast one, using @@ -135,6 +135,10 @@ class ssa_exprt:public symbol_exprt const irep_idt &l0, const irep_idt &l1, const irep_idt &l2); + + /* Used to determine whether or not an identifier can be built + * before trying and getting an exception */ + static bool can_build_identifier(const exprt &src); }; /*! \brief Cast a generic exprt to an \ref ssa_exprt diff --git a/src/util/std_expr.h b/src/util/std_expr.h index e2ed2ad433d..69a03bdfa9c 100644 --- a/src/util/std_expr.h +++ b/src/util/std_expr.h @@ -3287,6 +3287,17 @@ class member_exprt:public exprt { return op0(); } + + // Retrieves the object(symbol) this member corresponds to + inline const symbol_exprt &symbol() const + { + const exprt &op=op0(); + if(op.id()==ID_member) + { + return static_cast(op).symbol(); + } + return to_symbol_expr(op); + } }; /*! \brief Cast a generic exprt to a \ref member_exprt @@ -3792,6 +3803,19 @@ class function_application_exprt:public exprt operands().resize(2); } + explicit function_application_exprt(const typet &_type): + exprt(ID_function_application, _type) + { + operands().resize(2); + } + + function_application_exprt( + const symbol_exprt &_function, const typet &_type): + function_application_exprt(_type) // NOLINT(runtime/explicit) + { + function()=_function; + } + exprt &function() { return op0(); diff --git a/src/util/string_expr.h b/src/util/string_expr.h index e141f2a1598..cdb801988ae 100644 --- a/src/util/string_expr.h +++ b/src/util/string_expr.h @@ -77,7 +77,7 @@ class string_exprt: public struct_exprt return binary_relation_exprt(rhs.length(), ID_lt, length()); } - binary_relation_exprt axiom_for_is_strictly_longer_than(int i) const + binary_relation_exprt axiom_for_is_strictly_longer_than(mp_integer i) const { return axiom_for_is_strictly_longer_than(from_integer(i, length().type())); } @@ -94,7 +94,7 @@ class string_exprt: public struct_exprt return binary_relation_exprt(length(), ID_le, rhs); } - binary_relation_exprt axiom_for_is_shorter_than(int i) const + binary_relation_exprt axiom_for_is_shorter_than(mp_integer i) const { return axiom_for_is_shorter_than(from_integer(i, length().type())); } @@ -122,7 +122,7 @@ class string_exprt: public struct_exprt return equal_exprt(length(), rhs); } - equal_exprt axiom_for_has_length(int i) const + equal_exprt axiom_for_has_length(mp_integer i) const { return axiom_for_has_length(from_integer(i, length().type())); }