diff --git a/.clang-format b/.clang-format index 6d8c8f0b034..08fa2d1925c 100644 --- a/.clang-format +++ b/.clang-format @@ -84,7 +84,7 @@ NamespaceIndentation: None PenaltyBreakString: 10000 PointerAlignment: Right ReflowComments: 'false' -SortIncludes: 'false' +SortIncludes: 'true' SpaceAfterCStyleCast: 'false' SpaceBeforeAssignmentOperators: 'true' SpaceBeforeParens: Never diff --git a/.gitignore b/.gitignore index 4636f5a8380..cbe1112cbeb 100644 --- a/.gitignore +++ b/.gitignore @@ -30,8 +30,10 @@ Release/* *.lib src/ansi-c/arm_builtin_headers.inc src/ansi-c/clang_builtin_headers.inc +src/ansi-c/cprover_builtin_headers.inc src/ansi-c/cprover_library.inc src/ansi-c/cw_builtin_headers.inc +src/ansi-c/gcc_builtin_headers_types.inc src/ansi-c/gcc_builtin_headers_alpha.inc src/ansi-c/gcc_builtin_headers_arm.inc src/ansi-c/gcc_builtin_headers_generic.inc @@ -46,6 +48,7 @@ src/ansi-c/gcc_builtin_headers_tm.inc src/ansi-c/gcc_builtin_headers_mips.inc src/ansi-c/gcc_builtin_headers_power.inc src/ansi-c/gcc_builtin_headers_ubsan.inc +src/ansi-c/windows_builtin_headers.inc src/java_bytecode/java_core_models.inc # regression/test files @@ -104,8 +107,8 @@ src/goto-instrument/goto-instrument.exe src/jbmc/jbmc src/musketeer/musketeer src/musketeer/musketeer.exe -src/solvers/smt2/smt2_solver -src/solvers/smt2/smt2_solver.exe +src/solvers/smt2_solver +src/solvers/smt2_solver.exe src/symex/symex src/symex/symex.exe src/goto-diff/goto-diff diff --git a/.travis.yml b/.travis.yml index 52d548e3de2..6987a0b55d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,6 +38,13 @@ jobs: script: scripts/travis_lint.sh before_cache: + - &string-table-check + stage: Linter + Doxygen + non-debug Ubuntu/gcc-5 test + env: NAME="string-table" + install: + script: scripts/string_table_check.sh + before_cache: + - stage: Linter + Doxygen + non-debug Ubuntu/gcc-5 test env: NAME="DOXYGEN-CHECK" addons: diff --git a/CODING_STANDARD.md b/CODING_STANDARD.md index c5d67173e14..c218cdf859b 100644 --- a/CODING_STANDARD.md +++ b/CODING_STANDARD.md @@ -19,7 +19,10 @@ Formatting is enforced using clang-format. For more information about this, see - Nested function calls do not need to be broken up into separate lines even if the outer function call does. - If a method is bigger than 50 lines, break it into parts. -- Put matching `{ }` into the same column. +- Put matching `{ }` into the same column, except for initializer lists and + lambdas, where you should place `{` directly after the closing `)`. This is + to comply with clang-format, which doesn't support aligned curly braces in + these cases. - Spaces around binary operators (`=`, `+`, `==` ...) - Space after comma (parameter lists, argument lists, ...) - Space after colon inside `for` diff --git a/regression/ansi-c/Struct_ptrmember1/main.c b/regression/ansi-c/Struct_ptrmember1/main.c new file mode 100644 index 00000000000..b88cc5b8710 --- /dev/null +++ b/regression/ansi-c/Struct_ptrmember1/main.c @@ -0,0 +1,10 @@ +struct some_struct +{ + int some_field; +} array[10]; + +int main() +{ + array[0].some_field=1; + array->some_field=1; +} diff --git a/regression/ansi-c/Struct_ptrmember1/test.desc b/regression/ansi-c/Struct_ptrmember1/test.desc new file mode 100644 index 00000000000..466da18b2b5 --- /dev/null +++ b/regression/ansi-c/Struct_ptrmember1/test.desc @@ -0,0 +1,8 @@ +CORE +main.c + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +^CONVERSION ERROR$ diff --git a/regression/ansi-c/gcc_attributes11/main.c b/regression/ansi-c/gcc_attributes11/main.c new file mode 100644 index 00000000000..b69ac3e0e63 --- /dev/null +++ b/regression/ansi-c/gcc_attributes11/main.c @@ -0,0 +1,18 @@ +#ifdef __GNUC__ +// example extracted from SV-COMP's ldv-linux-3.4-simple/ +// 32_7_cpp_false-unreach-call_single_drivers-net-phy-dp83640 +static int __attribute__((__section__(".init.text"))) +__attribute__((no_instrument_function)) dp83640_init(void) +{ + return 0; +} +int init_module(void) __attribute__((alias("dp83640_init"))); +#endif + +int main() +{ +#ifdef __GNUC__ + dp83640_init(); +#endif + return 0; +} diff --git a/regression/ansi-c/gcc_attributes11/test.desc b/regression/ansi-c/gcc_attributes11/test.desc new file mode 100644 index 00000000000..466da18b2b5 --- /dev/null +++ b/regression/ansi-c/gcc_attributes11/test.desc @@ -0,0 +1,8 @@ +CORE +main.c + +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +^CONVERSION ERROR$ diff --git a/regression/ansi-c/gcc_attributes9/main.c b/regression/ansi-c/gcc_attributes9/main.c index f18e17aa773..76c7aeeca27 100644 --- a/regression/ansi-c/gcc_attributes9/main.c +++ b/regression/ansi-c/gcc_attributes9/main.c @@ -11,11 +11,23 @@ const char* __attribute__((section("s"))) __attribute__((weak)) bar(); volatile int __attribute__((__section__(".init.data1"))) txt_heap_base1; volatile int __attribute__((__section__(".init.data3"))) txt_heap_base, __attribute__((__section__(".init.data4"))) txt_heap_size; +int __attribute__((__section__(".init.text"))) __attribute__((__cold__)) +__alloc_bootmem_huge_page(void *h); +int __attribute__((__section__(".init.text"))) __attribute__((__cold__)) +alloc_bootmem_huge_page(void *h); +int alloc_bootmem_huge_page(void *h) + __attribute__((weak, alias("__alloc_bootmem_huge_page"))); +int __alloc_bootmem_huge_page(void *h) +{ + return 1; +} #endif int main() { #ifdef __GNUC__ + int r = alloc_bootmem_huge_page(0); + static int __attribute__((section(".data.unlikely"))) __warned; __warned=1; return __warned; diff --git a/regression/cbmc-concurrency/malloc2/main.c b/regression/cbmc-concurrency/malloc2/main.c new file mode 100644 index 00000000000..8634e886ccf --- /dev/null +++ b/regression/cbmc-concurrency/malloc2/main.c @@ -0,0 +1,21 @@ +#include +#include + +_Bool set_done; +int *ptr; + +void *set_x(void *arg) +{ + *(int *)arg = 10; + set_done = 1; +} + +int main(int argc, char *argv[]) +{ + __CPROVER_assume(argc >= sizeof(int)); + ptr = malloc(argc); + __CPROVER_ASYNC_1: set_x(ptr); + __CPROVER_assume(set_done); + assert(*ptr == 10); + return 0; +} diff --git a/regression/cbmc-concurrency/malloc2/test.desc b/regression/cbmc-concurrency/malloc2/test.desc new file mode 100644 index 00000000000..9efefbc7362 --- /dev/null +++ b/regression/cbmc-concurrency/malloc2/test.desc @@ -0,0 +1,8 @@ +CORE +main.c + +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/assertion_error_constructors/AssertionIssue.class b/regression/cbmc-java/assertion_error_constructors/AssertionIssue.class new file mode 100644 index 00000000000..a9312303951 Binary files /dev/null and b/regression/cbmc-java/assertion_error_constructors/AssertionIssue.class differ diff --git a/regression/cbmc-java/assertion_error_constructors/AssertionIssue.java b/regression/cbmc-java/assertion_error_constructors/AssertionIssue.java new file mode 100644 index 00000000000..b82d7b46df3 --- /dev/null +++ b/regression/cbmc-java/assertion_error_constructors/AssertionIssue.java @@ -0,0 +1,13 @@ +public class AssertionIssue { + + public static void throwAssertion() { + throw new AssertionError("Something went terribly wrong.", new ThrowableAssertion()); + } + + public static class ThrowableAssertion extends Throwable { + @Override + public String getMessage() { + return "How did we get here?"; + } + } +} diff --git a/regression/cbmc-java/assertion_error_constructors/test.desc b/regression/cbmc-java/assertion_error_constructors/test.desc new file mode 100644 index 00000000000..fde9624618f --- /dev/null +++ b/regression/cbmc-java/assertion_error_constructors/test.desc @@ -0,0 +1,8 @@ +CORE +AssertionIssue.class +--function AssertionIssue.throwAssertion +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/dynamic-multi-dimensional-array/TestClass.class b/regression/cbmc-java/dynamic-multi-dimensional-array/TestClass.class new file mode 100644 index 00000000000..66e0d073242 Binary files /dev/null and b/regression/cbmc-java/dynamic-multi-dimensional-array/TestClass.class differ diff --git a/regression/cbmc-java/dynamic-multi-dimensional-array/TestClass.java b/regression/cbmc-java/dynamic-multi-dimensional-array/TestClass.java new file mode 100644 index 00000000000..16d680bd804 --- /dev/null +++ b/regression/cbmc-java/dynamic-multi-dimensional-array/TestClass.java @@ -0,0 +1,7 @@ +public class TestClass { + public static void f(int y) { + float[][] a1 = new float[y][3]; + int j = 0; + a1[j][0] = 34.5f; + } +} diff --git a/regression/cbmc-java/dynamic-multi-dimensional-array/test.desc b/regression/cbmc-java/dynamic-multi-dimensional-array/test.desc new file mode 100644 index 00000000000..c9600f50852 --- /dev/null +++ b/regression/cbmc-java/dynamic-multi-dimensional-array/test.desc @@ -0,0 +1,10 @@ +CORE +TestClass.class +--function TestClass.f --cover location --unwind 2 +Source GOTO statement: .* +(^ exception: Can't convert byte_extraction|Nested exception printing not supported on Windows) +^EXIT=6$ +-- +-- +The exception thrown in this test is the symptom of a bug; the purpose of this +test is the validate the output of that exception diff --git a/regression/cbmc-java/static_init1/test1.desc b/regression/cbmc-java/static_init1/test1.desc new file mode 100644 index 00000000000..8bc396cff4d --- /dev/null +++ b/regression/cbmc-java/static_init1/test1.desc @@ -0,0 +1,8 @@ +CORE +static_init.class +--function static_init.main --java-threading +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/static_init2/test1.desc b/regression/cbmc-java/static_init2/test1.desc new file mode 100644 index 00000000000..8bc396cff4d --- /dev/null +++ b/regression/cbmc-java/static_init2/test1.desc @@ -0,0 +1,8 @@ +CORE +static_init.class +--function static_init.main --java-threading +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/regression/cbmc-java/static_init_order/test3.desc b/regression/cbmc-java/static_init_order/test3.desc new file mode 100644 index 00000000000..6ec4686fa57 --- /dev/null +++ b/regression/cbmc-java/static_init_order/test3.desc @@ -0,0 +1,7 @@ +CORE +static_init_order.class +--function static_init_order.test1 --trace --java-threading +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- diff --git a/regression/cbmc-java/static_init_order/test4.desc b/regression/cbmc-java/static_init_order/test4.desc new file mode 100644 index 00000000000..d008222606e --- /dev/null +++ b/regression/cbmc-java/static_init_order/test4.desc @@ -0,0 +1,7 @@ +CORE +static_init_order.class +--function static_init_order.test2 --java-threading +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- diff --git a/regression/cbmc-java/virtual7/test.desc b/regression/cbmc-java/virtual7/test.desc index 7d23df44236..900469e7dcf 100644 --- a/regression/cbmc-java/virtual7/test.desc +++ b/regression/cbmc-java/virtual7/test.desc @@ -3,6 +3,6 @@ test.class --show-goto-functions --function test.main ^EXIT=0$ ^SIGNAL=0$ -IF.*"java::C".*THEN GOTO -IF.*"java::D".*THEN GOTO +IF.*"java::B".*THEN GOTO +IF.*"java::E".*THEN GOTO IF.*"java::A".*THEN GOTO diff --git a/regression/cbmc/Bitfields3/main.c b/regression/cbmc/Bitfields3/main.c new file mode 100644 index 00000000000..c3aa64072cb --- /dev/null +++ b/regression/cbmc/Bitfields3/main.c @@ -0,0 +1,53 @@ +#include +#include + +#pragma pack(1) +struct A +{ + unsigned char a; + unsigned char b : 2; + unsigned char c : 2; + unsigned char d; +}; + +struct B +{ + unsigned char a; + unsigned char b : 2; + unsigned char c; + unsigned char d : 2; +}; + +struct C +{ + unsigned char a; + unsigned char b : 4; + unsigned char c : 4; + unsigned char d; +}; +#pragma pack() + +int main(void) +{ + assert(sizeof(struct A) == 3); + struct A *p = malloc(3); + assert((unsigned char *)p + 2 == &(p->d)); + p->c = 3; + if(p->c != 3) + { + free(p); + } + free(p); + + assert(sizeof(struct B) == 4); + struct B *pb = malloc(4); + assert((unsigned char *)pb + 2 == &(pb->c)); + free(pb); + + assert(sizeof(struct C) == 3); + struct C *pc = malloc(3); + assert((unsigned char *)pc + 2 == &(pc->d)); + free(pc); + + return 0; +} diff --git a/regression/cbmc/Bitfields3/test.desc b/regression/cbmc/Bitfields3/test.desc new file mode 100644 index 00000000000..96c9b4bcd7b --- /dev/null +++ b/regression/cbmc/Bitfields3/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--pointer-check --bounds-check +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ +-- +^warning: ignoring diff --git a/regression/jbmc-strings/char_escape/Test.class b/regression/jbmc-strings/char_escape/Test.class new file mode 100644 index 00000000000..5ffa97543e0 Binary files /dev/null and b/regression/jbmc-strings/char_escape/Test.class differ diff --git a/regression/jbmc-strings/char_escape/Test.java b/regression/jbmc-strings/char_escape/Test.java new file mode 100644 index 00000000000..791563bbbc0 --- /dev/null +++ b/regression/jbmc-strings/char_escape/Test.java @@ -0,0 +1,19 @@ +public class Test { + + public static boolean test(char c1, char c2, char c3, char c4, char c5, char c6, char c7, char c8) { + StringBuilder sb = new StringBuilder(""); + sb.append(c1); + sb.append(c2); + sb.append(c3); + sb.append(c4); + sb.append(c5); + sb.append(c6); + sb.append(c7); + sb.append(c8); + if (sb.toString().equals("\b\t\n\f\r\"\'\\")) + return true; + if (!sb.toString().equals("\b\t\n\f\r\"\'\\")) + return false; + return true; + } +} diff --git a/regression/jbmc-strings/char_escape/test.desc b/regression/jbmc-strings/char_escape/test.desc new file mode 100644 index 00000000000..53ab05408c9 --- /dev/null +++ b/regression/jbmc-strings/char_escape/test.desc @@ -0,0 +1,6 @@ +CORE +Test.class +--refine-strings --function Test.test --cover location --trace --json-ui +^EXIT=0$ +^SIGNAL=0$ +20 of 23 covered \(87.0%\)|30 of 44 covered \(68.2%\) diff --git a/regression/jbmc-strings/long_string/Test.class b/regression/jbmc-strings/long_string/Test.class index de6b488b03b..9442a3c1cf4 100644 Binary files a/regression/jbmc-strings/long_string/Test.class and b/regression/jbmc-strings/long_string/Test.class differ diff --git a/regression/jbmc-strings/long_string/Test.java b/regression/jbmc-strings/long_string/Test.java index 63b0d69babc..5decee61931 100644 --- a/regression/jbmc-strings/long_string/Test.java +++ b/regression/jbmc-strings/long_string/Test.java @@ -30,7 +30,9 @@ public static void checkAbort(String s, String t) { String u = s.concat(t); // Filter out - if(u.length() < 67_108_864) + // 67_108_864 corresponds to the maximum length for which the solver + // will concretize the string. + if(u.length() <= 67_108_864) return; if(CProverString.charAt(u, 2_000_000) != 'b') return; diff --git a/regression/jbmc-strings/long_string/test_abort.desc b/regression/jbmc-strings/long_string/test_abort.desc index 22074e1ed1e..8daa50acd1a 100644 --- a/regression/jbmc-strings/long_string/test_abort.desc +++ b/regression/jbmc-strings/long_string/test_abort.desc @@ -1,9 +1,10 @@ CORE Test.class ---refine-strings --function Test.checkAbort -^EXIT=6$ +--refine-strings --function Test.checkAbort --trace +^EXIT=10$ ^SIGNAL=0$ +dynamic_object[0-9]*=\(assignment removed\) -- -- -This tests should abort, because concretizing a string of the required -length may take to much memory. +This tests that the object does not appear in the trace, because concretizing +a string of the required length may take too much memory. diff --git a/regression/jbmc-strings/max-length-generic-array/IntegerTests.class b/regression/jbmc-strings/max-length-generic-array/IntegerTests.class new file mode 100644 index 00000000000..6120bff5bb6 Binary files /dev/null and b/regression/jbmc-strings/max-length-generic-array/IntegerTests.class differ diff --git a/regression/jbmc-strings/max-length-generic-array/IntegerTests.java b/regression/jbmc-strings/max-length-generic-array/IntegerTests.java new file mode 100644 index 00000000000..c57b3e19be8 --- /dev/null +++ b/regression/jbmc-strings/max-length-generic-array/IntegerTests.java @@ -0,0 +1,44 @@ +public class IntegerTests { + + public static Boolean testMyGenSet(Integer key) { + if (key == null) return null; + MyGenSet ms = new MyGenSet<>(); + ms.array[0] = 101; + if (ms.contains(key)) return true; + return false; + } + + public static Boolean testMySet(Integer key) { + if (key == null) return null; + MySet ms = new MySet(); + ms.array[0] = 101; + if (ms.contains(key)) return true; + return false; + } + +} + +class MyGenSet { + E[] array; + @SuppressWarnings("unchecked") + MyGenSet() { + array = (E[]) new Object[1]; + } + boolean contains(E o) { + if (o.equals(array[0])) + return true; + return false; + } +} + +class MySet { + Integer[] array; + MySet() { + array = new Integer[1]; + } + boolean contains(Integer o) { + if (o.equals(array[0])) + return true; + return false; + } +} diff --git a/regression/jbmc-strings/max-length-generic-array/MyGenSet.class b/regression/jbmc-strings/max-length-generic-array/MyGenSet.class new file mode 100644 index 00000000000..e92e43fee85 Binary files /dev/null and b/regression/jbmc-strings/max-length-generic-array/MyGenSet.class differ diff --git a/regression/jbmc-strings/max-length-generic-array/MySet.class b/regression/jbmc-strings/max-length-generic-array/MySet.class new file mode 100644 index 00000000000..e890519fb8b Binary files /dev/null and b/regression/jbmc-strings/max-length-generic-array/MySet.class differ diff --git a/regression/jbmc-strings/max-length-generic-array/test.desc b/regression/jbmc-strings/max-length-generic-array/test.desc new file mode 100644 index 00000000000..3862a4978b3 --- /dev/null +++ b/regression/jbmc-strings/max-length-generic-array/test.desc @@ -0,0 +1,19 @@ +CORE +IntegerTests.class +-refine-strings --string-max-length 100 IntegerTests.class --function IntegerTests.testMySet --cover location +^EXIT=0$ +^SIGNAL=0$ +coverage.* line 12 function java::IntegerTests.testMySet.* bytecode-index 1 .* SATISFIED +coverage.* line 12 function java::IntegerTests.testMySet.* bytecode-index 3 .* SATISFIED +coverage.* line 13 function java::IntegerTests.testMySet.* bytecode-index 4 .* SATISFIED +coverage.* line 13 function java::IntegerTests.testMySet.* bytecode-index 6 .* SATISFIED +coverage.* line 13 function java::IntegerTests.testMySet.* bytecode-index 7 .* SATISFIED +coverage.* line 14 function java::IntegerTests.testMySet.* bytecode-index 12 .* SATISFIED +coverage.* line 14 function java::IntegerTests.testMySet.* bytecode-index 13 .* SATISFIED +coverage.* line 15 function java::IntegerTests.testMySet.* bytecode-index 16 .* SATISFIED +coverage.* line 15 function java::IntegerTests.testMySet.* bytecode-index 17 .* SATISFIED +coverage.* line 16 function java::IntegerTests.testMySet.* bytecode-index 21 .* SATISFIED +coverage.* line 15 function java::IntegerTests.testMySet.* bytecode-index 19 .* SATISFIED +coverage.* line 15 function java::IntegerTests.testMySet.* bytecode-index 20 .* SATISFIED +coverage.* line 16 function java::IntegerTests.testMySet.* bytecode-index 22 .* SATISFIED +coverage.* line 16 function java::IntegerTests.testMySet.* bytecode-index 23 .* SATISFIED diff --git a/regression/jbmc-strings/max-length-generic-array/test_gen.desc b/regression/jbmc-strings/max-length-generic-array/test_gen.desc new file mode 100644 index 00000000000..ec123c9a16a --- /dev/null +++ b/regression/jbmc-strings/max-length-generic-array/test_gen.desc @@ -0,0 +1,20 @@ +CORE +IntegerTests.class +-refine-strings --string-max-length 100 IntegerTests.class --function IntegerTests.testMyGenSet --cover location +^EXIT=0$ +^SIGNAL=0$ +coverage.* line 4 function java::IntegerTests.testMyGenSet.* bytecode-index 1 .* SATISFIED +coverage.* line 4 function java::IntegerTests.testMyGenSet.* bytecode-index 3 .* SATISFIED +coverage.* line 5 function java::IntegerTests.testMyGenSet.* bytecode-index 4 .* SATISFIED +coverage.* line 5 function java::IntegerTests.testMyGenSet.* bytecode-index 6 .* SATISFIED +coverage.* line 5 function java::IntegerTests.testMyGenSet.* bytecode-index 7 .* SATISFIED +coverage.* line 6 function java::IntegerTests.testMyGenSet.* bytecode-index 10 .* SATISFIED +coverage.* line 6 function java::IntegerTests.testMyGenSet.* bytecode-index 13 .* SATISFIED +coverage.* line 6 function java::IntegerTests.testMyGenSet.* bytecode-index 14 .* SATISFIED +coverage.* line 7 function java::IntegerTests.testMyGenSet.* bytecode-index 17 .* SATISFIED +coverage.* line 7 function java::IntegerTests.testMyGenSet.* bytecode-index 18 .* SATISFIED +coverage.* line 8 function java::IntegerTests.testMyGenSet.* bytecode-index 22 .* SATISFIED +coverage.* line 7 function java::IntegerTests.testMyGenSet.* bytecode-index 20 .* SATISFIED +coverage.* line 7 function java::IntegerTests.testMyGenSet.* bytecode-index 21 .* SATISFIED +coverage.* line 8 function java::IntegerTests.testMyGenSet.* bytecode-index 23 .* SATISFIED +coverage.* line 8 function java::IntegerTests.testMyGenSet.* bytecode-index 24 .* SATISFIED diff --git a/regression/jbmc-strings/max-length/Test.class b/regression/jbmc-strings/max-length/Test.class new file mode 100644 index 00000000000..0bc43cd0bdb Binary files /dev/null and b/regression/jbmc-strings/max-length/Test.class differ diff --git a/regression/jbmc-strings/max-length/Test.java b/regression/jbmc-strings/max-length/Test.java new file mode 100644 index 00000000000..e947169506d --- /dev/null +++ b/regression/jbmc-strings/max-length/Test.java @@ -0,0 +1,37 @@ +public class Test { + + static void checkMaxInputLength(String arg1, String arg2) { + // Filter + if (arg1 == null || arg2 == null) + return; + + // The validity of this depends on string-max-input-length + assert arg1.length() + arg2.length() < 1_000_000; + } + + static void checkMaxLength(String arg1, String arg2) { + // Filter + if (arg1 == null || arg2 == null) + return; + + if(arg1.length() + arg2.length() < 4_001) + return; + + // Act + String s = arg1.concat(arg2); + + // When string-max-length is smaller than 4_000 this will + // always be the case + assert org.cprover.CProverString.charAt(s, 4_000) == '?'; + } + + static void main(String argv[]) { + // Filter + if (argv.length < 2) + return; + + // Act + checkMaxInputLength(argv[0], argv[1]); + checkMaxLength(argv[0], argv[1]); + } +} diff --git a/regression/jbmc-strings/max-length/test1.desc b/regression/jbmc-strings/max-length/test1.desc new file mode 100644 index 00000000000..1cdaf80b01e --- /dev/null +++ b/regression/jbmc-strings/max-length/test1.desc @@ -0,0 +1,6 @@ +CORE +Test.class +--refine-strings --verbosity 10 --string-max-input-length 499999 --function Test.checkMaxInputLength +^EXIT=0$ +^SIGNAL=0$ +assertion.* line 9 function java::Test.checkMaxInputLength.* bytecode-index 16: SUCCESS diff --git a/regression/jbmc-strings/max-length/test2.desc b/regression/jbmc-strings/max-length/test2.desc new file mode 100644 index 00000000000..e705d18deda --- /dev/null +++ b/regression/jbmc-strings/max-length/test2.desc @@ -0,0 +1,6 @@ +CORE +Test.class +--refine-strings --verbosity 10 --string-max-input-length 500000 --function Test.checkMaxInputLength +^EXIT=10$ +^SIGNAL=0$ +assertion.* line 9 function java::Test.checkMaxInputLength.* bytecode-index 16: FAILURE diff --git a/regression/jbmc-strings/max-length/test3.desc b/regression/jbmc-strings/max-length/test3.desc new file mode 100644 index 00000000000..ab4c3b62db5 --- /dev/null +++ b/regression/jbmc-strings/max-length/test3.desc @@ -0,0 +1,6 @@ +CORE +Test.class +--refine-strings --verbosity 10 --string-max-length 4001 --function Test.checkMaxLength +^EXIT=10$ +^SIGNAL=0$ +assertion.* line 25 function java::Test.checkMaxLength.* bytecode-index 26: FAILURE diff --git a/regression/jbmc-strings/max-length/test4.desc b/regression/jbmc-strings/max-length/test4.desc new file mode 100644 index 00000000000..b1cdfc3d39c --- /dev/null +++ b/regression/jbmc-strings/max-length/test4.desc @@ -0,0 +1,11 @@ +CORE +Test.class +--refine-strings --verbosity 10 --string-max-length 4000 --function Test.checkMaxLength +^SIGNAL=0$ +-- +^EXIT=0$ +assertion.* line 25 function java::Test.checkMaxLength.* bytecode-index 26: SUCCESS +-- +The solver may give an ERROR because the value of string-max-length is too +small to give an answer about the assertion. +So we just check that the answer is not success. diff --git a/scripts/cadical-patch b/scripts/cadical-patch new file mode 100644 index 00000000000..5baec02a370 --- /dev/null +++ b/scripts/cadical-patch @@ -0,0 +1,10 @@ +--- a/src/cadical.hpp 2018-03-10 14:22:11.000000000 +0000 ++++ b/src/cadical.hpp 2018-03-31 16:18:32.000000000 +0100 +@@ -141,6 +141,6 @@ + File * output (); // get access to internal 'output' file + }; + +-}; ++} + + #endif diff --git a/scripts/cpplint.py b/scripts/cpplint.py index bb08391f4d9..d01baeb2fcf 100755 --- a/scripts/cpplint.py +++ b/scripts/cpplint.py @@ -3972,14 +3972,6 @@ def CheckBracesSpacing(filename, clean_lines, linenum, nesting_state, error): error(filename, linenum, 'whitespace/braces', 5, 'Missing space before {') - # Make sure '} else {' has spaces. - # if Search(r'}else', line): - # error(filename, linenum, 'whitespace/braces', 5, - # 'Missing space before else') - if (Search(r'^.*[^\s].*}$', line) or Search(r'^.*[^\s].*{$', line)) and not(Search(r'{[^}]*}', line)): - error(filename, linenum, 'whitespace/braces', 5, - 'Put braces on a separate next line') - # You shouldn't have a space before a semicolon at the end of the line. # There's a special case for "for" since the style guide allows space before # the semicolon there. diff --git a/scripts/glucose-syrup-patch b/scripts/glucose-syrup-patch index 138e4a50315..22b34562b8e 100644 --- a/scripts/glucose-syrup-patch +++ b/scripts/glucose-syrup-patch @@ -1,6 +1,6 @@ -diff -rupN glucose-syrup/core/Solver.cc glucose-syrup-patched/core/Solver.cc ---- glucose-syrup/core/Solver.cc 2014-10-03 10:10:21.000000000 +0100 -+++ glucose-syrup-patched/core/Solver.cc 2016-07-08 13:06:02.772186004 +0100 +diff -rupNw glucose-syrup/core/Solver.cc glucose-syrup-patched/core/Solver.cc +--- glucose-syrup/core/Solver.cc 2014-10-03 11:10:21.000000000 +0200 ++++ glucose-syrup-patched/core/Solver.cc 2018-04-21 16:58:22.950005391 +0200 @@ -931,7 +931,6 @@ void Solver::uncheckedEnqueue(Lit p, CRe CRef Solver::propagate() { CRef confl = CRef_Undef; @@ -19,9 +19,9 @@ diff -rupN glucose-syrup/core/Solver.cc glucose-syrup-patched/core/Solver.cc // Model found: return l_True; } -diff -rupN glucose-syrup/core/SolverTypes.h glucose-syrup-patched/core/SolverTypes.h ---- glucose-syrup/core/SolverTypes.h 2014-10-03 10:10:22.000000000 +0100 -+++ glucose-syrup-patched/core/SolverTypes.h 2016-07-08 13:06:02.772186004 +0100 +diff -rupNw glucose-syrup/core/SolverTypes.h glucose-syrup-patched/core/SolverTypes.h +--- glucose-syrup/core/SolverTypes.h 2014-10-03 11:10:22.000000000 +0200 ++++ glucose-syrup-patched/core/SolverTypes.h 2018-04-21 16:58:22.950005391 +0200 @@ -53,7 +53,9 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR #include @@ -32,9 +32,20 @@ diff -rupN glucose-syrup/core/SolverTypes.h glucose-syrup-patched/core/SolverTyp #include "mtl/IntTypes.h" #include "mtl/Alg.h" -diff -rupN glucose-syrup/mtl/IntTypes.h glucose-syrup-patched/mtl/IntTypes.h ---- glucose-syrup/mtl/IntTypes.h 2014-10-03 10:10:22.000000000 +0100 -+++ glucose-syrup-patched/mtl/IntTypes.h 2016-07-08 13:06:02.772186004 +0100 +@@ -170,7 +172,10 @@ class Clause { + unsigned lbd : BITS_LBD; + } header; + ++#include ++#include + union { Lit lit; float act; uint32_t abs; CRef rel; } data[0]; ++#include + + friend class ClauseAllocator; + +diff -rupNw glucose-syrup/mtl/IntTypes.h glucose-syrup-patched/mtl/IntTypes.h +--- glucose-syrup/mtl/IntTypes.h 2014-10-03 11:10:22.000000000 +0200 ++++ glucose-syrup-patched/mtl/IntTypes.h 2018-04-21 16:58:22.950005391 +0200 @@ -31,7 +31,9 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR #else @@ -45,10 +56,49 @@ diff -rupN glucose-syrup/mtl/IntTypes.h glucose-syrup-patched/mtl/IntTypes.h #endif -diff -rupN glucose-syrup/simp/SimpSolver.cc glucose-syrup-patched/simp/SimpSolver.cc ---- glucose-syrup/simp/SimpSolver.cc 2014-10-03 10:10:22.000000000 +0100 -+++ glucose-syrup-patched/simp/SimpSolver.cc 2016-07-08 13:07:00.396187548 +0100 -@@ -687,11 +687,11 @@ bool SimpSolver::eliminate(bool turn_off +diff -rupNw glucose-syrup/mtl/Vec.h glucose-syrup-patched/mtl/Vec.h +--- glucose-syrup/mtl/Vec.h 2014-10-03 11:10:22.000000000 +0200 ++++ glucose-syrup-patched/mtl/Vec.h 2018-04-21 16:58:22.950005391 +0200 +@@ -103,7 +103,7 @@ template + void vec::capacity(int min_cap) { + if (cap >= min_cap) return; + int add = imax((min_cap - cap + 1) & ~1, ((cap >> 1) + 2) & ~1); // NOTE: grow by approximately 3/2 +- if (add > INT_MAX - cap || ((data = (T*)::realloc(data, (cap += add) * sizeof(T))) == NULL) && errno == ENOMEM) ++ if (add > INT_MAX - cap || (((data = (T*)::realloc(data, (cap += add) * sizeof(T))) == NULL) && errno == ENOMEM)) + throw OutOfMemoryException(); + } + +diff -rupNw glucose-syrup/simp/SimpSolver.cc glucose-syrup-patched/simp/SimpSolver.cc +--- glucose-syrup/simp/SimpSolver.cc 2014-10-03 11:10:22.000000000 +0200 ++++ glucose-syrup-patched/simp/SimpSolver.cc 2018-04-21 16:58:22.950005391 +0200 +@@ -319,10 +319,13 @@ bool SimpSolver::merge(const Clause& _ps + if (var(qs[i]) != v){ + for (int j = 0; j < ps.size(); j++) + if (var(ps[j]) == var(qs[i])) ++ { + if (ps[j] == ~qs[i]) ++ + return false; + else + goto next; ++ } + out_clause.push(qs[i]); + } + next:; +@@ -353,10 +356,12 @@ bool SimpSolver::merge(const Clause& _ps + if (var(__qs[i]) != v){ + for (int j = 0; j < ps.size(); j++) + if (var(__ps[j]) == var(__qs[i])) ++ { + if (__ps[j] == ~__qs[i]) + return false; + else + goto next; ++ } + size++; + } + next:; +@@ -687,11 +692,11 @@ bool SimpSolver::eliminate(bool turn_off // int toPerform = clauses.size()<=4800000; @@ -62,7 +112,7 @@ diff -rupN glucose-syrup/simp/SimpSolver.cc glucose-syrup-patched/simp/SimpSolve while (toPerform && (n_touched > 0 || bwdsub_assigns < trail.size() || elim_heap.size() > 0)){ gatherTouchedClauses(); -@@ -760,10 +760,11 @@ bool SimpSolver::eliminate(bool turn_off +@@ -760,10 +765,11 @@ bool SimpSolver::eliminate(bool turn_off checkGarbage(); } @@ -75,9 +125,21 @@ diff -rupN glucose-syrup/simp/SimpSolver.cc glucose-syrup-patched/simp/SimpSolve return ok; -diff -rupN glucose-syrup/utils/ParseUtils.h glucose-syrup-patched/utils/ParseUtils.h ---- glucose-syrup/utils/ParseUtils.h 2014-10-03 10:10:22.000000000 +0100 -+++ glucose-syrup-patched/utils/ParseUtils.h 2016-07-08 13:06:02.772186004 +0100 +diff -rupNw glucose-syrup/utils/Options.h glucose-syrup-patched/utils/Options.h +--- glucose-syrup/utils/Options.h 2014-10-03 11:10:22.000000000 +0200 ++++ glucose-syrup-patched/utils/Options.h 2018-04-21 16:58:22.950005391 +0200 +@@ -60,7 +60,7 @@ class Option + struct OptionLt { + bool operator()(const Option* x, const Option* y) { + int test1 = strcmp(x->category, y->category); +- return test1 < 0 || test1 == 0 && strcmp(x->type_name, y->type_name) < 0; ++ return test1 < 0 || (test1 == 0 && strcmp(x->type_name, y->type_name) < 0); + } + }; + +diff -rupNw glucose-syrup/utils/ParseUtils.h glucose-syrup-patched/utils/ParseUtils.h +--- glucose-syrup/utils/ParseUtils.h 2014-10-03 11:10:22.000000000 +0200 ++++ glucose-syrup-patched/utils/ParseUtils.h 2018-04-21 16:58:22.950005391 +0200 @@ -25,7 +25,7 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR #include #include @@ -109,9 +171,9 @@ diff -rupN glucose-syrup/utils/ParseUtils.h glucose-syrup-patched/utils/ParseUti int operator * () const { return (pos >= size) ? EOF : buf[pos]; } void operator ++ () { pos++; assureLookahead(); } -diff -rupN glucose-syrup/utils/System.h glucose-syrup-patched/utils/System.h ---- glucose-syrup/utils/System.h 2014-10-03 10:10:22.000000000 +0100 -+++ glucose-syrup-patched/utils/System.h 2016-07-08 13:06:02.776186005 +0100 +diff -rupNw glucose-syrup/utils/System.h glucose-syrup-patched/utils/System.h +--- glucose-syrup/utils/System.h 2014-10-03 11:10:22.000000000 +0200 ++++ glucose-syrup-patched/utils/System.h 2018-04-21 16:58:22.950005391 +0200 @@ -60,8 +60,11 @@ static inline double Glucose::cpuTime(vo // Laurent: I know that this will not compile directly under Windows... sorry for that diff --git a/scripts/glucose_CMakeLists.txt b/scripts/glucose_CMakeLists.txt index 94165238d8a..38506152963 100644 --- a/scripts/glucose_CMakeLists.txt +++ b/scripts/glucose_CMakeLists.txt @@ -18,3 +18,5 @@ target_include_directories(glucose-condensed PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ) + +target_link_libraries(glucose-condensed util) diff --git a/scripts/string_table_check.sh b/scripts/string_table_check.sh new file mode 100755 index 00000000000..5bf6d4b2dd2 --- /dev/null +++ b/scripts/string_table_check.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +whitelist=" \ +" + +cleanup() +{ + rm -f "$ids_file" +} + +ids_file=$(mktemp) + +trap cleanup EXIT + +gcc -E -P -x c src/util/irep_ids.def \ + -D'IREP_ID_ONE(x)=ID_ ## x' -D'IREP_ID_TWO(x,y)=ID_ ## x' > $ids_file + +for w in $whitelist +do + perl -p -i -e "s/^$w\n//" $ids_file +done + +for i in $(<$ids_file) +do + if ! git grep -w -q -c -F $i + then + echo "$i is never used" + exit 1 + fi +done diff --git a/src/Makefile b/src/Makefile index 82141a0f317..d28a2bdc976 100644 --- a/src/Makefile +++ b/src/Makefile @@ -25,6 +25,8 @@ languages: util.dir langapi.dir \ cpp.dir ansi-c.dir xmllang.dir assembler.dir java_bytecode.dir \ jsil.dir +solvers.dir: util.dir langapi.dir + goto-instrument.dir: languages goto-programs.dir pointer-analysis.dir \ goto-symex.dir linking.dir analyses.dir solvers.dir \ json.dir @@ -107,6 +109,15 @@ ipasir-build: ipasir-download $(MAKE) -C ../ipasir/sat/picosat961 libipasirpicosat961.a @(cd ../ipasir; ln -sf sat/picosat961/libipasirpicosat961.a libipasir.a) +cadical_release = rel-06w +cadical-download: + @echo "Downloading CaDiCaL $(cadical_release)" + @curl -L https://github.com/arminbiere/cadical/archive/$(cadical_release).tar.gz | tar xz + @rm -Rf ../cadical + @mv cadical-$(cadical_release) ../cadical + @(cd ../cadical; patch -p1 < ../scripts/cadical-patch) + @cd ../cadical && CXX=$(CXX) CXXFLAGS=-O3 ./configure --debug && make + doc : doxygen diff --git a/src/analyses/goto_rw.h b/src/analyses/goto_rw.h index 02f17a7af16..d84c6da1964 100644 --- a/src/analyses/goto_rw.h +++ b/src/analyses/goto_rw.h @@ -12,9 +12,9 @@ Date: April 2010 #ifndef CPROVER_ANALYSES_GOTO_RW_H #define CPROVER_ANALYSES_GOTO_RW_H -#include -#include +#include #include +#include #include // unique_ptr #include diff --git a/src/ansi-c/ansi_c_entry_point.cpp b/src/ansi-c/ansi_c_entry_point.cpp index a632d616fc2..f15a3124f55 100644 --- a/src/ansi-c/ansi_c_entry_point.cpp +++ b/src/ansi-c/ansi_c_entry_point.cpp @@ -8,21 +8,13 @@ Author: Daniel Kroening, kroening@kroening.com #include "ansi_c_entry_point.h" -#include -#include - #include #include #include -#include -#include -#include -#include -#include #include -#include #include + #include #include "c_nondet_symbol_factory.h" @@ -217,7 +209,7 @@ bool generate_ansi_c_start_function( if(init_it==symbol_table.symbols.end()) { messaget message(message_handler); - message.error() << "failed to find " CPROVER_PREFIX "initialize symbol" + message.error() << "failed to find " INITIALIZE_FUNCTION " symbol" << messaget::eom; return true; } diff --git a/src/ansi-c/ansi_c_internal_additions.cpp b/src/ansi-c/ansi_c_internal_additions.cpp index 845e2197e84..47ef1c503f5 100644 --- a/src/ansi-c/ansi_c_internal_additions.cpp +++ b/src/ansi-c/ansi_c_internal_additions.cpp @@ -10,6 +10,8 @@ Author: Daniel Kroening, kroening@kroening.com #include +#include + const char gcc_builtin_headers_types[]= "# 1 \"gcc_builtin_headers_types.h\"\n" #include "gcc_builtin_headers_types.inc" @@ -172,7 +174,7 @@ void ansi_c_internal_additions(std::string &code) "\n" // This function needs to be declared, or otherwise can't be called // by the entry-point construction. - "void __CPROVER_initialize(void);\n" + "void " INITIALIZE_FUNCTION "(void);\n" "\n"; // GCC junk stuff, also for CLANG and ARM diff --git a/src/ansi-c/c_nondet_symbol_factory.cpp b/src/ansi-c/c_nondet_symbol_factory.cpp index 9b7d88d2bfb..8200e70a84e 100644 --- a/src/ansi-c/c_nondet_symbol_factory.cpp +++ b/src/ansi-c/c_nondet_symbol_factory.cpp @@ -11,22 +11,14 @@ Author: Diffblue Ltd. #include "c_nondet_symbol_factory.h" -#include -#include - #include #include #include #include -#include -#include -#include #include #include #include -#include - #include /// Create a new temporary static symbol diff --git a/src/ansi-c/c_typecheck_base.cpp b/src/ansi-c/c_typecheck_base.cpp index 1d213aa8f0a..890815fcc86 100644 --- a/src/ansi-c/c_typecheck_base.cpp +++ b/src/ansi-c/c_typecheck_base.cpp @@ -708,7 +708,12 @@ void c_typecheck_baset::typecheck_declaration( // alias function need not have been declared yet, thus // can't lookup - symbol.value=symbol_exprt(full_spec.alias); + // also cater for renaming/placement in sections + const auto &renaming_entry = asm_label_map.find(full_spec.alias); + if(renaming_entry == asm_label_map.end()) + symbol.value = symbol_exprt(full_spec.alias); + else + symbol.value = symbol_exprt(renaming_entry->second); symbol.is_macro=true; } @@ -716,8 +721,18 @@ void c_typecheck_baset::typecheck_declaration( apply_asm_label(full_spec.asm_label, symbol); else { - std::string asm_name; - asm_name=id2string(full_spec.section)+"$$"; + // section name is not empty, do a bit of parsing + std::string asm_name = id2string(full_spec.section); + if(asm_name[0] != '.') + { + warning().source_location = symbol.location; + warning() << "section name `" << asm_name + << "' expected to start with `.'" << eom; + } + std::string::size_type primary_section = asm_name.find('.', 1); + if(primary_section != std::string::npos) + asm_name.resize(primary_section); + asm_name += "$$"; if(!full_spec.asm_label.empty()) asm_name+=id2string(full_spec.asm_label); else diff --git a/src/ansi-c/c_typecheck_expr.cpp b/src/ansi-c/c_typecheck_expr.cpp index be300c00258..b3d7389f995 100644 --- a/src/ansi-c/c_typecheck_expr.cpp +++ b/src/ansi-c/c_typecheck_expr.cpp @@ -14,17 +14,14 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include #include -#include -#include -#include #include -#include -#include -#include -#include +#include #include #include +#include +#include #include "builtin_factory.h" #include "c_typecast.h" @@ -1431,25 +1428,31 @@ void c_typecheck_baset::typecheck_expr_ptrmember(exprt &expr) const typet &final_op0_type=follow(expr.op0().type()); - if(final_op0_type.id()!=ID_pointer && - final_op0_type.id()!=ID_array) + if(final_op0_type.id()==ID_array) + { + // a->f is the same as a[0].f + exprt zero=from_integer(0, index_type()); + index_exprt index_expr(expr.op0(), zero, final_op0_type.subtype()); + index_expr.set(ID_C_lvalue, true); + expr.op0().swap(index_expr); + } + else if(final_op0_type.id()==ID_pointer) + { + // turn x->y into (*x).y + dereference_exprt deref_expr(expr.op0()); + deref_expr.add_source_location()=expr.source_location(); + typecheck_expr_dereference(deref_expr); + expr.op0().swap(deref_expr); + } + else { err_location(expr); - error() << "ptrmember operator requires pointer type " + error() << "ptrmember operator requires pointer or array type " "on left hand side, but got `" << to_string(expr.op0().type()) << "'" << eom; throw 0; } - // turn x->y into (*x).y - - dereference_exprt deref(expr.op0()); - deref.add_source_location()=expr.source_location(); - - typecheck_expr_dereference(deref); - - expr.op0().swap(deref); - expr.id(ID_member); typecheck_expr_member(expr); } diff --git a/src/ansi-c/c_typecheck_type.cpp b/src/ansi-c/c_typecheck_type.cpp index 0a4d12ba913..dcb40a0e897 100644 --- a/src/ansi-c/c_typecheck_type.cpp +++ b/src/ansi-c/c_typecheck_type.cpp @@ -13,19 +13,16 @@ Author: Daniel Kroening, kroening@kroening.com #include +#include #include #include -#include -#include -#include -#include #include +#include +#include "ansi_c_convert_type.h" #include "c_qualifiers.h" -#include "ansi_c_declaration.h" #include "padding.h" #include "type2name.h" -#include "ansi_c_convert_type.h" void c_typecheck_baset::typecheck_type(typet &type) { @@ -581,10 +578,9 @@ void c_typecheck_baset::typecheck_array_type(array_typet &type) new_symbol.base_name=id2string(current_symbol.base_name)+suffix; new_symbol.type=size.type(); new_symbol.type.set(ID_C_constant, true); - new_symbol.is_type=false; - new_symbol.is_static_lifetime=false; new_symbol.value=size; new_symbol.location=source_location; + new_symbol.mode = mode; symbol_table.add(new_symbol); diff --git a/src/ansi-c/expr2c.cpp b/src/ansi-c/expr2c.cpp index 8e723404511..305a38e008f 100644 --- a/src/ansi-c/expr2c.cpp +++ b/src/ansi-c/expr2c.cpp @@ -8,34 +8,23 @@ Author: Daniel Kroening, kroening@kroening.com #include "expr2c.h" +#include #include -#include -#include - -#ifdef _WIN32 -#ifndef __MINGW32__ -#define snprintf sprintf_s -#endif -#endif +#include #include -#include #include #include #include -#include -#include -#include +#include #include -#include -#include #include +#include #include -#include -#include -#include #include +#include +#include #include "c_misc.h" #include "c_qualifiers.h" @@ -89,6 +78,9 @@ static std::string clean_identifier(const irep_idt &id) *it2='_'; } + // rewrite . as used in ELF section names + std::replace(dest.begin(), dest.end(), '.', '_'); + return dest; } @@ -2254,9 +2246,9 @@ std::string expr2ct::convert_array( dest+=static_cast(ch); else { - char hexbuf[10]; - snprintf(hexbuf, sizeof(hexbuf), "\\x%x", ch); - dest+=hexbuf; + std::ostringstream oss; + oss << "\\x" << std::hex << ch; + dest += oss.str(); last_was_hex=true; } } diff --git a/src/ansi-c/padding.cpp b/src/ansi-c/padding.cpp index 3b87a6190d8..3139df62e52 100644 --- a/src/ansi-c/padding.cpp +++ b/src/ansi-c/padding.cpp @@ -199,9 +199,9 @@ void add_padding(struct_typet &type, const namespacet &ns) max_alignment=a; std::size_t w=to_c_bit_field_type(it_type).get_width(); - std::size_t bytes; - for(bytes=0; w>bit_field_bits; ++bytes, bit_field_bits+=8) {} - bit_field_bits-=w; + bit_field_bits += w; + const std::size_t bytes = bit_field_bits / 8; + bit_field_bits %= 8; offset+=bytes; continue; } @@ -209,6 +209,9 @@ void add_padding(struct_typet &type, const namespacet &ns) else a=alignment(it_type, ns); + DATA_INVARIANT( + bit_field_bits == 0, "padding ensures offset at byte boundaries"); + // check minimum alignment if(a #include +#include #include -#include -#include #include -#include +#include +#include typedef std::unordered_map> symbol_numbert; diff --git a/src/cbmc/bmc.cpp b/src/cbmc/bmc.cpp index 37bedbed2f4..34edbb516a6 100644 --- a/src/cbmc/bmc.cpp +++ b/src/cbmc/bmc.cpp @@ -12,45 +12,29 @@ Author: Daniel Kroening, kroening@kroening.com #include "bmc.h" #include -#include -#include #include -#include #include #include -#include #include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include #include +#include +#include #include +#include #include #include -#include -#include -#include + +#include #include "cbmc_solvers.h" #include "counterexample_beautification.h" #include "fault_localization.h" -void bmct::do_unwind_module() -{ - // this is a hook for hw-cbmc -} - /// Hook used by CEGIS to selectively freeze variables /// in the SAT solver after the SSA formula is added to the solver. /// Freezing variables is necessary to make use of incremental @@ -129,22 +113,11 @@ void bmct::output_graphml(resultt result) void bmct::do_conversion() { - // convert HDL (hook for hw-cbmc) - do_unwind_module(); - status() << "converting SSA" << eom; // convert SSA equation.convert(prop_conv); - // the 'extra constraints' - if(!bmc_constraints.empty()) - { - status() << "converting constraints" << eom; - - for(const auto &constraint : bmc_constraints) - prop_conv.set_to_true(constraint); - } // hook for cegis to freeze synthesis program vars freeze_program_variables(); } @@ -338,7 +311,7 @@ void bmct::setup() { const symbolt *init_symbol; - if(!ns.lookup(CPROVER_PREFIX "initialize", init_symbol)) + if(!ns.lookup(INITIALIZE_FUNCTION, init_symbol)) symex.language_mode=init_symbol->mode; } @@ -385,9 +358,9 @@ safety_checkert::resultt bmct::execute( (*memory_model)(equation); } - statistics() << "size of program expression: " - << equation.SSA_steps.size() - << " steps" << eom; + statistics() << "size of program expression: " + << equation.SSA_steps.size() + << " steps" << eom; slice(); diff --git a/src/cbmc/bmc.h b/src/cbmc/bmc.h index 0f394199fe0..551fa7c2b3d 100644 --- a/src/cbmc/bmc.h +++ b/src/cbmc/bmc.h @@ -18,13 +18,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include - -#include -#include -#include -#include -#include -#include +#include #include @@ -100,9 +94,6 @@ class bmct:public safety_checkert safety_checkert::resultt execute(abstract_goto_modelt &); virtual ~bmct() { } - // additional stuff - std::list bmc_constraints; - void set_ui(ui_message_handlert::uit _ui) { ui=_ui; } // the safety_checkert interface @@ -191,7 +182,6 @@ class bmct:public safety_checkert // unwinding virtual void setup_unwind(); - virtual void do_unwind_module(); void do_conversion(); virtual void freeze_program_variables(); diff --git a/src/cbmc/cbmc_parse_options.cpp b/src/cbmc/cbmc_parse_options.cpp index 5962d65ecc9..3eb08b6fd9a 100644 --- a/src/cbmc/cbmc_parse_options.cpp +++ b/src/cbmc/cbmc_parse_options.cpp @@ -312,100 +312,64 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options) options.set_option("aig", true); // SMT Options - bool version_set=false; if(cmdline.isset("smt1")) { - options.set_option("smt1", true); - options.set_option("smt2", false); - version_set=true; + error() << "--smt1 is no longer supported" << eom; + exit(CPROVER_EXIT_USAGE_ERROR); } if(cmdline.isset("smt2")) - { - // If both are given, smt2 takes precedence - options.set_option("smt1", false); options.set_option("smt2", true); - version_set=true; - } if(cmdline.isset("fpa")) options.set_option("fpa", true); - bool solver_set=false; if(cmdline.isset("boolector")) { options.set_option("boolector", true), solver_set=true; - if(!version_set) - options.set_option("smt2", true), version_set=true; + options.set_option("smt2", true); } if(cmdline.isset("mathsat")) { options.set_option("mathsat", true), solver_set=true; - if(!version_set) - options.set_option("smt2", true), version_set=true; - } - - if(cmdline.isset("cvc3")) - { - options.set_option("cvc3", true), solver_set=true; - if(!version_set) - options.set_option("smt1", true), version_set=true; + options.set_option("smt2", true); } if(cmdline.isset("cvc4")) { options.set_option("cvc4", true), solver_set=true; - if(!version_set) - options.set_option("smt2", true), version_set=true; + options.set_option("smt2", true); } if(cmdline.isset("yices")) { options.set_option("yices", true), solver_set=true; - if(!version_set) - options.set_option("smt2", true), version_set=true; + options.set_option("smt2", true); } if(cmdline.isset("z3")) { options.set_option("z3", true), solver_set=true; - if(!version_set) - options.set_option("smt2", true), version_set=true; - } - - if(cmdline.isset("opensmt")) - { - options.set_option("opensmt", true), solver_set=true; - if(!version_set) - options.set_option("smt1", true), version_set=true; + options.set_option("smt2", true); } - if(version_set && !solver_set) + if(cmdline.isset("smt2") && !solver_set) { if(cmdline.isset("outfile")) { // outfile and no solver should give standard compliant SMT-LIB - options.set_option("generic", true), solver_set=true; + options.set_option("generic", true); } else { - if(options.get_bool_option("smt1")) - { - options.set_option("boolector", true), solver_set=true; - } - else - { - PRECONDITION(options.get_bool_option("smt2")); - options.set_option("z3", true), solver_set=true; - } + // the default smt2 solver + options.set_option("z3", true); } } - // Either have solver and standard version set, or neither. - PRECONDITION(version_set == solver_set); if(cmdline.isset("beautify")) options.set_option("beautify", true); @@ -999,8 +963,9 @@ void cbmc_parse_optionst::help() " --refine use refinement procedure (experimental)\n" " --refine-strings use string refinement (experimental)\n" " --string-printable add constraint that strings are printable (experimental)\n" // NOLINT(*) - " --string-max-length add constraint on the length of strings\n" // NOLINT(*) " --string-max-input-length add constraint on the length of input strings\n" // NOLINT(*) + " --string-max-length add constraint on the length of strings" + " (deprecated: use string-max-input-length instead)\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_solvers.cpp b/src/cbmc/cbmc_solvers.cpp index 557bf1ca3b7..e5a29ba7fe6 100644 --- a/src/cbmc/cbmc_solvers.cpp +++ b/src/cbmc/cbmc_solvers.cpp @@ -21,7 +21,6 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include -#include #include #include #include @@ -32,34 +31,6 @@ Author: Daniel Kroening, kroening@kroening.com #include "counterexample_beautification.h" #include "version.h" -/// Uses the options to pick an SMT 1.2 solver -/// \return An smt1_dect::solvert giving the solver to use. -smt1_dect::solvert cbmc_solverst::get_smt1_solver_type() const -{ - assert(options.get_bool_option("smt1")); - - smt1_dect::solvert s=smt1_dect::solvert::GENERIC; - - if(options.get_bool_option("boolector")) - s=smt1_dect::solvert::BOOLECTOR; - else if(options.get_bool_option("mathsat")) - s=smt1_dect::solvert::MATHSAT; - else if(options.get_bool_option("cvc3")) - s=smt1_dect::solvert::CVC3; - else if(options.get_bool_option("cvc4")) - s=smt1_dect::solvert::CVC4; - else if(options.get_bool_option("opensmt")) - s=smt1_dect::solvert::OPENSMT; - else if(options.get_bool_option("yices")) - s=smt1_dect::solvert::YICES; - else if(options.get_bool_option("z3")) - s=smt1_dect::solvert::Z3; - else if(options.get_bool_option("generic")) - s=smt1_dect::solvert::GENERIC; - - return s; -} - /// Uses the options to pick an SMT 2.0 solver /// \return An smt2_dect::solvert giving the solver to use. smt2_dect::solvert cbmc_solverst::get_smt2_solver_type() const @@ -76,8 +47,6 @@ smt2_dect::solvert cbmc_solverst::get_smt2_solver_type() const s=smt2_dect::solvert::CVC3; else if(options.get_bool_option("cvc4")) s=smt2_dect::solvert::CVC4; - else if(options.get_bool_option("opensmt")) - s=smt2_dect::solvert::OPENSMT; else if(options.get_bool_option("yices")) s=smt2_dect::solvert::YICES; else if(options.get_bool_option("z3")) @@ -177,7 +146,7 @@ std::unique_ptr cbmc_solverst::get_string_refinement() info.refinement_bound=DEFAULT_MAX_NB_REFINEMENT; info.ui=ui; if(options.get_bool_option("string-max-length")) - info.string_max_length=options.get_signed_int_option("string-max-length"); + info.max_string_length = options.get_signed_int_option("string-max-length"); info.trace=options.get_bool_option("trace"); if(options.get_bool_option("max-node-refinement")) info.max_node_refinement= @@ -189,76 +158,6 @@ std::unique_ptr cbmc_solverst::get_string_refinement() util_make_unique(info), std::move(prop)); } -std::unique_ptr cbmc_solverst::get_smt1( - smt1_dect::solvert solver) -{ - no_beautification(); - no_incremental_check(); - - const std::string &filename=options.get_option("outfile"); - - if(filename=="") - { - if(solver==smt1_dect::solvert::GENERIC) - { - error() << "please use --outfile" << eom; - throw 0; - } - - auto smt1_dec= - util_make_unique( - ns, - "cbmc", - "Generated by CBMC " CBMC_VERSION, - "QF_AUFBV", - solver); - - return util_make_unique(std::move(smt1_dec)); - } - else if(filename=="-") - { - auto smt1_conv= - util_make_unique( - ns, - "cbmc", - "Generated by CBMC " CBMC_VERSION, - "QF_AUFBV", - solver, - std::cout); - - smt1_conv->set_message_handler(get_message_handler()); - - return util_make_unique(std::move(smt1_conv)); - } - else - { - #ifdef _MSC_VER - auto out=util_make_unique(widen(filename)); - #else - auto out=util_make_unique(filename); - #endif - - if(!out) - { - error() << "failed to open " << filename << eom; - throw 0; - } - - auto smt1_conv= - util_make_unique( - ns, - "cbmc", - "Generated by CBMC " CBMC_VERSION, - "QF_AUFBV", - solver, - *out); - - smt1_conv->set_message_handler(get_message_handler()); - - return util_make_unique(std::move(smt1_conv), std::move(out)); - } -} - std::unique_ptr cbmc_solverst::get_smt2( smt2_dect::solvert solver) { diff --git a/src/cbmc/cbmc_solvers.h b/src/cbmc/cbmc_solvers.h index 2245ff59b70..66df55eca87 100644 --- a/src/cbmc/cbmc_solvers.h +++ b/src/cbmc/cbmc_solvers.h @@ -24,7 +24,6 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include -#include #include #include @@ -112,8 +111,6 @@ class cbmc_solverst:public messaget return get_bv_refinement(); else if(options.get_bool_option("refine-strings")) return get_string_refinement(); - if(options.get_bool_option("smt1")) - return get_smt1(get_smt1_solver_type()); if(options.get_bool_option("smt2")) return get_smt2(get_smt2_solver_type()); return get_default(); @@ -137,10 +134,8 @@ class cbmc_solverst:public messaget std::unique_ptr get_dimacs(); std::unique_ptr get_bv_refinement(); std::unique_ptr get_string_refinement(); - std::unique_ptr get_smt1(smt1_dect::solvert solver); std::unique_ptr get_smt2(smt2_dect::solvert solver); - smt1_dect::solvert get_smt1_solver_type() const; smt2_dect::solvert get_smt2_solver_type() const; // consistency checks during solver creation diff --git a/src/cbmc/symex_coverage.cpp b/src/cbmc/symex_coverage.cpp index fec36dd1f5f..0ecd58b1083 100644 --- a/src/cbmc/symex_coverage.cpp +++ b/src/cbmc/symex_coverage.cpp @@ -13,22 +13,21 @@ Date: March 2016 #include "symex_coverage.h" -#include #include -#include +#include #include -#include +#include -#include #include -#include -#include +#include #include #include #include +#include + class coverage_recordt { public: @@ -313,7 +312,7 @@ void symex_coveraget::compute_overall_coverage( { if(!gf_it->second.body_available() || gf_it->first==goto_functions.entry_point() || - gf_it->first==CPROVER_PREFIX "initialize") + gf_it->first == INITIALIZE_FUNCTION) continue; goto_program_coverage_recordt func_cov(ns, gf_it, coverage); diff --git a/src/cbmc/symex_coverage.h b/src/cbmc/symex_coverage.h index b7556b1087b..6eac2cf4ef7 100644 --- a/src/cbmc/symex_coverage.h +++ b/src/cbmc/symex_coverage.h @@ -14,9 +14,9 @@ Date: March 2016 #ifndef CPROVER_CBMC_SYMEX_COVERAGE_H #define CPROVER_CBMC_SYMEX_COVERAGE_H -#include -#include +#include #include +#include #include diff --git a/src/clobber/CMakeLists.txt b/src/clobber/CMakeLists.txt index 384ae51824e..2e4803df7e2 100644 --- a/src/clobber/CMakeLists.txt +++ b/src/clobber/CMakeLists.txt @@ -25,7 +25,6 @@ target_link_libraries(clobber-lib ) add_if_library(clobber-lib bv_refinement) -add_if_library(clobber-lib java_bytecode) add_if_library(clobber-lib specc) add_if_library(clobber-lib php) diff --git a/src/clobber/Makefile b/src/clobber/Makefile index 74a133782c6..d9b9f09de1c 100644 --- a/src/clobber/Makefile +++ b/src/clobber/Makefile @@ -1,9 +1,9 @@ SRC = clobber_main.cpp \ clobber_parse_options.cpp \ # Empty last line + OBJ += ../ansi-c/ansi-c$(LIBEXT) \ ../cpp/cpp$(LIBEXT) \ - ../java_bytecode/java_bytecode$(LIBEXT) \ ../linking/linking$(LIBEXT) \ ../big-int/big-int$(LIBEXT) \ ../goto-programs/goto-programs$(LIBEXT) \ diff --git a/src/common b/src/common index ef872268350..81ede8836ab 100644 --- a/src/common +++ b/src/common @@ -159,7 +159,7 @@ else endif # select default solver to be minisat2 if no other is specified -ifeq ($(BOOLEFORCE)$(CHAFF)$(GLUCOSE)$(IPASIR)$(LINGELING)$(MINISAT)$(MINISAT2)$(PICOSAT),) +ifeq ($(BOOLEFORCE)$(CHAFF)$(GLUCOSE)$(IPASIR)$(LINGELING)$(MINISAT)$(MINISAT2)$(PICOSAT)$(CADICAL),) MINISAT2 = ../../minisat-2.2.1 endif @@ -195,6 +195,10 @@ ifneq ($(GLUCOSE),) CP_CXXFLAGS += -DHAVE_GLUCOSE endif +ifneq ($(CADICAL),) + CP_CXXFLAGS += -DHAVE_CADICAL +endif + first_target: all diff --git a/src/config.inc b/src/config.inc index 00d2bda6845..1bbaee22575 100644 --- a/src/config.inc +++ b/src/config.inc @@ -24,6 +24,7 @@ endif #MINISAT2 = ../../minisat-2.2.1 #IPASIR = ../../ipasir #GLUCOSE = ../../glucose-syrup +#CADICAL = ../../cadical # Extra library for SAT solver. This should link to the archive file to be used # when linking against an IPASIR solver. @@ -57,6 +58,10 @@ ifneq ($(GLUCOSE),) CP_CXXFLAGS += -DSATCHECK_GLUCOSE endif +ifneq ($(CADICAL),) + CP_CXXFLAGS += -DSATCHECK_CADICAL +endif + # Signing identity for MacOS Gatekeeper OSX_IDENTITY="Developer ID Application: Daniel Kroening" diff --git a/src/cpp/cpp_exception_id.cpp b/src/cpp/cpp_exception_id.cpp index 23d7f49a30c..aef6606a4bd 100644 --- a/src/cpp/cpp_exception_id.cpp +++ b/src/cpp/cpp_exception_id.cpp @@ -11,6 +11,8 @@ Author: Daniel Kroening, kroening@cs.cmu.edu #include "cpp_exception_id.h" +#include + /// turns a type into a list of relevant exception IDs void cpp_exception_list_rec( const typet &src, @@ -91,6 +93,6 @@ irep_idt cpp_exception_id( { std::vector ids; cpp_exception_list_rec(src, ns, "", ids); - assert(!ids.empty()); + CHECK_RETURN(!ids.empty()); return ids.front(); } diff --git a/src/cpp/cpp_internal_additions.cpp b/src/cpp/cpp_internal_additions.cpp index 19260f6ac24..85363a59b69 100644 --- a/src/cpp/cpp_internal_additions.cpp +++ b/src/cpp/cpp_internal_additions.cpp @@ -14,6 +14,8 @@ Author: Daniel Kroening, kroening@kroening.com #include +#include + std::string c2cpp(const std::string &s) { std::string result; @@ -75,7 +77,7 @@ void cpp_internal_additions(std::ostream &out) // CPROVER extensions out << "extern \"C\" const unsigned __CPROVER::constant_infinity_uint;\n"; - out << "extern \"C\" void __CPROVER_initialize();" << '\n'; + out << "extern \"C\" void " INITIALIZE_FUNCTION "();" << '\n'; out << "extern \"C\" void __CPROVER::input(const char *id, ...);" << '\n'; out << "extern \"C\" void __CPROVER::output(const char *id, ...);" << '\n'; out << "extern \"C\" void __CPROVER::cover(bool condition);" << '\n'; diff --git a/src/cpp/cpp_name.h b/src/cpp/cpp_name.h index a27374c5524..bb9e1007cf6 100644 --- a/src/cpp/cpp_name.h +++ b/src/cpp/cpp_name.h @@ -11,6 +11,7 @@ Author: Daniel Kroening, kroening@cs.cmu.edu #define CPROVER_CPP_CPP_NAME_H #include +#include class cpp_namet:public irept { @@ -142,13 +143,13 @@ class cpp_namet:public irept inline cpp_namet &to_cpp_name(irept &cpp_name) { - assert(cpp_name.id() == ID_cpp_name); + PRECONDITION(cpp_name.id() == ID_cpp_name); return static_cast(cpp_name); } inline const cpp_namet &to_cpp_name(const irept &cpp_name) { - assert(cpp_name.id() == ID_cpp_name); + PRECONDITION(cpp_name.id() == ID_cpp_name); return static_cast(cpp_name); } diff --git a/src/cpp/cpp_template_args.h b/src/cpp/cpp_template_args.h index 47ceca5f003..22018dfaad4 100644 --- a/src/cpp/cpp_template_args.h +++ b/src/cpp/cpp_template_args.h @@ -13,6 +13,7 @@ Author: Daniel Kroening, kroening@cs.cmu.edu #define CPROVER_CPP_CPP_TEMPLATE_ARGS_H #include +#include // A data structures for template arguments, i.e., // a sequence of types/expressions of the form . @@ -47,14 +48,14 @@ class cpp_template_args_non_tct:public cpp_template_args_baset inline cpp_template_args_non_tct &to_cpp_template_args_non_tc( irept &irep) { - assert(irep.id()==ID_template_args); + PRECONDITION(irep.id() == ID_template_args); return static_cast(irep); } inline const cpp_template_args_non_tct &to_cpp_template_args_non_tc( const irept &irep) { - assert(irep.id()==ID_template_args); + PRECONDITION(irep.id() == ID_template_args); return static_cast(irep); } @@ -80,13 +81,13 @@ class cpp_template_args_tct:public cpp_template_args_baset inline cpp_template_args_tct &to_cpp_template_args_tc(irept &irep) { - assert(irep.id()==ID_template_args); + PRECONDITION(irep.id() == ID_template_args); return static_cast(irep); } inline const cpp_template_args_tct &to_cpp_template_args_tc(const irept &irep) { - assert(irep.id()==ID_template_args); + PRECONDITION(irep.id() == ID_template_args); return static_cast(irep); } diff --git a/src/cpp/cpp_template_type.h b/src/cpp/cpp_template_type.h index 57e9d257e1d..9c69e6208de 100644 --- a/src/cpp/cpp_template_type.h +++ b/src/cpp/cpp_template_type.h @@ -10,8 +10,8 @@ Author: Daniel Kroening, kroening@cs.cmu.edu #ifndef CPROVER_CPP_CPP_TEMPLATE_TYPE_H #define CPROVER_CPP_CPP_TEMPLATE_TYPE_H +#include #include -#include #include "cpp_template_parameter.h" @@ -37,13 +37,13 @@ class template_typet:public typet inline template_typet &to_template_type(typet &type) { - assert(type.id()==ID_template); + PRECONDITION(type.id() == ID_template); return static_cast(type); } inline const template_typet &to_template_type(const typet &type) { - assert(type.id()==ID_template); + PRECONDITION(type.id() == ID_template); return static_cast(type); } diff --git a/src/cpp/cpp_token_buffer.h b/src/cpp/cpp_token_buffer.h index b24f84dbe70..4d3acdbfc3c 100644 --- a/src/cpp/cpp_token_buffer.h +++ b/src/cpp/cpp_token_buffer.h @@ -16,6 +16,8 @@ Author: Daniel Kroening, kroening@cs.cmu.edu #include +#include + class cpp_token_buffert { public: @@ -45,7 +47,7 @@ class cpp_token_buffert // the token that is currently being read from the file cpp_tokent ¤t_token() { - assert(!tokens.empty()); + PRECONDITION(!tokens.empty()); return tokens.back(); } diff --git a/src/cpp/cpp_typecheck_expr.cpp b/src/cpp/cpp_typecheck_expr.cpp index a6502391c3e..45d7c872759 100644 --- a/src/cpp/cpp_typecheck_expr.cpp +++ b/src/cpp/cpp_typecheck_expr.cpp @@ -15,23 +15,18 @@ Author: Daniel Kroening, kroening@cs.cmu.edu #include #endif -#include -#include #include -#include -#include -#include #include -#include - #include +#include +#include + #include #include -#include "cpp_type2name.h" -#include "cpp_convert_type.h" #include "cpp_exception_id.h" +#include "cpp_type2name.h" #include "expr2cpp.h" bool cpp_typecheckt::find_parent( diff --git a/src/cpp/cpp_typecheck_initializer.cpp b/src/cpp/cpp_typecheck_initializer.cpp index 565bca8a4bb..c4c85637878 100644 --- a/src/cpp/cpp_typecheck_initializer.cpp +++ b/src/cpp/cpp_typecheck_initializer.cpp @@ -14,12 +14,9 @@ Author: Daniel Kroening, kroening@cs.cmu.edu #include #include #include -#include #include -#include "cpp_util.h" - /// Initialize an object with a value void cpp_typecheckt::convert_initializer(symbolt &symbol) { diff --git a/src/cpp/cpp_typecheck_resolve.cpp b/src/cpp/cpp_typecheck_resolve.cpp index afc841da20b..647e1e14e46 100644 --- a/src/cpp/cpp_typecheck_resolve.cpp +++ b/src/cpp/cpp_typecheck_resolve.cpp @@ -839,11 +839,11 @@ exprt cpp_typecheck_resolvet::do_builtin( << ": " << original_scope->prefix << messaget::eom; } - else if(base_name=="size_t") + else if(base_name == ID_size_t) { dest=type_exprt(size_type()); } - else if(base_name=="ssize_t") + else if(base_name == ID_ssize_t) { dest=type_exprt(signed_size_type()); } diff --git a/src/cpp/template_map.cpp b/src/cpp/template_map.cpp index 16949d7aaa7..3526603d1dc 100644 --- a/src/cpp/template_map.cpp +++ b/src/cpp/template_map.cpp @@ -173,14 +173,15 @@ void template_mapt::build( } // these should have been typechecked before - assert(instance.size()==template_parameters.size()); + DATA_INVARIANT( + instance.size() == template_parameters.size(), + "template instantiation expected to match declaration"); for(cpp_template_args_tct::argumentst::const_iterator i_it=instance.begin(); i_it!=instance.end(); i_it++, t_it++) { - assert(t_it!=template_parameters.end()); set(*t_it, *i_it); } } diff --git a/src/goto-analyzer/static_show_domain.cpp b/src/goto-analyzer/static_show_domain.cpp index 99c8d63cefd..835311faf09 100644 --- a/src/goto-analyzer/static_show_domain.cpp +++ b/src/goto-analyzer/static_show_domain.cpp @@ -8,6 +8,8 @@ Author: Martin Brain, martin.brain@cs.ox.ac.uk #include "static_show_domain.h" +#include + #include /// Runs the analyzer and then prints out the domain diff --git a/src/goto-analyzer/static_show_domain.h b/src/goto-analyzer/static_show_domain.h index 5284cc6a9ec..71a6e90ef92 100644 --- a/src/goto-analyzer/static_show_domain.h +++ b/src/goto-analyzer/static_show_domain.h @@ -9,14 +9,12 @@ Author: Martin Brain, martin.brain@cs.ox.ac.uk #ifndef CPROVER_GOTO_ANALYZER_STATIC_SHOW_DOMAIN_H #define CPROVER_GOTO_ANALYZER_STATIC_SHOW_DOMAIN_H -#include +#include -#include -#include - -#include - -#include +class ai_baset; +class goto_modelt; +class message_handlert; +class optionst; bool static_show_domain( const goto_modelt &, diff --git a/src/goto-analyzer/static_simplifier.cpp b/src/goto-analyzer/static_simplifier.cpp index 9e6ffa57822..08e29037c70 100644 --- a/src/goto-analyzer/static_simplifier.cpp +++ b/src/goto-analyzer/static_simplifier.cpp @@ -6,17 +6,17 @@ Author: Martin Brain, martin.brain@cs.ox.ac.uk \*******************************************************************/ +#include "static_simplifier.h" + +#include +#include + +#include #include #include #include -#include -#include -#include -#include - -#include "static_simplifier.h" - +#include /// Simplifies the program using the information in the abstract domain. /// \param goto_model: the program analyzed diff --git a/src/goto-analyzer/static_simplifier.h b/src/goto-analyzer/static_simplifier.h index ee810bf8793..557d94737c0 100644 --- a/src/goto-analyzer/static_simplifier.h +++ b/src/goto-analyzer/static_simplifier.h @@ -9,14 +9,12 @@ Author: Martin Brain, martin.brain@cs.ox.ac.uk #ifndef CPROVER_GOTO_ANALYZER_STATIC_SIMPLIFIER_H #define CPROVER_GOTO_ANALYZER_STATIC_SIMPLIFIER_H -#include +#include -#include -#include - -#include - -#include +class ai_baset; +class goto_modelt; +class message_handlert; +class optionst; bool static_simplifier( goto_modelt &, diff --git a/src/goto-analyzer/static_verifier.cpp b/src/goto-analyzer/static_verifier.cpp index 660d20bd37e..f4fbc6320b7 100644 --- a/src/goto-analyzer/static_verifier.cpp +++ b/src/goto-analyzer/static_verifier.cpp @@ -8,11 +8,14 @@ Author: Martin Brain, martin.brain@cs.ox.ac.uk #include "static_verifier.h" -#include -#include -#include #include +#include +#include +#include +#include + +#include /// Runs the analyzer and then prints out the domain /// \param goto_model: the program analyzed diff --git a/src/goto-analyzer/static_verifier.h b/src/goto-analyzer/static_verifier.h index 77eeacbe527..87358a30958 100644 --- a/src/goto-analyzer/static_verifier.h +++ b/src/goto-analyzer/static_verifier.h @@ -9,14 +9,12 @@ Author: Martin Brain, martin.brain@cs.ox.ac.uk #ifndef CPROVER_GOTO_ANALYZER_STATIC_VERIFIER_H #define CPROVER_GOTO_ANALYZER_STATIC_VERIFIER_H -#include +#include -#include -#include - -#include - -#include +class ai_baset; +class goto_modelt; +class message_handlert; +class optionst; bool static_verifier( const goto_modelt &, diff --git a/src/goto-analyzer/unreachable_instructions.cpp b/src/goto-analyzer/unreachable_instructions.cpp index 0e783baaba5..c691142aead 100644 --- a/src/goto-analyzer/unreachable_instructions.cpp +++ b/src/goto-analyzer/unreachable_instructions.cpp @@ -13,18 +13,16 @@ Date: April 2016 #include "unreachable_instructions.h" -#include - -#include -#include #include +#include +#include #include -#include - -#include #include +#include +#include + typedef std::map dead_mapt; static void unreachable_instructions( diff --git a/src/goto-analyzer/unreachable_instructions.h b/src/goto-analyzer/unreachable_instructions.h index edffd0f7b1c..eeee658ea52 100644 --- a/src/goto-analyzer/unreachable_instructions.h +++ b/src/goto-analyzer/unreachable_instructions.h @@ -14,14 +14,12 @@ Date: April 2016 #ifndef CPROVER_GOTO_ANALYZER_UNREACHABLE_INSTRUCTIONS_H #define CPROVER_GOTO_ANALYZER_UNREACHABLE_INSTRUCTIONS_H -#include - -#include - -#include -#include +#include +class ai_baset; class goto_modelt; +class message_handlert; +class optionst; void unreachable_instructions( const goto_modelt &, diff --git a/src/goto-cc/CMakeLists.txt b/src/goto-cc/CMakeLists.txt index 8259d960561..75b8a7f860c 100644 --- a/src/goto-cc/CMakeLists.txt +++ b/src/goto-cc/CMakeLists.txt @@ -19,7 +19,6 @@ target_link_libraries(goto-cc-lib langapi ) -add_if_library(goto-cc-lib java_bytecode) add_if_library(goto-cc-lib jsil) # Executable diff --git a/src/goto-cc/compile.cpp b/src/goto-cc/compile.cpp index 4f84f36bc3f..98550ce7375 100644 --- a/src/goto-cc/compile.cpp +++ b/src/goto-cc/compile.cpp @@ -15,32 +15,28 @@ Date: June 2006 #include #include -#include #include -#include -#include -#include -#include -#include #include +#include #include -#include -#include -#include #include +#include +#include +#include #include #include #include #include -#include #include #include #include +#include + #include #define DOTGRAPHSETTINGS "color=black;" \ @@ -372,7 +368,7 @@ bool compilet::link() // new symbols may have been added to a previously linked file // make sure a new entry point is created that contains all // static initializers - compiled_functions.function_map.erase("__CPROVER_initialize"); + compiled_functions.function_map.erase(INITIALIZE_FUNCTION); symbol_table.remove(goto_functionst::entry_point()); compiled_functions.function_map.erase(goto_functionst::entry_point()); diff --git a/src/goto-cc/goto_cc_cmdline.cpp b/src/goto-cc/goto_cc_cmdline.cpp index ac86ee38551..f1b933a2847 100644 --- a/src/goto-cc/goto_cc_cmdline.cpp +++ b/src/goto-cc/goto_cc_cmdline.cpp @@ -65,7 +65,7 @@ bool goto_cc_cmdlinet::prefix_in_list( std::size_t goto_cc_cmdlinet::get_optnr(const std::string &opt_string) { - int optnr; + optionalt optnr; cmdlinet::optiont option; if(has_prefix(opt_string, "--")) // starts with -- ? @@ -107,13 +107,13 @@ std::size_t goto_cc_cmdlinet::get_optnr(const std::string &opt_string) } // new? - if(optnr==-1) + if(!optnr.has_value()) { options.push_back(option); return options.size()-1; } - return optnr; + return *optnr; } void goto_cc_cmdlinet::add_infile_arg(const std::string &arg) diff --git a/src/goto-cc/linker_script_merge.cpp b/src/goto-cc/linker_script_merge.cpp index 72ec71f7ad3..d89900d11f3 100644 --- a/src/goto-cc/linker_script_merge.cpp +++ b/src/goto-cc/linker_script_merge.cpp @@ -6,31 +6,25 @@ Author: Kareem Khazem , 2017 \*******************************************************************/ -#include +#include "linker_script_merge.h" #include -#include -#include -#include #include +#include #include #include -#include -#include #include -#include #include -#include #include +#include + +#include #include #include -#include "compile.h" -#include "linker_script_merge.h" - int linker_script_merget::add_linker_script_definitions() { if(!cmdline.isset('T') || elf_binaries.size()!=1) @@ -78,10 +72,10 @@ int linker_script_merget::add_linker_script_definitions() fail=1; linker_valuest linker_values; - const auto &pair=original_gf.function_map.find(CPROVER_PREFIX "initialize"); + const auto &pair=original_gf.function_map.find(INITIALIZE_FUNCTION); if(pair==original_gf.function_map.end()) { - error() << "No " << CPROVER_PREFIX "initialize found in goto_functions" + error() << "No " << INITIALIZE_FUNCTION << " found in goto_functions" << eom; return fail; } @@ -93,7 +87,7 @@ int linker_script_merget::add_linker_script_definitions() linker_values); if(fail!=0) { - error() << "Could not add linkerscript defs to __CPROVER_initialize" << eom; + error() << "Could not add linkerscript defs to " INITIALIZE_FUNCTION << eom; return fail; } diff --git a/src/goto-cc/ms_cl_cmdline.cpp b/src/goto-cc/ms_cl_cmdline.cpp index cdc9458bb0c..7364beca6ba 100644 --- a/src/goto-cc/ms_cl_cmdline.cpp +++ b/src/goto-cc/ms_cl_cmdline.cpp @@ -425,7 +425,7 @@ void ms_cl_cmdlinet::process_cl_option(const std::string &s) if(std::string(s, 1, std::string::npos)==ms_cl_flags[j]) { cmdlinet::optiont option; - int optnr; + optionalt optnr; if(s.size()==2) { @@ -442,13 +442,13 @@ void ms_cl_cmdlinet::process_cl_option(const std::string &s) optnr=getoptnr(option.optstring); } - if(optnr==-1) + if(!optnr.has_value()) { options.push_back(option); optnr=options.size()-1; } - options[optnr].isset=true; + options[*optnr].isset=true; return; } } @@ -461,7 +461,7 @@ void ms_cl_cmdlinet::process_cl_option(const std::string &s) { cmdlinet::optiont option; - int optnr; + optionalt optnr; if(ms_cl_prefix.size()==1) { @@ -478,14 +478,14 @@ void ms_cl_cmdlinet::process_cl_option(const std::string &s) optnr=getoptnr(option.optstring); } - if(optnr==-1) + if(!optnr.has_value()) { options.push_back(option); optnr=options.size()-1; } - options[optnr].isset=true; - options[optnr].values.push_back( + options[*optnr].isset=true; + options[*optnr].values.push_back( std::string(s, ms_cl_prefix.size()+1, std::string::npos)); return; diff --git a/src/goto-diff/goto_diff.h b/src/goto-diff/goto_diff.h index 72171a76b31..efb90d1ed1d 100644 --- a/src/goto-diff/goto_diff.h +++ b/src/goto-diff/goto_diff.h @@ -12,13 +12,14 @@ Author: Peter Schrammel #ifndef CPROVER_GOTO_DIFF_GOTO_DIFF_H #define CPROVER_GOTO_DIFF_GOTO_DIFF_H -#include - -#include #include -#include +#include +#include +class goto_modelt; +class json_arrayt; +class json_objectt; class optionst; class goto_difft:public messaget diff --git a/src/goto-diff/goto_diff_base.cpp b/src/goto-diff/goto_diff_base.cpp index db3b925d702..a06b13edf2b 100644 --- a/src/goto-diff/goto_diff_base.cpp +++ b/src/goto-diff/goto_diff_base.cpp @@ -11,11 +11,12 @@ Author: Peter Schrammel #include "goto_diff.h" -#include - #include #include +#include +#include + /// Output diff result void goto_difft::output_functions() const { diff --git a/src/goto-diff/syntactic_diff.cpp b/src/goto-diff/syntactic_diff.cpp index 83f4ef04a78..558bf1a8eb8 100644 --- a/src/goto-diff/syntactic_diff.cpp +++ b/src/goto-diff/syntactic_diff.cpp @@ -11,6 +11,8 @@ Author: Peter Schrammel #include "syntactic_diff.h" +#include + bool syntactic_difft::operator()() { forall_goto_functions(it, goto_model1.goto_functions) diff --git a/src/goto-instrument/alignment_checks.cpp b/src/goto-instrument/alignment_checks.cpp index 68c173bda7a..758539c68be 100644 --- a/src/goto-instrument/alignment_checks.cpp +++ b/src/goto-instrument/alignment_checks.cpp @@ -11,9 +11,8 @@ Module: Alignment Checks #include "alignment_checks.h" -#include #include -#include +#include void print_struct_alignment_problems( const symbol_tablet &symbol_table, diff --git a/src/goto-instrument/call_sequences.cpp b/src/goto-instrument/call_sequences.cpp index c188828768b..ca36d43ee99 100644 --- a/src/goto-instrument/call_sequences.cpp +++ b/src/goto-instrument/call_sequences.cpp @@ -15,15 +15,15 @@ Date: April 2013 #include #include -#include -#include #include #include #include +#include + void show_call_sequences( const irep_idt &caller, const goto_programt &goto_program) @@ -286,7 +286,7 @@ static void list_calls_and_arguments( continue; const irep_idt &identifier=to_symbol_expr(f).get_identifier(); - if(identifier=="__CPROVER_initialize") + if(identifier == INITIALIZE_FUNCTION) continue; std::string name=from_expr(ns, identifier, f); diff --git a/src/goto-instrument/code_contracts.cpp b/src/goto-instrument/code_contracts.cpp index 256149084eb..98d0d1248eb 100644 --- a/src/goto-instrument/code_contracts.cpp +++ b/src/goto-instrument/code_contracts.cpp @@ -13,7 +13,6 @@ Date: February 2016 #include "code_contracts.h" -#include #include #include @@ -21,6 +20,8 @@ Date: February 2016 #include +#include + #include "loop_utils.h" class code_contractst @@ -385,7 +386,7 @@ void code_contractst::operator()() code_contracts(it->second); goto_functionst::function_mapt::iterator i_it= - goto_functions.function_map.find(CPROVER_PREFIX "initialize"); + goto_functions.function_map.find(INITIALIZE_FUNCTION); assert(i_it!=goto_functions.function_map.end()); for(const auto &contract : summarized) diff --git a/src/goto-instrument/cover_filter.cpp b/src/goto-instrument/cover_filter.cpp index 3ca83843170..2c9c6c3f6d6 100644 --- a/src/goto-instrument/cover_filter.cpp +++ b/src/goto-instrument/cover_filter.cpp @@ -11,9 +11,7 @@ Author: Peter Schrammel #include "cover_filter.h" -#include - -#include +#include /// Filter out functions that are not considered provided by the user /// \param identifier: a function name @@ -26,7 +24,7 @@ bool internal_functions_filtert::operator()( if(identifier == goto_functionst::entry_point()) return false; - if(identifier == (CPROVER_PREFIX "initialize")) + if(identifier == INITIALIZE_FUNCTION) return false; if(goto_function.is_hidden()) diff --git a/src/goto-instrument/dump_c.cpp b/src/goto-instrument/dump_c.cpp index c36cca90179..2715f303063 100644 --- a/src/goto-instrument/dump_c.cpp +++ b/src/goto-instrument/dump_c.cpp @@ -11,23 +11,19 @@ Author: Daniel Kroening, kroening@kroening.com #include "dump_c.h" -#include -#include - +#include #include -#include -#include -#include #include -#include -#include +#include #include #include #include -#include "goto_program2code.h" +#include + #include "dump_c_class.h" +#include "goto_program2code.h" inline std::ostream &operator << (std::ostream &out, dump_ct &src) { @@ -953,7 +949,7 @@ void dump_ct::cleanup_harness(code_blockt &b) symbol_exprt &s=to_symbol_expr(func); if(s.get_identifier()==ID_main) s.set_identifier(CPROVER_PREFIX+id2string(ID_main)); - else if(s.get_identifier()==CPROVER_PREFIX "initialize") + else if(s.get_identifier() == INITIALIZE_FUNCTION) continue; } } diff --git a/src/goto-instrument/interrupt.cpp b/src/goto-instrument/interrupt.cpp index 23bf63eb1a4..4d3416a3b38 100644 --- a/src/goto-instrument/interrupt.cpp +++ b/src/goto-instrument/interrupt.cpp @@ -13,15 +13,7 @@ Date: September 2011 #include "interrupt.h" -#include -#include -#include -#include -#include - -#include - -#include "rw_set.h" +#include #ifdef LOCAL_MAY #include @@ -203,7 +195,7 @@ void interrupt( // now instrument Forall_goto_functions(f_it, goto_model.goto_functions) - if(f_it->first!=CPROVER_PREFIX "initialize" && + if(f_it->first != INITIALIZE_FUNCTION && f_it->first!=goto_functionst::entry_point() && f_it->first!=isr.get_identifier()) interrupt( diff --git a/src/goto-instrument/mmio.cpp b/src/goto-instrument/mmio.cpp index e818e9c4ec8..0e0a2a03693 100644 --- a/src/goto-instrument/mmio.cpp +++ b/src/goto-instrument/mmio.cpp @@ -13,20 +13,8 @@ Date: September 2011 #include "mmio.h" -#include +#include -#include -#include - -#if 0 -#include -#include -#include - -#include -#endif - -#include "interrupt.h" #include "rw_set.h" #ifdef LOCAL_MAY @@ -169,7 +157,7 @@ void mmio( // now instrument Forall_goto_functions(f_it, goto_model.goto_functions) - if(f_it->first!=CPROVER_PREFIX "initialize" && + if(f_it->first != INITIALIZE_FUNCTION && f_it->first!=goto_functionst::entry_point()) mmio(value_sets, goto_model.symbol_table, #ifdef LOCAL_MAY diff --git a/src/goto-instrument/nondet_static.cpp b/src/goto-instrument/nondet_static.cpp index 587b935f80a..51cbf5034fe 100644 --- a/src/goto-instrument/nondet_static.cpp +++ b/src/goto-instrument/nondet_static.cpp @@ -14,13 +14,9 @@ Date: November 2011 #include "nondet_static.h" -#include -#include -#include -#include - #include -#include + +#include void nondet_static( const namespacet &ns, @@ -75,7 +71,7 @@ void nondet_static( const namespacet &ns, goto_functionst &goto_functions) { - nondet_static(ns, goto_functions, CPROVER_PREFIX "initialize"); + nondet_static(ns, goto_functions, INITIALIZE_FUNCTION); // update counters etc. goto_functions.update(); diff --git a/src/goto-instrument/object_id.h b/src/goto-instrument/object_id.h index f7c597a798b..509bf6a15c5 100644 --- a/src/goto-instrument/object_id.h +++ b/src/goto-instrument/object_id.h @@ -12,8 +12,8 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_GOTO_INSTRUMENT_OBJECT_ID_H #define CPROVER_GOTO_INSTRUMENT_OBJECT_ID_H +#include #include -#include #include #include diff --git a/src/goto-instrument/race_check.cpp b/src/goto-instrument/race_check.cpp index b426c98815e..0289148f1ec 100644 --- a/src/goto-instrument/race_check.cpp +++ b/src/goto-instrument/race_check.cpp @@ -13,18 +13,10 @@ Date: February 2006 #include "race_check.h" -#include -#include -#include -#include -#include - -#include -#include - -#include #include +#include + #include "rw_set.h" #ifdef LOCAL_MAY @@ -300,7 +292,7 @@ void race_check( Forall_goto_functions(f_it, goto_model.goto_functions) if(f_it->first!=goto_functionst::entry_point() && - f_it->first!=CPROVER_PREFIX "initialize") + f_it->first != INITIALIZE_FUNCTION) race_check( value_sets, goto_model.symbol_table, diff --git a/src/goto-instrument/rw_set.h b/src/goto-instrument/rw_set.h index 69072389347..3dd99a9a7db 100644 --- a/src/goto-instrument/rw_set.h +++ b/src/goto-instrument/rw_set.h @@ -19,17 +19,17 @@ Date: February 2006 #include #include -#include -#include #include #include -#include #ifdef LOCAL_MAY #include #endif +class namespacet; +class value_setst; + // a container for read/write sets class rw_set_baset diff --git a/src/goto-instrument/stack_depth.cpp b/src/goto-instrument/stack_depth.cpp index 606a25f40bb..9784d648f39 100644 --- a/src/goto-instrument/stack_depth.cpp +++ b/src/goto-instrument/stack_depth.cpp @@ -13,15 +13,12 @@ Date: November 2011 #include "stack_depth.h" -#include -#include -#include -#include #include -#include #include +#include + symbol_exprt add_stack_depth_symbol(symbol_tablet &symbol_table) { const irep_idt identifier="$stack_depth"; @@ -94,17 +91,16 @@ void stack_depth( Forall_goto_functions(f_it, goto_model.goto_functions) if(f_it->second.body_available() && - f_it->first!=CPROVER_PREFIX "initialize" && + f_it->first != INITIALIZE_FUNCTION && f_it->first!=goto_functionst::entry_point()) stack_depth(f_it->second.body, sym, depth, depth_expr); // initialize depth to 0 - goto_functionst::function_mapt::iterator - i_it=goto_model.goto_functions.function_map.find( - CPROVER_PREFIX "initialize"); + goto_functionst::function_mapt::iterator i_it = + goto_model.goto_functions.function_map.find(INITIALIZE_FUNCTION); DATA_INVARIANT( i_it!=goto_model.goto_functions.function_map.end(), - "__CPROVER_initialize must exist"); + INITIALIZE_FUNCTION " must exist"); goto_programt &init=i_it->second.body; goto_programt::targett first=init.instructions.begin(); diff --git a/src/goto-instrument/wmm/goto2graph.cpp b/src/goto-instrument/wmm/goto2graph.cpp index 13587974058..6d130be954b 100644 --- a/src/goto-instrument/wmm/goto2graph.cpp +++ b/src/goto-instrument/wmm/goto2graph.cpp @@ -16,17 +16,10 @@ Date: 2012 #include #include #include -#include -#ifndef _WIN32 -#include -#endif - -#include -#include #include -#include -#include + +#include #include "../rw_set.h" #include "fence.h" @@ -168,7 +161,7 @@ void instrumentert::cfg_visitort::visit_cfg_function( instrumenter.message.debug() << "visit function " << function << messaget::eom; - if(function==CPROVER_PREFIX "initialize") + if(function == INITIALIZE_FUNCTION) { return; } diff --git a/src/goto-instrument/wmm/shared_buffers.cpp b/src/goto-instrument/wmm/shared_buffers.cpp index bf78d1ac742..feadf6af1ad 100644 --- a/src/goto-instrument/wmm/shared_buffers.cpp +++ b/src/goto-instrument/wmm/shared_buffers.cpp @@ -7,11 +7,14 @@ Author: Daniel Kroening, kroening@kroening.com \*******************************************************************/ #include "shared_buffers.h" -#include "fence.h" -#include "../rw_set.h" #include +#include + +#include "../rw_set.h" +#include "fence.h" + /// returns a unique id (for fresh variables) std::string shared_bufferst::unique(void) { @@ -1054,7 +1057,7 @@ void shared_bufferst::cfg_visitort::weak_memory( { shared_buffers.message.debug() << "visit function "<< function << messaget::eom; - if(function==CPROVER_PREFIX "initialize") + if(function == INITIALIZE_FUNCTION) return; namespacet ns(symbol_table); diff --git a/src/goto-instrument/wmm/weak_memory.cpp b/src/goto-instrument/wmm/weak_memory.cpp index 468d944f14a..155e2064383 100644 --- a/src/goto-instrument/wmm/weak_memory.cpp +++ b/src/goto-instrument/wmm/weak_memory.cpp @@ -23,12 +23,10 @@ Date: September 2011 #include -#include -#include -#include - #include +#include + #include "../rw_set.h" #include "shared_buffers.h" @@ -135,7 +133,7 @@ void weak_memory( // all access to shared variables is pushed into assignments Forall_goto_functions(f_it, goto_model.goto_functions) - if(f_it->first!=CPROVER_PREFIX "initialize" && + if(f_it->first != INITIALIZE_FUNCTION && f_it->first!=goto_functionst::entry_point()) introduce_temporaries(value_sets, goto_model.symbol_table, f_it->first, f_it->second.body, diff --git a/src/goto-programs/builtin_functions.cpp b/src/goto-programs/builtin_functions.cpp index a1dc45880ed..13685785d71 100644 --- a/src/goto-programs/builtin_functions.cpp +++ b/src/goto-programs/builtin_functions.cpp @@ -17,17 +17,8 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include -#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include #include @@ -468,8 +459,8 @@ void goto_convertt::do_cpp_new( assert(code_type.parameters().size()==1 || code_type.parameters().size()==2); - const symbolt &tmp_symbol= - new_tmp_symbol(return_type, "new", dest, rhs.source_location()); + const symbolt &tmp_symbol = + new_tmp_symbol(return_type, "new", dest, rhs.source_location(), ID_cpp); tmp_symbol_expr=tmp_symbol.symbol_expr(); @@ -499,8 +490,8 @@ void goto_convertt::do_cpp_new( assert(code_type.parameters().size()==2 || code_type.parameters().size()==3); - const symbolt &tmp_symbol= - new_tmp_symbol(return_type, "new", dest, rhs.source_location()); + const symbolt &tmp_symbol = + new_tmp_symbol(return_type, "new", dest, rhs.source_location(), ID_cpp); tmp_symbol_expr=tmp_symbol.symbol_expr(); @@ -539,217 +530,6 @@ void goto_convertt::do_cpp_new( dest.destructive_append(tmp_initializer); } -void goto_convertt::do_java_new( - const exprt &lhs, - const side_effect_exprt &rhs, - goto_programt &dest) -{ - PRECONDITION(!lhs.is_nil()); - PRECONDITION(rhs.operands().empty()); - PRECONDITION(rhs.type().id() == ID_pointer); - source_locationt location=rhs.source_location(); - typet object_type=rhs.type().subtype(); - - // build size expression - exprt object_size=size_of_expr(object_type, ns); - CHECK_RETURN(object_size.is_not_nil()); - - // we produce a malloc side-effect, which stays - side_effect_exprt malloc_expr(ID_allocate, rhs.type()); - malloc_expr.copy_to_operands(object_size); - // could use true and get rid of the code below - malloc_expr.copy_to_operands(false_exprt()); - - goto_programt::targett t_n=dest.add_instruction(ASSIGN); - t_n->code=code_assignt(lhs, malloc_expr); - t_n->source_location=location; - - // zero-initialize the object - dereference_exprt deref(lhs, object_type); - exprt zero_object= - zero_initializer(object_type, location, ns, get_message_handler()); - set_class_identifier( - to_struct_expr(zero_object), ns, to_symbol_type(object_type)); - goto_programt::targett t_i=dest.add_instruction(ASSIGN); - t_i->code=code_assignt(deref, zero_object); - t_i->source_location=location; -} - -void goto_convertt::do_java_new_array( - const exprt &lhs, - const side_effect_exprt &rhs, - goto_programt &dest) -{ - PRECONDITION(!lhs.is_nil()); // do_java_new_array without lhs not implemented - PRECONDITION(rhs.operands().size() >= 1); // one per dimension - PRECONDITION(rhs.type().id() == ID_pointer); - - source_locationt location=rhs.source_location(); - typet object_type=rhs.type().subtype(); - PRECONDITION(ns.follow(object_type).id() == ID_struct); - - // build size expression - exprt object_size=size_of_expr(object_type, ns); - - CHECK_RETURN(!object_size.is_nil()); - - // we produce a malloc side-effect, which stays - side_effect_exprt malloc_expr(ID_allocate, rhs.type()); - malloc_expr.copy_to_operands(object_size); - // code use true and get rid of the code below - malloc_expr.copy_to_operands(false_exprt()); - - goto_programt::targett t_n=dest.add_instruction(ASSIGN); - t_n->code=code_assignt(lhs, malloc_expr); - t_n->source_location=location; - - const struct_typet &struct_type=to_struct_type(ns.follow(object_type)); - - // Ideally we would have a check for `is_valid_java_array(struct_type)` but - // `is_valid_java_array is part of the java_bytecode module and we cannot - // introduce such dependencies. We do this simple check instead: - PRECONDITION(struct_type.components().size()==3); - - // Init base class: - dereference_exprt deref(lhs, object_type); - exprt zero_object= - zero_initializer(object_type, location, ns, get_message_handler()); - set_class_identifier( - to_struct_expr(zero_object), ns, to_symbol_type(object_type)); - goto_programt::targett t_i=dest.add_instruction(ASSIGN); - t_i->code=code_assignt(deref, zero_object); - t_i->source_location=location; - - // if it's an array, we need to set the length field - member_exprt length( - deref, - struct_type.components()[1].get_name(), - struct_type.components()[1].type()); - goto_programt::targett t_s=dest.add_instruction(ASSIGN); - t_s->code=code_assignt(length, rhs.op0()); - t_s->source_location=location; - - // we also need to allocate space for the data - member_exprt data( - deref, - struct_type.components()[2].get_name(), - struct_type.components()[2].type()); - - // Allocate a (struct realtype**) instead of a (void**) if possible. - const irept &given_element_type=object_type.find(ID_C_element_type); - typet allocate_data_type; - if(given_element_type.is_not_nil()) - { - allocate_data_type= - pointer_type(static_cast(given_element_type)); - } - else - allocate_data_type=data.type(); - - side_effect_exprt data_java_new_expr( - ID_java_new_array_data, allocate_data_type); - - // The instruction may specify a (hopefully small) upper bound on the - // array size, in which case we allocate a fixed-length array that may - // be larger than the `length` member rather than use a true variable- - // length array, which produces a more complex formula in the current - // backend. - const irept size_bound=rhs.find(ID_length_upper_bound); - if(size_bound.is_nil()) - data_java_new_expr.set(ID_size, rhs.op0()); - else - data_java_new_expr.set(ID_size, size_bound); - - // Must directly assign the new array to a temporary - // because goto-symex will notice `x=side_effect_exprt` but not - // `x=typecast_exprt(side_effect_exprt(...))` - symbol_exprt new_array_data_symbol= - new_tmp_symbol( - data_java_new_expr.type(), - "new_array_data", - dest, - location) - .symbol_expr(); - goto_programt::targett t_p2=dest.add_instruction(ASSIGN); - t_p2->code=code_assignt(new_array_data_symbol, data_java_new_expr); - t_p2->source_location=location; - - goto_programt::targett t_p=dest.add_instruction(ASSIGN); - exprt cast_java_new=new_array_data_symbol; - if(cast_java_new.type()!=data.type()) - cast_java_new=typecast_exprt(cast_java_new, data.type()); - t_p->code=code_assignt(data, cast_java_new); - t_p->source_location=location; - - // zero-initialize the data - 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(new_array_data_symbol, zero_element); - goto_programt::targett t_d=dest.add_instruction(OTHER); - t_d->code=array_set; - t_d->source_location=location; - } - - // multi-dimensional? - - if(rhs.operands().size()>=2) - { - // produce - // for(int i=0; i(rhs.type().subtype().find("#element_type")); - assert(sub_type.id()==ID_pointer); - sub_java_new.type()=sub_type; - - side_effect_exprt inc(ID_assign); - inc.operands().resize(2); - inc.op0()=tmp_i; - inc.op1()=plus_exprt(tmp_i, from_integer(1, tmp_i.type())); - - dereference_exprt deref_expr( - plus_exprt(data, tmp_i), data.type().subtype()); - - code_blockt for_body; - symbol_exprt init_sym= - new_tmp_symbol(sub_type, "subarray_init", tmp, location).symbol_expr(); - - code_assignt init_subarray(init_sym, sub_java_new); - code_assignt assign_subarray( - deref_expr, - typecast_exprt(init_sym, deref_expr.type())); - for_body.move_to_operands(init_subarray); - for_body.move_to_operands(assign_subarray); - - for_loop.init()=code_assignt(tmp_i, from_integer(0, tmp_i.type())); - for_loop.cond()=binary_relation_exprt(tmp_i, ID_lt, rhs.op0()); - for_loop.iter()=inc; - for_loop.body()=for_body; - - convert(for_loop, tmp); - dest.destructive_append(tmp); - } -} - /// builds a goto program for object initialization after new void goto_convertt::cpp_new_initializer( const exprt &lhs, @@ -969,11 +749,11 @@ void goto_convertt::do_function_call_symbol( copy(function_call, FUNCTION_CALL, dest); - if(arguments.size()!=1 && arguments.size()!=2) + if(arguments.size() != 1 && arguments.size() != 2 && arguments.size() != 3) { error().source_location=function.find_source_location(); error() << "`" << identifier - << "' expected to have one or two arguments" << eom; + << "' expected to have one, two or three arguments" << eom; throw 0; } diff --git a/src/goto-programs/class_hierarchy.h b/src/goto-programs/class_hierarchy.h index 9b926d25e18..1d180369765 100644 --- a/src/goto-programs/class_hierarchy.h +++ b/src/goto-programs/class_hierarchy.h @@ -19,7 +19,9 @@ Date: April 2016 #include #include -#include +#include + +class symbol_tablet; class class_hierarchyt { diff --git a/src/goto-programs/generate_function_bodies.cpp b/src/goto-programs/generate_function_bodies.cpp index 64d12ce0d4a..aca0ed19aba 100644 --- a/src/goto-programs/generate_function_bodies.cpp +++ b/src/goto-programs/generate_function_bodies.cpp @@ -8,17 +8,10 @@ Author: Diffblue Ltd. #include "generate_function_bodies.h" -#include -#include -#include -#include - +#include #include #include -#include #include -#include -#include void generate_function_bodiest::generate_function_body( goto_functiont &function, diff --git a/src/goto-programs/goto_clean_expr.cpp b/src/goto-programs/goto_clean_expr.cpp index 8c82a34a582..0660f80335f 100644 --- a/src/goto-programs/goto_clean_expr.cpp +++ b/src/goto-programs/goto_clean_expr.cpp @@ -237,8 +237,8 @@ void goto_convertt::clean_expr( if(result_is_used) { - symbolt &new_symbol= - new_tmp_symbol(expr.type(), "if_expr", dest, source_location); + symbolt &new_symbol = new_tmp_symbol( + expr.type(), "if_expr", dest, source_location, expr.get(ID_mode)); code_assignt assignment_true; assignment_true.lhs()=new_symbol.symbol_expr(); diff --git a/src/goto-programs/goto_convert.cpp b/src/goto-programs/goto_convert.cpp index 2bca47c7723..c662c5a4c2f 100644 --- a/src/goto-programs/goto_convert.cpp +++ b/src/goto-programs/goto_convert.cpp @@ -753,30 +753,43 @@ void goto_convertt::convert_assign( Forall_operands(it, rhs) clean_expr(*it, dest); + // TODO: This should be done in a separate pass do_cpp_new(lhs, to_side_effect_expr(rhs), dest); } - else if(rhs.id()==ID_side_effect && - rhs.get(ID_statement)==ID_java_new) + else if( + rhs.id() == ID_side_effect && + (rhs.get(ID_statement) == ID_assign || + rhs.get(ID_statement) == ID_postincrement || + rhs.get(ID_statement) == ID_preincrement || + rhs.get(ID_statement) == ID_statement_expression)) { - Forall_operands(it, rhs) - clean_expr(*it, dest); + // handle above side effects + clean_expr(rhs, dest); - do_java_new(lhs, to_side_effect_expr(rhs), dest); - } - else if(rhs.id()==ID_side_effect && - rhs.get(ID_statement)==ID_java_new_array) - { - Forall_operands(it, rhs) - clean_expr(*it, dest); + if(lhs.id() == ID_typecast) + { + DATA_INVARIANT( + lhs.operands().size() == 1, "Typecast must have one operand"); - do_java_new_array(lhs, to_side_effect_expr(rhs), dest); + // add a typecast to the rhs + exprt new_rhs = rhs; + rhs.make_typecast(lhs.op0().type()); + + // remove typecast from lhs + exprt tmp = lhs.op0(); + lhs.swap(tmp); + } + + code_assignt new_assign(code); + new_assign.lhs() = lhs; + new_assign.rhs() = rhs; + + copy(new_assign, ASSIGN, dest); } - else if( - rhs.id() == ID_side_effect && - (rhs.get(ID_statement) == ID_allocate || - rhs.get(ID_statement) == ID_java_new_array_data)) + else if(rhs.id() == ID_side_effect) { - // just preserve + // preserve side effects that will be handled at later stages, + // such as allocate, new operators of other languages, e.g. java, etc Forall_operands(it, rhs) clean_expr(*it, dest); @@ -788,6 +801,7 @@ void goto_convertt::convert_assign( } else { + // do everything else clean_expr(rhs, dest); if(lhs.id()==ID_typecast) @@ -1823,10 +1837,8 @@ void goto_convertt::generate_ifthenelse( // Note this depends on the fact that `instructions` is a std::list // and so goto-program-destructive-append preserves iterator validity. if(is_guarded_goto) - guarded_gotos.push_back({ // NOLINT(whitespace/braces) - tmp_v.instructions.begin(), - tmp_w.instructions.begin(), - guard}); + guarded_gotos.push_back( + {tmp_v.instructions.begin(), tmp_w.instructions.begin(), guard}); dest.destructive_append(tmp_v); dest.destructive_append(tmp_w); @@ -2055,16 +2067,16 @@ symbolt &goto_convertt::new_tmp_symbol( const typet &type, const std::string &suffix, goto_programt &dest, - const source_locationt &source_location) + const source_locationt &source_location, + const irep_idt &mode) { - symbolt &new_symbol= - get_fresh_aux_symbol( - type, - tmp_symbol_prefix, - "tmp_"+suffix, - source_location, - irep_idt(), - symbol_table); + symbolt &new_symbol = get_fresh_aux_symbol( + type, + tmp_symbol_prefix, + "tmp_" + suffix, + source_location, + mode, + symbol_table); code_declt decl; decl.symbol()=new_symbol.symbol_expr(); @@ -2081,8 +2093,8 @@ void goto_convertt::make_temp_symbol( { const source_locationt source_location=expr.find_source_location(); - symbolt &new_symbol= - new_tmp_symbol(expr.type(), suffix, dest, source_location); + symbolt &new_symbol = new_tmp_symbol( + expr.type(), suffix, dest, source_location, expr.get(ID_mode)); code_assignt assignment; assignment.lhs()=new_symbol.symbol_expr(); diff --git a/src/goto-programs/goto_convert_class.h b/src/goto-programs/goto_convert_class.h index e74833815c4..84a90cb59cf 100644 --- a/src/goto-programs/goto_convert_class.h +++ b/src/goto-programs/goto_convert_class.h @@ -59,7 +59,8 @@ class goto_convertt:public messaget const typet &type, const std::string &suffix, goto_programt &dest, - const source_locationt &); + const source_locationt &, + const irep_idt &mode); symbol_exprt make_compound_literal( const exprt &expr, diff --git a/src/goto-programs/goto_convert_side_effect.cpp b/src/goto-programs/goto_convert_side_effect.cpp index bec761420ca..def8d98b170 100644 --- a/src/goto-programs/goto_convert_side_effect.cpp +++ b/src/goto-programs/goto_convert_side_effect.cpp @@ -522,10 +522,8 @@ void goto_convertt::remove_temporary_object( throw 0; } - symbolt &new_symbol= - new_tmp_symbol(expr.type(), "obj", dest, expr.find_source_location()); - - new_symbol.mode=expr.get(ID_mode); + symbolt &new_symbol = new_tmp_symbol( + expr.type(), "obj", dest, expr.find_source_location(), expr.get(ID_mode)); if(expr.operands().size()==1) { @@ -599,8 +597,12 @@ void goto_convertt::remove_statement_expression( source_locationt source_location=last.find_source_location(); - symbolt &new_symbol= - new_tmp_symbol(expr.type(), "statement_expression", dest, source_location); + symbolt &new_symbol = new_tmp_symbol( + expr.type(), + "statement_expression", + dest, + source_location, + expr.get(ID_mode)); symbol_exprt tmp_symbol_expr(new_symbol.name, new_symbol.type); tmp_symbol_expr.add_source_location()=source_location; diff --git a/src/goto-programs/goto_functions.h b/src/goto-programs/goto_functions.h index 12b6b8c98be..0289fbdfcc2 100644 --- a/src/goto-programs/goto_functions.h +++ b/src/goto-programs/goto_functions.h @@ -14,14 +14,12 @@ Date: June 2003 #ifndef CPROVER_GOTO_PROGRAMS_GOTO_FUNCTIONS_H #define CPROVER_GOTO_PROGRAMS_GOTO_FUNCTIONS_H -#include "goto_program.h" - -#include -#include +#include -#include -#include #include +#include + +#include "goto_program.h" class goto_functiont { diff --git a/src/goto-programs/goto_program.h b/src/goto-programs/goto_program.h index aa53dfd97d8..88c84258b2f 100644 --- a/src/goto-programs/goto_program.h +++ b/src/goto-programs/goto_program.h @@ -12,7 +12,6 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_GOTO_PROGRAMS_GOTO_PROGRAM_H #define CPROVER_GOTO_PROGRAMS_GOTO_PROGRAM_H -#include #include #include #include diff --git a/src/goto-programs/interpreter_class.h b/src/goto-programs/interpreter_class.h index b8e2e4cc437..ccc4730fba0 100644 --- a/src/goto-programs/interpreter_class.h +++ b/src/goto-programs/interpreter_class.h @@ -85,6 +85,7 @@ class interpretert:public messaget irep_idt calling_function; function_assignmentst return_assignments; function_assignmentst param_assignments; + function_assignmentst exception_assignments; }; // list_input_varst maps function identifiers onto a vector of [name = value] diff --git a/src/goto-programs/interpreter_evaluate.cpp b/src/goto-programs/interpreter_evaluate.cpp index bb9ea793d0a..517f66f050b 100644 --- a/src/goto-programs/interpreter_evaluate.cpp +++ b/src/goto-programs/interpreter_evaluate.cpp @@ -11,16 +11,10 @@ Author: Daniel Kroening, kroening@kroening.com #include "interpreter_class.h" -#include -#include -#include - -#include -#include #include -#include -#include +#include #include +#include #include @@ -389,14 +383,11 @@ void interpretert::evaluate( } else if(expr.type().id()==ID_string) { - irep_idt value=to_constant_expr(expr).get_value(); - const char *str=value.c_str(); - std::size_t length=strlen(str)+1; + const std::string &value = id2string(to_constant_expr(expr).get_value()); if(show) warning() << "string decoding not fully implemented " - << length << eom; - mp_integer tmp = get_string_container()[id2string(value)]; - dest.push_back(tmp); + << value.size() + 1 << eom; + dest.push_back(get_string_container()[value]); return; } else diff --git a/src/goto-programs/lazy_goto_model.h b/src/goto-programs/lazy_goto_model.h index 78b078cadc2..417115024ce 100644 --- a/src/goto-programs/lazy_goto_model.h +++ b/src/goto-programs/lazy_goto_model.h @@ -53,11 +53,11 @@ class lazy_goto_modelt : public abstract_goto_modelt message_handlert &message_handler) { return lazy_goto_modelt( - [&handler, &options] - (goto_model_functiont &fun, const abstract_goto_modelt &model) { // NOLINT(*) + [&handler, + &options](goto_model_functiont &fun, const abstract_goto_modelt &model) { handler.process_goto_function(fun, model, options); }, - [&handler, &options] (goto_modelt &goto_model) -> bool { // NOLINT(*) + [&handler, &options](goto_modelt &goto_model) -> bool { return handler.process_goto_functions(goto_model, options); }, message_handler); diff --git a/src/goto-programs/remove_asm.cpp b/src/goto-programs/remove_asm.cpp index 0a514d04487..8df9d6429e8 100644 --- a/src/goto-programs/remove_asm.cpp +++ b/src/goto-programs/remove_asm.cpp @@ -14,14 +14,13 @@ Date: December 2014 #include "remove_asm.h" -#include - #include -#include #include #include +#include "goto_model.h" + class remove_asmt { public: @@ -195,7 +194,7 @@ void remove_asmt::process_instruction( { gcc_asm_function_call("__asm_"+id2string(command), code, tmp_dest); } - else if(command=="sync") // Power + else if(command == ID_sync) // Power { goto_programt::targett t=tmp_dest.add_instruction(OTHER); t->source_location=code.source_location(); @@ -210,7 +209,7 @@ void remove_asmt::process_instruction( t->code.set(ID_RRcumul, true); t->code.set(ID_WRcumul, true); } - else if(command=="lwsync") // Power + else if(command == ID_lwsync) // Power { goto_programt::targett t=tmp_dest.add_instruction(OTHER); t->source_location=code.source_location(); @@ -223,7 +222,7 @@ void remove_asmt::process_instruction( t->code.set(ID_RWcumul, true); t->code.set(ID_RRcumul, true); } - else if(command=="isync") // Power + else if(command == ID_isync) // Power { goto_programt::targett t=tmp_dest.add_instruction(OTHER); t->source_location=code.source_location(); diff --git a/src/goto-programs/remove_asm.h b/src/goto-programs/remove_asm.h index 913fe85c336..49d668c74d9 100644 --- a/src/goto-programs/remove_asm.h +++ b/src/goto-programs/remove_asm.h @@ -15,7 +15,10 @@ Date: December 2014 #ifndef CPROVER_GOTO_PROGRAMS_REMOVE_ASM_H #define CPROVER_GOTO_PROGRAMS_REMOVE_ASM_H -#include +#include + +class goto_modelt; +class symbol_tablet; void remove_asm( goto_functionst::goto_functiont &goto_function, diff --git a/src/goto-programs/remove_calls_no_body.cpp b/src/goto-programs/remove_calls_no_body.cpp index b8e46c41edf..62121dcfe17 100644 --- a/src/goto-programs/remove_calls_no_body.cpp +++ b/src/goto-programs/remove_calls_no_body.cpp @@ -9,9 +9,12 @@ Author: Daniel Poetzl /// \file /// Remove calls to functions without a body -#include #include "remove_calls_no_body.h" +#include + +#include "goto_functions.h" + /// Remove a single call /// \param goto_program: goto program to modify /// \param target: iterator pointing to the call diff --git a/src/goto-programs/remove_calls_no_body.h b/src/goto-programs/remove_calls_no_body.h index de10c426f2e..9b7382328ce 100644 --- a/src/goto-programs/remove_calls_no_body.h +++ b/src/goto-programs/remove_calls_no_body.h @@ -12,7 +12,9 @@ Author: Daniel Poetzl #ifndef CPROVER_GOTO_PROGRAMS_REMOVE_CALLS_NO_BODY_H #define CPROVER_GOTO_PROGRAMS_REMOVE_CALLS_NO_BODY_H -#include "goto_functions.h" +#include "goto_program.h" + +class goto_functionst; class remove_calls_no_bodyt { diff --git a/src/goto-programs/remove_complex.cpp b/src/goto-programs/remove_complex.cpp index 141fc4709fc..ef5b351f54d 100644 --- a/src/goto-programs/remove_complex.cpp +++ b/src/goto-programs/remove_complex.cpp @@ -14,6 +14,10 @@ Date: September 2014 #include "remove_complex.h" #include +#include +#include + +#include "goto_model.h" static exprt complex_member(const exprt &expr, irep_idt id) { diff --git a/src/goto-programs/remove_complex.h b/src/goto-programs/remove_complex.h index 098470ecc1a..c448f4a15e7 100644 --- a/src/goto-programs/remove_complex.h +++ b/src/goto-programs/remove_complex.h @@ -14,7 +14,9 @@ Date: September 2014 #ifndef CPROVER_GOTO_PROGRAMS_REMOVE_COMPLEX_H #define CPROVER_GOTO_PROGRAMS_REMOVE_COMPLEX_H -#include +class goto_functionst; +class goto_modelt; +class symbol_tablet; void remove_complex(symbol_tablet &, goto_functionst &); diff --git a/src/goto-programs/remove_const_function_pointers.cpp b/src/goto-programs/remove_const_function_pointers.cpp index 9b8e67c8b68..81e2812136b 100644 --- a/src/goto-programs/remove_const_function_pointers.cpp +++ b/src/goto-programs/remove_const_function_pointers.cpp @@ -11,9 +11,14 @@ Author: Thomas Kiley, thomas.kiley@diffblue.com #include "remove_const_function_pointers.h" -#include -#include #include +#include +#include +#include + +#include + +#include "goto_functions.h" #define LOG(message, irep) \ debug() << "Case " << __LINE__ << " : " << message << "\n" \ diff --git a/src/goto-programs/remove_const_function_pointers.h b/src/goto-programs/remove_const_function_pointers.h index 469deaec032..0299de8b383 100644 --- a/src/goto-programs/remove_const_function_pointers.h +++ b/src/goto-programs/remove_const_function_pointers.h @@ -12,13 +12,22 @@ Author: Thomas Kiley, thomas.kiley@diffblue.com #ifndef CPROVER_GOTO_PROGRAMS_REMOVE_CONST_FUNCTION_POINTERS_H #define CPROVER_GOTO_PROGRAMS_REMOVE_CONST_FUNCTION_POINTERS_H +#include #include -#include "goto_model.h" -#include #include -#include - +#include +#include + +class address_of_exprt; +class dereference_exprt; +class index_exprt; +class member_exprt; +class namespacet; +class struct_exprt; +class symbol_exprt; +class symbol_tablet; +class typecast_exprt; class remove_const_function_pointerst:public messaget { diff --git a/src/goto-programs/remove_function_pointers.h b/src/goto-programs/remove_function_pointers.h index 3038a940637..4a7bbfb09b5 100644 --- a/src/goto-programs/remove_function_pointers.h +++ b/src/goto-programs/remove_function_pointers.h @@ -14,8 +14,11 @@ Date: June 2003 #ifndef CPROVER_GOTO_PROGRAMS_REMOVE_FUNCTION_POINTERS_H #define CPROVER_GOTO_PROGRAMS_REMOVE_FUNCTION_POINTERS_H -#include "goto_model.h" -#include +class goto_functionst; +class goto_programt; +class goto_modelt; +class message_handlert; +class symbol_tablet; // remove indirect function calls // and replace by case-split diff --git a/src/goto-programs/remove_returns.cpp b/src/goto-programs/remove_returns.cpp index 4c275ff9bbb..5257c83ea0a 100644 --- a/src/goto-programs/remove_returns.cpp +++ b/src/goto-programs/remove_returns.cpp @@ -14,7 +14,8 @@ Date: September 2009 #include "remove_returns.h" #include -#include + +#include "goto_model.h" class remove_returnst { diff --git a/src/goto-programs/remove_returns.h b/src/goto-programs/remove_returns.h index f2017111478..32d2a81c824 100644 --- a/src/goto-programs/remove_returns.h +++ b/src/goto-programs/remove_returns.h @@ -14,10 +14,17 @@ Date: September 2009 #ifndef CPROVER_GOTO_PROGRAMS_REMOVE_RETURNS_H #define CPROVER_GOTO_PROGRAMS_REMOVE_RETURNS_H -#include +#include + +#include #define RETURN_VALUE_SUFFIX "#return_value" +class goto_functionst; +class goto_model_functiont; +class goto_modelt; +class symbol_table_baset; + // Turns 'return x' into an assignment to fkt#return_value, // unless the function returns void, // and a 'goto the_end_of_the_function'. diff --git a/src/goto-programs/remove_skip.h b/src/goto-programs/remove_skip.h index 68f9a833994..6ff55bf3e03 100644 --- a/src/goto-programs/remove_skip.h +++ b/src/goto-programs/remove_skip.h @@ -12,8 +12,9 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_GOTO_PROGRAMS_REMOVE_SKIP_H #define CPROVER_GOTO_PROGRAMS_REMOVE_SKIP_H -#include "goto_functions.h" +#include "goto_program.h" +class goto_functionst; class goto_modelt; bool is_skip(const goto_programt &, goto_programt::const_targett); diff --git a/src/goto-programs/remove_unreachable.cpp b/src/goto-programs/remove_unreachable.cpp index 562546f377b..07d71adf471 100644 --- a/src/goto-programs/remove_unreachable.cpp +++ b/src/goto-programs/remove_unreachable.cpp @@ -14,6 +14,8 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include "goto_functions.h" + /// remove unreachable code void remove_unreachable(goto_programt &goto_program) { diff --git a/src/goto-programs/remove_unreachable.h b/src/goto-programs/remove_unreachable.h index 5267529d364..ec8ac9bb9fb 100644 --- a/src/goto-programs/remove_unreachable.h +++ b/src/goto-programs/remove_unreachable.h @@ -12,7 +12,8 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_GOTO_PROGRAMS_REMOVE_UNREACHABLE_H #define CPROVER_GOTO_PROGRAMS_REMOVE_UNREACHABLE_H -#include "goto_functions.h" +class goto_functionst; +class goto_programt; void remove_unreachable(goto_programt &goto_program); void remove_unreachable(goto_functionst &goto_functions); diff --git a/src/goto-programs/remove_unused_functions.cpp b/src/goto-programs/remove_unused_functions.cpp index 3092e114796..edb4c712ec2 100644 --- a/src/goto-programs/remove_unused_functions.cpp +++ b/src/goto-programs/remove_unused_functions.cpp @@ -13,6 +13,8 @@ Author: CM Wintersteiger #include +#include "goto_model.h" + void remove_unused_functions( goto_modelt &goto_model, message_handlert &message_handler) diff --git a/src/goto-programs/remove_unused_functions.h b/src/goto-programs/remove_unused_functions.h index 8c8b1739a98..d7fd2569e18 100644 --- a/src/goto-programs/remove_unused_functions.h +++ b/src/goto-programs/remove_unused_functions.h @@ -12,9 +12,14 @@ Author: CM Wintersteiger #ifndef CPROVER_GOTO_PROGRAMS_REMOVE_UNUSED_FUNCTIONS_H #define CPROVER_GOTO_PROGRAMS_REMOVE_UNUSED_FUNCTIONS_H -#include +#include -#include +#include + +class goto_functionst; +class goto_modelt; +class message_handlert; +class symbol_tablet; void remove_unused_functions( goto_functionst &, diff --git a/src/goto-programs/remove_vector.cpp b/src/goto-programs/remove_vector.cpp index f2e7f5b9fe4..cabd5100698 100644 --- a/src/goto-programs/remove_vector.cpp +++ b/src/goto-programs/remove_vector.cpp @@ -14,6 +14,10 @@ Date: September 2014 #include "remove_vector.h" #include +#include +#include + +#include "goto_model.h" static bool have_to_remove_vector(const typet &type); diff --git a/src/goto-programs/remove_vector.h b/src/goto-programs/remove_vector.h index 960d75953a8..2bd1f623e95 100644 --- a/src/goto-programs/remove_vector.h +++ b/src/goto-programs/remove_vector.h @@ -14,7 +14,9 @@ Date: September 2014 #ifndef CPROVER_GOTO_PROGRAMS_REMOVE_VECTOR_H #define CPROVER_GOTO_PROGRAMS_REMOVE_VECTOR_H -#include +class goto_functionst; +class goto_modelt; +class symbol_tablet; void remove_vector(symbol_tablet &, goto_functionst &); diff --git a/src/goto-programs/remove_virtual_functions.cpp b/src/goto-programs/remove_virtual_functions.cpp index f3b53c57a9b..a242577e8cd 100644 --- a/src/goto-programs/remove_virtual_functions.cpp +++ b/src/goto-programs/remove_virtual_functions.cpp @@ -8,18 +8,16 @@ Author: Daniel Kroening, kroening@kroening.com /// \file /// Remove Virtual Function (Method) Calls -#include - #include "remove_virtual_functions.h" -#include "class_hierarchy.h" -#include "class_identifier.h" -#include +#include -#include -#include #include +#include "class_identifier.h" +#include "goto_model.h" +#include "resolve_inherited_component.h" + class remove_virtual_functionst { public: @@ -445,10 +443,15 @@ void remove_virtual_functionst::get_functions( has_prefix( id2string(b.symbol_expr.get_identifier()), "java::java.lang.Object")) return true; - else if(a.symbol_expr.get_identifier() == b.symbol_expr.get_identifier()) - return a.class_id < b.class_id; else - return a.symbol_expr.get_identifier() < b.symbol_expr.get_identifier(); + { + int cmp = a.symbol_expr.get_identifier().compare( + b.symbol_expr.get_identifier()); + if(cmp == 0) + return a.class_id < b.class_id; + else + return cmp < 0; + } }); } diff --git a/src/goto-programs/remove_virtual_functions.h b/src/goto-programs/remove_virtual_functions.h index 43bd0f2fea8..ae5d257f6fd 100644 --- a/src/goto-programs/remove_virtual_functions.h +++ b/src/goto-programs/remove_virtual_functions.h @@ -14,8 +14,15 @@ Date: April 2016 #ifndef CPROVER_GOTO_PROGRAMS_REMOVE_VIRTUAL_FUNCTIONS_H #define CPROVER_GOTO_PROGRAMS_REMOVE_VIRTUAL_FUNCTIONS_H -#include "goto_model.h" +#include + #include "class_hierarchy.h" +#include "goto_program.h" + +class goto_functionst; +class goto_model_functiont; +class goto_modelt; +class symbol_table_baset; // remove virtual function calls // and replace by case-split diff --git a/src/goto-programs/string_abstraction.cpp b/src/goto-programs/string_abstraction.cpp index bf97e4c0c5d..5a9043cff2b 100644 --- a/src/goto-programs/string_abstraction.cpp +++ b/src/goto-programs/string_abstraction.cpp @@ -11,16 +11,12 @@ Author: Daniel Kroening, kroening@kroening.com #include "string_abstraction.h" -#include +#include -#include -#include -#include -#include #include -#include - #include +#include +#include #include "pointer_arithmetic.h" @@ -759,7 +755,11 @@ bool string_abstractiont::build(const exprt &object, exprt &dest, bool write) if(object.id()==ID_string_constant) { - mp_integer str_len=strlen(object.get(ID_value).c_str()); + const std::string &str_value = id2string(object.get(ID_value)); + // make sure we handle the case of a string constant with string-terminating + // \0 in it + const std::size_t str_len = + std::min(str_value.size(), str_value.find('\0')); return build_symbol_constant(str_len, str_len+1, dest); } diff --git a/src/goto-programs/vcd_goto_trace.cpp b/src/goto-programs/vcd_goto_trace.cpp index 4becb3af583..9e736033df1 100644 --- a/src/goto-programs/vcd_goto_trace.cpp +++ b/src/goto-programs/vcd_goto_trace.cpp @@ -13,13 +13,11 @@ Date: June 2011 #include "vcd_goto_trace.h" -#include -#include #include +#include -#include -#include #include +#include std::string as_vcd_binary( const exprt &expr, @@ -63,17 +61,7 @@ std::string as_vcd_binary( // build "xxx" - mp_integer width; - - if(type.id()==ID_unsignedbv || - type.id()==ID_signedbv || - type.id()==ID_floatbv || - type.id()==ID_fixedbv || - type.id()==ID_pointer || - type.id()==ID_bv) - width=string2integer(type.get_string(ID_width)); - else - width=pointer_offset_size(type, ns)*8; + const mp_integer width = pointer_offset_bits(type, ns); if(width>=0) return std::string(integer2size_t(width), 'x'); @@ -106,12 +94,7 @@ void output_vcd( const auto number=n.number(identifier); - mp_integer width; - - if(type.id()==ID_bool) - width=1; - else - width=pointer_offset_bits(type, ns); + const mp_integer width = pointer_offset_bits(type, ns); if(width>=1) out << "$var reg " << width << " V" << number << " " diff --git a/src/goto-symex/equation_conversion_exceptions.h b/src/goto-symex/equation_conversion_exceptions.h new file mode 100644 index 00000000000..ffa57abefe0 --- /dev/null +++ b/src/goto-symex/equation_conversion_exceptions.h @@ -0,0 +1,47 @@ +/*******************************************************************\ + +Module: Symbolic Execution + +Author: Diffblue Ltd. + +\*******************************************************************/ + +/// \file +/// Exceptions that can be raised during the equation conversion phase + +#ifndef CPROVER_GOTO_SYMEX_EQUATION_CONVERSION_EXCEPTIONS_H +#define CPROVER_GOTO_SYMEX_EQUATION_CONVERSION_EXCEPTIONS_H + +#include + +#include + +#include "symex_target_equation.h" + +class equation_conversion_exceptiont : public std::runtime_error +{ +public: + equation_conversion_exceptiont( + const std::string &message, + const symex_target_equationt::SSA_stept &step) + : runtime_error(message), step(step) + { + std::ostringstream error_msg; + error_msg << runtime_error::what(); + error_msg << "\nSource GOTO statement: " << format(step.source.pc->code); + error_msg << "\nStep:\n"; + step.output(error_msg); + error_message = error_msg.str(); + } + + const char *what() const optional_noexcept override + { + return error_message.c_str(); + } + +private: + symex_target_equationt::SSA_stept step; + std::string error_message; +}; + +#endif // CPROVER_GOTO_SYMEX_EQUATION_CONVERSION_EXCEPTIONS_H diff --git a/src/goto-symex/goto_symex.h b/src/goto-symex/goto_symex.h index 7d7edb8891f..117693b8391 100644 --- a/src/goto-symex/goto_symex.h +++ b/src/goto-symex/goto_symex.h @@ -14,13 +14,13 @@ Author: Daniel Kroening, kroening@kroening.com #include #include -#include #include #include "goto_symex_state.h" #include "symex_target_equation.h" +class byte_extract_exprt; class typet; class code_typet; class symbol_tablet; diff --git a/src/goto-symex/slice_by_trace.cpp b/src/goto-symex/slice_by_trace.cpp index 5218870e96f..9fe0036911d 100644 --- a/src/goto-symex/slice_by_trace.cpp +++ b/src/goto-symex/slice_by_trace.cpp @@ -244,7 +244,7 @@ void symex_slice_by_tracet::compute_ts_back( !i->io_args.empty() && i->io_args.front().id()=="trace_event") { - irep_idt event=i->io_args.front().get("event"); + irep_idt event = i->io_args.front().get(ID_event); if(!alphabet.empty()) { diff --git a/src/goto-symex/symex_builtin_functions.cpp b/src/goto-symex/symex_builtin_functions.cpp index c000c3c5c0f..f827f1ecaea 100644 --- a/src/goto-symex/symex_builtin_functions.cpp +++ b/src/goto-symex/symex_builtin_functions.cpp @@ -11,25 +11,15 @@ Author: Daniel Kroening, kroening@kroening.com #include "goto_symex.h" -#include -#include #include -#include -#include +#include +#include #include -#include -#include -#include #include -#include #include -#include -#include #include -#include "goto_symex_state.h" - inline static typet c_sizeof_type_rec(const exprt &expr) { const irept &sizeof_type=expr.find(ID_C_c_sizeof_type); @@ -66,6 +56,9 @@ void goto_symext::symex_allocate( exprt size=code.op0(); typet object_type=nil_typet(); + auto function_symbol = outer_symbol_table.lookup(state.source.pc->function); + INVARIANT(function_symbol, "function associated with instruction not found"); + const irep_idt &mode = function_symbol->mode; // is the type given? if(code.type().id()==ID_pointer && code.type().subtype().id()!=ID_empty) @@ -135,14 +128,15 @@ void goto_symext::symex_allocate( { exprt &size=to_array_type(object_type).size(); - symbolt size_symbol; + auxiliary_symbolt size_symbol; size_symbol.base_name= "dynamic_object_size"+std::to_string(dynamic_counter); size_symbol.name="symex_dynamic::"+id2string(size_symbol.base_name); - size_symbol.is_lvalue=true; size_symbol.type=tmp_size.type(); - size_symbol.mode=ID_C; + size_symbol.mode = mode; + size_symbol.type.set(ID_C_constant, true); + size_symbol.value = size; state.symbol_table.add(size_symbol); @@ -161,7 +155,7 @@ void goto_symext::symex_allocate( value_symbol.is_lvalue=true; value_symbol.type=object_type; value_symbol.type.set("#dynamic", true); - value_symbol.mode=ID_C; + value_symbol.mode = mode; state.symbol_table.add(value_symbol); diff --git a/src/goto-symex/symex_clean_expr.cpp b/src/goto-symex/symex_clean_expr.cpp index 5e1e0cf4c91..ce6265e1c20 100644 --- a/src/goto-symex/symex_clean_expr.cpp +++ b/src/goto-symex/symex_clean_expr.cpp @@ -12,11 +12,10 @@ Author: Daniel Kroening, kroening@kroening.com #include "goto_symex.h" #include -#include -#include #include -#include +#include #include +#include /// Given an expression, find the root object and the offset into it. /// diff --git a/src/goto-symex/symex_dereference.cpp b/src/goto-symex/symex_dereference.cpp index 95b8866865e..e259a515489 100644 --- a/src/goto-symex/symex_dereference.cpp +++ b/src/goto-symex/symex_dereference.cpp @@ -11,16 +11,14 @@ Author: Daniel Kroening, kroening@kroening.com #include "goto_symex.h" -#include -#include #include #include #include +#include +#include +#include #include -#include - -#include #include "symex_dereference_state.h" diff --git a/src/goto-symex/symex_function_call.cpp b/src/goto-symex/symex_function_call.cpp index 37e173928c4..6de8995364d 100644 --- a/src/goto-symex/symex_function_call.cpp +++ b/src/goto-symex/symex_function_call.cpp @@ -11,19 +11,11 @@ Author: Daniel Kroening, kroening@kroening.com #include "goto_symex.h" -#include - -#include -#include -#include #include #include -#include -#include - +#include #include - -#include +#include bool goto_symext::get_unwind_recursion( const irep_idt &identifier, diff --git a/src/goto-symex/symex_main.cpp b/src/goto-symex/symex_main.cpp index 8c33d25541d..97c2c127c22 100644 --- a/src/goto-symex/symex_main.cpp +++ b/src/goto-symex/symex_main.cpp @@ -166,8 +166,8 @@ void goto_symext::symex_threaded_step( static goto_symext::get_goto_functiont get_function_from_goto_functions( const goto_functionst &goto_functions) { - return [&goto_functions](const irep_idt &key) -> - const goto_functionst::goto_functiont & { // NOLINT(*) + return [&goto_functions]( + const irep_idt &key) -> const goto_functionst::goto_functiont & { return goto_functions.function_map.at(key); }; } @@ -208,6 +208,9 @@ void goto_symext::symex_with_state( // execution, so return the names generated through symbolic execution // through `new_symbol_table`. new_symbol_table = state.symbol_table; + // reset the namespace back to a sane state as state.symbol_table might go out + // of scope + ns = namespacet(outer_symbol_table); } void goto_symext::resume_symex_from_saved_state( diff --git a/src/goto-symex/symex_other.cpp b/src/goto-symex/symex_other.cpp index f3cc50c32bb..30ca539f429 100644 --- a/src/goto-symex/symex_other.cpp +++ b/src/goto-symex/symex_other.cpp @@ -12,14 +12,10 @@ Author: Daniel Kroening, kroening@kroening.com #include "goto_symex.h" #include -#include -#include #include -#include -#include #include -#include #include +#include void goto_symext::havoc_rec( statet &state, diff --git a/src/goto-symex/symex_target_equation.cpp b/src/goto-symex/symex_target_equation.cpp index 27be83608f1..0d3709dde8e 100644 --- a/src/goto-symex/symex_target_equation.cpp +++ b/src/goto-symex/symex_target_equation.cpp @@ -11,13 +11,20 @@ Author: Daniel Kroening, kroening@kroening.com #include "symex_target_equation.h" +#include #include +#include +#include +// Can be removed once deprecated SSA_stept::output is removed #include -#include -#include + +#include #include +#include +#include +#include "equation_conversion_exceptions.h" #include "goto_symex_state.h" /// read from a shared variable @@ -368,14 +375,23 @@ void symex_target_equationt::constraint( void symex_target_equationt::convert( prop_convt &prop_conv) { - convert_guards(prop_conv); - convert_assignments(prop_conv); - convert_decls(prop_conv); - convert_assumptions(prop_conv); - convert_assertions(prop_conv); - convert_goto_instructions(prop_conv); - convert_io(prop_conv); - convert_constraints(prop_conv); + try + { + convert_guards(prop_conv); + convert_assignments(prop_conv); + convert_decls(prop_conv); + convert_assumptions(prop_conv); + convert_assertions(prop_conv); + convert_goto_instructions(prop_conv); + convert_io(prop_conv); + convert_constraints(prop_conv); + } + catch(const equation_conversion_exceptiont &conversion_exception) + { + // unwrap the except and throw like normal + const std::string full_error = unwrap_exception(conversion_exception); + throw full_error; + } } /// converts assignments @@ -402,7 +418,16 @@ void symex_target_equationt::convert_decls( { // The result is not used, these have no impact on // the satisfiability of the formula. - prop_conv.convert(step.cond_expr); + try + { + prop_conv.convert(step.cond_expr); + } + catch(const bitvector_conversion_exceptiont &conversion_exception) + { + util_throw_with_nested( + equation_conversion_exceptiont( + "Error converting decls for step", step)); + } } } } @@ -417,7 +442,18 @@ void symex_target_equationt::convert_guards( if(step.ignore) step.guard_literal=const_literal(false); else - step.guard_literal=prop_conv.convert(step.guard); + { + try + { + step.guard_literal = prop_conv.convert(step.guard); + } + catch(const bitvector_conversion_exceptiont &conversion_exception) + { + util_throw_with_nested( + equation_conversion_exceptiont( + "Error converting guard for step", step)); + } + } } } @@ -433,7 +469,18 @@ void symex_target_equationt::convert_assumptions( if(step.ignore) step.cond_literal=const_literal(true); else - step.cond_literal=prop_conv.convert(step.cond_expr); + { + try + { + step.cond_literal = prop_conv.convert(step.cond_expr); + } + catch(const bitvector_conversion_exceptiont &conversion_exception) + { + util_throw_with_nested( + equation_conversion_exceptiont( + "Error converting assumptions for step", step)); + } + } } } } @@ -450,7 +497,18 @@ void symex_target_equationt::convert_goto_instructions( if(step.ignore) step.cond_literal=const_literal(true); else - step.cond_literal=prop_conv.convert(step.cond_expr); + { + try + { + step.cond_literal = prop_conv.convert(step.cond_expr); + } + catch(const bitvector_conversion_exceptiont &conversion_exception) + { + util_throw_with_nested( + equation_conversion_exceptiont( + "Error converting goto instructions for step", step)); + } + } } } } @@ -519,7 +577,16 @@ void symex_target_equationt::convert_assertions( step.cond_expr); // do the conversion - step.cond_literal=prop_conv.convert(implication); + try + { + step.cond_literal = prop_conv.convert(implication); + } + catch(const bitvector_conversion_exceptiont &conversion_exception) + { + util_throw_with_nested( + equation_conversion_exceptiont( + "Error converting assertions for step", step)); + } // store disjunct disjuncts.push_back(literal_exprt(!step.cond_literal)); @@ -703,3 +770,118 @@ void symex_target_equationt::SSA_stept::output( out << "Guard: " << from_expr(ns, source.pc->function, guard) << '\n'; } + +void symex_target_equationt::SSA_stept::output(std::ostream &out) const +{ + if(source.is_set) + { + out << "Thread " << source.thread_nr; + + if(source.pc->source_location.is_not_nil()) + out << " " << source.pc->source_location << '\n'; + else + out << '\n'; + } + + switch(type) + { + case goto_trace_stept::typet::ASSERT: + out << "ASSERT " << format(cond_expr) << '\n'; + break; + case goto_trace_stept::typet::ASSUME: + out << "ASSUME " << format(cond_expr) << '\n'; + break; + case goto_trace_stept::typet::LOCATION: + out << "LOCATION" << '\n'; + break; + case goto_trace_stept::typet::INPUT: + out << "INPUT" << '\n'; + break; + case goto_trace_stept::typet::OUTPUT: + out << "OUTPUT" << '\n'; + break; + + case goto_trace_stept::typet::DECL: + out << "DECL" << '\n'; + out << format(ssa_lhs) << '\n'; + break; + + case goto_trace_stept::typet::ASSIGNMENT: + out << "ASSIGNMENT ("; + switch(assignment_type) + { + case assignment_typet::HIDDEN: + out << "HIDDEN"; + break; + case assignment_typet::STATE: + out << "STATE"; + break; + case assignment_typet::VISIBLE_ACTUAL_PARAMETER: + out << "VISIBLE_ACTUAL_PARAMETER"; + break; + case assignment_typet::HIDDEN_ACTUAL_PARAMETER: + out << "HIDDEN_ACTUAL_PARAMETER"; + break; + case assignment_typet::PHI: + out << "PHI"; + break; + case assignment_typet::GUARD: + out << "GUARD"; + break; + default: + { + } + } + + out << ")\n"; + break; + + case goto_trace_stept::typet::DEAD: + out << "DEAD\n"; + break; + case goto_trace_stept::typet::FUNCTION_CALL: + out << "FUNCTION_CALL\n"; + break; + case goto_trace_stept::typet::FUNCTION_RETURN: + out << "FUNCTION_RETURN\n"; + break; + case goto_trace_stept::typet::CONSTRAINT: + out << "CONSTRAINT\n"; + break; + case goto_trace_stept::typet::SHARED_READ: + out << "SHARED READ\n"; + break; + case goto_trace_stept::typet::SHARED_WRITE: + out << "SHARED WRITE\n"; + break; + case goto_trace_stept::typet::ATOMIC_BEGIN: + out << "ATOMIC_BEGIN\n"; + break; + case goto_trace_stept::typet::ATOMIC_END: + out << "AUTOMIC_END\n"; + break; + case goto_trace_stept::typet::SPAWN: + out << "SPAWN\n"; + break; + case goto_trace_stept::typet::MEMORY_BARRIER: + out << "MEMORY_BARRIER\n"; + break; + case goto_trace_stept::typet::GOTO: + out << "IF " << format(cond_expr) << " GOTO\n"; + break; + + default: + UNREACHABLE; + } + + if(is_assert() || is_assume() || is_assignment() || is_constraint()) + out << format(cond_expr) << '\n'; + + if(is_assert() || is_constraint()) + out << comment << '\n'; + + if(is_shared_read() || is_shared_write()) + out << format(ssa_lhs) << '\n'; + + out << "Guard: " << format(guard) << '\n'; +} diff --git a/src/goto-symex/symex_target_equation.h b/src/goto-symex/symex_target_equation.h index 178cbeae7ab..bada3f9d871 100644 --- a/src/goto-symex/symex_target_equation.h +++ b/src/goto-symex/symex_target_equation.h @@ -32,7 +32,6 @@ class prop_convt; class symex_target_equationt:public symex_targett { public: - symex_target_equationt() = default; virtual ~symex_target_equationt() = default; // read event @@ -257,9 +256,12 @@ class symex_target_equationt:public symex_targett { } + DEPRECATED("Use output without ns param") void output( const namespacet &ns, std::ostream &out) const; + + void output(std::ostream &out) const; }; std::size_t count_assertions() const diff --git a/src/java_bytecode/Makefile b/src/java_bytecode/Makefile index cf6d7a5cc9d..13aa8e6c2ca 100644 --- a/src/java_bytecode/Makefile +++ b/src/java_bytecode/Makefile @@ -31,9 +31,10 @@ SRC = bytecode_info.cpp \ java_types.cpp \ java_utils.cpp \ mz_zip_archive.cpp \ - replace_java_nondet.cpp \ remove_exceptions.cpp \ remove_instanceof.cpp \ + remove_java_new.cpp \ + replace_java_nondet.cpp \ select_pointer_type.cpp \ # Empty last line diff --git a/src/java_bytecode/ci_lazy_methods.h b/src/java_bytecode/ci_lazy_methods.h index 11095fa3d8a..71eb718fe42 100644 --- a/src/java_bytecode/ci_lazy_methods.h +++ b/src/java_bytecode/ci_lazy_methods.h @@ -12,18 +12,20 @@ #ifndef CPROVER_JAVA_BYTECODE_GATHER_METHODS_LAZILY_H #define CPROVER_JAVA_BYTECODE_GATHER_METHODS_LAZILY_H +#include "ci_lazy_methods_needed.h" +#include "java_bytecode_parse_tree.h" +#include "java_class_loader.h" +#include "select_pointer_type.h" +#include "synthetic_methods_map.h" + #include #include #include #include #include + #include -#include -#include -#include -#include -#include class java_string_library_preprocesst; diff --git a/src/java_bytecode/expr2java.cpp b/src/java_bytecode/expr2java.cpp index 51bb43ad82b..8bbd9b093c5 100644 --- a/src/java_bytecode/expr2java.cpp +++ b/src/java_bytecode/expr2java.cpp @@ -350,7 +350,8 @@ std::string expr2javat::convert_java_new( { std::string dest; - if(src.get(ID_statement)==ID_java_new_array) + if(src.get(ID_statement)==ID_java_new_array || + src.get(ID_statement)==ID_java_new_array_data) { dest="new"; @@ -398,7 +399,8 @@ std::string expr2javat::convert_with_precedence( return convert_java_instanceof(src, precedence=15); else if(src.id()==ID_side_effect && (src.get(ID_statement)==ID_java_new || - src.get(ID_statement)==ID_java_new_array)) + src.get(ID_statement)==ID_java_new_array || + src.get(ID_statement)==ID_java_new_array_data)) return convert_java_new(src, precedence=15); else if(src.id()==ID_side_effect && src.get(ID_statement)==ID_throw) diff --git a/src/java_bytecode/expr2java.h b/src/java_bytecode/expr2java.h index 2adb417eb03..1df94bdc9ce 100644 --- a/src/java_bytecode/expr2java.h +++ b/src/java_bytecode/expr2java.h @@ -66,7 +66,7 @@ std::string floating_point_to_java_string(float_type value) return class_name + ".POSITIVE_INFINITY"; if(std::isinf(value) && value <= 0.) return class_name + ".NEGATIVE_INFINITY"; - const std::string decimal = [&]() -> std::string { // NOLINT + const std::string decimal = [&]() -> std::string { // Using ostringstream instead of to_string to get string without // trailing zeros std::ostringstream raw_stream; @@ -76,7 +76,7 @@ std::string floating_point_to_java_string(float_type value) return raw_decimal + ".0"; return raw_decimal; }(); - const bool is_lossless = [&] { // NOLINT + const bool is_lossless = [&] { if(value == std::numeric_limits::min()) return true; try @@ -88,7 +88,7 @@ std::string floating_point_to_java_string(float_type value) return false; } }(); - const std::string lossless = [&]() -> std::string { // NOLINT + const std::string lossless = [&]() -> std::string { if(is_lossless) return decimal; std::ostringstream stream; diff --git a/src/java_bytecode/jar_file.cpp b/src/java_bytecode/jar_file.cpp index b289f4e2d3a..ff0f068a748 100644 --- a/src/java_bytecode/jar_file.cpp +++ b/src/java_bytecode/jar_file.cpp @@ -24,8 +24,7 @@ void jar_filet::initialize_file_index(java_class_loader_limitt &limit) } /// This constructor creates a jar_file object whose contents -/// are extracted from a memory buffer (byte array) as opposed -/// to a jar file. +/// are extracted from a file with given name. jar_filet::jar_filet( java_class_loader_limitt &limit, const std::string &filename): diff --git a/src/java_bytecode/java_bytecode_convert_class.cpp b/src/java_bytecode/java_bytecode_convert_class.cpp index 877252f5e12..62e1fd51fdc 100644 --- a/src/java_bytecode/java_bytecode_convert_class.cpp +++ b/src/java_bytecode/java_bytecode_convert_class.cpp @@ -740,6 +740,7 @@ void java_bytecode_convert_classt::add_array_types(symbol_tablet &symbol_table) symbol.base_name=symbol_type.get(ID_C_base_name); symbol.is_type=true; symbol.type = class_type; + symbol.mode = ID_java; symbol_table.add(symbol); // Also provide a clone method: diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index cdc75bad6dd..9b221d4298c 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -895,10 +895,8 @@ static void gather_symbol_live_ranges( if(e.id()==ID_symbol) { const auto &symexpr=to_symbol_expr(e); - auto findit= - result.insert({ // NOLINT(whitespace/braces) - symexpr.get_identifier(), - java_bytecode_convert_methodt::variablet()}); + auto findit = result.insert( + {symexpr.get_identifier(), java_bytecode_convert_methodt::variablet()}); auto &var=findit.first->second; if(findit.second) { diff --git a/src/java_bytecode/java_bytecode_convert_method.h b/src/java_bytecode/java_bytecode_convert_method.h index 90e76f501f9..2ef174dbda9 100644 --- a/src/java_bytecode/java_bytecode_convert_method.h +++ b/src/java_bytecode/java_bytecode_convert_method.h @@ -12,12 +12,12 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_JAVA_BYTECODE_JAVA_BYTECODE_CONVERT_METHOD_H #define CPROVER_JAVA_BYTECODE_JAVA_BYTECODE_CONVERT_METHOD_H -#include -#include +#include "ci_lazy_methods_needed.h" +#include "java_bytecode_parse_tree.h" #include "java_string_library_preprocess.h" -#include "java_bytecode_parse_tree.h" -#include +#include +#include class class_hierarchyt; diff --git a/src/java_bytecode/java_bytecode_convert_method_class.h b/src/java_bytecode/java_bytecode_convert_method_class.h index 0df926b1005..5ec7b38fb22 100644 --- a/src/java_bytecode/java_bytecode_convert_method_class.h +++ b/src/java_bytecode/java_bytecode_convert_method_class.h @@ -12,14 +12,16 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_JAVA_BYTECODE_JAVA_BYTECODE_CONVERT_METHOD_CLASS_H #define CPROVER_JAVA_BYTECODE_JAVA_BYTECODE_CONVERT_METHOD_CLASS_H +#include "ci_lazy_methods_needed.h" +#include "java_bytecode_parse_tree.h" +#include "java_bytecode_convert_class.h" + #include #include #include #include + #include -#include "java_bytecode_parse_tree.h" -#include "java_bytecode_convert_class.h" -#include #include #include diff --git a/src/java_bytecode/java_bytecode_instrument.cpp b/src/java_bytecode/java_bytecode_instrument.cpp index 7c09b07b2fe..bd2e6a95be4 100644 --- a/src/java_bytecode/java_bytecode_instrument.cpp +++ b/src/java_bytecode/java_bytecode_instrument.cpp @@ -75,7 +75,7 @@ class java_bytecode_instrumentt:public messaget optionalt instrument_expr(const exprt &expr); }; -const std::vector exception_needed_classes = { // NOLINT +const std::vector exception_needed_classes = { "java.lang.ArithmeticException", "java.lang.ArrayIndexOutOfBoundsException", "java.lang.ClassCastException", diff --git a/src/java_bytecode/java_bytecode_language.cpp b/src/java_bytecode/java_bytecode_language.cpp index a139b75c613..72deab72194 100644 --- a/src/java_bytecode/java_bytecode_language.cpp +++ b/src/java_bytecode/java_bytecode_language.cpp @@ -55,6 +55,10 @@ void java_bytecode_languaget::get_language_options(const cmdlinet &cmd) if(cmd.isset("string-max-input-length")) object_factory_parameters.max_nondet_string_length= std::stoi(cmd.get_value("string-max-input-length")); + else if(cmd.isset("string-max-length")) + object_factory_parameters.max_nondet_string_length = + std::stoi(cmd.get_value("string-max-length")); + object_factory_parameters.string_printable = cmd.isset("string-printable"); if(cmd.isset("java-max-vla-length")) max_user_array_length=std::stoi(cmd.get_value("java-max-vla-length")); @@ -65,6 +69,11 @@ void java_bytecode_languaget::get_language_options(const cmdlinet &cmd) else lazy_methods_mode=LAZY_METHODS_MODE_EAGER; + if(cmd.isset("java-threading")) + threading_support = true; + else + threading_support = false; + if(cmd.isset("java-throw-runtime-exceptions")) { throw_runtime_exceptions = true; @@ -157,7 +166,7 @@ bool java_bytecode_languaget::parse( { string_preprocess.initialize_known_type_table(); - auto get_string_base_classes = [this](const irep_idt &id) { // NOLINT (*) + auto get_string_base_classes = [this](const irep_idt &id) { return string_preprocess.get_string_type_base_classes(id); }; @@ -697,7 +706,8 @@ bool java_bytecode_languaget::typecheck( // For each class that will require a static initializer wrapper, create a // function named package.classname::clinit_wrapper, and a corresponding // global tracking whether it has run or not: - create_static_initializer_wrappers(symbol_table, synthetic_methods); + create_static_initializer_wrappers( + symbol_table, synthetic_methods, threading_support); // Now incrementally elaborate methods // that are reachable from this entry point. @@ -957,7 +967,11 @@ bool java_bytecode_languaget::convert_single_method( switch(synthetic_method_it->second) { case synthetic_method_typet::STATIC_INITIALIZER_WRAPPER: - symbol.value = get_clinit_wrapper_body(function_id, symbol_table); + if(threading_support) + symbol.value = get_thread_safe_clinit_wrapper_body( + function_id, symbol_table); + else + symbol.value = get_clinit_wrapper_body(function_id, symbol_table); break; case synthetic_method_typet::STUB_CLASS_STATIC_INITIALIZER: symbol.value = diff --git a/src/java_bytecode/java_bytecode_language.h b/src/java_bytecode/java_bytecode_language.h index 47d5fb69d82..29c347fe227 100644 --- a/src/java_bytecode/java_bytecode_language.h +++ b/src/java_bytecode/java_bytecode_language.h @@ -10,22 +10,21 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_JAVA_BYTECODE_JAVA_BYTECODE_LANGUAGE_H #define CPROVER_JAVA_BYTECODE_JAVA_BYTECODE_LANGUAGE_H -#include - -#include -#include - -#include - #include "ci_lazy_methods.h" #include "ci_lazy_methods_needed.h" #include "java_class_loader.h" #include "java_static_initializers.h" #include "java_string_library_preprocess.h" #include "object_factory_parameters.h" +#include "select_pointer_type.h" #include "synthetic_methods_map.h" -#include +#include + +#include +#include + +#include #define JAVA_BYTECODE_LANGUAGE_OPTIONS /*NOLINT*/ \ "(no-core-models)" \ @@ -160,6 +159,7 @@ class java_bytecode_languaget:public languaget irep_idt main_class; std::vector main_jar_classes; java_class_loadert java_class_loader; + bool threading_support; bool assume_inputs_non_null; // assume inputs variables to be non-null object_factory_parameterst object_factory_parameters; size_t max_user_array_length; // max size for user code created arrays diff --git a/src/java_bytecode/java_bytecode_typecheck_type.cpp b/src/java_bytecode/java_bytecode_typecheck_type.cpp index aa92d9333cf..2f26feb59bc 100644 --- a/src/java_bytecode/java_bytecode_typecheck_type.cpp +++ b/src/java_bytecode/java_bytecode_typecheck_type.cpp @@ -11,6 +11,7 @@ Author: Daniel Kroening, kroening@kroening.com #include "java_bytecode_typecheck.h" +#include #include void java_bytecode_typecheckt::typecheck_type(typet &type) @@ -19,17 +20,12 @@ void java_bytecode_typecheckt::typecheck_type(typet &type) { irep_idt identifier=to_symbol_type(type).get_identifier(); - symbol_tablet::symbolst::const_iterator s_it= - symbol_table.symbols.find(identifier); - - // must exist already in the symbol table - if(s_it==symbol_table.symbols.end()) - { - error() << "failed to find type symbol "<< identifier << eom; - throw 0; - } - - assert(s_it->second.is_type); + auto type_symbol = symbol_table.lookup(identifier); + DATA_INVARIANT( + type_symbol, "symbol " + id2string(identifier) + " must exist already"); + DATA_INVARIANT( + type_symbol->is_type, + "symbol " + id2string(identifier) + " must be a type"); } else if(type.id()==ID_pointer) { @@ -55,7 +51,9 @@ void java_bytecode_typecheckt::typecheck_type(typet &type) void java_bytecode_typecheckt::typecheck_type_symbol(symbolt &symbol) { - assert(symbol.is_type); + DATA_INVARIANT( + symbol.is_type, "symbol " + id2string(symbol.name) + " must be a type"); + symbol.mode = ID_java; typecheck_type(symbol.type); } diff --git a/src/java_bytecode/java_class_loader.h b/src/java_bytecode/java_class_loader.h index 6f46072aaa2..6634172da93 100644 --- a/src/java_bytecode/java_class_loader.h +++ b/src/java_bytecode/java_class_loader.h @@ -55,7 +55,7 @@ class java_class_loadert:public messaget java_class_loader_limitt &class_loader_limit, const irep_idt &class_name); - void set_java_cp_include_files(std::string &java_cp_include_files) + void set_java_cp_include_files(const std::string &java_cp_include_files) { this->java_cp_include_files = java_cp_include_files; } diff --git a/src/java_bytecode/java_entry_point.cpp b/src/java_bytecode/java_entry_point.cpp index 5c3beafc357..2556ee4d7e9 100644 --- a/src/java_bytecode/java_entry_point.cpp +++ b/src/java_bytecode/java_entry_point.cpp @@ -8,30 +8,15 @@ Author: Daniel Kroening, kroening@kroening.com #include "java_entry_point.h" -#include -#include -#include -#include - -#include - -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include "remove_exceptions.h" +#include + +#include + #include "java_object_factory.h" -#include "java_types.h" #include "java_utils.h" static void create_initialize(symbol_table_baset &symbol_table) @@ -203,7 +188,7 @@ exprt::operandst java_build_arguments( !assume_init_pointers_not_null && !is_main && !is_this; object_factory_parameterst parameters = object_factory_parameters; - parameters.function_id = function.name; + parameters.function_id = goto_functionst::entry_point(); // generate code to allocate and non-deterministicaly initialize the // argument diff --git a/src/java_bytecode/java_entry_point.h b/src/java_bytecode/java_entry_point.h index 399078ee2f8..006334ff99c 100644 --- a/src/java_bytecode/java_entry_point.h +++ b/src/java_bytecode/java_entry_point.h @@ -10,10 +10,11 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_JAVA_BYTECODE_JAVA_ENTRY_POINT_H #define CPROVER_JAVA_BYTECODE_JAVA_ENTRY_POINT_H +#include "java_bytecode_language.h" +#include "select_pointer_type.h" + #include #include -#include -#include #define JAVA_ENTRY_POINT_RETURN_SYMBOL "return'" #define JAVA_ENTRY_POINT_EXCEPTION_SYMBOL "uncaught_exception'" diff --git a/src/java_bytecode/java_object_factory.cpp b/src/java_bytecode/java_object_factory.cpp index feaeb218f6c..612a66f9ce5 100644 --- a/src/java_bytecode/java_object_factory.cpp +++ b/src/java_bytecode/java_object_factory.cpp @@ -8,32 +8,14 @@ Author: Daniel Kroening, kroening@kroening.com #include "java_object_factory.h" -#include -#include - -#include #include -#include -#include -#include -#include #include -#include #include -#include -#include - -#include #include -#include - -#include "java_types.h" -#include "java_utils.h" -#include "java_string_library_preprocess.h" -#include "java_root_class.h" #include "generic_parameter_specialization_map_keys.h" +#include "java_root_class.h" class java_object_factoryt { diff --git a/src/java_bytecode/java_object_factory.h b/src/java_bytecode/java_object_factory.h index a5ba9ea5500..0d8ec5f0995 100644 --- a/src/java_bytecode/java_object_factory.h +++ b/src/java_bytecode/java_object_factory.h @@ -68,13 +68,13 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_JAVA_BYTECODE_JAVA_OBJECT_FACTORY_H #define CPROVER_JAVA_BYTECODE_JAVA_OBJECT_FACTORY_H +#include "java_bytecode_language.h" +#include "select_pointer_type.h" + #include #include #include -#include -#include - /// Selects the kind of allocation used by java_object_factory et al. enum class allocation_typet { diff --git a/src/java_bytecode/java_static_initializers.cpp b/src/java_bytecode/java_static_initializers.cpp index eefa2a42eb7..b001bb26001 100644 --- a/src/java_bytecode/java_static_initializers.cpp +++ b/src/java_bytecode/java_static_initializers.cpp @@ -14,6 +14,37 @@ Author: Chris Smowton, chris.smowton@diffblue.com #include #include #include +#include + +/// The three states in which a `` method for a class can be before, +/// after, and during static class initialization. These states are only used +/// when the thread safe version of the clinit wrapper is generated. +/// +/// According to the JVM Spec document (section 5.5), the JVM needs to +/// maintain, for every class initializer, a state indicating whether the +/// initializer has been executed, is being executed, or has raised errors. +/// The spec mandates that the JVM consider 4 different states (not +/// initialized, being initialized, ready for use, and initialization error). +/// The `clinit_statet` is a simplification of those 4 states where: +/// +/// `NOT_INIT` corresponds to "not initialized" +/// `IN_PROGRESS` corresponds to "some thread is currently running the +/// `` and no other thread should run it" +/// `INIT_COMPLETE` corresponds to "the `` has been executed and the +/// class is ready to be used, or it has errored" +/// +/// The last state corresponds to a fusion of the two original states "ready +/// for use" and "initialization error". The basis for fusing these states is +/// that for simplification reasons both implementations of the clinit wrapper +/// do not handle exceptions, hence the error state is not possible. +enum class clinit_statest +{ + NOT_INIT, + IN_PROGRESS, + INIT_COMPLETE +}; + +const typet clinit_states_type = java_byte_type(); // Disable linter here to allow a std::string constant, since that holds // a length, whereas a cstr would require strlen every time. @@ -39,6 +70,37 @@ bool is_clinit_wrapper_function(const irep_idt &function_id) return has_suffix(id2string(function_id), clinit_wrapper_suffix); } +/// Add a new symbol to the symbol table. +/// Note: assumes that a symbol with this name does not exist. +/// /param name: name of the symbol to be generated +/// /param type: type of the symbol to be generated +/// /param value: initial value of the symbol to be generated +/// /param is_thread_local: if true this symbol will be set as thread local +/// /param is_static_lifetime: if true this symbol will be set as static +/// /return returns new symbol. +static symbolt add_new_symbol( + symbol_table_baset &symbol_table, + const irep_idt &name, + const typet &type, + const exprt &value, + const bool is_thread_local, + const bool is_static_lifetime) +{ + symbolt new_symbol; + new_symbol.name = name; + new_symbol.pretty_name = name; + new_symbol.base_name = name; + new_symbol.type = type; + new_symbol.value = value; + new_symbol.is_lvalue = true; + new_symbol.is_state_var = true; + new_symbol.is_static_lifetime = is_static_lifetime; + new_symbol.is_thread_local = is_thread_local; + new_symbol.mode = ID_java; + symbol_table.add(new_symbol); + return new_symbol; +} + /// Get name of the static-initialization-already-done global variable for a /// given class. /// \param class_name: class symbol name @@ -57,6 +119,98 @@ static irep_idt clinit_function_name(const irep_idt &class_name) return id2string(class_name) + clinit_function_suffix; } +/// Get name of the static-initialization-state global variable for a +/// given class. +/// \param class_name: class symbol name +/// \return static initializer wrapper-state variable global name +static irep_idt clinit_state_var_name(const irep_idt &class_name) +{ + return id2string(class_name) + CPROVER_PREFIX "clinit_state"; +} + +/// Get name of the static-initialization-state local state variable for a +/// given class. +/// \param class_name: class symbol name +/// \return static initializer wrapper-state local state variable name +static irep_idt clinit_thread_local_state_var_name(const irep_idt &class_name) +{ + return id2string(class_name) + CPROVER_PREFIX "clinit_threadlocal_state"; +} + +/// Get name of the static-initialization local variable for a given class. +/// \param class_name: class symbol name +/// \return static initializer wrapper-state local variable +static irep_idt clinit_local_init_complete_var_name(const irep_idt &class_name) +{ + return id2string(class_name) + CPROVER_PREFIX "clinit_wrapper::init_complete"; +} + +/// Generates a code_assignt for clinit_statest +/// /param expr: +/// expression to be used as the LHS of generated assignment. +/// /param state: +/// execution state of the clint_wrapper, used as the RHS of the generated +/// assignment. +/// /return returns a code_assignt, assigning \p expr to the integer +/// representation of \p state +static code_assignt +gen_clinit_assignexpr(const exprt &expr, const clinit_statest state) +{ + mp_integer initv(static_cast(state)); + constant_exprt init_s = from_integer(initv, clinit_states_type); + return code_assignt(expr, init_s); +} + +/// Generates an equal_exprt for clinit_statest +/// /param expr: +/// expression to be used as the LHS of generated eqaul exprt. +/// /param state: +/// execution state of the clint_wrapper, used as the RHS of the generated +/// equal exprt. +/// /return returns a equal_exprt, equating \p expr to the integer +/// representation of \p state +static equal_exprt +gen_clinit_eqexpr(const exprt &expr, const clinit_statest state) +{ + mp_integer initv(static_cast(state)); + constant_exprt init_s = from_integer(initv, clinit_states_type); + return equal_exprt(expr, init_s); +} + +/// Generates codet that iterates through the base types of the class specified +/// by class_name, C, and recursively adds calls to their clinit wrapper. +/// Finally a call to the clinint wrapper of C is made. +/// \param symbol_table: symbol table +/// \param class_name: name of the class to generate clinit wrapper calls for +/// \param [out] init_body: appended with calls to clinit wrapper +static void clinit_wrapper_do_recursive_calls( + const symbol_tablet &symbol_table, + const irep_idt &class_name, + code_blockt &init_body) +{ + const symbolt &class_symbol = symbol_table.lookup_ref(class_name); + for(const auto &base : to_class_type(class_symbol.type).bases()) + { + const auto base_name = to_symbol_type(base.type()).get_identifier(); + irep_idt base_init_routine = clinit_wrapper_name(base_name); + auto findit = symbol_table.symbols.find(base_init_routine); + if(findit == symbol_table.symbols.end()) + continue; + code_function_callt call_base; + call_base.function() = findit->second.symbol_expr(); + init_body.move_to_operands(call_base); + } + + const irep_idt &real_clinit_name = clinit_function_name(class_name); + auto find_sym_it = symbol_table.symbols.find(real_clinit_name); + if(find_sym_it != symbol_table.symbols.end()) + { + code_function_callt call_real_init; + call_real_init.function() = find_sym_it->second.symbol_expr(); + init_body.move_to_operands(call_real_init); + } +} + /// Checks whether a static initializer wrapper is needed for a given class, /// i.e. if the given class or any superclass has a static initializer. /// \param class_name: class symbol name @@ -91,26 +245,53 @@ static bool needs_clinit_wrapper( /// \param synthetic_methods: synthetic method type map. The new clinit wrapper /// symbol will be recorded, such that we get a callback to produce its body /// if and when required. +/// \param thread_safe: if true state variables required to make the +/// clinit_wrapper thread safe will be created. static void create_clinit_wrapper_symbols( const irep_idt &class_name, symbol_tablet &symbol_table, - synthetic_methods_mapt &synthetic_methods) + synthetic_methods_mapt &synthetic_methods, + const bool thread_safe) { - const irep_idt &already_run_name = - clinit_already_run_variable_name(class_name); - symbolt already_run_symbol; - already_run_symbol.name = already_run_name; - already_run_symbol.pretty_name = already_run_name; - already_run_symbol.base_name = "clinit_already_run"; - already_run_symbol.type = bool_typet(); - already_run_symbol.value = false_exprt(); - already_run_symbol.is_lvalue = true; - already_run_symbol.is_state_var = true; - already_run_symbol.is_static_lifetime = true; - already_run_symbol.mode = ID_java; - bool failed = symbol_table.add(already_run_symbol); - INVARIANT(!failed, "clinit-already-run symbol should be fresh"); + if(thread_safe) + { + exprt not_init_value = from_integer( + static_cast(clinit_statest::NOT_INIT), clinit_states_type); + + // Create two global static synthetic "fields" for the class "id" + // these two variables hold the state of the class initialization algorithm + // across calls to the clinit_wrapper + add_new_symbol( + symbol_table, + clinit_state_var_name(class_name), + clinit_states_type, + not_init_value, + false, + true); + add_new_symbol( + symbol_table, + clinit_thread_local_state_var_name(class_name), + clinit_states_type, + not_init_value, + true, + true); + } + else + { + const irep_idt &already_run_name = + clinit_already_run_variable_name(class_name); + + add_new_symbol( + symbol_table, + already_run_name, + bool_typet(), + false_exprt(), + false, + true); + } + + // Create symbol for the "clinit_wrapper" symbolt wrapper_method_symbol; code_typet wrapper_method_type; wrapper_method_type.return_type() = void_typet(); @@ -126,7 +307,7 @@ static void create_clinit_wrapper_symbols( // java_bytecode_convert_methodt::convert wrapper_method_symbol.type.set(ID_C_class, class_name); wrapper_method_symbol.mode = ID_java; - failed = symbol_table.add(wrapper_method_symbol); + bool failed = symbol_table.add(wrapper_method_symbol); INVARIANT(!failed, "clinit-wrapper symbol should be fresh"); auto insert_result = synthetic_methods.emplace( @@ -138,13 +319,256 @@ static void create_clinit_wrapper_symbols( "clinit wrapper"); } -/// Produces the static initialiser wrapper body for the given function. +/// Thread safe version of the static initialiser. +/// +/// Produces the static initialiser wrapper body for the given function. This +/// static initializer implements (a simplification of) the algorithm defined +/// in Section 5.5 of the JVM Specs. This function, or wrapper, checks whether +/// static init has already taken place, calls the actual `` method if +/// not, and possibly recursively initializes super-classes and interfaces. +/// Assume that C is the class to be initialized and that C extends C' and +/// implements interfaces I1 ... In, then the algorithm is as follows: +/// +/// \code +/// +/// bool init_complete; +/// if(java::C::__CPROVER_PREFIX_clinit_thread_local_state == INIT_COMPLETE) +/// { +/// return; +/// } +/// java::C::__CPROVER_PREFIX_clinit_thread_local_state = INIT_COMPLETE; +/// +/// // This thread atomically checks and sets the global variable +/// // 'clinit_state' in order to ensure that only this thread runs the +/// // static initializer. The assume() statement below will prevent the SAT +/// // solver from producing a thread schedule where more than 1 thread is +/// // running the initializer. At the end of this function the only +/// // thread that runs the static initializer will update the variable. +/// // Alternatively we could have done a busy wait / spin-lock, but that +/// // would achieve the same effect and blow up the size of the SAT formula. +/// ATOMIC_BEGIN +/// assume(java::C::__CPROVER_PREFIX_clinit_state != IN_PROGRESS) +/// if(java::C::__CPROVER_PREFIX_clinit_state == NOT_INIT) +/// { +/// java::C::__CPROVER_PREFIX_clinit_state = IN_PROGRESS +/// init_complete = false; +/// } +/// else if(java::C::__CPROVER_PREFIX_clinit_state == INIT_COMPLETE) +/// { +/// init_complete = true; +/// } +/// ATOMIC_END +/// +/// if(init_complete) +/// return; +/// +/// java::C'::clinit_wrapper(); +/// java::I1::clinit_wrapper(); +/// java::I2::clinit_wrapper(); +/// // ... +/// java::In::clinit_wrapper(); +/// +/// java::C::(); +/// +/// // Setting this variable to INIT_COMPLETE will let other threads "cross" +/// // beyond the assume() statement above in this function. +/// ATOMIC_START +/// C::__CPROVER_PREFIX_clinit_state = INIT_COMPLETE; +/// ATOMIC_END +/// +/// return; +/// +/// \endcode +/// +/// Note: The current implementation does not deal with exceptions. +/// /// \param function_id: clinit wrapper function id (the wrapper_method_symbol /// name created by `create_clinit_wrapper_symbols`) /// \param symbol_table: global symbol table /// \return the body of the static initialiser wrapper +codet get_thread_safe_clinit_wrapper_body( + const irep_idt &function_id, + symbol_table_baset &symbol_table) +{ + const symbolt &wrapper_method_symbol = symbol_table.lookup_ref(function_id); + irep_idt class_name = wrapper_method_symbol.type.get(ID_C_class); + INVARIANT( + !class_name.empty(), "wrapper function should be annotated with its class"); + + const symbolt &clinit_state_sym = + symbol_table.lookup_ref(clinit_state_var_name(class_name)); + const symbolt &clinit_thread_local_state_sym = + symbol_table.lookup_ref(clinit_thread_local_state_var_name(class_name)); + + // Create a function-local variable "init_complete". This variable is used to + // avoid inspecting the global state (clinit_state_sym) outside of + // the critical-section. + const symbolt &init_complete = add_new_symbol( + symbol_table, + clinit_local_init_complete_var_name(class_name), + bool_typet(), + nil_exprt(), + true, + false); + + code_blockt function_body; + codet atomic_begin(ID_atomic_begin); + codet atomic_end(ID_atomic_end); + +#if 0 + // This code defines source locations for every codet generated below for + // the static initializer wrapper. Enable this for debugging the symex going + // through the clinit_wrapper. + // + // java::C::clinit_wrapper() + // You will additionally need to associate the `location` with the + // `function_body` and then manually set lines of code for each of the + // statements of the function, using something along the lines of: + // `mycodet.then_case().add_source_location().set_line(17);`/ + + source_locationt &location = function_body.add_source_location(); + location.set_file (""); + location.set_line (""); + location.set_function (clinit_wrapper_name); + std::string comment = + "Automatically generated function. States are:\n" + " 0 = class not initialized, init val of clinit_state/clinit_local_state\n" + " 1 = class initialization in progress, by this or another thread\n" + " 2 = initialization finished with success, by this or another thread\n"; + static_assert((int) clinit_statest::NOT_INIT==0, "Check commment above"); + static_assert((int) clinit_statest::IN_PROGRESS==1, "Check comment above"); + static_assert((int) clinit_statest::INIT_COMPLETE==2, "Check comment above"); +#endif + + // bool init_complete; + { + code_declt decl(init_complete.symbol_expr()); + function_body.add(decl); + } + + // if(C::__CPROVER_PREFIX_clinit_thread_local_state == INIT_COMPLETE) return; + { + code_ifthenelset conditional; + conditional.cond() = gen_clinit_eqexpr( + clinit_thread_local_state_sym.symbol_expr(), + clinit_statest::INIT_COMPLETE); + conditional.then_case() = code_returnt(); + function_body.add(conditional); + } + + // C::__CPROVER_PREFIX_clinit_thread_local_state = INIT_COMPLETE; + { + code_assignt assign = gen_clinit_assignexpr( + clinit_thread_local_state_sym.symbol_expr(), + clinit_statest::INIT_COMPLETE); + function_body.add(assign); + } + + // ATOMIC_BEGIN + { + function_body.add(atomic_begin); + } + + // Assume: clinit_state_sym != IN_PROGRESS + { + exprt assumption = gen_clinit_eqexpr( + clinit_state_sym.symbol_expr(), clinit_statest::IN_PROGRESS); + assumption = not_exprt(assumption); + code_assumet assume(assumption); + function_body.add(assume); + } + + // If(C::__CPROVER_PREFIX_clinit_state == NOT_INIT) + // { + // C::__CPROVER_PREFIX_clinit_state = IN_PROGRESS; + // init_complete = false; + // } + // else If(C::__CPROVER_PREFIX_clinit_state == INIT_COMPLETE) + // { + // init_complete = true; + // } + { + code_ifthenelset not_init_conditional; + code_blockt then_block; + not_init_conditional.cond() = gen_clinit_eqexpr( + clinit_state_sym.symbol_expr(), clinit_statest::NOT_INIT); + then_block.add( + gen_clinit_assignexpr( + clinit_state_sym.symbol_expr(), clinit_statest::IN_PROGRESS)); + then_block.add(code_assignt(init_complete.symbol_expr(), false_exprt())); + not_init_conditional.then_case() = then_block; + + code_ifthenelset init_conditional; + code_blockt init_conditional_body; + init_conditional.cond() = gen_clinit_eqexpr( + clinit_state_sym.symbol_expr(), clinit_statest::INIT_COMPLETE); + init_conditional_body.add( + code_assignt(init_complete.symbol_expr(), true_exprt())); + init_conditional.then_case() = init_conditional_body; + not_init_conditional.else_case() = init_conditional; + function_body.add(not_init_conditional); + } + + // ATOMIC_END + { + function_body.add(atomic_end); + } + + // if(init_complete) return; + { + code_ifthenelset conditional; + conditional.cond() = init_complete.symbol_expr(); + conditional.then_case() = code_returnt(); + function_body.add(conditional); + } + + // Initialize the super-class C' and + // the implemented interfaces l_1 ... l_n. + // see JVMS p.359 step 7, for the exact definition of + // the sequence l_1 to l_n. + // This is achieved by iterating through the base types and + // adding recursive calls to the clinit_wrapper() + // + // java::C'::clinit_wrapper(); + // java::I1::clinit_wrapper(); + // java::I2::clinit_wrapper(); + // // ... + // java::In::clinit_wrapper(); + // + // java::C::(); + // + { + code_blockt init_body; + clinit_wrapper_do_recursive_calls(symbol_table, class_name, init_body); + function_body.append(init_body); + } + + // ATOMIC_START + // C::__CPROVER_PREFIX_clinit_state = INIT_COMPLETE; + // ATOMIC_END + // return; + { + // synchronization prologue + function_body.add(atomic_begin); + function_body.add( + gen_clinit_assignexpr( + clinit_state_sym.symbol_expr(), clinit_statest::INIT_COMPLETE)); + function_body.add(atomic_end); + function_body.add(code_returnt()); + } + + return function_body; +} + +/// Produces the static initialiser wrapper body for the given function. +/// Note: this version of the clinit wrapper is not thread safe. +/// \param function_id: clinit wrapper function id (the wrapper_method_symbol +/// name created by `create_clinit_wrapper_symbols`) +/// \param symbol_table: global symbol table +/// \return the body of the static initialiser wrapper/ codet get_clinit_wrapper_body( - const irep_idt &function_id, const symbol_table_baset &symbol_table) + const irep_idt &function_id, + symbol_table_baset &symbol_table) { // Assume that class C extends class C' and implements interfaces // I1, ..., In. We now create the following function (possibly recursively @@ -169,6 +593,7 @@ codet get_clinit_wrapper_body( irep_idt class_name = wrapper_method_symbol.type.get(ID_C_class); INVARIANT( !class_name.empty(), "wrapper function should be annotated with its class"); + const symbolt &already_run_symbol = symbol_table.lookup_ref(clinit_already_run_variable_name(class_name)); @@ -180,50 +605,32 @@ codet get_clinit_wrapper_body( code_ifthenelset wrapper_body; // add the condition to the if - wrapper_body.cond()=check_already_run; + wrapper_body.cond() = check_already_run; // add the "already-run = false" statement code_blockt init_body; code_assignt set_already_run(already_run_symbol.symbol_expr(), true_exprt()); init_body.move_to_operands(set_already_run); - // iterate through the base types and add recursive calls to the - // clinit_wrapper() - const symbolt &class_symbol = symbol_table.lookup_ref(class_name); - for(const auto &base : to_class_type(class_symbol.type).bases()) - { - const auto base_name = to_symbol_type(base.type()).get_identifier(); - irep_idt base_init_routine = clinit_wrapper_name(base_name); - auto findit = symbol_table.symbols.find(base_init_routine); - if(findit == symbol_table.symbols.end()) - continue; - code_function_callt call_base; - call_base.function() = findit->second.symbol_expr(); - init_body.move_to_operands(call_base); - } + clinit_wrapper_do_recursive_calls(symbol_table, class_name, init_body); - // call java::C::(), if the class has one static initializer - const irep_idt &real_clinit_name = clinit_function_name(class_name); - auto find_sym_it = symbol_table.symbols.find(real_clinit_name); - if(find_sym_it!=symbol_table.symbols.end()) - { - code_function_callt call_real_init; - call_real_init.function()=find_sym_it->second.symbol_expr(); - init_body.move_to_operands(call_real_init); - } - wrapper_body.then_case()=init_body; + wrapper_body.then_case() = init_body; return wrapper_body; } + /// Create static initializer wrappers for all classes that need them. /// \param symbol_table: global symbol table /// \param synthetic_methods: synthetic methods map. Will be extended noting /// that any wrapper belongs to this code, and so `get_clinit_wrapper_body` /// should be used to produce the method body when required. +/// \param thread_safe: if true state variables required to make the +/// clinit_wrapper thread safe will be created. void create_static_initializer_wrappers( symbol_tablet &symbol_table, - synthetic_methods_mapt &synthetic_methods) + synthetic_methods_mapt &synthetic_methods, + const bool thread_safe) { // Top-sort the class hierarchy, such that we visit parents before children, // and can so identify parents that need static initialisation by whether we @@ -239,7 +646,7 @@ void create_static_initializer_wrappers( if(needs_clinit_wrapper(class_identifier, symbol_table)) { create_clinit_wrapper_symbols( - class_identifier, symbol_table, synthetic_methods); + class_identifier, symbol_table, synthetic_methods, thread_safe); } } } diff --git a/src/java_bytecode/java_static_initializers.h b/src/java_bytecode/java_static_initializers.h index 6b65a29459d..f5f965a31b9 100644 --- a/src/java_bytecode/java_static_initializers.h +++ b/src/java_bytecode/java_static_initializers.h @@ -9,13 +9,14 @@ Author: Chris Smowton, chris.smowton@diffblue.com #ifndef CPROVER_JAVA_BYTECODE_JAVA_STATIC_INITIALIZERS_H #define CPROVER_JAVA_BYTECODE_JAVA_STATIC_INITIALIZERS_H +#include "object_factory_parameters.h" +#include "select_pointer_type.h" +#include "synthetic_methods_map.h" + #include #include #include -#include -#include -#include irep_idt clinit_wrapper_name(const irep_idt &class_name); @@ -23,10 +24,16 @@ bool is_clinit_wrapper_function(const irep_idt &function_id); void create_static_initializer_wrappers( symbol_tablet &symbol_table, - synthetic_methods_mapt &synthetic_methods); + synthetic_methods_mapt &synthetic_methods, + bool thread_safe); + +codet get_thread_safe_clinit_wrapper_body( + const irep_idt &function_id, + symbol_table_baset &symbol_table); codet get_clinit_wrapper_body( - const irep_idt &function_id, const symbol_table_baset &symbol_table); + const irep_idt &function_id, + symbol_table_baset &symbol_table); class stub_global_initializer_factoryt { diff --git a/src/java_bytecode/java_string_library_preprocess.cpp b/src/java_bytecode/java_string_library_preprocess.cpp index 009882d2dab..655c696f659 100644 --- a/src/java_bytecode/java_string_library_preprocess.cpp +++ b/src/java_bytecode/java_string_library_preprocess.cpp @@ -247,6 +247,7 @@ void java_string_library_preprocesst::add_string_type( string_symbol->pretty_name=id2string(class_name); string_symbol->type=string_type; string_symbol->is_type=true; + string_symbol->mode = ID_java; } /// add a symbol in the table with static lifetime and name containing @@ -877,7 +878,7 @@ codet java_string_library_preprocesst::code_assign_string_expr_to_java_string( /// \param symbol_table: symbol table /// \param [out] code: code block that gets appended the following code: /// ~~~~~~~~~~~~~~~~~~~~~~ -/// lhs.length=rhs->length +/// lhs.length = rhs==null ? 0 : rhs->length /// lhs.data=rhs->data /// ~~~~~~~~~~~~~~~~~~~~~~ void java_string_library_preprocesst::code_assign_java_string_to_string_expr( @@ -898,8 +899,14 @@ void java_string_library_preprocesst::code_assign_java_string_to_string_expr( const dereference_exprt deref = checked_dereference(rhs, deref_type); - // Fields of the string object - const exprt rhs_length = get_length(deref, symbol_table); + // Although we should not reach this code if rhs is null, the association + // `pointer -> length` is added to the solver anyway, so we have to make sure + // the length is set to something reasonable. + auto rhs_length = if_exprt( + equal_exprt(rhs, null_pointer_exprt(to_pointer_type(rhs.type()))), + from_integer(0, lhs.length().type()), + get_length(deref, symbol_table)); + rhs_length.set(ID_mode, ID_java); // Assignments code.add(code_assignt(lhs.length(), rhs_length), loc); diff --git a/src/java_bytecode/object_factory_parameters.h b/src/java_bytecode/object_factory_parameters.h index 5e0785bf7a7..17b838242c2 100644 --- a/src/java_bytecode/object_factory_parameters.h +++ b/src/java_bytecode/object_factory_parameters.h @@ -12,6 +12,8 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include + #define MAX_NONDET_ARRAY_LENGTH_DEFAULT 5 #define MAX_NONDET_STRING_LENGTH std::numeric_limits::max() #define MAX_NONDET_TREE_DEPTH 5 diff --git a/src/java_bytecode/remove_exceptions.cpp b/src/java_bytecode/remove_exceptions.cpp index 618c1a8cda1..9b6801128c2 100644 --- a/src/java_bytecode/remove_exceptions.cpp +++ b/src/java_bytecode/remove_exceptions.cpp @@ -572,7 +572,7 @@ void remove_exceptions( std::map> exceptions_map; uncaught_exceptions(goto_functions, ns, exceptions_map); remove_exceptionst::function_may_throwt function_may_throw = - [&exceptions_map](const irep_idt &id) { // NOLINT(whitespace/braces) + [&exceptions_map](const irep_idt &id) { return !exceptions_map[id].empty(); }; remove_exceptionst remove_exceptions( diff --git a/src/java_bytecode/remove_instanceof.cpp b/src/java_bytecode/remove_instanceof.cpp index 37cb8cc3094..cb93fcbbb98 100644 --- a/src/java_bytecode/remove_instanceof.cpp +++ b/src/java_bytecode/remove_instanceof.cpp @@ -90,9 +90,7 @@ std::size_t remove_instanceoft::lower_instanceof( // Sort alphabetically to make order of generated disjuncts // independent of class loading order std::sort( - children.begin(), - children.end(), - [](const irep_idt &a, const irep_idt &b) { // NOLINT + children.begin(), children.end(), [](const irep_idt &a, const irep_idt &b) { return a.compare(b) < 0; }); diff --git a/src/java_bytecode/remove_java_new.cpp b/src/java_bytecode/remove_java_new.cpp new file mode 100644 index 00000000000..c1354c53e16 --- /dev/null +++ b/src/java_bytecode/remove_java_new.cpp @@ -0,0 +1,438 @@ +/*******************************************************************\ + +Module: Remove Java New Operators + +Author: Peter Schrammel + +\*******************************************************************/ + +/// \file +/// Remove Java New Operators + +#include "remove_java_new.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +class remove_java_newt : public messaget +{ +public: + remove_java_newt( + symbol_table_baset &symbol_table, + message_handlert &_message_handler) + : messaget(_message_handler), symbol_table(symbol_table), ns(symbol_table) + { + } + + // Lower java_new for a single function + bool lower_java_new(goto_programt &); + + // Lower java_new for a single instruction + goto_programt::targett + lower_java_new(goto_programt &, goto_programt::targett); + +protected: + symbol_table_baset &symbol_table; + namespacet ns; + + goto_programt::targett lower_java_new( + exprt lhs, + side_effect_exprt rhs, + goto_programt &, + goto_programt::targett); + + goto_programt::targett lower_java_new_array( + exprt lhs, + side_effect_exprt rhs, + goto_programt &, + goto_programt::targett); +}; + +/// Replaces the instruction `lhs = new java_type` by +/// two instructions: +/// lhs = ALLOCATE(java_type) +/// *lhs = { zero-initialized java_type } +/// \param lhs: the lhs +/// \param rhs: the rhs +/// \param dest: the goto program to modify +/// \param target: the goto instruction to replace +/// \return the iterator advanced to the last of the inserted instructions +/// Note: we have to take a copy of `lhs` and `rhs` since they would suffer +/// destruction when replacing the instruction. +goto_programt::targett remove_java_newt::lower_java_new( + exprt lhs, + side_effect_exprt rhs, + goto_programt &dest, + goto_programt::targett target) +{ + PRECONDITION(!lhs.is_nil()); + PRECONDITION(rhs.operands().empty()); + PRECONDITION(rhs.type().id() == ID_pointer); + source_locationt location = rhs.source_location(); + typet object_type = rhs.type().subtype(); + + // build size expression + exprt object_size = size_of_expr(object_type, ns); + CHECK_RETURN(object_size.is_not_nil()); + + // we produce a malloc side-effect, which stays + side_effect_exprt malloc_expr(ID_allocate, rhs.type()); + malloc_expr.copy_to_operands(object_size); + // could use true and get rid of the code below + malloc_expr.copy_to_operands(false_exprt()); + target->make_assignment(code_assignt(lhs, malloc_expr)); + target->source_location = location; + + // zero-initialize the object + dereference_exprt deref(lhs, object_type); + exprt zero_object = + zero_initializer(object_type, location, ns, get_message_handler()); + set_class_identifier( + to_struct_expr(zero_object), ns, to_symbol_type(object_type)); + goto_programt::targett t_i = dest.insert_after(target); + t_i->make_assignment(code_assignt(deref, zero_object)); + t_i->source_location = location; + + return t_i; +} + +/// Replaces the instruction `lhs = new java_array_type` by +/// the following code: +/// lhs = ALLOCATE(java_type) +/// loops to initialize the elements (including multi-dimensional arrays) +/// \param lhs: the lhs +/// \param rhs: the rhs +/// \param dest: the goto program to modify +/// \param target: the goto instruction to replace +/// \return the iterator advanced to the last of the inserted instructions +/// Note: we have to take a copy of `lhs` and `rhs` since they would suffer +/// destruction when replacing the instruction. +goto_programt::targett remove_java_newt::lower_java_new_array( + exprt lhs, + side_effect_exprt rhs, + goto_programt &dest, + goto_programt::targett target) +{ + // lower_java_new_array without lhs not implemented + PRECONDITION(!lhs.is_nil()); + PRECONDITION(rhs.operands().size() >= 1); // one per dimension + PRECONDITION(rhs.type().id() == ID_pointer); + + source_locationt location = rhs.source_location(); + typet object_type = rhs.type().subtype(); + PRECONDITION(ns.follow(object_type).id() == ID_struct); + + // build size expression + exprt object_size = size_of_expr(object_type, ns); + CHECK_RETURN(!object_size.is_nil()); + + // we produce a malloc side-effect, which stays + side_effect_exprt malloc_expr(ID_allocate, rhs.type()); + malloc_expr.copy_to_operands(object_size); + // code use true and get rid of the code below + malloc_expr.copy_to_operands(false_exprt()); + + target->make_assignment(code_assignt(lhs, malloc_expr)); + target->source_location = location; + goto_programt::targett next = std::next(target); + + const struct_typet &struct_type = to_struct_type(ns.follow(object_type)); + + // Ideally we would have a check for `is_valid_java_array(struct_type)` but + // `is_valid_java_array is part of the java_bytecode module and we cannot + // introduce such dependencies. We do this simple check instead: + PRECONDITION(struct_type.components().size() == 3); + + // Init base class: + dereference_exprt deref(lhs, object_type); + exprt zero_object = + zero_initializer(object_type, location, ns, get_message_handler()); + set_class_identifier( + to_struct_expr(zero_object), ns, to_symbol_type(object_type)); + goto_programt::targett t_i = dest.insert_before(next); + t_i->make_assignment(code_assignt(deref, zero_object)); + t_i->source_location = location; + + // if it's an array, we need to set the length field + member_exprt length( + deref, + struct_type.components()[1].get_name(), + struct_type.components()[1].type()); + goto_programt::targett t_s = dest.insert_before(next); + t_s->make_assignment(code_assignt(length, rhs.op0())); + t_s->source_location = location; + + // we also need to allocate space for the data + member_exprt data( + deref, + struct_type.components()[2].get_name(), + struct_type.components()[2].type()); + + // Allocate a (struct realtype**) instead of a (void**) if possible. + const irept &given_element_type = object_type.find(ID_C_element_type); + typet allocate_data_type; + if(given_element_type.is_not_nil()) + { + allocate_data_type = + pointer_type(static_cast(given_element_type)); + } + else + allocate_data_type = data.type(); + + side_effect_exprt data_java_new_expr( + ID_java_new_array_data, allocate_data_type); + + // The instruction may specify a (hopefully small) upper bound on the + // array size, in which case we allocate a fixed-length array that may + // be larger than the `length` member rather than use a true variable- + // length array, which produces a more complex formula in the current + // backend. + const irept size_bound = rhs.find(ID_length_upper_bound); + if(size_bound.is_nil()) + data_java_new_expr.set(ID_size, rhs.op0()); + else + data_java_new_expr.set(ID_size, size_bound); + + // Must directly assign the new array to a temporary + // because goto-symex will notice `x=side_effect_exprt` but not + // `x=typecast_exprt(side_effect_exprt(...))` + symbol_exprt new_array_data_symbol = get_fresh_aux_symbol( + data_java_new_expr.type(), + id2string(target->function), + "tmp_new_data_array", + location, + ID_java, + symbol_table) + .symbol_expr(); + code_declt array_decl(new_array_data_symbol); + array_decl.add_source_location() = location; + goto_programt::targett t_array_decl = dest.insert_before(next); + t_array_decl->make_decl(array_decl); + t_array_decl->source_location = location; + goto_programt::targett t_p2 = dest.insert_before(next); + t_p2->make_assignment( + code_assignt(new_array_data_symbol, data_java_new_expr)); + t_p2->source_location = location; + + goto_programt::targett t_p = dest.insert_before(next); + exprt cast_java_new = new_array_data_symbol; + if(cast_java_new.type() != data.type()) + cast_java_new = typecast_exprt(cast_java_new, data.type()); + t_p->make_assignment(code_assignt(data, cast_java_new)); + t_p->source_location = location; + + // zero-initialize the data + 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(new_array_data_symbol, zero_element); + goto_programt::targett t_d = dest.insert_before(next); + t_d->make_other(array_set); + t_d->source_location = location; + } + + // multi-dimensional? + + if(rhs.operands().size() >= 2) + { + // produce + // for(int i=0; ifunction), + "tmp_index", + location, + ID_java, + symbol_table) + .symbol_expr(); + code_declt decl(tmp_i); + decl.add_source_location() = location; + goto_programt::targett t_decl = tmp.insert_before(tmp.instructions.begin()); + t_decl->make_decl(decl); + t_decl->source_location = location; + + code_fort for_loop; + + side_effect_exprt sub_java_new = rhs; + sub_java_new.operands().erase(sub_java_new.operands().begin()); + + // we already know that rhs has pointer type + typet sub_type = + static_cast(rhs.type().subtype().find("#element_type")); + CHECK_RETURN(sub_type.id() == ID_pointer); + sub_java_new.type() = sub_type; + + side_effect_exprt inc(ID_assign); + inc.operands().resize(2); + inc.op0() = tmp_i; + inc.op1() = plus_exprt(tmp_i, from_integer(1, tmp_i.type())); + + dereference_exprt deref_expr( + plus_exprt(data, tmp_i), data.type().subtype()); + + code_blockt for_body; + symbol_exprt init_sym = get_fresh_aux_symbol( + sub_type, + id2string(target->function), + "subarray_init", + location, + ID_java, + symbol_table) + .symbol_expr(); + code_declt init_decl(init_sym); + init_decl.add_source_location() = location; + for_body.move_to_operands(init_decl); + + code_assignt init_subarray(init_sym, sub_java_new); + code_assignt assign_subarray( + deref_expr, typecast_exprt(init_sym, deref_expr.type())); + for_body.move_to_operands(init_subarray); + for_body.move_to_operands(assign_subarray); + + for_loop.init() = code_assignt(tmp_i, from_integer(0, tmp_i.type())); + for_loop.cond() = binary_relation_exprt(tmp_i, ID_lt, rhs.op0()); + for_loop.iter() = inc; + for_loop.body() = for_body; + + goto_convert(for_loop, symbol_table, tmp, get_message_handler()); + + // lower new side effects recursively + lower_java_new(tmp); + + dest.destructive_insert(next, tmp); + } + + return std::prev(next); +} + +/// Replace every java_new or java_new_array by a malloc side-effect +/// and zero initialization. +/// \param goto_program: program to process +/// \param target: instruction to check for java_new expressions +/// \return true if a replacement has been made +goto_programt::targett remove_java_newt::lower_java_new( + goto_programt &goto_program, + goto_programt::targett target) +{ + const auto maybe_code_assign = + expr_try_dynamic_cast(target->code); + if(!maybe_code_assign) + return target; + + const exprt &lhs = maybe_code_assign->lhs(); + const exprt &rhs = maybe_code_assign->rhs(); + + if(rhs.id() == ID_side_effect && rhs.get(ID_statement) == ID_java_new) + { + return lower_java_new(lhs, to_side_effect_expr(rhs), goto_program, target); + } + + if(rhs.id() == ID_side_effect && rhs.get(ID_statement) == ID_java_new_array) + { + return lower_java_new_array( + lhs, to_side_effect_expr(rhs), goto_program, target); + } + + return target; +} + +/// Replace every java_new or java_new_array by a malloc side-effect +/// and zero initialization. +/// Extra auxiliary variables may be introduced into symbol_table. +/// \param goto_program: The function body to work on. +/// \return true if one or more java_new expressions have been replaced +bool remove_java_newt::lower_java_new(goto_programt &goto_program) +{ + bool changed = false; + for(goto_programt::instructionst::iterator target = + goto_program.instructions.begin(); + target != goto_program.instructions.end(); + ++target) + { + goto_programt::targett new_target = lower_java_new(goto_program, target); + changed = changed || new_target == target; + target = new_target; + } + if(!changed) + return false; + goto_program.update(); + return true; +} + +/// Replace every java_new or java_new_array by a malloc side-effect +/// and zero initialization. +/// \remarks Extra auxiliary variables may be introduced into symbol_table. +/// \param target: The instruction to work on. +/// \param goto_program: The function body containing the instruction. +/// \param symbol_table: The symbol table to add symbols to. +/// \param message_handler: a message handler +void remove_java_new( + goto_programt::targett target, + goto_programt &goto_program, + symbol_table_baset &symbol_table, + message_handlert &message_handler) +{ + remove_java_newt rem(symbol_table, message_handler); + rem.lower_java_new(goto_program, target); +} + +/// Replace every java_new or java_new_array by a malloc side-effect +/// and zero initialization. +/// \remarks Extra auxiliary variables may be introduced into symbol_table. +/// \param function: The function to work on. +/// \param symbol_table: The symbol table to add symbols to. +/// \param message_handler: a message handler +void remove_java_new( + goto_functionst::goto_functiont &function, + symbol_table_baset &symbol_table, + message_handlert &message_handler) +{ + remove_java_newt rem(symbol_table, message_handler); + rem.lower_java_new(function.body); +} + +/// Replace every java_new or java_new_array by a malloc side-effect +/// and zero initialization. +/// \remarks Extra auxiliary variables may be introduced into symbol_table. +/// \param goto_functions: The functions to work on. +/// \param symbol_table: The symbol table to add symbols to. +/// \param message_handler: a message handler +void remove_java_new( + goto_functionst &goto_functions, + symbol_table_baset &symbol_table, + message_handlert &message_handler) +{ + remove_java_newt rem(symbol_table, message_handler); + bool changed = false; + for(auto &f : goto_functions.function_map) + changed = rem.lower_java_new(f.second.body) || changed; + if(changed) + goto_functions.compute_location_numbers(); +} + +/// Replace every java_new or java_new_array by a malloc side-effect +/// and zero initialization. +/// \remarks Extra auxiliary variables may be introduced into symbol_table. +/// \param goto_model: The functions to work on and the symbol table to add +/// symbols to. +/// \param message_handler: a message handler +void remove_java_new(goto_modelt &goto_model, message_handlert &message_handler) +{ + remove_java_new( + goto_model.goto_functions, goto_model.symbol_table, message_handler); +} diff --git a/src/java_bytecode/remove_java_new.h b/src/java_bytecode/remove_java_new.h new file mode 100644 index 00000000000..a40b98b7607 --- /dev/null +++ b/src/java_bytecode/remove_java_new.h @@ -0,0 +1,40 @@ +/*******************************************************************\ + +Module: Remove Java New Operators + +Author: Peter Schrammel + +\*******************************************************************/ + +/// \file +/// Remove Java New Operators + +#ifndef CPROVER_JAVA_BYTECODE_REMOVE_JAVA_NEW_H +#define CPROVER_JAVA_BYTECODE_REMOVE_JAVA_NEW_H + +#include + +#include +#include + +class message_handlert; + +void remove_java_new( + goto_programt::targett target, + goto_programt &goto_program, + symbol_table_baset &symbol_table, + message_handlert &_message_handler); + +void remove_java_new( + goto_functionst::goto_functiont &function, + symbol_table_baset &symbol_table, + message_handlert &_message_handler); + +void remove_java_new( + goto_functionst &goto_functions, + symbol_table_baset &symbol_table, + message_handlert &_message_handler); + +void remove_java_new(goto_modelt &model, message_handlert &_message_handler); + +#endif // CPROVER_JAVA_BYTECODE_REMOVE_JAVA_NEW_H diff --git a/src/java_bytecode/replace_java_nondet.cpp b/src/java_bytecode/replace_java_nondet.cpp index 264de82328b..6d0e23210c1 100644 --- a/src/java_bytecode/replace_java_nondet.cpp +++ b/src/java_bytecode/replace_java_nondet.cpp @@ -249,9 +249,7 @@ static goto_programt::targett check_and_replace_target( "goto_program missing END_FUNCTION instruction"); std::for_each( - target, - after_matching_assignment, - [](goto_programt::instructiont &instr) { // NOLINT (*) + target, after_matching_assignment, [](goto_programt::instructiont &instr) { instr.make_skip(); }); diff --git a/src/jbmc/jbmc_parse_options.cpp b/src/jbmc/jbmc_parse_options.cpp index 0a80a382b94..9766aa399f1 100644 --- a/src/jbmc/jbmc_parse_options.cpp +++ b/src/jbmc/jbmc_parse_options.cpp @@ -53,8 +53,9 @@ Author: Daniel Kroening, kroening@kroening.com #include #include -#include #include +#include +#include #include #include @@ -493,13 +494,13 @@ int jbmc_parse_optionst::doit() std::function configure_bmc = nullptr; if(options.get_bool_option("java-unwind-enum-static")) { - configure_bmc = []( - bmct &bmc, const symbol_tablet &symbol_table) { // NOLINT (*) - bmc.add_loop_unwind_handler([&symbol_table]( - const irep_idt &function_id, - unsigned loop_number, - unsigned unwind, - unsigned &max_unwind) { // NOLINT (*) + configure_bmc = [](bmct &bmc, const symbol_tablet &symbol_table) { + bmc.add_loop_unwind_handler( + [&symbol_table]( + const irep_idt &function_id, + unsigned loop_number, + unsigned unwind, + unsigned &max_unwind) { return java_enum_static_init_unwind_handler( function_id, loop_number, @@ -564,7 +565,7 @@ int jbmc_parse_optionst::doit() // executes. If --paths is active, these dump routines run after every // paths iteration. Its return value indicates that if we ran any dump // function, then we should skip the actual solver phase. - auto callback_after_symex = [this, &lazy_goto_model]() { // NOLINT (*) + auto callback_after_symex = [this, &lazy_goto_model]() { return show_loaded_functions(lazy_goto_model); }; @@ -729,11 +730,10 @@ void jbmc_parse_optionst::process_goto_function( remove_exceptions_typest::REMOVE_ADDED_INSTANCEOF); } - auto function_is_stub = - [&symbol_table, &model](const irep_idt &id) { // NOLINT(*) - return symbol_table.lookup_ref(id).value.is_nil() && - !model.can_produce_function(id); - }; + auto function_is_stub = [&symbol_table, &model](const irep_idt &id) { + return symbol_table.lookup_ref(id).value.is_nil() && + !model.can_produce_function(id); + }; remove_returns(function, function_is_stub); @@ -764,6 +764,9 @@ void jbmc_parse_optionst::process_goto_function( // add generic checks goto_check(ns, options, ID_java, function.get_goto_function()); + // Replace Java new side effects + remove_java_new(goto_function, symbol_table, get_message_handler()); + // checks don't know about adjusted float expressions adjust_float_expressions(goto_function, ns); @@ -1047,6 +1050,7 @@ void jbmc_parse_optionst::help() JAVA_BYTECODE_LANGUAGE_OPTIONS_HELP // This one is handled by jbmc_parse_options not by the Java frontend, // hence its presence here: + " --java-threading enable experimental support for java multi-threading\n"// NOLINT(*) " --java-unwind-enum-static try to unwind loops in static initialization of enums\n" // NOLINT(*) // Currently only supported in the JBMC frontend: " --symex-driven-lazy-loading only load functions when first entered by symbolic execution\n" // NOLINT(*) diff --git a/src/jbmc/jbmc_parse_options.h b/src/jbmc/jbmc_parse_options.h index 32f7e269465..4bc76174737 100644 --- a/src/jbmc/jbmc_parse_options.h +++ b/src/jbmc/jbmc_parse_options.h @@ -74,6 +74,7 @@ class optionst; JAVA_BYTECODE_LANGUAGE_OPTIONS \ "(java-unwind-enum-static)" \ "(localize-faults)(localize-faults-method):" \ + "(java-threading)" \ OPT_GOTO_TRACE \ "(symex-driven-lazy-loading)" // clang-format on diff --git a/src/jsil/jsil_entry_point.cpp b/src/jsil/jsil_entry_point.cpp index 991ca1c226c..43f60bd1950 100644 --- a/src/jsil/jsil_entry_point.cpp +++ b/src/jsil/jsil_entry_point.cpp @@ -13,20 +13,17 @@ Author: Michael Tautschnig, tautschn@amazon.com #include #include -#include #include -#include -#include #include -#define INITIALIZE CPROVER_PREFIX "initialize" +#include static void create_initialize(symbol_tablet &symbol_table) { symbolt initialize; - initialize.name=CPROVER_PREFIX "initialize"; - initialize.base_name=CPROVER_PREFIX "initialize"; + initialize.name = INITIALIZE_FUNCTION; + initialize.base_name = INITIALIZE_FUNCTION; initialize.mode="jsil"; code_typet type; @@ -46,7 +43,7 @@ static void create_initialize(symbol_tablet &symbol_table) initialize.value=init_code; if(symbol_table.add(initialize)) - throw "failed to add " CPROVER_PREFIX "initialize"; + throw "failed to add " INITIALIZE_FUNCTION; } bool jsil_entry_point( @@ -130,10 +127,10 @@ bool jsil_entry_point( { symbol_tablet::symbolst::const_iterator init_it= - symbol_table.symbols.find(CPROVER_PREFIX "initialize"); + symbol_table.symbols.find(INITIALIZE_FUNCTION); if(init_it==symbol_table.symbols.end()) - throw "failed to find " CPROVER_PREFIX "initialize symbol"; + throw "failed to find " INITIALIZE_FUNCTION " symbol"; code_function_callt call_init; call_init.lhs().make_nil(); diff --git a/src/jsil/jsil_parse_tree.cpp b/src/jsil/jsil_parse_tree.cpp index 093a62f4fb9..8263b843c98 100644 --- a/src/jsil/jsil_parse_tree.cpp +++ b/src/jsil/jsil_parse_tree.cpp @@ -11,6 +11,8 @@ Author: Michael Tautschnig, tautschn@amazon.com #include "jsil_parse_tree.h" +#include + #include #include "jsil_types.h" diff --git a/src/jsil/jsil_parse_tree.h b/src/jsil/jsil_parse_tree.h index 55ee57de51b..f5410564783 100644 --- a/src/jsil/jsil_parse_tree.h +++ b/src/jsil/jsil_parse_tree.h @@ -12,7 +12,7 @@ Author: Michael Tautschnig, tautschn@amazon.com #ifndef CPROVER_JSIL_JSIL_PARSE_TREE_H #define CPROVER_JSIL_JSIL_PARSE_TREE_H -#include +#include #include #include diff --git a/src/jsil/jsil_types.cpp b/src/jsil/jsil_types.cpp index 12a76787149..ac2ff75c487 100644 --- a/src/jsil/jsil_types.cpp +++ b/src/jsil/jsil_types.cpp @@ -15,54 +15,38 @@ Author: Daiva Naudziuniene, daivan@amazon.com typet jsil_any_type() { - return jsil_union_typet({ // NOLINT(whitespace/braces) - jsil_empty_type(), - jsil_reference_type(), - jsil_value_type() - }); + return jsil_union_typet( + {jsil_empty_type(), jsil_reference_type(), jsil_value_type()}); } typet jsil_value_or_empty_type() { - return jsil_union_typet({ // NOLINT(whitespace/braces) - jsil_value_type(), - jsil_empty_type() - }); + return jsil_union_typet({jsil_value_type(), jsil_empty_type()}); } typet jsil_value_or_reference_type() { - return jsil_union_typet({ // NOLINT(whitespace/braces) - jsil_value_type(), - jsil_reference_type() - }); + return jsil_union_typet({jsil_value_type(), jsil_reference_type()}); } typet jsil_value_type() { - return jsil_union_typet({ // NOLINT(whitespace/braces) - jsil_undefined_type(), - jsil_null_type(), - jsil_prim_type(), - jsil_object_type() - }); + return jsil_union_typet( + {jsil_undefined_type(), + jsil_null_type(), + jsil_prim_type(), + jsil_object_type()}); } typet jsil_prim_type() { - return jsil_union_typet({ // NOLINT(whitespace/braces) - floatbv_typet(), - string_typet(), - bool_typet() - }); + return jsil_union_typet({floatbv_typet(), string_typet(), bool_typet()}); } typet jsil_reference_type() { - return jsil_union_typet({ // NOLINT(whitespace/braces) - jsil_member_reference_type(), - jsil_variable_reference_type() - }); + return jsil_union_typet( + {jsil_member_reference_type(), jsil_variable_reference_type()}); } typet jsil_member_reference_type() @@ -77,10 +61,8 @@ typet jsil_variable_reference_type() typet jsil_object_type() { - return jsil_union_typet({ // NOLINT(whitespace/braces) - jsil_user_object_type(), - jsil_builtin_object_type() - }); + return jsil_union_typet( + {jsil_user_object_type(), jsil_builtin_object_type()}); } typet jsil_user_object_type() diff --git a/src/langapi/language.h b/src/langapi/language.h index a3b6cbc0206..9e35daa17c9 100644 --- a/src/langapi/language.h +++ b/src/langapi/language.h @@ -114,21 +114,42 @@ class languaget:public messaget // conversion of expressions + /// Formats the given expression in a language-specific way + /// \param expr: the expression to format + /// \param code: the formatted expression + /// \param ns: a namespace + /// \return false if conversion succeeds virtual bool from_expr( const exprt &expr, std::string &code, const namespacet &ns); + /// Formats the given type in a language-specific way + /// \param type: the type to format + /// \param code: the formatted type + /// \param ns: a namespace + /// \return false if conversion succeeds virtual bool from_type( const typet &type, std::string &code, const namespacet &ns); + /// Encodes the given type in a language-specific way + /// \param type: the type to encode + /// \param name: the encoded type + /// \param ns: a namespace + /// \return false if the conversion succeeds virtual bool type_to_name( const typet &type, std::string &name, const namespacet &ns); + /// Parses the given string into an expression + /// \param code: the string to parse + /// \param module: prefix to be used for identifiers + /// \param expr: the parsed expression + /// \param ns: a namespace + /// \return false if the conversion succeeds virtual bool to_expr( const std::string &code, const std::string &module, diff --git a/src/langapi/language_util.cpp b/src/langapi/language_util.cpp index 7a2e691af38..87c51c9877f 100644 --- a/src/langapi/language_util.cpp +++ b/src/langapi/language_util.cpp @@ -17,32 +17,12 @@ Author: Daniel Kroening, kroening@cs.cmu.edu #include "language.h" #include "mode.h" -static std::unique_ptr get_language( - const namespacet &ns, - const irep_idt &identifier) -{ - const symbolt *symbol; - - if(identifier=="" || - ns.lookup(identifier, symbol) || - symbol->mode=="") - return get_default_language(); - - std::unique_ptr ptr=get_language_from_mode(symbol->mode); - - if(ptr==nullptr) - throw "symbol `"+id2string(symbol->name)+ - "' has unknown mode '"+id2string(symbol->mode)+"'"; - - return ptr; -} - std::string from_expr( const namespacet &ns, const irep_idt &identifier, const exprt &expr) { - std::unique_ptr p(get_language(ns, identifier)); + std::unique_ptr p(get_language_from_identifier(ns, identifier)); std::string result; p->from_expr(expr, result, ns); @@ -55,7 +35,7 @@ std::string from_type( const irep_idt &identifier, const typet &type) { - std::unique_ptr p(get_language(ns, identifier)); + std::unique_ptr p(get_language_from_identifier(ns, identifier)); std::string result; p->from_type(type, result, ns); @@ -68,7 +48,7 @@ std::string type_to_name( const irep_idt &identifier, const typet &type) { - std::unique_ptr p(get_language(ns, identifier)); + std::unique_ptr p(get_language_from_identifier(ns, identifier)); std::string result; p->type_to_name(type, result, ns); @@ -93,7 +73,7 @@ exprt to_expr( const irep_idt &identifier, const std::string &src) { - std::unique_ptr p(get_language(ns, identifier)); + std::unique_ptr p(get_language_from_identifier(ns, identifier)); null_message_handlert null_message_handler; p->set_message_handler(null_message_handler); diff --git a/src/langapi/mode.cpp b/src/langapi/mode.cpp index dd12882c544..d2bc2474189 100644 --- a/src/langapi/mode.cpp +++ b/src/langapi/mode.cpp @@ -18,6 +18,9 @@ Author: Daniel Kroening, kroening@cs.cmu.edu #include "language.h" +#include +#include + struct language_entryt { language_factoryt factory; @@ -28,6 +31,10 @@ struct language_entryt typedef std::list languagest; languagest languages; +/// Register a language +/// Note: registering a language is required for using the functions +/// in language_util.h +/// \param factory: a language factory, e.g. `new_ansi_c_language` void register_language(language_factoryt factory) { languages.push_back(language_entryt()); @@ -37,17 +44,60 @@ void register_language(language_factoryt factory) languages.back().mode=l->id(); } +/// Get the language corresponding to the given mode +/// \param mode: the mode, e.g. `ID_C` +/// \return the language or `nullptr` if the language has not been registered std::unique_ptr get_language_from_mode(const irep_idt &mode) { - for(languagest::const_iterator it=languages.begin(); - it!=languages.end(); - it++) - if(mode==it->mode) - return it->factory(); + for(const auto &language : languages) + if(mode == language.mode) + return language.factory(); return nullptr; } +/// Get the mode of the given identifier's symbol +/// \param ns: a namespace +/// \param identifier: an identifier +/// \return the mode, e.g. `ID_C`, if the identifier is in the given +/// symbol table, or `ID_unknown` otherwise +const irep_idt & +get_mode_from_identifier(const namespacet &ns, const irep_idt &identifier) +{ + if(identifier.empty()) + return ID_unknown; + const symbolt *symbol; + if(ns.lookup(identifier, symbol)) + return ID_unknown; + return symbol->mode; +} + +/// Get the language corresponding to the mode of the given identifier's symbol +/// \param ns: a namespace +/// \param identifier: an identifier +/// \return the corresponding language if the mode is not `ID_unknown`, or +/// the default language otherwise; +/// Note: It is assumed as an invariant that languages of symbols in the symbol +/// table have been registered. +std::unique_ptr +get_language_from_identifier(const namespacet &ns, const irep_idt &identifier) +{ + const irep_idt &mode = get_mode_from_identifier(ns, identifier); + if(mode == ID_unknown) + return get_default_language(); + + std::unique_ptr language = get_language_from_mode(mode); + INVARIANT( + language, + "symbol `" + id2string(identifier) + "' has unknown mode '" + + id2string(mode) + "'"); + return language; +} + +/// Get the language corresponding to the registered file name extensions +/// \param filename: a filename +/// \return the corresponding language or `nullptr` if the extension cannot +/// be resolved to any registered language std::unique_ptr get_language_from_filename( const std::string &filename) { @@ -83,8 +133,10 @@ std::unique_ptr get_language_from_filename( return nullptr; } +/// Returns the default language +/// \return the first registered language std::unique_ptr get_default_language() { - assert(!languages.empty()); + PRECONDITION(!languages.empty()); return languages.front().factory(); } diff --git a/src/langapi/mode.h b/src/langapi/mode.h index 3edb7a30be8..3223cf4a960 100644 --- a/src/langapi/mode.h +++ b/src/langapi/mode.h @@ -15,8 +15,13 @@ Author: Daniel Kroening, kroening@cs.cmu.edu #include // unique_ptr class languaget; +class namespacet; std::unique_ptr get_language_from_mode(const irep_idt &mode); +const irep_idt & +get_mode_from_identifier(const namespacet &ns, const irep_idt &identifier); +std::unique_ptr +get_language_from_identifier(const namespacet &ns, const irep_idt &identifier); std::unique_ptr get_language_from_filename( const std::string &filename); std::unique_ptr get_default_language(); diff --git a/src/linking/linking.cpp b/src/linking/linking.cpp index 5b5a1d36fd2..a93e0919e64 100644 --- a/src/linking/linking.cpp +++ b/src/linking/linking.cpp @@ -12,15 +12,13 @@ Author: Daniel Kroening, kroening@kroening.com #include "linking.h" #include -#include +#include +#include -#include -#include #include -#include -#include -#include +#include #include +#include #include diff --git a/src/linking/remove_internal_symbols.cpp b/src/linking/remove_internal_symbols.cpp index 11037431b66..d563278ff52 100644 --- a/src/linking/remove_internal_symbols.cpp +++ b/src/linking/remove_internal_symbols.cpp @@ -11,12 +11,13 @@ Author: Daniel Kroening #include "remove_internal_symbols.h" -#include -#include +#include #include +#include #include -#include -#include +#include + +#include "static_lifetime_init.h" void get_symbols_rec( const namespacet &ns, @@ -84,7 +85,7 @@ void remove_internal_symbols( special.insert("envp'"); special.insert("envp_size'"); special.insert(CPROVER_PREFIX "memory"); - special.insert(CPROVER_PREFIX "initialize"); + special.insert(INITIALIZE_FUNCTION); special.insert(CPROVER_PREFIX "malloc_size"); special.insert(CPROVER_PREFIX "deallocated"); special.insert(CPROVER_PREFIX "dead_object"); diff --git a/src/linking/static_lifetime_init.h b/src/linking/static_lifetime_init.h index 0955fc1f57c..829e2e16a05 100644 --- a/src/linking/static_lifetime_init.h +++ b/src/linking/static_lifetime_init.h @@ -10,11 +10,12 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_LINKING_STATIC_LIFETIME_INIT_H #define CPROVER_LINKING_STATIC_LIFETIME_INIT_H -#include -#include -#include #include +class message_handlert; +class source_locationt; +class symbol_tablet; + bool static_lifetime_init( symbol_tablet &symbol_table, const source_locationt &source_location, diff --git a/src/linking/zero_initializer.cpp b/src/linking/zero_initializer.cpp index 0916256ab5d..675cdb7dd7f 100644 --- a/src/linking/zero_initializer.cpp +++ b/src/linking/zero_initializer.cpp @@ -11,16 +11,13 @@ Author: Daniel Kroening, kroening@kroening.com #include "zero_initializer.h" -#include - -#include -#include #include -#include -#include +#include +#include +#include #include +#include -#include #include class zero_initializert:public messaget diff --git a/src/pointer-analysis/value_set.cpp b/src/pointer-analysis/value_set.cpp index 0e528f5760b..7cd08339d7a 100644 --- a/src/pointer-analysis/value_set.cpp +++ b/src/pointer-analysis/value_set.cpp @@ -14,17 +14,11 @@ Author: Daniel Kroening, kroening@kroening.com #include #include -#include -#include -#include -#include -#include -#include #include -#include -#include - +#include #include +#include +#include #include diff --git a/src/pointer-analysis/value_set_dereference.cpp b/src/pointer-analysis/value_set_dereference.cpp index 59a62f31cd6..8b2ed99baab 100644 --- a/src/pointer-analysis/value_set_dereference.cpp +++ b/src/pointer-analysis/value_set_dereference.cpp @@ -16,35 +16,23 @@ Author: Daniel Kroening, kroening@kroening.com #include #endif -#include -#include - -#include -#include -#include -#include -#include #include -#include #include +#include +#include +#include #include -#include #include -#include -#include +#include #include #include +#include #include -#include +#include #include -#include #include -#include - -#include "pointer_offset_sum.h" - // global data, horrible unsigned int value_set_dereferencet::invalid_counter=0; @@ -165,6 +153,7 @@ exprt value_set_dereferencet::dereference( symbol.name="symex::invalid_object"+std::to_string(invalid_counter++); symbol.base_name="invalid_object"; symbol.type=type; + symbol.mode = language_mode; // make it a lvalue, so we can assign to it symbol.is_lvalue=true; @@ -712,20 +701,6 @@ void value_set_dereferencet::bounds_check( } } -inline static unsigned bv_width( - const typet &type, - const namespacet &ns) -{ - if(type.id()==ID_c_enum_tag) - { - const typet &t=ns.follow_tag(to_c_enum_tag_type(type)); - assert(t.id()==ID_c_enum); - return bv_width(t.subtype(), ns); - } - - return unsafe_string2unsigned(type.get_string(ID_width)); -} - static bool is_a_bv_type(const typet &type) { return type.id()==ID_unsignedbv || @@ -752,7 +727,7 @@ bool value_set_dereferencet::memory_model( if(is_a_bv_type(from_type) && is_a_bv_type(to_type)) { - if(bv_width(from_type, ns)==bv_width(to_type, ns)) + if(pointer_offset_bits(from_type, ns) == pointer_offset_bits(to_type, ns)) { // avoid semantic conversion in case of // cast to float or fixed-point, @@ -772,7 +747,7 @@ bool value_set_dereferencet::memory_model( if(from_type.id()==ID_pointer && to_type.id()==ID_pointer) { - if(bv_width(from_type, ns)==bv_width(to_type, ns)) + if(pointer_offset_bits(from_type, ns) == pointer_offset_bits(to_type, ns)) return memory_model_conversion(value, to_type, guard, offset); } diff --git a/src/solvers/Makefile b/src/solvers/Makefile index 3d1a572eb36..b33a2a149e1 100644 --- a/src/solvers/Makefile +++ b/src/solvers/Makefile @@ -67,6 +67,13 @@ ifneq ($(LINGELING),) CP_CXXFLAGS += -DHAVE_LINGELING endif +ifneq ($(CADICAL),) + CADICAL_SRC=sat/satcheck_cadical.cpp + CADICAL_INCLUDE=-I $(CADICAL)/src + CADICAL_LIB=$(CADICAL)/build/libcadical$(LIBEXT) + CP_CXXFLAGS += -DHAVE_CADICAL +endif + SRC = $(BOOLEFORCE_SRC) \ $(CHAFF_SRC) \ $(CUDD_SRC) \ @@ -77,6 +84,7 @@ SRC = $(BOOLEFORCE_SRC) \ $(MINISAT_SRC) \ $(PICOSAT_SRC) \ $(SQUOLEM2_SRC) \ + $(CADICAL_SRC) \ cvc/cvc_conv.cpp \ cvc/cvc_dec.cpp \ flattening/arrays.cpp \ @@ -181,8 +189,6 @@ SRC = $(BOOLEFORCE_SRC) \ sat/pbs_dimacs_cnf.cpp \ sat/resolution_proof.cpp \ sat/satcheck.cpp \ - smt1/smt1_conv.cpp \ - smt1/smt1_dec.cpp \ smt2/smt2_conv.cpp \ smt2/smt2_dec.cpp \ smt2/smt2_parser.cpp \ @@ -194,7 +200,7 @@ INCLUDES += -I .. \ $(CHAFF_INCLUDE) $(BOOLEFORCE_INCLUDE) $(MINISAT_INCLUDE) $(MINISAT2_INCLUDE) \ $(IPASIR_INCLUDE) \ $(SQUOLEM2_INC) $(CUDD_INCLUDE) $(GLUCOSE_INCLUDE) \ - $(PICOSAT_INCLUDE) $(LINGELING_INCLUDE) + $(PICOSAT_INCLUDE) $(LINGELING_INCLUDE) $(CADICAL_INCLUDE) CLEANFILES += solvers$(LIBEXT) \ smt2_solver$(EXEEXT) smt2/smt2_solver$(OBJEXT) smt2/smt2_solver$(DEPEXT) @@ -211,7 +217,7 @@ endif SOLVER_LIB = $(CHAFF_LIB) $(BOOLEFORCE_LIB) $(MINISAT_LIB) \ $(MINISAT2_LIB) $(SQUOLEM2_LIB) $(CUDD_LIB) \ - $(PICOSAT_LIB) $(LINGELING_LIB) $(GLUCOSE_LIB) + $(PICOSAT_LIB) $(LINGELING_LIB) $(GLUCOSE_LIB) $(CADICAL_LIB) ############################################################################### diff --git a/src/solvers/flattening/boolbv.cpp b/src/solvers/flattening/boolbv.cpp index a61e50a0f33..40ddc83e3d6 100644 --- a/src/solvers/flattening/boolbv.cpp +++ b/src/solvers/flattening/boolbv.cpp @@ -152,6 +152,14 @@ bvt boolbvt::conversion_failed(const exprt &expr) return prop.new_variables(width); } +/// Converts an expression into its gate-level representation and returns a +/// vector of literals corresponding to the outputs of the Boolean circuit. +/// \param expr: Expression to convert +/// \return A vector of literals corresponding to the outputs of the Boolean +/// circuit +/// \throws bitvector_conversion_exceptiont raised if converting byte_extraction +/// goes wrong. +/// TODO: extend for other types of conversion exception (diffblue/cbmc#2103). bvt boolbvt::convert_bitvector(const exprt &expr) { if(expr.type().id()==ID_bool) diff --git a/src/solvers/flattening/boolbv_byte_extract.cpp b/src/solvers/flattening/boolbv_byte_extract.cpp index 0cc2c46bd89..f3841a6f0f3 100644 --- a/src/solvers/flattening/boolbv_byte_extract.cpp +++ b/src/solvers/flattening/boolbv_byte_extract.cpp @@ -11,10 +11,13 @@ Author: Daniel Kroening, kroening@kroening.com #include #include -#include #include #include +#include +#include +#include "bv_conversion_exceptions.h" +#include "flatten_byte_extract_exceptions.h" #include "flatten_byte_operators.h" bvt map_bv(const endianness_mapt &map, const bvt &src) @@ -42,8 +45,16 @@ bvt boolbvt::convert_byte_extract(const byte_extract_exprt &expr) // if we extract from an unbounded array, call the flattening code if(is_unbounded_array(expr.op().type())) { - exprt tmp=flatten_byte_extract(expr, ns); - return convert_bv(tmp); + try + { + exprt tmp = flatten_byte_extract(expr, ns); + return convert_bv(tmp); + } + catch(const flatten_byte_extract_exceptiont &byte_extract_flatten_exception) + { + util_throw_with_nested( + bitvector_conversion_exceptiont("Can't convert byte_extraction", expr)); + } } std::size_t width=boolbv_width(expr.type()); diff --git a/src/solvers/flattening/boolbv_update.cpp b/src/solvers/flattening/boolbv_update.cpp index f5121f8bf91..668b8cc8fdc 100644 --- a/src/solvers/flattening/boolbv_update.cpp +++ b/src/solvers/flattening/boolbv_update.cpp @@ -8,13 +8,7 @@ Author: Daniel Kroening, kroening@kroening.com #include "boolbv.h" -#include -#include #include -#include -#include - -#include bvt boolbvt::convert_update(const exprt &expr) { diff --git a/src/solvers/flattening/bv_conversion_exceptions.h b/src/solvers/flattening/bv_conversion_exceptions.h new file mode 100644 index 00000000000..2d3bbd2410b --- /dev/null +++ b/src/solvers/flattening/bv_conversion_exceptions.h @@ -0,0 +1,34 @@ +/*******************************************************************\ + +Module: Bit vector conversion + +Author: Diffblue Ltd. + +\*******************************************************************/ + +/// \file +/// Exceptions that can be raised in bv_conversion + +#ifndef CPROVER_SOLVERS_FLATTENING_BV_CONVERSION_EXCEPTIONS_H +#define CPROVER_SOLVERS_FLATTENING_BV_CONVERSION_EXCEPTIONS_H + +#include +#include + +#include + +class bitvector_conversion_exceptiont : public std::runtime_error +{ +public: + bitvector_conversion_exceptiont( + const std::string &exception_message, + const exprt &bv_expr) + : runtime_error(exception_message), bv_expr(bv_expr) + { + } + +private: + exprt bv_expr; +}; + +#endif // CPROVER_SOLVERS_FLATTENING_BV_CONVERSION_EXCEPTIONS_H diff --git a/src/solvers/flattening/bv_pointers.cpp b/src/solvers/flattening/bv_pointers.cpp index 5833a3e4549..7043938eccf 100644 --- a/src/solvers/flattening/bv_pointers.cpp +++ b/src/solvers/flattening/bv_pointers.cpp @@ -8,14 +8,10 @@ Author: Daniel Kroening, kroening@kroening.com #include "bv_pointers.h" +#include #include #include -#include -#include -#include -#include #include -#include literalt bv_pointerst::convert_rest(const exprt &expr) { @@ -136,7 +132,7 @@ bool bv_pointerst::convert_address_of_rec( { // this should be gone bv=convert_pointer_type(array); - POSTCONDITION(bv.size()==bits); + CHECK_RETURN(bv.size()==bits); } else if(array_type.id()==ID_array || array_type.id()==ID_incomplete_array || @@ -144,7 +140,7 @@ bool bv_pointerst::convert_address_of_rec( { if(convert_address_of_rec(array, bv)) return true; - POSTCONDITION(bv.size()==bits); + CHECK_RETURN(bv.size()==bits); } else UNREACHABLE; @@ -155,7 +151,22 @@ bool bv_pointerst::convert_address_of_rec( DATA_INVARIANT(size>0, "array subtype expected to have non-zero size"); offset_arithmetic(bv, size, index); - POSTCONDITION(bv.size()==bits); + CHECK_RETURN(bv.size()==bits); + return false; + } + else if(expr.id()==ID_byte_extract_little_endian || + expr.id()==ID_byte_extract_big_endian) + { + const auto &byte_extract_expr=to_byte_extract_expr(expr); + + // recursive call + if(convert_address_of_rec(byte_extract_expr.op(), bv)) + return true; + + CHECK_RETURN(bv.size()==bits); + + offset_arithmetic(bv, 1, byte_extract_expr.offset()); + CHECK_RETURN(bv.size()==bits); return false; } else if(expr.id()==ID_member) @@ -296,7 +307,7 @@ bvt bv_pointerst::convert_pointer_type(const exprt &expr) return bv; } - POSTCONDITION(bv.size()==bits); + CHECK_RETURN(bv.size()==bits); return bv; } else if(expr.id()==ID_constant) @@ -334,13 +345,13 @@ bvt bv_pointerst::convert_pointer_type(const exprt &expr) { count++; bv=convert_bv(*it); - POSTCONDITION(bv.size()==bits); + CHECK_RETURN(bv.size()==bits); typet pointer_sub_type=it->type().subtype(); if(pointer_sub_type.id()==ID_empty) pointer_sub_type=char_type(); size=pointer_offset_size(pointer_sub_type, ns); - POSTCONDITION(size>0); + CHECK_RETURN(size>0); } } diff --git a/src/solvers/flattening/flatten_byte_extract_exceptions.h b/src/solvers/flattening/flatten_byte_extract_exceptions.h new file mode 100644 index 00000000000..a5ae22791b3 --- /dev/null +++ b/src/solvers/flattening/flatten_byte_extract_exceptions.h @@ -0,0 +1,144 @@ +/*******************************************************************\ + +Module: Byte flattening + +Author: Diffblue Ltd. + +\*******************************************************************/ + +#ifndef CPROVER_SOLVERS_FLATTENING_FLATTEN_BYTE_EXTRACT_EXCEPTIONS_H +#define CPROVER_SOLVERS_FLATTENING_FLATTEN_BYTE_EXTRACT_EXCEPTIONS_H + +#include +#include +#include + +#include +#include + +class flatten_byte_extract_exceptiont : public std::runtime_error +{ +public: + explicit flatten_byte_extract_exceptiont(const std::string &exception_message) + : runtime_error(exception_message) + { + } +}; + +class non_const_array_sizet : public flatten_byte_extract_exceptiont +{ +public: + non_const_array_sizet(const array_typet &array_type, const exprt &max_bytes) + : flatten_byte_extract_exceptiont("cannot unpack array of non-const size"), + max_bytes(max_bytes), + array_type(array_type) + { + std::ostringstream error_message; + error_message << runtime_error::what() << "\n"; + error_message << "array_type: " << array_type.pretty(); + error_message << "\nmax_bytes: " << max_bytes.pretty(); + computed_error_message = error_message.str(); + } + + const char *what() const optional_noexcept override + { + return computed_error_message.c_str(); + } + +private: + exprt max_bytes; + array_typet array_type; + + std::string computed_error_message; +}; + +class non_byte_alignedt : public flatten_byte_extract_exceptiont +{ +public: + non_byte_alignedt( + const struct_typet &struct_type, + const struct_union_typet::componentt &component, + const mp_integer &byte_width) + : flatten_byte_extract_exceptiont( + "cannot unpack struct with non-byte aligned components"), + struct_type(struct_type), + component(component), + byte_width(byte_width) + { + std::ostringstream error_message; + error_message << runtime_error::what() << "\n"; + error_message << "width: " << byte_width << "\n"; + error_message << "component:" << component.get_name() << "\n"; + error_message << "struct_type: " << struct_type.pretty(); + computed_error_message = error_message.str(); + } + + const char *what() const optional_noexcept override + { + return computed_error_message.c_str(); + } + +private: + const struct_typet struct_type; + const struct_union_typet::componentt component; + const mp_integer byte_width; + + std::string computed_error_message; +}; + +class non_constant_widtht : public flatten_byte_extract_exceptiont +{ +public: +public: + non_constant_widtht(const exprt &src, const exprt &max_bytes) + : flatten_byte_extract_exceptiont( + "cannot unpack object of non-constant width"), + src(src), + max_bytes(max_bytes) + { + std::ostringstream error_message; + error_message << runtime_error::what() << "\n"; + error_message << "array_type: " << src.pretty(); + error_message << "\nmax_bytes: " << max_bytes.pretty(); + computed_error_message = error_message.str(); + } + + const char *what() const optional_noexcept override + { + return computed_error_message.c_str(); + } + +private: + exprt src; + exprt max_bytes; + + std::string computed_error_message; +}; + +class non_const_byte_extraction_sizet : public flatten_byte_extract_exceptiont +{ +public: + explicit non_const_byte_extraction_sizet( + const byte_extract_exprt &unpack_expr) + : flatten_byte_extract_exceptiont( + "byte_extract flatting with non-constant size"), + unpack_expr(unpack_expr) + { + std::ostringstream error_message; + error_message << runtime_error::what() << "\n"; + error_message << "unpack_expr: " << unpack_expr.pretty(); + computed_error_message = error_message.str(); + } + + const char *what() const optional_noexcept override + { + return computed_error_message.c_str(); + } + +private: + const byte_extract_exprt unpack_expr; + + std::string computed_error_message; +}; + +#endif // CPROVER_SOLVERS_FLATTENING_FLATTEN_BYTE_EXTRACT_EXCEPTIONS_H diff --git a/src/solvers/flattening/flatten_byte_operators.cpp b/src/solvers/flattening/flatten_byte_operators.cpp index c564b48df02..2cc586c7c02 100644 --- a/src/solvers/flattening/flatten_byte_operators.cpp +++ b/src/solvers/flattening/flatten_byte_operators.cpp @@ -6,18 +6,17 @@ Author: Daniel Kroening, kroening@kroening.com \*******************************************************************/ -#include -#include -#include -#include +#include "flatten_byte_operators.h" + #include -#include #include +#include #include +#include #include #include -#include "flatten_byte_operators.h" +#include "flatten_byte_extract_exceptions.h" /// rewrite an object into its individual bytes /// \par parameters: src object to unpack @@ -25,6 +24,9 @@ Author: Daniel Kroening, kroening@kroening.com /// max_bytes if not nil, use as upper bound of the number of bytes to unpack /// ns namespace for type lookups /// \return array of bytes in the sequence found in memory +/// \throws flatten_byte_extract_exceptiont Raised is unable to unpack the +/// object because of either non constant size, byte misalignment or +/// non-constant component width. static exprt unpack_rec( const exprt &src, bool little_endian, @@ -63,7 +65,9 @@ static exprt unpack_rec( mp_integer num_elements; if(to_integer(max_bytes, num_elements) && to_integer(array_type.size(), num_elements)) - throw "cannot unpack array of non-const size:\n"+type.pretty(); + { + throw non_const_array_sizet(array_type, max_bytes); + } // all array members will have the same structure; do this just // once and then replace the dummy symbol by a suitable index @@ -97,8 +101,9 @@ static exprt unpack_rec( // the next member would be misaligned, abort if(element_width<=0 || element_width%8!=0) - throw "cannot unpack struct with non-byte aligned components:\n"+ - struct_type.pretty(); + { + throw non_byte_alignedt(struct_type, comp, element_width); + } member_exprt member(src, comp.get_name(), comp.type()); exprt sub=unpack_rec(member, little_endian, max_bytes, ns, true); @@ -115,8 +120,9 @@ static exprt unpack_rec( if(bits<0) { if(to_integer(max_bytes, bits)) - throw "cannot unpack object of non-constant width:\n"+ - src.pretty(); + { + throw non_constant_widtht(src, max_bytes); + } else bits*=8; } @@ -300,8 +306,9 @@ exprt flatten_byte_extract( { mp_integer op0_bits=pointer_offset_bits(unpacked.op().type(), ns); if(op0_bits<0) - throw "byte_extract flatting with non-constant size:\n"+ - unpacked.pretty(); + { + throw non_const_byte_extraction_sizet(unpacked); + } else size_bits=op0_bits; } diff --git a/src/solvers/flattening/pointer_logic.cpp b/src/solvers/flattening/pointer_logic.cpp index 5bbbad458f2..d0a2a866903 100644 --- a/src/solvers/flattening/pointer_logic.cpp +++ b/src/solvers/flattening/pointer_logic.cpp @@ -15,9 +15,10 @@ Author: Daniel Kroening, kroening@kroening.com #include #include -#include -#include +#include #include +#include +#include bool pointer_logict::is_dynamic_object(const exprt &expr) const { diff --git a/src/solvers/refinement/string_constraint_generator.h b/src/solvers/refinement/string_constraint_generator.h index 0beb04b766f..5a921d11adc 100644 --- a/src/solvers/refinement/string_constraint_generator.h +++ b/src/solvers/refinement/string_constraint_generator.h @@ -94,14 +94,7 @@ class string_constraint_generatort final // Used by format function class format_specifiert; - /// Arguments pack for the string_constraint_generator constructor - struct infot - { - /// Max length of non-deterministic strings - size_t string_max_length=std::numeric_limits::max(); - }; - - string_constraint_generatort(const infot& info, const namespacet& ns); + explicit string_constraint_generatort(const namespacet &ns); /// Axioms are of three kinds: universally quantified string constraint, /// not contains string constraints and simple formulas. @@ -181,10 +174,9 @@ class string_constraint_generatort final static constant_exprt constant_char(int i, const typet &char_type); - array_string_exprt + const array_string_exprt & char_array_of_pointer(const exprt &pointer, const exprt &length); - void add_default_axioms(const array_string_exprt &s); exprt axiom_for_is_positive_index(const exprt &x); void add_constraint_on_characters( @@ -402,7 +394,6 @@ class string_constraint_generatort final // MEMBERS public: - const size_t max_string_length; // Used to store information about witnesses for not_contains constraints std::map witness; private: diff --git a/src/solvers/refinement/string_constraint_generator_main.cpp b/src/solvers/refinement/string_constraint_generator_main.cpp index 72cb6a97120..3b3dc66c846 100644 --- a/src/solvers/refinement/string_constraint_generator_main.cpp +++ b/src/solvers/refinement/string_constraint_generator_main.cpp @@ -28,10 +28,8 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com #include #include -string_constraint_generatort::string_constraint_generatort( - const string_constraint_generatort::infot &info, - const namespacet &ns) - : array_pool(fresh_symbol), max_string_length(info.string_max_length), ns(ns) +string_constraint_generatort::string_constraint_generatort(const namespacet &ns) + : array_pool(fresh_symbol), ns(ns) { } @@ -172,7 +170,6 @@ array_string_exprt string_constraint_generatort::fresh_string( symbol_exprt content = fresh_symbol("string_content", array_type); array_string_exprt str = to_array_string_expr(content); created_strings.insert(str); - add_default_axioms(str); return str; } @@ -279,7 +276,7 @@ exprt string_constraint_generatort::associate_array_to_pointer( const exprt &pointer_expr = f.arguments()[1]; array_pool.insert(pointer_expr, array_expr); - add_default_axioms(to_array_string_expr(array_expr)); + created_strings.emplace(to_array_string_expr(array_expr)); return from_integer(0, f.type()); } @@ -319,27 +316,6 @@ void string_constraint_generatort::clear_constraints() not_contains_constraints.clear(); } -/// 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 '~' -/// \param s: a string expression -/// \return a string expression that is linked to the argument through axioms -/// that are added to the list -void string_constraint_generatort::add_default_axioms( - const array_string_exprt &s) -{ - // If `s` was already added we do nothing. - if(!created_strings.insert(s).second) - return; - - const exprt index_zero = from_integer(0, s.length().type()); - lemmas.push_back(s.axiom_for_length_ge(index_zero)); - - if(max_string_length!=std::numeric_limits::max()) - lemmas.push_back(s.axiom_for_length_le(max_string_length)); -} - /// Add constraint on characters of a string. /// /// This constraint is @@ -409,14 +385,13 @@ array_string_exprt array_poolt::find(const exprt &pointer, const exprt &length) } /// Adds creates a new array if it does not already exists -/// \todo This should be replaced by associate_char_array_to_char_pointer -array_string_exprt string_constraint_generatort::char_array_of_pointer( +/// \todo This should be replaced +/// by array_poolt.make_char_array_for_char_pointer +const array_string_exprt &string_constraint_generatort::char_array_of_pointer( const exprt &pointer, const exprt &length) { - const array_string_exprt array = array_pool.find(pointer, length); - add_default_axioms(array); - return array; + return *created_strings.insert(array_pool.find(pointer, length)).first; } array_string_exprt array_poolt::find(const refined_string_exprt &str) diff --git a/src/solvers/refinement/string_constraint_generator_transformation.cpp b/src/solvers/refinement/string_constraint_generator_transformation.cpp index 154e027a5ef..effcef775e6 100644 --- a/src/solvers/refinement/string_constraint_generator_transformation.cpp +++ b/src/solvers/refinement/string_constraint_generator_transformation.cpp @@ -128,7 +128,7 @@ exprt string_constraint_generatort::add_axioms_for_substring( lemmas.push_back(equal_exprt(res.length(), minus_exprt(end1, start1))); // Axiom 2. - constraints.push_back([&] { // NOLINT + constraints.push_back([&] { const symbol_exprt idx = fresh_univ_index("QA_index_substring", index_type); return string_constraintt( idx, res.length(), equal_exprt(res[idx], str[plus_exprt(start1, idx)])); @@ -197,7 +197,7 @@ exprt string_constraint_generatort::add_axioms_for_trim( constraints.push_back(a6); // Axiom 7. - constraints.push_back([&] { // NOLINT + constraints.push_back([&] { const symbol_exprt n2 = fresh_univ_index("QA_index_trim2", index_type); const minus_exprt bound(minus_exprt(str.length(), idx), res.length()); const binary_relation_exprt eqn2( @@ -473,7 +473,7 @@ exprt string_constraint_generatort::add_axioms_for_replace( char_array_of_pointer(f.arguments()[1], f.arguments()[0]); if( const auto maybe_chars = - to_char_pair(f.arguments()[3], f.arguments()[4], [this](const exprt &e) { // NOLINT + to_char_pair(f.arguments()[3], f.arguments()[4], [this](const exprt &e) { return get_string_expr(e); })) { diff --git a/src/solvers/refinement/string_refinement.cpp b/src/solvers/refinement/string_refinement.cpp index c2685dc6202..4fe87dfc7cb 100644 --- a/src/solvers/refinement/string_refinement.cpp +++ b/src/solvers/refinement/string_refinement.cpp @@ -28,6 +28,7 @@ Author: Alberto Griggio, alberto.griggio@gmail.com #include #include #include +#include static bool is_valid_string_constraint( messaget::mstreamt &stream, @@ -166,11 +167,14 @@ static bool validate(const string_refinementt::infot &info) return true; } -string_refinementt::string_refinementt(const infot &info, bool): - supert(info), - config_(info), - loop_bound_(info.refinement_bound), - generator(info, *info.ns) { } +string_refinementt::string_refinementt(const infot &info, bool) + : supert(info), + config_(info), + loop_bound_(info.refinement_bound), + max_string_length(info.max_string_length), + generator(*info.ns) +{ +} string_refinementt::string_refinementt(const infot &info): string_refinementt(info, validate(info)) { } @@ -692,7 +696,7 @@ decision_proceduret::resultt string_refinementt::dec_solve() constraints.begin(), constraints.end(), std::back_inserter(axioms.universal), - [&](string_constraintt constraint) { // NOLINT + [&](string_constraintt constraint) { symbol_resolve.replace_expr(constraint); DATA_INVARIANT( is_valid_string_constraint(error(), ns, constraint), @@ -707,14 +711,14 @@ decision_proceduret::resultt string_refinementt::dec_solve() not_contains_constraints.begin(), not_contains_constraints.end(), std::back_inserter(axioms.not_contains), - [&](string_not_contains_constraintt axiom) { // NOLINT + [&](string_not_contains_constraintt axiom) { symbol_resolve.replace_expr(axiom); return axiom; }); for(const auto &nc_axiom : axioms.not_contains) { - const auto &witness_type = [&] { // NOLINT + const auto &witness_type = [&] { const auto &rtype = to_array_type(nc_axiom.s0().type()); const typet &index_type = rtype.size().type(); return array_typet(index_type, infinity_exprt(index_type)); @@ -723,11 +727,8 @@ decision_proceduret::resultt string_refinementt::dec_solve() generator.fresh_symbol("not_contains_witness", witness_type); } - for(exprt lemma : generator.get_lemmas()) - { - symbol_resolve.replace_expr(lemma); + for(const exprt &lemma : generator.get_lemmas()) add_lemma(lemma); - } // Initial try without index set const auto get = [this](const exprt &expr) { return this->get(expr); }; @@ -737,13 +738,13 @@ decision_proceduret::resultt string_refinementt::dec_solve() { bool satisfied; std::vector counter_examples; - std::tie(satisfied, counter_examples)=check_axioms( + std::tie(satisfied, counter_examples) = check_axioms( axioms, generator, get, debug(), ns, - generator.max_string_length, + max_string_length, config_.use_counter_example, supert::config_.ui, symbol_resolve); @@ -781,13 +782,13 @@ decision_proceduret::resultt string_refinementt::dec_solve() { bool satisfied; std::vector counter_examples; - std::tie(satisfied, counter_examples)=check_axioms( + std::tie(satisfied, counter_examples) = check_axioms( axioms, generator, get, debug(), ns, - generator.max_string_length, + max_string_length, config_.use_counter_example, supert::config_.ui, symbol_resolve); @@ -936,12 +937,17 @@ static optionalt get_array( if(n > MAX_CONCRETE_STRING_SIZE) { - stream << "(sr::get_array) long string (size=" << n << ")" << eom; - std::ostringstream msg; - msg << "consider reducing string-max-input-length so that no string " - << "exceeds " << MAX_CONCRETE_STRING_SIZE << " in length and make sure" - << " all functions returning strings are available in the classpath"; - throw string_refinement_invariantt(msg.str()); + stream << "(sr::get_array) long string (size " << format(arr.length()) + << " = " << n << ") " << format(arr) << eom; + stream << "(sr::get_array) consider reducing string-max-input-length so " + "that no string exceeds " + << MAX_CONCRETE_STRING_SIZE + << " in length and " + "make sure all functions returning strings are loaded" + << eom; + stream << "(sr::get_array) this can also happen on invalid object access" + << eom; + return nil_exprt(); } if( @@ -1121,9 +1127,6 @@ static exprt substitute_array_access( const bool left_propagate) { const exprt &array = index_expr.array(); - - if(array.id() == ID_symbol) - return index_expr; if(auto array_of = expr_try_dynamic_cast(array)) return array_of->op(); if(auto array_with = expr_try_dynamic_cast(array)) @@ -1136,7 +1139,12 @@ static exprt substitute_array_access( return substitute_array_access( *if_expr, index_expr.index(), symbol_generator, left_propagate); - UNREACHABLE; + INVARIANT( + array.is_nil() || array.id() == ID_symbol, + std::string( + "in case the array is unknown, it should be a symbol or nil, id: ") + + id2string(array.id())); + return index_expr; } /// Auxiliary function for substitute_array_access @@ -1920,7 +1928,7 @@ static void update_index_set( static optionalt find_index(const exprt &expr, const exprt &str, const symbol_exprt &qvar) { - auto index_str_containing_qvar = [&](const exprt &e) { // NOLINT + auto index_str_containing_qvar = [&](const exprt &e) { if(auto index_expr = expr_try_dynamic_cast(e)) { const auto &arr = index_expr->array(); @@ -2119,9 +2127,11 @@ exprt string_refinementt::get(const exprt &expr) const } INVARIANT( - array.id() == ID_symbol, - "apart from symbols, array valuations can be interpreted as sparse " - "arrays"); + array.is_nil() || array.id() == ID_symbol, + std::string( + "apart from symbols, array valuations can be interpreted as " + "sparse arrays, id: ") + + id2string(array.id())); return index_exprt(array, index); } @@ -2137,7 +2147,7 @@ exprt string_refinementt::get(const exprt &expr) const if( const auto arr_model_opt = - get_array(super_get, ns, generator.max_string_length, debug(), arr)) + get_array(super_get, ns, max_string_length, debug(), arr)) return *arr_model_opt; if(generator.get_created_strings().count(arr)) @@ -2171,14 +2181,7 @@ static optionalt find_counter_example( const symbol_exprt &var) { satcheck_no_simplifiert sat_check; - bv_refinementt::infot info; - info.ns=&ns; - info.prop=&sat_check; - info.refine_arithmetic=true; - info.refine_arrays=true; - info.max_node_refinement=5; - info.ui=ui; - bv_refinementt solver(info); + boolbvt solver(ns, sat_check); solver << axiom; if(solver()==decision_proceduret::resultt::D_SATISFIABLE) diff --git a/src/solvers/refinement/string_refinement.h b/src/solvers/refinement/string_refinement.h index 0fd5dbc8f5a..ec7892838ed 100644 --- a/src/solvers/refinement/string_refinement.h +++ b/src/solvers/refinement/string_refinement.h @@ -31,8 +31,6 @@ Author: Alberto Griggio, alberto.griggio@gmail.com #define DEFAULT_MAX_NB_REFINEMENT std::numeric_limits::max() #define CHARACTER_FOR_UNKNOWN '?' -// Limit the size of strings in traces to 64M chars to avoid memout -#define MAX_CONCRETE_STRING_SIZE (1 << 26) class string_refinementt final: public bv_refinementt { @@ -43,11 +41,11 @@ class string_refinementt final: public bv_refinementt /// Concretize strings after solver is finished bool trace=false; bool use_counter_example=true; + std::size_t max_string_length; }; public: /// string_refinementt constructor arguments struct infot : public bv_refinementt::infot, - public string_constraint_generatort::infot, public configt { }; @@ -69,6 +67,7 @@ class string_refinementt final: public bv_refinementt const configt config_; std::size_t loop_bound_; + std::size_t max_string_length; string_constraint_generatort generator; // Simple constraints that have been given to the solver diff --git a/src/solvers/sat/satcheck.h b/src/solvers/sat/satcheck.h index 6896be55da4..c7175fa414c 100644 --- a/src/solvers/sat/satcheck.h +++ b/src/solvers/sat/satcheck.h @@ -21,6 +21,7 @@ Author: Daniel Kroening, kroening@kroening.com // #define SATCHECK_BOOLEFORCE // #define SATCHECK_PICOSAT // #define SATCHECK_LINGELING +// #define SATCHECK_CADICAL #if defined(HAVE_IPASIR) && !defined(SATCHECK_IPASIR) #define SATCHECK_IPASIR @@ -54,6 +55,10 @@ Author: Daniel Kroening, kroening@kroening.com #define SATCHECK_LINGELING #endif +#if defined(HAVE_CADICAL) && !defined(SATCHECK_CADICAL) +#define SATCHECK_CADICAL +#endif + #if defined SATCHECK_ZCHAFF #include "satcheck_zchaff.h" @@ -110,6 +115,13 @@ typedef satcheck_lingelingt satcheck_no_simplifiert; typedef satcheck_glucose_simplifiert satcheckt; typedef satcheck_glucose_no_simplifiert satcheck_no_simplifiert; +#elif defined SATCHECK_CADICAL + +#include "satcheck_cadical.h" + +typedef satcheck_cadicalt satcheckt; +typedef satcheck_cadicalt satcheck_no_simplifiert; + #endif #endif // CPROVER_SOLVERS_SAT_SATCHECK_H diff --git a/src/solvers/sat/satcheck_cadical.cpp b/src/solvers/sat/satcheck_cadical.cpp new file mode 100644 index 00000000000..a92a815ffc7 --- /dev/null +++ b/src/solvers/sat/satcheck_cadical.cpp @@ -0,0 +1,129 @@ +/*******************************************************************\ + +Module: + +Author: Michael Tautschnig + +\*******************************************************************/ + +#include "satcheck_cadical.h" + +#include +#include + +#ifdef HAVE_CADICAL + +#include + +tvt satcheck_cadicalt::l_get(literalt a) const +{ + if(a.is_constant()) + return tvt(a.sign()); + + tvt result; + + if(a.var_no() > static_cast(solver->max())) + return tvt(tvt::tv_enumt::TV_UNKNOWN); + + const int val = solver->val(a.dimacs()); + if(val>0) + result = tvt(true); + else if(val<0) + result = tvt(false); + else + return tvt(tvt::tv_enumt::TV_UNKNOWN); + + return result; +} + +const std::string satcheck_cadicalt::solver_text() +{ + return std::string("CaDiCaL ") + solver->version(); +} + +void satcheck_cadicalt::lcnf(const bvt &bv) +{ + for(const auto &lit : bv) + { + if(lit.is_true()) + return; + else if(!lit.is_false()) + INVARIANT(lit.var_no() < no_variables(), "reject out of bound variables"); + } + + for(const auto &lit : bv) + { + if(!lit.is_false()) + { + // add literal with correct sign + solver->add(lit.dimacs()); + } + } + solver->add(0); // terminate clause + + clause_counter++; +} + +propt::resultt satcheck_cadicalt::prop_solve() +{ + INVARIANT(status != statust::ERROR, "there cannot be an error"); + + messaget::status() << (no_variables() - 1) << " variables, " << clause_counter + << " clauses" << eom; + + if(status == statust::UNSAT) + { + messaget::status() << "SAT checker inconsistent: instance is UNSATISFIABLE" + << eom; + } + else + { + switch(solver->solve()) + { + case 10: + messaget::status() << "SAT checker: instance is SATISFIABLE" << eom; + status = statust::SAT; + return resultt::P_SATISFIABLE; + case 20: + messaget::status() << "SAT checker: instance is UNSATISFIABLE" << eom; + break; + default: + messaget::status() << "SAT checker: solving returned without solution" + << eom; + throw "solving inside CaDiCaL SAT solver has been interrupted"; + } + } + + status = statust::UNSAT; + return resultt::P_UNSATISFIABLE; +} + +void satcheck_cadicalt::set_assignment(literalt a, bool value) +{ + INVARIANT(!a.is_constant(), "cannot set an assignment for a constant"); + INVARIANT(false, "method not supported"); +} + +satcheck_cadicalt::satcheck_cadicalt() : + solver(new CaDiCaL::Solver()) +{ + solver->set("quiet", 1); +} + +satcheck_cadicalt::~satcheck_cadicalt() +{ + delete solver; +} + +void satcheck_cadicalt::set_assumptions(const bvt &bv) +{ + INVARIANT(false, "method not supported"); +} + +bool satcheck_cadicalt::is_in_conflict(literalt a) const +{ + INVARIANT(false, "method not supported"); + return false; +} + +#endif diff --git a/src/solvers/sat/satcheck_cadical.h b/src/solvers/sat/satcheck_cadical.h new file mode 100644 index 00000000000..763b2e3f150 --- /dev/null +++ b/src/solvers/sat/satcheck_cadical.h @@ -0,0 +1,43 @@ +/*******************************************************************\ + +Module: + +Author: Michael Tautschnig + +\*******************************************************************/ + + +#ifndef CPROVER_SOLVERS_SAT_SATCHECK_CADICAL_H +#define CPROVER_SOLVERS_SAT_SATCHECK_CADICAL_H + +#include "cnf.h" + +namespace CaDiCaL // NOLINT(readability/namespace) +{ + class Solver; // NOLINT(readability/identifiers) +} + +class satcheck_cadicalt:public cnf_solvert +{ +public: + satcheck_cadicalt(); + virtual ~satcheck_cadicalt(); + + virtual const std::string solver_text() override; + virtual resultt prop_solve() override; + virtual tvt l_get(literalt a) const override; + + virtual void lcnf(const bvt &bv) override; + virtual void set_assignment(literalt a, bool value) override; + + virtual void set_assumptions(const bvt &_assumptions) override; + virtual bool has_set_assumptions() const override { return false; } + virtual bool has_is_in_conflict() const override { return false; } + virtual bool is_in_conflict(literalt a) const override; + +protected: + // NOLINTNEXTLINE(readability/identifiers) + CaDiCaL::Solver * solver; +}; + +#endif // CPROVER_SOLVERS_SAT_SATCHECK_CADICAL_H diff --git a/src/solvers/smt1/smt1_conv.cpp b/src/solvers/smt1/smt1_conv.cpp deleted file mode 100644 index 39c2e3f2e20..00000000000 --- a/src/solvers/smt1/smt1_conv.cpp +++ /dev/null @@ -1,3215 +0,0 @@ -/*******************************************************************\ - -Module: SMT Version 1 Backend - -Author: Daniel Kroening, kroening@kroening.com - -\*******************************************************************/ - -/// \file -/// SMT Version 1 Backend - -#include "smt1_conv.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -void smt1_convt::print_assignment(std::ostream &out) const -{ - // Boolean stuff - - for(std::size_t v=0; vsecond.value; - } - else if(expr.id()==ID_member) - { - const member_exprt &member_expr=to_member_expr(expr); - exprt tmp=get(member_expr.struct_op()); - if(tmp.is_nil()) - return nil_exprt(); - return member_exprt(tmp, member_expr.get_component_name(), expr.type()); - } - else if(expr.id()==ID_index) - { - const index_exprt &index_expr=to_index_expr(expr); - exprt tmp_array=get(index_expr.array()); - exprt tmp_index=get(index_expr.index()); - if(tmp_array.is_nil() || tmp_index.is_nil()) - return nil_exprt(); - return index_exprt(tmp_array, tmp_index, expr.type()); - } - else if(expr.id()==ID_constant) - return expr; - else if(expr.id()==ID_typecast) - { - exprt tmp=get(to_typecast_expr(expr).op()); - if(tmp.is_nil()) - return nil_exprt(); - return typecast_exprt(tmp, expr.type()); - } - - return nil_exprt(); -} - -exprt smt1_convt::ce_value( - const typet &type, - const std::string &index, - const std::string &value, - bool in_struct) const -{ - if(type.id()==ID_symbol) - return ce_value(ns.follow(type), index, value, in_struct); - - if(type.id()==ID_signedbv || - type.id()==ID_unsignedbv || - type.id()==ID_bv || - type.id()==ID_fixedbv) - { - assert(value.size()==boolbv_width(type)); - constant_exprt c(type); - c.set_value(value); - return c; - } - else if(type.id()==ID_bool) - { - if(value=="1") - return true_exprt(); - else if(value=="0") - return false_exprt(); - } - else if(type.id()==ID_pointer) - { - assert(value.size()==boolbv_width(type)); - - constant_exprt result(type); - result.set_value(value); - - // add the elaborated expression as operand - - pointer_logict::pointert p; - p.object=integer2unsigned( - binary2integer( - value.substr(0, config.bv_encoding.object_bits), false)); - - p.offset= - binary2integer( - value.substr(config.bv_encoding.object_bits, std::string::npos), true); - - result.copy_to_operands( - pointer_logic.pointer_expr(p, to_pointer_type(type))); - - return result; - } - else if(type.id()==ID_struct) - { - return binary2struct(to_struct_type(type), value); - } - else if(type.id()==ID_union) - { - return binary2union(to_union_type(type), value); - } - else if(type.id()==ID_array) - { - const array_typet &array_type = to_array_type(type); - const typet &subtype=ns.follow(type.subtype()); - - // arrays in structs are flat, no index - if(in_struct) - { - // we can only do fixed-size arrays - mp_integer size; - - if(!to_integer(array_type.size(), size)) - { - std::size_t size_int=integer2unsigned(size); - std::size_t sub_width=value.size()/size_int; - array_exprt array_list(array_type); - array_list.reserve_operands(size_int); - - std::size_t offset=value.size(); - - for(std::size_t i=0; i!=size_int; i++) - { - offset-=sub_width; - std::string sub_value=value.substr(offset, sub_width); - array_list.copy_to_operands(ce_value(subtype, "", sub_value, true)); - } - - return array_list; - } - } - else if(subtype.id()==ID_array) - { - // a 2 dimensional array - second dimension is flattened - return ce_value(subtype, "", value, true); - } - else - { - exprt value_expr=ce_value(subtype, "", value, in_struct); - - if(index=="") - return nil_exprt(); - - // use index, recusive call - exprt index_expr= - ce_value(signedbv_typet(index.size()), "", index, false); - - if(index_expr.is_nil()) - return nil_exprt(); - - array_list_exprt array_list(array_type); - array_list.copy_to_operands(index_expr, value_expr); - - return array_list; - } - } - - return nil_exprt(); -} - -typet smt1_convt::array_index_type() const -{ - return signedbv_typet(array_index_bits); -} - -void smt1_convt::array_index(const exprt &expr) -{ - if(expr.type().id()==ID_integer) - return convert_expr(expr, true); - - typet t=array_index_type(); - if(t==expr.type()) - return convert_expr(expr, true); - const typecast_exprt tmp(expr, t); - convert_expr(tmp, true); -} - -void smt1_convt::convert_address_of_rec( - const exprt &expr, - const pointer_typet &result_type) -{ - if(expr.id()==ID_symbol || - expr.id()==ID_constant || - expr.id()==ID_string_constant || - expr.id()==ID_label) - { - out - << "(concat" - << " bv" << pointer_logic.add_object(expr) << "[" - << config.bv_encoding.object_bits << "]" - << " bv0[" - << boolbv_width(result_type)-config.bv_encoding.object_bits << "]" - << ")"; - } - else if(expr.id()==ID_index) - { - if(expr.operands().size()!=2) - throw "index takes two operands"; - - const exprt &array=to_index_expr(expr).array(); - const exprt &index=to_index_expr(expr).index(); - - if(index.is_zero()) - { - if(array.type().id()==ID_pointer) - convert_expr(array, true); - else if(array.type().id()==ID_array) - convert_address_of_rec(array, result_type); - else - assert(false); - } - else - { - // this is really pointer arithmetic - exprt new_index_expr=expr; - new_index_expr.op1()=from_integer(0, index.type()); - - address_of_exprt address_of_expr( - new_index_expr, - pointer_type(array.type().subtype())); - - plus_exprt plus_expr( - address_of_expr, - index, - address_of_expr.type()); - - convert_expr(plus_expr, true); - } - } - else if(expr.id()==ID_member) - { - if(expr.operands().size()!=1) - throw "member takes one operand"; - - const member_exprt &member_expr=to_member_expr(expr); - - const exprt &struct_op=member_expr.struct_op(); - const typet &struct_op_type=ns.follow(struct_op.type()); - - if(struct_op_type.id()==ID_struct) - { - const struct_typet &struct_type= - to_struct_type(struct_op_type); - - const irep_idt &component_name= - member_expr.get_component_name(); - - mp_integer offset=member_offset(struct_type, component_name, ns); - assert(offset>=0); - - const unsignedbv_typet index_type(boolbv_width(result_type)); - - out << "(bvadd "; - convert_address_of_rec(struct_op, result_type); - out << " "; - convert_expr(from_integer(offset, index_type), true); - out << ")"; - } - else if(struct_op_type.id()==ID_union) - { - // these all have offset 0 - convert_address_of_rec(struct_op, result_type); - } - else - throw "unexpected type of member operand"; - } - else if(expr.id()==ID_if) - { - assert(expr.operands().size()==3); - - out << "(ite "; - convert_expr(expr.op0(), false); - out << " "; - convert_address_of_rec(expr.op1(), result_type); - out << " "; - convert_address_of_rec(expr.op2(), result_type); - out << ")"; - } - else - throw "don't know how to take address of: "+expr.id_string(); -} - -void smt1_convt::convert_byte_extract( - const byte_extract_exprt &expr, - bool bool_as_bv) -{ - // we just run the flattener - exprt flattened_expr=flatten_byte_extract(expr, ns); - convert_expr(flattened_expr, bool_as_bv); -} - -void smt1_convt::convert_byte_update( - const exprt &expr, - bool bool_as_bv) -{ - assert(expr.operands().size()==3); - - // The situation: expr.op0 needs to be split in 3 parts - // |<--- L --->|<--- M --->|<--- R --->| - // where M is the expr.op1'th byte - // We need to output L expr.op2 R - - mp_integer i; - if(to_integer(expr.op1(), i)) - throw "byte_update takes constant as second operand"; - - std::size_t w=boolbv_width(expr.op0().type()); - - if(w==0) - throw "failed to get width of byte_update operand"; - - mp_integer upper, lower; // of the byte - mp_integer max=w-1; - std::size_t op_w = boolbv_width(expr.op2().type()); - - if(expr.id()==ID_byte_update_little_endian) - { - lower = i*8; - upper = lower+op_w-1; - } - else - { - upper = max-(i*8); - lower = max-(i*8+op_w-1); - } - - if(upper==max) - { - if(lower==0) // there was only one byte - convert_expr(expr.op2(), true); - else // uppermost byte selected, only R needed - { - out << "(concat "; - convert_expr(expr.op2(), true); - out << " (extract[" << lower-1 << ":0] "; - convert_expr(expr.op0(), true); - out << ")"; // extract - out << ")"; // concat - } - } - else - { - if(lower==0) // lowermost byte selected, only L needed - { - out << "(concat "; - out << "(extract[" << max << ":" << (upper+1) << "] "; - convert_expr(expr.op0(), true); - out << ") "; - convert_expr(expr.op2(), true); - out << ")"; - } - else // byte in the middle selected, L & R needed - { - out << "(concat (concat"; - out << " (extract[" << max << ":" << (upper+1) << "] "; - convert_expr(expr.op0(), true); - out << ")"; // extract - out << " "; - convert_expr(expr.op2(), true); - out << ")"; // concat - out<< " (extract[" << (lower-1) << ":0] "; - convert_expr(expr.op0(), true); - out << ")"; // extract - out << ")"; // concat - } - } -} - -literalt smt1_convt::convert(const exprt &expr) -{ - assert(expr.type().id()==ID_bool); - - // Trivial cases that don't need a new handle. - - if(expr.is_true()) - return const_literal(true); - else if(expr.is_false()) - return const_literal(false); - else if(expr.id()==ID_literal) - return to_literal_expr(expr).get_literal(); - - // Ok, need new handle - - out << "\n"; - - find_symbols(expr); - - literalt l(no_boolean_variables, false); - no_boolean_variables++; - - out << ":extrapreds(("; - convert_literal(l); - out << "))" << "\n"; - - out << ":assumption ; convert " << "\n" - << " (iff "; - convert_literal(l); - out << " "; - convert_expr(expr, false); - out << ")" << "\n"; - - return l; -} - -std::string smt1_convt::convert_identifier(const irep_idt &identifier) -{ - std::string s=id2string(identifier), dest; - dest.reserve(s.size()); - - // a sequence of letters, digits, dots (.), single quotes (’), and - // underscores (_), starting with a letter - - // MathSAT does not really seem to like the single quotes ' - // so we avoid these. - - for(std::string::const_iterator - it=s.begin(); - it!=s.end(); - ++it) - { - char ch=*it; - - if(isalnum(ch) || ch=='_') - dest+=ch; - else if(ch==':') - { - std::string::const_iterator next_it(it); - ++next_it; - if(next_it!=s.end() && *next_it==':') - { - dest.append(".S"); - it=next_it; - } - else - dest+=".C"; - } - else if(ch=='#') - dest+=".H"; - else if(ch=='$') - dest+=".D"; - else if(ch=='!') - dest+=".E"; - else if(ch=='.') - dest+=".."; - else if(ch=='%') - dest+=".P"; - else - { - dest+='.'; - dest.append(std::to_string(ch)); - dest+='.'; - } - } - - return dest; -} - -void smt1_convt::convert_expr(const exprt &expr, bool bool_as_bv) -{ - if(expr.id()==ID_symbol) - { - const typet &type=expr.type(); - - irep_idt id=to_symbol_expr(expr).get_identifier(); - DATA_INVARIANT(!id.empty(), "symbol must have identifier"); - - // boolean symbols may have to be converted - from_bool_begin(type, bool_as_bv); - - out << convert_identifier(id); - - from_bool_end(type, bool_as_bv); - } - else if(expr.id()==ID_nondet_symbol) - { - const typet &type=expr.type(); - - irep_idt id=to_nondet_symbol_expr(expr).get_identifier(); - DATA_INVARIANT(!id.empty(), "symbol must have identifier"); - - // boolean symbols may have to be converted - from_bool_begin(type, bool_as_bv); - - out << "nondet_" << convert_identifier(id); - - from_bool_end(type, bool_as_bv); - } - else if(expr.id()==ID_literal) - { - convert_literal(to_literal_expr(expr).get_literal()); - } - else if(expr.id()==ID_typecast) - { - convert_typecast(to_typecast_expr(expr), bool_as_bv); - } - else if(expr.id()==ID_struct) - { - convert_struct(expr); - } - else if(expr.id()==ID_union) - { - convert_union(expr); - } - else if(expr.id()==ID_constant) - { - convert_constant(to_constant_expr(expr), bool_as_bv); - } - else if(expr.id()==ID_concatenation) - convert_nary(expr, "concat", true); - else if(expr.id()==ID_bitand) - convert_nary(expr, "bvand", true); - else if(expr.id()==ID_bitor) - convert_nary(expr, "bvor", true); - else if(expr.id()==ID_bitxor) - convert_nary(expr, "bvxor", true); - else if(expr.id()==ID_bitnand) - convert_nary(expr, "bvnand", true); - else if(expr.id()==ID_bitnor) - convert_nary(expr, "bvnor", true); - else if(expr.id()==ID_bitnot) - { - assert(expr.operands().size()==1); - out << "(bvnot "; - convert_expr(expr.op0(), true); - out << ")"; - } - else if(expr.id()==ID_unary_minus) - { - const typet &type=expr.type(); - - assert(expr.operands().size()==1); - - if(type.id()==ID_rational) - { - out << "(- "; - convert_expr(expr.op0(), true); - out << ")"; - } - else if(type.id()==ID_integer) - { - out << "(~ "; - convert_expr(expr.op0(), true); - out << ")"; - } - else - { - out << "(bvneg "; - convert_expr(expr.op0(), true); - out << ")"; - } - } - else if(expr.id()==ID_if) - { - assert(expr.operands().size()==3); - - // The SMTLIB standard requires a different operator in a boolean context - if(expr.op1().type().id()==ID_bool && !bool_as_bv) - out << "(if_then_else "; - else - out << "(ite "; - - convert_expr(expr.op0(), false); - out << " "; - convert_expr(expr.op1(), bool_as_bv); - out << " "; - convert_expr(expr.op2(), bool_as_bv); - out << ")"; - } - else if(expr.id()==ID_and || - expr.id()==ID_or || - expr.id()==ID_xor) - { - const typet &type=expr.type(); - const exprt::operandst &operands=expr.operands(); - - assert(type.id()==ID_bool); - assert(operands.size()>=2); - - // this may have to be converted - from_bool_begin(type, bool_as_bv); - - out << "(" << expr.id(); - forall_expr(it, operands) - { - out << " "; - convert_expr(*it, false); - } - out << ")"; - - // this may have to be converted - from_bool_end(type, bool_as_bv); - } - else if(expr.id()==ID_implies) - { - const typet &type=expr.type(); - - assert(type.id()==ID_bool); - assert(expr.operands().size()==2); - - // this may have to be converted - from_bool_begin(type, bool_as_bv); - - out << "(implies "; - convert_expr(expr.op0(), false); - out << " "; - convert_expr(expr.op1(), false); - out << ")"; - - // this may have to be converted - from_bool_end(type, bool_as_bv); - } - else if(expr.id()==ID_not) - { - const typet &type=expr.type(); - - assert(expr.operands().size()==1); - - // this may have to be converted - from_bool_begin(type, bool_as_bv); - - out << "(not "; - convert_expr(expr.op0(), false); - out << ")"; - - // this may have to be converted - from_bool_end(type, bool_as_bv); - } - else if(expr.id()==ID_equal || - expr.id()==ID_notequal) - { - const typet &type=expr.type(); - - assert(expr.operands().size()==2); - assert(base_type_eq(expr.op0().type(), expr.op1().type(), ns)); - - // this may have to be converted - from_bool_begin(type, bool_as_bv); - - if(expr.op0().type().id()==ID_bool) - { - if(expr.id()==ID_notequal) - out << "(xor "; - else - out << "(iff "; - - convert_expr(expr.op0(), false); - out << " "; - convert_expr(expr.op1(), false); - out << ")"; - } - else - { - if(expr.id()==ID_notequal) - { - out << "(not (= "; - convert_expr(expr.op0(), true); - out << " "; - convert_expr(expr.op1(), true); - out << "))"; - } - else - { - out << "(= "; - convert_expr(expr.op0(), true); - out << " "; - convert_expr(expr.op1(), true); - out << ")"; - } - } - - // this may have to be converted - from_bool_end(type, bool_as_bv); - } - else if(expr.id()==ID_le || - expr.id()==ID_lt || - expr.id()==ID_ge || - expr.id()==ID_gt) - { - convert_relation(expr, bool_as_bv); - } - else if(expr.id()==ID_plus) - { - convert_plus(to_plus_expr(expr)); - } - else if(expr.id()==ID_floatbv_plus) - { - convert_floatbv_plus(expr); - } - else if(expr.id()==ID_minus) - { - convert_minus(to_minus_expr(expr)); - } - else if(expr.id()==ID_floatbv_minus) - { - convert_floatbv_minus(expr); - } - else if(expr.id()==ID_div) - { - convert_div(to_div_expr(expr)); - } - else if(expr.id()==ID_floatbv_div) - { - convert_floatbv_div(expr); - } - else if(expr.id()==ID_mod) - { - convert_mod(to_mod_expr(expr)); - } - else if(expr.id()==ID_mult) - { - convert_mult(to_mult_expr(expr)); - } - else if(expr.id()==ID_floatbv_mult) - { - convert_floatbv_mult(expr); - } - else if(expr.id()==ID_address_of) - { - const typet &type=expr.type(); - - assert(expr.operands().size()==1); - assert(type.id()==ID_pointer); - convert_address_of_rec(expr.op0(), to_pointer_type(type)); - } - else if(expr.id()=="implicit_address_of" || - expr.id()=="reference_to") - { - // old stuff - assert(false); - } - else if(expr.id()==ID_array_of) - { - assert(expr.type().id()==ID_array); - assert(expr.operands().size()==1); - - // const array_typet &array_type=to_array_type(expr.type()); - - // not really there in SMT, so we replace it - // this is an over-approximation - array_of_mapt::const_iterator it=array_of_map.find(expr); - assert(it!=array_of_map.end()); - - out << it->second; - } - else if(expr.id()==ID_index) - { - convert_index(to_index_expr(expr), bool_as_bv); - } - else if(expr.id()==ID_ashr || - expr.id()==ID_lshr || - expr.id()==ID_shl) - { - const typet &type=expr.type(); - - assert(expr.operands().size()==2); - - if(type.id()==ID_unsignedbv || - type.id()==ID_signedbv || - type.id()==ID_bv || - type.id()==ID_struct || - type.id()==ID_union) - { - if(expr.id()==ID_ashr) - out << "(bvashr "; - else if(expr.id()==ID_lshr) - out << "(bvlshr "; - else if(expr.id()==ID_shl) - out << "(bvshl "; - else - assert(false); - - convert_expr(expr.op0(), true); - out << " "; - - // SMT1 requires the shift distance to have the same width as - // the value that is shifted -- odd! - - std::size_t width_op0=boolbv_width(expr.op0().type()); - std::size_t width_op1=boolbv_width(expr.op1().type()); - - if(width_op0==width_op1) - convert_expr(expr.op1(), true); - else if(width_op0>width_op1) - { - out << "(zero_extend[" << width_op0-width_op1 << "] "; - convert_expr(expr.op1(), true); - out << ")"; // zero_extend - } - else // width_op00) - out << "(zero_extend[" << ext << "] "; - - out << "(extract[" - << (op_width-1) - << ":" - << op_width-1-config.bv_encoding.object_bits << "] "; - convert_expr(expr.op0(), true); - out << ")"; - - if(ext>0) - out << ")"; - } - else if(expr.id()=="is_dynamic_object") - { - convert_is_dynamic_object(expr, bool_as_bv); - } - else if(expr.id()==ID_invalid_pointer) - { - const typet &type=expr.type(); - - assert(expr.operands().size()==1); - assert(expr.op0().type().id()==ID_pointer); - std::size_t op_width=boolbv_width(expr.op0().type()); - - // this may have to be converted - from_bool_begin(type, bool_as_bv); - - out << "(= (extract[" - << (op_width-1) - << ":" << op_width-config.bv_encoding.object_bits << "] "; - convert_expr(expr.op0(), true); - out << ") bv" << pointer_logic.get_invalid_object() - << "[" << config.bv_encoding.object_bits << "])"; - - // this may have to be converted - from_bool_end(type, bool_as_bv); - } - else if(expr.id()=="pointer_object_has_type") - { - const typet &type=expr.type(); - - assert(expr.operands().size()==1); - - // this may have to be converted - from_bool_begin(type, bool_as_bv); - - out << "false"; // TODO - - // this may have to be converted - from_bool_end(type, bool_as_bv); - } - else if(expr.id()==ID_string_constant) - { - exprt tmp; - string2array_mapt::const_iterator fit=string2array_map.find(expr); - assert(fit!=string2array_map.end()); - - convert_expr(fit->second, true); - } - else if(expr.id()==ID_extractbit) - { - assert(expr.operands().size()==2); - - if(expr.op0().type().id()==ID_unsignedbv || - expr.op0().type().id()==ID_signedbv) - { - const typet &type=expr.type(); - - // this may have to be converted - from_bv_begin(type, bool_as_bv); - - if(expr.op1().is_constant()) - { - mp_integer i; - if(to_integer(expr.op1(), i)) - throw "extractbit: to_integer failed"; - - out << "(extract[" << i << ":" << i << "] "; - convert_expr(expr.op0(), true); - out << ")"; - } - else - { - out << "(extract[0:0] "; - // the arguments of the shift need to have the same width - out << "(bvlshr "; - convert_expr(expr.op0(), true); - typecast_exprt tmp(expr.op0().type()); - tmp.op0()=expr.op1(); - convert_expr(tmp, true); - out << "))"; // bvlshr, extract - } - - // this may have to be converted - from_bv_end(type, bool_as_bv); - } - else - throw "unsupported type for "+expr.id_string()+ - ": "+expr.op0().type().id_string(); - } - else if(expr.id()==ID_replication) - { - assert(expr.operands().size()==2); - - mp_integer times; - if(to_integer(expr.op0(), times)) - throw "replication takes constant as first parameter"; - - out << "(repeat[" << times << "] "; - convert_expr(expr.op1(), true); // this ensures we have a vector - out << ")"; - } - else if(expr.id()==ID_byte_extract_little_endian || - expr.id()==ID_byte_extract_big_endian) - { - convert_byte_extract(to_byte_extract_expr(expr), bool_as_bv); - } - else if(expr.id()==ID_byte_update_little_endian || - expr.id()==ID_byte_update_big_endian) - { - convert_byte_update(expr, bool_as_bv); - } - else if(expr.id()==ID_width) - { - std::size_t result_width=boolbv_width(expr.type()); - - if(result_width==0) - throw "conversion failed"; - - if(expr.operands().size()!=1) - throw "width expects 1 operand"; - - std::size_t op_width=boolbv_width(expr.op0().type()); - - if(op_width==0) - throw "conversion failed"; - - out << "bv" << op_width/8 << "[" << result_width << "]"; - } - else if(expr.id()==ID_abs) - { - const typet &type=expr.type(); - - assert(expr.operands().size()==1); - const exprt &op0=expr.op0(); - - std::size_t result_width=boolbv_width(type); - - if(result_width==0) - throw "conversion failed"; - - if(type.id()==ID_signedbv || - type.id()==ID_fixedbv) - { - out << "(ite (bvslt "; - convert_expr(op0, true); - out << " bv0[" << result_width << "]) "; - out << "(bvneg "; - convert_expr(op0, true); - out << ") "; - convert_expr(op0, true); - out << ")"; - } - else if(type.id()==ID_floatbv) - { - out << "(bvand "; - convert_expr(op0, true); - out << " bv" - << (power(2, result_width-1)-1) - << "[" << result_width << "])"; - } - else - throw "abs with unsupported operand type"; - } - else if(expr.id()==ID_isnan) - { - const typet &type=expr.type(); - - assert(expr.operands().size()==1); - - const typet &op_type=expr.op0().type(); - - if(op_type.id()==ID_fixedbv) - { - from_bool_begin(type, bool_as_bv); - out << "false"; - from_bool_end(type, bool_as_bv); - } - else - throw "isnan with unsupported operand type"; - } - else if(expr.id()==ID_isfinite) - { - const typet &type=expr.type(); - - if(expr.operands().size()!=1) - throw "isfinite expects one operand"; - - const typet &op_type=expr.op0().type(); - - if(op_type.id()==ID_fixedbv) - { - from_bool_begin(type, bool_as_bv); - out << "true"; - from_bool_end(type, bool_as_bv); - } - else - throw "isfinite with unsupported operand type"; - } - else if(expr.id()==ID_isinf) - { - const typet &type=expr.type(); - - if(expr.operands().size()!=1) - throw "isinf expects one operand"; - - const typet &op_type=expr.op0().type(); - - if(op_type.id()==ID_fixedbv) - { - from_bool_begin(type, bool_as_bv); - out << "false"; - from_bool_end(type, bool_as_bv); - } - else - throw "isinf with unsupported operand type"; - } - else if(expr.id()==ID_isnormal) - { - const typet &type=expr.type(); - - if(expr.operands().size()!=1) - throw "isnormal expects one operand"; - - const typet &op_type=expr.op0().type(); - - if(op_type.id()==ID_fixedbv) - { - from_bool_begin(type, bool_as_bv); - out << "true"; - from_bool_end(type, bool_as_bv); - } - else - throw "isnormal with unsupported operand type"; - } - else if(expr.id()==ID_overflow_plus || - expr.id()==ID_overflow_minus) - { - const typet &type=expr.type(); - - assert(expr.operands().size()==2); - bool subtract=expr.id()==ID_overflow_minus; - - const typet &op_type=expr.op0().type(); - - std::size_t width=boolbv_width(op_type); - - if(op_type.id()==ID_signedbv) - { - // an overflow occurs if the top two bits of the extended sum differ - - from_bool_begin(type, bool_as_bv); - out << "(let (?sum ("; - out << (subtract?"bvsub":"bvadd"); - out << " (sign_extend[1] "; - convert_expr(expr.op0(), true); - out << ")"; - out << " (sign_extend[1] "; - convert_expr(expr.op1(), true); - out << "))) "; // sign_extend, bvadd/sub let2 - out << "(not (= " - "(extract[" << width << ":" << width << "] ?sum) " - "(extract[" << (width-1) << ":" << (width-1) << "] ?sum)"; - out << ")))"; // =, not, let - from_bool_end(type, bool_as_bv); - } - else if(op_type.id()==ID_unsignedbv) - { - // overflow is simply carry-out - from_bv_begin(type, bool_as_bv); - out << "(extract[" << width << ":" << width << "] "; - out << "(" << (subtract?"bvsub":"bvadd"); - out << " (zero_extend[1] "; - convert_expr(expr.op0(), true); - out << ")"; - out << " (zero_extend[1] "; - convert_expr(expr.op1(), true); - out << ")))"; // zero_extend, bvsub/bvadd, extract - from_bv_end(type, bool_as_bv); - } - else - throw "overflow check on unknown type: "+op_type.id_string(); - } - else if(expr.id()==ID_overflow_mult) - { - assert(expr.operands().size()==2); - - // No better idea than to multiply with double the bits and then compare - // with max value. - - const typet &op_type=expr.op0().type(); - std::size_t width=boolbv_width(op_type); - - if(op_type.id()==ID_signedbv) - { - out << "(let (?prod (bvmul (sign_extend[" << width << "] "; - convert_expr(expr.op0(), true); - out << ") (sign_extend[" << width << "] "; - convert_expr(expr.op1(), true); - out << "))) "; // sign_extend, bvmul, ?prod - out << "(or (bvsge ?prod (bv" << power(2, width-1) - << "[" << width*2 << "]))"; - out << " (bvslt ?prod (bvneg (bv" << power(2, width-1) - << "[" << width*2 << "])))"; - out << "))"; // or, let - } - else if(op_type.id()==ID_unsignedbv) - { - out << "(bvuge (bvmul (zero_extend[" << width << "] "; - convert_expr(expr.op0(), true); - out << ") (zero_extend[" << width << "] "; - convert_expr(expr.op1(), true); - out << ")) bv" << power(2, width) << "[" << width*2 << "])"; - } - else - throw "overflow-* check on unknown type: "+op_type.id_string(); - } - else if(expr.id()==ID_forall || expr.id()==ID_exists) - { - from_bv_begin(expr.type(), bool_as_bv); - - assert(expr.operands().size()==2); - out << "(" << expr.id() << " ("; - exprt bound=expr.op0(); - convert_expr(bound, false); - out << " "; - - if(bound.type().id()==ID_bool) - out << "Bool"; - else - convert_type(bound.type()); - - out << ") "; - convert_expr(expr.op1(), false); - out << ")"; - - from_bv_end(expr.type(), bool_as_bv); - } - else if(expr.id()==ID_extractbits) - { - assert(expr.operands().size()==3); - - const typet &op_type=ns.follow(expr.op0().type()); - - if(op_type.id()==ID_unsignedbv || - op_type.id()==ID_signedbv || - op_type.id()==ID_bv || - op_type.id()==ID_fixedbv || - op_type.id()==ID_struct || - op_type.id()==ID_union || - op_type.id()==ID_vector) - { - if(expr.op1().is_constant() && - expr.op2().is_constant()) - { - mp_integer op1_i, op2_i; - - if(to_integer(expr.op1(), op1_i)) - throw "extractbits: to_integer failed"; - - if(to_integer(expr.op2(), op2_i)) - throw "extractbits: to_integer failed"; - - out << "(extract[" << op1_i << ":" << op2_i << "] "; - convert_expr(expr.op0(), true); - out << ")"; - } - else - { - #if 0 - out << "(extract["; - convert_expr(expr.op1(), bool_as_bv); - out << ":"; - convert_expr(expr.op2(), bool_as_bv); - out << "] "; - convert_expr(expr.op0(), bool_as_bv); - out << ")"; - #endif - throw "smt1 todo: extractbits with variable bits"; - } - } - else - throw "unsupported type for "+expr.id_string()+ - ": "+op_type.id_string(); - } - else if(expr.id()==ID_array) - { - const exprt::operandst &operands=expr.operands(); - - // array constructor - array_expr_mapt::const_iterator it=array_expr_map.find(expr); - assert(it!=array_expr_map.end()); - - assert(!operands.empty()); - - forall_expr(it, operands) - out << "(store "; - - out << it->second; - - std::size_t i=0; - forall_expr(it, operands) - { - exprt index=from_integer(i, unsignedbv_typet(array_index_bits)); - out << " "; - convert_expr(index, true); - out << " "; - convert_expr(*it, true); - out << ")"; - i++; - } - } - else if(expr.id()==ID_vector) - { - // Vector constructor. - // We flatten the vector by concatenating its elements. - convert_nary(expr, "concat", bool_as_bv); - } - else - throw "smt1_convt::convert_expr: `"+ - expr.id_string()+"' is unsupported"; -} - -void smt1_convt::convert_typecast( - const typecast_exprt &expr, - bool bool_as_bv) -{ - assert(expr.operands().size()==1); - const exprt &src=expr.op0(); - - typet dest_type=ns.follow(expr.type()); - if(dest_type.id()==ID_c_enum_tag) - dest_type=ns.follow_tag(to_c_enum_tag_type(dest_type)); - - typet src_type=ns.follow(src.type()); - if(src_type.id()==ID_c_enum_tag) - src_type=ns.follow_tag(to_c_enum_tag_type(src_type)); - - if(dest_type.id()==ID_bool) - { - // boolean typecasts may have to be converted - from_bool_begin(dest_type, bool_as_bv); - - // this is comparison with zero - if(src_type.id()==ID_signedbv || - src_type.id()==ID_unsignedbv || - src_type.id()==ID_fixedbv || - src_type.id()==ID_c_bit_field || - src_type.id()==ID_pointer) - { - out << "(not (= "; - convert_expr(src, true); - out << " "; - convert_expr( - from_integer(0, src_type), - true); - out << "))"; - } - else - { - // NOLINTNEXTLINE(readability/throw) - throw "TODO typecast1 "+src_type.id_string()+" -> bool"; - } - - // boolean typecasts may have to be converted - from_bool_end(dest_type, bool_as_bv); - } - else if(dest_type.id()==ID_c_bool) - { - // this is comparison with zero - if(src_type.id()==ID_signedbv || - src_type.id()==ID_unsignedbv || - src_type.id()==ID_fixedbv || - src_type.id()==ID_c_bit_field || - src_type.id()==ID_pointer) - { - std::size_t to_width=boolbv_width(dest_type); - - out << "(ite "; - out << "(not (= "; - convert_expr(src, true); - out << " "; - convert_expr( - from_integer(0, src_type), - true); - out << ")) "; // not, = - out << " bv1[" << to_width << "]"; - out << " bv0[" << to_width << "]"; - out << ")"; // ite - } - else - { - // NOLINTNEXTLINE(readability/throw) - throw "TODO typecast1 "+src_type.id_string()+" -> bool"; - } - } - else if(dest_type.id()==ID_signedbv || - dest_type.id()==ID_unsignedbv || - dest_type.id()==ID_c_enum) - { - std::size_t to_width=boolbv_width(dest_type); - - if(src_type.id()==ID_signedbv || // from signedbv - src_type.id()==ID_unsignedbv || // from unsigedbv - src_type.id()==ID_c_bool || - src_type.id()==ID_c_enum) - { - std::size_t from_width=boolbv_width(src_type); - - if(from_width==to_width) - convert_expr(src, true); // ignore - else if(from_widthfrom_integer_bits) - { - out << "(sign_extend[" << (to_width-from_integer_bits) << "] "; - out << "(extract[" << (from_width-1) << ":" - << from_fraction_bits << "] "; - convert_expr(src, true); - out << "))"; - } - else - { - out << "(extract[" << (from_fraction_bits+to_width-1) - << ":" << from_fraction_bits << "] "; - convert_expr(src, true); - out << ")"; - } - } - else if(src_type.id()==ID_bool) // from boolean - { - out << "(ite "; - convert_expr(src, false); - - if(dest_type.id()==ID_fixedbv) - { - fixedbv_spect spec(to_fixedbv_type(expr.type())); - out << " (concat bv1[" << spec.integer_bits << "] " << - "bv0[" << spec.get_fraction_bits() << "]) " << - "bv0[" << spec.width << "]"; - } - else - { - out << " bv1[" << to_width << "]"; - out << " bv0[" << to_width << "]"; - } - - out << ")"; - } - else if(src_type.id()==ID_pointer) // from pointer to int - { - std::size_t from_width=boolbv_width(src_type); - - if(from_width "+dest_type.id_string(); - } - } - else if(dest_type.id()==ID_fixedbv) // to fixedbv - { - const fixedbv_typet &fixedbv_type=to_fixedbv_type(dest_type); - std::size_t to_fraction_bits=fixedbv_type.get_fraction_bits(); - std::size_t to_integer_bits=fixedbv_type.get_integer_bits(); - - if(src_type.id()==ID_unsignedbv || - src_type.id()==ID_signedbv || - src_type.id()==ID_c_enum) - { - // integer to fixedbv - std::size_t from_width=to_bitvector_type(src_type).get_width(); - - // we just concatenate a zero-valued fractional part - out << "(concat"; - - if(from_width==to_integer_bits) - convert_expr(src, true); - else if(from_width>to_integer_bits) - { - // too many integer bits, chop some off - out << " (extract[" << (to_integer_bits-1) << ":0] "; - convert_expr(src, true); - out << ")"; - } - else - { - // too few integer bits - assert(from_widthfrom_integer_bits); - out << "(sign_extend[" - << (to_integer_bits-from_integer_bits) - << "] (extract[" - << (from_width-1) << ":" - << from_fraction_bits - << "] "; - convert_expr(src, true); - out << "))"; - } - - out << " "; - - if(to_fraction_bits<=from_fraction_bits) - { - out << "(extract[" - << (from_fraction_bits-1) << ":" - << (from_fraction_bits-to_fraction_bits) - << "] "; - convert_expr(src, true); - out << ")"; - } - else - { - assert(to_fraction_bits>from_fraction_bits); - out << "(concat (extract[" - << (from_fraction_bits-1) << ":0] "; - convert_expr(src, true); - out << ")" - << " bv0[" << to_fraction_bits-from_fraction_bits - << "])"; - } - - out << ")"; // concat - } - else - throw "unexpected typecast to fixedbv"; - } - else if(dest_type.id()==ID_pointer) - { - std::size_t to_width=boolbv_width(dest_type); - - if(src_type.id()==ID_pointer) - { - // this just passes through - convert_expr(src, true); - } - else if(src_type.id()==ID_unsignedbv || - src_type.id()==ID_signedbv) - { - std::size_t from_width=boolbv_width(src_type); - - if(from_width==to_width) - convert_expr(src, true); // pass through - else if(from_widthto_width - { - out << "(extract[" - << to_width - << ":0] "; - convert_expr(src, true); - out << ")"; // extract - } - } - else - // NOLINTNEXTLINE(readability/throw) - throw "TODO typecast3 "+src_type.id_string()+" -> pointer"; - } - else if(dest_type.id()==ID_range) - { - // NOLINTNEXTLINE(readability/throw) - throw "TODO range typecast"; - } - else if(dest_type.id()==ID_c_bit_field) - { - std::size_t from_width=boolbv_width(src_type); - std::size_t to_width=boolbv_width(dest_type); - - if(from_width==to_width) - convert_expr(src, bool_as_bv); // ignore - else - { - typet t=c_bit_field_replacement_type(to_c_bit_field_type(dest_type), ns); - typecast_exprt tmp(typecast_exprt(src, t), dest_type); - convert_typecast(tmp, bool_as_bv); - } - } - else - // NOLINTNEXTLINE(readability/throw) - throw "TODO typecast4 ? -> "+dest_type.id_string(); -} - -void smt1_convt::convert_struct(const exprt &expr) -{ - const struct_typet &struct_type=to_struct_type(expr.type()); - - const struct_typet::componentst &components= - struct_type.components(); - - assert(components.size()==expr.operands().size()); - - assert(!components.empty()); - - if(components.size()==1) - { - const exprt &op=expr.op0(); - - if(op.type().id()==ID_array) - flatten_array(op); - else - convert_expr(op, true); - } - else - { - std::size_t nr_ops=0; - - for(std::size_t i=0; imember_width); - out << "(concat "; - out << "bv0[" << (total_width-member_width) << "] "; - convert_expr(op, true); - out << ")"; - } -} - -void smt1_convt::convert_constant( - const constant_exprt &expr, - bool bool_as_bv) -{ - if(expr.type().id()==ID_unsignedbv || - expr.type().id()==ID_signedbv || - expr.type().id()==ID_bv || - expr.type().id()==ID_c_enum || - expr.type().id()==ID_c_enum_tag || - expr.type().id()==ID_c_bool || - expr.type().id()==ID_c_bit_field) - { - mp_integer value; - - if(to_integer(expr, value)) - throw "failed to convert bitvector constant"; - - std::size_t width=boolbv_width(expr.type()); - - if(value<0) - value=power(2, width)+value; - - out << "bv" << value - << "[" << width << "]"; - } - else if(expr.type().id()==ID_fixedbv) - { - fixedbv_spect spec(to_fixedbv_type(expr.type())); - - std::string v_str=expr.get_string(ID_value); - mp_integer v=binary2integer(v_str, false); - - out << "bv" << v << "[" << spec.width << "]"; - } - else if(expr.type().id()==ID_floatbv) - { - ieee_float_spect spec(to_floatbv_type(expr.type())); - - std::string v_str=expr.get_string(ID_value); - mp_integer v=binary2integer(v_str, false); - - out << "bv" << v << "[" << spec.width() << "]"; - } - else if(expr.type().id()==ID_pointer) - { - const irep_idt &value=expr.get(ID_value); - - if(value==ID_NULL) - { - assert(boolbv_width(expr.type())!=0); - out << "(concat" - << " bv" << pointer_logic.get_null_object() - << "[" << config.bv_encoding.object_bits << "]" - << " bv0[" << boolbv_width(expr.type())-config.bv_encoding.object_bits - << "]" - << ")"; // concat - } - else - throw "unknown pointer constant: "+id2string(value); - } - else if(expr.type().id()==ID_bool) - { - if(expr.is_true()) - out << (bool_as_bv?"bit1":"true"); - else if(expr.is_false()) - out << (bool_as_bv?"bit0":"false"); - else - throw "unknown boolean constant"; - } - else if(expr.type().id()==ID_array) - { - // this should be the 'array' expression - assert(false); - } - else if(expr.type().id()==ID_rational) - { - std::string value=expr.get_string(ID_value); - size_t pos=value.find("/"); - - if(pos==std::string::npos) - out << value << ".0"; - else - { - out << "(/ " << value.substr(0, pos) << ".0 " - << value.substr(pos+1) << ".0)"; - } - } - else if(expr.type().id()==ID_integer || - expr.type().id()==ID_natural) - { - std::string value=expr.get_string(ID_value); - - if(value[0]=='-') - out << "(~ " << value.substr(1) << ")"; - else - out << value; - } - else - throw "unknown constant: "+expr.type().id_string(); -} - -void smt1_convt::convert_mod(const mod_exprt &expr) -{ - assert(expr.operands().size()==2); - - if(expr.type().id()==ID_unsignedbv || - expr.type().id()==ID_signedbv) - { - if(expr.type().id()==ID_unsignedbv) - out << "(bvurem "; - else - out << "(bvsrem "; - - convert_expr(expr.op0(), true); - out << " "; - convert_expr(expr.op1(), true); - out << ")"; - } - else - throw "unsupported type for mod: "+expr.type().id_string(); -} - -void smt1_convt::convert_is_dynamic_object( - const exprt &expr, - bool bool_as_bv) -{ - std::vector dynamic_objects; - pointer_logic.get_dynamic_objects(dynamic_objects); - - assert(expr.operands().size()==1); - assert(expr.op0().type().id()==ID_pointer); - std::size_t op_width=boolbv_width(expr.op0().type()); - - // this may have to be converted - from_bool_begin(expr.type(), bool_as_bv); - - if(dynamic_objects.empty()) - out << "false"; - else - { - // let is only allowed in formulas - - out << "(let (?obj (extract[" - << (op_width-1) - << ":" << op_width-config.bv_encoding.object_bits << "] "; - convert_expr(expr.op0(), true); - out << ")) "; - - if(dynamic_objects.size()==1) - { - out << "(= bv" << dynamic_objects.front() - << "[" << config.bv_encoding.object_bits << "] ?obj)"; - } - else - { - out << "(or"; - - for(const auto &obj : dynamic_objects) - out << " (= bv" << obj - << "[" << config.bv_encoding.object_bits << "] ?obj)"; - - out << ")"; // or - } - - out << ")"; // let - } - - // this may have to be converted - from_bool_end(expr.type(), bool_as_bv); -} - -void smt1_convt::convert_relation(const exprt &expr, bool bool_as_bv) -{ - assert(expr.operands().size()==2); - - // this may have to be converted - from_bool_begin(expr.type(), bool_as_bv); - - const typet &op_type=expr.op0().type(); - - out << "("; - - if(op_type.id()==ID_unsignedbv || - op_type.id()==ID_pointer) - { - if(expr.id()==ID_le) - out << "bvule"; - else if(expr.id()==ID_lt) - out << "bvult"; - else if(expr.id()==ID_ge) - out << "bvuge"; - else if(expr.id()==ID_gt) - out << "bvugt"; - - out << " "; - convert_expr(expr.op0(), true); - out << " "; - convert_expr(expr.op1(), true); - } - else if(op_type.id()==ID_signedbv || - op_type.id()==ID_fixedbv) - { - if(expr.id()==ID_le) - out << "bvsle"; - else if(expr.id()==ID_lt) - out << "bvslt"; - else if(expr.id()==ID_ge) - out << "bvsge"; - else if(expr.id()==ID_gt) - out << "bvsgt"; - - out << " "; - convert_expr(expr.op0(), true); - out << " "; - convert_expr(expr.op1(), true); - } - else if(op_type.id()==ID_rational || - op_type.id()==ID_integer) - { - out << expr.id(); - - out << " "; - convert_expr(expr.op0(), true); - out << " "; - convert_expr(expr.op1(), true); - } - else - throw "unsupported type for "+expr.id_string()+ - ": "+op_type.id_string(); - - out << ")"; - - // this may have to be converted - from_bool_end(expr.type(), bool_as_bv); -} - -void smt1_convt::convert_plus(const plus_exprt &expr) -{ - assert(expr.operands().size()>=2); - - if(expr.type().id()==ID_unsignedbv || - expr.type().id()==ID_signedbv || - expr.type().id()==ID_fixedbv) - { - convert_nary(expr, "bvadd", true); - } - else if(expr.type().id()==ID_pointer) - { - if(expr.operands().size()<2) - throw "pointer arithmetic with less than two operands"; - - if(expr.operands().size()==2) - { - exprt p=expr.op0(), i=expr.op1(); - - if(p.type().id()!=ID_pointer) - p.swap(i); - - if(p.type().id()!=ID_pointer) - throw "unexpected mixture in pointer arithmetic"; - - mp_integer element_size= - pointer_offset_size(expr.type().subtype(), ns); - assert(element_size>0); - - // adjust width if needed - if(boolbv_width(i.type())!=boolbv_width(expr.type())) - i.make_typecast(signedbv_typet(boolbv_width(expr.type()))); - - out << "(bvadd "; - convert_expr(p, true); - out << " "; - - if(element_size>=2) - { - out << "(bvmul "; - convert_expr(i, true); - out << " bv" << element_size - << "[" << boolbv_width(expr.type()) << "])"; - } - else - convert_expr(i, true); - - out << ")"; - } - else - { - // more than two operands - exprt p; - typet integer_type=signedbv_typet(boolbv_width(expr.type())); - exprt integer_sum(ID_plus, integer_type); - - forall_operands(it, expr) - { - if(it->type().id()==ID_pointer) - p=*it; - else - integer_sum.copy_to_operands(*it); - } - - Forall_operands(it, integer_sum) - if(it->type()!=integer_type) - it->make_typecast(integer_type); - - plus_exprt pointer_arithmetic(p, integer_sum, expr.type()); - convert_plus(pointer_arithmetic); // recursive call - } - } - else if(expr.type().id()==ID_rational || - expr.type().id()==ID_integer) - { - convert_nary(expr, "+", true); - } - else - throw "unsupported type for +: "+expr.type().id_string(); -} - -void smt1_convt::convert_floatbv_plus(const exprt &expr) -{ - assert(expr.operands().size()==3); - assert(expr.type().id()==ID_floatbv); - - throw "todo: floatbv_plus"; -} - -void smt1_convt::convert_minus(const minus_exprt &expr) -{ - assert(expr.operands().size()==2); - - if(expr.type().id()==ID_unsignedbv || - expr.type().id()==ID_signedbv || - expr.type().id()==ID_fixedbv) - { - out << "(bvsub "; - - if(expr.op0().type().id()==ID_pointer) - out << "(extract[" << boolbv_width(expr.op0().type())-1 << ":0] "; - convert_expr(expr.op0(), true); - if(expr.op0().type().id()==ID_pointer) - out << ")"; - - out << " "; - - if(expr.op1().type().id()==ID_pointer) - out << "(extract[" << boolbv_width(expr.op1().type())-1 << ":0] "; - convert_expr(expr.op1(), true); - if(expr.op1().type().id()==ID_pointer) - out << ")"; - - out << ")"; - } - else if(expr.type().id()==ID_pointer) - { - convert_expr(binary_exprt( - expr.op0(), - "+", - unary_minus_exprt(expr.op1(), expr.op1().type()), - expr.type()), - true); - } - else - throw "unsupported type for -: "+expr.type().id_string(); -} - -void smt1_convt::convert_floatbv_minus(const exprt &expr) -{ - assert(expr.operands().size()==3); - assert(expr.type().id()==ID_floatbv); - - throw "todo: floatbv_minus"; -} - -void smt1_convt::convert_div(const div_exprt &expr) -{ - assert(expr.operands().size()==2); - - if(expr.type().id()==ID_unsignedbv || - expr.type().id()==ID_signedbv) - { - if(expr.type().id()==ID_unsignedbv) - out << "(bvudiv "; - else - out << "(bvsdiv "; - - convert_expr(expr.op0(), true); - out << " "; - convert_expr(expr.op1(), true); - out << ")"; - } - else if(expr.type().id()==ID_fixedbv) - { - fixedbv_spect spec(to_fixedbv_type(expr.type())); - std::size_t fraction_bits=spec.get_fraction_bits(); - - out << "(extract[" << spec.width-1 << ":0] "; - out << "(bvsdiv "; - - out << "(concat "; - convert_expr(expr.op0(), true); - out << " bv0[" << fraction_bits << "]) "; - - out << "(sign_extend[" << fraction_bits << "] "; - convert_expr(expr.op1(), true); - out << ")"; - - out << "))"; - } - else - throw "unsupported type for /: "+expr.type().id_string(); -} - -void smt1_convt::convert_floatbv_div(const exprt &expr) -{ - assert(expr.operands().size()==3); - assert(expr.type().id()==ID_floatbv); - - throw "todo: floatbv_div"; -} - -void smt1_convt::convert_mult(const mult_exprt &expr) -{ - assert(expr.operands().size()>=2); - - // re-write to binary if needed - if(expr.operands().size()>2) - { - // strip last operand - exprt tmp=expr; - tmp.operands().pop_back(); - - // recursive call - return convert_mult(mult_exprt(tmp, expr.operands().back())); - } - - assert(expr.operands().size()==2); - - if(expr.type().id()==ID_unsignedbv || - expr.type().id()==ID_signedbv) - { - // Note that bvmul is really unsigned, - // but this is irrelevant as we chop-off any extra result - // bits. - out << "(bvmul "; - convert_expr(expr.op0(), true); - out << " "; - convert_expr(expr.op1(), true); - out << ")"; - } - else if(expr.type().id()==ID_fixedbv) - { - fixedbv_spect spec(to_fixedbv_type(expr.type())); - std::size_t fraction_bits=spec.get_fraction_bits(); - - // strip away faction_bits off the result - out << "(extract[" << spec.width+fraction_bits-1 << ":" - << fraction_bits << "] "; - - out << "(bvmul "; - - out << "(sign_extend[" << fraction_bits << "] "; - convert_expr(expr.op0(), true); - out << ") "; - - out << "(sign_extend[" << fraction_bits << "] "; - convert_expr(expr.op1(), true); - out << ") "; - - out << ")"; // bvmul, fraction_bits+width wide - out << ")"; // extract, width bits wide - } - else if(expr.type().id()==ID_rational) - { - out << "(* "; - convert_expr(expr.op0(), true); - out << " "; - convert_expr(expr.op1(), true); - out << ")"; - } - else - throw "unsupported type for *: "+expr.type().id_string(); -} - -void smt1_convt::convert_floatbv_mult(const exprt &expr) -{ - assert(expr.operands().size()==3); - assert(expr.type().id()==ID_floatbv); - - throw "todo: floatbv_mult"; -} - -void smt1_convt::convert_with(const exprt &expr) -{ - // get rid of "with" that has more than three operands - - assert(expr.operands().size()>=3); - - if(expr.operands().size()>3) - { - std::size_t s=expr.operands().size(); - - // strip of the trailing two operands - exprt tmp=expr; - tmp.operands().resize(s-2); - - with_exprt new_with_expr; - assert(new_with_expr.operands().size()==3); - new_with_expr.type()=expr.type(); - new_with_expr.old()=tmp; - new_with_expr.where()=expr.operands()[s-2]; - new_with_expr.new_value()=expr.operands()[s-1]; - - // recursive call - return convert_with(new_with_expr); - } - - const typet &expr_type=ns.follow(expr.type()); - - if(expr_type.id()==ID_array) - { - const exprt &array=expr.op0(); - - if(array.id()==ID_member) - { - // arrays in structs and unions are flattened! - - const typet &array_type=to_array_type(expr.type()); - const typet &elem_type=array_type.subtype(); - - const member_exprt &member_expr=to_member_expr(array); - const exprt &struct_op=member_expr.struct_op(); - const irep_idt &name=member_expr.get_component_name(); - - const typet &struct_op_type=ns.follow(struct_op.type()); - - std::size_t total_width=boolbv_width(struct_op_type); - - if(total_width==0) - throw "failed to get struct width"; - - std::size_t offset; - - if(struct_op_type.id()==ID_struct) - offset=boolbv_width.get_member( - to_struct_type(struct_op_type), name).offset; - else if(struct_op_type.id()==ID_union) - offset=0; - else - throw "failed to get offset"; - - std::size_t width=boolbv_width(expr.type()); - - if(width==0) - throw "failed to get struct member width"; - - std::size_t elem_width=boolbv_width(elem_type); - - if(elem_width==0) - throw "failed to get struct width"; - - std::size_t array_bits=(offset+width) - offset; - - assert(expr.operands().size()==3); - const exprt &index=expr.operands()[1]; - const exprt &value=expr.operands()[2]; - typecast_exprt index_tc(index, array_index_type()); - - out << "(bvor "; - out << "(bvand "; - - // this gets us the array - out << "(extract[" << offset+width-1 << ":" << offset << "] "; - convert_expr(struct_op, true); - out << ")"; - - // the mask - out << " (bvnot (bvshl"; - - out << " (concat"; - out << " (repeat[" << array_bits-elem_width << "] bv0[1])"; - out << " (repeat[" << elem_width << "] bv1[1])"; - out << ")"; // concat - - // shift it to the index - if(width>=array_index_bits) - out << " (zero_extend[" << width-array_index_bits << "]"; - else - out << " (extract[" << width-1 << ":0]"; - out << " (bvmul "; - convert_expr(index_tc, true); - out << " bv" << elem_width << "[" << array_index_bits << "]"; - out << "))))"; // bvmul, zero_extend, bvshl, bvneg - - out << ")"; // bvand - - // the new value - out << " (bvshl (zero_extend[" << array_bits-elem_width << "] "; - convert_expr(value, true); - - // shift it to the index - out << ")"; - if(width>=array_index_bits) - out << " (zero_extend[" << width-array_index_bits << "]"; - else - out << " (extract[" << width-1 << ":0]"; - out << " (bvmul "; - convert_expr(index_tc, true); - out << " bv" << elem_width << "[" << array_index_bits << "]"; - out << ")))"; // bvmul, bvshl, ze - - out << ")"; // bvor - } - else if(array.id()==ID_index) - { - // arrays in structs are flattened! - - const typet &array_type=to_array_type(expr.type()); - const typet &elem_type=array_type.subtype(); - - const index_exprt &index_expr=to_index_expr(array); - - std::size_t width=boolbv_width(expr.type()); - - if(width==0) - throw "failed to get width of 2nd dimension array"; - - std::size_t elem_width=boolbv_width(elem_type); - - if(elem_width==0) - throw "failed to get array element width"; - - assert(expr.operands().size()==3); - const exprt &index_2nd=expr.operands()[1]; - const exprt &value=expr.operands()[2]; - typecast_exprt index_tc(index_2nd, array_index_type()); - - out << "(bvor "; - out << "(bvand "; - - // this gets us the array - convert_expr(index_expr, true); - - // the mask - out << " (bvnot (bvshl"; - - out << " (concat"; - out << " (repeat[" << width-elem_width << "] bv0[1])"; - out << " (repeat[" << elem_width << "] bv1[1])"; - out << ")"; // concat - - // shift it to the index - if(width>=array_index_bits) - out << " (zero_extend[" << width-array_index_bits << "]"; - else - out << " (extract[" << width-1 << ":0]"; - out << " (bvmul "; - convert_expr(index_tc, true); - out << " bv" << elem_width << "[" << array_index_bits << "]"; - out << "))))"; // bvmul, zero_extend, bvshl, bvneg - - out << ")"; // bvand - - // the new value - out << " (bvshl (zero_extend[" << width-elem_width << "] "; - convert_expr(value, true); - // shift it to the index - out << ")"; - if(width>=array_index_bits) - out << " (zero_extend[" << width-array_index_bits << "]"; - else - out << " (extract[" << width-1 << ":0]"; - out << " (bvmul "; - convert_expr(index_tc, true); - out << " bv" << elem_width << "[" << array_index_bits << "]"; - out << ")))"; // bvmul, bvshl, ze - - out << ")"; // bvor - } - else - { - out << "(store "; - - convert_expr(expr.op0(), true); - - out << " "; - array_index(expr.op1()); - out << " "; - - // Booleans are put as bv[1] into an array - convert_expr(expr.op2(), true); - - out << ")"; - } - } - else if(expr_type.id()==ID_struct) - { - const struct_typet &struct_type=to_struct_type(expr_type); - - const exprt &index=expr.op1(); - const exprt &value=expr.op2(); - - std::size_t total_width=boolbv_width(expr.type()); - - if(total_width==0) - throw "failed to get struct width for with"; - - std::size_t width=boolbv_width(value.type()); - - if(width==0) - throw "failed to get member width for with"; - - std::size_t offset=boolbv_width.get_member( - struct_type, index.get(ID_component_name)).offset; - - if(total_width==width) - convert_expr(value, true); - else - { - if(offset+width!=total_width) - { - out << "(concat"; - out << " (extract[" << (total_width-1) << ":" << (offset+width) << "] "; - convert_expr(expr.op0(), true); - out << ")"; - } - - if(offset!=0) - out << " (concat"; - - out << " "; - convert_expr(value, true); - - if(offset!=0) - { - out << " (extract[" << (offset-1) << ":0] "; - convert_expr(expr.op0(), true); - out << ")"; - out << ")"; // concat - } - - if(offset+width!=total_width) - out << ")"; // concat - } - } - else if(expr_type.id()==ID_union) - { - const union_typet &union_type=to_union_type(expr_type); - - const exprt &value=expr.op2(); - - std::size_t total_width=boolbv_width(union_type); - - if(total_width==0) - throw "failed to get union width for with"; - - std::size_t member_width=boolbv_width(value.type()); - - if(member_width==0) - throw "failed to get union member width for with"; - - if(total_width==member_width) - convert_expr(value, true); - else - { - assert(total_width>member_width); - out << "(concat "; - out << "(extract[" - << (total_width-1) - << ":" << member_width << "] "; - convert_expr(expr.op0(), true); - out << ") "; // extract - convert_expr(value, true); - out << ")"; // concat - } - } - else if(expr_type.id()==ID_bv || - expr_type.id()==ID_unsignedbv || - expr_type.id()==ID_signedbv) - { - // Update bits in a bit-vector. We will use masking and shifts. - - std::size_t total_width=boolbv_width(expr_type); - - if(total_width==0) - throw "failed to get total width"; - - assert(expr.operands().size()==3); - const exprt &index=expr.operands()[1]; - const exprt &value=expr.operands()[2]; - - std::size_t value_width=boolbv_width(value.type()); - - if(value_width==0) - throw "failed to get value width"; - - typecast_exprt index_tc(index, expr_type); - - out << "(bvor "; - out << "(band "; - - // the mask to get rid of the old bits - out << " (bvnot (bvshl"; - - out << " (concat"; - out << " (repeat[" << total_width-value_width << "] bv0[1])"; - out << " (repeat[" << value_width << "] bv1[1])"; - out << ")"; // concat - - // shift it to the index - convert_expr(index_tc, true); - out << "))"; // bvshl, bvot - - out << ")"; // bvand - - // the new value - out << " (bvshl "; - convert_expr(value, true); - - // shift it to the index - convert_expr(index_tc, true); - out << ")"; // bvshl - - out << ")"; // bvor - } - else - { - throw "with expects struct, union, or array type, " - "but got "+expr.type().id_string(); - } -} - -void smt1_convt::convert_update(const exprt &expr) -{ - assert(expr.operands().size()==3); - - // todo - throw "smt1_convt::convert_update to be implemented"; -} - -void smt1_convt::convert_index(const index_exprt &expr, bool bool_as_bv) -{ - assert(expr.operands().size()==2); - - if(expr.array().id()==ID_member || - expr.array().id()==ID_index) - { - // arrays inside structs and 2-dimensional arrays - // these were flattened - - const typet &array_type=to_array_type(expr.array().type()); - const typet &elem_type=array_type.subtype(); - - std::size_t width=boolbv_width(expr.array().type()); - if(width==0) - throw "failed to get array width"; - - std::size_t elem_width=boolbv_width(elem_type); - - if(elem_width==0) - throw "failed to get struct width"; - - out << "(extract[" << elem_width-1 << ":0] "; - out << "(bvlshr "; - convert_expr(expr.array(), true); - if(width>=array_index_bits) - out << " (zero_extend[" << width-array_index_bits << "]"; - else - out << " (extract[" << width-1 << ":0]"; - out << " (bvmul "; - typecast_exprt index_tc(expr.index(), array_index_type()); - convert_expr(index_tc, true); - out << " bv" << elem_width << "[" << array_index_bits << "]"; - out << "))))"; - } - else - { - // Booleans out of arrays may have to be converted - from_bv_begin(expr.type(), bool_as_bv); - - out << "(select "; - convert_expr(expr.array(), true); - out << " "; - array_index(expr.index()); - out << ")"; - - // Booleans out of arrays may have to be converted - from_bv_end(expr.type(), bool_as_bv); - } -} - -void smt1_convt::convert_member(const member_exprt &expr, bool bool_as_bv) -{ - assert(expr.operands().size()==1); - - const member_exprt &member_expr=to_member_expr(expr); - const exprt &struct_op=member_expr.struct_op(); - const typet &struct_op_type=ns.follow(struct_op.type()); - const irep_idt &name=member_expr.get_component_name(); - - // Booleans pulled out of structs may have to be converted - from_bv_begin(expr.type(), bool_as_bv); - - if(struct_op_type.id()==ID_struct) - { - std::size_t offset=boolbv_width.get_member( - to_struct_type(struct_op_type), name).offset; - - std::size_t width=boolbv_width(expr.type()); - - if(width==0) - throw "failed to get struct member width"; - - out << "(extract[" - << (offset+width-1) - << ":" - << offset - << "] "; - convert_expr(struct_op, true); - out << ")"; - } - else if(struct_op_type.id()==ID_union) - { - std::size_t width=boolbv_width(expr.type()); - - if(width==0) - throw "failed to get union member width"; - - out << "(extract[" - << (width-1) - << ":0] "; - convert_expr(struct_op, true); - out << ")"; - } - else - assert(false); - - // Booleans pulled out of structs may have to be converted - from_bv_end(expr.type(), bool_as_bv); -} - -void smt1_convt::convert_overflow(const exprt &expr) -{ -} - -void smt1_convt::set_to(const exprt &expr, bool value) -{ - if(expr.id()==ID_and && value) - { - forall_operands(it, expr) - set_to(*it, true); - return; - } - - if(expr.id()==ID_not) - { - assert(expr.operands().size()==1); - return set_to(expr.op0(), !value); - } - - out << "\n"; - - find_symbols(expr); - - #if 0 - out << "; CONV: " - << format(expr) << '\n'; - #endif - - out << ":assumption ; set_to " << (value ? "true" : "false") << '\n' << " "; - - assert(expr.type().id()==ID_bool); - - if(!value) - { - out << "(not "; - convert_expr(expr, false); - out << ")"; - } - else - convert_expr(expr, false); - - out << "\n"; -} - -void smt1_convt::find_symbols(const exprt &expr) -{ - const typet &type=expr.type(); - find_symbols(type); - - if(expr.id()==ID_forall || expr.id()==ID_exists) - { - assert(expr.operands().size()==2); - assert(expr.op0().id()==ID_symbol); - - const irep_idt &ident=expr.op0().get(ID_identifier); - quantified_symbols.insert(ident); - find_symbols(expr.op1()); - quantified_symbols.erase(ident); - } - else - forall_operands(it, expr) - find_symbols(*it); - - if(expr.id()==ID_symbol || - expr.id()==ID_nondet_symbol) - { - // we don't track function-typed symbols - if(type.id()==ID_code) - return; - - irep_idt identifier; - - if(expr.id()==ID_symbol) - identifier=to_symbol_expr(expr).get_identifier(); - else - identifier="nondet_"+ - id2string(to_nondet_symbol_expr(expr).get_identifier()); - - if(quantified_symbols.find(identifier)!=quantified_symbols.end()) - return; // Symbol is quantified, i.e., it doesn't require declaration. - - identifiert &id=identifier_map[identifier]; - - if(id.type.is_nil()) - { - id.type=type; - - if(id.type.id()==ID_bool) - { - out << ":extrapreds((" - << convert_identifier(identifier) - << "))" << "\n"; - } - else - { - out << ":extrafuns((" - << convert_identifier(identifier) - << " "; - convert_type(type); - out << "))" << "\n"; - } - } - } - else if(expr.id()==ID_array_of) - { - if(array_of_map.find(expr)==array_of_map.end()) - { - irep_idt id="array_of'"+std::to_string(array_of_map.size()); - out << "; the following is a poor substitute for lambda i. x" << "\n"; - out << ":extrafuns((" - << id - << " "; - convert_type(type); - out << "))" << "\n"; - - // we can initialize array_ofs if they have - // a constant size and a constant element - if(type.find(ID_size)!=get_nil_irep() && - expr.op0().id()==ID_constant) - { - const array_typet &array_type=to_array_type(type); - mp_integer size; - - if(!to_integer(array_type.size(), size)) - { - // since we can't use quantifiers, let's enumerate... - for(mp_integer i=0; i rec_stack; - find_symbols_rec(type, rec_stack); -} - -void smt1_convt::find_symbols_rec( - const typet &type, - std::set &recstack) -{ - if(type.id()==ID_array) - { - const array_typet &array_type=to_array_type(type); - find_symbols(array_type.size()); - find_symbols_rec(array_type.subtype(), recstack); - } - else if(type.id()==ID_struct || - type.id()==ID_union) - { - const struct_union_typet::componentst &components= - to_struct_union_type(type).components(); - - for(const auto &comp : components) - find_symbols_rec(comp.type(), recstack); - } - else if(type.id()==ID_code) - { - const code_typet::parameterst ¶meters= - to_code_type(type).parameters(); - - for(const auto ¶m : parameters) - find_symbols_rec(param.type(), recstack); - - find_symbols_rec(to_code_type(type).return_type(), recstack); - } - else if(type.id()==ID_pointer) - { - find_symbols_rec(type.subtype(), recstack); - } - else if(type.id()==ID_incomplete_array) - { - find_symbols_rec(type.subtype(), recstack); - } - else if(type.id()==ID_symbol) - { - const symbol_typet &st=to_symbol_type(type); - const irep_idt &id=st.get_identifier(); - - if(recstack.find(id)==recstack.end()) - { - recstack.insert(id); - find_symbols_rec(ns.follow(type), recstack); - } - } -} - -exprt smt1_convt::binary2struct( - const struct_typet &type, - const std::string &binary) const -{ - const struct_typet::componentst &components=type.components(); - - std::size_t total_width=boolbv_width(type); - - if(total_width==0) - throw "failed to get struct width"; - - struct_exprt e(type); - e.reserve_operands(components.size()); - - std::size_t index=binary.size(); - for(const auto &comp : components) - { - const typet &sub_type=ns.follow(comp.type()); - - std::size_t sub_size=boolbv_width(sub_type); - - if(sub_size==0) - throw "failed to get component width"; - - index-=sub_size; - std::string cval=binary.substr(index, sub_size); - - e.copy_to_operands(ce_value(sub_type, "", cval, true)); - } - - return e; -} - -exprt smt1_convt::binary2union( - const union_typet &type, - const std::string &binary) const -{ - std::size_t total_width=boolbv_width(type); - - if(total_width==0) - throw "failed to get union width"; - - const union_typet::componentst &components=type.components(); - - // Taking the first component should work. - // Maybe a better idea is to take a largest component - std::size_t component_nr=0; - - // construct a union expr - union_exprt e(type); - e.set_component_number(component_nr); - e.set_component_name(components[component_nr].get_name()); - - const typet &sub_type=ns.follow(components[component_nr].type()); - std::size_t comp_width=boolbv_width(sub_type); - assert(comp_width<=total_width); - - std::string cval=binary.substr(total_width-comp_width, comp_width); - e.op()=ce_value(sub_type, "", cval, true); - - return e; -} - -void smt1_convt::flatten_array(const exprt &op) -{ - const array_typet array_type=to_array_type(op.type()); - const typet &elem_type=array_type.subtype(); - const exprt &size=array_type.size(); - - if(size.id()!=ID_constant) - throw "non-constant size array cannot be flattened"; - - mp_integer sizei; - if(to_integer(size, sizei)) - throw "array with non-constant size"; - - std::size_t elem_width=boolbv_width(elem_type); - - if(elem_width==0) - throw "failed to get width of array subtype"; - - #if 0 - out << " (let (?fbv "; - convert_expr(op, true); - out << ")"; - #endif - - for(mp_integer i=1; i0); - - if(num_ops==1) - convert_expr(expr.op0(), bool_as_bv); - else - { - exprt::operandst::const_iterator it= - expr.operands().begin(); - - for(std::size_t i=0; i -#include - -#include - -#include -#include -#include - -class byte_extract_exprt; -class typecast_exprt; -class constant_exprt; -class index_exprt; -class member_exprt; - -class smt1_convt:public prop_convt -{ -public: - enum class solvert - { - GENERIC, - BOOLECTOR, - CVC3, - CVC4, - MATHSAT, - OPENSMT, - YICES, - Z3 - }; - - smt1_convt( - const namespacet &_ns, - const std::string &_benchmark, - const std::string &_source, - const std::string &_logic, - solvert _solver, - std::ostream &_out): - prop_convt(_ns), - benchmark(_benchmark), - source(_source), - logic(_logic), - solver(_solver), - out(_out), - boolbv_width(_ns), - pointer_logic(_ns), - array_index_bits(32), - no_boolean_variables(0) - { - write_header(); - } - - virtual ~smt1_convt() { } - virtual resultt dec_solve(); - - // overloading interfaces - virtual literalt convert(const exprt &expr); - virtual void set_to(const exprt &expr, bool value); - virtual exprt get(const exprt &expr) const; - virtual tvt l_get(literalt) const; - virtual std::string decision_procedure_text() const { return "SMT1"; } - virtual void print_assignment(std::ostream &out) const; - -protected: - std::string benchmark, source, logic; - solvert solver; - std::ostream &out; - boolbv_widtht boolbv_width; - - void write_header(); - void write_footer(); - - // new stuff - void convert_expr(const exprt &expr, bool bool_as_bv); - void convert_type(const typet &type); - - // specific expressions go here - void convert_byte_update(const exprt &expr, bool bool_as_bv); - void convert_byte_extract( - const byte_extract_exprt &expr, - bool bool_as_bv); - void convert_typecast(const typecast_exprt &expr, bool bool_as_bv); - void convert_struct(const exprt &expr); - void convert_union(const exprt &expr); - void convert_constant(const constant_exprt &expr, bool bool_as_bv); - void convert_relation(const exprt &expr, bool bool_as_bv); - void convert_is_dynamic_object(const exprt &expr, bool bool_as_bv); - void convert_plus(const plus_exprt &expr); - void convert_minus(const minus_exprt &expr); - void convert_div(const div_exprt &expr); - void convert_mult(const mult_exprt &expr); - void convert_floatbv_plus(const exprt &expr); - void convert_floatbv_minus(const exprt &expr); - void convert_floatbv_div(const exprt &expr); - void convert_floatbv_mult(const exprt &expr); - void convert_mod(const mod_exprt &expr); - void convert_index(const index_exprt &expr, bool bool_as_bv); - void convert_member(const member_exprt &expr, bool bool_as_bv); - void convert_overflow(const exprt &expr); - void convert_with(const exprt &expr); - void convert_update(const exprt &expr); - - std::string convert_identifier(const irep_idt &identifier); - void convert_literal(const literalt l); - - // auxiliary methods - std::set quantified_symbols; - void find_symbols(const exprt &expr); - void find_symbols(const typet &type); - void find_symbols_rec(const typet &type, std::set &recstack); - void flatten_array(const exprt &op); - - // booleans vs. bit-vector[1] - void from_bv_begin(const typet &type, bool bool_as_bv); - void from_bv_end(const typet &type, bool bool_as_bv); - void from_bool_begin(const typet &type, bool bool_as_bv); - void from_bool_end(const typet &type, bool bool_as_bv); - - // arrays - typet array_index_type() const; - void array_index(const exprt &expr); - - // pointers - pointer_logict pointer_logic; - void convert_address_of_rec( - const exprt &expr, const pointer_typet &result_type); - - // keeps track of all symbols - struct identifiert - { - typet type; - exprt value; - - identifiert() - { - type.make_nil(); - value.make_nil(); - } - }; - - void set_value( - identifiert &identifier, - const std::string &index, - const std::string &value) - { - exprt tmp=ce_value(identifier.type, index, value, false); - if(tmp.id() == ID_array_list && identifier.value.id() == ID_array_list) - { - forall_operands(it, tmp) - identifier.value.copy_to_operands(*it); - } - else - identifier.value=tmp; - } - - typedef std::unordered_map identifier_mapt; - - identifier_mapt identifier_map; - - unsigned array_index_bits; - - // for replacing 'array_of' expressions - typedef std::map array_of_mapt; - array_of_mapt array_of_map; - - // for replacing 'array' expressions - typedef std::map array_expr_mapt; - array_expr_mapt array_expr_map; - - // for replacing string constants - typedef std::map string2array_mapt; - string2array_mapt string2array_map; - - exprt ce_value( - const typet &type, - const std::string &index, - const std::string &v, - bool in_struct) const; - - exprt binary2struct( - const struct_typet &type, - const std::string &binary) const; - - exprt binary2union( - const union_typet &type, - const std::string &binary) const; - - // flattens multi-operand expressions into binary - // expressions - void convert_nary(const exprt &expr, - const irep_idt op_string, - bool bool_as_bv); - - // Boolean part - unsigned no_boolean_variables; - std::vector boolean_assignment; -}; - -#endif // CPROVER_SOLVERS_SMT1_SMT1_CONV_H diff --git a/src/solvers/smt1/smt1_dec.cpp b/src/solvers/smt1/smt1_dec.cpp deleted file mode 100644 index 807fa527339..00000000000 --- a/src/solvers/smt1/smt1_dec.cpp +++ /dev/null @@ -1,667 +0,0 @@ -/*******************************************************************\ - -Module: - -Author: Daniel Kroening, kroening@kroening.com - -\*******************************************************************/ - -#include "smt1_dec.h" - -#include - -#if defined(__linux__) || \ - defined(__FreeBSD_kernel__) || \ - defined(__GNU__) || \ - defined(__unix__) || \ - defined(__CYGWIN__) || \ - defined(__MACH__) -#include -#endif - -#include -#include -#include -#include -#include -#include - -std::string smt1_dect::decision_procedure_text() const -{ - return "SMT1 "+logic+" using "+ - (solver==solvert::GENERIC?"Generic": - solver==solvert::BOOLECTOR?"Boolector": - solver==solvert::CVC3?"CVC3": - solver==solvert::CVC4?"CVC3": - solver==solvert::MATHSAT?"MathSAT": - solver==solvert::OPENSMT?"OpenSMT": - solver==solvert::YICES?"Yices": - solver==solvert::Z3?"Z3": - "(unknown)"); -} - -smt1_temp_filet::smt1_temp_filet() -{ - temp_out_filename=get_temporary_file("smt1_dec_out_", ""); - - temp_out.open( - temp_out_filename.c_str(), - std::ios_base::out | std::ios_base::trunc); -} - -smt1_temp_filet::~smt1_temp_filet() -{ - temp_out.close(); - - if(temp_out_filename!="") - unlink(temp_out_filename.c_str()); - - if(temp_result_filename!="") - unlink(temp_result_filename.c_str()); -} - -decision_proceduret::resultt smt1_dect::dec_solve() -{ - // SMT1 is really not incremental - assert(!dec_solve_was_called); - dec_solve_was_called=true; - - // this closes the SMT benchmark - write_footer(); - temp_out.close(); - - temp_result_filename= - get_temporary_file("smt1_dec_result_", ""); - - std::string command; - - switch(solver) - { - case solvert::BOOLECTOR: - // -rwl0 disables rewriting, which makes things slower, - // but in return values for arrays appear - // command = "boolector -rwl0 --smt " - // Removed as not necessarily needed on newer versions - command = "boolector --smt " - + temp_out_filename - + " --model --output " - + temp_result_filename; - break; - - case solvert::CVC3: - command = "cvc3 +model -lang smtlib -output-lang smtlib " - + temp_out_filename - + " > " - + temp_result_filename; - break; - - case solvert::CVC4: - command = "cvc4 -L smt1 " - + temp_out_filename - + " > " - + temp_result_filename; - break; - - case solvert::MATHSAT: - command = "mathsat -model -input=smt" - " < "+temp_out_filename - + " > "+temp_result_filename; - break; - - case solvert::OPENSMT: - command = "opensmt " - + temp_out_filename - + " > " - + temp_result_filename; - break; - - case solvert::YICES: - // command = "yices -smt -e " // Calling convention for older versions - command = "yices-smt --full-model " // Calling for 2.2.1 - + temp_out_filename - + " > " - + temp_result_filename; - break; - - case solvert::Z3: - command = "z3 -smt " - + temp_out_filename - + " > " - + temp_result_filename; - break; - - default: - assert(false); - } - - #if defined(__linux__) || defined(__APPLE__) - command+=" 2>&1"; - #endif - - int res=system(command.c_str()); - if(res<0) - { - error() << "error running SMT1 solver" << eom; - return decision_proceduret::resultt::D_ERROR; - } - - std::ifstream in(temp_result_filename.c_str()); - - switch(solver) - { - case solvert::BOOLECTOR: - return read_result_boolector(in); - - case solvert::CVC3: - return read_result_cvc3(in); - - case solvert::CVC4: - error() << "no support for CVC4 with SMT1, use SMT2 instead" << eom; - return decision_proceduret::resultt::D_ERROR; - - case solvert::MATHSAT: - return read_result_mathsat(in); - - case solvert::OPENSMT: - return read_result_opensmt(in); - - case solvert::YICES: - return read_result_yices(in); - - case solvert::Z3: - return read_result_z3(in); - - case solvert::GENERIC: - default: - error() << "Generic solver can't solve" << eom; - return decision_proceduret::resultt::D_ERROR; - } -} - -/// read model produced by Boolector -decision_proceduret::resultt smt1_dect::read_result_boolector(std::istream &in) -{ - std::string line; - - std::getline(in, line); - - if(line=="sat") - { - boolean_assignment.clear(); - boolean_assignment.resize(no_boolean_variables, false); - - typedef std::unordered_map valuest; - valuest values; - - while(std::getline(in, line)) - { - std::size_t pos=line.find(' '); - if(pos!=std::string::npos && pos!=0) - { - std::string id=std::string(line, 0, pos); - std::string value=std::string(line, pos+1, std::string::npos); - - // Boolector offers array values as follows: - // - // ID[INDEX] VALUE - // - // There may be more than one line per ID - - if(id!="" && id[id.size()-1]==']') // array? - { - std::size_t pos2=id.find('['); - - if(pos2!=std::string::npos) - { - std::string new_id=std::string(id, 0, pos2); - std::string index=std::string(id, pos2+1, id.size()-pos2-2); - values[new_id].index_value_map[index]=value; - } - } - else - values[id].value=value; - } - } - - // Theory variables - - for(identifier_mapt::iterator - it=identifier_map.begin(); - it!=identifier_map.end(); - it++) - { - it->second.value.make_nil(); - std::string conv_id=convert_identifier(it->first); - const valuet &v=values[conv_id]; - - for(valuet::index_value_mapt::const_iterator - i_it=v.index_value_map.begin(); i_it!=v.index_value_map.end(); i_it++) - set_value(it->second, i_it->first, i_it->second); - - if(v.value!="") - set_value(it->second, "", v.value); - } - - // Booleans - - for(unsigned v=0; v valuest; - valuest values; - - while(std::getline(in, line)) - { - if(line=="sat") - res=resultt::D_SATISFIABLE; - else if(line=="unsat") - res=resultt::D_UNSATISFIABLE; - else if(line.size()>=1 && line[0]=='(') - { - // (iff B0 true) - // (= c_h39__h39___CPROVER_malloc_size_h39_35_h39_1 bv0[64]) - // (= (select __h64_0 bv0[32]) bv5[8]) - std::size_t pos1=line.find(' '); - std::size_t pos2=line.rfind(' '); - if(pos1!=std::string::npos && - pos2!=std::string::npos && - pos1!=pos2) - { - std::string id=std::string(line, pos1+1, pos2-pos1-1); - std::string value=std::string(line, pos2+1, line.size()-pos2-2); - - if(has_prefix(id, "(select ")) - { - #if 0 - std::size_t pos3=id.rfind(' '); - std::string index=std::string(pos3+1, id.size()-pos3-1); - id=std::string(id, 8, pos3-8); - #endif - } - else - values[id].value=value; - } - } - } - - for(identifier_mapt::iterator - it=identifier_map.begin(); - it!=identifier_map.end(); - it++) - { - it->second.value.make_nil(); - std::string conv_id=convert_identifier(it->first); - std::string value=mathsat_value(values[conv_id].value); - - if(value!="") - set_value(it->second, "", value); - } - - // Booleans - for(unsigned v=0; v valuest; - valuest values; - - while(std::getline(in, line)) - { - if(line=="sat") - res = resultt::D_SATISFIABLE; - else if(line=="unsat") - res = resultt::D_UNSATISFIABLE; - else - { - std::size_t pos=line.find(" -> "); - if(pos!=std::string::npos) - values[std::string(line, 0, pos)]= - std::string(line, pos+4, std::string::npos); - } - } - - for(identifier_mapt::iterator - it=identifier_map.begin(); - it!=identifier_map.end(); - it++) - { - it->second.value.make_nil(); - std::string conv_id=convert_identifier(it->first); - std::string value=values[conv_id]; - if(value=="") - continue; - - exprt e; - if(string_to_expr_z3(it->second.type, value, e)) - it->second.value=e; - else - set_value(it->second, "", value); - } - - // Booleans - for(unsigned v=0; vsecond!=id) fit++; - - if(fit==array_of_map.end()) - return false; - - e = fit->first; - - return true; - } - else if(type.id()==ID_rational) - { - constant_exprt result; - result.type()=rational_typet(); - - if(value.substr(0, 4)=="val!") - result.set_value(value.substr(4)); - else - result.set_value(value); - - e = result; - return true; - } - - return false; -} - -decision_proceduret::resultt smt1_dect::read_result_cvc3(std::istream &in) -{ - std::string line; - decision_proceduret::resultt res = resultt::D_ERROR; - - boolean_assignment.clear(); - boolean_assignment.resize(no_boolean_variables, false); - - typedef std::unordered_map valuest; - valuest values; - - while(std::getline(in, line)) - { - if(line=="sat") - res = resultt::D_SATISFIABLE; - else if(line=="unsat") - res = resultt::D_UNSATISFIABLE; - else if(line.find("Current scope level")!=std::string::npos || - line.find("Variable Assignment")!=std::string::npos) - { - // ignore - } - else - { - assert(line.substr(0, 13)==" :assumption"); - std::size_t pos=line.find('('); - - if(pos!=std::string::npos) - { - std::string var; - std::string val; - - if(line[pos+1]=='=') - { - std::string ops = line.substr(pos+3, line.length()-pos-4); - std::size_t blank=ops.find(' '); - var = ops.substr(0, blank); - val = ops.substr(blank+1, ops.length()-blank); - - if((var.length()>=4 && var.substr(0, 4)=="cvc3") || - (val.length()>=4 && val.substr(0, 4)=="cvc3") || - var==val) - continue; - else if((var.substr(0, 9)=="array_of'") || - (var.substr(0, 2)=="bv" && val.substr(0, 2)!="bv")) - { - std::string t=var; var=val; val=t; - } - } - else if(line.substr(pos+1, 3)=="not") - { - var = line.substr(pos+5, line.length()-pos-6); - val = "false"; - } - else - { - var = line.substr(pos+1, line.length()-pos-2); - assert(var.find(' ')==std::string::npos); - val = "true"; - } - - values[var]=val; - } - } - } - - for(identifier_mapt::iterator - it=identifier_map.begin(); - it!=identifier_map.end(); - it++) - { - it->second.value.make_nil(); - std::string conv_id=convert_identifier(it->first); - std::string value=values[conv_id]; - if(value=="") - continue; - - if(value.substr(0, 2)=="bv") - { - std::string v=value.substr(2, value.find('[')-2); - size_t p = value.find('[')+1; - std::string w=value.substr(p, value.find(']')-p); - - std::string binary= - integer2binary( - string2integer(v, 10), - integer2unsigned(string2integer(w, 10))); - - set_value(it->second, "", binary); - } - else if(value=="false") - it->second.value=false_exprt(); - else if(value=="true") - it->second.value=true_exprt(); - else if(value.substr(0, 8)=="array_of") - { - // We assume that array_of has only concrete arguments... - irep_idt id(value); - array_of_mapt::const_iterator fit=array_of_map.begin(); - while(fit!=array_of_map.end() && fit->second!=id) fit++; - - if(fit!=array_of_map.end()) - it->second.value = fit->first; - } - else - set_value(it->second, "", value); - } - - // Booleans - for(unsigned v=0; v - -#include "smt1_conv.h" - -class smt1_temp_filet -{ -public: - smt1_temp_filet(); - ~smt1_temp_filet(); - -protected: - std::ofstream temp_out; - std::string temp_out_filename, temp_result_filename; -}; - -/*! \brief Decision procedure interface for various SMT 1.x solvers -*/ -class smt1_dect:protected smt1_temp_filet, public smt1_convt -{ -public: - smt1_dect( - const namespacet &_ns, - const std::string &_benchmark, - const std::string &_source, - const std::string &_logic, - solvert _solver): - smt1_temp_filet(), - smt1_convt(_ns, _benchmark, _source, _logic, _solver, temp_out), - logic(_logic), - dec_solve_was_called(false) - { - } - - virtual resultt dec_solve(); - virtual std::string decision_procedure_text() const; - -protected: - std::string logic; - bool dec_solve_was_called; - - resultt read_result_boolector(std::istream &in); - resultt read_result_cvc3(std::istream &in); - resultt read_result_opensmt(std::istream &in); - resultt read_result_mathsat(std::istream &in); - resultt read_result_yices(std::istream &in); - resultt read_result_z3(std::istream &in); - - bool string_to_expr_z3( - const typet &type, - const std::string &value, exprt &e) const; - - std::string mathsat_value(const std::string &src); - - struct valuet - { - // map from array index to value - typedef std::map index_value_mapt; - index_value_mapt index_value_map; - std::string value; - }; -}; - -#endif // CPROVER_SOLVERS_SMT1_SMT1_DEC_H diff --git a/src/solvers/smt2/smt2_conv.cpp b/src/solvers/smt2/smt2_conv.cpp index 03bd1dc736f..9e46d45c67a 100644 --- a/src/solvers/smt2/smt2_conv.cpp +++ b/src/solvers/smt2/smt2_conv.cpp @@ -78,7 +78,6 @@ void smt2_convt::write_header() case solvert::CVC3: out << "; Generated for CVC 3\n"; break; case solvert::CVC4: out << "; Generated for CVC 4\n"; break; case solvert::MATHSAT: out << "; Generated for MathSAT\n"; break; - case solvert::OPENSMT: out << "; Generated for OPENSMT\n"; break; case solvert::YICES: out << "; Generated for Yices\n"; break; case solvert::Z3: out << "; Generated for Z3\n"; break; } diff --git a/src/solvers/smt2/smt2_conv.h b/src/solvers/smt2/smt2_conv.h index 665b747b58c..41d8564050b 100644 --- a/src/solvers/smt2/smt2_conv.h +++ b/src/solvers/smt2/smt2_conv.h @@ -35,7 +35,6 @@ class smt2_convt:public prop_convt CVC3, CVC4, MATHSAT, - OPENSMT, YICES, Z3 }; @@ -82,9 +81,6 @@ class smt2_convt:public prop_convt case solvert::MATHSAT: break; - case solvert::OPENSMT: - break; - case solvert::YICES: break; diff --git a/src/solvers/smt2/smt2_dec.cpp b/src/solvers/smt2/smt2_dec.cpp index 63bd0afaeca..e303701d26c 100644 --- a/src/solvers/smt2/smt2_dec.cpp +++ b/src/solvers/smt2/smt2_dec.cpp @@ -37,7 +37,6 @@ std::string smt2_dect::decision_procedure_text() const solver==solvert::CVC3?"CVC3": solver==solvert::CVC4?"CVC4": solver==solvert::MATHSAT?"MathSAT": - solver==solvert::OPENSMT?"OpenSMT": solver==solvert::YICES?"Yices": solver==solvert::Z3?"Z3": "(unknown)"); @@ -126,14 +125,6 @@ decision_proceduret::resultt smt2_dect::dec_solve() + " > "+smt2_temp_file.temp_result_filename; break; - case solvert::OPENSMT: - command = "opensmt " - + smt2_temp_file.temp_out_filename - + " > " - + smt2_temp_file.temp_result_filename; - break; - - case solvert::YICES: // command = "yices -smt -e " // Calling convention for older versions command = "yices-smt2 " // Calling for 2.2.1 diff --git a/src/solvers/smt2/smt2_parser.cpp b/src/solvers/smt2/smt2_parser.cpp index 39bb7c0d519..d52bb8eafa1 100644 --- a/src/solvers/smt2/smt2_parser.cpp +++ b/src/solvers/smt2/smt2_parser.cpp @@ -774,7 +774,7 @@ exprt smt2_parsert::function_application() } else if(id=="rotate_left" || id=="rotate_right" || - id=="repeat" || + id == ID_repeat || id=="sign_extend" || id=="zero_extend") { @@ -826,7 +826,7 @@ exprt smt2_parsert::function_application() return typecast_exprt(op[0], unsigned_type); } - else if(id=="repeat") + else if(id == ID_repeat) { return nil_exprt(); } diff --git a/src/util/Makefile b/src/util/Makefile index cb9d221dd60..74fc5aec412 100644 --- a/src/util/Makefile +++ b/src/util/Makefile @@ -96,6 +96,7 @@ SRC = arith_tools.cpp \ unicode.cpp \ union_find.cpp \ union_find_replace.cpp \ + unwrap_nested_exception.cpp \ xml.cpp \ xml_expr.cpp \ xml_irep.cpp \ diff --git a/src/util/base_type.cpp b/src/util/base_type.cpp index 62d40ad32e5..d32a2836aaf 100644 --- a/src/util/base_type.cpp +++ b/src/util/base_type.cpp @@ -11,12 +11,44 @@ Author: Daniel Kroening, kroening@kroening.com #include "base_type.h" -#include #include -#include "std_types.h" #include "namespace.h" +#include "std_types.h" #include "symbol.h" +#include "union_find.h" + +class base_type_eqt +{ +public: + explicit base_type_eqt(const namespacet &_ns):ns(_ns) + { + } + + bool base_type_eq(const typet &type1, const typet &type2) + { + identifiers.clear(); + return base_type_eq_rec(type1, type2); + } + + bool base_type_eq(const exprt &expr1, const exprt &expr2) + { + identifiers.clear(); + return base_type_eq_rec(expr1, expr2); + } + + virtual ~base_type_eqt() { } + +protected: + const namespacet &ns; + + virtual bool base_type_eq_rec(const typet &type1, const typet &type2); + virtual bool base_type_eq_rec(const exprt &expr1, const exprt &expr2); + + // for loop avoidance + typedef union_find identifierst; + identifierst identifiers; +}; void base_type_rec( typet &type, const namespacet &ns, std::set &symb) diff --git a/src/util/base_type.h b/src/util/base_type.h index 833fd855cca..6315ac09542 100644 --- a/src/util/base_type.h +++ b/src/util/base_type.h @@ -12,9 +12,6 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_UTIL_BASE_TYPE_H #define CPROVER_UTIL_BASE_TYPE_H -#include "union_find.h" -#include "irep.h" - class exprt; class typet; class namespacet; @@ -29,36 +26,4 @@ bool base_type_eq( const exprt &expr2, const namespacet &ns); -class base_type_eqt -{ -public: - explicit base_type_eqt(const namespacet &_ns):ns(_ns) - { - } - - bool base_type_eq(const typet &type1, const typet &type2) - { - identifiers.clear(); - return base_type_eq_rec(type1, type2); - } - - bool base_type_eq(const exprt &expr1, const exprt &expr2) - { - identifiers.clear(); - return base_type_eq_rec(expr1, expr2); - } - - virtual ~base_type_eqt() { } - -protected: - const namespacet &ns; - - virtual bool base_type_eq_rec(const typet &type1, const typet &type2); - virtual bool base_type_eq_rec(const exprt &expr1, const exprt &expr2); - - // for loop avoidance - typedef union_find identifierst; - identifierst identifiers; -}; - #endif // CPROVER_UTIL_BASE_TYPE_H diff --git a/src/util/cmdline.cpp b/src/util/cmdline.cpp index 9477d8d4a6c..b022fdce78d 100644 --- a/src/util/cmdline.cpp +++ b/src/util/cmdline.cpp @@ -26,92 +26,114 @@ void cmdlinet::clear() bool cmdlinet::isset(char option) const { - int i=getoptnr(option); - if(i<0) + auto i=getoptnr(option); + if(i.has_value()) + return options[*i].isset; + else return false; - return options[i].isset; } bool cmdlinet::isset(const char *option) const { - int i=getoptnr(option); - if(i<0) + auto i=getoptnr(option); + if(i.has_value()) + return options[*i].isset; + else return false; - return options[i].isset; } std::string cmdlinet::get_value(char option) const { - int i=getoptnr(option); - if(i<0) - return ""; - if(options[i].values.empty()) + auto i=getoptnr(option); + + if(i.has_value()) + { + if(options[*i].values.empty()) + return ""; + else + return options[*i].values.front(); + } + else return ""; - return options[i].values.front(); } void cmdlinet::set(const std::string &option) { - int i=getoptnr(option); - if(i<0) - return; // ignore - options[i].isset=true; + auto i=getoptnr(option); + + if(i.has_value()) + options[*i].isset=true; + + // otherwise ignore } void cmdlinet::set(const std::string &option, const std::string &value) { - int i=getoptnr(option); - if(i<0) - return; // ignore - options[i].isset=true; - options[i].values.push_back(value); + auto i=getoptnr(option); + + if(i.has_value()) + { + options[*i].isset=true; + options[*i].values.push_back(value); + } + + // otherwise ignore } static std::list immutable_empty_list; const std::list &cmdlinet::get_values(char option) const { - int i=getoptnr(option); - if(i<0) + auto i=getoptnr(option); + + if(i.has_value()) + return options[*i].values; + else return immutable_empty_list; - return options[i].values; } std::string cmdlinet::get_value(const char *option) const { - int i=getoptnr(option); - if(i<0) - return ""; - if(options[i].values.empty()) + auto i=getoptnr(option); + + if(i.has_value()) + { + if(options[*i].values.empty()) + return ""; + else + return options[*i].values.front(); + } + else return ""; - return options[i].values.front(); } const std::list &cmdlinet::get_values( const std::string &option) const { - int i=getoptnr(option); - if(i<0) + auto i=getoptnr(option); + + if(i.has_value()) + return options[*i].values; + else return immutable_empty_list; - return options[i].values; } -int cmdlinet::getoptnr(char option) const +optionalt cmdlinet::getoptnr(char option) const { for(std::size_t i=0; i(); } -int cmdlinet::getoptnr(const std::string &option) const +optionalt cmdlinet::getoptnr(const std::string &option) const { for(std::size_t i=0; i(); } bool cmdlinet::parse(int argc, const char **argv, const char *optstring) @@ -165,7 +187,7 @@ bool cmdlinet::parse(int argc, const char **argv, const char *optstring) args.push_back(argv[i]); else { - int optnr; + optionalt optnr; if(argv[i][1]!=0 && argv[i][2]==0) optnr=getoptnr(argv[i][1]); // single-letter option -X @@ -177,29 +199,31 @@ bool cmdlinet::parse(int argc, const char **argv, const char *optstring) // We first try single-letter. optnr=getoptnr(argv[i][1]); - if(optnr<0) // try multi-letter + if(!optnr.has_value()) // try multi-letter optnr=getoptnr(argv[i]+1); } - if(optnr<0) + if(!optnr.has_value()) { unknown_arg=argv[i]; return true; } - options[optnr].isset=true; - if(options[optnr].hasval) + + options[*optnr].isset=true; + + if(options[*optnr].hasval) { - if(argv[i][2]==0 || options[optnr].islong) + if(argv[i][2]==0 || options[*optnr].islong) { i++; if(i==argc) return true; if(argv[i][0]=='-' && argv[i][1]!=0) return true; - options[optnr].values.push_back(argv[i]); + options[*optnr].values.push_back(argv[i]); } else - options[optnr].values.push_back(argv[i]+2); + options[*optnr].values.push_back(argv[i]+2); } } } diff --git a/src/util/cmdline.h b/src/util/cmdline.h index 2d58daa8d44..b395e024f7f 100644 --- a/src/util/cmdline.h +++ b/src/util/cmdline.h @@ -14,6 +14,8 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include "optional.h" + class cmdlinet { public: @@ -53,13 +55,13 @@ class cmdlinet hasval(false), islong(false), optchar(0) - {} + {} }; std::vector options; - int getoptnr(char option) const; - int getoptnr(const std::string &option) const; + optionalt getoptnr(char option) const; + optionalt getoptnr(const std::string &option) const; }; #endif // CPROVER_UTIL_CMDLINE_H diff --git a/src/util/fresh_symbol.cpp b/src/util/fresh_symbol.cpp index 0f7c3a9daf2..c77c7e33e47 100644 --- a/src/util/fresh_symbol.cpp +++ b/src/util/fresh_symbol.cpp @@ -13,6 +13,8 @@ Author: Chris Smowton, chris.smowton@diffblue.com #include "namespace.h" #include "rename.h" +#include "symbol.h" +#include "symbol_table_base.h" /// Installs a fresh-named symbol with the requested name pattern /// \par parameters: `type`: type of new symbol diff --git a/src/util/fresh_symbol.h b/src/util/fresh_symbol.h index 8cdedc56977..0d1601ad180 100644 --- a/src/util/fresh_symbol.h +++ b/src/util/fresh_symbol.h @@ -14,10 +14,12 @@ Author: Chris Smowton, chris.smowton@diffblue.com #include -#include -#include -#include -#include +#include "irep.h" + +class source_locationt; +class symbolt; +class symbol_table_baset; +class typet; symbolt &get_fresh_aux_symbol( const typet &type, diff --git a/src/util/graph.h b/src/util/graph.h index 45530f09ef6..6b7fd6e07f7 100644 --- a/src/util/graph.h +++ b/src/util/graph.h @@ -12,15 +12,15 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_UTIL_GRAPH_H #define CPROVER_UTIL_GRAPH_H +#include +#include +#include +#include #include -#include #include -#include -#include -#include -#include #include -#include +#include +#include #include "invariant.h" @@ -486,7 +486,7 @@ void get_reachable( { auto n = stack.back(); stack.pop_back(); - for_each_successor(n, [&](const nodet &node) { // NOLINT + for_each_successor(n, [&](const nodet &node) { if(set.insert(node).second) stack.push_back(node); }); @@ -749,8 +749,8 @@ void output_dot_generic( &for_each_succ, const std::function node_to_string) { - for_each_node([&](const node_index_type &i) { // NOLINT - for_each_succ(i, [&](const node_index_type &n) { // NOLINT + for_each_node([&](const node_index_type &i) { + for_each_succ(i, [&](const node_index_type &n) { out << node_to_string(i) << " -> " << node_to_string(n) << '\n'; }); }); @@ -784,14 +784,13 @@ template void grapht::output_dot(std::ostream &out) const { const auto for_each_node = - [&](const std::function &f) { // NOLINT + [&](const std::function &f) { for(node_indext i = 0; i < nodes.size(); ++i) f(i); }; const auto for_each_succ = [&]( - const node_indext &i, - const std::function &f) { // NOLINT + const node_indext &i, const std::function &f) { for_each_successor(i, f); }; diff --git a/src/util/invariant_utils.h b/src/util/invariant_utils.h index d448fedfeb3..3dd9d386418 100644 --- a/src/util/invariant_utils.h +++ b/src/util/invariant_utils.h @@ -10,8 +10,7 @@ Author: Chris Smowton, chris.smowton@diffblue.com #define CPROVER_UTIL_INVARIANT_TYPES_H #include "invariant.h" - -#include +#include "irep.h" #include diff --git a/src/util/irep.h b/src/util/irep.h index fbaf0ad5a94..2365989bfaa 100644 --- a/src/util/irep.h +++ b/src/util/irep.h @@ -12,8 +12,6 @@ Author: Daniel Kroening, kroening@kroening.com #include #include -#include -#include #include "irep_ids.h" diff --git a/src/util/irep_hash_container.h b/src/util/irep_hash_container.h index 382130659e0..65342ba99b1 100644 --- a/src/util/irep_hash_container.h +++ b/src/util/irep_hash_container.h @@ -12,7 +12,6 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_UTIL_IREP_HASH_CONTAINER_H #define CPROVER_UTIL_IREP_HASH_CONTAINER_H -#include // for size_t #include #include "numbering.h" @@ -22,7 +21,7 @@ class irept; class irep_hash_container_baset { public: - size_t number(const irept &irep); + std::size_t number(const irept &irep); explicit irep_hash_container_baset(bool _full):full(_full) { @@ -41,23 +40,23 @@ class irep_hash_container_baset struct pointer_hasht { - size_t operator()(const void *p) const + std::size_t operator()(const void *p) const { - return (size_t)p; + return (std::size_t)p; } }; - typedef std::unordered_map + typedef std::unordered_map ptr_hasht; ptr_hasht ptr_hash; // this is the second level: content - typedef std::vector packedt; + typedef std::vector packedt; struct vector_hasht { - size_t operator()(const packedt &p) const; + std::size_t operator()(const packedt &p) const; }; typedef hash_numbering numberingt; diff --git a/src/util/irep_ids.cpp b/src/util/irep_ids.cpp index 5151cd92fed..5a6bc4e525d 100644 --- a/src/util/irep_ids.cpp +++ b/src/util/irep_ids.cpp @@ -27,6 +27,14 @@ const char *irep_ids_table[]= #ifdef USE_DSTRING +enum class idt:unsigned +{ +#define IREP_ID_ONE(the_id) id_##the_id, +#define IREP_ID_TWO(the_id, str) id_##the_id, + +#include "irep_ids.def" // NOLINT(build/include) +}; + #define IREP_ID_ONE(the_id) \ const dstringt ID_##the_id=dstringt::make_from_table_index( \ static_cast(idt::id_##the_id)); diff --git a/src/util/irep_ids.def b/src/util/irep_ids.def index 4f68f78051c..78ff9b00e16 100644 --- a/src/util/irep_ids.def +++ b/src/util/irep_ids.def @@ -1,4 +1,5 @@ -/// \file List of irep id names and values. +/// \file +/// List of irep id names and values. /// For an explanation of how this works, see irep_ids.h. IREP_ID_TWO(empty_string, ) @@ -34,7 +35,6 @@ IREP_ID_ONE(dynamic_cast) IREP_ID_ONE(const_cast) IREP_ID_ONE(reinterpret_cast) IREP_ID_ONE(index) -IREP_ID_ONE(index_range) IREP_ID_ONE(ptrmember) IREP_ID_ONE(member) IREP_ID_ONE(member_name) @@ -47,7 +47,6 @@ IREP_ID_ONE(nand) IREP_ID_ONE(or) IREP_ID_ONE(nor) IREP_ID_ONE(xor) -IREP_ID_ONE(xnor) IREP_ID_ONE(not) IREP_ID_ONE(bitand) IREP_ID_ONE(bitor) @@ -61,7 +60,6 @@ IREP_ID_ONE(if) IREP_ID_ONE(symbol) IREP_ID_ONE(next_symbol) IREP_ID_ONE(nondet_symbol) -IREP_ID_ONE(predicate) IREP_ID_ONE(predicate_symbol) IREP_ID_ONE(predicate_next_symbol) IREP_ID_ONE(nondet_bool) @@ -148,13 +146,6 @@ IREP_ID_ONE(range) IREP_ID_ONE(from) IREP_ID_ONE(to) IREP_ID_ONE(module) -IREP_ID_ONE(module_instance) -IREP_ID_ONE(macromodule) -IREP_ID_ONE(primitive_module_instance) -IREP_ID_ONE(module_items) -IREP_ID_ONE(module_source) -IREP_ID_ONE(parameter_decl) -IREP_ID_ONE(local_parameter_decl) IREP_ID_ONE(parameter) IREP_ID_ONE(component_name) IREP_ID_ONE(component_number) @@ -170,13 +161,9 @@ IREP_ID_ONE(width) IREP_ID_ONE(components) IREP_ID_ONE(bv) IREP_ID_ONE(f) -IREP_ID_ONE(ports) -IREP_ID_ONE(port) -IREP_ID_ONE(offset) IREP_ID_ONE(with) IREP_ID_ONE(trans) IREP_ID_ONE(throw) -IREP_ID_ONE(catch) IREP_ID_ONE(try_catch) IREP_ID_ONE(noexcept) IREP_ID_ONE(CPROVER_throw) @@ -193,7 +180,6 @@ IREP_ID_ONE(constexpr) IREP_ID_ONE(inline) IREP_ID_ONE(forall) IREP_ID_ONE(exists) -IREP_ID_ONE(forever) IREP_ID_ONE(repeat) IREP_ID_ONE(extractbit) IREP_ID_ONE(extractbits) @@ -222,8 +208,6 @@ IREP_ID_ONE(java_string_literal) IREP_ID_ONE(printf) IREP_ID_ONE(input) IREP_ID_ONE(output) -IREP_ID_ONE(output_register) -IREP_ID_ONE(inout) IREP_ID_ONE(nondet) IREP_ID_ONE(NULL) IREP_ID_ONE(null) @@ -280,7 +264,6 @@ IREP_ID_ONE(ptr64) IREP_ID_ONE(char) IREP_ID_ONE(short) IREP_ID_ONE(long) -IREP_ID_ONE(longlong) IREP_ID_ONE(float) IREP_ID_ONE(double) IREP_ID_ONE(byte) @@ -299,9 +282,6 @@ IREP_ID_ONE(unsigned_long_long_int) IREP_ID_ONE(signed_int128) IREP_ID_ONE(unsigned_int128) IREP_ID_ONE(case) -IREP_ID_ONE(casex) -IREP_ID_ONE(casez) -IREP_ID_ONE(case_item) IREP_ID_TWO(C_inlined, #inlined) IREP_ID_TWO(C_hide, #hide) IREP_ID_ONE(hide) @@ -322,22 +302,6 @@ IREP_ID_ONE(bv_literals) IREP_ID_ONE(isfinite) IREP_ID_ONE(isinf) IREP_ID_ONE(isnormal) -IREP_ID_ONE(AG) -IREP_ID_ONE(AF) -IREP_ID_ONE(AX) -IREP_ID_ONE(EG) -IREP_ID_ONE(EF) -IREP_ID_ONE(EX) -IREP_ID_ONE(U) -IREP_ID_ONE(R) -IREP_ID_ONE(A) -IREP_ID_ONE(F) -IREP_ID_ONE(E) -IREP_ID_ONE(G) -IREP_ID_ONE(X) -IREP_ID_ONE(continuous_assign) -IREP_ID_ONE(blocking_assign) -IREP_ID_ONE(non_blocking_assign) IREP_ID_ONE(alignof) IREP_ID_ONE(clang_builtin_convertvector) IREP_ID_ONE(gcc_builtin_va_arg) @@ -353,11 +317,6 @@ IREP_ID_ONE(gcc_decimal128) IREP_ID_ONE(builtin_offsetof) IREP_ID_ONE(0) IREP_ID_ONE(1) -IREP_ID_ONE(8) -IREP_ID_ONE(16) -IREP_ID_ONE(32) -IREP_ID_ONE(64) -IREP_ID_ONE(128) IREP_ID_ONE(sizeof) IREP_ID_ONE(type_arg) IREP_ID_ONE(expr_arg) @@ -382,11 +341,9 @@ IREP_ID_TWO(mult, *) IREP_ID_TWO(div, /) IREP_ID_TWO(power, **) IREP_ID_ONE(factorial_power) -IREP_ID_ONE(component) IREP_ID_ONE(pretty_name) IREP_ID_TWO(C_class, #class) IREP_ID_TWO(C_interface, #interface) -IREP_ID_ONE(interface) IREP_ID_ONE(targets) IREP_ID_ONE(location) IREP_ID_ONE(labels) @@ -396,7 +353,6 @@ IREP_ID_ONE(designated_initializer) IREP_ID_ONE(designator) IREP_ID_ONE(member_designator) IREP_ID_ONE(index_designator) -IREP_ID_ONE(offset_designator) IREP_ID_TWO(C_constant, #constant) IREP_ID_TWO(C_volatile, #volatile) IREP_ID_TWO(C_restricted, #restricted) @@ -411,7 +367,6 @@ IREP_ID_ONE(byte_extract_little_endian) IREP_ID_ONE(byte_update_big_endian) IREP_ID_ONE(byte_update_little_endian) IREP_ID_ONE(replication) -IREP_ID_ONE(dummy) IREP_ID_ONE(init) IREP_ID_ONE(cprover_atomic) IREP_ID_ONE(atomic) @@ -424,18 +379,10 @@ IREP_ID_ONE(specc_notify) IREP_ID_ONE(specc_par) IREP_ID_ONE(specc_wait) IREP_ID_ONE(specc_event) -IREP_ID_ONE(bp_enforce) -IREP_ID_ONE(bp_abortif) -IREP_ID_ONE(bp_constrain) -IREP_ID_ONE(bp_schoose) -IREP_ID_ONE(bp_dead) -IREP_ID_ONE(instance) -IREP_ID_ONE(cover) IREP_ID_ONE(coverage_criterion) IREP_ID_ONE(initializer) IREP_ID_ONE(anonymous) IREP_ID_TWO(C_is_anonymous, #is_anonymous) -IREP_ID_ONE(is_macro) IREP_ID_ONE(is_enum_constant) IREP_ID_ONE(is_inline) IREP_ID_ONE(is_extern) @@ -475,34 +422,14 @@ IREP_ID_ONE(typename) IREP_ID_ONE(C) IREP_ID_ONE(cpp) IREP_ID_ONE(java) -IREP_ID_ONE(SpecC) -IREP_ID_ONE(SystemC) IREP_ID_ONE(decl_block) IREP_ID_ONE(decl_type) -IREP_ID_ONE(genvar) -IREP_ID_ONE(realtime) IREP_ID_ONE(parameters) -IREP_ID_ONE(parameter_assignments) -IREP_ID_ONE(named_parameter_assignment) -IREP_ID_ONE(specify) -IREP_ID_ONE(pullup) -IREP_ID_ONE(pulldown) -IREP_ID_ONE(automatic) -IREP_ID_ONE(rcmos) -IREP_ID_ONE(cmos) -IREP_ID_ONE(nmos) -IREP_ID_ONE(pmos) -IREP_ID_ONE(rnmos) -IREP_ID_ONE(rpmos) IREP_ID_ONE(wchar_t) IREP_ID_ONE(char16_t) IREP_ID_ONE(char32_t) IREP_ID_ONE(size_t) IREP_ID_ONE(ssize_t) -IREP_ID_ONE(inst) -IREP_ID_ONE(inst_builtin) -IREP_ID_ONE(always) -IREP_ID_ONE(initial) IREP_ID_ONE(mode) IREP_ID_ONE(this) IREP_ID_TWO(C_this, #this) @@ -514,7 +441,6 @@ IREP_ID_ONE(reduction_xor) IREP_ID_ONE(reduction_xnor) IREP_ID_TWO(C_zero_initializer, #zero_initializer) IREP_ID_ONE(body) -IREP_ID_ONE(entity) IREP_ID_ONE(temporary_object) IREP_ID_TWO(overflow_plus, overflow-+) IREP_ID_TWO(overflow_minus, overflow--) @@ -531,10 +457,7 @@ IREP_ID_ONE(static_object) IREP_ID_ONE(stack_object) IREP_ID_TWO(C_is_failed_symbol, #is_failed_symbol) IREP_ID_TWO(C_failed_symbol, #failed_symbol) -IREP_ID_ONE(list) -IREP_ID_ONE(map) IREP_ID_ONE(set) -IREP_ID_ONE(storage) IREP_ID_ONE(friend) IREP_ID_ONE(explicit) IREP_ID_ONE(storage_spec) @@ -548,21 +471,6 @@ IREP_ID_ONE(aligned) IREP_ID_TWO(C_alignment, #alignment) IREP_ID_ONE(vector) IREP_ID_ONE(abstract) -IREP_ID_ONE(bit) -IREP_ID_ONE(logic) -IREP_ID_ONE(chandle) -IREP_ID_ONE(reg) -IREP_ID_ONE(wire) -IREP_ID_ONE(tri) -IREP_ID_ONE(tri1) -IREP_ID_ONE(supply0) -IREP_ID_ONE(wand) -IREP_ID_ONE(triand) -IREP_ID_ONE(tri0) -IREP_ID_ONE(supply1) -IREP_ID_ONE(wor) -IREP_ID_ONE(trior) -IREP_ID_ONE(trireg) IREP_ID_ONE(function_application) IREP_ID_ONE(cpp_declarator) IREP_ID_ONE(cpp_linkage_spec) @@ -576,57 +484,12 @@ IREP_ID_TWO(C_c_type, #c_type) IREP_ID_ONE(namespace) IREP_ID_ONE(linkage) IREP_ID_ONE(decltype) -IREP_ID_ONE(buf) -IREP_ID_ONE(bufif0) -IREP_ID_ONE(bufif1) -IREP_ID_ONE(notif0) -IREP_ID_ONE(notif1) -IREP_ID_ONE(task) -IREP_ID_TWO(C_little_endian, #little_endian) -IREP_ID_TWO(C_offset, #offset) IREP_ID_TWO(C_tag_only_declaration, #tag_only_declaration) IREP_ID_ONE(struct_tag) IREP_ID_ONE(union_tag) IREP_ID_ONE(c_enum_tag) -IREP_ID_ONE(enum_constant) -IREP_ID_ONE(bit_select) -IREP_ID_ONE(part_select) -IREP_ID_ONE(indexed_part_select_plus) -IREP_ID_ONE(indexed_part_select_minus) -IREP_ID_ONE(generate_block) -IREP_ID_ONE(generate_assign) -IREP_ID_ONE(generate_skip) -IREP_ID_ONE(generate_case) -IREP_ID_ONE(generate_if) -IREP_ID_ONE(generate_for) -IREP_ID_ONE(delay) -IREP_ID_ONE(verilog_cycle_delay) -IREP_ID_ONE(sva_cycle_delay) -IREP_ID_ONE(sva_sequence_throughout) -IREP_ID_ONE(sva_sequence_concatenation) -IREP_ID_ONE(sva_sequence_first_match) -IREP_ID_ONE(sva_always) -IREP_ID_ONE(sva_nexttime) -IREP_ID_ONE(sva_s_nexttime) -IREP_ID_ONE(sva_eventually) -IREP_ID_ONE(sva_s_eventually) -IREP_ID_ONE(sva_until) -IREP_ID_ONE(sva_s_until) -IREP_ID_ONE(sva_until_with) -IREP_ID_ONE(sva_s_until_with) -IREP_ID_ONE(sva_overlapped_implication) -IREP_ID_ONE(sva_non_overlapped_implication) -IREP_ID_ONE(hierarchical_identifier) -IREP_ID_ONE(named_port_connection) -IREP_ID_ONE(named_block) -IREP_ID_ONE(verilog_primitive_module) -IREP_ID_ONE(verilog_module) IREP_ID_ONE(verilog_case_equality) IREP_ID_ONE(verilog_case_inequality) -IREP_ID_ONE(event_guard) -IREP_ID_ONE(posedge) -IREP_ID_ONE(negedge) -IREP_ID_ONE(pointer_and_address_pair) IREP_ID_ONE(user_specified_predicate) IREP_ID_ONE(user_specified_parameter_predicates) IREP_ID_ONE(user_specified_return_predicates) @@ -644,13 +507,9 @@ IREP_ID_ONE(msc_if_not_exists) IREP_ID_ONE(msc_underlying_type) IREP_ID_ONE(msc_based) IREP_ID_ONE(alias) -IREP_ID_ONE(auto_object) -IREP_ID_ONE(ssa_object) IREP_ID_ONE(ptr_object) IREP_ID_TWO(C_c_sizeof_type, #c_sizeof_type) IREP_ID_ONE(array_update) -IREP_ID_ONE(struct_update) -IREP_ID_ONE(union_update) IREP_ID_ONE(update) IREP_ID_ONE(float_debug1) IREP_ID_ONE(float_debug2) @@ -659,10 +518,7 @@ IREP_ID_ONE(gcc_attribute_mode) IREP_ID_TWO(built_in, ) IREP_ID_ONE(exception_list) IREP_ID_ONE(exception_id) -IREP_ID_ONE(priority) IREP_ID_ONE(predicate_passive_symbol) -IREP_ID_ONE(all) -IREP_ID_ONE(when) IREP_ID_ONE(cw_va_arg_typeof) IREP_ID_ONE(fence) IREP_ID_ONE(sync) @@ -676,7 +532,6 @@ IREP_ID_ONE(RRcumul) IREP_ID_ONE(RWcumul) IREP_ID_ONE(WWcumul) IREP_ID_ONE(WRcumul) -IREP_ID_ONE(claim) IREP_ID_ONE(generic_selection) IREP_ID_ONE(generic_associations) IREP_ID_ONE(generic_association) @@ -685,13 +540,7 @@ IREP_ID_ONE(floatbv_minus) IREP_ID_ONE(floatbv_mult) IREP_ID_ONE(floatbv_div) IREP_ID_ONE(floatbv_rem) -IREP_ID_ONE(floatbv_sin) -IREP_ID_ONE(floatbv_cos) IREP_ID_ONE(floatbv_typecast) -IREP_ID_ONE(read) -IREP_ID_ONE(write) -IREP_ID_ONE(native) -IREP_ID_ONE(final) IREP_ID_ONE(compound_literal) IREP_ID_ONE(custom_bv) IREP_ID_ONE(custom_unsignedbv) @@ -699,7 +548,6 @@ IREP_ID_ONE(custom_signedbv) IREP_ID_ONE(custom_fixedbv) IREP_ID_ONE(custom_floatbv) IREP_ID_TWO(C_SSA_symbol, #SSA_symbol) -IREP_ID_TWO(C_full_identifier, #full_identifier) IREP_ID_ONE(L0) IREP_ID_ONE(L1) IREP_ID_ONE(L2) @@ -707,26 +555,12 @@ IREP_ID_ONE(L1_object_identifier) IREP_ID_ONE(already_typechecked) IREP_ID_TWO(C_va_arg_type, #va_arg_type) IREP_ID_ONE(smt2_symbol) -IREP_ID_ONE(VHDL) -IREP_ID_ONE(Verilog) -IREP_ID_ONE(verilog_realtime) IREP_ID_ONE(onehot) IREP_ID_ONE(onehot0) -IREP_ID_ONE(verilog_star_event) -IREP_ID_ONE(verilog_attribute) -IREP_ID_ONE(time) -IREP_ID_ONE(fork) -IREP_ID_ONE(disable) -IREP_ID_ONE(wait) -IREP_ID_ONE(deassign) -IREP_ID_ONE(force) -IREP_ID_ONE(release) IREP_ID_ONE(popcount) IREP_ID_ONE(function_type) IREP_ID_ONE(noreturn) IREP_ID_TWO(C_noreturn, #noreturn) -IREP_ID_ONE(process) -IREP_ID_ONE(signal) IREP_ID_ONE(weak) IREP_ID_ONE(is_weak) IREP_ID_TWO(C_spec_loop_invariant, #spec_loop_invariant) @@ -736,13 +570,6 @@ IREP_ID_ONE(virtual_function) IREP_ID_TWO(C_element_type, #element_type) IREP_ID_ONE(working_directory) IREP_ID_ONE(section) -IREP_ID_ONE(msb) -IREP_ID_ONE(lsb) -IREP_ID_ONE(verilog_signed_vector) -IREP_ID_ONE(verilog_unsigned_vector) -IREP_ID_ONE(verilog_array) -IREP_ID_ONE(low) -IREP_ID_ONE(high) IREP_ID_ONE(bswap) IREP_ID_ONE(java_bytecode_index) IREP_ID_ONE(java_instanceof) @@ -758,7 +585,6 @@ IREP_ID_ONE(cprover_associate_array_to_pointer_func) IREP_ID_ONE(cprover_associate_length_to_array_func) IREP_ID_ONE(cprover_char_literal_func) IREP_ID_ONE(cprover_string_literal_func) -IREP_ID_ONE(cprover_string_array_of_char_pointer_func) IREP_ID_ONE(cprover_string_char_at_func) IREP_ID_ONE(cprover_string_char_set_func) IREP_ID_ONE(cprover_string_code_point_at_func) @@ -794,13 +620,11 @@ IREP_ID_ONE(cprover_string_insert_bool_func) IREP_ID_ONE(cprover_string_insert_char_func) IREP_ID_ONE(cprover_string_insert_float_func) IREP_ID_ONE(cprover_string_insert_double_func) -IREP_ID_ONE(cprover_string_insert_char_array_func) IREP_ID_ONE(cprover_string_is_prefix_func) IREP_ID_ONE(cprover_string_is_suffix_func) IREP_ID_ONE(cprover_string_is_empty_func) IREP_ID_ONE(cprover_string_last_index_of_func) IREP_ID_ONE(cprover_string_length_func) -IREP_ID_ONE(cprover_string_data_func) IREP_ID_ONE(cprover_string_of_int_func) IREP_ID_ONE(cprover_string_of_int_hex_func) IREP_ID_ONE(cprover_string_of_long_func) @@ -809,17 +633,14 @@ IREP_ID_ONE(cprover_string_of_float_func) IREP_ID_ONE(cprover_string_of_float_scientific_notation_func) IREP_ID_ONE(cprover_string_of_double_func) IREP_ID_ONE(cprover_string_of_char_func) -IREP_ID_ONE(cprover_string_of_char_array_func) IREP_ID_ONE(cprover_string_parse_int_func) IREP_ID_ONE(cprover_string_replace_func) IREP_ID_ONE(cprover_string_set_length_func) IREP_ID_ONE(cprover_string_startswith_func) IREP_ID_ONE(cprover_string_substring_func) -IREP_ID_ONE(cprover_string_to_char_array_func) IREP_ID_ONE(cprover_string_to_lower_case_func) 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(skip_initialize) IREP_ID_ONE(basic_block_covered_lines) IREP_ID_ONE(is_nondet_nullable) @@ -831,7 +652,6 @@ IREP_ID_ONE(integer_dereference) IREP_ID_TWO(C_java_generic_parameter, #java_generic_parameter) IREP_ID_TWO(C_java_generic_type, #java_generic_type) IREP_ID_TWO(C_java_generics_class_type, #java_generics_class_type) -IREP_ID_TWO(C_specialized_generic_java_class, #specialized_generic_java_class) IREP_ID_TWO(C_java_implicitly_generic_class_type, #java_implicitly_generic_class_type) IREP_ID_TWO(C_java_generic_symbol, #java_generic_symbol) IREP_ID_TWO(generic_types, #generic_types) @@ -846,5 +666,13 @@ IREP_ID_TWO(overlay_class, java::com.diffblue.OverlayClassImplementation) IREP_ID_TWO(overlay_method, java::com.diffblue.OverlayMethodImplementation) IREP_ID_ONE(annotations) +// Projects depending on this code base that wish to extend the list of +// available ids should provide a file local_irep_ids.h in their source tree and +// add -D'LOCAL_IREP_IDS=' to their compiler command +// line. +#ifdef LOCAL_IREP_IDS +#include LOCAL_IREP_IDS +#endif + #undef IREP_ID_ONE #undef IREP_ID_TWO diff --git a/src/util/irep_ids.h b/src/util/irep_ids.h index 2fec6ff4114..7d946bed305 100644 --- a/src/util/irep_ids.h +++ b/src/util/irep_ids.h @@ -33,14 +33,6 @@ Author: Reuben Thomas, reuben.thomas@me.com /// into a const extern irep_idt with the variable name `ID_param` and the /// string value `"contents"`. -enum class idt:unsigned -{ -#define IREP_ID_ONE(the_id) id_##the_id, -#define IREP_ID_TWO(the_id, str) id_##the_id, - -#include "irep_ids.def" -}; - #ifdef USE_DSTRING #define IREP_ID_ONE(the_id) extern const dstringt ID_##the_id; @@ -53,6 +45,6 @@ enum class idt:unsigned #endif -#include "irep_ids.def" // NOLINT(build/include) +#include "irep_ids.def" #endif diff --git a/src/util/json_irep.h b/src/util/json_irep.h index 6fdc3dfc92d..6e6fe6b1a55 100644 --- a/src/util/json_irep.h +++ b/src/util/json_irep.h @@ -12,7 +12,7 @@ Author: Thomas Kiley, thomas.kiley@diffblue.com #ifndef CPROVER_UTIL_JSON_IREP_H #define CPROVER_UTIL_JSON_IREP_H -#include +#include "irep.h" class jsont; class json_objectt; diff --git a/src/util/json_stream.h b/src/util/json_stream.h index 4f1541d0496..cbb4689a5de 100644 --- a/src/util/json_stream.h +++ b/src/util/json_stream.h @@ -9,8 +9,8 @@ Author: Peter Schrammel #ifndef CPROVER_UTIL_JSON_STREAM_H #define CPROVER_UTIL_JSON_STREAM_H +#include #include -#include #include "json.h" #include "invariant.h" diff --git a/src/util/magic.h b/src/util/magic.h index 48c72436e2d..3d1c2ed8d90 100644 --- a/src/util/magic.h +++ b/src/util/magic.h @@ -10,5 +10,7 @@ const std::size_t CNF_DUMP_BLOCK_SIZE = 4096; const std::size_t MAX_FLATTENED_ARRAY_SIZE=1000; const std::size_t STRING_REFINEMENT_MAX_CHAR_WIDTH = 16; +// Limit the size of strings in traces to 64M chars to avoid memout +const std::size_t MAX_CONCRETE_STRING_SIZE = 1 << 26; #endif diff --git a/src/util/nondet_bool.h b/src/util/nondet_bool.h index af628d3456e..700b85ec5b0 100644 --- a/src/util/nondet_bool.h +++ b/src/util/nondet_bool.h @@ -12,8 +12,8 @@ Author: Chris Smowton, chris@smowton.net #ifndef CPROVER_UTIL_NONDET_BOOL_H #define CPROVER_UTIL_NONDET_BOOL_H -#include -#include +#include "std_expr.h" +#include "std_types.h" /// \par parameters: Desired type (C_bool or plain bool) /// \return nondet expr of that type diff --git a/src/util/nondet_ifthenelse.h b/src/util/nondet_ifthenelse.h index 664a6bdf1b2..cf1966526ef 100644 --- a/src/util/nondet_ifthenelse.h +++ b/src/util/nondet_ifthenelse.h @@ -12,7 +12,7 @@ Author: Chris Smowton, chris@smowton.net #ifndef CPROVER_UTIL_NONDET_IFTHENELSE_H #define CPROVER_UTIL_NONDET_IFTHENELSE_H -#include +#include "std_code.h" class symbol_tablet; class source_locationt; diff --git a/src/util/numbering.h b/src/util/numbering.h index f932874695a..42e18354e21 100644 --- a/src/util/numbering.h +++ b/src/util/numbering.h @@ -9,13 +9,12 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_UTIL_NUMBERING_H #define CPROVER_UTIL_NUMBERING_H -#include #include #include #include -#include -#include +#include "invariant.h" +#include "optional.h" /// \tparam Map a map from a key type to some numeric type template diff --git a/src/util/pointer_offset_size.cpp b/src/util/pointer_offset_size.cpp index 27104f2292c..2e315ba242f 100644 --- a/src/util/pointer_offset_size.cpp +++ b/src/util/pointer_offset_size.cpp @@ -11,17 +11,13 @@ Author: Daniel Kroening, kroening@kroening.com #include "pointer_offset_size.h" +#include "arith_tools.h" #include "c_types.h" -#include "expr.h" #include "invariant.h" -#include "arith_tools.h" -#include "std_types.h" -#include "std_expr.h" -#include "expr_util.h" -#include "simplify_expr.h" #include "namespace.h" -#include "symbol.h" +#include "simplify_expr.h" #include "ssa_expr.h" +#include "std_expr.h" member_offset_iterator::member_offset_iterator( const struct_typet &_type, @@ -42,11 +38,14 @@ member_offset_iterator &member_offset_iterator::operator++() { // take the extra bytes needed std::size_t w=to_c_bit_field_type(comp.type()).get_width(); - for(; w>bit_field_bits; ++current.second, bit_field_bits+=8) {} - bit_field_bits-=w; + bit_field_bits += w; + current.second += bit_field_bits / 8; + bit_field_bits %= 8; } else { + DATA_INVARIANT( + bit_field_bits == 0, "padding ensures offset at byte boundaries"); const typet &subtype=comp.type(); mp_integer sub_size=pointer_offset_size(subtype, ns); if(sub_size==-1) @@ -287,13 +286,15 @@ exprt member_offset_expr( if(it->type().id()==ID_c_bit_field) { std::size_t w=to_c_bit_field_type(it->type()).get_width(); - std::size_t bytes; - for(bytes=0; w>bit_field_bits; ++bytes, bit_field_bits+=8) {} - bit_field_bits-=w; + bit_field_bits += w; + const std::size_t bytes = bit_field_bits / 8; + bit_field_bits %= 8; result=plus_exprt(result, from_integer(bytes, result.type())); } else { + DATA_INVARIANT( + bit_field_bits == 0, "padding ensures offset at byte boundaries"); const typet &subtype=it->type(); exprt sub_size=size_of_expr(subtype, ns); if(sub_size.is_nil()) @@ -381,13 +382,15 @@ exprt size_of_expr( if(it->type().id()==ID_c_bit_field) { std::size_t w=to_c_bit_field_type(it->type()).get_width(); - std::size_t bytes; - for(bytes=0; w>bit_field_bits; ++bytes, bit_field_bits+=8) {} - bit_field_bits-=w; + bit_field_bits += w; + const std::size_t bytes = bit_field_bits / 8; + bit_field_bits %= 8; result=plus_exprt(result, from_integer(bytes, result.type())); } else { + DATA_INVARIANT( + bit_field_bits == 0, "padding ensures offset at byte boundaries"); const typet &subtype=it->type(); exprt sub_size=size_of_expr(subtype, ns); if(sub_size.is_nil()) diff --git a/src/util/pointer_predicates.cpp b/src/util/pointer_predicates.cpp index 312166f0088..966ebdae021 100644 --- a/src/util/pointer_predicates.cpp +++ b/src/util/pointer_predicates.cpp @@ -11,14 +11,12 @@ Author: Daniel Kroening, kroening@kroening.com #include "pointer_predicates.h" +#include "arith_tools.h" #include "c_types.h" #include "cprover_prefix.h" #include "namespace.h" -#include "std_expr.h" -#include "expr_util.h" -#include "arith_tools.h" #include "pointer_offset_size.h" -#include "config.h" +#include "std_expr.h" #include "symbol.h" exprt pointer_object(const exprt &p) diff --git a/src/util/rational.h b/src/util/rational.h index 809f237c95a..a043ed0923d 100644 --- a/src/util/rational.h +++ b/src/util/rational.h @@ -10,9 +10,6 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_UTIL_RATIONAL_H #define CPROVER_UTIL_RATIONAL_H -#include -#include - #include "mp_arith.h" class constant_exprt; diff --git a/src/util/refined_string_type.cpp b/src/util/refined_string_type.cpp index 818eb9e4391..91cbc7ff090 100644 --- a/src/util/refined_string_type.cpp +++ b/src/util/refined_string_type.cpp @@ -18,6 +18,8 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com #include "refined_string_type.h" +#include "std_expr.h" + refined_string_typet::refined_string_typet( const typet &index_type, const typet &char_type) { diff --git a/src/util/refined_string_type.h b/src/util/refined_string_type.h index ecef73288ea..bc597556b2d 100644 --- a/src/util/refined_string_type.h +++ b/src/util/refined_string_type.h @@ -19,11 +19,8 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com #ifndef CPROVER_UTIL_REFINED_STRING_TYPE_H #define CPROVER_UTIL_REFINED_STRING_TYPE_H -#include -#include -#include -#include -#include +#include "cprover_prefix.h" +#include "std_types.h" // Internal type used for string refinement class refined_string_typet: public struct_typet diff --git a/src/util/sharing_map.h b/src/util/sharing_map.h index a558ec42901..1c8943ae1ac 100644 --- a/src/util/sharing_map.h +++ b/src/util/sharing_map.h @@ -15,17 +15,15 @@ Author: Daniel Poetzl #include #include #include -#include #include #include #include #include #include -#include -#include -#include -#include +#include "irep.h" +#include "sharing_node.h" +#include "threeval.h" #define _sm_assert(b) assert(b) //#define _sm_assert(b) diff --git a/src/util/sharing_node.h b/src/util/sharing_node.h index 9cec1cd2f3a..2ecebabb467 100644 --- a/src/util/sharing_node.h +++ b/src/util/sharing_node.h @@ -15,7 +15,6 @@ Author: Daniel Poetzl #include #include #include -#include #include "invariant.h" diff --git a/src/util/simplify_expr.cpp b/src/util/simplify_expr.cpp index 4a0e2855d29..c2e07be9630 100644 --- a/src/util/simplify_expr.cpp +++ b/src/util/simplify_expr.cpp @@ -11,29 +11,21 @@ Author: Daniel Kroening, kroening@kroening.com #include #include -#include "c_types.h" -#include "rational.h" -#include "simplify_expr_class.h" -#include "mp_arith.h" #include "arith_tools.h" -#include "replace_expr.h" -#include "std_types.h" +#include "base_type.h" +#include "byte_operators.h" +#include "c_types.h" +#include "config.h" +#include "endianness_map.h" #include "expr_util.h" -#include "std_expr.h" #include "fixedbv.h" +#include "namespace.h" #include "pointer_offset_size.h" +#include "rational.h" #include "rational_tools.h" -#include "config.h" -#include "base_type.h" -#include "type_eq.h" -#include "namespace.h" -#include "threeval.h" -#include "pointer_predicates.h" -#include "prefix.h" -#include "byte_operators.h" -#include "bv_arithmetic.h" -#include "endianness_map.h" #include "simplify_utils.h" +#include "std_expr.h" +#include "type_eq.h" // #define DEBUGX @@ -41,6 +33,8 @@ Author: Daniel Kroening, kroening@kroening.com #include #endif +#include "simplify_expr_class.h" + // #define USE_CACHE #ifdef USE_CACHE diff --git a/src/util/simplify_expr_array.cpp b/src/util/simplify_expr_array.cpp index 026cb84105f..db64a51b243 100644 --- a/src/util/simplify_expr_array.cpp +++ b/src/util/simplify_expr_array.cpp @@ -8,14 +8,11 @@ Author: Daniel Kroening, kroening@kroening.com #include "simplify_expr_class.h" -#include - -#include "expr.h" -#include "namespace.h" -#include "std_expr.h" -#include "replace_expr.h" #include "arith_tools.h" +#include "namespace.h" #include "pointer_offset_size.h" +#include "replace_expr.h" +#include "std_expr.h" bool simplify_exprt::simplify_index(exprt &expr) { diff --git a/src/util/simplify_expr_int.cpp b/src/util/simplify_expr_int.cpp index c225997d2c8..da3c03da448 100644 --- a/src/util/simplify_expr_int.cpp +++ b/src/util/simplify_expr_int.cpp @@ -14,7 +14,6 @@ Author: Daniel Kroening, kroening@kroening.com #include "base_type.h" #include "bv_arithmetic.h" #include "config.h" -#include "expr.h" #include "expr_util.h" #include "fixedbv.h" #include "ieee_float.h" @@ -24,7 +23,6 @@ Author: Daniel Kroening, kroening@kroening.com #include "rational.h" #include "rational_tools.h" #include "std_expr.h" -#include "string2int.h" bool simplify_exprt::simplify_bswap(bswap_exprt &expr) { diff --git a/src/util/simplify_expr_pointer.cpp b/src/util/simplify_expr_pointer.cpp index a1e26187897..fff9ba57f52 100644 --- a/src/util/simplify_expr_pointer.cpp +++ b/src/util/simplify_expr_pointer.cpp @@ -10,17 +10,15 @@ Author: Daniel Kroening, kroening@kroening.com #include -#include "c_types.h" -#include "expr.h" -#include "namespace.h" -#include "std_expr.h" -#include "pointer_offset_size.h" #include "arith_tools.h" +#include "c_types.h" #include "config.h" #include "expr_util.h" -#include "threeval.h" -#include "prefix.h" +#include "namespace.h" +#include "pointer_offset_size.h" #include "pointer_predicates.h" +#include "std_expr.h" +#include "threeval.h" static bool is_dereference_integer_object( const exprt &expr, diff --git a/src/util/simplify_expr_struct.cpp b/src/util/simplify_expr_struct.cpp index e6195f2cb54..331d04c3001 100644 --- a/src/util/simplify_expr_struct.cpp +++ b/src/util/simplify_expr_struct.cpp @@ -8,15 +8,12 @@ Author: Daniel Kroening, kroening@kroening.com #include "simplify_expr_class.h" -#include - +#include "arith_tools.h" +#include "base_type.h" #include "byte_operators.h" -#include "expr.h" #include "namespace.h" -#include "std_expr.h" #include "pointer_offset_size.h" -#include "arith_tools.h" -#include "base_type.h" +#include "std_expr.h" bool simplify_exprt::simplify_member(exprt &expr) { diff --git a/src/util/small_shared_two_way_ptr.h b/src/util/small_shared_two_way_ptr.h new file mode 100644 index 00000000000..7758411210f --- /dev/null +++ b/src/util/small_shared_two_way_ptr.h @@ -0,0 +1,287 @@ +/*******************************************************************\ + +Module: Small shared two-way pointer + +Author: Daniel Poetzl + +\*******************************************************************/ + +#ifndef CPROVER_UTIL_SMALL_SHARED_TWO_WAY_PTR_H +#define CPROVER_UTIL_SMALL_SHARED_TWO_WAY_PTR_H + +#include +#include +#include + +#include "invariant.h" + +template +class small_shared_two_way_pointeet; + +/// This class is similar to small_shared_ptrt and boost's intrusive_ptr. Like +/// those, it stores the use count with the pointed-to object instead of in a +/// separate control block. Additionally, it uses the MSB of the use count to +/// indicate the type of the managed object (which is either of type U or V). +/// +/// A possible use case is the implementation of data structures with sharing +/// that consist of two different types of objects (such as a tree with internal +/// nodes and leaf nodes). Storing the type with the use count avoids having to +/// keep a separate `type` member or using `typeid` or `dynamic_cast`. Moreover, +/// since the shared pointer is aware of the concrete type of the object being +/// stored, it can delete it without requiring a virtual destructor or custom +/// delete function (like std::shared_ptr). +template +class small_shared_two_way_ptrt final +{ +public: + typedef decltype(std::declval().use_count()) use_countt; + + typedef small_shared_two_way_pointeet pointeet; + + static_assert(std::is_base_of::value, ""); + static_assert(std::is_base_of::value, ""); + + small_shared_two_way_ptrt() = default; + + explicit small_shared_two_way_ptrt(U *u) : p(u) + { + PRECONDITION(u != nullptr); + PRECONDITION(u->use_count() == 0); + + p->set_derived_u(); + p->increment_use_count(); + } + + explicit small_shared_two_way_ptrt(V *v) : p(v) + { + PRECONDITION(v != nullptr); + PRECONDITION(v->use_count() == 0); + + p->set_derived_v(); + p->increment_use_count(); + } + + small_shared_two_way_ptrt(const small_shared_two_way_ptrt &rhs) : p(rhs.p) + { + PRECONDITION(is_same_type(rhs)); + + if(p) + { + p->increment_use_count(); + } + } + + small_shared_two_way_ptrt(small_shared_two_way_ptrt &&rhs) + { + PRECONDITION(is_same_type(rhs)); + + swap(rhs); + } + + small_shared_two_way_ptrt &operator=(const small_shared_two_way_ptrt &rhs) + { + PRECONDITION(is_same_type(rhs)); + + small_shared_two_way_ptrt copy(rhs); + swap(copy); + return *this; + } + + small_shared_two_way_ptrt &operator=(small_shared_two_way_ptrt &&rhs) + { + PRECONDITION(is_same_type(rhs)); + + swap(rhs); + return *this; + } + + ~small_shared_two_way_ptrt() + { + if(!p) + { + return; + } + + auto use_count = p->use_count(); + + if(use_count == 1) + { + if(p->is_derived_u()) + { + U *u = static_cast(p); + delete u; + } + else + { + V *v = static_cast(p); + delete v; + } + } + else + { + p->decrement_use_count(); + } + } + + void swap(small_shared_two_way_ptrt &rhs) + { + PRECONDITION(is_same_type(rhs)); + + std::swap(p, rhs.p); + } + + use_countt use_count() const + { + return p ? p->use_count() : 0; + } + + /// Checks if converting the held raw pointer to `U*` is valid + bool is_derived_u() const + { + return p == nullptr || p->is_derived_u(); + } + + /// Checks if converting the held raw pointer to `V*` is valid + bool is_derived_v() const + { + return p == nullptr || p->is_derived_v(); + } + + pointeet *get() const + { + return p; + } + + U *get_derived_u() const + { + PRECONDITION(is_derived_u()); + + return static_cast(p); + } + + V *get_derived_v() const + { + PRECONDITION(is_derived_v()); + + return static_cast(p); + } + + /// Checks if the raw pointers held by `*this` and `other` both can be + /// converted to either U* or V* + bool is_same_type(const small_shared_two_way_ptrt &other) const + { + if(p == nullptr || other.p == nullptr) + return true; + + return p->is_same_type(*other.p); + } + + explicit operator bool() const + { + return p != nullptr; + } + +private: + pointeet *p = nullptr; +}; + +template +small_shared_two_way_ptrt make_shared_derived_u(Ts &&... ts) +{ + return small_shared_two_way_ptrt(new U(std::forward(ts)...)); +} + +template +small_shared_two_way_ptrt make_shared_derived_v(Ts &&... ts) +{ + return small_shared_two_way_ptrt(new V(std::forward(ts)...)); +} + +template +bool operator==( + const small_shared_two_way_ptrt &lhs, + const small_shared_two_way_ptrt &rhs) +{ + return lhs.get() == rhs.get(); +} + +template +bool operator!=( + const small_shared_two_way_ptrt &lhs, + const small_shared_two_way_ptrt &rhs) +{ + return lhs.get() != rhs.get(); +} + +template +class small_shared_two_way_pointeet +{ +public: + static_assert(std::is_unsigned::value, ""); + + static const int bit_idx = std::numeric_limits::digits - 1; + static const Num mask = ~((Num)1 << bit_idx); + + small_shared_two_way_pointeet() = default; + + // The use count shall be unaffected + small_shared_two_way_pointeet(const small_shared_two_way_pointeet &rhs) + { + } + + // The use count shall be unaffected + small_shared_two_way_pointeet & + operator=(const small_shared_two_way_pointeet &rhs) + { + return *this; + } + + Num use_count() const + { + return use_count_ & mask; + } + + void increment_use_count() + { + PRECONDITION((use_count_ & mask) < mask); + + use_count_++; + } + + void decrement_use_count() + { + PRECONDITION((use_count_ & mask) > 0); + + use_count_--; + } + + void set_derived_u() + { + use_count_ &= mask; + } + + void set_derived_v() + { + use_count_ |= ~mask; + } + + bool is_derived_u() const + { + return !(use_count_ & ~mask); + } + + bool is_derived_v() const + { + return use_count_ & ~mask; + } + + bool is_same_type(const small_shared_two_way_pointeet &other) const + { + return !((use_count_ ^ other.use_count_) & ~mask); + } + +private: + Num use_count_ = 0; +}; + +#endif diff --git a/src/util/ssa_expr.h b/src/util/ssa_expr.h index 63e6dfaf7d7..3a0e3b151d6 100644 --- a/src/util/ssa_expr.h +++ b/src/util/ssa_expr.h @@ -10,7 +10,7 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_UTIL_SSA_EXPR_H #define CPROVER_UTIL_SSA_EXPR_H -#include +#include "std_expr.h" /*! \brief Expression providing an SSA-renamed symbol of expressions */ diff --git a/src/util/std_expr.cpp b/src/util/std_expr.cpp index 445c31c3c27..431ca387530 100644 --- a/src/util/std_expr.cpp +++ b/src/util/std_expr.cpp @@ -13,9 +13,7 @@ Author: Daniel Kroening, kroening@kroening.com #include "arith_tools.h" #include "byte_operators.h" #include "c_types.h" -#include "namespace.h" #include "pointer_offset_size.h" -#include "std_types.h" bool constant_exprt::value_is_zero_string() const { diff --git a/src/util/string_expr.h b/src/util/string_expr.h index c9d54470d3b..dd44684140f 100644 --- a/src/util/string_expr.h +++ b/src/util/string_expr.h @@ -12,9 +12,9 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com #ifndef CPROVER_UTIL_STRING_EXPR_H #define CPROVER_UTIL_STRING_EXPR_H -#include -#include -#include +#include "arith_tools.h" +#include "refined_string_type.h" +#include "std_expr.h" // Given an representation of strings as exprt that implements `length` and // `content` this provides additional useful methods. diff --git a/src/util/string_utils.h b/src/util/string_utils.h index 87dd742d666..23d3d6ea6ba 100644 --- a/src/util/string_utils.h +++ b/src/util/string_utils.h @@ -10,7 +10,7 @@ Author: Daniel Poetzl #ifndef CPROVER_UTIL_STRING_UTILS_H #define CPROVER_UTIL_STRING_UTILS_H -#include +#include #include #include diff --git a/src/util/symbol.cpp b/src/util/symbol.cpp index 652fe422c56..95676c17dfc 100644 --- a/src/util/symbol.cpp +++ b/src/util/symbol.cpp @@ -73,86 +73,6 @@ std::ostream &operator<<(std::ostream &out, return out; } -irept symbolt::to_irep() const -{ - irept dest; - - dest.clear(); - dest.add(ID_type)=type; - dest.add(ID_value)=value; - dest.add(ID_location)=location; - dest.set(ID_name, name); - dest.set(ID_module, module); - dest.set(ID_base_name, base_name); - dest.set(ID_mode, mode); - dest.set(ID_pretty_name, pretty_name); - - if(is_type) - dest.set("is_type", true); - if(is_macro) - dest.set("is_macro", true); - if(is_exported) - dest.set("is_exported", true); - if(is_input) - dest.set("is_input", true); - if(is_output) - dest.set("is_output", true); - if(is_state_var) - dest.set("is_statevar", true); - if(is_parameter) - dest.set("is_parameter", true); - if(is_auxiliary) - dest.set("is_auxiliary", true); - if(is_weak) - dest.set("is_weak", true); - if(is_property) - dest.set("is_property", true); - if(is_lvalue) - dest.set("is_lvalue", true); - if(is_static_lifetime) - dest.set("is_static_lifetime", true); - if(is_thread_local) - dest.set("is_thread_local", true); - if(is_file_local) - dest.set("is_file_local", true); - if(is_extern) - dest.set("is_extern", true); - if(is_volatile) - dest.set("is_volatile", true); - - return dest; -} - -void symbolt::from_irep(const irept &src) -{ - type=static_cast(src.find(ID_type)); - value=static_cast(src.find(ID_value)); - location=static_cast(src.find(ID_location)); - - name=src.get(ID_name); - module=src.get(ID_module); - base_name=src.get(ID_base_name); - mode=src.get(ID_mode); - pretty_name=src.get(ID_pretty_name); - - is_type=src.get_bool("is_type"); - is_macro=src.get_bool("is_macro"); - is_exported=src.get_bool("is_exported"); - is_input=src.get_bool("is_input"); - is_output=src.get_bool("is_output"); - is_state_var=src.get_bool("is_state_var"); - is_parameter=src.get_bool("is_parameter"); - is_auxiliary=src.get_bool("is_auxiliary"); - is_weak=src.get_bool("is_weak"); - is_property=src.get_bool("property"); - is_lvalue=src.get_bool("lvalue"); - is_static_lifetime=src.get_bool("static_lifetime"); - is_thread_local=src.get_bool("thread_local"); - is_file_local=src.get_bool("file_local"); - is_extern=src.get_bool("is_extern"); - is_volatile=src.get_bool("is_volatile"); -} - void symbolt::swap(symbolt &b) { #define SYM_SWAP1(x) x.swap(b.x) diff --git a/src/util/symbol.h b/src/util/symbol.h index ca26306d6bf..078f80ad7b2 100644 --- a/src/util/symbol.h +++ b/src/util/symbol.h @@ -91,10 +91,6 @@ class symbolt void swap(symbolt &b); void show(std::ostream &out) const; - // serialization - irept to_irep() const; - void from_irep(const irept &src); - class symbol_exprt symbol_expr() const; bool is_shared() const diff --git a/src/util/symbol_table_base.h b/src/util/symbol_table_base.h index 62db57c024c..6a51a34a863 100644 --- a/src/util/symbol_table_base.h +++ b/src/util/symbol_table_base.h @@ -6,13 +6,9 @@ #ifndef CPROVER_UTIL_SYMBOL_TABLE_BASE_H #define CPROVER_UTIL_SYMBOL_TABLE_BASE_H -#include -#include #include #include -#include - #include "symbol.h" typedef std::multimap symbol_base_mapt; diff --git a/src/util/throw_with_nested.h b/src/util/throw_with_nested.h new file mode 100644 index 00000000000..444a7a60e6b --- /dev/null +++ b/src/util/throw_with_nested.h @@ -0,0 +1,60 @@ +/*******************************************************************\ + +Module: util + +Author: Diffblue Ltd. + +\*******************************************************************/ + +#ifndef CPROVER_UTIL_THROW_WITH_NESTED_H +#define CPROVER_UTIL_THROW_WITH_NESTED_H + +#include + +#ifdef _MSC_VER +#include +// TODO(tkiley): Nested exception logging not supported on windows due to a bug +// TODO(tkiley): in MSVC++ Compiler (diffblue/cbmc#2104): +// TODO(tkiley): https://blogs.msdn.microsoft.com/vcblog/2016/01/22/vs-2015-update-2s-stl-is-c17-so-far-feature-complete + +#define DISABLE_NESTED_EXCEPTIONS + +class non_nested_exception_support : public std::runtime_error +{ +public: + non_nested_exception_support() + : std::runtime_error("Nested exception printing not supported on Windows") + { + } +}; + +#endif + +template +#ifdef __GNUC__ +__attribute__((noreturn)) +#endif +void util_throw_with_nested(T &&t) +{ +#ifndef DISABLE_NESTED_EXCEPTIONS + std::throw_with_nested(t); +#else + throw t; +#endif +} + +template +void util_rethrow_if_nested(const E &e) +{ +#ifndef DISABLE_NESTED_EXCEPTIONS + std::rethrow_if_nested(e); +#else + // Check we've not already thrown the non_nested_support_exception + if(!dynamic_cast(&e)) + { + throw non_nested_exception_support(); + } +#endif +} + +#endif // CPROVER_UTIL_THROW_WITH_NESTED_H diff --git a/src/util/typecheck.cpp b/src/util/typecheck.cpp index a09f54d8ff0..24c57c8a7b7 100644 --- a/src/util/typecheck.cpp +++ b/src/util/typecheck.cpp @@ -6,12 +6,13 @@ Author: Daniel Kroening, kroening@kroening.com \*******************************************************************/ - #include "typecheck.h" +#include "invariant.h" + bool typecheckt::typecheck_main() { - assert(message_handler); + PRECONDITION(message_handler); const unsigned errors_before= message_handler->get_message_count(messaget::M_ERROR); diff --git a/src/util/union_find_replace.h b/src/util/union_find_replace.h index 37f86604f1b..b7630db11ed 100644 --- a/src/util/union_find_replace.h +++ b/src/util/union_find_replace.h @@ -9,7 +9,7 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com #ifndef CPROVER_UTIL_UNION_FIND_REPLACE_H #define CPROVER_UTIL_UNION_FIND_REPLACE_H -#include +#include "replace_expr.h" /// Similar interface to union-find for expressions, with a function for /// replacing sub-expressions by their result for find. diff --git a/src/util/unwrap_nested_exception.cpp b/src/util/unwrap_nested_exception.cpp new file mode 100644 index 00000000000..0689391466b --- /dev/null +++ b/src/util/unwrap_nested_exception.cpp @@ -0,0 +1,54 @@ +/*******************************************************************\ + +Module: util + +Author: Diffblue Ltd. + +\*******************************************************************/ + +#include "unwrap_nested_exception.h" +#include "invariant.h" +#include "string_utils.h" +#include "suffix.h" +#include "throw_with_nested.h" + +#include +#include + +/// Given a potentially nested exception, produce a string with all of nested +/// exceptions information. If a nested exception string contains new lines +/// then the newlines are indented to the correct level. +/// \param e: The outer exeception +/// \param level: How many exceptions have already been unrolled +/// \return A string with all nested exceptions printed and indented +std::string unwrap_exception(const std::exception &e, int level) +{ + const std::string msg = e.what(); + std::vector lines; + split_string(msg, '\n', lines, false, true); + std::ostringstream message_stream; + message_stream << std::string(level, ' ') << "exception: "; + join_strings( + message_stream, lines.begin(), lines.end(), "\n" + std::string(level, ' ')); + + try + { + util_rethrow_if_nested(e); + } + catch(const std::exception &e) + { + std::string nested_message = unwrap_exception(e, level + 1); + // Some exception messages already end in a new line (e.g. as they have + // dumped an irept. Most do not so add a new line on. + if(nested_message.back() != '\n') + { + message_stream << '\n'; + } + message_stream << nested_message; + } + catch(...) + { + UNREACHABLE; + } + return message_stream.str(); +} diff --git a/src/util/unwrap_nested_exception.h b/src/util/unwrap_nested_exception.h new file mode 100644 index 00000000000..4e2903c2c00 --- /dev/null +++ b/src/util/unwrap_nested_exception.h @@ -0,0 +1,17 @@ +/*******************************************************************\ + +Module: util + +Author: Diffblue Ltd. + +\*******************************************************************/ + +#ifndef CPROVER_UTIL_UNWRAP_NESTED_EXCEPTION_H +#define CPROVER_UTIL_UNWRAP_NESTED_EXCEPTION_H + +#include +#include + +std::string unwrap_exception(const std::exception &e, int level = 0); + +#endif // CPROVER_UTIL_UNWRAP_NESTED_EXCEPTION_H diff --git a/src/xmllang/graphml.h b/src/xmllang/graphml.h index 3b399d48c3b..f86dac5648e 100644 --- a/src/xmllang/graphml.h +++ b/src/xmllang/graphml.h @@ -12,8 +12,7 @@ Author: Michael Tautschnig, mt@eecs.qmul.ac.uk #ifndef CPROVER_XMLLANG_GRAPHML_H #define CPROVER_XMLLANG_GRAPHML_H -#include -#include +#include #include #include diff --git a/unit/Makefile b/unit/Makefile index eaf35100e23..05f188506aa 100644 --- a/unit/Makefile +++ b/unit/Makefile @@ -47,6 +47,7 @@ SRC += unit_tests.cpp \ util/optional.cpp \ util/parameter_indices.cpp \ util/simplify_expr.cpp \ + util/small_shared_two_way_ptr.cpp \ util/string_utils/split_string.cpp \ util/string_utils/strip_string.cpp \ util/symbol_table.cpp \ diff --git a/unit/java_bytecode/inherited_static_fields/inherited_static_fields.cpp b/unit/java_bytecode/inherited_static_fields/inherited_static_fields.cpp index 1341c158176..16fb06aec81 100644 --- a/unit/java_bytecode/inherited_static_fields/inherited_static_fields.cpp +++ b/unit/java_bytecode/inherited_static_fields/inherited_static_fields.cpp @@ -19,13 +19,10 @@ /// \return true if a suitable symbol_exprt is found static bool contains_symbol_reference(const exprt &expr, const irep_idt &id) { - return - std::any_of( - expr.depth_begin(), - expr.depth_end(), - [id](const exprt &e) { // NOLINT (*) - return e.id() == ID_symbol && to_symbol_expr(e).get_identifier() == id; - }); + return std::any_of( + expr.depth_begin(), expr.depth_end(), [id](const exprt &e) { + return e.id() == ID_symbol && to_symbol_expr(e).get_identifier() == id; + }); } SCENARIO( diff --git a/unit/java_bytecode/java_string_library_preprocess/convert_exprt_to_string_exprt.cpp b/unit/java_bytecode/java_string_library_preprocess/convert_exprt_to_string_exprt.cpp index b292e445ae2..fb65105afbb 100644 --- a/unit/java_bytecode/java_string_library_preprocess/convert_exprt_to_string_exprt.cpp +++ b/unit/java_bytecode/java_string_library_preprocess/convert_exprt_to_string_exprt.cpp @@ -68,10 +68,11 @@ TEST_CASE("Convert exprt to string exprt") std::regex_replace(line, spaces, " "), numbers, "")); } - const std::vector reference_code = { // NOLINT + const std::vector reference_code = { + // NOLINT "char *cprover_string_content;", "int cprover_string_length;", - "cprover_string_length = a->length;", + "cprover_string_length = a == null ? 0 : a->length;", "cprover_string_content = a->data;"}; for(std::size_t i = 0; diff --git a/unit/pointer-analysis/custom_value_set_analysis.cpp b/unit/pointer-analysis/custom_value_set_analysis.cpp index 5fdc3197f38..01791c36528 100644 --- a/unit/pointer-analysis/custom_value_set_analysis.cpp +++ b/unit/pointer-analysis/custom_value_set_analysis.cpp @@ -8,13 +8,14 @@ Author: Chris Smowton, chris@smowton.net #include -#include -#include -#include #include +#include #include #include +#include +#include #include +#include /// An example customised value_sett. It makes a series of small changes /// to the underlying value_sett logic, which can then be verified by the @@ -183,6 +184,9 @@ SCENARIO("test_value_set_analysis", goto_modelt goto_model= initialize_goto_model(command_line, null_output); + null_message_handlert message_handler; + remove_java_new(goto_model, message_handler); + namespacet ns(goto_model.symbol_table); // Fully inline the test program, to avoid VSA conflating diff --git a/unit/solvers/refinement/string_constraint_instantiation/instantiate_not_contains.cpp b/unit/solvers/refinement/string_constraint_instantiation/instantiate_not_contains.cpp index 3556cc26915..7e6773e50c0 100644 --- a/unit/solvers/refinement/string_constraint_instantiation/instantiate_not_contains.cpp +++ b/unit/solvers/refinement/string_constraint_instantiation/instantiate_not_contains.cpp @@ -195,8 +195,7 @@ SCENARIO("instantiate_not_contains", // Generating the corresponding axioms and simplifying, recording info symbol_tablet symtab; const namespacet empty_ns(symtab); - string_constraint_generatort::infot info; - string_constraint_generatort generator(info, ns); + string_constraint_generatort generator(ns); exprt res=generator.add_axioms_for_function_application(func); std::string axioms; std::vector nc_axioms; @@ -206,7 +205,7 @@ SCENARIO("instantiate_not_contains", constraints.begin(), constraints.end(), axioms, - [&](const std::string &accu, string_constraintt sc) { // NOLINT + [&](const std::string &accu, string_constraintt sc) { simplify(sc, ns); std::string s; java_lang->from_expr(sc, s, ns); @@ -218,8 +217,7 @@ SCENARIO("instantiate_not_contains", nc_contraints.begin(), nc_contraints.end(), axioms, - [&]( - const std::string &accu, string_not_contains_constraintt sc) { // NOLINT + [&](const std::string &accu, string_not_contains_constraintt sc) { simplify(sc, ns); generator.witness[sc] = generator.fresh_symbol("w", t.witness_type()); nc_axioms.push_back(sc); @@ -233,7 +231,7 @@ SCENARIO("instantiate_not_contains", lemmas.begin(), lemmas.end(), axioms, - [&](const std::string &accu, exprt axiom) { // NOLINT + [&](const std::string &accu, exprt axiom) { simplify(axiom, ns); std::string s; java_lang->from_expr(axiom, s, ns); @@ -297,8 +295,7 @@ SCENARIO("instantiate_not_contains", // Create witness for axiom symbol_tablet symtab; const namespacet empty_ns(symtab); - string_constraint_generatort::infot info; - string_constraint_generatort generator(info, ns); + string_constraint_generatort generator(ns); generator.witness[vacuous]= generator.fresh_symbol("w", t.witness_type()); @@ -353,8 +350,7 @@ SCENARIO("instantiate_not_contains", // Create witness for axiom symbol_tablet symtab; const namespacet ns(symtab); - string_constraint_generatort::infot info; - string_constraint_generatort generator(info, ns); + string_constraint_generatort generator(ns); generator.witness[trivial]= generator.fresh_symbol("w", t.witness_type()); @@ -410,8 +406,7 @@ SCENARIO("instantiate_not_contains", // Create witness for axiom symbol_tablet symtab; const namespacet empty_ns(symtab); - string_constraint_generatort::infot info; - string_constraint_generatort generator(info, ns); + string_constraint_generatort generator(ns); generator.witness[trivial]= generator.fresh_symbol("w", t.witness_type()); @@ -470,8 +465,7 @@ SCENARIO("instantiate_not_contains", symbol_tablet symtab; const namespacet empty_ns(symtab); - string_constraint_generatort::infot info; - string_constraint_generatort generator(info, ns); + string_constraint_generatort generator(ns); generator.witness[trivial]= generator.fresh_symbol("w", t.witness_type()); @@ -527,8 +521,7 @@ SCENARIO("instantiate_not_contains", // Create witness for axiom symbol_tablet symtab; const namespacet empty_ns(symtab); - string_constraint_generatort::infot info; - string_constraint_generatort generator(info, ns); + string_constraint_generatort generator(ns); generator.witness[trivial]= generator.fresh_symbol("w", t.witness_type()); diff --git a/unit/solvers/refinement/string_refinement/dependency_graph.cpp b/unit/solvers/refinement/string_refinement/dependency_graph.cpp index 3a0b6e16b62..de6bd2d69e6 100644 --- a/unit/solvers/refinement/string_refinement/dependency_graph.cpp +++ b/unit/solvers/refinement/string_refinement/dependency_graph.cpp @@ -142,8 +142,7 @@ SCENARIO("dependency_graph", "[core][solvers][refinement][string_refinement]") const auto &node = dependencies.get_node(char_array3); std::size_t nb_dependencies = 0; dependencies.for_each_dependency( - node, - [&](const string_dependenciest::builtin_function_nodet &n) { // NOLINT + node, [&](const string_dependenciest::builtin_function_nodet &n) { nb_dependencies++; THEN("primitive0 depends on string1 and string2") { @@ -161,8 +160,7 @@ SCENARIO("dependency_graph", "[core][solvers][refinement][string_refinement]") const auto &node = dependencies.get_node(char_array5); std::size_t nb_dependencies = 0; dependencies.for_each_dependency( - node, - [&](const string_dependenciest::builtin_function_nodet &n) { // NOLINT + node, [&](const string_dependenciest::builtin_function_nodet &n) { nb_dependencies++; THEN("primitive1 depends on string3 and string4") { diff --git a/unit/testing-utils/load_java_class.cpp b/unit/testing-utils/load_java_class.cpp index f198008dff4..217a3bb25d7 100644 --- a/unit/testing-utils/load_java_class.cpp +++ b/unit/testing-utils/load_java_class.cpp @@ -16,6 +16,8 @@ #include +#include + #include #include @@ -37,11 +39,13 @@ symbol_tablet load_java_class_lazy( free_form_cmdlinet lazy_command_line; lazy_command_line.add_flag("lazy-methods"); + register_language(new_java_bytecode_language); + return load_java_class( java_class_name, class_path, main, - new_java_bytecode_language(), + get_language_from_mode(ID_java), lazy_command_line); } @@ -59,8 +63,10 @@ symbol_tablet load_java_class( const std::string &class_path, const std::string &main) { + register_language(new_java_bytecode_language); + return load_java_class( - java_class_name, class_path, main, new_java_bytecode_language()); + java_class_name, class_path, main, get_language_from_mode(ID_java)); } /// Go through the process of loading, type-checking and finalising loading a diff --git a/unit/util/small_shared_two_way_ptr.cpp b/unit/util/small_shared_two_way_ptr.cpp new file mode 100644 index 00000000000..7ca44c94e2c --- /dev/null +++ b/unit/util/small_shared_two_way_ptr.cpp @@ -0,0 +1,103 @@ +/// Author: Daniel Poetzl + +/// \file Tests for small shared two-way pointer + +#include +#include + +class d1t : public small_shared_two_way_pointeet +{ +public: + d1t() = default; + + explicit d1t(int i) : d1(i) + { + } + + int d1; +}; + +class d2t : public small_shared_two_way_pointeet +{ +public: + d2t() = default; + + explicit d2t(int i) : d2(i) + { + } + + int d2; +}; + +TEST_CASE("Small shared two-way pointer") +{ + typedef small_shared_two_way_ptrt spt; + + SECTION("Types") + { + spt sp1; + spt sp2(new d1t()); + spt sp3(new d2t()); + + REQUIRE(sp1.is_same_type(sp1)); + REQUIRE(sp2.is_same_type(sp2)); + REQUIRE(sp3.is_same_type(sp3)); + + REQUIRE(sp1.is_same_type(sp2)); + REQUIRE(sp1.is_same_type(sp3)); + + REQUIRE(!sp2.is_same_type(sp3)); + + REQUIRE(sp1.is_derived_u()); + REQUIRE(sp1.is_derived_v()); + + REQUIRE(sp2.is_derived_u()); + REQUIRE(!sp2.is_derived_v()); + + REQUIRE(sp3.is_derived_v()); + REQUIRE(!sp3.is_derived_u()); + } + + SECTION("Basic") + { + spt sp1; + REQUIRE(sp1.use_count() == 0); + + const d1t *p; + + p = sp1.get_derived_u(); + REQUIRE(p == nullptr); + + spt sp2(new d1t()); + REQUIRE(sp2.use_count() == 1); + + p = sp2.get_derived_u(); + REQUIRE(p != nullptr); + + spt sp3(sp2); + REQUIRE(sp3.is_derived_u()); + REQUIRE(sp2.get_derived_u() == sp3.get_derived_u()); + REQUIRE(sp2.use_count() == 2); + REQUIRE(sp3.use_count() == 2); + + sp1 = sp2; + REQUIRE(sp1.is_derived_u()); + REQUIRE(sp1.get_derived_u() == sp2.get_derived_u()); + REQUIRE(sp1.use_count() == 3); + REQUIRE(sp2.use_count() == 3); + REQUIRE(sp3.use_count() == 3); + } + + SECTION("Creation") + { + spt sp1 = make_shared_derived_u(); + spt sp2 = make_shared_derived_v(); + + REQUIRE(!sp1.is_same_type(sp2)); + + sp1 = make_shared_derived_u(0); + sp2 = make_shared_derived_v(0); + + REQUIRE(!sp1.is_same_type(sp2)); + } +}