diff --git a/regression/Makefile b/regression/Makefile index 296f583cc5e..71e3494e073 100644 --- a/regression/Makefile +++ b/regression/Makefile @@ -12,3 +12,10 @@ DIRS = ansi-c \ test: $(foreach var,$(DIRS), $(MAKE) -C $(var) test || exit 1;) + +clean: + @for dir in *; do \ + if [ -d "$$dir" ]; then \ + $(MAKE) -C "$$dir" clean; \ + fi; \ + done; diff --git a/regression/goto-analyze-show-goto-functions/Makefile b/regression/goto-analyze-show-goto-functions/Makefile new file mode 100644 index 00000000000..08fe97ae88c --- /dev/null +++ b/regression/goto-analyze-show-goto-functions/Makefile @@ -0,0 +1,31 @@ + +default: tests.log + +test: + @if ! ../test.pl -c ../chain.sh ; then \ + ../failed-tests-printer.pl ; \ + exit 1; \ + fi + +tests.log: + @if ! ../test.pl -c ../chain.sh ; then \ + ../failed-tests-printer.pl ; \ + exit 1; \ + fi + +show: + @for dir in *; do \ + if [ -d "$$dir" ]; then \ + vim -o "$$dir/*.c" "$$dir/*.out"; \ + fi; \ + done; + +clean: + @for dir in *; do \ + rm -f tests.log; \ + if [ -d "$$dir" ]; then \ + cd "$$dir"; \ + rm -f *.out *.gb; \ + cd ..; \ + fi \ + done diff --git a/regression/goto-analyze-show-goto-functions/chain.sh b/regression/goto-analyze-show-goto-functions/chain.sh new file mode 100755 index 00000000000..a62699b6555 --- /dev/null +++ b/regression/goto-analyze-show-goto-functions/chain.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -e + +SRC=../../../src +GA=$SRC/goto-analyzer/goto-analyzer + +if [ -a $1_simplified.gb ] + then + rm $1_simplified.gb +fi +$GA $1 --simplify $1_simplified.gb --variable --arrays --structs --pointers +$GA $1_simplified.gb --show-goto-functions \ No newline at end of file diff --git a/regression/goto-analyze-show-goto-functions/simplify-fp-const-lost/main.c b/regression/goto-analyze-show-goto-functions/simplify-fp-const-lost/main.c new file mode 100644 index 00000000000..b9bd141e6f0 --- /dev/null +++ b/regression/goto-analyze-show-goto-functions/simplify-fp-const-lost/main.c @@ -0,0 +1,35 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp = f2; + + // Warning: this loses const-ness of f2 + void_fp * p2fp = (void_fp*)&fp; + *p2fp = &f4; + + fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyze-show-goto-functions/simplify-fp-const-lost/test.desc b/regression/goto-analyze-show-goto-functions/simplify-fp-const-lost/test.desc new file mode 100644 index 00000000000..3f5ea6bb9a7 --- /dev/null +++ b/regression/goto-analyze-show-goto-functions/simplify-fp-const-lost/test.desc @@ -0,0 +1,18 @@ +CORE +main.c + +^\s*f4\(\);$ +^SIGNAL=0$ +-- +^warning: ignoring +^\s*\d+: f1\(\);$ +^\s*\d+: f2\(\);$ +^\s*\d+: f3\(\);$ +^\s*\d+: f5\(\);$ +^\s*\d+: f6\(\);$ +^\s*\d+: f7\(\);$ +^\s*\d+: f8\(\);$ +^\s*\d+: f9\(\);$ +-- +Check the simplified goto program doesn't call any of the other functions (i.e +it has simplified all the unused cases generated by function pointer removal) diff --git a/regression/goto-analyze-show-goto-functions/simplify-fp-dynamic-array-fp/main.c b/regression/goto-analyze-show-goto-functions/simplify-fp-dynamic-array-fp/main.c new file mode 100644 index 00000000000..3cd1109dd98 --- /dev/null +++ b/regression/goto-analyze-show-goto-functions/simplify-fp-dynamic-array-fp/main.c @@ -0,0 +1,36 @@ +#include +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + void_fp * const fp_tbl= malloc(sizeof(void_fp) * 3); + fp_tbl[0]=f2; + fp_tbl[1]=f3; + fp_tbl[2]=f4; + + const void_fp fp = fp_tbl[1]; + fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyze-show-goto-functions/simplify-fp-dynamic-array-fp/test.desc b/regression/goto-analyze-show-goto-functions/simplify-fp-dynamic-array-fp/test.desc new file mode 100644 index 00000000000..aa3f71b788c --- /dev/null +++ b/regression/goto-analyze-show-goto-functions/simplify-fp-dynamic-array-fp/test.desc @@ -0,0 +1,18 @@ +FUTURE +main.c + +^\s*f3\(\);$ +^SIGNAL=0$ +-- +^warning: ignoring +^\s*\d+: f1\(\);$ +^\s*\d+: f2\(\);$ +^\s*\d+: f4\(\);$ +^\s*\d+: f5\(\);$ +^\s*\d+: f6\(\);$ +^\s*\d+: f7\(\);$ +^\s*\d+: f8\(\);$ +^\s*\d+: f9\(\);$ +-- +Check the GOTOs generated by the function pointer removal are removed by the +simplify step. This requires supporting tracking arrays assigned dynamically diff --git a/regression/goto-analyze-show-goto-functions/simplify-fp-fp-param/main.c b/regression/goto-analyze-show-goto-functions/simplify-fp-fp-param/main.c new file mode 100644 index 00000000000..3d50d8583fd --- /dev/null +++ b/regression/goto-analyze-show-goto-functions/simplify-fp-fp-param/main.c @@ -0,0 +1,29 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(void_fp fp) +{ + fp(); +} + +int main(int argc, char** argv) +{ + + func(&f2); + return 0; +} diff --git a/regression/goto-analyze-show-goto-functions/simplify-fp-fp-param/test.desc b/regression/goto-analyze-show-goto-functions/simplify-fp-fp-param/test.desc new file mode 100644 index 00000000000..f39b45de9f0 --- /dev/null +++ b/regression/goto-analyze-show-goto-functions/simplify-fp-fp-param/test.desc @@ -0,0 +1,18 @@ +CORE +main.c + +^SIGNAL=0$ +^\s*f2\(\);$ +-- +^warning: ignoring +^\s*\d+: f1\(\);$ +^\s*\d+: f3\(\);$ +^\s*\d+: f4\(\);$ +^\s*\d+: f5\(\);$ +^\s*\d+: f6\(\);$ +^\s*\d+: f7\(\);$ +^\s*\d+: f8\(\);$ +^\s*\d+: f9\(\);$ +-- +Check the GOTOs generated by the function pointer removal are removed by the +simplify step. diff --git a/regression/goto-analyze-show-goto-functions/simplify-fp-modified-array-pointer-fp/main.c b/regression/goto-analyze-show-goto-functions/simplify-fp-modified-array-pointer-fp/main.c new file mode 100644 index 00000000000..a17acab6166 --- /dev/null +++ b/regression/goto-analyze-show-goto-functions/simplify-fp-modified-array-pointer-fp/main.c @@ -0,0 +1,41 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp start_fp = f2; + const void_fp * const fp_tbl[] = { &start_fp, &start_fp, &start_fp }; + + // warning: loses const + void_fp * arr_ptr=fp_tbl[0]; + (*arr_ptr) = f5; + arr_ptr++; + (*arr_ptr) = f5; + + const void_fp * const fp = fp_tbl[1]; + + + (*fp)(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyze-show-goto-functions/simplify-fp-modified-array-pointer-fp/test.desc b/regression/goto-analyze-show-goto-functions/simplify-fp-modified-array-pointer-fp/test.desc new file mode 100644 index 00000000000..b538de20af0 --- /dev/null +++ b/regression/goto-analyze-show-goto-functions/simplify-fp-modified-array-pointer-fp/test.desc @@ -0,0 +1,18 @@ +FUTURE +main.c + +^SIGNAL=0$ +^\s*f5\(\);$ +-- +^warning: ignoring +^\s*\d+: f1\(\);$ +^\s*\d+: f2\(\);$ +^\s*\d+: f3\(\);$ +^\s*\d+: f4\(\);$ +^\s*\d+: f6\(\);$ +^\s*\d+: f7\(\);$ +^\s*\d+: f8\(\);$ +^\s*\d+: f9\(\);$ +-- +Check the GOTOs generated by the function pointer removal are removed by the +simplify step diff --git a/regression/goto-analyze-show-goto-functions/simplify-fp-modified-array/main.c b/regression/goto-analyze-show-goto-functions/simplify-fp-modified-array/main.c new file mode 100644 index 00000000000..9566bba3472 --- /dev/null +++ b/regression/goto-analyze-show-goto-functions/simplify-fp-modified-array/main.c @@ -0,0 +1,39 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp_tbl[] = {f2, f3 ,f4}; + + // warning: loses const + void_fp * arr_ptr=&fp_tbl[0]; + (*arr_ptr) = f5; + arr_ptr++; + (*arr_ptr) = f5; + + const void_fp fp = &fp_tbl[1]; + + fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyze-show-goto-functions/simplify-fp-modified-array/test.desc b/regression/goto-analyze-show-goto-functions/simplify-fp-modified-array/test.desc new file mode 100644 index 00000000000..b538de20af0 --- /dev/null +++ b/regression/goto-analyze-show-goto-functions/simplify-fp-modified-array/test.desc @@ -0,0 +1,18 @@ +FUTURE +main.c + +^SIGNAL=0$ +^\s*f5\(\);$ +-- +^warning: ignoring +^\s*\d+: f1\(\);$ +^\s*\d+: f2\(\);$ +^\s*\d+: f3\(\);$ +^\s*\d+: f4\(\);$ +^\s*\d+: f6\(\);$ +^\s*\d+: f7\(\);$ +^\s*\d+: f8\(\);$ +^\s*\d+: f9\(\);$ +-- +Check the GOTOs generated by the function pointer removal are removed by the +simplify step diff --git a/regression/goto-analyze-show-goto-functions/simplify-fp-non-const-pointer/main.c b/regression/goto-analyze-show-goto-functions/simplify-fp-non-const-pointer/main.c new file mode 100644 index 00000000000..80c8c863ff5 --- /dev/null +++ b/regression/goto-analyze-show-goto-functions/simplify-fp-non-const-pointer/main.c @@ -0,0 +1,31 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + void_fp fp = f2; + fp = f3; + fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyze-show-goto-functions/simplify-fp-non-const-pointer/test.desc b/regression/goto-analyze-show-goto-functions/simplify-fp-non-const-pointer/test.desc new file mode 100644 index 00000000000..ee6436f917a --- /dev/null +++ b/regression/goto-analyze-show-goto-functions/simplify-fp-non-const-pointer/test.desc @@ -0,0 +1,18 @@ +CORE +main.c + +^SIGNAL=0$ +^\s*f3\(\);$ +-- +^warning: ignoring +^\s*\d+: f1\(\);$ +^\s*\d+: f2\(\);$ +^\s*\d+: f4\(\);$ +^\s*\d+: f5\(\);$ +^\s*\d+: f6\(\);$ +^\s*\d+: f7\(\);$ +^\s*\d+: f8\(\);$ +^\s*\d+: f9\(\);$ +-- +Check the GOTOs generated by the function pointer removal are removed by the +simplify step diff --git a/regression/goto-analyze-show-goto-functions/simplify-fp-pointer-fp/main.c b/regression/goto-analyze-show-goto-functions/simplify-fp-pointer-fp/main.c new file mode 100644 index 00000000000..ec6b49f2b44 --- /dev/null +++ b/regression/goto-analyze-show-goto-functions/simplify-fp-pointer-fp/main.c @@ -0,0 +1,36 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func() +{ + const void_fp fp = f3; + const void_fp fp2 = f4; + const void_fp* p2fp = &fp; + + // legal: + p2fp = &fp2; + const void_fp final_fp=*p2fp; + final_fp(); +} + +int main() +{ + func(); + + return 0; +} diff --git a/regression/goto-analyze-show-goto-functions/simplify-fp-pointer-fp/test.desc b/regression/goto-analyze-show-goto-functions/simplify-fp-pointer-fp/test.desc new file mode 100644 index 00000000000..b5aa98ea052 --- /dev/null +++ b/regression/goto-analyze-show-goto-functions/simplify-fp-pointer-fp/test.desc @@ -0,0 +1,18 @@ +CORE +main.c + +^SIGNAL=0$ +^\s*f4\(\);$ +-- +^warning: ignoring +^\s*\d+: f1\(\);$ +^\s*\d+: f2\(\);$ +^\s*\d+: f3\(\);$ +^\s*\d+: f5\(\);$ +^\s*\d+: f6\(\);$ +^\s*\d+: f7\(\);$ +^\s*\d+: f8\(\);$ +^\s*\d+: f9\(\);$ +-- +Check the GOTOs generated by the function pointer removal are removed by the +simplify step diff --git a/regression/goto-analyze-show-goto-functions/simplify-fp-variable-array/main.c b/regression/goto-analyze-show-goto-functions/simplify-fp-variable-array/main.c new file mode 100644 index 00000000000..7ea01679fa9 --- /dev/null +++ b/regression/goto-analyze-show-goto-functions/simplify-fp-variable-array/main.c @@ -0,0 +1,31 @@ +#include + +void f1 (void) { printf("%i\n", 1); } +void f2 (void) { printf("%i\n", 2); } +void f3 (void) { printf("%i\n", 3); } +void f4 (void) { printf("%i\n", 4); } +void f5 (void) { printf("%i\n", 5); } +void f6 (void) { printf("%i\n", 6); } +void f7 (void) { printf("%i\n", 7); } +void f8 (void) { printf("%i\n", 8); } +void f9 (void) { printf("%i\n", 9); } + +typedef void(*void_fp)(void); + +// There is a basic check that excludes all functions that aren't used anywhere +// This ensures that check can't work in this example +const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9}; + +void func(int i, int j) +{ + const void_fp fp_tbl[] = {fp_all[i*2], fp_all[j+1]}; + const void_fp fp = fp_tbl[1]; + fp(); +} + +int main(int argc, char** argv) +{ + + func(argc,0); + return 0; +} diff --git a/regression/goto-analyze-show-goto-functions/simplify-fp-variable-array/test.desc b/regression/goto-analyze-show-goto-functions/simplify-fp-variable-array/test.desc new file mode 100644 index 00000000000..d8fbed4bfbd --- /dev/null +++ b/regression/goto-analyze-show-goto-functions/simplify-fp-variable-array/test.desc @@ -0,0 +1,19 @@ +CORE +main.c + +^SIGNAL=0$ +^\s*f2\(\);$ +-- +^warning: ignoring +^\s*\d+: f1\(\);$ +^\s*\d+: f3\(\);$ +^\s*\d+: f4\(\);$ +^\s*\d+: f5\(\);$ +^\s*\d+: f6\(\);$ +^\s*\d+: f7\(\);$ +^\s*\d+: f8\(\);$ +^\s*\d+: f9\(\);$ +-- +Check the GOTOs generated by the function pointer removal are removed by the +simplify step. The number fo removed goto statements doesn't seem correct, +but inspecting the output using show-goto-functions reveals the right program. diff --git a/regression/goto-analyzer/constant_assertions_01/main.c b/regression/goto-analyzer/constant_assertions_01/main.c new file mode 100644 index 00000000000..3a767276c2a --- /dev/null +++ b/regression/goto-analyzer/constant_assertions_01/main.c @@ -0,0 +1,17 @@ +#include + +int nondet_int (void); + +int main (int argc, char **argv) +{ + int x = nondet_int(); + int y = nondet_int(); + + __CPROVER_assert(0, "0"); + __CPROVER_assert(0 && 1, "0 && 1"); + __CPROVER_assert(0 || 0, "0 || 0"); + __CPROVER_assert(0 && x, "0 && x"); + __CPROVER_assert(y && 0, "y && 0"); + + return 0; +} diff --git a/regression/goto-analyzer/constant_assertions_01/test.desc b/regression/goto-analyzer/constant_assertions_01/test.desc new file mode 100644 index 00000000000..51b45717a62 --- /dev/null +++ b/regression/goto-analyzer/constant_assertions_01/test.desc @@ -0,0 +1,12 @@ +CORE +main.c +--verify --variable +^\[main.assertion.1\] file main.c .* 0: Failure \(if reachable\)$ +^\[main.assertion.2\] file main.c .* 0 && 1: Failure \(if reachable\)$ +^\[main.assertion.3\] file main.c .* 0 || 0: Failure \(if reachable\)$ +^\[main.assertion.4\] file main.c .* 0 && x: Failure \(if reachable\)$ +^\[main.assertion.5\] file main.c .* y && 0: Failure \(if reachable\)$ +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/constant_assertions_02/main.c b/regression/goto-analyzer/constant_assertions_02/main.c new file mode 100644 index 00000000000..889d980d200 --- /dev/null +++ b/regression/goto-analyzer/constant_assertions_02/main.c @@ -0,0 +1,17 @@ +#include + +int nondet_int (void); + +int main (int argc, char **argv) +{ + int x = nondet_int(); + int y = nondet_int(); + + __CPROVER_assert(1, "1"); + __CPROVER_assert(0 || 1, "0 || 1"); + __CPROVER_assert(1 && 1, "1 && 1"); + __CPROVER_assert(1 || x, "1 || x"); + __CPROVER_assert(y || 1, "y || 1"); + + return 0; +} diff --git a/regression/goto-analyzer/constant_assertions_02/test.desc b/regression/goto-analyzer/constant_assertions_02/test.desc new file mode 100644 index 00000000000..577ec981fd2 --- /dev/null +++ b/regression/goto-analyzer/constant_assertions_02/test.desc @@ -0,0 +1,12 @@ +CORE +main.c +--verify --variable +^\[main\.assertion\.1\] file main\.c .* 1: Success +^\[main\.assertion\.2\] file main\.c .* 0 || 1: Success +^\[main\.assertion\.3\] file main\.c .* 1 && 1: Success +^\[main\.assertion\.4\] file main\.c .* 1 || x: Success +^\[main\.assertion\.5\] file main\.c .* y || 1: Success +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/constant_propagation_01/constant_propagation1.c b/regression/goto-analyzer/constant_propagation_01/main.c similarity index 72% rename from regression/goto-analyzer/constant_propagation_01/constant_propagation1.c rename to regression/goto-analyzer/constant_propagation_01/main.c index 801a21535a9..49d90994aa2 100644 --- a/regression/goto-analyzer/constant_propagation_01/constant_propagation1.c +++ b/regression/goto-analyzer/constant_propagation_01/main.c @@ -3,12 +3,12 @@ int main() { int i, j=20; - + if (j==20) { int x=1,y=2,z; z=x+y; - assert(z==3); + __CPROVER_assert(z==3, "z==3"); } - + } diff --git a/regression/goto-analyzer/constant_propagation_01/test.desc b/regression/goto-analyzer/constant_propagation_01/test.desc index 1eb849c3c7a..755dba52ce4 100644 --- a/regression/goto-analyzer/constant_propagation_01/test.desc +++ b/regression/goto-analyzer/constant_propagation_01/test.desc @@ -1,9 +1,9 @@ -FUTURE -constant_propagation1.c ---constants --simplify out.goto +CORE +main.c +--variable --simplify out.gb ^EXIT=0$ ^SIGNAL=0$ -^SIMPLIFIED: assert: 1, assume: 0, goto: 2, assigns: 5, function calls: 0$ -^UNMODIFIED: assert: 0, assume: 0, goto: 0, assigns: 12, function calls: 2$ +^Simplified: assert: 1, assume: 0, goto: 1, assigns: 5, function calls: 0$ +^Unmodified: assert: 0, assume: 0, goto: 0, assigns: 12, function calls: 2$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/constant_propagation_05/constant_propagation_05.c b/regression/goto-analyzer/constant_propagation_02/main.c similarity index 54% rename from regression/goto-analyzer/constant_propagation_05/constant_propagation_05.c rename to regression/goto-analyzer/constant_propagation_02/main.c index 037fbbe0632..e6f6764badf 100644 --- a/regression/goto-analyzer/constant_propagation_05/constant_propagation_05.c +++ b/regression/goto-analyzer/constant_propagation_02/main.c @@ -1,13 +1,12 @@ -#include int main() { int i=0, j=2; - if (i<50) + if (i==0) { i++; j++; } - assert(j!=3); + __CPROVER_assert(j!=3, "j!=3"); } diff --git a/regression/goto-analyzer/constant_propagation_02/original b/regression/goto-analyzer/constant_propagation_02/original deleted file mode 100644 index 13a9e245c81..00000000000 --- a/regression/goto-analyzer/constant_propagation_02/original +++ /dev/null @@ -1,3 +0,0 @@ -Task defaults to --show -Domain defaults to --constants -GOTO-ANALYSER version 5.5 64-bit x86_64 linux diff --git a/regression/goto-analyzer/constant_propagation_02/simplified b/regression/goto-analyzer/constant_propagation_02/simplified deleted file mode 100644 index 6c722a607de..00000000000 --- a/regression/goto-analyzer/constant_propagation_02/simplified +++ /dev/null @@ -1,81 +0,0 @@ -Reading GOTO program from `out.goto' -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -main /* main */ - // 0 file constant_propagation_02.c line 5 function main - signed int i; - // 1 file constant_propagation_02.c line 5 function main - i = 0; - // 2 file constant_propagation_02.c line 5 function main - signed int j; - // 3 file constant_propagation_02.c line 5 function main - j = 2; - // 4 file constant_propagation_02.c line 7 function main - IF FALSE THEN GOTO 1 - // 5 file constant_propagation_02.c line 9 function main - 0 = 1; - // 6 file constant_propagation_02.c line 10 function main - 2 = 3; - // 7 no location - 1: SKIP - // 8 file constant_propagation_02.c line 12 function main - ASSERT FALSE // assertion j!=3 - // 9 file constant_propagation_02.c line 12 function main - GOTO 2 - // 10 file constant_propagation_02.c line 12 function main - (void)0; - // 11 no location - 2: SKIP - // 12 file constant_propagation_02.c line 13 function main - dead j; - // 13 file constant_propagation_02.c line 13 function main - dead i; - // 14 file constant_propagation_02.c line 13 function main - main#return_value = NONDET(signed int); - // 15 file constant_propagation_02.c line 13 function main - END_FUNCTION -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -_start /* _start */ - // 16 no location - __CPROVER_initialize(); - // 17 file constant_propagation_02.c line 3 - main(); - // 18 file constant_propagation_02.c line 3 - return' = main#return_value; - // 19 file constant_propagation_02.c line 3 - dead main#return_value; - // 20 file constant_propagation_02.c line 3 - OUTPUT("return", return'); - // 21 no location - END_FUNCTION -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -__CPROVER_initialize /* __CPROVER_initialize */ - // 22 no location - // Labels: __CPROVER_HIDE - SKIP - // 23 file line 39 - __CPROVER_dead_object = NULL; - // 24 file line 38 - __CPROVER_deallocated = NULL; - // 25 file line 42 - __CPROVER_malloc_is_new_array = FALSE; - // 26 file line 40 - __CPROVER_malloc_object = NULL; - // 27 file line 41 - __CPROVER_malloc_size = 0ul; - // 28 file line 43 - __CPROVER_memory_leak = NULL; - // 29 file line 31 - __CPROVER_next_thread_id = 0ul; - // 30 file line 85 - __CPROVER_pipe_count = 0u; - // 31 file line 65 - __CPROVER_rounding_mode = 0; - // 32 file line 29 - __CPROVER_thread_id = 0ul; - // 33 file line 30 - __CPROVER_threads_exited = ARRAY_OF(FALSE); - // 34 no location - END_FUNCTION diff --git a/regression/goto-analyzer/constant_propagation_02/test.desc b/regression/goto-analyzer/constant_propagation_02/test.desc index 20cc5fcf86e..49b87fa3483 100644 --- a/regression/goto-analyzer/constant_propagation_02/test.desc +++ b/regression/goto-analyzer/constant_propagation_02/test.desc @@ -1,9 +1,9 @@ -FUTURE -constant_propagation_02.c ---constants --simplify out.goto +CORE +main.c +--variable --simplify out.gb ^EXIT=0$ ^SIGNAL=0$ -^SIMPLIFIED: assert: 1, assume: 0, goto: 2, assigns: 6, function calls: 0$ -^UNMODIFIED: assert: 0, assume: 0, goto: 0, assigns: 11, function calls: 2$ +^Simplified: assert: 1, assume: 0, goto: 1, assigns: 6, function calls: 0$ +^Unmodified: assert: 0, assume: 0, goto: 0, assigns: 11, function calls: 2$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/constant_propagation_02/constant_propagation_02.c b/regression/goto-analyzer/constant_propagation_03/main.c similarity index 54% rename from regression/goto-analyzer/constant_propagation_02/constant_propagation_02.c rename to regression/goto-analyzer/constant_propagation_03/main.c index ff139437bd8..3a929f776b8 100644 --- a/regression/goto-analyzer/constant_propagation_02/constant_propagation_02.c +++ b/regression/goto-analyzer/constant_propagation_03/main.c @@ -1,13 +1,12 @@ -#include int main() { int i=0, j=2; - if (i==0) + if (i==0) { i++; j++; } - assert(j!=3); + __CPROVER_assert(j==3, "j==3"); } diff --git a/regression/goto-analyzer/constant_propagation_03/test.desc b/regression/goto-analyzer/constant_propagation_03/test.desc index 2225c1a666e..49b87fa3483 100644 --- a/regression/goto-analyzer/constant_propagation_03/test.desc +++ b/regression/goto-analyzer/constant_propagation_03/test.desc @@ -1,9 +1,9 @@ -FUTURE -constant_propagation_03.c ---constants --simplify out.goto +CORE +main.c +--variable --simplify out.gb ^EXIT=0$ ^SIGNAL=0$ -^SIMPLIFIED: assert: 1, assume: 0, goto: 2, assigns: 6, function calls: 0$ -^UNMODIFIED: assert: 0, assume: 0, goto: 0, assigns: 11, function calls: 2$ +^Simplified: assert: 1, assume: 0, goto: 1, assigns: 6, function calls: 0$ +^Unmodified: assert: 0, assume: 0, goto: 0, assigns: 11, function calls: 2$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/constant_propagation_03/constant_propagation_03.c b/regression/goto-analyzer/constant_propagation_04/main.c similarity index 54% rename from regression/goto-analyzer/constant_propagation_03/constant_propagation_03.c rename to regression/goto-analyzer/constant_propagation_04/main.c index f08f6020d82..b667e66dfe5 100644 --- a/regression/goto-analyzer/constant_propagation_03/constant_propagation_03.c +++ b/regression/goto-analyzer/constant_propagation_04/main.c @@ -1,13 +1,12 @@ -#include int main() { int i=0, j=2; - if (i==0) + if (i<50) { i++; j++; } - assert(j==3); + __CPROVER_assert(j==3, "j==3"); } diff --git a/regression/goto-analyzer/constant_propagation_04/test.desc b/regression/goto-analyzer/constant_propagation_04/test.desc index 2510b3f8a5e..49b87fa3483 100644 --- a/regression/goto-analyzer/constant_propagation_04/test.desc +++ b/regression/goto-analyzer/constant_propagation_04/test.desc @@ -1,9 +1,9 @@ -FUTURE -constant_propagation_04.c ---constants --simplify out.goto +CORE +main.c +--variable --simplify out.gb ^EXIT=0$ ^SIGNAL=0$ -^SIMPLIFIED: assert: 1, assume: 0, goto: 2, assigns: 6, function calls: 0$ -^UNMODIFIED: assert: 0, assume: 0, goto: 0, assigns: 11, function calls: 2$ +^Simplified: assert: 1, assume: 0, goto: 1, assigns: 6, function calls: 0$ +^Unmodified: assert: 0, assume: 0, goto: 0, assigns: 11, function calls: 2$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/constant_propagation_04/constant_propagation_04.c b/regression/goto-analyzer/constant_propagation_05/main.c similarity index 54% rename from regression/goto-analyzer/constant_propagation_04/constant_propagation_04.c rename to regression/goto-analyzer/constant_propagation_05/main.c index ca003ccd2b8..7f5ae516853 100644 --- a/regression/goto-analyzer/constant_propagation_04/constant_propagation_04.c +++ b/regression/goto-analyzer/constant_propagation_05/main.c @@ -1,13 +1,12 @@ -#include int main() { int i=0, j=2; - if (i<50) + if (i<50) { i++; j++; } - assert(j==3); + __CPROVER_assert(j!=3, "j!=3"); } diff --git a/regression/goto-analyzer/constant_propagation_05/test.desc b/regression/goto-analyzer/constant_propagation_05/test.desc index ddb22cc3616..2ebfd52ca32 100644 --- a/regression/goto-analyzer/constant_propagation_05/test.desc +++ b/regression/goto-analyzer/constant_propagation_05/test.desc @@ -1,8 +1,8 @@ -FUTURE -constant_propagation_05.c ---constants --verify +CORE +main.c +--variable --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] file constant_propagation_05.c line 12 function main, assertion j!=3: FAILURE (if reachable)$ +^\[main\.assertion\.1\] .* j!=3: Failure \(if reachable\)$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/constant_propagation_06/constant_propagation_06.c b/regression/goto-analyzer/constant_propagation_06/constant_propagation_06.c deleted file mode 100644 index d1d29427250..00000000000 --- a/regression/goto-analyzer/constant_propagation_06/constant_propagation_06.c +++ /dev/null @@ -1,30 +0,0 @@ -#include - -int main() -{ - int i, j=20; - - if(i>=20) - assert(i>=10); // success - - if(i>=10 && i<=20) - assert(i!=30); // success - - if(i>=10 && i<=20) - assert(i!=15); // fails - - if(i<1 && i>10) - assert(0); // success - - if(i>=10 && j>=i) - assert(j>=10); // success - - if(i>=j) - assert(i>=j); // unknown - - if(i>10) - assert(i>=11); // success - - if(i<=100 && j=10: SUCCESS$ -^\[main.assertion.2\] file constant_propagation_06.c line 11 function main, assertion i!=30: SUCCESS$ -^\[main.assertion.3\] file constant_propagation_06.c line 14 function main, assertion i!=15: UNKNOWN$ -^\[main.assertion.4\] file constant_propagation_06.c line 17 function main, assertion 0: SUCCESS$ -^\[main.assertion.5\] file constant_propagation_06.c line 20 function main, assertion j>=10: SUCCESS$ -^\[main.assertion.6\] file constant_propagation_06.c line 23 function main, assertion i>=j: UNKNOWN$ -^\[main.assertion.7\] file constant_propagation_06.c line 26 function main, assertion i>=11: SUCCESS$ -^\[main.assertion.8\] file constant_propagation_06.c line 29 function main, assertion j<100: SUCCESS$ +^\[main.assertion.1\] .* i\s*<\s*51: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/constant_propagation_10/constant_propagation_10.c b/regression/goto-analyzer/constant_propagation_07/main.c similarity index 79% rename from regression/goto-analyzer/constant_propagation_10/constant_propagation_10.c rename to regression/goto-analyzer/constant_propagation_07/main.c index 169f7965b9d..83db927383e 100644 --- a/regression/goto-analyzer/constant_propagation_10/constant_propagation_10.c +++ b/regression/goto-analyzer/constant_propagation_07/main.c @@ -1,10 +1,10 @@ -#include + int main() { signed int i; signed int j; i = 0; - if(!(i >= 2)) + if(!(i >= 2)) { j = j + 1; i = i + 1; @@ -17,7 +17,7 @@ int main() j = j + 1; i = i + 1; } - assert(!(i < 2)); + __CPROVER_assert(!(i < 2), "!(i < 2)"); } } return 0; diff --git a/regression/goto-analyzer/constant_propagation_07/test.desc b/regression/goto-analyzer/constant_propagation_07/test.desc index 615893d4f78..d3336fc21c0 100644 --- a/regression/goto-analyzer/constant_propagation_07/test.desc +++ b/regression/goto-analyzer/constant_propagation_07/test.desc @@ -1,8 +1,9 @@ -FUTURE -constant_propagation_07.c ---constants --verify +KNOWNBUG +main.c +--variable --simplify out.gb ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] file constant_propagation_07.c line 12 function main, assertion i<51: UNKNOWN$ +^Simplified: assert: 1, assume: 0, goto: 3, assigns: 10, function calls: 0$ +^Unmodified: assert: 0, assume: 0, goto: 1, assigns: 10, function calls: 2$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/constant_propagation_08/constant_propagation_08.c b/regression/goto-analyzer/constant_propagation_08/constant_propagation_08.c deleted file mode 100644 index 3909e3889e4..00000000000 --- a/regression/goto-analyzer/constant_propagation_08/constant_propagation_08.c +++ /dev/null @@ -1,16 +0,0 @@ -#include - -int main() -{ - int i=0, j=2; - - while (i<=50) - { - i++; - j++; - } - assert(i<50); - assert(i<51); - assert(i<52); -} - diff --git a/regression/goto-analyzer/constant_propagation_11/constant_propagation_11.c b/regression/goto-analyzer/constant_propagation_08/main.c similarity index 62% rename from regression/goto-analyzer/constant_propagation_11/constant_propagation_11.c rename to regression/goto-analyzer/constant_propagation_08/main.c index 3022a4f0f19..fa70c7b001d 100644 --- a/regression/goto-analyzer/constant_propagation_11/constant_propagation_11.c +++ b/regression/goto-analyzer/constant_propagation_08/main.c @@ -1,4 +1,4 @@ -#include + int main() { int a[2]; @@ -10,7 +10,7 @@ int main() else a[1]=2; - assert(a[0]==1 || a[1]==2); + __CPROVER_assert(a[0]==1 || a[1]==2, "a[0]==1 || a[1]==2"); return 0; } diff --git a/regression/goto-analyzer/constant_propagation_08/test.desc b/regression/goto-analyzer/constant_propagation_08/test.desc index 994c2c532df..4b10f41e952 100644 --- a/regression/goto-analyzer/constant_propagation_08/test.desc +++ b/regression/goto-analyzer/constant_propagation_08/test.desc @@ -1,10 +1,9 @@ -FUTURE -constant_propagation_08.c ---intervals --verify +KNOWNBUG +main.c +--variable --arrays --simplify out.gb ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] file constant_propagation_08.c line 12 function main, assertion i<50: UNKNOWN$ -^\[main.assertion.2\] file constant_propagation_08.c line 13 function main, assertion i<51: UNKNOWN$ -^\[main.assertion.3\] file constant_propagation_08.c line 14 function main, assertion i<52: SUCCESS$ +^Simplified: assert: 1, assume: 0, goto: 2, assigns: 5, function calls: 0$ +^Unmodified: assert: 0, assume: 0, goto: 4, assigns: 13, function calls: 2$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/constant_propagation_09/constant_propagation_09.c b/regression/goto-analyzer/constant_propagation_09/constant_propagation_09.c deleted file mode 100644 index 002e9063228..00000000000 --- a/regression/goto-analyzer/constant_propagation_09/constant_propagation_09.c +++ /dev/null @@ -1,14 +0,0 @@ -#include - -int main() -{ - int i=0, j=2; - - while (i<=50) - { - i++; - j++; - } - assert(j<52); -} - diff --git a/regression/goto-analyzer/constant_propagation_18/constant_propagation_18.c b/regression/goto-analyzer/constant_propagation_09/main.c similarity index 64% rename from regression/goto-analyzer/constant_propagation_18/constant_propagation_18.c rename to regression/goto-analyzer/constant_propagation_09/main.c index 6639f9b5c81..e3ad2204ca2 100644 --- a/regression/goto-analyzer/constant_propagation_18/constant_propagation_18.c +++ b/regression/goto-analyzer/constant_propagation_09/main.c @@ -1,4 +1,4 @@ -#include + int main() { int a[2]={0,0}; @@ -6,7 +6,7 @@ int main() if (a[0]==0) a[0]=1; - assert(a[0]==2); + __CPROVER_assert(a[0]==0, "a[0]==0"); return 0; } diff --git a/regression/goto-analyzer/constant_propagation_09/test.desc b/regression/goto-analyzer/constant_propagation_09/test.desc index 6a1b75f0c1b..eb8dcca3246 100644 --- a/regression/goto-analyzer/constant_propagation_09/test.desc +++ b/regression/goto-analyzer/constant_propagation_09/test.desc @@ -1,9 +1,9 @@ -FUTURE -constant_propagation_09.c ---intervals --verify +KNOWNBUG +main.c +--variable --arrays --simplify out.gb ^EXIT=0$ ^SIGNAL=0$ -******** Function main -^\[main.assertion.1\] file constant_propagation_09.c line 12 function main, assertion j<52: UNKNOWN$ +^Simplified: assert: 1, assume: 0, goto: 3, assigns: 4, function calls: 0$ +^Unmodified: assert: 0, assume: 0, goto: 0, assigns: 11, function calls: 2$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/constant_propagation_13/constant_propagation_13.c b/regression/goto-analyzer/constant_propagation_10/main.c similarity index 68% rename from regression/goto-analyzer/constant_propagation_13/constant_propagation_13.c rename to regression/goto-analyzer/constant_propagation_10/main.c index ac5933e9177..be7b386afad 100644 --- a/regression/goto-analyzer/constant_propagation_13/constant_propagation_13.c +++ b/regression/goto-analyzer/constant_propagation_10/main.c @@ -1,4 +1,4 @@ -#include + int main() { int a[2]={0,0}; @@ -7,7 +7,7 @@ int main() if (a[0]==0) a[0]=1; - assert(a[0]==2); + __CPROVER_assert(a[0]==2, "a[0]==2"); return 0; } diff --git a/regression/goto-analyzer/constant_propagation_10/test.desc b/regression/goto-analyzer/constant_propagation_10/test.desc index 52d98cb611b..43d07eb8172 100644 --- a/regression/goto-analyzer/constant_propagation_10/test.desc +++ b/regression/goto-analyzer/constant_propagation_10/test.desc @@ -1,9 +1,8 @@ -FUTURE -constant_propagation_10.c ---constants --simplify out.goto +CORE +main.c +--variable --arrays --verify ^EXIT=0$ ^SIGNAL=0$ -^SIMPLIFIED: assert: 1, assume: 0, goto: 4, assigns: 10, function calls: 0$ -^UNMODIFIED: assert: 0, assume: 0, goto: 1, assigns: 10, function calls: 2$ +^\[main\.assertion\.1\] .* a\[0\]==2: Failure \(if reachable\)$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/constant_propagation_14/constant_propagation_14.c b/regression/goto-analyzer/constant_propagation_11/main.c similarity index 51% rename from regression/goto-analyzer/constant_propagation_14/constant_propagation_14.c rename to regression/goto-analyzer/constant_propagation_11/main.c index 124d1e30a20..40e8b43d2e3 100644 --- a/regression/goto-analyzer/constant_propagation_14/constant_propagation_14.c +++ b/regression/goto-analyzer/constant_propagation_11/main.c @@ -1,4 +1,4 @@ -#include + int main() { int a[2]={0,0}; @@ -6,7 +6,7 @@ int main() if (a[0]==0) a[0]=1; - assert(a[0]==1 /*|| a[0]==2*/); + __CPROVER_assert(a[0]==1 /*|| a[0]==2*/, "a[0]==1 /*|| a[0]==2*/"); return 0; } diff --git a/regression/goto-analyzer/constant_propagation_11/test.desc b/regression/goto-analyzer/constant_propagation_11/test.desc index 7c849326cf6..327325637a5 100644 --- a/regression/goto-analyzer/constant_propagation_11/test.desc +++ b/regression/goto-analyzer/constant_propagation_11/test.desc @@ -1,9 +1,9 @@ -FUTURE -constant_propagation_11.c ---constants --simplify out.goto +CORE +main.c +--variable --arrays --simplify out.gb ^EXIT=0$ ^SIGNAL=0$ -^SIMPLIFIED: assert: 1, assume: 0, goto: 2, assigns: 5, function calls: 0$ -^UNMODIFIED: assert: 0, assume: 0, goto: 4, assigns: 13, function calls: 2$ +^Simplified: assert: 1, assume: 0, goto: 1, assigns: 5, function calls: 0$ +^Unmodified: assert: 0, assume: 0, goto: 1, assigns: 10, function calls: 2$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/constant_propagation_15/constant_propagation_15.c b/regression/goto-analyzer/constant_propagation_12/main.c similarity index 64% rename from regression/goto-analyzer/constant_propagation_15/constant_propagation_15.c rename to regression/goto-analyzer/constant_propagation_12/main.c index 9a7e7692d62..e86aaba5d7b 100644 --- a/regression/goto-analyzer/constant_propagation_15/constant_propagation_15.c +++ b/regression/goto-analyzer/constant_propagation_12/main.c @@ -1,4 +1,4 @@ -#include + int main() { int i=0, y; @@ -6,7 +6,7 @@ int main() if (i==0) y=1; - assert(y==1); + __CPROVER_assert(y==1, "y==1"); return 0; } diff --git a/regression/goto-analyzer/constant_propagation_12/test.desc b/regression/goto-analyzer/constant_propagation_12/test.desc index ca5803363ad..2c983dd21fa 100644 --- a/regression/goto-analyzer/constant_propagation_12/test.desc +++ b/regression/goto-analyzer/constant_propagation_12/test.desc @@ -1,9 +1,9 @@ -FUTURE -constant_propagation_12.c ---constants --simplify out.goto +KNOWNBUG +main.c +--variable --simplify out.gb ^EXIT=0$ ^SIGNAL=0$ -^SIMPLIFIED: assert: 1, assume: 0, goto: 3, assigns: 4, function calls: 0$ -^UNMODIFIED: assert: 0, assume: 0, goto: 0, assigns: 11, function calls: 2$ +^Simplified: assert: 1, assume: 0, goto: 1, assigns: 4, function calls: 0$ +^Unmodified: assert: 0, assume: 0, goto: 2, assigns: 11, function calls: 2$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/constant_propagation_16/constant_propagation_16.c b/regression/goto-analyzer/constant_propagation_13/main.c similarity index 64% rename from regression/goto-analyzer/constant_propagation_16/constant_propagation_16.c rename to regression/goto-analyzer/constant_propagation_13/main.c index 102cfd7f812..393ebae92c9 100644 --- a/regression/goto-analyzer/constant_propagation_16/constant_propagation_16.c +++ b/regression/goto-analyzer/constant_propagation_13/main.c @@ -1,4 +1,4 @@ -#include + int main() { int i=0, y; @@ -6,7 +6,7 @@ int main() if (i==0) y=1; - assert(y==0); + __CPROVER_assert(y==0, "y==0"); return 0; } diff --git a/regression/goto-analyzer/constant_propagation_13/test.desc b/regression/goto-analyzer/constant_propagation_13/test.desc index 22f10d125e3..40ff1a7bf30 100644 --- a/regression/goto-analyzer/constant_propagation_13/test.desc +++ b/regression/goto-analyzer/constant_propagation_13/test.desc @@ -1,8 +1,8 @@ -FUTURE -constant_propagation_13.c ---constants --verify +CORE +main.c +--variable --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] file constant_propagation_13.c line 10 function main, assertion a\[0\]==2: FAILURE$ +^\[main\.assertion\.1\] .* y==0: Failure \(if reachable\)$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/constant_propagation_14/main.c b/regression/goto-analyzer/constant_propagation_14/main.c new file mode 100644 index 00000000000..7b38dd7be9e --- /dev/null +++ b/regression/goto-analyzer/constant_propagation_14/main.c @@ -0,0 +1,16 @@ + +int main() +{ + int a[2]={0,0}; + + if (a[0]==0) + a[0]=1; + else + a[0]=2; + + __CPROVER_assert(a[0]==1 || a[0]==2, "a[0]==1 || a[0]==2"); + __CPROVER_assert(a[0]==1 && a[0]==2, "a[0]==1 && a[0]==2"); + + return 0; +} + diff --git a/regression/goto-analyzer/constant_propagation_14/test.desc b/regression/goto-analyzer/constant_propagation_14/test.desc index a39a1f66cda..a0c6e4c6a2d 100644 --- a/regression/goto-analyzer/constant_propagation_14/test.desc +++ b/regression/goto-analyzer/constant_propagation_14/test.desc @@ -1,9 +1,9 @@ -FUTURE -constant_propagation_14.c ---constants --simplify out.goto +CORE +main.c +--variable --arrays --verify ^EXIT=0$ ^SIGNAL=0$ -^SIMPLIFIED: assert: 1, assume: 0, goto: 0$ -^UNKNOWN: assert: 0, assume: 0, goto: 0$ +\[main\.assertion\.1\] .* a\[0\]==1 || a\[0\]==2: Success$ +\[main\.assertion\.2\] .* a\[0\]==1 && a\[0\]==2: Failure \(if reachable\)$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/constant_propagation_12/constant_propagation_12.c b/regression/goto-analyzer/constant_propagation_15/main.c similarity index 64% rename from regression/goto-analyzer/constant_propagation_12/constant_propagation_12.c rename to regression/goto-analyzer/constant_propagation_15/main.c index 55ea9ac7fc2..4e63b0f873a 100644 --- a/regression/goto-analyzer/constant_propagation_12/constant_propagation_12.c +++ b/regression/goto-analyzer/constant_propagation_15/main.c @@ -1,4 +1,4 @@ -#include + int main() { int a[2]={0,0}; @@ -6,7 +6,7 @@ int main() if (a[0]==0) a[0]=1; - assert(a[0]==0); + __CPROVER_assert(a[0]==2, "a[0]==2"); return 0; } diff --git a/regression/goto-analyzer/constant_propagation_15/test.desc b/regression/goto-analyzer/constant_propagation_15/test.desc index 20d36183eb0..43d07eb8172 100644 --- a/regression/goto-analyzer/constant_propagation_15/test.desc +++ b/regression/goto-analyzer/constant_propagation_15/test.desc @@ -1,9 +1,8 @@ -FUTURE -constant_propagation_15.c ---constants --simplify out.goto +CORE +main.c +--variable --arrays --verify ^EXIT=0$ ^SIGNAL=0$ -^SIMPLIFIED: assert: 1, assume: 0, goto: 1, assigns: 4, function calls: 0$ -^UNMODIFIED: assert: 0, assume: 0, goto: 2, assigns: 11, function calls: 2$ +^\[main\.assertion\.1\] .* a\[0\]==2: Failure \(if reachable\)$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/constant_propagation_16/main.c b/regression/goto-analyzer/constant_propagation_16/main.c new file mode 100644 index 00000000000..22fbac6a427 --- /dev/null +++ b/regression/goto-analyzer/constant_propagation_16/main.c @@ -0,0 +1,13 @@ + +void func() +{ + while(1) {} +} + +int main() +{ + func(); + + return 0; +} + diff --git a/regression/goto-analyzer/constant_propagation_16/test.desc b/regression/goto-analyzer/constant_propagation_16/test.desc index b56c871deb4..ef4ab9321a2 100644 --- a/regression/goto-analyzer/constant_propagation_16/test.desc +++ b/regression/goto-analyzer/constant_propagation_16/test.desc @@ -1,8 +1,7 @@ -FUTURE -constant_propagation_16.c ---constants --verify +CORE +main.c +--show --constants ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] file constant_propagation_16.c line 9 function main, assertion y==0: FAILURE (if reachable)$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/constant_propagation_17/constant_propagation_17.c b/regression/goto-analyzer/constant_propagation_17/constant_propagation_17.c deleted file mode 100644 index 8b426fe84b5..00000000000 --- a/regression/goto-analyzer/constant_propagation_17/constant_propagation_17.c +++ /dev/null @@ -1,16 +0,0 @@ -#include -int main() -{ - int a[2]={0,0}; - - if (a[0]==0) - a[0]=1; - else - a[0]=2; - - assert(a[0]==1 || a[0]==2); - assert(a[0]==1 && a[0]==2); - - return 0; -} - diff --git a/regression/goto-analyzer/constant_propagation_07/constant_propagation_07.c b/regression/goto-analyzer/constant_propagation_17/main.c similarity index 62% rename from regression/goto-analyzer/constant_propagation_07/constant_propagation_07.c rename to regression/goto-analyzer/constant_propagation_17/main.c index 40b04edfdd0..cb41fe9e87f 100644 --- a/regression/goto-analyzer/constant_propagation_07/constant_propagation_07.c +++ b/regression/goto-analyzer/constant_propagation_17/main.c @@ -4,11 +4,11 @@ int main() { int i=0, j=2; - while (i<50) + while (i<50) { i++; j++; } - assert(i<51); + __CPROVER_assert(i<51, "i<51"); } diff --git a/regression/goto-analyzer/constant_propagation_17/test.desc b/regression/goto-analyzer/constant_propagation_17/test.desc index acecb91eb0a..4b7db991084 100644 --- a/regression/goto-analyzer/constant_propagation_17/test.desc +++ b/regression/goto-analyzer/constant_propagation_17/test.desc @@ -1,9 +1,8 @@ -FUTURE -constant_propagation_17.c +CORE +main.c --constants --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] file constant_propagation_17.c line 11 function main, assertion a\[0\]==1 || a\[0\]==2: SUCCESS$ -^\[main.assertion.2\] file constant_propagation_17.c line 12 function main, assertion a\[0\]==1 && a\[0\]==2: FAILURE$ +^\[main\.assertion\.1\] .* i\s*<\s*51: (Unknown|Failure \(if reachable\))$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/constant_propagation_18/test.desc b/regression/goto-analyzer/constant_propagation_18/test.desc deleted file mode 100644 index 7ea74c4d264..00000000000 --- a/regression/goto-analyzer/constant_propagation_18/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -FUTURE -constant_propagation_18.c ---constants --verify -^EXIT=0$ -^SIGNAL=0$ -^\[main.assertion.1\] file constant_propagation_18.c line 9 function main, assertion a\[0\]==2: FAILURE$ --- -^warning: ignoring diff --git a/regression/goto-analyzer/demo/main.c b/regression/goto-analyzer/demo/main.c new file mode 100644 index 00000000000..cbea87ebae9 --- /dev/null +++ b/regression/goto-analyzer/demo/main.c @@ -0,0 +1,119 @@ +#include + + +// To demonstrate run +// $ goto-analyzer main.c --variable --verify --pointers --structs +// Will show the asserts + +// To see the pointer optimizations run +// $ goto-analyzer main.c --variable --simplify out.gb --pointers --structs +// $ goto-analyzer out.gb --show-goto-functions + +void func(int unknwon); +int main() +{ + func(4); +} + + +// Pass in an unknown to show when we don't know what branch is taken + +void func(int unknown) +{ + int i=0, j=2; + if (i==0) + { + i++; + j++; + } + + // Knows we took if statement so can conclude assertion is true + __CPROVER_assert(j==3, "j==3"); // Verified + + int value=4; + + int * p2v = &value; + int ** pp2v = &p2v; + + __CPROVER_assert(*p2v==4, "*p2v==4"); + __CPROVER_assert(**pp2v==4, "**pp2v==4"); + + value=10; + + // Tracks the value pointed to has changed + __CPROVER_assert(*p2v==10, "*p2v==10"); + __CPROVER_assert(**pp2v==10, "**pp2v==10"); + + *p2v = 15; + __CPROVER_assert(value==15, "value==15"); + __CPROVER_assert(*p2v==15, "*p2v==15"); + __CPROVER_assert(**pp2v==15, "**pp2v==15"); + + **pp2v = 20; + __CPROVER_assert(value==20, "value==20"); + __CPROVER_assert(*p2v==20, "*p2v==20"); + __CPROVER_assert(**pp2v==20, "**pp2v==20"); + + int other = 5; + p2v = &other; + + __CPROVER_assert(*p2v==5, "*p2v==5"); + __CPROVER_assert(**pp2v==5, "**pp2v==5"); + + if(unknown > 10) + { + p2v = &value; + } + else + { + p2v = &other; + } + + __CPROVER_assert(pp2v==&p2v, "pp2v==&p2v"); // success (even though p2v has changed) + __CPROVER_assert(*p2v==10, "*p2v==10"); // unknown since we don't know anymore what p2v points to + __CPROVER_assert(**pp2v==10, "**pp2v==10"); // unknown + + // Running this through --simplify will yield: + // yp = &x + int x = 4; + int * xp = &x; + int * yp = xp; + + int ** ypp = &yp; + **ypp = *yp; + + int array[4] = {0, 1 , 2, 3}; + + __CPROVER_assert(array[0] == 0, "array[0] == 0"); // Success + __CPROVER_assert(array[3] == 3, "array[3] == 3"); // Success + + if(unknown > 10) + { + array[0] = 4; + array[1] = 1; + array[2] = 5; + } + else + { + array[0] = 4; + array[2] = 10; + } + + __CPROVER_assert(array[0] == 4, "array[0] == 4"); // Success + __CPROVER_assert(array[1] == 1, "array[1] == 1"); // Success + __CPROVER_assert(array[2] == 5, "array[2] == 5"); // Unknown + __CPROVER_assert(array[3] == 3, "array[3] == 3"); // Success + + + typedef struct + { + int a; + int b; + } struct_t; + + struct_t s; + s.a = 1; + + __CPROVER_assert(s.a == 1, "s.a == 1"); + __CPROVER_assert(s.a == 2, "s.a == 2"); +} diff --git a/regression/goto-analyzer/intervals1/intervals1.c b/regression/goto-analyzer/intervals1/intervals1.c deleted file mode 100644 index cdec490fe6d..00000000000 --- a/regression/goto-analyzer/intervals1/intervals1.c +++ /dev/null @@ -1,30 +0,0 @@ -#include - -int main() -{ - int i, j=20; - - if(i>=20) - assert(i>=10); - - if(i>=10 && i<=20) - assert(i!=30); - - if(i>=10 && i<=20) - assert(i!=15); // fails - - if(i<1 && i>10) - assert(0); - - if(i>=10 && j>=i) - assert(j>=10); - - if(i>=j) - assert(i>=j); // fails - - if(i>10) - assert(i>=11); - - if(i<=100 && j=10: SUCCESS$ -^\[main.assertion.2\] file intervals1.c line 11 function main, assertion i!=30: SUCCESS$ -^\[main.assertion.3\] file intervals1.c line 14 function main, assertion i!=15: UNKNOWN$ -^\[main.assertion.4\] file intervals1.c line 17 function main, assertion 0: SUCCESS$ -^\[main.assertion.5\] file intervals1.c line 20 function main, assertion j>=10: SUCCESS$ -^\[main.assertion.6\] file intervals1.c line 23 function main, assertion i>=j: UNKNOWN$ -^\[main.assertion.7\] file intervals1.c line 26 function main, assertion i>=11: SUCCESS$ -^\[main.assertion.8\] file intervals1.c line 29 function main, assertion j<100: SUCCESS$ --- -^warning: ignoring diff --git a/regression/goto-analyzer/intervals10/intervals10.c b/regression/goto-analyzer/intervals10/intervals10.c deleted file mode 100644 index b27cc6f2001..00000000000 --- a/regression/goto-analyzer/intervals10/intervals10.c +++ /dev/null @@ -1,21 +0,0 @@ -#include - -int main() -{ - int i, j; - - if(i<=100 && j100); // fails - - if(i<=100 && j100: FAILURE (if reachable)$ -^\[main.assertion.4\] file intervals10.c line 17 function main, assertion j<99: UNKNOWN$ -^\[main.assertion.5\] file intervals10.c line 20 function main, assertion j==100: FAILURE (if reachable)$ --- -^warning: ignoring diff --git a/regression/goto-analyzer/intervals11/test.desc b/regression/goto-analyzer/intervals11/test.desc deleted file mode 100644 index 039cbffbeb0..00000000000 --- a/regression/goto-analyzer/intervals11/test.desc +++ /dev/null @@ -1,9 +0,0 @@ -FUTURE -intervals11.c ---intervals --verify -^EXIT=0$ -^SIGNAL=0$ -^\[main.assertion.1\] file intervals11.c line 30 function main, assertion y\[i\]>=-1.0f && y\[i\]<=1.0f: UNKNOWN$ -^\[main.assertion.2\] file intervals11.c line 35 function main, assertion y\[i\]>=-1.0f && y\[i\]<=1.0f: UNKNOWN$ --- -^warning: ignoring diff --git a/regression/goto-analyzer/intervals12/test.desc b/regression/goto-analyzer/intervals12/test.desc deleted file mode 100644 index 59a724c28b5..00000000000 --- a/regression/goto-analyzer/intervals12/test.desc +++ /dev/null @@ -1,9 +0,0 @@ -FUTURE -intervals12.c ---intervals --verify -^EXIT=0$ -^SIGNAL=0$ -^[main.assertion.1] file intervals12.c line 8 function main, assertion j < 0: SUCCESS$ -^[main.assertion.2] file intervals12.c line 11 function main, assertion j < 0: SUCCESS$ --- -^warning: ignoring diff --git a/regression/goto-analyzer/intervals2/intervals2.c b/regression/goto-analyzer/intervals2/intervals2.c deleted file mode 100644 index d542854bb6a..00000000000 --- a/regression/goto-analyzer/intervals2/intervals2.c +++ /dev/null @@ -1,11 +0,0 @@ -#include - -int main(){ - int x; - if (x > 0 && x < 20) { - //if (x < 20) { - assert(x > -10 && x < 100); - //} - } - return 0; -} diff --git a/regression/goto-analyzer/intervals2/test.desc b/regression/goto-analyzer/intervals2/test.desc deleted file mode 100644 index 65aae030db1..00000000000 --- a/regression/goto-analyzer/intervals2/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -KNOWNBUG -intervals2.c ---intervals --verify -^EXIT=0$ -^SIGNAL=0$ -^\[main.assertion.1\] file intervals2.c line 7 function main, assertion x > -10 && x < 100: SUCCESS$ --- -^warning: ignoring diff --git a/regression/goto-analyzer/intervals3/test.desc b/regression/goto-analyzer/intervals3/test.desc deleted file mode 100644 index 69ded2182ee..00000000000 --- a/regression/goto-analyzer/intervals3/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -KNOWNBUG -intervals3.c ---intervals --verify -^EXIT=0$ -^SIGNAL=0$ -^\[main.assertion.1\] file intervals3.c line 7 function main, assertion x > -10 || x < 100: SUCCESS$ --- -^warning: ignoring diff --git a/regression/goto-analyzer/intervals4/test.desc b/regression/goto-analyzer/intervals4/test.desc deleted file mode 100644 index 2b725180e3f..00000000000 --- a/regression/goto-analyzer/intervals4/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -KNOWNBUG -intervals4.c ---intervals --verify -^EXIT=0$ -^SIGNAL=0$ -^\[main.assertion.1\] file intervals4.c line 9 function main, assertion i >= 1 && i <= 2: SUCCESS$ --- -^warning: ignoring diff --git a/regression/goto-analyzer/intervals5/test.desc b/regression/goto-analyzer/intervals5/test.desc deleted file mode 100644 index eb64fbc13d1..00000000000 --- a/regression/goto-analyzer/intervals5/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -KNOWNBUG -intervals5.c ---intervals --verify -^EXIT=0$ -^SIGNAL=0$ -^\[main.assertion.1\] file intervals5.c line 9 function main, assertion i >= 1 || i <= 2: SUCCESS$ --- -^warning: ignoring diff --git a/regression/goto-analyzer/intervals6/test.desc b/regression/goto-analyzer/intervals6/test.desc deleted file mode 100644 index 6e36b7948d2..00000000000 --- a/regression/goto-analyzer/intervals6/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -FUTURE -intervals6.c ---intervals --verify -^EXIT=0$ -^SIGNAL=0$ -^\[main.assertion.1\] file intervals6.c line 7 function main, assertion x < -10 || x > 100: FAILURE (if reachable)$ --- -^warning: ignoring diff --git a/regression/goto-analyzer/intervals7/test.desc b/regression/goto-analyzer/intervals7/test.desc deleted file mode 100644 index 6a42b4a30ec..00000000000 --- a/regression/goto-analyzer/intervals7/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -FUTURE -intervals7.c ---intervals --verify -^EXIT=0$ -^SIGNAL=0$ -^\[main.assertion.1\] file intervals7.c line 7 function main, assertion x < -10 && x > 100: FAILURE (if reachable)$ --- -^warning: ignoring diff --git a/regression/goto-analyzer/intervals8/intervals8.c b/regression/goto-analyzer/intervals8/intervals8.c deleted file mode 100644 index 4128ac07ce5..00000000000 --- a/regression/goto-analyzer/intervals8/intervals8.c +++ /dev/null @@ -1,9 +0,0 @@ -#include - -int main(){ - int x; - if (x > 0 && x < 20) { - assert(x < -10 && x < 100); - } - return 0; -} diff --git a/regression/goto-analyzer/intervals8/test.desc b/regression/goto-analyzer/intervals8/test.desc deleted file mode 100644 index 7500059a717..00000000000 --- a/regression/goto-analyzer/intervals8/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -FUTURE -intervals8.c ---intervals --verify -^EXIT=0$ -^SIGNAL=0$ -^\[main.assertion.1\] file intervals8.c line 6 function main, assertion x < -10 && x < 100: FAILURE (if reachable)$ --- -^warning: ignoring diff --git a/regression/goto-analyzer/intervals9/intervals9.c b/regression/goto-analyzer/intervals9/intervals9.c deleted file mode 100644 index 27739c7aa28..00000000000 --- a/regression/goto-analyzer/intervals9/intervals9.c +++ /dev/null @@ -1,12 +0,0 @@ -#include - -int main() -{ - int i; - - if(i>0) - if(i<3) - assert(i>=1 && i<=2); - - return 0; -} diff --git a/regression/goto-analyzer/intervals9/test.desc b/regression/goto-analyzer/intervals9/test.desc deleted file mode 100644 index 37c33b97288..00000000000 --- a/regression/goto-analyzer/intervals9/test.desc +++ /dev/null @@ -1,8 +0,0 @@ -KNOWNBUG -intervals9.c ---intervals --verify -^EXIT=0$ -^SIGNAL=0$ -^\[main.assertion.1\] file intervals9.c line 9 function main, assertion i>=1 && i<=2: SUCCESS$ --- -^warning: ignoring diff --git a/regression/goto-analyzer/intervals_01/main.c b/regression/goto-analyzer/intervals_01/main.c new file mode 100644 index 00000000000..68f3c189bea --- /dev/null +++ b/regression/goto-analyzer/intervals_01/main.c @@ -0,0 +1,29 @@ + +int main() +{ + int i, j=20; + + if(i>=20) + __CPROVER_assert(i>=10, "i>=10"); + + if(i>=10 && i<=20) + __CPROVER_assert(i!=30, "i!=30"); + + if(i>=10 && i<=20) + __CPROVER_assert(i!=15, "i!=15"); // fails + + if(i<1 && i>10) + __CPROVER_assert(0, "0"); + + if(i>=10 && j>=i) + __CPROVER_assert(j>=10, "j>=10"); + + if(i>=j) + __CPROVER_assert(i>=j, "i>=j"); // fails + + if(i>10) + __CPROVER_assert(i>=11, "i>=11"); + + if(i<=100 && j=\s*10: Success$ +^\[main\.assertion\.2\] .* i\s*!=\s*30: Success$ +^\[main\.assertion\.3\] .* i\s*!=\s*15: Unknown$ +^\[main\.assertion\.4\] .* 0: Success$ +^\[main\.assertion\.5\] .* j\s*>=\s*10: Success$ +^\[main\.assertion\.6\] .* i\s*>=\s*j: Unknown$ +^\[main\.assertion\.7\] .* i\s*>=\s*11: Success$ +^\[main\.assertion\.8]\ .* j\s*<\s*100: Success$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/intervals_02/main.c b/regression/goto-analyzer/intervals_02/main.c new file mode 100644 index 00000000000..eecb30f3613 --- /dev/null +++ b/regression/goto-analyzer/intervals_02/main.c @@ -0,0 +1,8 @@ + +int main(){ + int x; + if (x > 0 && x < 20) { + __CPROVER_assert(x > -10 && x < 100, "x > -10 && x < 100"); + } + return 0; +} diff --git a/regression/goto-analyzer/intervals_02/test.desc b/regression/goto-analyzer/intervals_02/test.desc new file mode 100644 index 00000000000..fa4f926287f --- /dev/null +++ b/regression/goto-analyzer/intervals_02/test.desc @@ -0,0 +1,8 @@ +KNOWNBUG +main.c +--intervals --verify +^EXIT=0$ +^SIGNAL=0$ +^\[main.assertion.1\] file main.c line 7 function main, assertion x > -10 && x < 100: Success$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/intervals3/intervals3.c b/regression/goto-analyzer/intervals_03/main.c similarity index 54% rename from regression/goto-analyzer/intervals3/intervals3.c rename to regression/goto-analyzer/intervals_03/main.c index bbaa3ce4e1e..816d67172dc 100644 --- a/regression/goto-analyzer/intervals3/intervals3.c +++ b/regression/goto-analyzer/intervals_03/main.c @@ -1,10 +1,9 @@ -#include int main(){ int x; if (x > 0) { if (x < 20) { - assert(x > -10 || x < 100); + __CPROVER_assert(x > -10 || x < 100, "x > -10 || x < 100"); } } return 0; diff --git a/regression/goto-analyzer/intervals_03/test.desc b/regression/goto-analyzer/intervals_03/test.desc new file mode 100644 index 00000000000..79042c334de --- /dev/null +++ b/regression/goto-analyzer/intervals_03/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--intervals --verify +^EXIT=0$ +^SIGNAL=0$ +^\[main.assertion.1\] file main.c line 7 function main, assertion x > -10 || x < 100: Success$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/intervals4/intervals4.c b/regression/goto-analyzer/intervals_04/main.c similarity index 53% rename from regression/goto-analyzer/intervals4/intervals4.c rename to regression/goto-analyzer/intervals_04/main.c index 790a5f1379f..6dc4da4fd02 100644 --- a/regression/goto-analyzer/intervals4/intervals4.c +++ b/regression/goto-analyzer/intervals_04/main.c @@ -1,4 +1,3 @@ -//#include int main() { @@ -6,7 +5,7 @@ int main() if(i>0) if(i<3) - assert(i>=1 && i<=2); + __CPROVER_assert(i>=1 && i<=2, "i>=1 && i<=2"); return 0; } diff --git a/regression/goto-analyzer/intervals_04/test.desc b/regression/goto-analyzer/intervals_04/test.desc new file mode 100644 index 00000000000..5bb03255f37 --- /dev/null +++ b/regression/goto-analyzer/intervals_04/test.desc @@ -0,0 +1,8 @@ +KNOWNBUG +main.c +--intervals --verify +^EXIT=0$ +^SIGNAL=0$ +^\[main.assertion.1\] file main.c line 9 function main, assertion i >= 1 && i <= 2: Success$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/intervals5/intervals5.c b/regression/goto-analyzer/intervals_05/main.c similarity index 53% rename from regression/goto-analyzer/intervals5/intervals5.c rename to regression/goto-analyzer/intervals_05/main.c index ed19ba71590..b1337e9f72c 100644 --- a/regression/goto-analyzer/intervals5/intervals5.c +++ b/regression/goto-analyzer/intervals_05/main.c @@ -1,4 +1,3 @@ -//#include int main() { @@ -6,7 +5,7 @@ int main() if(i>0) if(i<3) - assert(i>=1 || i<=2); + __CPROVER_assert(i>=1 || i<=2, "i>=1 || i<=2"); return 0; } diff --git a/regression/goto-analyzer/intervals_05/test.desc b/regression/goto-analyzer/intervals_05/test.desc new file mode 100644 index 00000000000..5c9af29a2b1 --- /dev/null +++ b/regression/goto-analyzer/intervals_05/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--intervals --verify +^EXIT=0$ +^SIGNAL=0$ +^\[main.assertion.1\] file main.c line 9 function main, assertion i >= 1 || i <= 2: Success$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/intervals6/intervals6.c b/regression/goto-analyzer/intervals_06/main.c similarity index 54% rename from regression/goto-analyzer/intervals6/intervals6.c rename to regression/goto-analyzer/intervals_06/main.c index e93240e7573..aa55440a7eb 100644 --- a/regression/goto-analyzer/intervals6/intervals6.c +++ b/regression/goto-analyzer/intervals_06/main.c @@ -1,10 +1,9 @@ -#include int main(){ int x; if (x > 0) { if (x < 20) { - assert(x < -10 || x > 100); + __CPROVER_assert(x < -10 || x > 100, "x < -10 || x > 100"); } } return 0; diff --git a/regression/goto-analyzer/intervals_06/test.desc b/regression/goto-analyzer/intervals_06/test.desc new file mode 100644 index 00000000000..2dc8d29a3b6 --- /dev/null +++ b/regression/goto-analyzer/intervals_06/test.desc @@ -0,0 +1,8 @@ +FUTURE +main.c +--intervals --verify +^EXIT=0$ +^SIGNAL=0$ +^\[main.assertion.1\] file main.c line 7 function main, assertion x < -10 || x > 100: Failure (if reachable)$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/intervals7/intervals7.c b/regression/goto-analyzer/intervals_07/main.c similarity index 54% rename from regression/goto-analyzer/intervals7/intervals7.c rename to regression/goto-analyzer/intervals_07/main.c index c893c413ad5..d4c5a079e53 100644 --- a/regression/goto-analyzer/intervals7/intervals7.c +++ b/regression/goto-analyzer/intervals_07/main.c @@ -1,10 +1,9 @@ -#include int main(){ int x; if (x > 0) { if (x < 20) { - assert(x < -10 && x > 100); + __CPROVER_assert(x < -10 && x > 100, "x < -10 && x > 100"); } } return 0; diff --git a/regression/goto-analyzer/intervals_07/test.desc b/regression/goto-analyzer/intervals_07/test.desc new file mode 100644 index 00000000000..aa3962f39de --- /dev/null +++ b/regression/goto-analyzer/intervals_07/test.desc @@ -0,0 +1,8 @@ +FUTURE +main.c +--intervals --verify +^EXIT=0$ +^SIGNAL=0$ +^\[main.assertion.1\] file main.c line 7 function main, assertion x < -10 && x > 100: Failure (if reachable)$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/intervals_08/main.c b/regression/goto-analyzer/intervals_08/main.c new file mode 100644 index 00000000000..8c4b6683739 --- /dev/null +++ b/regression/goto-analyzer/intervals_08/main.c @@ -0,0 +1,8 @@ + +int main(){ + int x; + if (x > 0 && x < 20) { + __CPROVER_assert(x < -10 && x < 100, "x < -10 && x < 100"); + } + return 0; +} diff --git a/regression/goto-analyzer/intervals_08/test.desc b/regression/goto-analyzer/intervals_08/test.desc new file mode 100644 index 00000000000..7b83ecd0f21 --- /dev/null +++ b/regression/goto-analyzer/intervals_08/test.desc @@ -0,0 +1,8 @@ +FUTURE +main.c +--intervals --verify +^EXIT=0$ +^SIGNAL=0$ +^\[main.assertion.1\] file main.c line 6 function main, assertion x < -10 && x < 100: Failure (if reachable)$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/intervals_09/main.c b/regression/goto-analyzer/intervals_09/main.c new file mode 100644 index 00000000000..6dc4da4fd02 --- /dev/null +++ b/regression/goto-analyzer/intervals_09/main.c @@ -0,0 +1,11 @@ + +int main() +{ + int i; + + if(i>0) + if(i<3) + __CPROVER_assert(i>=1 && i<=2, "i>=1 && i<=2"); + + return 0; +} diff --git a/regression/goto-analyzer/intervals_09/test.desc b/regression/goto-analyzer/intervals_09/test.desc new file mode 100644 index 00000000000..83776b8ae34 --- /dev/null +++ b/regression/goto-analyzer/intervals_09/test.desc @@ -0,0 +1,8 @@ +KNOWNBUG +main.c +--intervals --verify +^EXIT=0$ +^SIGNAL=0$ +^\[main.assertion.1\] file main.c line 9 function main, assertion i>=1 && i<=2: Success$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/intervals_10/main.c b/regression/goto-analyzer/intervals_10/main.c new file mode 100644 index 00000000000..8eb55131936 --- /dev/null +++ b/regression/goto-analyzer/intervals_10/main.c @@ -0,0 +1,20 @@ + +int main() +{ + int i, j; + + if(i<=100 && j100, "j>100"); // fails + + if(i<=100 && j100: Failure (if reachable)$ +^\[main.assertion.4\] file main.c line 17 function main, assertion j<99: Unknown$ +^\[main.assertion.5\] file main.c line 20 function main, assertion j==100: Failure (if reachable)$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/intervals11/intervals11.c b/regression/goto-analyzer/intervals_11/main.c similarity index 80% rename from regression/goto-analyzer/intervals11/intervals11.c rename to regression/goto-analyzer/intervals_11/main.c index 2f061cd554d..a97f00f4429 100644 --- a/regression/goto-analyzer/intervals11/intervals11.c +++ b/regression/goto-analyzer/intervals_11/main.c @@ -1,4 +1,4 @@ -#include + const int xLen = 10; const int Alen = 2; const int Blen = 1; @@ -13,7 +13,7 @@ int main() { float y_aux[xLen]; float total=0; for (i=0;i=-1 && x[i]<=1); x_aux[i]=0; y_aux[i]=0; @@ -27,12 +27,12 @@ int main() { /* Num, x values */ for (j = 0; j < Blen; j++) { y[i] = y[i] + B[j]*x_aux[j]; - assert(y[i]>=-1.0f && y[i]<=1.0f); //success + __CPROVER_assert(y[i]>=-1.0f && y[i]<=1.0f, "y[i]>=-1.0f && y[i]<=1.0f"); //success } /* Den, y values */ for(j=0;j=-1.0f && y[i]<=1.0f); //fails + __CPROVER_assert(y[i]>=-1.0f && y[i]<=1.0f, "y[i]>=-1.0f && y[i]<=1.0f"); //fails } /* Update past y values */ for(j=Alen-2;j>=1;j--) diff --git a/regression/goto-analyzer/intervals_11/test.desc b/regression/goto-analyzer/intervals_11/test.desc new file mode 100644 index 00000000000..799ad36f64f --- /dev/null +++ b/regression/goto-analyzer/intervals_11/test.desc @@ -0,0 +1,9 @@ +FUTURE +main.c +--intervals --verify +^EXIT=0$ +^SIGNAL=0$ +^\[main.assertion.1\] file main.c line 30 function main, assertion y\[i\]>=-1.0f && y\[i\]<=1.0f: Unknown$ +^\[main.assertion.2\] file main.c line 35 function main, assertion y\[i\]>=-1.0f && y\[i\]<=1.0f: Unknown$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/intervals12/intervals12.c b/regression/goto-analyzer/intervals_12/main.c similarity index 57% rename from regression/goto-analyzer/intervals12/intervals12.c rename to regression/goto-analyzer/intervals_12/main.c index 15d865adf80..c5ff1c34061 100644 --- a/regression/goto-analyzer/intervals12/intervals12.c +++ b/regression/goto-analyzer/intervals_12/main.c @@ -1,14 +1,13 @@ -#include int main (void) { int i; int j; if (i <= 0 && j < i) - assert(j < 0); + __CPROVER_assert(j < 0, "j < 0"); if (j < i && i <= 0) - assert(j < 0); + __CPROVER_assert(j < 0, "j < 0"); return 0; } diff --git a/regression/goto-analyzer/intervals_12/test.desc b/regression/goto-analyzer/intervals_12/test.desc new file mode 100644 index 00000000000..ffdf46857de --- /dev/null +++ b/regression/goto-analyzer/intervals_12/test.desc @@ -0,0 +1,9 @@ +FUTURE +main.c +--intervals --verify +^EXIT=0$ +^SIGNAL=0$ +^[main.assertion.1] file main.c line 8 function main, assertion j < 0: Success$ +^[main.assertion.2] file main.c line 11 function main, assertion j < 0: Success$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/intervals_13/main.c b/regression/goto-analyzer/intervals_13/main.c new file mode 100644 index 00000000000..0de4b75dc1d --- /dev/null +++ b/regression/goto-analyzer/intervals_13/main.c @@ -0,0 +1,29 @@ + +int main() +{ + int i, j=20; + + if(i>=20) + __CPROVER_assert(i>=10, "i>=10"); // success + + if(i>=10 && i<=20) + __CPROVER_assert(i!=30, "i!=30"); // success + + if(i>=10 && i<=20) + __CPROVER_assert(i!=15, "i!=15"); // fails + + if(i<1 && i>10) + __CPROVER_assert(0, "0"); // success + + if(i>=10 && j>=i) + __CPROVER_assert(j>=10, "j>=10"); // success + + if(i>=j) + __CPROVER_assert(i>=j, "i>=j"); // unknown + + if(i>10) + __CPROVER_assert(i>=11, "i>=11"); // success + + if(i<=100 && j=\s*10: Success$ +^\[main\.assertion\.2\] .* i\s*!=\s*30: Success$ +^\[main\.assertion\.3\] .* i\s*!=\s*15: Unknown$ +^\[main\.assertion\.4\] .* 0: Success$ +^\[main\.assertion\.5\] .* j\s*>=\s*10: Success$ +^\[main\.assertion\.6\] .* i\s*>=\s*j: Unknown$ +^\[main\.assertion\.7\] .* i\s*>=\s*11: Success$ +^\[main\.assertion\.8\] .* j\s*<\s*100: Success$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/intervals_14/main.c b/regression/goto-analyzer/intervals_14/main.c new file mode 100644 index 00000000000..106d3fb61e1 --- /dev/null +++ b/regression/goto-analyzer/intervals_14/main.c @@ -0,0 +1,15 @@ + +int main() +{ + int i=0, j=2; + + while (i<=50) + { + i++; + j++; + } + __CPROVER_assert(i<50, "i<50"); + __CPROVER_assert(i<51, "i<51"); + __CPROVER_assert(i<52, "i<52"); +} + diff --git a/regression/goto-analyzer/intervals_14/test.desc b/regression/goto-analyzer/intervals_14/test.desc new file mode 100644 index 00000000000..20a01bf3e12 --- /dev/null +++ b/regression/goto-analyzer/intervals_14/test.desc @@ -0,0 +1,10 @@ +FUTURE +main.c +--intervals --verify +^EXIT=0$ +^SIGNAL=0$ +^\[main.assertion.1\] file main.c line 12 function main, assertion i<50: Unknown$ +^\[main.assertion.2\] file main.c line 13 function main, assertion i<51: Unknown$ +^\[main.assertion.3\] file main.c line 14 function main, assertion i<52: Success$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/intervals_15/main.c b/regression/goto-analyzer/intervals_15/main.c new file mode 100644 index 00000000000..40673b0e5e6 --- /dev/null +++ b/regression/goto-analyzer/intervals_15/main.c @@ -0,0 +1,13 @@ + +int main() +{ + int i=0, j=2; + + while (i<=50) + { + i++; + j++; + } + __CPROVER_assert(j<52, "j<52"); +} + diff --git a/regression/goto-analyzer/intervals_15/test.desc b/regression/goto-analyzer/intervals_15/test.desc new file mode 100644 index 00000000000..91036e37a4c --- /dev/null +++ b/regression/goto-analyzer/intervals_15/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--intervals --verify +^EXIT=0$ +^SIGNAL=0$ +^\[main\.assertion\.1\] .* j\s*<\s*52: Unknown$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/intervals_16/main.c b/regression/goto-analyzer/intervals_16/main.c new file mode 100644 index 00000000000..40673b0e5e6 --- /dev/null +++ b/regression/goto-analyzer/intervals_16/main.c @@ -0,0 +1,13 @@ + +int main() +{ + int i=0, j=2; + + while (i<=50) + { + i++; + j++; + } + __CPROVER_assert(j<52, "j<52"); +} + diff --git a/regression/goto-analyzer/intervals_16/test.desc b/regression/goto-analyzer/intervals_16/test.desc new file mode 100644 index 00000000000..ef9d6ae0a0a --- /dev/null +++ b/regression/goto-analyzer/intervals_16/test.desc @@ -0,0 +1,8 @@ +CORE +main.c +--intervals --verify +^EXIT=0$ +^SIGNAL=0$ +^\[main\.assertion\.1\] .* j\s*<\s*52: (Unknown|Failure \(if reachable\))$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/minimal-reproducer-for-struct-problem/minimal_reproducer_for_struct_problem.c b/regression/goto-analyzer/minimal-reproducer-for-struct-problem/minimal_reproducer_for_struct_problem.c new file mode 100644 index 00000000000..b763f672118 --- /dev/null +++ b/regression/goto-analyzer/minimal-reproducer-for-struct-problem/minimal_reproducer_for_struct_problem.c @@ -0,0 +1,28 @@ +#include + +int main(int argc, char *argv[]) +{ + // Test if we can represent constant structs + struct int_struct + { + int a; + }; + + struct int_struct x = {0}; + x.a = 0; + __CPROVER_assert(x.a==0, "x.a==0"); + __CPROVER_assert(x.a==1, "x.a==1"); + + if(argc>2) + { + __CPROVER_assert(x.a==0, "x.a==0"); + __CPROVER_assert(x.a==1, "x.a==1"); + x.a=1; + __CPROVER_assert(x.a==0, "x.a==0"); + __CPROVER_assert(x.a==1, "x.a==1"); + } + __CPROVER_assert(x.a==0, "x.a==0"); + __CPROVER_assert(x.a==1, "x.a==1"); + + return 0; +} diff --git a/regression/goto-analyzer/minimal-reproducer-for-struct-problem/test.desc b/regression/goto-analyzer/minimal-reproducer-for-struct-problem/test.desc new file mode 100644 index 00000000000..48983ce22d7 --- /dev/null +++ b/regression/goto-analyzer/minimal-reproducer-for-struct-problem/test.desc @@ -0,0 +1,15 @@ +CORE +minimal_reproducer_for_struct_problem.c +--variable --structs --verify +^EXIT=0$ +^SIGNAL=0$ +^\[main.assertion.1\] .* x.a==0: Success$ +^\[main.assertion.2\] .* x.a==1: Failure \(if reachable\)$ +^\[main.assertion.3\] .* x.a==0: Success$ +^\[main.assertion.4\] .* x.a==1: Failure \(if reachable\)$ +^\[main.assertion.5\] .* x.a==0: Failure \(if reachable\)$ +^\[main.assertion.6\] .* x.a==1: Success$ +^\[main.assertion.7\] .* x.a==0: Unknown$ +^\[main.assertion.8\] .* x.a==1: Unknown$ +-- +^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-common-files/array_of_array_sensitivity_tests.c b/regression/goto-analyzer/sensitivity-test-common-files/array_of_array_sensitivity_tests.c index 63af187ade2..0ea6f6ac258 100644 --- a/regression/goto-analyzer/sensitivity-test-common-files/array_of_array_sensitivity_tests.c +++ b/regression/goto-analyzer/sensitivity-test-common-files/array_of_array_sensitivity_tests.c @@ -8,34 +8,34 @@ int main(int argc, char *argv[]) int b[3][3]={{0, 1, 2}, {3, 4, 5}, {6, 7, 8}}; // Test if we can represent uniform constant arrays - assert(a[1][2]==0); - assert(a[1][2]==1); + __CPROVER_assert(a[1][2]==0, "a[1][2]==0"); + __CPROVER_assert(a[1][2]==1, "a[1][2]==1"); // Test if we can represent constant arrays which aren't uniform - assert(b[1][2]==5); - assert(b[1][2]==0); + __CPROVER_assert(b[1][2]==5, "b[1][2]==5"); + __CPROVER_assert(b[1][2]==0, "b[1][2]==0"); // Test alternative syntax for accessing an array value - assert(*(b[1]+2)==5); - assert(*(b[1]+2)==0); - assert((*(b+1))[2]==5); - assert((*(b+1))[2]==0); - assert(*(*(b+1)+2)==5); - assert(*(*(b+1)+2)==0); - assert(1[b][2]==5); - assert(1[b][2]==0); - assert(*(1[b]+2)==5); - assert(*(1[b]+2)==0); - assert((*(1+b))[2]==5); - assert((*(1+b))[2]==0); - assert(*(*(1+b)+2)==5); - assert(*(*(1+b)+2)==0); - assert(2[1[b]]==5); - assert(2[1[b]]==0); - assert(*(2+1[b])==5); - assert(*(2+1[b])==0); - assert(*(2+*(1+b))==5); - assert(*(2+*(1+b))==0); + __CPROVER_assert(*(b[1]+2)==5, "*(b[1]+2)==5"); + __CPROVER_assert(*(b[1]+2)==0, "*(b[1]+2)==0"); + __CPROVER_assert((*(b+1))[2]==5, "(*(b+1))[2]==5"); + __CPROVER_assert((*(b+1))[2]==0, "(*(b+1))[2]==0"); + __CPROVER_assert(*(*(b+1)+2)==5, "*(*(b+1)+2)==5"); + __CPROVER_assert(*(*(b+1)+2)==0, "*(*(b+1)+2)==0"); + __CPROVER_assert(1[b][2]==5, "1[b][2]==5"); + __CPROVER_assert(1[b][2]==0, "1[b][2]==0"); + __CPROVER_assert(*(1[b]+2)==5, "*(1[b]+2)==5"); + __CPROVER_assert(*(1[b]+2)==0, "*(1[b]+2)==0"); + __CPROVER_assert((*(1+b))[2]==5, "(*(1+b))[2]==5"); + __CPROVER_assert((*(1+b))[2]==0, "(*(1+b))[2]==0"); + __CPROVER_assert(*(*(1+b)+2)==5, "*(*(1+b)+2)==5"); + __CPROVER_assert(*(*(1+b)+2)==0, "*(*(1+b)+2)==0"); + __CPROVER_assert(2[1[b]]==5, "2[1[b]]==5"); + __CPROVER_assert(2[1[b]]==0, "2[1[b]]==0"); + __CPROVER_assert(*(2+1[b])==5, "*(2+1[b])==5"); + __CPROVER_assert(*(2+1[b])==0, "*(2+1[b])==0"); + __CPROVER_assert(*(2+*(1+b))==5, "*(2+*(1+b))==5"); + __CPROVER_assert(*(2+*(1+b))==0, "*(2+*(1+b))==0"); // Test how well we can deal with merging for an array value when there is one // possible value @@ -43,9 +43,9 @@ int main(int argc, char *argv[]) { a[0][1]=0; } - assert(a[0][1]==0); - assert(a[0][1]==1); - assert(a[0][2]==0); + __CPROVER_assert(a[0][1]==0, "a[0][1]==0"); + __CPROVER_assert(a[0][1]==1, "a[0][1]==1"); + __CPROVER_assert(a[0][2]==0, "a[0][2]==0"); // Test how well we can deal with merging for an array value when there are // two possible values @@ -53,9 +53,9 @@ int main(int argc, char *argv[]) { b[0][1]=2; } - assert(b[0][1]==2); - assert(b[0][1]==3); - assert(b[0][2]==2); + __CPROVER_assert(b[0][1]==2, "b[0][1]==2"); + __CPROVER_assert(b[0][1]==3, "b[0][1]==3"); + __CPROVER_assert(b[0][2]==2, "b[0][2]==2"); // Reset this change to ensure tests later work as expected b[0][1]=1; @@ -77,74 +77,74 @@ int main(int argc, char *argv[]) // Test how well we can deal with merging for an index on a uniform array when // the index has one possible value - assert(a[i][1]==0); - assert(a[i][1]==1); - assert(a[1][i]==0); - assert(a[1][i]==1); - assert(a[i][i]==0); - assert(a[i][i]==1); + __CPROVER_assert(a[i][1]==0, "a[i][1]==0"); + __CPROVER_assert(a[i][1]==1, "a[i][1]==1"); + __CPROVER_assert(a[1][i]==0, "a[1][i]==0"); + __CPROVER_assert(a[1][i]==1, "a[1][i]==1"); + __CPROVER_assert(a[i][i]==0, "a[i][i]==0"); + __CPROVER_assert(a[i][i]==1, "a[i][i]==1"); // Test how well we can deal with merging for an index on a uniform array when // the index has two possible values - assert(a[j][1]==0); - assert(a[j][1]==1); - assert(a[1][j]==0); - assert(a[1][j]==1); - assert(a[j][j]==0); - assert(a[j][j]==1); + __CPROVER_assert(a[j][1]==0, "a[j][1]==0"); + __CPROVER_assert(a[j][1]==1, "a[j][1]==1"); + __CPROVER_assert(a[1][j]==0, "a[1][j]==0"); + __CPROVER_assert(a[1][j]==1, "a[1][j]==1"); + __CPROVER_assert(a[j][j]==0, "a[j][j]==0"); + __CPROVER_assert(a[j][j]==1, "a[j][j]==1"); // Test how well we can deal with merging for an index on a non-uniform array - assert(b[i][1]==1); - assert(b[i][1]==11); - assert(b[1][i]==3); - assert(b[1][i]==11); - assert(b[i][i]==0); - assert(b[i][i]==11); + __CPROVER_assert(b[i][1]==1, "b[i][1]==1"); + __CPROVER_assert(b[i][1]==11, "b[i][1]==11"); + __CPROVER_assert(b[1][i]==3, "b[1][i]==3"); + __CPROVER_assert(b[1][i]==11, "b[1][i]==11"); + __CPROVER_assert(b[i][i]==0, "b[i][i]==0"); + __CPROVER_assert(b[i][i]==11, "b[i][i]==11"); // Test how well we can deal with merging for an index on a non-uniform array - assert(b[j][1]==1); - assert(b[j][1]==11); - assert(b[1][j]==3); - assert(b[1][j]==11); - assert(b[j][j]==0); - assert(b[j][j]==11); + __CPROVER_assert(b[j][1]==1, "b[j][1]==1"); + __CPROVER_assert(b[j][1]==11, "b[j][1]==11"); + __CPROVER_assert(b[1][j]==3, "b[1][j]==3"); + __CPROVER_assert(b[1][j]==11, "b[1][j]==11"); + __CPROVER_assert(b[j][j]==0, "b[j][j]==0"); + __CPROVER_assert(b[j][j]==11, "b[j][j]==11"); // Test how we deal with reading off the end of an array - assert(a[100][0]==0); - assert(a[0][100]==0); + __CPROVER_assert(a[100][0]==0, "a[100][0]==0"); + __CPROVER_assert(a[0][100]==0, "a[0][100]==0"); // Test how we deal with writing off the end of an array int c=0; a[100][0]=1; - assert(c==0); + __CPROVER_assert(c==0, "c==0"); c=0; a[0][100]=1; - assert(c==0); + __CPROVER_assert(c==0, "c==0"); // Test how we deal with merging for an index with one possible value when // writing to an array int ei[3][3]={{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; ei[i][1]=1; - assert(ei[0][1]==1); - assert(ei[0][1]==0); - assert(ei[2][1]==0); - assert(ei[2][1]==1); + __CPROVER_assert(ei[0][1]==1, "ei[0][1]==1"); + __CPROVER_assert(ei[0][1]==0, "ei[0][1]==0"); + __CPROVER_assert(ei[2][1]==0, "ei[2][1]==0"); + __CPROVER_assert(ei[2][1]==1, "ei[2][1]==1"); // Test how we deal with merging for an index with two possible values when // writing to an array int ej[3][3]={{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; ej[j][1]=1; - assert(ej[0][1]==0); - assert(ej[2][1]==0); + __CPROVER_assert(ej[0][1]==0, "ej[0][1]==0"); + __CPROVER_assert(ej[2][1]==0, "ej[2][1]==0"); // Test how we deal with merging for an index with two possible values when // it means writing to an array element that may be out of bounds int ek[3][3]={{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; c=0; ek[k][1]=1; - assert(ek[0][1]==0); - assert(c==0); + __CPROVER_assert(ek[0][1]==0, "ek[0][1]==0"); + __CPROVER_assert(c==0, "c==0"); return 0; } diff --git a/regression/goto-analyzer/sensitivity-test-common-files/array_of_pointer_sensitivity_tests.c b/regression/goto-analyzer/sensitivity-test-common-files/array_of_pointer_sensitivity_tests.c index 907fc4180ad..f90bc5e2f0b 100644 --- a/regression/goto-analyzer/sensitivity-test-common-files/array_of_pointer_sensitivity_tests.c +++ b/regression/goto-analyzer/sensitivity-test-common-files/array_of_pointer_sensitivity_tests.c @@ -25,30 +25,30 @@ int main(int argc, char *argv[]) int *b[3]={&b0, &b1, &b2}; // Test if we can represent uniform constant arrays - assert(a[1]==&a0); - assert(a[1]==&a3); - assert(*a[1]==0); - assert(*a[1]==3); + __CPROVER_assert(a[1]==&a0, "a[1]==&a0"); + __CPROVER_assert(a[1]==&a3, "a[1]==&a3"); + __CPROVER_assert(*a[1]==0, "*a[1]==0"); + __CPROVER_assert(*a[1]==3, "*a[1]==3"); // Test if we can represent constant arrays which aren't uniform - assert(b[1]==&b1); - assert(b[1]==&b3); - assert(*b[1]==11); - assert(*b[1]==13); + __CPROVER_assert(b[1]==&b1, "b[1]==&b1"); + __CPROVER_assert(b[1]==&b3, "b[1]==&b3"); + __CPROVER_assert(*b[1]==11, "*b[1]==11"); + __CPROVER_assert(*b[1]==13, "*b[1]==13"); // Test alternative syntax for accessing an array value - assert(*(b+1)==&b1); - assert(*(b+1)==&b3); - assert(*(1+b)==&b1); - assert(*(1+b)==&b3); - assert(1[b]==&b1); - assert(1[b]==&b3); - assert(**(b+1)==11); - assert(**(b+1)==13); - assert(**(1+b)==11); - assert(**(1+b)==13); - assert(*1[b]==11); - assert(*1[b]==13); + __CPROVER_assert(*(b+1)==&b1, "*(b+1)==&b1"); + __CPROVER_assert(*(b+1)==&b3, "*(b+1)==&b3"); + __CPROVER_assert(*(1+b)==&b1, "*(1+b)==&b1"); + __CPROVER_assert(*(1+b)==&b3, "*(1+b)==&b3"); + __CPROVER_assert(1[b]==&b1, "1[b]==&b1"); + __CPROVER_assert(1[b]==&b3, "1[b]==&b3"); + __CPROVER_assert(**(b+1)==11, "**(b+1)==11"); + __CPROVER_assert(**(b+1)==13, "**(b+1)==13"); + __CPROVER_assert(**(1+b)==11, "**(1+b)==11"); + __CPROVER_assert(**(1+b)==13, "**(1+b)==13"); + __CPROVER_assert(*1[b]==11, "*1[b]==11"); + __CPROVER_assert(*1[b]==13, "*1[b]==13"); // c and d are arrays whose values requiring merging paths in the CFG. For // c[0] there is only one possibility after merging and for d[0] there are @@ -62,14 +62,14 @@ int main(int argc, char *argv[]) } // Test how well we can deal with merging for an array value - assert(c[0]==&c0); - assert(c[0]==&c3); - assert(d[0]==&d0); - assert(d[0]==&d3); - assert(*c[0]==20); - assert(*c[0]==23); - assert(*d[0]==30); - assert(*d[0]==33); + __CPROVER_assert(c[0]==&c0, "c[0]==&c0"); + __CPROVER_assert(c[0]==&c3, "c[0]==&c3"); + __CPROVER_assert(d[0]==&d0, "d[0]==&d0"); + __CPROVER_assert(d[0]==&d3, "d[0]==&d3"); + __CPROVER_assert(*c[0]==20, "*c[0]==20"); + __CPROVER_assert(*c[0]==23, "*c[0]==23"); + __CPROVER_assert(*d[0]==30, "*d[0]==30"); + __CPROVER_assert(*d[0]==33, "*d[0]==33"); // The variables i, j and k will be used as indexes into arrays of size 3. // They all require merging paths in the CFG. For i there is only one value on @@ -87,33 +87,33 @@ int main(int argc, char *argv[]) } // Test how well we can deal with merging for an index on a uniform array - assert(a[i]==&a0); - assert(a[i]==&a3); - assert(a[j]==&a0); - assert(a[j]==&a3); - assert(*a[i]==0); - assert(*a[i]==3); - assert(*a[j]==0); - assert(*a[j]==3); + __CPROVER_assert(a[i]==&a0, "a[i]==&a0"); + __CPROVER_assert(a[i]==&a3, "a[i]==&a3"); + __CPROVER_assert(a[j]==&a0, "a[j]==&a0"); + __CPROVER_assert(a[j]==&a3, "a[j]==&a3"); + __CPROVER_assert(*a[i]==0, "*a[i]==0"); + __CPROVER_assert(*a[i]==3, "*a[i]==3"); + __CPROVER_assert(*a[j]==0, "*a[j]==0"); + __CPROVER_assert(*a[j]==3, "*a[j]==3"); // Test how well we can deal with merging for an index on a non-uniform array - assert(b[i]==&b0); - assert(b[i]==&b1); - assert(b[j]==&b0); - assert(b[j]==&b3); - assert(*b[i]==10); - assert(*b[i]==11); - assert(*b[j]==10); - assert(*b[j]==13); + __CPROVER_assert(b[i]==&b0, "b[i]==&b0"); + __CPROVER_assert(b[i]==&b1, "b[i]==&b1"); + __CPROVER_assert(b[j]==&b0, "b[j]==&b0"); + __CPROVER_assert(b[j]==&b3, "b[j]==&b3"); + __CPROVER_assert(*b[i]==10, "*b[i]==10"); + __CPROVER_assert(*b[i]==11, "*b[i]==11"); + __CPROVER_assert(*b[j]==10, "*b[j]==10"); + __CPROVER_assert(*b[j]==13, "*b[j]==13"); // Test how we deal with reading off the end of an array - assert(a[100]==&a2); - assert(*a[100]==2); + __CPROVER_assert(a[100]==&a2, "a[100]==&a2"); + __CPROVER_assert(*a[100]==2, "*a[100]==2"); // Test how we deal with writing off the end of an array a[100]=&a2; - assert(b[1]==&b1); - assert(*b[1]==11); + __CPROVER_assert(b[1]==&b1, "b[1]==&b1"); + __CPROVER_assert(*b[1]==11, "*b[1]==11"); // Test how we deal with merging for an index with one possible value when // writing to an array @@ -121,14 +121,14 @@ int main(int argc, char *argv[]) int ei1=41; int *ei[3]={&ei0, &ei0, &ei0}; ei[i]=&ei1; - assert(ei[0]==&ei1); - assert(ei[0]==&ei0); - assert(ei[2]==&ei0); - assert(ei[2]==&ei1); - assert(*ei[0]==41); - assert(*ei[0]==40); - assert(*ei[2]==40); - assert(*ei[2]==41); + __CPROVER_assert(ei[0]==&ei1, "ei[0]==&ei1"); + __CPROVER_assert(ei[0]==&ei0, "ei[0]==&ei0"); + __CPROVER_assert(ei[2]==&ei0, "ei[2]==&ei0"); + __CPROVER_assert(ei[2]==&ei1, "ei[2]==&ei1"); + __CPROVER_assert(*ei[0]==41, "*ei[0]==41"); + __CPROVER_assert(*ei[0]==40, "*ei[0]==40"); + __CPROVER_assert(*ei[2]==40, "*ei[2]==40"); + __CPROVER_assert(*ei[2]==41, "*ei[2]==41"); // Test how we deal with merging for an index with two possible values when // writing to an array @@ -136,12 +136,12 @@ int main(int argc, char *argv[]) int ej1=51; int *ej[3]={&ej0, &ej0, &ej0}; ej[j]=&ej1; - assert(ej[0]==&ej0); - assert(ej[2]==&ej0); - assert(ej[2]==&ej1); - assert(*ej[0]==50); - assert(*ej[2]==50); - assert(*ej[2]==51); + __CPROVER_assert(ej[0]==&ej0, "ej[0]==&ej0"); + __CPROVER_assert(ej[2]==&ej0, "ej[2]==&ej0"); + __CPROVER_assert(ej[2]==&ej1, "ej[2]==&ej1"); + __CPROVER_assert(*ej[0]==50, "*ej[0]==50"); + __CPROVER_assert(*ej[2]==50, "*ej[2]==50"); + __CPROVER_assert(*ej[2]==51, "*ej[2]==51"); // Test how we deal with merging for an index with two possible values when // it means writing to an array element that may be out of bounds @@ -149,8 +149,28 @@ int main(int argc, char *argv[]) int ek1=61; int *ek[3]={&ek0, &ek0, &ek0}; ek[k]=&ek1; - assert(ek[0]==&ek0); - assert(*ek[0]==60); + __CPROVER_assert(ek[0]==&ek0, "ek[0]==&ek0"); + __CPROVER_assert(*ek[0]==60, "*ek[0]==60"); + + // Test writing to an unknown index (i.e. a merging write of the pointer) + int x = 4; + int y = 5; + int *ps[2] = {&x, &y}; + int i; + if(argc > 2) + { + i=0; + } + else + { + i=1; + } + *(ps[i])=4; + + __CPROVER_assert(*ps[0]==4, "*ps[0]==4"); + __CPROVER_assert(*ps[1]==4, "*ps[1]==4"); + __CPROVER_assert(x==4, "x==4"); + __CPROVER_assert(y==4, "y==4"); return 0; } diff --git a/regression/goto-analyzer/sensitivity-test-common-files/array_sensitivity_tests.c b/regression/goto-analyzer/sensitivity-test-common-files/array_sensitivity_tests.c index 68bace194c8..b0b413b7014 100644 --- a/regression/goto-analyzer/sensitivity-test-common-files/array_sensitivity_tests.c +++ b/regression/goto-analyzer/sensitivity-test-common-files/array_sensitivity_tests.c @@ -8,20 +8,20 @@ int main(int argc, char *argv[]) int b[3]={1, 0, 0}; // Test if we can represent uniform constant arrays - assert(a[1]==0); - assert(a[1]==1); + __CPROVER_assert(a[1]==0, "a[1]==0"); + __CPROVER_assert(a[1]==1, "a[1]==1"); // Test if we can represent constant arrays which aren't uniform - assert(b[1]==0); - assert(b[1]==1); + __CPROVER_assert(b[1]==0, "b[1]==0"); + __CPROVER_assert(b[1]==1, "b[1]==1"); // Test alternative syntax for accessing an array value - assert(*(b+1)==0); - assert(*(b+1)==1); - assert(*(1+b)==0); - assert(*(1+b)==1); - assert(1[b]==0); - assert(1[b]==1); + __CPROVER_assert(*(b+1)==0, "*(b+1)==0"); + __CPROVER_assert(*(b+1)==1, "*(b+1)==1"); + __CPROVER_assert(*(1+b)==0, "*(1+b)==0"); + __CPROVER_assert(*(1+b)==1, "*(1+b)==1"); + __CPROVER_assert(1[b]==0, "1[b]==0"); + __CPROVER_assert(1[b]==1, "1[b]==1"); // c and d are arrays whose values requiring merging paths in the CFG. For // c[0] there is only one possibility after merging and for d[0] there are @@ -35,11 +35,11 @@ int main(int argc, char *argv[]) } // Test how well we can deal with merging for an array value - assert(c[0]==0); - assert(c[0]==1); - assert(d[0]==0); - assert(d[0]==2); - assert(d[1]==0); + __CPROVER_assert(c[0]==0, "c[0]==0"); + __CPROVER_assert(c[0]==1, "c[0]==1"); + __CPROVER_assert(d[0]==0, "d[0]==0"); + __CPROVER_assert(d[0]==2, "d[0]==2"); + __CPROVER_assert(d[1]==0, "d[1]==0"); // The variables i, j and k will be used as indexes into arrays of size 3. // They all require merging paths in the CFG. For i there is only one value on @@ -57,45 +57,45 @@ int main(int argc, char *argv[]) } // Test how well we can deal with merging for an index on a uniform array - assert(a[i]==0); - assert(a[i]==1); - assert(a[j]==0); - assert(a[j]==1); + __CPROVER_assert(a[i]==0, "a[i]==0"); + __CPROVER_assert(a[i]==1, "a[i]==1"); + __CPROVER_assert(a[j]==0, "a[j]==0"); + __CPROVER_assert(a[j]==1, "a[j]==1"); // Test how well we can deal with merging for an index on a non-uniform array - assert(b[i]==1); - assert(b[i]==0); - assert(b[j]==0); - assert(b[j]==1); + __CPROVER_assert(b[i]==1, "b[i]==1"); + __CPROVER_assert(b[i]==0, "b[i]==0"); + __CPROVER_assert(b[j]==0, "b[j]==0"); + __CPROVER_assert(b[j]==1, "b[j]==1"); // Test how we deal with reading off the end of an array - assert(a[100]==0); + __CPROVER_assert(a[100]==0, "a[100]==0"); // Test how we deal with writing off the end of an array a[100]=1; - assert(b[1]==0); + __CPROVER_assert(b[1]==0, "b[1]==0"); // Test how we deal with merging for an index with one possible value when // writing to an array int ei[3]={0, 0, 0}; ei[i]=1; - assert(ei[0]==1); - assert(ei[0]==0); - assert(ei[2]==0); - assert(ei[2]==1); + __CPROVER_assert(ei[0]==1, "ei[0]==1"); + __CPROVER_assert(ei[0]==0, "ei[0]==0"); + __CPROVER_assert(ei[2]==0, "ei[2]==0"); + __CPROVER_assert(ei[2]==1, "ei[2]==1"); // Test how we deal with merging for an index with two possible values when // writing to an array int ej[3]={0, 0, 0}; ej[j]=1; - assert(ej[0]==0); - assert(ej[2]==0); + __CPROVER_assert(ej[0]==0, "ej[0]==0"); + __CPROVER_assert(ej[2]==0, "ej[2]==0"); // Test how we deal with merging for an index with two possible values when // it means writing to an array element that may be out of bounds int ek[3]={0, 0, 0}; ek[k]=1; - assert(ek[0]==0); + __CPROVER_assert(ek[0]==0, "ek[0]==0"); return 0; } diff --git a/regression/goto-analyzer/sensitivity-test-common-files/char_sensitivity_tests.c b/regression/goto-analyzer/sensitivity-test-common-files/char_sensitivity_tests.c index 9e87454b68e..c56bc05e551 100644 --- a/regression/goto-analyzer/sensitivity-test-common-files/char_sensitivity_tests.c +++ b/regression/goto-analyzer/sensitivity-test-common-files/char_sensitivity_tests.c @@ -4,7 +4,7 @@ int main(int argc, char *argv[]) { // Test if we can represent constant chars char x='a'; - assert(x=='a'); - assert(x=='b'); + __CPROVER_assert(x=='a', "x=='a'"); + __CPROVER_assert(x=='b', "x=='b'"); return 0; } diff --git a/regression/goto-analyzer/sensitivity-test-common-files/float_sensitivity_tests.c b/regression/goto-analyzer/sensitivity-test-common-files/float_sensitivity_tests.c index 1f73fae4a6c..f45b9db843f 100644 --- a/regression/goto-analyzer/sensitivity-test-common-files/float_sensitivity_tests.c +++ b/regression/goto-analyzer/sensitivity-test-common-files/float_sensitivity_tests.c @@ -4,7 +4,7 @@ int main(int argc, char *argv[]) { // Test if we can represent constant floats float x=0.0; - assert(x==0.0); - assert(x==1.0); + __CPROVER_assert(x==0.0, "x==0.0"); + __CPROVER_assert(x==1.0, "x==1.0"); return 0; } diff --git a/regression/goto-analyzer/sensitivity-test-common-files/int_sensitivity_tests.c b/regression/goto-analyzer/sensitivity-test-common-files/int_sensitivity_tests.c index ab4265a051f..13845600396 100644 --- a/regression/goto-analyzer/sensitivity-test-common-files/int_sensitivity_tests.c +++ b/regression/goto-analyzer/sensitivity-test-common-files/int_sensitivity_tests.c @@ -10,46 +10,68 @@ int main(int argc, char *argv[]) { y=1; } - assert(x==0); - assert(x==1); - assert(x==y); + __CPROVER_assert(x==0, "x==0"); + __CPROVER_assert(x==1, "x==1"); + __CPROVER_assert(x==y, "x==y"); - assert(x<1); - assert(x<-1); - assert(x-1); - assert(x>1); - assert(x>y); + __CPROVER_assert(x>-1, "x>-1"); + __CPROVER_assert(x>1, "x>1"); + __CPROVER_assert(x>y, "x>y"); - assert(x!=1); - assert(x!=0); - assert(x!=y); + __CPROVER_assert(x!=1, "x!=1"); + __CPROVER_assert(x!=0, "x!=0"); + __CPROVER_assert(x!=y, "x!=y"); - assert(!(x==1)); - assert(!(x==0)); - assert(!(x==y)); + __CPROVER_assert(!(x==1), "!(x==1)"); + __CPROVER_assert(!(x==0), "!(x==0)"); + __CPROVER_assert(!(x==y), "!(x==y)"); // Test how well we can represent an int when it has more than one possible // value - assert(y<2); - assert(y>2); - assert(y==1); + __CPROVER_assert(y<2, "y<2"); + __CPROVER_assert(y>2, "y>2"); + __CPROVER_assert(y==1, "y==1"); // Try copying a variable and then modifying the original int z=x; x=10; - assert(z==0); - assert(z==10); + __CPROVER_assert(z==0, "z==0"); + __CPROVER_assert(z==10, "z==10"); // Test how we treat assertions in unreachable code x=0; if(0) { - assert(x==0); - assert(x==1); - assert(y==0); + __CPROVER_assert(x==0, "x==0"); + __CPROVER_assert(x==1, "x==1"); + __CPROVER_assert(y==0, "y==0"); } + // Try merging two states with multiple variables + + int a1 = 0; + int a2 = 0; + int a3 = 0; + int a4 = 0; + int a5 = 0; + if(argc > 2) + { + a1 = argc; + a2 = argc; + a3 = argc; + // all three variables are now top in this branch + } + + // all three asserts are unverifiable + __CPROVER_assert(a1==0, "a1==0"); + __CPROVER_assert(a2==0, "a2==0"); + __CPROVER_assert(a3==0, "a3==0"); + __CPROVER_assert(a4==0, "a4==0"); + __CPROVER_assert(a5==0, "a5==0"); + return 0; } diff --git a/regression/goto-analyzer/sensitivity-test-common-files/pointer_sensitivity_tests.c b/regression/goto-analyzer/sensitivity-test-common-files/pointer_sensitivity_tests.c index be328fa4a5d..5e6f1f1da73 100644 --- a/regression/goto-analyzer/sensitivity-test-common-files/pointer_sensitivity_tests.c +++ b/regression/goto-analyzer/sensitivity-test-common-files/pointer_sensitivity_tests.c @@ -10,31 +10,31 @@ int main(int argc, char *argv[]) int *x=&a; int *x2=&a; int *y=&b; - assert(x==&a); - assert(x==&b); - assert(x==x2); - assert(x==y); + __CPROVER_assert(x==&a, "x==&a"); + __CPROVER_assert(x==&b, "x==&b"); + __CPROVER_assert(x==x2, "x==x2"); + __CPROVER_assert(x==y, "x==y"); // Reading from a dereferenced pointer - assert(*x==0); - assert(*x==1); + __CPROVER_assert(*x==0, "*x==0"); + __CPROVER_assert(*x==1, "*x==1"); // Modify the referenced value and access it through the pointer again a=1; - assert(*x==1); - assert(*x==0); + __CPROVER_assert(*x==1, "*x==1"); + __CPROVER_assert(*x==0, "*x==0"); // Writing to a dereferenced pointer *x=2; - assert(a==2); - assert(a==0); + __CPROVER_assert(a==2, "a==2"); + __CPROVER_assert(a==0, "a==0"); // Conditionally reassign the pointer, but to the same value if(argc>2) { x=&a; } - assert(x==&a); + __CPROVER_assert(x==&a, "x==&a"); // Conditionally reassign the pointer, to a different value this time if(argc>3) @@ -45,9 +45,9 @@ int main(int argc, char *argv[]) { x=&c; } - assert(*x==0); - assert(x==&a); - assert(x==&b); + __CPROVER_assert(*x==0, "*x==0"); + __CPROVER_assert(x==&a, "x==&a"); + __CPROVER_assert(x==&b, "x==&b"); return 0; } diff --git a/regression/goto-analyzer/sensitivity-test-common-files/pointer_to_array_sensitivity_tests.c b/regression/goto-analyzer/sensitivity-test-common-files/pointer_to_array_sensitivity_tests.c index db9fe720e15..b379f048a58 100644 --- a/regression/goto-analyzer/sensitivity-test-common-files/pointer_to_array_sensitivity_tests.c +++ b/regression/goto-analyzer/sensitivity-test-common-files/pointer_to_array_sensitivity_tests.c @@ -6,21 +6,40 @@ int main(int argc, char *argv[]) // Test reading from an array using a pointer int a[3]={1, 2, 3}; int *p=a; - assert(p==&a[0]); - assert(*p==1); + __CPROVER_assert(p==&a[0], "p==&a[0]"); + + __CPROVER_assert(*p==1, "*p==1"); + + __CPROVER_assert(p[1]==2, "p[1]==2"); + __CPROVER_assert(1[p]==2, "1[p]==2"); + + __CPROVER_assert(*(p+1)==2, "*(p+1)==2"); + __CPROVER_assert(*(1+p)==2, "*(1+p)==2"); + + __CPROVER_assert(*(p-1)==1, "*(p-1)==1"); // Test pointer arithmetic int *q=&a[1]; - assert(q==p+1); - assert(*q==2); + __CPROVER_assert(q==p+1, "q==p+1"); + __CPROVER_assert(*q==2, "*q==2"); // Test pointer diffs ptrdiff_t x=1; - assert(q-p==x); + __CPROVER_assert(q-p==x, "q-p==x"); // Test writing into an array using a pointer *q=4; - assert(a[1]==4); + __CPROVER_assert(a[1]==4, "a[1]==4"); + + p[1]=5; + __CPROVER_assert(a[1]==5, "a[1]==5"); + + *(p+1)=6; + __CPROVER_assert(a[1]==6, "a[1]==6"); + + *(1+p)=7; + __CPROVER_assert(a[1]==7, "a[1]==7"); + a[1]=2; // We now explore pointers and indexes each with more than one possible value @@ -37,23 +56,23 @@ int main(int argc, char *argv[]) // Test reading from an array using a pointer with more than one possible // value - assert(*r==2); - assert(*r==1); - assert(*s==0); - assert(*s==1); + __CPROVER_assert(*r==2, "*r==2"); + __CPROVER_assert(*r==1, "*r==1"); + __CPROVER_assert(*s==0, "*s==0"); + __CPROVER_assert(*s==1, "*s==1"); // Test pointer arithmetic with an unknown index int *t=&a[i]; - assert(t==p+i); + __CPROVER_assert(t==p+i, "t==p+i"); // Test pointer diffs with an unknown index ptrdiff_t y=i; - assert(t-p==y); + __CPROVER_assert(t-p==y, "t-p==y"); // Test writing into an array using a pointer with an unknown index *r=5; - assert(a[i]==5); - assert(a[1]==5); + __CPROVER_assert(a[i]==5, "a[i]==5"); + __CPROVER_assert(a[1]==5, "a[1]==5"); return 0; } diff --git a/regression/goto-analyzer/sensitivity-test-common-files/pointer_to_pointer_sensitivity_tests.c b/regression/goto-analyzer/sensitivity-test-common-files/pointer_to_pointer_sensitivity_tests.c index ee29a7059db..61aa658a2ec 100644 --- a/regression/goto-analyzer/sensitivity-test-common-files/pointer_to_pointer_sensitivity_tests.c +++ b/regression/goto-analyzer/sensitivity-test-common-files/pointer_to_pointer_sensitivity_tests.c @@ -9,16 +9,16 @@ int main(int argc, char *argv[]) int **x=&p; // Reading from a pointer to a pointer that's been dereferenced twice - assert(**x==0); - assert(**x==1); + __CPROVER_assert(**x==0, "**x==0"); + __CPROVER_assert(**x==1, "**x==1"); a=1; - assert(**x==1); - assert(**x==0); + __CPROVER_assert(**x==1, "**x==1"); + __CPROVER_assert(**x==0, "**x==0"); // Writing to a pointer to a pointer that's been dereferenced twice **x=2; - assert(a==2); - assert(a==1); + __CPROVER_assert(a==2, "a==2"); + __CPROVER_assert(a==1, "a==1"); return 0; } diff --git a/regression/goto-analyzer/sensitivity-test-common-files/pointer_to_struct_sensitivity_tests.c b/regression/goto-analyzer/sensitivity-test-common-files/pointer_to_struct_sensitivity_tests.c index e0092afae4a..52cef2e54e7 100644 --- a/regression/goto-analyzer/sensitivity-test-common-files/pointer_to_struct_sensitivity_tests.c +++ b/regression/goto-analyzer/sensitivity-test-common-files/pointer_to_struct_sensitivity_tests.c @@ -12,17 +12,17 @@ int main(int argc, char *argv[]) x.a=0; x.b=1.0; struct int_float *p=&x; - assert((*p).a==0); - assert((*p).a==1); + __CPROVER_assert((*p).a==0, "(*p).a==0"); + __CPROVER_assert((*p).a==1, "(*p).a==1"); // Test alternative syntax - assert(p->a==0); - assert(p->a==1); + __CPROVER_assert(p->a==0, "p->a==0"); + __CPROVER_assert(p->a==1, "p->a==1"); // Test writing to the struct through the pointer p->b=2.0; - assert(p->b==2.0); - assert(p->b==1.0); + __CPROVER_assert(p->b==2.0, "p->b==2.0"); + __CPROVER_assert(p->b==1.0, "p->b==1.0"); return 0; } diff --git a/regression/goto-analyzer/sensitivity-test-common-files/struct_of_array_sensitivity_tests.c b/regression/goto-analyzer/sensitivity-test-common-files/struct_of_array_sensitivity_tests.c index d5924b71ed7..646aa133183 100644 --- a/regression/goto-analyzer/sensitivity-test-common-files/struct_of_array_sensitivity_tests.c +++ b/regression/goto-analyzer/sensitivity-test-common-files/struct_of_array_sensitivity_tests.c @@ -15,19 +15,19 @@ int main(int argc, char *argv[]) x.b[0]=3.0f; x.b[1]=4.0f; x.b[2]=5.0f; - assert(x.a[0]==0); - assert(*(x.a+0)==0); - assert(*(0+x.a)==0); - assert(0[x.a]==0); + __CPROVER_assert(x.a[0]==0, "x.a[0]==0"); + __CPROVER_assert(*(x.a+0)==0, "*(x.a+0)==0"); + __CPROVER_assert(*(0+x.a)==0, "*(0+x.a)==0"); + __CPROVER_assert(0[x.a]==0, "0[x.a]==0"); // Test merging when there is only one value on both paths if(argc>2) { x.a[0]=0; } - assert(x.a[0]==0); - assert(x.a[1]==1); - assert(x.b[0]==3.0f); + __CPROVER_assert(x.a[0]==0, "x.a[0]==0"); + __CPROVER_assert(x.a[1]==1, "x.a[1]==1"); + __CPROVER_assert(x.b[0]==3.0f, "x.b[0]==3.0f"); // Test merging when there is one value for a and two values for b, to test if // we are representing them separately @@ -36,12 +36,12 @@ int main(int argc, char *argv[]) x.a[0]=0; x.b[2]=15.0f; } - assert(x.a[0]==0); - assert(x.a[1]==1); - assert(x.b[2]>0.0f); - assert(x.b[2]==15.0f); - assert(x.b[2]==1.0f); - assert(x.b[0]==3.0f); + __CPROVER_assert(x.a[0]==0, "x.a[0]==0"); + __CPROVER_assert(x.a[1]==1, "x.a[1]==1"); + __CPROVER_assert(x.b[2]>0.0f, "x.b[2]>0.0f"); + __CPROVER_assert(x.b[2]==15.0f, "x.b[2]==15.0f"); + __CPROVER_assert(x.b[2]==1.0f, "x.b[2]==1.0f"); + __CPROVER_assert(x.b[0]==3.0f, "x.b[0]==3.0f"); // Test merging when there are two values for a and b if(argc>4) @@ -49,10 +49,10 @@ int main(int argc, char *argv[]) x.a[0]=11; x.b[2]=25.0f; } - assert(x.a[0]<12); - assert(x.a[0]>2); - assert(x.a[0]==0); - assert(x.a[1]==1); + __CPROVER_assert(x.a[0]<12, "x.a[0]<12"); + __CPROVER_assert(x.a[0]>2, "x.a[0]>2"); + __CPROVER_assert(x.a[0]==0, "x.a[0]==0"); + __CPROVER_assert(x.a[1]==1, "x.a[1]==1"); return 0; } diff --git a/regression/goto-analyzer/sensitivity-test-common-files/struct_of_pointer_sensitivity_tests.c b/regression/goto-analyzer/sensitivity-test-common-files/struct_of_pointer_sensitivity_tests.c index 3cde8011c2b..19371f81644 100644 --- a/regression/goto-analyzer/sensitivity-test-common-files/struct_of_pointer_sensitivity_tests.c +++ b/regression/goto-analyzer/sensitivity-test-common-files/struct_of_pointer_sensitivity_tests.c @@ -18,14 +18,14 @@ int main(int argc, char *argv[]) struct int_float x; x.a=&a1; x.b=&b1; - assert(x.a==&a1); - assert(x.a==&a2); - assert(x.b==&b1); - assert(x.b==&b2); - assert(*x.a==0); - assert(*x.a==100); - assert(*x.b==10.0f); - assert(*x.b==110.0f); + __CPROVER_assert(x.a==&a1, "x.a==&a1"); + __CPROVER_assert(x.a==&a2, "x.a==&a2"); + __CPROVER_assert(x.b==&b1, "x.b==&b1"); + __CPROVER_assert(x.b==&b2, "x.b==&b2"); + __CPROVER_assert(*x.a==0, "*x.a==0"); + __CPROVER_assert(*x.a==100, "*x.a==100"); + __CPROVER_assert(*x.b==10.0f, "*x.b==10.0f"); + __CPROVER_assert(*x.b==110.0f, "*x.b==110.0f"); // Test merging when there is only one value on both paths if(argc>2) @@ -33,10 +33,10 @@ int main(int argc, char *argv[]) x.a=&a1; x.b=&b1; } - assert(x.a==&a1); - assert(x.a==&a2); - assert(*x.a==0); - assert(*x.a==100); + __CPROVER_assert(x.a==&a1, "x.a==&a1"); + __CPROVER_assert(x.a==&a2, "x.a==&a2"); + __CPROVER_assert(*x.a==0, "*x.a==0"); + __CPROVER_assert(*x.a==100, "*x.a==100"); // Test merging when there is one value for a and two values for b, to test if // we are representing them separately @@ -45,12 +45,12 @@ int main(int argc, char *argv[]) x.a=&a1; x.b=&b2; } - assert(x.a==&a1); - assert(x.b==&b2); - assert(x.b==&b3); - assert(*x.a==0); - assert(*x.b==11.0f); - assert(*x.b==12.0f); + __CPROVER_assert(x.a==&a1, "x.a==&a1"); + __CPROVER_assert(x.b==&b2, "x.b==&b2"); + __CPROVER_assert(x.b==&b3, "x.b==&b3"); + __CPROVER_assert(*x.a==0, "*x.a==0"); + __CPROVER_assert(*x.b==11.0f, "*x.b==11.0f"); + __CPROVER_assert(*x.b==12.0f, "*x.b==12.0f"); // Test merging when there are two values for a and b if(argc>4) @@ -58,14 +58,14 @@ int main(int argc, char *argv[]) x.a=&a2; x.b=&b3; } - assert(x.a==&a2); - assert(x.a==&a3); - assert(x.b==&b3); - assert(x.b==&b4); - assert(*x.a==1); - assert(*x.a==2); - assert(*x.b==12.0f); - assert(*x.b==13.0f); + __CPROVER_assert(x.a==&a2, "x.a==&a2"); + __CPROVER_assert(x.a==&a3, "x.a==&a3"); + __CPROVER_assert(x.b==&b3, "x.b==&b3"); + __CPROVER_assert(x.b==&b4, "x.b==&b4"); + __CPROVER_assert(*x.a==1, "*x.a==1"); + __CPROVER_assert(*x.a==2, "*x.a==2"); + __CPROVER_assert(*x.b==12.0f, "*x.b==12.0f"); + __CPROVER_assert(*x.b==13.0f, "*x.b==13.0f"); return 0; } diff --git a/regression/goto-analyzer/sensitivity-test-common-files/struct_of_struct_sensitivity_tests.c b/regression/goto-analyzer/sensitivity-test-common-files/struct_of_struct_sensitivity_tests.c index ac6a32a0086..dcaa72c4f34 100644 --- a/regression/goto-analyzer/sensitivity-test-common-files/struct_of_struct_sensitivity_tests.c +++ b/regression/goto-analyzer/sensitivity-test-common-files/struct_of_struct_sensitivity_tests.c @@ -18,16 +18,16 @@ int main(int argc, char *argv[]) x.s1.b=1.0; x.s2.a=2; x.s2.b=3.0f; - assert(x.s1.a==0); - assert(x.s2.b==3.0f); + __CPROVER_assert(x.s1.a==0, "x.s1.a==0"); + __CPROVER_assert(x.s2.b==3.0f, "x.s2.b==3.0f"); // Test merging when there is only one value on both paths if(argc>2) { x.s1.a=0; } - assert(x.s1.a==0); - assert(x.s1.a==10); + __CPROVER_assert(x.s1.a==0, "x.s1.a==0"); + __CPROVER_assert(x.s1.a==10, "x.s1.a==10"); // Test merging when there is one value for s1 and two values for s2, to test // if we are representing them separately @@ -36,9 +36,9 @@ int main(int argc, char *argv[]) x.s1.b=1.0f; x.s2.b=13.0f; } - assert(x.s1.b==1.0f); - assert(x.s2.b==3.0f); - assert(x.s2.b==0.0f); + __CPROVER_assert(x.s1.b==1.0f, "x.s1.b==1.0f"); + __CPROVER_assert(x.s2.b==3.0f, "x.s2.b==3.0f"); + __CPROVER_assert(x.s2.b==0.0f, "x.s2.b==0.0f"); // Test merging when there are two values for s1 and s2 if(argc>4) @@ -46,10 +46,10 @@ int main(int argc, char *argv[]) x.s1.a=20; x.s2.a=22; } - assert(x.s1.a==20); - assert(x.s1.a<30); - assert(x.s2.a==22); - assert(x.s2.a<30); + __CPROVER_assert(x.s1.a==20, "x.s1.a==20"); + __CPROVER_assert(x.s1.a<30, "x.s1.a<30"); + __CPROVER_assert(x.s2.a==22, "x.s2.a==22"); + __CPROVER_assert(x.s2.a<30, "x.s2.a<30"); return 0; } diff --git a/regression/goto-analyzer/sensitivity-test-common-files/struct_sensitivity_tests.c b/regression/goto-analyzer/sensitivity-test-common-files/struct_sensitivity_tests.c index a4ad229e34c..1d54f561265 100644 --- a/regression/goto-analyzer/sensitivity-test-common-files/struct_sensitivity_tests.c +++ b/regression/goto-analyzer/sensitivity-test-common-files/struct_sensitivity_tests.c @@ -11,8 +11,8 @@ int main(int argc, char *argv[]) struct int_float x={0, 1.0f}; x.a=0; x.b=1.0f; - assert(x.a==0); - assert(x.a==1); + __CPROVER_assert(x.a==0, "x.a==0"); + __CPROVER_assert(x.a==1, "x.a==1"); // Test merging when there is only one value on both paths if(argc>2) @@ -20,7 +20,7 @@ int main(int argc, char *argv[]) x.a=0; x.b=1.0f; } - assert(x.a==0); + __CPROVER_assert(x.a==0, "x.a==0"); // Test merging when there is one value for a and two values for b, to test if // we are representing them separately @@ -29,9 +29,9 @@ int main(int argc, char *argv[]) x.a=0; x.b=2.0f; } - assert(x.a==0); - assert(x.b>0.0f); - assert(x.b==1.0f); + __CPROVER_assert(x.a==0, "x.a==0"); + __CPROVER_assert(x.b>0.0f, "x.b>0.0f"); + __CPROVER_assert(x.b==1.0f, "x.b==1.0f"); // Test merging when there are two values for a and b if(argc>4) @@ -39,9 +39,9 @@ int main(int argc, char *argv[]) x.a=1; x.b=2.0f; } - assert(x.a<2); - assert(x.a>2); - assert(x.a==1); + __CPROVER_assert(x.a<2, "x.a<2"); + __CPROVER_assert(x.a>2, "x.a>2"); + __CPROVER_assert(x.a==1, "x.a==1"); return 0; } diff --git a/regression/goto-analyzer/sensitivity-test-constants-array-of-constants-array/test.desc b/regression/goto-analyzer/sensitivity-test-constants-array-of-constants-array/test.desc index c8db44a2c09..faad9ed3f87 100644 --- a/regression/goto-analyzer/sensitivity-test-constants-array-of-constants-array/test.desc +++ b/regression/goto-analyzer/sensitivity-test-constants-array-of-constants-array/test.desc @@ -1,73 +1,73 @@ -FUTURE +CORE sensitivity_test_constants_array_of_constants_array.c --variable --arrays --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion a\[1\]\[2\]==0: Success$ -^\[main.assertion.2\] .* assertion a\[1\]\[2\]==1: Failure \(if reachable\)$ -^\[main.assertion.3\] .* assertion b\[1\]\[2\]==5: Success$ -^\[main.assertion.4\] .* assertion b\[1\]\[2\]==0: Failure \(if reachable\)$ -^\[main.assertion.5\] .* assertion \*\(b\[1\]\+2\)==5: Success$ -^\[main.assertion.6\] .* assertion \*\(b\[1\]\+2\)==0: Failure \(if reachable\)$ -^\[main.assertion.7\] .* assertion \(\*\(b\+1\)\)\[2\]==5: Success$ -^\[main.assertion.8\] .* assertion \(\*\(b\+1\)\)\[2\]==0: Failure \(if reachable\)$ -^\[main.assertion.9\] .* assertion \*\(\*\(b\+1\)\+2\)==5: Success$ -^\[main.assertion.10\] .* assertion \*\(\*\(b\+1\)\+2\)==0: Failure \(if reachable\)$ -^\[main.assertion.11\] .* assertion 1\[b\]\[2\]==5: Success$ -^\[main.assertion.12\] .* assertion 1\[b\]\[2\]==0: Failure \(if reachable\)$ -^\[main.assertion.13\] .* assertion \*\(1\[b\]\+2\)==5: Success$ -^\[main.assertion.14\] .* assertion \*\(1\[b\]\+2\)==0: Failure \(if reachable\)$ -^\[main.assertion.15\] .* assertion \(\*\(1\+b\)\)\[2\]==5: Unknown$ -^\[main.assertion.16\] .* assertion \(\*\(1\+b\)\)\[2\]==0: Unknown$ -^\[main.assertion.17\] .* assertion \*\(\*\(1\+b\)\+2\)==5: Unknown$ -^\[main.assertion.18\] .* assertion \*\(\*\(1\+b\)\+2\)==0: Unknown$ -^\[main.assertion.19\] .* assertion 2\[1\[b\]\]==5: Success$ -^\[main.assertion.20\] .* assertion 2\[1\[b\]\]==0: Failure \(if reachable\)$ -^\[main.assertion.21\] .* assertion \*\(2\+1\[b\]\)==5: Unknown$ -^\[main.assertion.22\] .* assertion \*\(2\+1\[b\]\)==0: Unknown$ -^\[main.assertion.23\] .* assertion \*\(2\+\*\(1\+b\)\)==5: Unknown$ -^\[main.assertion.24\] .* assertion \*\(2\+\*\(1\+b\)\)==0: Unknown$ -^\[main.assertion.25\] .* assertion a\[0\]\[1\]==0: Success$ -^\[main.assertion.26\] .* assertion a\[0\]\[1\]==1: Failure \(if reachable\)$ -^\[main.assertion.27\] .* assertion a\[0\]\[2\]==0: Success$ -^\[main.assertion.28\] .* assertion b\[0\]\[1\]==2: Unknown$ -^\[main.assertion.29\] .* assertion b\[0\]\[1\]==3: Unknown$ -^\[main.assertion.30\] .* assertion b\[0\]\[2\]==2: Success$ -^\[main.assertion.31\] .* assertion a\[i\]\[1\]==0: Success$ -^\[main.assertion.32\] .* assertion a\[i\]\[1\]==1: Failure \(if reachable\)$ -^\[main.assertion.33\] .* assertion a\[1\]\[i\]==0: Success$ -^\[main.assertion.34\] .* assertion a\[1\]\[i\]==1: Failure \(if reachable\)$ -^\[main.assertion.35\] .* assertion a\[i\]\[i\]==0: Success$ -^\[main.assertion.36\] .* assertion a\[i\]\[i\]==1: Failure \(if reachable\)$ -^\[main.assertion.37\] .* assertion a\[j\]\[1\]==0: Unknown$ -^\[main.assertion.38\] .* assertion a\[j\]\[1\]==1: Unknown$ -^\[main.assertion.39\] .* assertion a\[1\]\[j\]==0: Unknown$ -^\[main.assertion.40\] .* assertion a\[1\]\[j\]==1: Unknown$ -^\[main.assertion.41\] .* assertion a\[j\]\[j\]==0: Unknown$ -^\[main.assertion.42\] .* assertion a\[j\]\[j\]==1: Unknown$ -^\[main.assertion.43\] .* assertion b\[i\]\[1\]==1: Success$ -^\[main.assertion.44\] .* assertion b\[i\]\[1\]==11: Failure \(if reachable\)$ -^\[main.assertion.45\] .* assertion b\[1\]\[i\]==3: Success$ -^\[main.assertion.46\] .* assertion b\[1\]\[i\]==11: Failure \(if reachable\)$ -^\[main.assertion.47\] .* assertion b\[i\]\[i\]==0: Success$ -^\[main.assertion.48\] .* assertion b\[i\]\[i\]==11: Failure \(if reachable\)$ -^\[main.assertion.49\] .* assertion b\[j\]\[1\]==1: Unknown$ -^\[main.assertion.50\] .* assertion b\[j\]\[1\]==11: Unknown$ -^\[main.assertion.51\] .* assertion b\[1\]\[j\]==3: Unknown$ -^\[main.assertion.52\] .* assertion b\[1\]\[j\]==11: Unknown$ -^\[main.assertion.53\] .* assertion b\[j\]\[j\]==0: Unknown$ -^\[main.assertion.54\] .* assertion b\[j\]\[j\]==11: Unknown$ -^\[main.assertion.55\] .* assertion a\[100\]\[0\]==0: Unknown$ -^\[main.assertion.56\] .* assertion a\[0\]\[100\]==0: Unknown$ -^\[main.assertion.57\] .* assertion c==0: Success$ -^\[main.assertion.58\] .* assertion c==0: Success$ -^\[main.assertion.59\] .* assertion ei\[0\]\[1\]==1: Success$ -^\[main.assertion.60\] .* assertion ei\[0\]\[1\]==0: Failure \(if reachable\)$ -^\[main.assertion.61\] .* assertion ei\[2\]\[1\]==0: Success$ -^\[main.assertion.62\] .* assertion ei\[2\]\[1\]==1: Failure \(if reachable\)$ -^\[main.assertion.63\] .* assertion ej\[0\]\[1\]==0: Unknown$ -^\[main.assertion.64\] .* assertion ej\[2\]\[1\]==0: Unknown$ -^\[main.assertion.65\] .* assertion ek\[0\]\[1\]==0: Unknown$ -^\[main.assertion.66\] .* assertion c==0: Success$ +^\[main.assertion.1\] .* a\[1\]\[2\]==0: Success$ +^\[main.assertion.2\] .* a\[1\]\[2\]==1: Failure \(if reachable\)$ +^\[main.assertion.3\] .* b\[1\]\[2\]==5: Success$ +^\[main.assertion.4\] .* b\[1\]\[2\]==0: Failure \(if reachable\)$ +^\[main.assertion.5\] .* \*\(b\[1\]\+2\)==5: Success$ +^\[main.assertion.6\] .* \*\(b\[1\]\+2\)==0: Failure \(if reachable\)$ +^\[main.assertion.7\] .* \(\*\(b\+1\)\)\[2\]==5: Success$ +^\[main.assertion.8\] .* \(\*\(b\+1\)\)\[2\]==0: Failure \(if reachable\)$ +^\[main.assertion.9\] .* \*\(\*\(b\+1\)\+2\)==5: Success$ +^\[main.assertion.10\] .* \*\(\*\(b\+1\)\+2\)==0: Failure \(if reachable\)$ +^\[main.assertion.11\] .* 1\[b\]\[2\]==5: Success$ +^\[main.assertion.12\] .* 1\[b\]\[2\]==0: Failure \(if reachable\)$ +^\[main.assertion.13\] .* \*\(1\[b\]\+2\)==5: Success$ +^\[main.assertion.14\] .* \*\(1\[b\]\+2\)==0: Failure \(if reachable\)$ +^\[main.assertion.15\] .* \(\*\(1\+b\)\)\[2\]==5: Unknown$ +^\[main.assertion.16\] .* \(\*\(1\+b\)\)\[2\]==0: Unknown$ +^\[main.assertion.17\] .* \*\(\*\(1\+b\)\+2\)==5: Unknown$ +^\[main.assertion.18\] .* \*\(\*\(1\+b\)\+2\)==0: Unknown$ +^\[main.assertion.19\] .* 2\[1\[b\]\]==5: Success$ +^\[main.assertion.20\] .* 2\[1\[b\]\]==0: Failure \(if reachable\)$ +^\[main.assertion.21\] .* \*\(2\+1\[b\]\)==5: Unknown$ +^\[main.assertion.22\] .* \*\(2\+1\[b\]\)==0: Unknown$ +^\[main.assertion.23\] .* \*\(2\+\*\(1\+b\)\)==5: Unknown$ +^\[main.assertion.24\] .* \*\(2\+\*\(1\+b\)\)==0: Unknown$ +^\[main.assertion.25\] .* a\[0\]\[1\]==0: Success$ +^\[main.assertion.26\] .* a\[0\]\[1\]==1: Failure \(if reachable\)$ +^\[main.assertion.27\] .* a\[0\]\[2\]==0: Success$ +^\[main.assertion.28\] .* b\[0\]\[1\]==2: Unknown$ +^\[main.assertion.29\] .* b\[0\]\[1\]==3: Unknown$ +^\[main.assertion.30\] .* b\[0\]\[2\]==2: Success$ +^\[main.assertion.31\] .* a\[i\]\[1\]==0: Success$ +^\[main.assertion.32\] .* a\[i\]\[1\]==1: Failure \(if reachable\)$ +^\[main.assertion.33\] .* a\[1\]\[i\]==0: Success$ +^\[main.assertion.34\] .* a\[1\]\[i\]==1: Failure \(if reachable\)$ +^\[main.assertion.35\] .* a\[i\]\[i\]==0: Success$ +^\[main.assertion.36\] .* a\[i\]\[i\]==1: Failure \(if reachable\)$ +^\[main.assertion.37\] .* a\[j\]\[1\]==0: Unknown$ +^\[main.assertion.38\] .* a\[j\]\[1\]==1: Unknown$ +^\[main.assertion.39\] .* a\[1\]\[j\]==0: Unknown$ +^\[main.assertion.40\] .* a\[1\]\[j\]==1: Unknown$ +^\[main.assertion.41\] .* a\[j\]\[j\]==0: Unknown$ +^\[main.assertion.42\] .* a\[j\]\[j\]==1: Unknown$ +^\[main.assertion.43\] .* b\[i\]\[1\]==1: Success$ +^\[main.assertion.44\] .* b\[i\]\[1\]==11: Failure \(if reachable\)$ +^\[main.assertion.45\] .* b\[1\]\[i\]==3: Success$ +^\[main.assertion.46\] .* b\[1\]\[i\]==11: Failure \(if reachable\)$ +^\[main.assertion.47\] .* b\[i\]\[i\]==0: Success$ +^\[main.assertion.48\] .* b\[i\]\[i\]==11: Failure \(if reachable\)$ +^\[main.assertion.49\] .* b\[j\]\[1\]==1: Unknown$ +^\[main.assertion.50\] .* b\[j\]\[1\]==11: Unknown$ +^\[main.assertion.51\] .* b\[1\]\[j\]==3: Unknown$ +^\[main.assertion.52\] .* b\[1\]\[j\]==11: Unknown$ +^\[main.assertion.53\] .* b\[j\]\[j\]==0: Unknown$ +^\[main.assertion.54\] .* b\[j\]\[j\]==11: Unknown$ +^\[main.assertion.55\] .* a\[100\]\[0\]==0: Unknown$ +^\[main.assertion.56\] .* a\[0\]\[100\]==0: Unknown$ +^\[main.assertion.57\] .* c==0: Success$ +^\[main.assertion.58\] .* c==0: Success$ +^\[main.assertion.59\] .* ei\[0\]\[1\]==1: Success$ +^\[main.assertion.60\] .* ei\[0\]\[1\]==0: Failure \(if reachable\)$ +^\[main.assertion.61\] .* ei\[2\]\[1\]==0: Success$ +^\[main.assertion.62\] .* ei\[2\]\[1\]==1: Failure \(if reachable\)$ +^\[main.assertion.63\] .* ej\[0\]\[1\]==0: Unknown$ +^\[main.assertion.64\] .* ej\[2\]\[1\]==0: Unknown$ +^\[main.assertion.65\] .* ek\[0\]\[1\]==0: Unknown$ +^\[main.assertion.66\] .* c==0: Success$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-constants-array-of-constants-pointer/test.desc b/regression/goto-analyzer/sensitivity-test-constants-array-of-constants-pointer/test.desc index 9242552c707..6c1efef50a2 100644 --- a/regression/goto-analyzer/sensitivity-test-constants-array-of-constants-pointer/test.desc +++ b/regression/goto-analyzer/sensitivity-test-constants-array-of-constants-pointer/test.desc @@ -1,71 +1,75 @@ -FUTURE +CORE sensitivity_test_constants_array_of_constants_pointer.c --variable --arrays --pointers --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion a\[1\]==&a0: Success$ -^\[main.assertion.2\] .* assertion a\[1\]==&a3: Failure \(if reachable\)$ -^\[main.assertion.3\] .* assertion \*a\[1\]==0: Success$ -^\[main.assertion.4\] .* assertion \*a\[1\]==3: Failure \(if reachable\)$ -^\[main.assertion.5\] .* assertion b\[1\]==&b1: Success$ -^\[main.assertion.6\] .* assertion b\[1\]==&b3: Failure \(if reachable\)$ -^\[main.assertion.7\] .* assertion \*b\[1\]==11: Success$ -^\[main.assertion.8\] .* assertion \*b\[1\]==13: Failure \(if reachable\)$ -^\[main.assertion.9\] .* assertion \*\(b\+1\)==&b1: Success$ -^\[main.assertion.10\] .* assertion \*\(b\+1\)==&b3: Failure \(if reachable\)$ -^\[main.assertion.11\] .* assertion \*\(1\+b\)==&b1: Unknown$ -^\[main.assertion.12\] .* assertion \*\(1\+b\)==&b3: Unknown$ -^\[main.assertion.13\] .* assertion 1\[b\]==&b1: Success$ -^\[main.assertion.14\] .* assertion 1\[b\]==&b3: Failure \(if reachable\)$ -^\[main.assertion.15\] .* assertion \*\*\(b\+1\)==11: Success$ -^\[main.assertion.16\] .* assertion \*\*\(b\+1\)==13: Failure \(if reachable\)$ -^\[main.assertion.17\] .* assertion \*\*\(1\+b\)==11: Unknown$ -^\[main.assertion.18\] .* assertion \*\*\(1\+b\)==13: Unknown$ -^\[main.assertion.19\] .* assertion \*1\[b\]==11: Success$ -^\[main.assertion.20\] .* assertion \*1\[b\]==13: Failure \(if reachable\)$ -^\[main.assertion.21\] .* assertion c\[0\]==&c0: Unknown$ -^\[main.assertion.22\] .* assertion c\[0\]==&c3: Unknown$ -^\[main.assertion.23\] .* assertion d\[0\]==&d0: Unknown$ -^\[main.assertion.24\] .* assertion d\[0\]==&d3: Unknown$ -^\[main.assertion.25\] .* assertion \*c\[0\]==20: Unknown$ -^\[main.assertion.26\] .* assertion \*c\[0\]==23: Unknown$ -^\[main.assertion.27\] .* assertion \*d\[0\]==30: Unknown$ -^\[main.assertion.28\] .* assertion \*d\[0\]==33: Unknown$ -^\[main.assertion.29\] .* assertion a\[i\]==&a0: Success$ -^\[main.assertion.30\] .* assertion a\[i\]==&a3: Failure \(if reachable\)$ -^\[main.assertion.31\] .* assertion a\[j\]==&a0: Unknown$ -^\[main.assertion.32\] .* assertion a\[j\]==&a3: Unknown$ -^\[main.assertion.33\] .* assertion \*a\[i\]==0: Success$ -^\[main.assertion.34\] .* assertion \*a\[i\]==3: Failure \(if reachable\)$ -^\[main.assertion.35\] .* assertion \*a\[j\]==0: Unknown$ -^\[main.assertion.36\] .* assertion \*a\[j\]==3: Unknown$ -^\[main.assertion.37\] .* assertion b\[i\]==&b0: Success$ -^\[main.assertion.38\] .* assertion b\[i\]==&b1: Failure \(if reachable\)$ -^\[main.assertion.39\] .* assertion b\[j\]==&b0: Unknown$ -^\[main.assertion.40\] .* assertion b\[j\]==&b3: Unknown$ -^\[main.assertion.41\] .* assertion \*b\[i\]==10: Success$ -^\[main.assertion.42\] .* assertion \*b\[i\]==11: Failure \(if reachable\)$ -^\[main.assertion.43\] .* assertion \*b\[j\]==10: Unknown$ -^\[main.assertion.44\] .* assertion \*b\[j\]==13: Unknown$ -^\[main.assertion.45\] .* assertion a\[100\]==&a2: Unknown$ -^\[main.assertion.46\] .* assertion \*a\[100\]==2: Unknown$ -^\[main.assertion.47\] .* assertion b\[1\]==&b1: Success$ -^\[main.assertion.48\] .* assertion \*b\[1\]==11: Success$ -^\[main.assertion.49\] .* assertion ei\[0\]==&ei1: Success$ -^\[main.assertion.50\] .* assertion ei\[0\]==&ei0: Failure \(if reachable\)$ -^\[main.assertion.51\] .* assertion ei\[2\]==&ei0: Success$ -^\[main.assertion.52\] .* assertion ei\[2\]==&ei1: Failure \(if reachable\)$ -^\[main.assertion.53\] .* assertion \*ei\[0\]==41: Success$ -^\[main.assertion.54\] .* assertion \*ei\[0\]==40: Failure \(if reachable\)$ -^\[main.assertion.55\] .* assertion \*ei\[2\]==40: Success$ -^\[main.assertion.56\] .* assertion \*ei\[2\]==41: Failure \(if reachable\)$ -^\[main.assertion.57\] .* assertion ej\[0\]==&ej0: Unknown$ -^\[main.assertion.58\] .* assertion ej\[2\]==&ej0: Unknown$ -^\[main.assertion.59\] .* assertion ej\[2\]==&ej1: Unknown$ -^\[main.assertion.60\] .* assertion \*ej\[0\]==50: Unknown$ -^\[main.assertion.61\] .* assertion \*ej\[2\]==50: Unknown$ -^\[main.assertion.62\] .* assertion \*ej\[2\]==51: Unknown$ -^\[main.assertion.63\] .* assertion ek\[0\]==&ek0: Unknown$ -^\[main.assertion.64\] .* assertion \*ek\[0\]==60: Unknown$ +^\[main.assertion.1\] .* a\[1\]==&a0: Success$ +^\[main.assertion.2\] .* a\[1\]==&a3: Failure \(if reachable\)$ +^\[main.assertion.3\] .* \*a\[1\]==0: Success$ +^\[main.assertion.4\] .* \*a\[1\]==3: Failure \(if reachable\)$ +^\[main.assertion.5\] .* b\[1\]==&b1: Success$ +^\[main.assertion.6\] .* b\[1\]==&b3: Failure \(if reachable\)$ +^\[main.assertion.7\] .* \*b\[1\]==11: Success$ +^\[main.assertion.8\] .* \*b\[1\]==13: Failure \(if reachable\)$ +^\[main.assertion.9\] .* \*\(b\+1\)==&b1: Success$ +^\[main.assertion.10\] .* \*\(b\+1\)==&b3: Failure \(if reachable\)$ +^\[main.assertion.11\] .* \*\(1\+b\)==&b1: Unknown$ +^\[main.assertion.12\] .* \*\(1\+b\)==&b3: Unknown$ +^\[main.assertion.13\] .* 1\[b\]==&b1: Success$ +^\[main.assertion.14\] .* 1\[b\]==&b3: Failure \(if reachable\)$ +^\[main.assertion.15\] .* \*\*\(b\+1\)==11: Success$ +^\[main.assertion.16\] .* \*\*\(b\+1\)==13: Failure \(if reachable\)$ +^\[main.assertion.17\] .* \*\*\(1\+b\)==11: Unknown$ +^\[main.assertion.18\] .* \*\*\(1\+b\)==13: Unknown$ +^\[main.assertion.19\] .* \*1\[b\]==11: Success$ +^\[main.assertion.20\] .* \*1\[b\]==13: Failure \(if reachable\)$ +^\[main.assertion.21\] .* c\[0\]==&c0: Unknown$ +^\[main.assertion.22\] .* c\[0\]==&c3: Unknown$ +^\[main.assertion.23\] .* d\[0\]==&d0: Unknown$ +^\[main.assertion.24\] .* d\[0\]==&d3: Unknown$ +^\[main.assertion.25\] .* \*c\[0\]==20: Unknown$ +^\[main.assertion.26\] .* \*c\[0\]==23: Unknown$ +^\[main.assertion.27\] .* \*d\[0\]==30: Unknown$ +^\[main.assertion.28\] .* \*d\[0\]==33: Unknown$ +^\[main.assertion.29\] .* a\[i\]==&a0: Success$ +^\[main.assertion.30\] .* a\[i\]==&a3: Failure \(if reachable\)$ +^\[main.assertion.31\] .* a\[j\]==&a0: Unknown$ +^\[main.assertion.32\] .* a\[j\]==&a3: Unknown$ +^\[main.assertion.33\] .* \*a\[i\]==0: Success$ +^\[main.assertion.34\] .* \*a\[i\]==3: Failure \(if reachable\)$ +^\[main.assertion.35\] .* \*a\[j\]==0: Unknown$ +^\[main.assertion.36\] .* \*a\[j\]==3: Unknown$ +^\[main.assertion.37\] .* b\[i\]==&b0: Success$ +^\[main.assertion.38\] .* b\[i\]==&b1: Failure \(if reachable\)$ +^\[main.assertion.39\] .* b\[j\]==&b0: Unknown$ +^\[main.assertion.40\] .* b\[j\]==&b3: Unknown$ +^\[main.assertion.41\] .* \*b\[i\]==10: Success$ +^\[main.assertion.42\] .* \*b\[i\]==11: Failure \(if reachable\)$ +^\[main.assertion.43\] .* \*b\[j\]==10: Unknown$ +^\[main.assertion.44\] .* \*b\[j\]==13: Unknown$ +^\[main.assertion.45\] .* a\[100\]==&a2: Unknown$ +^\[main.assertion.46\] .* \*a\[100\]==2: Unknown$ +^\[main.assertion.47\] .* b\[1\]==&b1: Success$ +^\[main.assertion.48\] .* \*b\[1\]==11: Success$ +^\[main.assertion.49\] .* ei\[0\]==&ei1: Success$ +^\[main.assertion.50\] .* ei\[0\]==&ei0: Failure \(if reachable\)$ +^\[main.assertion.51\] .* ei\[2\]==&ei0: Success$ +^\[main.assertion.52\] .* ei\[2\]==&ei1: Failure \(if reachable\)$ +^\[main.assertion.53\] .* \*ei\[0\]==41: Success$ +^\[main.assertion.54\] .* \*ei\[0\]==40: Failure \(if reachable\)$ +^\[main.assertion.55\] .* \*ei\[2\]==40: Success$ +^\[main.assertion.56\] .* \*ei\[2\]==41: Failure \(if reachable\)$ +^\[main.assertion.57\] .* ej\[0\]==&ej0: Unknown$ +^\[main.assertion.58\] .* ej\[2\]==&ej0: Unknown$ +^\[main.assertion.59\] .* ej\[2\]==&ej1: Unknown$ +^\[main.assertion.60\] .* \*ej\[0\]==50: Unknown$ +^\[main.assertion.61\] .* \*ej\[2\]==50: Unknown$ +^\[main.assertion.62\] .* \*ej\[2\]==51: Unknown$ +^\[main.assertion.63\] .* ek\[0\]==&ek0: Unknown$ +^\[main.assertion.64\] .* \*ek\[0\]==60: Unknown$ +^\[main\.assertion\.65\] .* \*ps\[0\]==4: Success$ +^\[main\.assertion\.66\] .* \*ps\[1\]==4: Unknown$ +^\[main\.assertion\.67\] .* x==4: Success$ +^\[main\.assertion\.68\] .* y==4: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-constants-array-of-two-value-pointer/test.desc b/regression/goto-analyzer/sensitivity-test-constants-array-of-two-value-pointer/test.desc index 74f5f128ed6..0ed4c8ad55a 100644 --- a/regression/goto-analyzer/sensitivity-test-constants-array-of-two-value-pointer/test.desc +++ b/regression/goto-analyzer/sensitivity-test-constants-array-of-two-value-pointer/test.desc @@ -1,71 +1,75 @@ -FUTURE +CORE sensitivity_test_constants_array_of_two_value_pointer.c --variable --arrays --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion a\[1\]==&a0: Unknown$ -^\[main.assertion.2\] .* assertion a\[1\]==&a3: Unknown$ -^\[main.assertion.3\] .* assertion \*a\[1\]==0: Unknown$ -^\[main.assertion.4\] .* assertion \*a\[1\]==3: Unknown$ -^\[main.assertion.5\] .* assertion b\[1\]==&b1: Unknown$ -^\[main.assertion.6\] .* assertion b\[1\]==&b3: Unknown$ -^\[main.assertion.7\] .* assertion \*b\[1\]==11: Unknown$ -^\[main.assertion.8\] .* assertion \*b\[1\]==13: Unknown$ -^\[main.assertion.9\] .* assertion \*\(b\+1\)==&b1: Unknown$ -^\[main.assertion.10\] .* assertion \*\(b\+1\)==&b3: Unknown$ -^\[main.assertion.11\] .* assertion \*\(1\+b\)==&b1: Unknown$ -^\[main.assertion.12\] .* assertion \*\(1\+b\)==&b3: Unknown$ -^\[main.assertion.13\] .* assertion 1\[b\]==&b1: Unknown$ -^\[main.assertion.14\] .* assertion 1\[b\]==&b3: Unknown$ -^\[main.assertion.15\] .* assertion \*\*\(b\+1\)==11: Unknown$ -^\[main.assertion.16\] .* assertion \*\*\(b\+1\)==13: Unknown$ -^\[main.assertion.17\] .* assertion \*\*\(1\+b\)==11: Unknown$ -^\[main.assertion.18\] .* assertion \*\*\(1\+b\)==13: Unknown$ -^\[main.assertion.19\] .* assertion \*1\[b\]==11: Unknown$ -^\[main.assertion.20\] .* assertion \*1\[b\]==13: Unknown$ -^\[main.assertion.21\] .* assertion c\[0\]==&c0: Unknown$ -^\[main.assertion.22\] .* assertion c\[0\]==&c3: Unknown$ -^\[main.assertion.23\] .* assertion d\[0\]==&d0: Unknown$ -^\[main.assertion.24\] .* assertion d\[0\]==&d3: Unknown$ -^\[main.assertion.25\] .* assertion \*c\[0\]==20: Unknown$ -^\[main.assertion.26\] .* assertion \*c\[0\]==23: Unknown$ -^\[main.assertion.27\] .* assertion \*d\[0\]==30: Unknown$ -^\[main.assertion.28\] .* assertion \*d\[0\]==33: Unknown$ -^\[main.assertion.29\] .* assertion a\[i\]==&a0: Unknown$ -^\[main.assertion.30\] .* assertion a\[i\]==&a3: Unknown$ -^\[main.assertion.31\] .* assertion a\[j\]==&a0: Unknown$ -^\[main.assertion.32\] .* assertion a\[j\]==&a3: Unknown$ -^\[main.assertion.33\] .* assertion \*a\[i\]==0: Unknown$ -^\[main.assertion.34\] .* assertion \*a\[i\]==3: Unknown$ -^\[main.assertion.35\] .* assertion \*a\[j\]==0: Unknown$ -^\[main.assertion.36\] .* assertion \*a\[j\]==3: Unknown$ -^\[main.assertion.37\] .* assertion b\[i\]==&b0: Unknown$ -^\[main.assertion.38\] .* assertion b\[i\]==&b1: Unknown$ -^\[main.assertion.39\] .* assertion b\[j\]==&b0: Unknown$ -^\[main.assertion.40\] .* assertion b\[j\]==&b3: Unknown$ -^\[main.assertion.41\] .* assertion \*b\[i\]==10: Unknown$ -^\[main.assertion.42\] .* assertion \*b\[i\]==11: Unknown$ -^\[main.assertion.43\] .* assertion \*b\[j\]==10: Unknown$ -^\[main.assertion.44\] .* assertion \*b\[j\]==13: Unknown$ -^\[main.assertion.45\] .* assertion a\[100\]==&a2: Unknown$ -^\[main.assertion.46\] .* assertion \*a\[100\]==2: Unknown$ -^\[main.assertion.47\] .* assertion b\[1\]==&b1: Unknown$ -^\[main.assertion.48\] .* assertion \*b\[1\]==11: Unknown$ -^\[main.assertion.49\] .* assertion ei\[0\]==&ei1: Unknown$ -^\[main.assertion.50\] .* assertion ei\[0\]==&ei0: Unknown$ -^\[main.assertion.51\] .* assertion ei\[2\]==&ei0: Unknown$ -^\[main.assertion.52\] .* assertion ei\[2\]==&ei1: Unknown$ -^\[main.assertion.53\] .* assertion \*ei\[0\]==41: Unknown$ -^\[main.assertion.54\] .* assertion \*ei\[0\]==40: Unknown$ -^\[main.assertion.55\] .* assertion \*ei\[2\]==40: Unknown$ -^\[main.assertion.56\] .* assertion \*ei\[2\]==41: Unknown$ -^\[main.assertion.57\] .* assertion ej\[0\]==&ej0: Unknown$ -^\[main.assertion.58\] .* assertion ej\[2\]==&ej0: Unknown$ -^\[main.assertion.59\] .* assertion ej\[2\]==&ej1: Unknown$ -^\[main.assertion.60\] .* assertion \*ej\[0\]==50: Unknown$ -^\[main.assertion.61\] .* assertion \*ej\[2\]==50: Unknown$ -^\[main.assertion.62\] .* assertion \*ej\[2\]==51: Unknown$ -^\[main.assertion.63\] .* assertion ek\[0\]==&ek0: Unknown$ -^\[main.assertion.64\] .* assertion \*ek\[0\]==60: Unknown$ +^\[main.assertion.1\] .* a\[1\]==&a0: Unknown$ +^\[main.assertion.2\] .* a\[1\]==&a3: Unknown$ +^\[main.assertion.3\] .* \*a\[1\]==0: Unknown$ +^\[main.assertion.4\] .* \*a\[1\]==3: Unknown$ +^\[main.assertion.5\] .* b\[1\]==&b1: Unknown$ +^\[main.assertion.6\] .* b\[1\]==&b3: Unknown$ +^\[main.assertion.7\] .* \*b\[1\]==11: Unknown$ +^\[main.assertion.8\] .* \*b\[1\]==13: Unknown$ +^\[main.assertion.9\] .* \*\(b\+1\)==&b1: Unknown$ +^\[main.assertion.10\] .* \*\(b\+1\)==&b3: Unknown$ +^\[main.assertion.11\] .* \*\(1\+b\)==&b1: Unknown$ +^\[main.assertion.12\] .* \*\(1\+b\)==&b3: Unknown$ +^\[main.assertion.13\] .* 1\[b\]==&b1: Unknown$ +^\[main.assertion.14\] .* 1\[b\]==&b3: Unknown$ +^\[main.assertion.15\] .* \*\*\(b\+1\)==11: Unknown$ +^\[main.assertion.16\] .* \*\*\(b\+1\)==13: Unknown$ +^\[main.assertion.17\] .* \*\*\(1\+b\)==11: Unknown$ +^\[main.assertion.18\] .* \*\*\(1\+b\)==13: Unknown$ +^\[main.assertion.19\] .* \*1\[b\]==11: Unknown$ +^\[main.assertion.20\] .* \*1\[b\]==13: Unknown$ +^\[main.assertion.21\] .* c\[0\]==&c0: Unknown$ +^\[main.assertion.22\] .* c\[0\]==&c3: Unknown$ +^\[main.assertion.23\] .* d\[0\]==&d0: Unknown$ +^\[main.assertion.24\] .* d\[0\]==&d3: Unknown$ +^\[main.assertion.25\] .* \*c\[0\]==20: Unknown$ +^\[main.assertion.26\] .* \*c\[0\]==23: Unknown$ +^\[main.assertion.27\] .* \*d\[0\]==30: Unknown$ +^\[main.assertion.28\] .* \*d\[0\]==33: Unknown$ +^\[main.assertion.29\] .* a\[i\]==&a0: Unknown$ +^\[main.assertion.30\] .* a\[i\]==&a3: Unknown$ +^\[main.assertion.31\] .* a\[j\]==&a0: Unknown$ +^\[main.assertion.32\] .* a\[j\]==&a3: Unknown$ +^\[main.assertion.33\] .* \*a\[i\]==0: Unknown$ +^\[main.assertion.34\] .* \*a\[i\]==3: Unknown$ +^\[main.assertion.35\] .* \*a\[j\]==0: Unknown$ +^\[main.assertion.36\] .* \*a\[j\]==3: Unknown$ +^\[main.assertion.37\] .* b\[i\]==&b0: Unknown$ +^\[main.assertion.38\] .* b\[i\]==&b1: Unknown$ +^\[main.assertion.39\] .* b\[j\]==&b0: Unknown$ +^\[main.assertion.40\] .* b\[j\]==&b3: Unknown$ +^\[main.assertion.41\] .* \*b\[i\]==10: Unknown$ +^\[main.assertion.42\] .* \*b\[i\]==11: Unknown$ +^\[main.assertion.43\] .* \*b\[j\]==10: Unknown$ +^\[main.assertion.44\] .* \*b\[j\]==13: Unknown$ +^\[main.assertion.45\] .* a\[100\]==&a2: Unknown$ +^\[main.assertion.46\] .* \*a\[100\]==2: Unknown$ +^\[main.assertion.47\] .* b\[1\]==&b1: Unknown$ +^\[main.assertion.48\] .* \*b\[1\]==11: Unknown$ +^\[main.assertion.49\] .* ei\[0\]==&ei1: Unknown$ +^\[main.assertion.50\] .* ei\[0\]==&ei0: Unknown$ +^\[main.assertion.51\] .* ei\[2\]==&ei0: Unknown$ +^\[main.assertion.52\] .* ei\[2\]==&ei1: Unknown$ +^\[main.assertion.53\] .* \*ei\[0\]==41: Unknown$ +^\[main.assertion.54\] .* \*ei\[0\]==40: Unknown$ +^\[main.assertion.55\] .* \*ei\[2\]==40: Unknown$ +^\[main.assertion.56\] .* \*ei\[2\]==41: Unknown$ +^\[main.assertion.57\] .* ej\[0\]==&ej0: Unknown$ +^\[main.assertion.58\] .* ej\[2\]==&ej0: Unknown$ +^\[main.assertion.59\] .* ej\[2\]==&ej1: Unknown$ +^\[main.assertion.60\] .* \*ej\[0\]==50: Unknown$ +^\[main.assertion.61\] .* \*ej\[2\]==50: Unknown$ +^\[main.assertion.62\] .* \*ej\[2\]==51: Unknown$ +^\[main.assertion.63\] .* ek\[0\]==&ek0: Unknown$ +^\[main.assertion.64\] .* \*ek\[0\]==60: Unknown$ +^\[main\.assertion\.65\] .* \*ps\[0\]==4: Unknown$ +^\[main\.assertion\.66\] .* \*ps\[1\]==4: Unknown$ +^\[main\.assertion\.67\] .* x==4: Unknown$ +^\[main\.assertion\.68\] .* y==4: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-constants-array/test.desc b/regression/goto-analyzer/sensitivity-test-constants-array/test.desc index b48a2c823ca..01c9d186194 100644 --- a/regression/goto-analyzer/sensitivity-test-constants-array/test.desc +++ b/regression/goto-analyzer/sensitivity-test-constants-array/test.desc @@ -1,39 +1,39 @@ -FUTURE +CORE sensitivity_test_constants_array.c --variable --arrays --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion a\[1\]==0: Success$ -^\[main.assertion.2\] .* assertion a\[1\]==1: Failure \(if reachable\)$ -^\[main.assertion.3\] .* assertion b\[1\]==0: Success$ -^\[main.assertion.4\] .* assertion b\[1\]==1: Failure \(if reachable\)$ -^\[main.assertion.5\] .* assertion \*\(b\+1\)==0: Success$ -^\[main.assertion.6\] .* assertion \*\(b\+1\)==1: Failure \(if reachable\)$ -^\[main.assertion.7\] .* assertion \*\(1\+b\)==0: Unknown$ -^\[main.assertion.8\] .* assertion \*\(1\+b\)==1: Unknown$ -^\[main.assertion.9\] .* assertion 1\[b\]==0: Success$ -^\[main.assertion.10\] .* assertion 1\[b\]==1: Failure \(if reachable\)$ -^\[main.assertion.11\] .* assertion c\[0\]==0: Success$ -^\[main.assertion.12\] .* assertion c\[0\]==1: Failure \(if reachable\)$ -^\[main.assertion.13\] .* assertion d\[0\]==0: Unknown$ -^\[main.assertion.14\] .* assertion d\[0\]==2: Unknown$ -^\[main.assertion.15\] .* assertion d\[1\]==0: Success$ -^\[main.assertion.16\] .* assertion a\[i\]==0: Success$ -^\[main.assertion.17\] .* assertion a\[i\]==1: Failure \(if reachable\)$ -^\[main.assertion.18\] .* assertion a\[j\]==0: Unknown$ -^\[main.assertion.19\] .* assertion a\[j\]==1: Unknown$ -^\[main.assertion.20\] .* assertion b\[i\]==1: Success$ -^\[main.assertion.21\] .* assertion b\[i\]==0: Failure \(if reachable\)$ -^\[main.assertion.22\] .* assertion b\[j\]==0: Unknown$ -^\[main.assertion.23\] .* assertion b\[j\]==1: Unknown$ -^\[main.assertion.24\] .* assertion a\[100\]==0: Unknown$ -^\[main.assertion.25\] .* assertion b\[1\]==0: Success$ -^\[main.assertion.26\] .* assertion ei\[0\]==1: Success$ -^\[main.assertion.27\] .* assertion ei\[0\]==0: Failure \(if reachable\)$ -^\[main.assertion.28\] .* assertion ei\[2\]==0: Success$ -^\[main.assertion.29\] .* assertion ei\[2\]==1: Failure \(if reachable\)$ -^\[main.assertion.30\] .* assertion ej\[0\]==0: Unknown$ -^\[main.assertion.31\] .* assertion ej\[2\]==0: Unknown$ -^\[main.assertion.32\] .* assertion ek\[0\]==0: Unknown$ +^\[main.assertion.1\] .* a\[1\]==0: Success$ +^\[main.assertion.2\] .* a\[1\]==1: Failure \(if reachable\)$ +^\[main.assertion.3\] .* b\[1\]==0: Success$ +^\[main.assertion.4\] .* b\[1\]==1: Failure \(if reachable\)$ +^\[main.assertion.5\] .* \*\(b\+1\)==0: Success$ +^\[main.assertion.6\] .* \*\(b\+1\)==1: Failure \(if reachable\)$ +^\[main.assertion.7\] .* \*\(1\+b\)==0: Unknown$ +^\[main.assertion.8\] .* \*\(1\+b\)==1: Unknown$ +^\[main.assertion.9\] .* 1\[b\]==0: Success$ +^\[main.assertion.10\] .* 1\[b\]==1: Failure \(if reachable\)$ +^\[main.assertion.11\] .* c\[0\]==0: Success$ +^\[main.assertion.12\] .* c\[0\]==1: Failure \(if reachable\)$ +^\[main.assertion.13\] .* d\[0\]==0: Unknown$ +^\[main.assertion.14\] .* d\[0\]==2: Unknown$ +^\[main.assertion.15\] .* d\[1\]==0: Success$ +^\[main.assertion.16\] .* a\[i\]==0: Success$ +^\[main.assertion.17\] .* a\[i\]==1: Failure \(if reachable\)$ +^\[main.assertion.18\] .* a\[j\]==0: Unknown$ +^\[main.assertion.19\] .* a\[j\]==1: Unknown$ +^\[main.assertion.20\] .* b\[i\]==1: Success$ +^\[main.assertion.21\] .* b\[i\]==0: Failure \(if reachable\)$ +^\[main.assertion.22\] .* b\[j\]==0: Unknown$ +^\[main.assertion.23\] .* b\[j\]==1: Unknown$ +^\[main.assertion.24\] .* a\[100\]==0: Unknown$ +^\[main.assertion.25\] .* b\[1\]==0: Success$ +^\[main.assertion.26\] .* ei\[0\]==1: Success$ +^\[main.assertion.27\] .* ei\[0\]==0: Failure \(if reachable\)$ +^\[main.assertion.28\] .* ei\[2\]==0: Success$ +^\[main.assertion.29\] .* ei\[2\]==1: Failure \(if reachable\)$ +^\[main.assertion.30\] .* ej\[0\]==0: Unknown$ +^\[main.assertion.31\] .* ej\[2\]==0: Unknown$ +^\[main.assertion.32\] .* ek\[0\]==0: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-constants-char/test.desc b/regression/goto-analyzer/sensitivity-test-constants-char/test.desc index 4ae7832010b..11129c480a6 100644 --- a/regression/goto-analyzer/sensitivity-test-constants-char/test.desc +++ b/regression/goto-analyzer/sensitivity-test-constants-char/test.desc @@ -1,9 +1,9 @@ -FUTURE +CORE sensitivity_test_constants_char.c --variable --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion x=='a': Success$ -^\[main.assertion.2\] .* assertion x=='b': Failure \(if reachable\)$ +^\[main.assertion.1\] .* x=='a': Success$ +^\[main.assertion.2\] .* x=='b': Failure \(if reachable\)$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-constants-float/test.desc b/regression/goto-analyzer/sensitivity-test-constants-float/test.desc index 634ea862f56..0868c1da64c 100644 --- a/regression/goto-analyzer/sensitivity-test-constants-float/test.desc +++ b/regression/goto-analyzer/sensitivity-test-constants-float/test.desc @@ -1,9 +1,9 @@ -FUTURE +CORE sensitivity_test_constants_float.c --variable --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion x==0.0: Success$ -^\[main.assertion.2\] .* assertion x==1.0: Failure \(if reachable\)$ +^\[main.assertion.1\] .* x==0.0: Success$ +^\[main.assertion.2\] .* x==1.0: Failure \(if reachable\)$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-constants-int/test.desc b/regression/goto-analyzer/sensitivity-test-constants-int/test.desc index d3c274a9447..8a05deb8c53 100644 --- a/regression/goto-analyzer/sensitivity-test-constants-int/test.desc +++ b/regression/goto-analyzer/sensitivity-test-constants-int/test.desc @@ -1,30 +1,35 @@ -FUTURE +CORE sensitivity_test_constants_int.c --variable --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion x==0: Success$ -^\[main.assertion.2\] .* assertion x==1: Failure \(if reachable\)$ -^\[main.assertion.3\] .* assertion x==y: Unknown$ -^\[main.assertion.4\] .* assertion x<1: Success$ -^\[main.assertion.5\] .* assertion x<-1: Failure \(if reachable\)$ -^\[main.assertion.6\] .* assertion x-1: Success$ -^\[main.assertion.8\] .* assertion x>1: Failure \(if reachable\)$ -^\[main.assertion.9\] .* assertion x>y: Unknown$ -^\[main.assertion.10\] .* assertion x!=1: Success$ -^\[main.assertion.11\] .* assertion x!=0: Failure \(if reachable\)$ -^\[main.assertion.12\] .* assertion x!=y: Unknown$ -^\[main.assertion.13\] .* assertion !\(x==1\): Success$ -^\[main.assertion.14\] .* assertion !\(x==0\): Failure \(if reachable\)$ -^\[main.assertion.15\] .* assertion !\(x==y\): Unknown$ -^\[main.assertion.16\] .* assertion y<2: Unknown$ -^\[main.assertion.17\] .* assertion y>2: Unknown$ -^\[main.assertion.18\] .* assertion y==1: Unknown$ -^\[main.assertion.19\] .* assertion z==0: Success$ -^\[main.assertion.20\] .* assertion z==10: Failure \(if reachable\)$ -^\[main.assertion.21\] .* assertion x==0: Success \(unreachable\)$ -^\[main.assertion.22\] .* assertion x==1: Success \(unreachable\)$ -^\[main.assertion.23\] .* assertion y==0: Success \(unreachable\)$ +^\[main.assertion.1\] .* x==0: Success$ +^\[main.assertion.2\] .* x==1: Failure \(if reachable\)$ +^\[main.assertion.3\] .* x==y: Unknown$ +^\[main.assertion.4\] .* x<1: Success$ +^\[main.assertion.5\] .* x<-1: Failure \(if reachable\)$ +^\[main.assertion.6\] .* x-1: Success$ +^\[main.assertion.8\] .* x>1: Failure \(if reachable\)$ +^\[main.assertion.9\] .* x>y: Unknown$ +^\[main.assertion.10\] .* x!=1: Success$ +^\[main.assertion.11\] .* x!=0: Failure \(if reachable\)$ +^\[main.assertion.12\] .* x!=y: Unknown$ +^\[main.assertion.13\] .* !\(x==1\): Success$ +^\[main.assertion.14\] .* !\(x==0\): Failure \(if reachable\)$ +^\[main.assertion.15\] .* !\(x==y\): Unknown$ +^\[main.assertion.16\] .* y<2: Unknown$ +^\[main.assertion.17\] .* y>2: Unknown$ +^\[main.assertion.18\] .* y==1: Unknown$ +^\[main.assertion.19\] .* z==0: Success$ +^\[main.assertion.20\] .* z==10: Failure \(if reachable\)$ +^\[main.assertion.21\] .* x==0: Success \(unreachable\)$ +^\[main.assertion.22\] .* x==1: Success \(unreachable\)$ +^\[main.assertion.23\] .* y==0: Success \(unreachable\)$ +^\[main.assertion.24\] .* a1==0: Unknown$ +^\[main.assertion.25\] .* a2==0: Unknown$ +^\[main.assertion.26\] .* a3==0: Unknown$ +^\[main.assertion.27\] .* a4==0: Success$ +^\[main.assertion.28\] .* a5==0: Success$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-constants-pointer-to-constants-array/test.desc b/regression/goto-analyzer/sensitivity-test-constants-pointer-to-constants-array/test.desc index 7ccb164ab0f..62ff39b5230 100644 --- a/regression/goto-analyzer/sensitivity-test-constants-pointer-to-constants-array/test.desc +++ b/regression/goto-analyzer/sensitivity-test-constants-pointer-to-constants-array/test.desc @@ -1,21 +1,29 @@ -FUTURE +CORE sensitivity_test_constants_pointer_to_constants_array.c --variable --pointers --arrays --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion p==&a\[0\]: Success$ -^\[main.assertion.2\] .* assertion \*p==1: Success$ -^\[main.assertion.3\] .* assertion q==p\+1: Unknown$ -^\[main.assertion.4\] .* assertion \*q==2: Unknown$ -^\[main.assertion.5\] .* assertion q-p==x: Unknown$ -^\[main.assertion.6\] .* assertion a\[1\]==4: Unknown$ -^\[main.assertion.7\] .* assertion \*r==2: Unknown$ -^\[main.assertion.8\] .* assertion \*r==1: Unknown$ -^\[main.assertion.9\] .* assertion \*s==0: Unknown$ -^\[main.assertion.10\] .* assertion \*s==1: Unknown$ -^\[main.assertion.11\] .* assertion t==p\+i: Unknown$ -^\[main.assertion.12\] .* assertion t-p==y: Unknown$ -^\[main.assertion.13\] .* assertion a\[i\]==5: Unknown$ -^\[main.assertion.14\] .* assertion a\[1\]==5: Unknown$ +^\[main.assertion.1\] .* p==&a\[0\]: Success$ +^\[main.assertion.2\] .* \*p==1: Success$ +^\[main\.assertion\.3\] .* p\[1\]==2: Unknown$ +^\[main\.assertion\.4\] .* 1\[p\]==2: Unknown$ +^\[main\.assertion\.5\] .* \*\(p\+1\)==2: Unknown$ +^\[main\.assertion\.6\] .* \*\(1\+p\)==2: Unknown$ +^\[main\.assertion\.7\] .* \*\(p-1\)==1: Unknown$ +^\[main\.assertion\.8\] .* q==p\+1: Unknown$ +^\[main\.assertion\.9\] .* \*q==2: Unknown$ +^\[main\.assertion\.10\] .* q-p==x: Unknown$ +^\[main\.assertion\.11\] .* a\[1\]==4: Unknown$ +^\[main\.assertion\.12\] .* a\[1\]==5: Unknown$ +^\[main\.assertion\.13\] .* a\[1\]==6: Unknown$ +^\[main\.assertion\.14\] .* a\[1\]==7: Unknown$ +^\[main\.assertion\.15\] .* \*r==2: Unknown$ +^\[main\.assertion\.16\] .* \*r==1: Unknown$ +^\[main\.assertion\.17\] .* \*s==0: Unknown$ +^\[main\.assertion\.18\] .* \*s==1: Unknown$ +^\[main\.assertion\.19\] .* t==p\+i: Unknown$ +^\[main\.assertion\.20\] .* t-p==y: Unknown$ +^\[main\.assertion\.21\] .* a\[i\]==5: Unknown$ +^\[main\.assertion\.22\] .* a\[1\]==5: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-constants-pointer-to-constants-pointer/test.desc b/regression/goto-analyzer/sensitivity-test-constants-pointer-to-constants-pointer/test.desc index f7fa1706d6a..d4d18683447 100644 --- a/regression/goto-analyzer/sensitivity-test-constants-pointer-to-constants-pointer/test.desc +++ b/regression/goto-analyzer/sensitivity-test-constants-pointer-to-constants-pointer/test.desc @@ -1,13 +1,13 @@ -FUTURE +CORE sensitivity_test_constants_pointer_to_constants_pointer.c --variable --pointers --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion \*\*x==0: Success$ -^\[main.assertion.2\] .* assertion \*\*x==1: Failure \(if reachable\)$ -^\[main.assertion.3\] .* assertion \*\*x==1: Success$ -^\[main.assertion.4\] .* assertion \*\*x==0: Failure \(if reachable\)$ -^\[main.assertion.5\] .* assertion a==2: Success$ -^\[main.assertion.6\] .* assertion a==1: Failure \(if reachable\)$ +^\[main.assertion.1\] .* \*\*x==0: Success$ +^\[main.assertion.2\] .* \*\*x==1: Failure \(if reachable\)$ +^\[main.assertion.3\] .* \*\*x==1: Success$ +^\[main.assertion.4\] .* \*\*x==0: Failure \(if reachable\)$ +^\[main.assertion.5\] .* a==2: Success$ +^\[main.assertion.6\] .* a==1: Failure \(if reachable\)$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-constants-pointer-to-constants-struct/test.desc b/regression/goto-analyzer/sensitivity-test-constants-pointer-to-constants-struct/test.desc index c7abd5e6821..f6e0a55e3ef 100644 --- a/regression/goto-analyzer/sensitivity-test-constants-pointer-to-constants-struct/test.desc +++ b/regression/goto-analyzer/sensitivity-test-constants-pointer-to-constants-struct/test.desc @@ -3,12 +3,12 @@ sensitivity_test_constants_pointer_to_constants_struct.c --variable --pointers --structs --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion \(\*p\).a==0: Success$ -^\[main.assertion.2\] .* assertion \(\*p\).a==1: Failure \(if reachable\)$ -^\[main.assertion.3\] .* assertion p->a==0: Success$ -^\[main.assertion.4\] .* assertion p->a==1: Failure \(if reachable\)$ -^\[main.assertion.5\] .* assertion p->b==2.0: Success$ -^\[main.assertion.6\] .* assertion p->b==1.0: Failure \(if reachable\)$ +^\[main.assertion.1\] .* \(\*p\).a==0: Success$ +^\[main.assertion.2\] .* \(\*p\).a==1: Failure \(if reachable\)$ +^\[main.assertion.3\] .* p->a==0: Success$ +^\[main.assertion.4\] .* p->a==1: Failure \(if reachable\)$ +^\[main.assertion.5\] .* p->b==2.0: Success$ +^\[main.assertion.6\] .* p->b==1.0: Failure \(if reachable\)$ -- ^warning: ignoring -- diff --git a/regression/goto-analyzer/sensitivity-test-constants-pointer-to-two-value-array/test.desc b/regression/goto-analyzer/sensitivity-test-constants-pointer-to-two-value-array/test.desc index 7121e17040d..56d38be4bb0 100644 --- a/regression/goto-analyzer/sensitivity-test-constants-pointer-to-two-value-array/test.desc +++ b/regression/goto-analyzer/sensitivity-test-constants-pointer-to-two-value-array/test.desc @@ -1,21 +1,29 @@ -FUTURE +CORE sensitivity_test_constants_pointer_to_two_value_array.c --variable --pointers --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion p==&a\[0\]: Success$ -^\[main.assertion.2\] .* assertion \*p==1: Unknown$ -^\[main.assertion.3\] .* assertion q==p\+1: Unknown$ -^\[main.assertion.4\] .* assertion \*q==2: Unknown$ -^\[main.assertion.5\] .* assertion q-p==x: Unknown$ -^\[main.assertion.6\] .* assertion a\[1\]==4: Unknown$ -^\[main.assertion.7\] .* assertion \*r==2: Unknown$ -^\[main.assertion.8\] .* assertion \*r==1: Unknown$ -^\[main.assertion.9\] .* assertion \*s==0: Unknown$ -^\[main.assertion.10\] .* assertion \*s==1: Unknown$ -^\[main.assertion.11\] .* assertion t==p\+i: Unknown$ -^\[main.assertion.12\] .* assertion t-p==y: Unknown$ -^\[main.assertion.13\] .* assertion a\[i\]==5: Unknown$ -^\[main.assertion.14\] .* assertion a\[1\]==5: Unknown$ +^\[main.assertion.1\] .* p==&a\[0\]: Success$ +^\[main.assertion.2\] .* \*p==1: Unknown$ +^\[main\.assertion\.3\] .* p\[1\]==2: Unknown$ +^\[main\.assertion\.4\] .* 1\[p\]==2: Unknown$ +^\[main\.assertion\.5\] .* \*\(p\+1\)==2: Unknown$ +^\[main\.assertion\.6\] .* \*\(1\+p\)==2: Unknown$ +^\[main\.assertion\.7\] .* \*\(p-1\)==1: Unknown$ +^\[main.assertion.8\] .* q==p\+1: Unknown$ +^\[main.assertion.9\] .* \*q==2: Unknown$ +^\[main.assertion.10\] .* q-p==x: Unknown$ +^\[main.assertion.11\] .* a\[1\]==4: Unknown$ +^\[main.assertion.12\] .* a\[1\]==5: Unknown$ +^\[main\.assertion\.13\] .* a\[1\]==6: Unknown$ +^\[main\.assertion\.14\] .* a\[1\]==7: Unknown$ +^\[main.assertion.15\] .* \*r==2: Unknown$ +^\[main.assertion.16\] .* \*r==1: Unknown$ +^\[main.assertion.17\] .* \*s==0: Unknown$ +^\[main.assertion.18\] .* \*s==1: Unknown$ +^\[main.assertion.19\] .* t==p\+i: Unknown$ +^\[main.assertion.20\] .* t-p==y: Unknown$ +^\[main.assertion.21\] .* a\[i\]==5: Unknown$ +^\[main.assertion.22\] .* a\[1\]==5: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-constants-pointer-to-two-value-struct/test.desc b/regression/goto-analyzer/sensitivity-test-constants-pointer-to-two-value-struct/test.desc index a214499b34b..225a8c942df 100644 --- a/regression/goto-analyzer/sensitivity-test-constants-pointer-to-two-value-struct/test.desc +++ b/regression/goto-analyzer/sensitivity-test-constants-pointer-to-two-value-struct/test.desc @@ -1,13 +1,13 @@ -FUTURE +CORE sensitivity_test_constants_pointer_to_two_value_struct.c --variable --pointers --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion \(\*p\).a==0: Unknown$ -^\[main.assertion.2\] .* assertion \(\*p\).a==1: Unknown$ -^\[main.assertion.3\] .* assertion p->a==0: Unknown$ -^\[main.assertion.4\] .* assertion p->a==1: Unknown$ -^\[main.assertion.5\] .* assertion p->b==2.0: Unknown$ -^\[main.assertion.6\] .* assertion p->b==1.0: Unknown$ +^\[main.assertion.1\] .* \(\*p\).a==0: Unknown$ +^\[main.assertion.2\] .* \(\*p\).a==1: Unknown$ +^\[main.assertion.3\] .* p->a==0: Unknown$ +^\[main.assertion.4\] .* p->a==1: Unknown$ +^\[main.assertion.5\] .* p->b==2.0: Unknown$ +^\[main.assertion.6\] .* p->b==1.0: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-constants-pointer/test.desc b/regression/goto-analyzer/sensitivity-test-constants-pointer/test.desc index 22c179f2233..a9800cb3943 100644 --- a/regression/goto-analyzer/sensitivity-test-constants-pointer/test.desc +++ b/regression/goto-analyzer/sensitivity-test-constants-pointer/test.desc @@ -1,21 +1,21 @@ -FUTURE +CORE sensitivity_test_constants_pointer.c --variable --pointers --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion x==&a: Success$ -^\[main.assertion.2\] .* assertion x==&b: Failure \(if reachable\)$ -^\[main.assertion.3\] .* assertion x==x2: Success$ -^\[main.assertion.4\] .* assertion x==y: Failure \(if reachable\)$ -^\[main.assertion.5\] .* assertion \*x==0: Success$ -^\[main.assertion.6\] .* assertion \*x==1: Failure \(if reachable\)$ -^\[main.assertion.7\] .* assertion \*x==1: Success$ -^\[main.assertion.8\] .* assertion \*x==0: Failure \(if reachable\)$ -^\[main.assertion.9\] .* assertion a==2: Success$ -^\[main.assertion.10\] .* assertion a==0: Failure \(if reachable\)$ -^\[main.assertion.11\] .* assertion x==&a: Success$ -^\[main.assertion.12\] .* assertion \*x==0: Unknown$ -^\[main.assertion.13\] .* assertion x==&a: Unknown$ -^\[main.assertion.14\] .* assertion x==&b: Unknown$ +^\[main.assertion.1\] .* x==&a: Success$ +^\[main.assertion.2\] .* x==&b: Failure \(if reachable\)$ +^\[main.assertion.3\] .* x==x2: Success$ +^\[main.assertion.4\] .* x==y: Failure \(if reachable\)$ +^\[main.assertion.5\] .* \*x==0: Success$ +^\[main.assertion.6\] .* \*x==1: Failure \(if reachable\)$ +^\[main.assertion.7\] .* \*x==1: Success$ +^\[main.assertion.8\] .* \*x==0: Failure \(if reachable\)$ +^\[main.assertion.9\] .* a==2: Success$ +^\[main.assertion.10\] .* a==0: Failure \(if reachable\)$ +^\[main.assertion.11\] .* x==&a: Success$ +^\[main.assertion.12\] .* \*x==0: Unknown$ +^\[main.assertion.13\] .* x==&a: Unknown$ +^\[main.assertion.14\] .* x==&b: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-constants-struct-of-constants-array/test.desc b/regression/goto-analyzer/sensitivity-test-constants-struct-of-constants-array/test.desc index 7b6ae24bf61..29eb717e225 100644 --- a/regression/goto-analyzer/sensitivity-test-constants-struct-of-constants-array/test.desc +++ b/regression/goto-analyzer/sensitivity-test-constants-struct-of-constants-array/test.desc @@ -1,24 +1,24 @@ -FUTURE +CORE sensitivity_test_constants_struct_of_constants_array.c --variable --structs --arrays --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion x.a\[0\]==0: Success$ -^\[main.assertion.2\] .* assertion \*\(x.a\+0\)==0: Success$ -^\[main.assertion.3\] .* assertion \*\(0\+x.a\)==0: Success$ -^\[main.assertion.4\] .* assertion 0\[x.a\]==0: Success$ -^\[main.assertion.5\] .* assertion x.a\[0\]==0: Success$ -^\[main.assertion.6\] .* assertion x.a\[1\]==1: Success$ -^\[main.assertion.7\] .* assertion x.b\[0\]==3.0f: Success$ -^\[main.assertion.8\] .* assertion x.a\[0\]==0: Success$ -^\[main.assertion.9\] .* assertion x.a\[1\]==1: Success$ -^\[main.assertion.10\] .* assertion x.b\[2\]>0.0f: Unknown$ -^\[main.assertion.11\] .* assertion x.b\[2\]==15.0f: Unknown$ -^\[main.assertion.12\] .* assertion x.b\[2\]==1.0f: Unknown$ -^\[main.assertion.13\] .* assertion x.b\[0\]==3.0f: Success$ -^\[main.assertion.14\] .* assertion x.a\[0\]<12: Unknown$ -^\[main.assertion.15\] .* assertion x.a\[0\]>2: Unknown$ -^\[main.assertion.16\] .* assertion x.a\[0\]==0: Unknown$ -^\[main.assertion.17\] .* assertion x.a\[1\]==1: Success$ +^\[main.assertion.1\] .* x.a\[0\]==0: Success$ +^\[main.assertion.2\] .* \*\(x.a\+0\)==0: Success$ +^\[main.assertion.3\] .* \*\(0\+x.a\)==0: Success$ +^\[main.assertion.4\] .* 0\[x.a\]==0: Success$ +^\[main.assertion.5\] .* x.a\[0\]==0: Success$ +^\[main.assertion.6\] .* x.a\[1\]==1: Success$ +^\[main.assertion.7\] .* x.b\[0\]==3.0f: Success$ +^\[main.assertion.8\] .* x.a\[0\]==0: Success$ +^\[main.assertion.9\] .* x.a\[1\]==1: Success$ +^\[main.assertion.10\] .* x.b\[2\]>0.0f: Unknown$ +^\[main.assertion.11\] .* x.b\[2\]==15.0f: Unknown$ +^\[main.assertion.12\] .* x.b\[2\]==1.0f: Unknown$ +^\[main.assertion.13\] .* x.b\[0\]==3.0f: Success$ +^\[main.assertion.14\] .* x.a\[0\]<12: Unknown$ +^\[main.assertion.15\] .* x.a\[0\]>2: Unknown$ +^\[main.assertion.16\] .* x.a\[0\]==0: Unknown$ +^\[main.assertion.17\] .* x.a\[1\]==1: Success$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-constants-struct-of-constants-pointer/test.desc b/regression/goto-analyzer/sensitivity-test-constants-struct-of-constants-pointer/test.desc index b278a7ed47c..78664b1ea0d 100644 --- a/regression/goto-analyzer/sensitivity-test-constants-struct-of-constants-pointer/test.desc +++ b/regression/goto-analyzer/sensitivity-test-constants-struct-of-constants-pointer/test.desc @@ -1,33 +1,33 @@ -FUTURE +CORE sensitivity_test_constants_struct_of_constants_pointer.c --variable --structs --pointers --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion x.a==&a1: Success$ -^\[main.assertion.2\] .* assertion x.a==&a2: Failure \(if reachable\)$ -^\[main.assertion.3\] .* assertion x.b==&b1: Success$ -^\[main.assertion.4\] .* assertion x.b==&b2: Failure \(if reachable\)$ -^\[main.assertion.5\] .* assertion \*x.a==0: Success$ -^\[main.assertion.6\] .* assertion \*x.a==100: Failure \(if reachable\)$ -^\[main.assertion.7\] .* assertion \*x.b==10.0f: Success$ -^\[main.assertion.8\] .* assertion \*x.b==110.0f: Failure \(if reachable\)$ -^\[main.assertion.9\] .* assertion x.a==&a1: Success$ -^\[main.assertion.10\] .* assertion x.a==&a2: Failure \(if reachable\)$ -^\[main.assertion.11\] .* assertion \*x.a==0: Success$ -^\[main.assertion.12\] .* assertion \*x.a==100: Failure \(if reachable\)$ -^\[main.assertion.13\] .* assertion x.a==&a1: Success$ -^\[main.assertion.14\] .* assertion x.b==&b2: Unknown$ -^\[main.assertion.15\] .* assertion x.b==&b3: Unknown$ -^\[main.assertion.16\] .* assertion \*x.a==0: Success$ -^\[main.assertion.17\] .* assertion \*x.b==11.0f: Unknown$ -^\[main.assertion.18\] .* assertion \*x.b==12.0f: Unknown$ -^\[main.assertion.19\] .* assertion x.a==&a2: Unknown$ -^\[main.assertion.20\] .* assertion x.a==&a3: Unknown$ -^\[main.assertion.21\] .* assertion x.b==&b3: Unknown$ -^\[main.assertion.22\] .* assertion x.b==&b4: Unknown$ -^\[main.assertion.23\] .* assertion \*x.a==1: Unknown$ -^\[main.assertion.24\] .* assertion \*x.a==2: Unknown$ -^\[main.assertion.25\] .* assertion \*x.b==12.0f: Unknown$ -^\[main.assertion.26\] .* assertion \*x.b==13.0f: Unknown$ +^\[main.assertion.1\] .* x.a==&a1: Success$ +^\[main.assertion.2\] .* x.a==&a2: Failure \(if reachable\)$ +^\[main.assertion.3\] .* x.b==&b1: Success$ +^\[main.assertion.4\] .* x.b==&b2: Failure \(if reachable\)$ +^\[main.assertion.5\] .* \*x.a==0: Success$ +^\[main.assertion.6\] .* \*x.a==100: Failure \(if reachable\)$ +^\[main.assertion.7\] .* \*x.b==10.0f: Success$ +^\[main.assertion.8\] .* \*x.b==110.0f: Failure \(if reachable\)$ +^\[main.assertion.9\] .* x.a==&a1: Success$ +^\[main.assertion.10\] .* x.a==&a2: Failure \(if reachable\)$ +^\[main.assertion.11\] .* \*x.a==0: Success$ +^\[main.assertion.12\] .* \*x.a==100: Failure \(if reachable\)$ +^\[main.assertion.13\] .* x.a==&a1: Success$ +^\[main.assertion.14\] .* x.b==&b2: Unknown$ +^\[main.assertion.15\] .* x.b==&b3: Unknown$ +^\[main.assertion.16\] .* \*x.a==0: Success$ +^\[main.assertion.17\] .* \*x.b==11.0f: Unknown$ +^\[main.assertion.18\] .* \*x.b==12.0f: Unknown$ +^\[main.assertion.19\] .* x.a==&a2: Unknown$ +^\[main.assertion.20\] .* x.a==&a3: Unknown$ +^\[main.assertion.21\] .* x.b==&b3: Unknown$ +^\[main.assertion.22\] .* x.b==&b4: Unknown$ +^\[main.assertion.23\] .* \*x.a==1: Unknown$ +^\[main.assertion.24\] .* \*x.a==2: Unknown$ +^\[main.assertion.25\] .* \*x.b==12.0f: Unknown$ +^\[main.assertion.26\] .* \*x.b==13.0f: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-constants-struct-of-constants-struct/test.desc b/regression/goto-analyzer/sensitivity-test-constants-struct-of-constants-struct/test.desc index 28f2e09614a..a479614cb9a 100644 --- a/regression/goto-analyzer/sensitivity-test-constants-struct-of-constants-struct/test.desc +++ b/regression/goto-analyzer/sensitivity-test-constants-struct-of-constants-struct/test.desc @@ -1,18 +1,18 @@ -FUTURE +CORE sensitivity_test_constants_struct_of_constants_struct.c --variable --structs --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion x.s1.a==0: Success$ -^\[main.assertion.2\] .* assertion x.s2.b==3.0f: Success$ -^\[main.assertion.3\] .* assertion x.s1.a==0: Success$ -^\[main.assertion.4\] .* assertion x.s1.a==10: Failure \(if reachable\)$ -^\[main.assertion.5\] .* assertion x.s1.b==1.0f: Success$ -^\[main.assertion.6\] .* assertion x.s2.b==3.0f: Unknown$ -^\[main.assertion.7\] .* assertion x.s2.b==0.0f: Unknown$ -^\[main.assertion.8\] .* assertion x.s1.a==20: Unknown$ -^\[main.assertion.9\] .* assertion x.s1.a<30: Unknown$ -^\[main.assertion.10\] .* assertion x.s2.a==22: Unknown$ -^\[main.assertion.11\] .* assertion x.s2.a<30: Unknown$ +^\[main.assertion.1\] .* x.s1.a==0: Success$ +^\[main.assertion.2\] .* x.s2.b==3.0f: Success$ +^\[main.assertion.3\] .* x.s1.a==0: Success$ +^\[main.assertion.4\] .* x.s1.a==10: Failure \(if reachable\)$ +^\[main.assertion.5\] .* x.s1.b==1.0f: Success$ +^\[main.assertion.6\] .* x.s2.b==3.0f: Unknown$ +^\[main.assertion.7\] .* x.s2.b==0.0f: Unknown$ +^\[main.assertion.8\] .* x.s1.a==20: Unknown$ +^\[main.assertion.9\] .* x.s1.a<30: Unknown$ +^\[main.assertion.10\] .* x.s2.a==22: Unknown$ +^\[main.assertion.11\] .* x.s2.a<30: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-constants-struct-of-two-value-array/test.desc b/regression/goto-analyzer/sensitivity-test-constants-struct-of-two-value-array/test.desc index 30edb4b598c..8f7111b0fcf 100644 --- a/regression/goto-analyzer/sensitivity-test-constants-struct-of-two-value-array/test.desc +++ b/regression/goto-analyzer/sensitivity-test-constants-struct-of-two-value-array/test.desc @@ -1,24 +1,24 @@ -FUTURE +CORE sensitivity_test_constants_struct_of_two_value_array.c --variable --structs --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion x.a\[0\]==0: Unknown$ -^\[main.assertion.2\] .* assertion \*\(x.a\+0\)==0: Unknown$ -^\[main.assertion.3\] .* assertion \*\(0\+x.a\)==0: Unknown$ -^\[main.assertion.4\] .* assertion 0\[x.a\]==0: Unknown$ -^\[main.assertion.5\] .* assertion x.a\[0\]==0: Unknown$ -^\[main.assertion.6\] .* assertion x.a\[1\]==1: Unknown$ -^\[main.assertion.7\] .* assertion x.b\[0\]==3.0f: Unknown$ -^\[main.assertion.8\] .* assertion x.a\[0\]==0: Unknown$ -^\[main.assertion.9\] .* assertion x.a\[1\]==1: Unknown$ -^\[main.assertion.10\] .* assertion x.b\[2\]>0.0f: Unknown$ -^\[main.assertion.11\] .* assertion x.b\[2\]==15.0f: Unknown$ -^\[main.assertion.12\] .* assertion x.b\[2\]==1.0f: Unknown$ -^\[main.assertion.13\] .* assertion x.b\[0\]==3.0f: Unknown$ -^\[main.assertion.14\] .* assertion x.a\[0\]<12: Unknown$ -^\[main.assertion.15\] .* assertion x.a\[0\]>2: Unknown$ -^\[main.assertion.16\] .* assertion x.a\[0\]==0: Unknown$ -^\[main.assertion.17\] .* assertion x.a\[1\]==1: Unknown$ +^\[main.assertion.1\] .* x.a\[0\]==0: Unknown$ +^\[main.assertion.2\] .* \*\(x.a\+0\)==0: Unknown$ +^\[main.assertion.3\] .* \*\(0\+x.a\)==0: Unknown$ +^\[main.assertion.4\] .* 0\[x.a\]==0: Unknown$ +^\[main.assertion.5\] .* x.a\[0\]==0: Unknown$ +^\[main.assertion.6\] .* x.a\[1\]==1: Unknown$ +^\[main.assertion.7\] .* x.b\[0\]==3.0f: Unknown$ +^\[main.assertion.8\] .* x.a\[0\]==0: Unknown$ +^\[main.assertion.9\] .* x.a\[1\]==1: Unknown$ +^\[main.assertion.10\] .* x.b\[2\]>0.0f: Unknown$ +^\[main.assertion.11\] .* x.b\[2\]==15.0f: Unknown$ +^\[main.assertion.12\] .* x.b\[2\]==1.0f: Unknown$ +^\[main.assertion.13\] .* x.b\[0\]==3.0f: Unknown$ +^\[main.assertion.14\] .* x.a\[0\]<12: Unknown$ +^\[main.assertion.15\] .* x.a\[0\]>2: Unknown$ +^\[main.assertion.16\] .* x.a\[0\]==0: Unknown$ +^\[main.assertion.17\] .* x.a\[1\]==1: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-constants-struct-of-two-value-pointer/test.desc b/regression/goto-analyzer/sensitivity-test-constants-struct-of-two-value-pointer/test.desc index ea3a9cadb69..955f2504d87 100644 --- a/regression/goto-analyzer/sensitivity-test-constants-struct-of-two-value-pointer/test.desc +++ b/regression/goto-analyzer/sensitivity-test-constants-struct-of-two-value-pointer/test.desc @@ -1,33 +1,33 @@ -FUTURE +CORE sensitivity_test_constants_struct_of_two_value_pointer.c --variable --structs --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion x.a==&a1: Unknown$ -^\[main.assertion.2\] .* assertion x.a==&a2: Unknown$ -^\[main.assertion.3\] .* assertion x.b==&b1: Unknown$ -^\[main.assertion.4\] .* assertion x.b==&b2: Unknown$ -^\[main.assertion.5\] .* assertion \*x.a==0: Unknown$ -^\[main.assertion.6\] .* assertion \*x.a==100: Unknown$ -^\[main.assertion.7\] .* assertion \*x.b==10.0f: Unknown$ -^\[main.assertion.8\] .* assertion \*x.b==110.0f: Unknown$ -^\[main.assertion.9\] .* assertion x.a==&a1: Unknown$ -^\[main.assertion.10\] .* assertion x.a==&a2: Unknown$ -^\[main.assertion.11\] .* assertion \*x.a==0: Unknown$ -^\[main.assertion.12\] .* assertion \*x.a==100: Unknown$ -^\[main.assertion.13\] .* assertion x.a==&a1: Unknown$ -^\[main.assertion.14\] .* assertion x.b==&b2: Unknown$ -^\[main.assertion.15\] .* assertion x.b==&b3: Unknown$ -^\[main.assertion.16\] .* assertion \*x.a==0: Unknown$ -^\[main.assertion.17\] .* assertion \*x.b==11.0f: Unknown$ -^\[main.assertion.18\] .* assertion \*x.b==12.0f: Unknown$ -^\[main.assertion.19\] .* assertion x.a==&a2: Unknown$ -^\[main.assertion.20\] .* assertion x.a==&a3: Unknown$ -^\[main.assertion.21\] .* assertion x.b==&b3: Unknown$ -^\[main.assertion.22\] .* assertion x.b==&b4: Unknown$ -^\[main.assertion.23\] .* assertion \*x.a==1: Unknown$ -^\[main.assertion.24\] .* assertion \*x.a==2: Unknown$ -^\[main.assertion.25\] .* assertion \*x.b==12.0f: Unknown$ -^\[main.assertion.26\] .* assertion \*x.b==13.0f: Unknown$ +^\[main.assertion.1\] .* x.a==&a1: Unknown$ +^\[main.assertion.2\] .* x.a==&a2: Unknown$ +^\[main.assertion.3\] .* x.b==&b1: Unknown$ +^\[main.assertion.4\] .* x.b==&b2: Unknown$ +^\[main.assertion.5\] .* \*x.a==0: Unknown$ +^\[main.assertion.6\] .* \*x.a==100: Unknown$ +^\[main.assertion.7\] .* \*x.b==10.0f: Unknown$ +^\[main.assertion.8\] .* \*x.b==110.0f: Unknown$ +^\[main.assertion.9\] .* x.a==&a1: Unknown$ +^\[main.assertion.10\] .* x.a==&a2: Unknown$ +^\[main.assertion.11\] .* \*x.a==0: Unknown$ +^\[main.assertion.12\] .* \*x.a==100: Unknown$ +^\[main.assertion.13\] .* x.a==&a1: Unknown$ +^\[main.assertion.14\] .* x.b==&b2: Unknown$ +^\[main.assertion.15\] .* x.b==&b3: Unknown$ +^\[main.assertion.16\] .* \*x.a==0: Unknown$ +^\[main.assertion.17\] .* \*x.b==11.0f: Unknown$ +^\[main.assertion.18\] .* \*x.b==12.0f: Unknown$ +^\[main.assertion.19\] .* x.a==&a2: Unknown$ +^\[main.assertion.20\] .* x.a==&a3: Unknown$ +^\[main.assertion.21\] .* x.b==&b3: Unknown$ +^\[main.assertion.22\] .* x.b==&b4: Unknown$ +^\[main.assertion.23\] .* \*x.a==1: Unknown$ +^\[main.assertion.24\] .* \*x.a==2: Unknown$ +^\[main.assertion.25\] .* \*x.b==12.0f: Unknown$ +^\[main.assertion.26\] .* \*x.b==13.0f: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-constants-struct/test.desc b/regression/goto-analyzer/sensitivity-test-constants-struct/test.desc index 64a15fcae85..93b3589bc9a 100644 --- a/regression/goto-analyzer/sensitivity-test-constants-struct/test.desc +++ b/regression/goto-analyzer/sensitivity-test-constants-struct/test.desc @@ -1,16 +1,16 @@ -FUTURE +CORE sensitivity_test_constants_struct.c --variable --structs --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion x.a==0: Success$ -^\[main.assertion.2\] .* assertion x.a==1: Failure \(if reachable\)$ -^\[main.assertion.3\] .* assertion x.a==0: Success$ -^\[main.assertion.4\] .* assertion x.a==0: Success$ -^\[main.assertion.5\] .* assertion x.b>0.0f: Unknown$ -^\[main.assertion.6\] .* assertion x.b==1.0f: Unknown$ -^\[main.assertion.7\] .* assertion x.a<2: Unknown$ -^\[main.assertion.8\] .* assertion x.a>2: Unknown$ -^\[main.assertion.9\] .* assertion x.a==1: Unknown$ +^\[main.assertion.1\] .* x.a==0: Success$ +^\[main.assertion.2\] .* x.a==1: Failure \(if reachable\)$ +^\[main.assertion.3\] .* x.a==0: Success$ +^\[main.assertion.4\] .* x.a==0: Success$ +^\[main.assertion.5\] .* x.b>0.0f: Unknown$ +^\[main.assertion.6\] .* x.b==1.0f: Unknown$ +^\[main.assertion.7\] .* x.a<2: Unknown$ +^\[main.assertion.8\] .* x.a>2: Unknown$ +^\[main.assertion.9\] .* x.a==1: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-two-value-array-of-two-value-array/test.desc b/regression/goto-analyzer/sensitivity-test-two-value-array-of-two-value-array/test.desc index 2c2c3ed15a8..fc61fe8bbfa 100644 --- a/regression/goto-analyzer/sensitivity-test-two-value-array-of-two-value-array/test.desc +++ b/regression/goto-analyzer/sensitivity-test-two-value-array-of-two-value-array/test.desc @@ -1,73 +1,73 @@ -FUTURE +CORE sensitivity_test_two_value_array_of_two_value_array.c --variable --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion a\[1\]\[2\]==0: Unknown$ -^\[main.assertion.2\] .* assertion a\[1\]\[2\]==1: Unknown$ -^\[main.assertion.3\] .* assertion b\[1\]\[2\]==5: Unknown$ -^\[main.assertion.4\] .* assertion b\[1\]\[2\]==0: Unknown$ -^\[main.assertion.5\] .* assertion \*\(b\[1\]\+2\)==5: Unknown$ -^\[main.assertion.6\] .* assertion \*\(b\[1\]\+2\)==0: Unknown$ -^\[main.assertion.7\] .* assertion \(\*\(b\+1\)\)\[2\]==5: Unknown$ -^\[main.assertion.8\] .* assertion \(\*\(b\+1\)\)\[2\]==0: Unknown$ -^\[main.assertion.9\] .* assertion \*\(\*\(b\+1\)\+2\)==5: Unknown$ -^\[main.assertion.10\] .* assertion \*\(\*\(b\+1\)\+2\)==0: Unknown$ -^\[main.assertion.11\] .* assertion 1\[b\]\[2\]==5: Unknown$ -^\[main.assertion.12\] .* assertion 1\[b\]\[2\]==0: Unknown$ -^\[main.assertion.13\] .* assertion \*\(1\[b\]\+2\)==5: Unknown$ -^\[main.assertion.14\] .* assertion \*\(1\[b\]\+2\)==0: Unknown$ -^\[main.assertion.15\] .* assertion \(\*\(1\+b\)\)\[2\]==5: Unknown$ -^\[main.assertion.16\] .* assertion \(\*\(1\+b\)\)\[2\]==0: Unknown$ -^\[main.assertion.17\] .* assertion \*\(\*\(1\+b\)\+2\)==5: Unknown$ -^\[main.assertion.18\] .* assertion \*\(\*\(1\+b\)\+2\)==0: Unknown$ -^\[main.assertion.19\] .* assertion 2\[1\[b\]\]==5: Unknown$ -^\[main.assertion.20\] .* assertion 2\[1\[b\]\]==0: Unknown$ -^\[main.assertion.21\] .* assertion \*\(2\+1\[b\]\)==5: Unknown$ -^\[main.assertion.22\] .* assertion \*\(2\+1\[b\]\)==0: Unknown$ -^\[main.assertion.23\] .* assertion \*\(2\+\*\(1\+b\)\)==5: Unknown$ -^\[main.assertion.24\] .* assertion \*\(2\+\*\(1\+b\)\)==0: Unknown$ -^\[main.assertion.25\] .* assertion a\[0\]\[1\]==0: Unknown$ -^\[main.assertion.26\] .* assertion a\[0\]\[1\]==1: Unknown$ -^\[main.assertion.27\] .* assertion a\[0\]\[2\]==0: Unknown$ -^\[main.assertion.28\] .* assertion b\[0\]\[1\]==2: Unknown$ -^\[main.assertion.29\] .* assertion b\[0\]\[1\]==3: Unknown$ -^\[main.assertion.30\] .* assertion b\[0\]\[2\]==2: Unknown$ -^\[main.assertion.31\] .* assertion a\[i\]\[1\]==0: Unknown$ -^\[main.assertion.32\] .* assertion a\[i\]\[1\]==1: Unknown$ -^\[main.assertion.33\] .* assertion a\[1\]\[i\]==0: Unknown$ -^\[main.assertion.34\] .* assertion a\[1\]\[i\]==1: Unknown$ -^\[main.assertion.35\] .* assertion a\[i\]\[i\]==0: Unknown$ -^\[main.assertion.36\] .* assertion a\[i\]\[i\]==1: Unknown$ -^\[main.assertion.37\] .* assertion a\[j\]\[1\]==0: Unknown$ -^\[main.assertion.38\] .* assertion a\[j\]\[1\]==1: Unknown$ -^\[main.assertion.39\] .* assertion a\[1\]\[j\]==0: Unknown$ -^\[main.assertion.40\] .* assertion a\[1\]\[j\]==1: Unknown$ -^\[main.assertion.41\] .* assertion a\[j\]\[j\]==0: Unknown$ -^\[main.assertion.42\] .* assertion a\[j\]\[j\]==1: Unknown$ -^\[main.assertion.43\] .* assertion b\[i\]\[1\]==1: Unknown$ -^\[main.assertion.44\] .* assertion b\[i\]\[1\]==11: Unknown$ -^\[main.assertion.45\] .* assertion b\[1\]\[i\]==3: Unknown$ -^\[main.assertion.46\] .* assertion b\[1\]\[i\]==11: Unknown$ -^\[main.assertion.47\] .* assertion b\[i\]\[i\]==0: Unknown$ -^\[main.assertion.48\] .* assertion b\[i\]\[i\]==11: Unknown$ -^\[main.assertion.49\] .* assertion b\[j\]\[1\]==1: Unknown$ -^\[main.assertion.50\] .* assertion b\[j\]\[1\]==11: Unknown$ -^\[main.assertion.51\] .* assertion b\[1\]\[j\]==3: Unknown$ -^\[main.assertion.52\] .* assertion b\[1\]\[j\]==11: Unknown$ -^\[main.assertion.53\] .* assertion b\[j\]\[j\]==0: Unknown$ -^\[main.assertion.54\] .* assertion b\[j\]\[j\]==11: Unknown$ -^\[main.assertion.55\] .* assertion a\[100\]\[0\]==0: Unknown$ -^\[main.assertion.56\] .* assertion a\[0\]\[100\]==0: Unknown$ -^\[main.assertion.57\] .* assertion c==0: Success$ -^\[main.assertion.58\] .* assertion c==0: Success$ -^\[main.assertion.59\] .* assertion ei\[0\]\[1\]==1: Unknown$ -^\[main.assertion.60\] .* assertion ei\[0\]\[1\]==0: Unknown$ -^\[main.assertion.61\] .* assertion ei\[2\]\[1\]==0: Unknown$ -^\[main.assertion.62\] .* assertion ei\[2\]\[1\]==1: Unknown$ -^\[main.assertion.63\] .* assertion ej\[0\]\[1\]==0: Unknown$ -^\[main.assertion.64\] .* assertion ej\[2\]\[1\]==0: Unknown$ -^\[main.assertion.65\] .* assertion ek\[0\]\[1\]==0: Unknown$ -^\[main.assertion.66\] .* assertion c==0: Success$ +^\[main.assertion.1\] .* a\[1\]\[2\]==0: Unknown$ +^\[main.assertion.2\] .* a\[1\]\[2\]==1: Unknown$ +^\[main.assertion.3\] .* b\[1\]\[2\]==5: Unknown$ +^\[main.assertion.4\] .* b\[1\]\[2\]==0: Unknown$ +^\[main.assertion.5\] .* \*\(b\[1\]\+2\)==5: Unknown$ +^\[main.assertion.6\] .* \*\(b\[1\]\+2\)==0: Unknown$ +^\[main.assertion.7\] .* \(\*\(b\+1\)\)\[2\]==5: Unknown$ +^\[main.assertion.8\] .* \(\*\(b\+1\)\)\[2\]==0: Unknown$ +^\[main.assertion.9\] .* \*\(\*\(b\+1\)\+2\)==5: Unknown$ +^\[main.assertion.10\] .* \*\(\*\(b\+1\)\+2\)==0: Unknown$ +^\[main.assertion.11\] .* 1\[b\]\[2\]==5: Unknown$ +^\[main.assertion.12\] .* 1\[b\]\[2\]==0: Unknown$ +^\[main.assertion.13\] .* \*\(1\[b\]\+2\)==5: Unknown$ +^\[main.assertion.14\] .* \*\(1\[b\]\+2\)==0: Unknown$ +^\[main.assertion.15\] .* \(\*\(1\+b\)\)\[2\]==5: Unknown$ +^\[main.assertion.16\] .* \(\*\(1\+b\)\)\[2\]==0: Unknown$ +^\[main.assertion.17\] .* \*\(\*\(1\+b\)\+2\)==5: Unknown$ +^\[main.assertion.18\] .* \*\(\*\(1\+b\)\+2\)==0: Unknown$ +^\[main.assertion.19\] .* 2\[1\[b\]\]==5: Unknown$ +^\[main.assertion.20\] .* 2\[1\[b\]\]==0: Unknown$ +^\[main.assertion.21\] .* \*\(2\+1\[b\]\)==5: Unknown$ +^\[main.assertion.22\] .* \*\(2\+1\[b\]\)==0: Unknown$ +^\[main.assertion.23\] .* \*\(2\+\*\(1\+b\)\)==5: Unknown$ +^\[main.assertion.24\] .* \*\(2\+\*\(1\+b\)\)==0: Unknown$ +^\[main.assertion.25\] .* a\[0\]\[1\]==0: Unknown$ +^\[main.assertion.26\] .* a\[0\]\[1\]==1: Unknown$ +^\[main.assertion.27\] .* a\[0\]\[2\]==0: Unknown$ +^\[main.assertion.28\] .* b\[0\]\[1\]==2: Unknown$ +^\[main.assertion.29\] .* b\[0\]\[1\]==3: Unknown$ +^\[main.assertion.30\] .* b\[0\]\[2\]==2: Unknown$ +^\[main.assertion.31\] .* a\[i\]\[1\]==0: Unknown$ +^\[main.assertion.32\] .* a\[i\]\[1\]==1: Unknown$ +^\[main.assertion.33\] .* a\[1\]\[i\]==0: Unknown$ +^\[main.assertion.34\] .* a\[1\]\[i\]==1: Unknown$ +^\[main.assertion.35\] .* a\[i\]\[i\]==0: Unknown$ +^\[main.assertion.36\] .* a\[i\]\[i\]==1: Unknown$ +^\[main.assertion.37\] .* a\[j\]\[1\]==0: Unknown$ +^\[main.assertion.38\] .* a\[j\]\[1\]==1: Unknown$ +^\[main.assertion.39\] .* a\[1\]\[j\]==0: Unknown$ +^\[main.assertion.40\] .* a\[1\]\[j\]==1: Unknown$ +^\[main.assertion.41\] .* a\[j\]\[j\]==0: Unknown$ +^\[main.assertion.42\] .* a\[j\]\[j\]==1: Unknown$ +^\[main.assertion.43\] .* b\[i\]\[1\]==1: Unknown$ +^\[main.assertion.44\] .* b\[i\]\[1\]==11: Unknown$ +^\[main.assertion.45\] .* b\[1\]\[i\]==3: Unknown$ +^\[main.assertion.46\] .* b\[1\]\[i\]==11: Unknown$ +^\[main.assertion.47\] .* b\[i\]\[i\]==0: Unknown$ +^\[main.assertion.48\] .* b\[i\]\[i\]==11: Unknown$ +^\[main.assertion.49\] .* b\[j\]\[1\]==1: Unknown$ +^\[main.assertion.50\] .* b\[j\]\[1\]==11: Unknown$ +^\[main.assertion.51\] .* b\[1\]\[j\]==3: Unknown$ +^\[main.assertion.52\] .* b\[1\]\[j\]==11: Unknown$ +^\[main.assertion.53\] .* b\[j\]\[j\]==0: Unknown$ +^\[main.assertion.54\] .* b\[j\]\[j\]==11: Unknown$ +^\[main.assertion.55\] .* a\[100\]\[0\]==0: Unknown$ +^\[main.assertion.56\] .* a\[0\]\[100\]==0: Unknown$ +^\[main.assertion.57\] .* c==0: Success$ +^\[main.assertion.58\] .* c==0: Success$ +^\[main.assertion.59\] .* ei\[0\]\[1\]==1: Unknown$ +^\[main.assertion.60\] .* ei\[0\]\[1\]==0: Unknown$ +^\[main.assertion.61\] .* ei\[2\]\[1\]==0: Unknown$ +^\[main.assertion.62\] .* ei\[2\]\[1\]==1: Unknown$ +^\[main.assertion.63\] .* ej\[0\]\[1\]==0: Unknown$ +^\[main.assertion.64\] .* ej\[2\]\[1\]==0: Unknown$ +^\[main.assertion.65\] .* ek\[0\]\[1\]==0: Unknown$ +^\[main.assertion.66\] .* c==0: Success$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-two-value-array-of-two-value-pointer/test.desc b/regression/goto-analyzer/sensitivity-test-two-value-array-of-two-value-pointer/test.desc index f9de8e20a03..9b8416d3b37 100644 --- a/regression/goto-analyzer/sensitivity-test-two-value-array-of-two-value-pointer/test.desc +++ b/regression/goto-analyzer/sensitivity-test-two-value-array-of-two-value-pointer/test.desc @@ -1,71 +1,75 @@ -FUTURE +CORE sensitivity_test_two_value_array_of_two_value_pointer.c --variable --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion a\[1\]==&a0: Unknown$ -^\[main.assertion.2\] .* assertion a\[1\]==&a3: Unknown$ -^\[main.assertion.3\] .* assertion \*a\[1\]==0: Unknown$ -^\[main.assertion.4\] .* assertion \*a\[1\]==3: Unknown$ -^\[main.assertion.5\] .* assertion b\[1\]==&b1: Unknown$ -^\[main.assertion.6\] .* assertion b\[1\]==&b3: Unknown$ -^\[main.assertion.7\] .* assertion \*b\[1\]==11: Unknown$ -^\[main.assertion.8\] .* assertion \*b\[1\]==13: Unknown$ -^\[main.assertion.9\] .* assertion \*\(b\+1\)==&b1: Unknown$ -^\[main.assertion.10\] .* assertion \*\(b\+1\)==&b3: Unknown$ -^\[main.assertion.11\] .* assertion \*\(1\+b\)==&b1: Unknown$ -^\[main.assertion.12\] .* assertion \*\(1\+b\)==&b3: Unknown$ -^\[main.assertion.13\] .* assertion 1\[b\]==&b1: Unknown$ -^\[main.assertion.14\] .* assertion 1\[b\]==&b3: Unknown$ -^\[main.assertion.15\] .* assertion \*\*\(b\+1\)==11: Unknown$ -^\[main.assertion.16\] .* assertion \*\*\(b\+1\)==13: Unknown$ -^\[main.assertion.17\] .* assertion \*\*\(1\+b\)==11: Unknown$ -^\[main.assertion.18\] .* assertion \*\*\(1\+b\)==13: Unknown$ -^\[main.assertion.19\] .* assertion \*1\[b\]==11: Unknown$ -^\[main.assertion.20\] .* assertion \*1\[b\]==13: Unknown$ -^\[main.assertion.21\] .* assertion c\[0\]==&c0: Unknown$ -^\[main.assertion.22\] .* assertion c\[0\]==&c3: Unknown$ -^\[main.assertion.23\] .* assertion d\[0\]==&d0: Unknown$ -^\[main.assertion.24\] .* assertion d\[0\]==&d3: Unknown$ -^\[main.assertion.25\] .* assertion \*c\[0\]==20: Unknown$ -^\[main.assertion.26\] .* assertion \*c\[0\]==23: Unknown$ -^\[main.assertion.27\] .* assertion \*d\[0\]==30: Unknown$ -^\[main.assertion.28\] .* assertion \*d\[0\]==33: Unknown$ -^\[main.assertion.29\] .* assertion a\[i\]==&a0: Unknown$ -^\[main.assertion.30\] .* assertion a\[i\]==&a3: Unknown$ -^\[main.assertion.31\] .* assertion a\[j\]==&a0: Unknown$ -^\[main.assertion.32\] .* assertion a\[j\]==&a3: Unknown$ -^\[main.assertion.33\] .* assertion \*a\[i\]==0: Unknown$ -^\[main.assertion.34\] .* assertion \*a\[i\]==3: Unknown$ -^\[main.assertion.35\] .* assertion \*a\[j\]==0: Unknown$ -^\[main.assertion.36\] .* assertion \*a\[j\]==3: Unknown$ -^\[main.assertion.37\] .* assertion b\[i\]==&b0: Unknown$ -^\[main.assertion.38\] .* assertion b\[i\]==&b1: Unknown$ -^\[main.assertion.39\] .* assertion b\[j\]==&b0: Unknown$ -^\[main.assertion.40\] .* assertion b\[j\]==&b3: Unknown$ -^\[main.assertion.41\] .* assertion \*b\[i\]==10: Unknown$ -^\[main.assertion.42\] .* assertion \*b\[i\]==11: Unknown$ -^\[main.assertion.43\] .* assertion \*b\[j\]==10: Unknown$ -^\[main.assertion.44\] .* assertion \*b\[j\]==13: Unknown$ -^\[main.assertion.45\] .* assertion a\[100\]==&a2: Unknown$ -^\[main.assertion.46\] .* assertion \*a\[100\]==2: Unknown$ -^\[main.assertion.47\] .* assertion b\[1\]==&b1: Unknown$ -^\[main.assertion.48\] .* assertion \*b\[1\]==11: Unknown$ -^\[main.assertion.49\] .* assertion ei\[0\]==&ei1: Unknown$ -^\[main.assertion.50\] .* assertion ei\[0\]==&ei0: Unknown$ -^\[main.assertion.51\] .* assertion ei\[2\]==&ei0: Unknown$ -^\[main.assertion.52\] .* assertion ei\[2\]==&ei1: Unknown$ -^\[main.assertion.53\] .* assertion \*ei\[0\]==41: Unknown$ -^\[main.assertion.54\] .* assertion \*ei\[0\]==40: Unknown$ -^\[main.assertion.55\] .* assertion \*ei\[2\]==40: Unknown$ -^\[main.assertion.56\] .* assertion \*ei\[2\]==41: Unknown$ -^\[main.assertion.57\] .* assertion ej\[0\]==&ej0: Unknown$ -^\[main.assertion.58\] .* assertion ej\[2\]==&ej0: Unknown$ -^\[main.assertion.59\] .* assertion ej\[2\]==&ej1: Unknown$ -^\[main.assertion.60\] .* assertion \*ej\[0\]==50: Unknown$ -^\[main.assertion.61\] .* assertion \*ej\[2\]==50: Unknown$ -^\[main.assertion.62\] .* assertion \*ej\[2\]==51: Unknown$ -^\[main.assertion.63\] .* assertion ek\[0\]==&ek0: Unknown$ -^\[main.assertion.64\] .* assertion \*ek\[0\]==60: Unknown$ +^\[main.assertion.1\] .* a\[1\]==&a0: Unknown$ +^\[main.assertion.2\] .* a\[1\]==&a3: Unknown$ +^\[main.assertion.3\] .* \*a\[1\]==0: Unknown$ +^\[main.assertion.4\] .* \*a\[1\]==3: Unknown$ +^\[main.assertion.5\] .* b\[1\]==&b1: Unknown$ +^\[main.assertion.6\] .* b\[1\]==&b3: Unknown$ +^\[main.assertion.7\] .* \*b\[1\]==11: Unknown$ +^\[main.assertion.8\] .* \*b\[1\]==13: Unknown$ +^\[main.assertion.9\] .* \*\(b\+1\)==&b1: Unknown$ +^\[main.assertion.10\] .* \*\(b\+1\)==&b3: Unknown$ +^\[main.assertion.11\] .* \*\(1\+b\)==&b1: Unknown$ +^\[main.assertion.12\] .* \*\(1\+b\)==&b3: Unknown$ +^\[main.assertion.13\] .* 1\[b\]==&b1: Unknown$ +^\[main.assertion.14\] .* 1\[b\]==&b3: Unknown$ +^\[main.assertion.15\] .* \*\*\(b\+1\)==11: Unknown$ +^\[main.assertion.16\] .* \*\*\(b\+1\)==13: Unknown$ +^\[main.assertion.17\] .* \*\*\(1\+b\)==11: Unknown$ +^\[main.assertion.18\] .* \*\*\(1\+b\)==13: Unknown$ +^\[main.assertion.19\] .* \*1\[b\]==11: Unknown$ +^\[main.assertion.20\] .* \*1\[b\]==13: Unknown$ +^\[main.assertion.21\] .* c\[0\]==&c0: Unknown$ +^\[main.assertion.22\] .* c\[0\]==&c3: Unknown$ +^\[main.assertion.23\] .* d\[0\]==&d0: Unknown$ +^\[main.assertion.24\] .* d\[0\]==&d3: Unknown$ +^\[main.assertion.25\] .* \*c\[0\]==20: Unknown$ +^\[main.assertion.26\] .* \*c\[0\]==23: Unknown$ +^\[main.assertion.27\] .* \*d\[0\]==30: Unknown$ +^\[main.assertion.28\] .* \*d\[0\]==33: Unknown$ +^\[main.assertion.29\] .* a\[i\]==&a0: Unknown$ +^\[main.assertion.30\] .* a\[i\]==&a3: Unknown$ +^\[main.assertion.31\] .* a\[j\]==&a0: Unknown$ +^\[main.assertion.32\] .* a\[j\]==&a3: Unknown$ +^\[main.assertion.33\] .* \*a\[i\]==0: Unknown$ +^\[main.assertion.34\] .* \*a\[i\]==3: Unknown$ +^\[main.assertion.35\] .* \*a\[j\]==0: Unknown$ +^\[main.assertion.36\] .* \*a\[j\]==3: Unknown$ +^\[main.assertion.37\] .* b\[i\]==&b0: Unknown$ +^\[main.assertion.38\] .* b\[i\]==&b1: Unknown$ +^\[main.assertion.39\] .* b\[j\]==&b0: Unknown$ +^\[main.assertion.40\] .* b\[j\]==&b3: Unknown$ +^\[main.assertion.41\] .* \*b\[i\]==10: Unknown$ +^\[main.assertion.42\] .* \*b\[i\]==11: Unknown$ +^\[main.assertion.43\] .* \*b\[j\]==10: Unknown$ +^\[main.assertion.44\] .* \*b\[j\]==13: Unknown$ +^\[main.assertion.45\] .* a\[100\]==&a2: Unknown$ +^\[main.assertion.46\] .* \*a\[100\]==2: Unknown$ +^\[main.assertion.47\] .* b\[1\]==&b1: Unknown$ +^\[main.assertion.48\] .* \*b\[1\]==11: Unknown$ +^\[main.assertion.49\] .* ei\[0\]==&ei1: Unknown$ +^\[main.assertion.50\] .* ei\[0\]==&ei0: Unknown$ +^\[main.assertion.51\] .* ei\[2\]==&ei0: Unknown$ +^\[main.assertion.52\] .* ei\[2\]==&ei1: Unknown$ +^\[main.assertion.53\] .* \*ei\[0\]==41: Unknown$ +^\[main.assertion.54\] .* \*ei\[0\]==40: Unknown$ +^\[main.assertion.55\] .* \*ei\[2\]==40: Unknown$ +^\[main.assertion.56\] .* \*ei\[2\]==41: Unknown$ +^\[main.assertion.57\] .* ej\[0\]==&ej0: Unknown$ +^\[main.assertion.58\] .* ej\[2\]==&ej0: Unknown$ +^\[main.assertion.59\] .* ej\[2\]==&ej1: Unknown$ +^\[main.assertion.60\] .* \*ej\[0\]==50: Unknown$ +^\[main.assertion.61\] .* \*ej\[2\]==50: Unknown$ +^\[main.assertion.62\] .* \*ej\[2\]==51: Unknown$ +^\[main.assertion.63\] .* ek\[0\]==&ek0: Unknown$ +^\[main.assertion.64\] .* \*ek\[0\]==60: Unknown$ +^\[main\.assertion\.65\] .* \*ps\[0\]==4: Unknown$ +^\[main\.assertion\.66\] .* \*ps\[1\]==4: Unknown$ +^\[main\.assertion\.67\] .* x==4: Success$ +^\[main\.assertion\.68\] .* y==4: Failure \(if reachable\)$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-two-value-array/test.desc b/regression/goto-analyzer/sensitivity-test-two-value-array/test.desc index 23ee78bd74f..c7daafa0c23 100644 --- a/regression/goto-analyzer/sensitivity-test-two-value-array/test.desc +++ b/regression/goto-analyzer/sensitivity-test-two-value-array/test.desc @@ -1,39 +1,39 @@ -FUTURE +CORE sensitivity_test_two_value_array.c --variable --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion a\[1\]==0: Unknown$ -^\[main.assertion.2\] .* assertion a\[1\]==1: Unknown$ -^\[main.assertion.3\] .* assertion b\[1\]==0: Unknown$ -^\[main.assertion.4\] .* assertion b\[1\]==1: Unknown$ -^\[main.assertion.5\] .* assertion \*\(b\+1\)==0: Unknown$ -^\[main.assertion.6\] .* assertion \*\(b\+1\)==1: Unknown$ -^\[main.assertion.7\] .* assertion \*\(1\+b\)==0: Unknown$ -^\[main.assertion.8\] .* assertion \*\(1\+b\)==1: Unknown$ -^\[main.assertion.9\] .* assertion 1\[b\]==0: Unknown$ -^\[main.assertion.10\] .* assertion 1\[b\]==1: Unknown$ -^\[main.assertion.11\] .* assertion c\[0\]==0: Unknown$ -^\[main.assertion.12\] .* assertion c\[0\]==1: Unknown$ -^\[main.assertion.13\] .* assertion d\[0\]==0: Unknown$ -^\[main.assertion.14\] .* assertion d\[0\]==2: Unknown$ -^\[main.assertion.15\] .* assertion d\[1\]==0: Unknown$ -^\[main.assertion.16\] .* assertion a\[i\]==0: Unknown$ -^\[main.assertion.17\] .* assertion a\[i\]==1: Unknown$ -^\[main.assertion.18\] .* assertion a\[j\]==0: Unknown$ -^\[main.assertion.19\] .* assertion a\[j\]==1: Unknown$ -^\[main.assertion.20\] .* assertion b\[i\]==1: Unknown$ -^\[main.assertion.21\] .* assertion b\[i\]==0: Unknown$ -^\[main.assertion.22\] .* assertion b\[j\]==0: Unknown$ -^\[main.assertion.23\] .* assertion b\[j\]==1: Unknown$ -^\[main.assertion.24\] .* assertion a\[100\]==0: Unknown$ -^\[main.assertion.25\] .* assertion b\[1\]==0: Unknown$ -^\[main.assertion.26\] .* assertion ei\[0\]==1: Unknown$ -^\[main.assertion.27\] .* assertion ei\[0\]==0: Unknown$ -^\[main.assertion.28\] .* assertion ei\[2\]==0: Unknown$ -^\[main.assertion.29\] .* assertion ei\[2\]==1: Unknown$ -^\[main.assertion.30\] .* assertion ej\[0\]==0: Unknown$ -^\[main.assertion.31\] .* assertion ej\[2\]==0: Unknown$ -^\[main.assertion.32\] .* assertion ek\[0\]==0: Unknown$ +^\[main.assertion.1\] .* a\[1\]==0: Unknown$ +^\[main.assertion.2\] .* a\[1\]==1: Unknown$ +^\[main.assertion.3\] .* b\[1\]==0: Unknown$ +^\[main.assertion.4\] .* b\[1\]==1: Unknown$ +^\[main.assertion.5\] .* \*\(b\+1\)==0: Unknown$ +^\[main.assertion.6\] .* \*\(b\+1\)==1: Unknown$ +^\[main.assertion.7\] .* \*\(1\+b\)==0: Unknown$ +^\[main.assertion.8\] .* \*\(1\+b\)==1: Unknown$ +^\[main.assertion.9\] .* 1\[b\]==0: Unknown$ +^\[main.assertion.10\] .* 1\[b\]==1: Unknown$ +^\[main.assertion.11\] .* c\[0\]==0: Unknown$ +^\[main.assertion.12\] .* c\[0\]==1: Unknown$ +^\[main.assertion.13\] .* d\[0\]==0: Unknown$ +^\[main.assertion.14\] .* d\[0\]==2: Unknown$ +^\[main.assertion.15\] .* d\[1\]==0: Unknown$ +^\[main.assertion.16\] .* a\[i\]==0: Unknown$ +^\[main.assertion.17\] .* a\[i\]==1: Unknown$ +^\[main.assertion.18\] .* a\[j\]==0: Unknown$ +^\[main.assertion.19\] .* a\[j\]==1: Unknown$ +^\[main.assertion.20\] .* b\[i\]==1: Unknown$ +^\[main.assertion.21\] .* b\[i\]==0: Unknown$ +^\[main.assertion.22\] .* b\[j\]==0: Unknown$ +^\[main.assertion.23\] .* b\[j\]==1: Unknown$ +^\[main.assertion.24\] .* a\[100\]==0: Unknown$ +^\[main.assertion.25\] .* b\[1\]==0: Unknown$ +^\[main.assertion.26\] .* ei\[0\]==1: Unknown$ +^\[main.assertion.27\] .* ei\[0\]==0: Unknown$ +^\[main.assertion.28\] .* ei\[2\]==0: Unknown$ +^\[main.assertion.29\] .* ei\[2\]==1: Unknown$ +^\[main.assertion.30\] .* ej\[0\]==0: Unknown$ +^\[main.assertion.31\] .* ej\[2\]==0: Unknown$ +^\[main.assertion.32\] .* ek\[0\]==0: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-two-value-pointer-to-two-value-array/test.desc b/regression/goto-analyzer/sensitivity-test-two-value-pointer-to-two-value-array/test.desc index 974705f9fc1..4a96ad8909c 100644 --- a/regression/goto-analyzer/sensitivity-test-two-value-pointer-to-two-value-array/test.desc +++ b/regression/goto-analyzer/sensitivity-test-two-value-pointer-to-two-value-array/test.desc @@ -1,21 +1,29 @@ -FUTURE +CORE sensitivity_test_two_value_pointer_to_two_value_array.c --variable --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion p==&a\[0\]: Unknown$ -^\[main.assertion.2\] .* assertion \*p==1: Unknown$ -^\[main.assertion.3\] .* assertion q==p\+1: Unknown$ -^\[main.assertion.4\] .* assertion \*q==2: Unknown$ -^\[main.assertion.5\] .* assertion q-p==x: Unknown$ -^\[main.assertion.6\] .* assertion a\[1\]==4: Unknown$ -^\[main.assertion.7\] .* assertion \*r==2: Unknown$ -^\[main.assertion.8\] .* assertion \*r==1: Unknown$ -^\[main.assertion.9\] .* assertion \*s==0: Unknown$ -^\[main.assertion.10\] .* assertion \*s==1: Unknown$ -^\[main.assertion.11\] .* assertion t==p\+i: Unknown$ -^\[main.assertion.12\] .* assertion t-p==y: Unknown$ -^\[main.assertion.13\] .* assertion a\[i\]==5: Unknown$ -^\[main.assertion.14\] .* assertion a\[1\]==5: Unknown$ +^\[main\.assertion\.1\] .* p==&a\[0\]: Unknown$ +^\[main\.assertion\.2\] .* \*p==1: Unknown$ +^\[main\.assertion\.3\] .* p\[1\]==2: Unknown$ +^\[main\.assertion\.4\] .* 1\[p\]==2: Unknown$ +^\[main\.assertion\.5\] .* \*\(p\+1\)==2: Unknown$ +^\[main\.assertion\.6\] .* \*\(1\+p\)==2: Unknown$ +^\[main\.assertion\.7\] .* \*\(p-1\)==1: Unknown$ +^\[main\.assertion\.8\] .* q==p\+1: Unknown$ +^\[main\.assertion\.9\] .* \*q==2: Unknown$ +^\[main\.assertion\.10\] .* q-p==x: Unknown$ +^\[main\.assertion\.11\] .* a\[1\]==4: Unknown$ +^\[main\.assertion\.12\] .* a\[1\]==5: Unknown$ +^\[main\.assertion\.13\] .* a\[1\]==6: Unknown$ +^\[main\.assertion\.14\] .* a\[1\]==7: Unknown$ +^\[main\.assertion\.15\] .* \*r==2: Unknown$ +^\[main\.assertion\.16\] .* \*r==1: Unknown$ +^\[main\.assertion\.17\] .* \*s==0: Unknown$ +^\[main\.assertion\.18\] .* \*s==1: Unknown$ +^\[main\.assertion\.19\] .* t==p\+i: Unknown$ +^\[main\.assertion\.20\] .* t-p==y: Unknown$ +^\[main\.assertion\.21\] .* a\[i\]==5: Unknown$ +^\[main\.assertion\.22\] .* a\[1\]==5: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-two-value-pointer-to-two-value-pointer/test.desc b/regression/goto-analyzer/sensitivity-test-two-value-pointer-to-two-value-pointer/test.desc index e3582834688..1b6643766e9 100644 --- a/regression/goto-analyzer/sensitivity-test-two-value-pointer-to-two-value-pointer/test.desc +++ b/regression/goto-analyzer/sensitivity-test-two-value-pointer-to-two-value-pointer/test.desc @@ -1,13 +1,13 @@ -FUTURE +CORE sensitivity_test_two_value_pointer_to_two_value_pointer.c --variable --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion \*\*x==0: Unknown$ -^\[main.assertion.2\] .* assertion \*\*x==1: Unknown$ -^\[main.assertion.3\] .* assertion \*\*x==1: Unknown$ -^\[main.assertion.4\] .* assertion \*\*x==0: Unknown$ -^\[main.assertion.5\] .* assertion a==2: Unknown$ -^\[main.assertion.6\] .* assertion a==1: Unknown$ +^\[main.assertion.1\] .* \*\*x==0: Unknown$ +^\[main.assertion.2\] .* \*\*x==1: Unknown$ +^\[main.assertion.3\] .* \*\*x==1: Unknown$ +^\[main.assertion.4\] .* \*\*x==0: Unknown$ +^\[main.assertion.5\] .* a==2: Unknown$ +^\[main.assertion.6\] .* a==1: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-two-value-pointer-to-two-value-struct/test.desc b/regression/goto-analyzer/sensitivity-test-two-value-pointer-to-two-value-struct/test.desc index 56a0be48407..57b974c1619 100644 --- a/regression/goto-analyzer/sensitivity-test-two-value-pointer-to-two-value-struct/test.desc +++ b/regression/goto-analyzer/sensitivity-test-two-value-pointer-to-two-value-struct/test.desc @@ -1,13 +1,13 @@ -FUTURE +CORE sensitivity_test_two_value_pointer_to_two_value_struct.c --variable --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion \(\*p\).a==0: Unknown$ -^\[main.assertion.2\] .* assertion \(\*p\).a==1: Unknown$ -^\[main.assertion.3\] .* assertion p->a==0: Unknown$ -^\[main.assertion.4\] .* assertion p->a==1: Unknown$ -^\[main.assertion.5\] .* assertion p->b==2.0: Unknown$ -^\[main.assertion.6\] .* assertion p->b==1.0: Unknown$ +^\[main.assertion.1\] .* \(\*p\).a==0: Unknown$ +^\[main.assertion.2\] .* \(\*p\).a==1: Unknown$ +^\[main.assertion.3\] .* p->a==0: Unknown$ +^\[main.assertion.4\] .* p->a==1: Unknown$ +^\[main.assertion.5\] .* p->b==2.0: Unknown$ +^\[main.assertion.6\] .* p->b==1.0: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-two-value-pointer/test.desc b/regression/goto-analyzer/sensitivity-test-two-value-pointer/test.desc index da9abe2464f..f55b2fae94d 100644 --- a/regression/goto-analyzer/sensitivity-test-two-value-pointer/test.desc +++ b/regression/goto-analyzer/sensitivity-test-two-value-pointer/test.desc @@ -1,21 +1,21 @@ -FUTURE +CORE sensitivity_test_two_value_pointer.c --variable --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion x==&a: Unknown$ -^\[main.assertion.2\] .* assertion x==&b: Unknown$ -^\[main.assertion.3\] .* assertion x==x2: Unknown$ -^\[main.assertion.4\] .* assertion x==y: Unknown$ -^\[main.assertion.5\] .* assertion \*x==0: Unknown$ -^\[main.assertion.6\] .* assertion \*x==1: Unknown$ -^\[main.assertion.7\] .* assertion \*x==1: Unknown$ -^\[main.assertion.8\] .* assertion \*x==0: Unknown$ -^\[main.assertion.9\] .* assertion a==2: Unknown$ -^\[main.assertion.10\] .* assertion a==0: Unknown$ -^\[main.assertion.11\] .* assertion x==&a: Unknown$ -^\[main.assertion.12\] .* assertion \*x==0: Unknown$ -^\[main.assertion.13\] .* assertion x==&a: Unknown$ -^\[main.assertion.14\] .* assertion x==&b: Unknown$ +^\[main.assertion.1\] .* x==&a: Unknown$ +^\[main.assertion.2\] .* x==&b: Unknown$ +^\[main.assertion.3\] .* x==x2: Unknown$ +^\[main.assertion.4\] .* x==y: Unknown$ +^\[main.assertion.5\] .* \*x==0: Unknown$ +^\[main.assertion.6\] .* \*x==1: Unknown$ +^\[main.assertion.7\] .* \*x==1: Unknown$ +^\[main.assertion.8\] .* \*x==0: Unknown$ +^\[main.assertion.9\] .* a==2: Unknown$ +^\[main.assertion.10\] .* a==0: Unknown$ +^\[main.assertion.11\] .* x==&a: Unknown$ +^\[main.assertion.12\] .* \*x==0: Unknown$ +^\[main.assertion.13\] .* x==&a: Unknown$ +^\[main.assertion.14\] .* x==&b: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-two-value-struct-of-two-value-array/test.desc b/regression/goto-analyzer/sensitivity-test-two-value-struct-of-two-value-array/test.desc index e8773cf68fc..66350a644c7 100644 --- a/regression/goto-analyzer/sensitivity-test-two-value-struct-of-two-value-array/test.desc +++ b/regression/goto-analyzer/sensitivity-test-two-value-struct-of-two-value-array/test.desc @@ -1,24 +1,24 @@ -FUTURE +CORE sensitivity_test_two_value_struct_of_two_value_array.c --variable --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion x.a\[0\]==0: Unknown$ -^\[main.assertion.2\] .* assertion \*\(x.a\+0\)==0: Unknown$ -^\[main.assertion.3\] .* assertion \*\(0\+x.a\)==0: Unknown$ -^\[main.assertion.4\] .* assertion 0\[x.a\]==0: Unknown$ -^\[main.assertion.5\] .* assertion x.a\[0\]==0: Unknown$ -^\[main.assertion.6\] .* assertion x.a\[1\]==1: Unknown$ -^\[main.assertion.7\] .* assertion x.b\[0\]==3.0f: Unknown$ -^\[main.assertion.8\] .* assertion x.a\[0\]==0: Unknown$ -^\[main.assertion.9\] .* assertion x.a\[1\]==1: Unknown$ -^\[main.assertion.10\] .* assertion x.b\[2\]>0.0f: Unknown$ -^\[main.assertion.11\] .* assertion x.b\[2\]==15.0f: Unknown$ -^\[main.assertion.12\] .* assertion x.b\[2\]==1.0f: Unknown$ -^\[main.assertion.13\] .* assertion x.b\[0\]==3.0f: Unknown$ -^\[main.assertion.14\] .* assertion x.a\[0\]<12: Unknown$ -^\[main.assertion.15\] .* assertion x.a\[0\]>2: Unknown$ -^\[main.assertion.16\] .* assertion x.a\[0\]==0: Unknown$ -^\[main.assertion.17\] .* assertion x.a\[1\]==1: Unknown$ +^\[main.assertion.1\] .* x.a\[0\]==0: Unknown$ +^\[main.assertion.2\] .* \*\(x.a\+0\)==0: Unknown$ +^\[main.assertion.3\] .* \*\(0\+x.a\)==0: Unknown$ +^\[main.assertion.4\] .* 0\[x.a\]==0: Unknown$ +^\[main.assertion.5\] .* x.a\[0\]==0: Unknown$ +^\[main.assertion.6\] .* x.a\[1\]==1: Unknown$ +^\[main.assertion.7\] .* x.b\[0\]==3.0f: Unknown$ +^\[main.assertion.8\] .* x.a\[0\]==0: Unknown$ +^\[main.assertion.9\] .* x.a\[1\]==1: Unknown$ +^\[main.assertion.10\] .* x.b\[2\]>0.0f: Unknown$ +^\[main.assertion.11\] .* x.b\[2\]==15.0f: Unknown$ +^\[main.assertion.12\] .* x.b\[2\]==1.0f: Unknown$ +^\[main.assertion.13\] .* x.b\[0\]==3.0f: Unknown$ +^\[main.assertion.14\] .* x.a\[0\]<12: Unknown$ +^\[main.assertion.15\] .* x.a\[0\]>2: Unknown$ +^\[main.assertion.16\] .* x.a\[0\]==0: Unknown$ +^\[main.assertion.17\] .* x.a\[1\]==1: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-two-value-struct-of-two-value-pointer/test.desc b/regression/goto-analyzer/sensitivity-test-two-value-struct-of-two-value-pointer/test.desc index 06ebb29d047..054effb0edb 100644 --- a/regression/goto-analyzer/sensitivity-test-two-value-struct-of-two-value-pointer/test.desc +++ b/regression/goto-analyzer/sensitivity-test-two-value-struct-of-two-value-pointer/test.desc @@ -1,33 +1,33 @@ -FUTURE +CORE sensitivity_test_two_value_struct_of_two_value_pointer.c --variable --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion x.a==&a1: Unknown$ -^\[main.assertion.2\] .* assertion x.a==&a2: Unknown$ -^\[main.assertion.3\] .* assertion x.b==&b1: Unknown$ -^\[main.assertion.4\] .* assertion x.b==&b2: Unknown$ -^\[main.assertion.5\] .* assertion \*x.a==0: Unknown$ -^\[main.assertion.6\] .* assertion \*x.a==100: Unknown$ -^\[main.assertion.7\] .* assertion \*x.b==10.0f: Unknown$ -^\[main.assertion.8\] .* assertion \*x.b==110.0f: Unknown$ -^\[main.assertion.9\] .* assertion x.a==&a1: Unknown$ -^\[main.assertion.10\] .* assertion x.a==&a2: Unknown$ -^\[main.assertion.11\] .* assertion \*x.a==0: Unknown$ -^\[main.assertion.12\] .* assertion \*x.a==100: Unknown$ -^\[main.assertion.13\] .* assertion x.a==&a1: Unknown$ -^\[main.assertion.14\] .* assertion x.b==&b2: Unknown$ -^\[main.assertion.15\] .* assertion x.b==&b3: Unknown$ -^\[main.assertion.16\] .* assertion \*x.a==0: Unknown$ -^\[main.assertion.17\] .* assertion \*x.b==11.0f: Unknown$ -^\[main.assertion.18\] .* assertion \*x.b==12.0f: Unknown$ -^\[main.assertion.19\] .* assertion x.a==&a2: Unknown$ -^\[main.assertion.20\] .* assertion x.a==&a3: Unknown$ -^\[main.assertion.21\] .* assertion x.b==&b3: Unknown$ -^\[main.assertion.22\] .* assertion x.b==&b4: Unknown$ -^\[main.assertion.23\] .* assertion \*x.a==1: Unknown$ -^\[main.assertion.24\] .* assertion \*x.a==2: Unknown$ -^\[main.assertion.25\] .* assertion \*x.b==12.0f: Unknown$ -^\[main.assertion.26\] .* assertion \*x.b==13.0f: Unknown$ +^\[main.assertion.1\] .* x.a==&a1: Unknown$ +^\[main.assertion.2\] .* x.a==&a2: Unknown$ +^\[main.assertion.3\] .* x.b==&b1: Unknown$ +^\[main.assertion.4\] .* x.b==&b2: Unknown$ +^\[main.assertion.5\] .* \*x.a==0: Unknown$ +^\[main.assertion.6\] .* \*x.a==100: Unknown$ +^\[main.assertion.7\] .* \*x.b==10.0f: Unknown$ +^\[main.assertion.8\] .* \*x.b==110.0f: Unknown$ +^\[main.assertion.9\] .* x.a==&a1: Unknown$ +^\[main.assertion.10\] .* x.a==&a2: Unknown$ +^\[main.assertion.11\] .* \*x.a==0: Unknown$ +^\[main.assertion.12\] .* \*x.a==100: Unknown$ +^\[main.assertion.13\] .* x.a==&a1: Unknown$ +^\[main.assertion.14\] .* x.b==&b2: Unknown$ +^\[main.assertion.15\] .* x.b==&b3: Unknown$ +^\[main.assertion.16\] .* \*x.a==0: Unknown$ +^\[main.assertion.17\] .* \*x.b==11.0f: Unknown$ +^\[main.assertion.18\] .* \*x.b==12.0f: Unknown$ +^\[main.assertion.19\] .* x.a==&a2: Unknown$ +^\[main.assertion.20\] .* x.a==&a3: Unknown$ +^\[main.assertion.21\] .* x.b==&b3: Unknown$ +^\[main.assertion.22\] .* x.b==&b4: Unknown$ +^\[main.assertion.23\] .* \*x.a==1: Unknown$ +^\[main.assertion.24\] .* \*x.a==2: Unknown$ +^\[main.assertion.25\] .* \*x.b==12.0f: Unknown$ +^\[main.assertion.26\] .* \*x.b==13.0f: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-two-value-struct-of-two-value-struct/test.desc b/regression/goto-analyzer/sensitivity-test-two-value-struct-of-two-value-struct/test.desc index 450055d2be6..6d9cd97289c 100644 --- a/regression/goto-analyzer/sensitivity-test-two-value-struct-of-two-value-struct/test.desc +++ b/regression/goto-analyzer/sensitivity-test-two-value-struct-of-two-value-struct/test.desc @@ -1,18 +1,18 @@ -FUTURE +CORE sensitivity_test_two_value_struct_of_two_value_struct.c --variable --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion x.s1.a==0: Unknown$ -^\[main.assertion.2\] .* assertion x.s2.b==3.0f: Unknown$ -^\[main.assertion.3\] .* assertion x.s1.a==0: Unknown$ -^\[main.assertion.4\] .* assertion x.s1.a==10: Unknown$ -^\[main.assertion.5\] .* assertion x.s1.b==1.0f: Unknown$ -^\[main.assertion.6\] .* assertion x.s2.b==3.0f: Unknown$ -^\[main.assertion.7\] .* assertion x.s2.b==0.0f: Unknown$ -^\[main.assertion.8\] .* assertion x.s1.a==20: Unknown$ -^\[main.assertion.9\] .* assertion x.s1.a<30: Unknown$ -^\[main.assertion.10\] .* assertion x.s2.a==22: Unknown$ -^\[main.assertion.11\] .* assertion x.s2.a<30: Unknown$ +^\[main.assertion.1\] .* x.s1.a==0: Unknown$ +^\[main.assertion.2\] .* x.s2.b==3.0f: Unknown$ +^\[main.assertion.3\] .* x.s1.a==0: Unknown$ +^\[main.assertion.4\] .* x.s1.a==10: Unknown$ +^\[main.assertion.5\] .* x.s1.b==1.0f: Unknown$ +^\[main.assertion.6\] .* x.s2.b==3.0f: Unknown$ +^\[main.assertion.7\] .* x.s2.b==0.0f: Unknown$ +^\[main.assertion.8\] .* x.s1.a==20: Unknown$ +^\[main.assertion.9\] .* x.s1.a<30: Unknown$ +^\[main.assertion.10\] .* x.s2.a==22: Unknown$ +^\[main.assertion.11\] .* x.s2.a<30: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/sensitivity-test-two-value-struct/test.desc b/regression/goto-analyzer/sensitivity-test-two-value-struct/test.desc index 157a3b25968..962873ac044 100644 --- a/regression/goto-analyzer/sensitivity-test-two-value-struct/test.desc +++ b/regression/goto-analyzer/sensitivity-test-two-value-struct/test.desc @@ -1,16 +1,16 @@ -FUTURE +CORE sensitivity_test_two_value_struct.c --variable --verify ^EXIT=0$ ^SIGNAL=0$ -^\[main.assertion.1\] .* assertion x.a==0: Unknown$ -^\[main.assertion.2\] .* assertion x.a==1: Unknown$ -^\[main.assertion.3\] .* assertion x.a==0: Unknown$ -^\[main.assertion.4\] .* assertion x.a==0: Unknown$ -^\[main.assertion.5\] .* assertion x.b>0.0f: Unknown$ -^\[main.assertion.6\] .* assertion x.b==1.0f: Unknown$ -^\[main.assertion.7\] .* assertion x.a<2: Unknown$ -^\[main.assertion.8\] .* assertion x.a>2: Unknown$ -^\[main.assertion.9\] .* assertion x.a==1: Unknown$ +^\[main.assertion.1\] .* x.a==0: Unknown$ +^\[main.assertion.2\] .* x.a==1: Unknown$ +^\[main.assertion.3\] .* x.a==0: Unknown$ +^\[main.assertion.4\] .* x.a==0: Unknown$ +^\[main.assertion.5\] .* x.b>0.0f: Unknown$ +^\[main.assertion.6\] .* x.b==1.0f: Unknown$ +^\[main.assertion.7\] .* x.a<2: Unknown$ +^\[main.assertion.8\] .* x.a>2: Unknown$ +^\[main.assertion.9\] .* x.a==1: Unknown$ -- ^warning: ignoring diff --git a/regression/goto-analyzer/unreachable_assertions_01/main.c b/regression/goto-analyzer/unreachable_assertions_01/main.c new file mode 100644 index 00000000000..d89733963f7 --- /dev/null +++ b/regression/goto-analyzer/unreachable_assertions_01/main.c @@ -0,0 +1,28 @@ +#include + +int nondet_int (void); + +int main (int argc, char **argv) +{ + int a = 1; + int b = 2; + int x = nondet_int(); + int y = nondet_int(); + + if (a == b) + __CPROVER_assert(0, "0"); // Trivial false + + if (a == b) + __CPROVER_assert(1, "1"); // Trivial true + + if (a == b) + __CPROVER_assert(x == y, "x == y"); // Undetermined + + if (a == b) + __CPROVER_assert(!(x == y) || (x + 1 + a == b + y), "!(x == y) || (x + 1 + a == b + y)"); // Non-trivial true + + if (a == b) + __CPROVER_assert(!(!(x == y) || (x + 1 + a == b + y)), "!(!(x == y) || (x + 1 + a == b + y)"); // Non-trivial false + + return 0; +} diff --git a/regression/goto-analyzer/unreachable_assertions_01/test.desc b/regression/goto-analyzer/unreachable_assertions_01/test.desc new file mode 100644 index 00000000000..2125fa276e1 --- /dev/null +++ b/regression/goto-analyzer/unreachable_assertions_01/test.desc @@ -0,0 +1,12 @@ +CORE +main.c +--verify --variable +^\[main\.assertion\.1\] .* 0: Success \(unreachable\)$ +^\[main\.assertion\.2\] .* 1: Success \(unreachable\)$ +^\[main\.assertion\.3\] .* x == y: Success \(unreachable\)$ +^\[main\.assertion\.4\] .* !\(x == y\) || \(x + 1 + a == b + y\): Success \(unreachable\)$ +^\[main\.assertion\.5\] .* !\(!\(x == y\) || \(x + 1 + a == b + y\)\): Success \(unreachable\)$ +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring diff --git a/src/analyses/Makefile b/src/analyses/Makefile index 690b119e83c..d2b31e8838a 100644 --- a/src/analyses/Makefile +++ b/src/analyses/Makefile @@ -22,9 +22,20 @@ SRC = ai.cpp \ locals.cpp \ natural_loops.cpp \ reaching_definitions.cpp \ - replace_symbol_ext.cpp \ static_analysis.cpp \ uninitialized_domain.cpp \ + variable-sensitivity/abstract_object.cpp \ + variable-sensitivity/abstract_enviroment.cpp \ + variable-sensitivity/abstract_value.cpp \ + variable-sensitivity/array_abstract_object.cpp \ + variable-sensitivity/constant_abstract_value.cpp \ + variable-sensitivity/constant_pointer_abstract_object.cpp \ + variable-sensitivity/pointer_abstract_object.cpp \ + variable-sensitivity/struct_abstract_object.cpp \ + variable-sensitivity/variable_sensitivity_domain.cpp \ + variable-sensitivity/variable_sensitivity_object_factory.cpp \ + variable-sensitivity/full_struct_abstract_object.cpp \ + variable-sensitivity/constant_array_abstract_object.cpp \ # Empty last line INCLUDES= -I .. diff --git a/src/analyses/ai.cpp b/src/analyses/ai.cpp index 45d4b83c92c..36991b63c96 100644 --- a/src/analyses/ai.cpp +++ b/src/analyses/ai.cpp @@ -8,6 +8,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include #include #include @@ -18,6 +19,51 @@ Author: Daniel Kroening, kroening@kroening.com /*******************************************************************\ +Function: ai_domain_baset::output_json + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +jsont ai_domain_baset::output_json( + const ai_baset &ai, + const namespacet &ns) const +{ + std::ostringstream out; + output(out, ai, ns); + json_stringt json(out.str()); + return json; +} + +/*******************************************************************\ + +Function: ai_domain_baset::output_xml + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +xmlt ai_domain_baset::output_xml( + const ai_baset &ai, + const namespacet &ns) const +{ + std::ostringstream out; + output(out, ai, ns); + xmlt xml("abstract_state"); + xml.data=out.str(); + return xml; +} + +/*******************************************************************\ + Function: ai_baset::output Inputs: @@ -139,7 +185,7 @@ jsont ai_baset::output_json( json_numbert(std::to_string(i_it->location_number)); location["sourceLocation"]= json_stringt(i_it->source_location.as_string()); - location["domain"]=find_state(i_it).output_json(*this, ns); + location["abstractState"]=find_state(i_it).output_json(*this, ns); // Ideally we need output_instruction_json std::ostringstream out; @@ -526,7 +572,12 @@ bool ai_baset::do_function_call( assert(l_end->is_end_function()); // do edge from end of function to instruction after call - std::unique_ptr tmp_state(make_temporary_state(get_state(l_end))); + const statet &end_state=get_state(l_end); + + if(end_state.is_bottom()) + return false; // function exit point not reachable + + std::unique_ptr tmp_state(make_temporary_state(end_state)); tmp_state->transform(l_end, l_return, *this, ns); // Propagate those diff --git a/src/analyses/ai.h b/src/analyses/ai.h index 2894cde3b10..d7393c8d9ef 100644 --- a/src/analyses/ai.h +++ b/src/analyses/ai.h @@ -11,10 +11,10 @@ Author: Daniel Kroening, kroening@kroening.com #include #include -#include #include #include +#include #include @@ -40,9 +40,9 @@ class ai_domain_baset // how function calls are treated: // a) there is an edge from each call site to the function head - // b) there is an edge from the last instruction (END_FUNCTION) - // of the function to the instruction _following_ the call site - // (this also needs to set the LHS, if applicable) + // b) there is an edge from the last instruction (END_FUNCTION) of + // the function to the instruction _following_ the call site (this + // also needs to set the LHS, if applicable) virtual void transform( locationt from, @@ -59,24 +59,11 @@ class ai_domain_baset virtual jsont output_json( const ai_baset &ai, - const namespacet &ns) const - { - std::ostringstream out; - output(out, ai, ns); - json_stringt json(out.str()); - return json; - } + const namespacet &ns) const; virtual xmlt output_xml( const ai_baset &ai, - const namespacet &ns) const - { - std::ostringstream out; - output(out, ai, ns); - xmlt xml("domain"); - xml.data=out.str(); - return xml; - } + const namespacet &ns) const; // no states virtual void make_bottom()=0; @@ -88,12 +75,31 @@ class ai_domain_baset // a reasonable entry-point state virtual void make_entry()=0; + virtual bool is_bottom() const=0; + + // the analysis doesn't use this, + // and domains may refuse to implement it. + virtual bool is_top() const=0; + // also add // // bool merge(const T &b, locationt from, locationt to); // // This computes the join between "this" and "b". // Return true if "this" has changed. + + // This method allows an expression to be simplified / evaluated using the + // current state. It is used to evaluate assertions and in program + // simplification + + // return true if unchanged + virtual bool ai_simplify( + exprt &condition, + const namespacet &ns, + const bool lhs=false) const + { + return true; + } }; // don't use me -- I am just a base class @@ -208,7 +214,6 @@ class ai_baset return output_json(ns, goto_function.body, ""); } - virtual xmlt output_xml( const namespacet &ns, const goto_functionst &goto_functions) const; diff --git a/src/analyses/constant_propagator.cpp b/src/analyses/constant_propagator.cpp index 6735d558cc3..81d3fbb062c 100644 --- a/src/analyses/constant_propagator.cpp +++ b/src/analyses/constant_propagator.cpp @@ -1,6 +1,6 @@ /*******************************************************************\ -Module: Constant Propagation +Module: Constant propagation Author: Peter Schrammel @@ -13,66 +13,12 @@ Author: Peter Schrammel #include #include #include +#include #include "constant_propagator.h" /*******************************************************************\ -Function: concatenate_array_id - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -exprt concatenate_array_id( - const exprt &array, const exprt &index, - const typet &type) -{ - std::string a, idx, identifier; - a = array.get_string(ID_identifier); - - if (index.id()==ID_typecast) - idx = index.op0().get_string(ID_value); - else - idx = index.get_string(ID_value); - - mp_integer i=string2integer(idx); - identifier=a+"["+integer2string(i)+"]"; - symbol_exprt new_expr(identifier, type); - - return new_expr; -} - -/*******************************************************************\ - -Function: concatenate_array_id - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -exprt concatenate_array_id( - const exprt &array, const mp_integer &index, - const typet &type) -{ - std::string a, identifier; - a = array.get_string(ID_identifier); - identifier=a+"["+integer2string(index)+"]"; - symbol_exprt new_expr(identifier, type); - - return new_expr; -} - -/*******************************************************************\ - Function: constant_propagator_domaint::assign_rec Inputs: @@ -85,73 +31,23 @@ Function: constant_propagator_domaint::assign_rec void constant_propagator_domaint::assign_rec( valuest &values, - const exprt &lhs, const exprt &rhs, + const exprt &lhs, + const exprt &rhs, const namespacet &ns) { - const typet & lhs_type = ns.follow(lhs.type()); - const typet & rhs_type = ns.follow(rhs.type()); + if(lhs.id()!=ID_symbol) + return; -#ifdef DEBUG - std::cout << "assign: " << from_expr(ns, "", lhs) - << " := " << from_type(ns, "", rhs_type) << std::endl; -#endif + const symbol_exprt &s=to_symbol_expr(lhs); - if(lhs.id()==ID_symbol && rhs.id()==ID_if) - { - exprt cond=rhs.op0(); - assert(cond.operands().size()==2); - if(values.is_constant(cond.op0()) - && values.is_constant(cond.op1())) - { - if(cond.op0().id()==ID_index) - { - exprt index=cond.op0(); - exprt new_expr=concatenate_array_id(index.op0(), index.op1(), index.type()); - values.replace_const(new_expr); - cond.op0()=new_expr; - cond = simplify_expr(cond,ns); - } - else - assert(0); + exprt tmp=rhs; + values.replace_const(tmp); + simplify(tmp, ns); - assign(values, to_symbol_expr(lhs), cond, ns); - } - } - else if(lhs.id()==ID_symbol && rhs_type.id()!=ID_array - && rhs_type.id()!=ID_struct - && rhs_type.id()!=ID_union) - { - if(values.is_constant(rhs)) - assign(values, to_symbol_expr(lhs), rhs, ns); - else - values.set_to_top(to_symbol_expr(lhs)); - } - else if(lhs.id()==ID_symbol && lhs_type.id()==ID_array - && rhs_type.id()==ID_array) - { - exprt new_expr; - mp_integer idx=0; - forall_operands(it, rhs) - { - new_expr=concatenate_array_id(lhs, idx, it->type()); - assign(values, to_symbol_expr(new_expr), *it, ns); - idx = idx +1; - } - } - else if (lhs.id()==ID_index) - { - if (values.is_constant(lhs.op1()) - && values.is_constant(rhs)) - { - exprt new_expr=concatenate_array_id(lhs.op0(), lhs.op1(), rhs.type()); - assign(values, to_symbol_expr(new_expr), rhs, ns); - } - } -#if 0 - else // TODO: could make field or array element-sensitive - { - } -#endif + if(tmp.is_constant()) + values.set_to(s, tmp); + else + values.set_to_top(s); } /*******************************************************************\ @@ -172,16 +68,37 @@ void constant_propagator_domaint::transform( ai_baset &ai, const namespacet &ns) { - #ifdef DEBUG +#ifdef DEBUG + std::cout << "Transform from/to:\n"; std::cout << from->location_number << " --> " << to->location_number << '\n'; - #endif +#endif #ifdef DEBUG - std::cout << "before:\n"; + std::cout << "Before:\n"; output(std::cout, ai, ns); #endif + // When the domain is used with constant_propagator_ait, + // information about dirty variables and config flags are + // available. Otherwise, the below will be null and we use default + // values + const constant_propagator_ait *cp= + dynamic_cast(&ai); + + bool have_dirty=false; + bool ignore_unresolved_calls=false; + + if(cp!=nullptr) + { + have_dirty=true; + ignore_unresolved_calls=cp->ignore_unresolved_calls; + } + + // assert(!values.is_bottom); + if(values.is_bottom) + return; + if(from->is_decl()) { const code_declt &code_decl=to_code_decl(from->code); @@ -191,8 +108,8 @@ void constant_propagator_domaint::transform( else if(from->is_assign()) { const code_assignt &assignment=to_code_assign(from->code); - const exprt &lhs = assignment.lhs(); - const exprt &rhs = assignment.rhs(); + const exprt &lhs=assignment.lhs(); + const exprt &rhs=assignment.rhs(); assign_rec(values, lhs, rhs, ns); } else if(from->is_assume()) @@ -204,19 +121,16 @@ void constant_propagator_domaint::transform( exprt g; if(from->get_target()==to) - g = simplify_expr(from->guard, ns); + g=simplify_expr(from->guard, ns); else - g = simplify_expr(not_exprt(from->guard), ns); + g=simplify_expr(not_exprt(from->guard), ns); - if (g.is_false()) + if(g.is_false()) values.set_to_bottom(); else { - //TODO: we need to support widening! - if (g.is_constant()) - values.set_to_top(); - else - two_way_propagate_rec(g, ns); + two_way_propagate_rec(g, ns); + assert(!values.is_bottom); // for now } } else if(from->is_dead()) @@ -226,35 +140,102 @@ void constant_propagator_domaint::transform( } else if(from->is_function_call()) { - const exprt &function=to_code_function_call(from->code).function(); + const code_function_callt &function_call=to_code_function_call(from->code); + const exprt &function=function_call.function(); + + locationt next=from; + next++; if(function.id()==ID_symbol) { - const irep_idt &identifier=to_symbol_expr(function).get_identifier(); - - if(identifier=="__CPROVER_set_must" || - identifier=="__CPROVER_get_must" || - identifier=="__CPROVER_set_may" || - identifier=="__CPROVER_get_may" || - identifier=="__CPROVER_cleanup" || - identifier=="__CPROVER_clear_may" || - identifier=="__CPROVER_clear_must") + // called function identifier + const symbol_exprt &symbol_expr=to_symbol_expr(function); + const irep_idt id=symbol_expr.get_identifier(); + + if(to==next) { + if(id==CPROVER_PREFIX "set_must" || + id==CPROVER_PREFIX "get_must" || + id==CPROVER_PREFIX "set_may" || + id==CPROVER_PREFIX "get_may" || + id==CPROVER_PREFIX "cleanup" || + id==CPROVER_PREFIX "clear_may" || + id==CPROVER_PREFIX "clear_must") + { + // no effect on constants + } + else + { + if(!ignore_unresolved_calls) + { + if(have_dirty) + values.set_dirty_to_top(cp->dirty, ns); + else + values.set_to_top(); + } + } } else - values.set_to_top(); + { + // we have an actual call + + // parameters of called function + const symbolt &symbol=ns.lookup(id); + const code_typet &code_type=to_code_type(symbol.type); + const code_typet::parameterst ¶meters=code_type.parameters(); + + const code_function_callt::argumentst &arguments= + function_call.arguments(); + + code_typet::parameterst::const_iterator p_it=parameters.begin(); + for(const auto &arg : arguments) + { + if(p_it==parameters.end()) + break; + + const symbol_exprt parameter_expr(p_it->get_identifier(), arg.type()); + assign_rec(values, parameter_expr, arg, ns); + + ++p_it; + } + } } else - values.set_to_top(); + { + // unresolved call + + assert(to==next); + + if(!ignore_unresolved_calls) + { + if(have_dirty) + values.set_dirty_to_top(cp->dirty, ns); + else + values.set_to_top(); + } + } + } + else if(from->is_end_function()) + { + // erase parameters + + const irep_idt id=from->function; + const symbolt &symbol=ns.lookup(id); + + const code_typet &type=to_code_type(symbol.type); + + for(const auto ¶m : type.parameters()) + values.set_to_top(param.get_identifier()); } + assert(from->is_goto() || !values.is_bottom); + #ifdef DEBUG - std::cout << "after:\n"; + std::cout << "After:\n"; output(std::cout, ai, ns); #endif } - /*******************************************************************\ Function: constant_propagator_domaint::two_way_propagate_rec @@ -274,8 +255,11 @@ bool constant_propagator_domaint::two_way_propagate_rec( #ifdef DEBUG std::cout << "two_way_propagate_rec: " << from_expr(ns, "", expr) << '\n'; #endif - bool change = false; + bool change=false; + + // this seems to be buggy at present +#if 0 if(expr.id()==ID_and) { // need a fixed point here to get the most out of it @@ -285,74 +269,63 @@ bool constant_propagator_domaint::two_way_propagate_rec( forall_operands(it, expr) if(two_way_propagate_rec(*it, ns)) - change = true; + change=true; } while(change); } else if(expr.id()==ID_equal) { - const exprt &lhs = expr.op0(); - const exprt &rhs = expr.op1(); + const exprt &lhs=expr.op0(); + const exprt &rhs=expr.op1(); // two-way propagation - valuest copy_values = values; + valuest copy_values=values; assign_rec(copy_values, lhs, rhs, ns); if(!values.is_constant(rhs) || values.is_constant(lhs)) - assign_rec(values, rhs, lhs, ns); - change = values.meet(copy_values); + assign_rec(values, rhs, lhs, ns); + change=values.meet(copy_values); } +#endif #ifdef DEBUG std::cout << "two_way_propagate_rec: " << change << '\n'; #endif - return change; -} - -/*******************************************************************\ -Function: constant_propagator_domaint::assign - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -void constant_propagator_domaint::assign( - valuest &dest, - const symbol_exprt &lhs, - exprt rhs, - const namespacet &ns) const -{ - values.replace_const(rhs); - rhs = simplify_expr(rhs, ns); - dest.set_to(lhs, rhs); + return change; } /*******************************************************************\ -Function: constant_propagator_domaint::is_array_constant +Function: constant_propagator_domaint::simplify - Inputs: + Inputs: The condition to simplify and its namespace. - Outputs: + Outputs: The simplified condition. - Purpose: + Purpose: Simplify the condition given context-sensitive knowledge + from the abstract state. \*******************************************************************/ -bool constant_propagator_domaint::valuest::is_array_constant(const exprt &expr) const +bool constant_propagator_domaint::ai_simplify( + exprt &condition, + const namespacet &ns, + const bool lhs) const { - exprt new_expr = concatenate_array_id(expr.op0(), - expr.op1(), expr.type()); + if(lhs) + { + // For now do not simplify the left hand sides of assignments + return true; + } + else + { + bool b; - if (replace_const.expr_map.find(to_symbol_expr(new_expr).get_identifier()) == - replace_const.expr_map.end()) - return false; + b=values.replace_const.replace(condition); + b&=simplify(condition, ns); - return true; + return b; + } } /*******************************************************************\ @@ -378,12 +351,12 @@ bool constant_propagator_domaint::valuest::is_constant(const exprt &expr) const return false; if(expr.id()==ID_symbol) - if(replace_const.expr_map.find(to_symbol_expr(expr).get_identifier()) == + if(replace_const.expr_map.find(to_symbol_expr(expr).get_identifier())== replace_const.expr_map.end()) return false; - if (expr.id()==ID_index) - return is_array_constant(expr); + if(expr.id()==ID_index) + return false; if(expr.id()==ID_address_of) return is_constant_address_of(to_address_of_expr(expr).object()); @@ -434,25 +407,52 @@ Function: constant_propagator_domaint::valuest::set_to_top Outputs: - Purpose: Do not call this when iterating over replace_const.expr_map! + Purpose: Do not call when iterating over replace_const.expr_map! \*******************************************************************/ bool constant_propagator_domaint::valuest::set_to_top(const irep_idt &id) { - bool result = false; + replace_symbolt::expr_mapt::size_type n_erased= + replace_const.expr_map.erase(id); + + assert(n_erased==0 || !is_bottom); + + return n_erased>0; +} + +/*******************************************************************\ + +Function: constant_propagator_domaint::valuest::set_dirty_to_top + + Inputs: + + Outputs: + + Purpose: - replace_symbolt::expr_mapt::iterator r_it = - replace_const.expr_map.find(id); +\*******************************************************************/ - if(r_it != replace_const.expr_map.end()) +void constant_propagator_domaint::valuest::set_dirty_to_top( + const dirtyt &dirty, + const namespacet &ns) +{ + typedef replace_symbolt::expr_mapt expr_mapt; + expr_mapt &expr_map=replace_const.expr_map; + + for(expr_mapt::iterator it=expr_map.begin(); + it!=expr_map.end();) { - assert(!is_bottom); - replace_const.expr_map.erase(r_it); - result = true; - } + const irep_idt id=it->first; + + const symbolt &symbol=ns.lookup(id); - return result; + if((!symbol.is_procedure_local() || dirty(id)) && + !symbol.type.get_bool(ID_C_constant)) + it=expr_map.erase(it); + else + it++; + } } /*******************************************************************\ @@ -474,11 +474,23 @@ void constant_propagator_domaint::valuest::output( out << "const map:\n"; if(is_bottom) + { out << " bottom\n"; + assert(replace_const.expr_map.empty()); + return; + } + + assert(!is_bottom); + if(replace_const.expr_map.empty()) + { + out << "top\n"; + return; + } - for(const auto &replace_pair : replace_const.expr_map) - out << ' ' << replace_pair.first << "=" - << from_expr(ns, "", replace_pair.second) << '\n'; + for(const auto &p : replace_const.expr_map) + { + out << ' ' << p.first << "=" << from_expr(ns, "", p.second) << '\n'; + } } /*******************************************************************\ @@ -522,38 +534,62 @@ bool constant_propagator_domaint::valuest::merge(const valuest &src) // just copy if(is_bottom) { - replace_const = src.replace_const; - is_bottom = src.is_bottom; + assert(!src.is_bottom); + replace_const=src.replace_const; // copy + is_bottom=false; return true; } - bool changed = false; + assert(!is_bottom && !src.is_bottom); + + bool changed=false; - // set everything to top that is not in src - for(replace_symbolt::expr_mapt::const_iterator - it=replace_const.expr_map.begin(); - it!=replace_const.expr_map.end(); - ) // no it++ + replace_symbolt::expr_mapt &expr_map=replace_const.expr_map; + const replace_symbolt::expr_mapt &src_expr_map=src.replace_const.expr_map; + + // handle top + if(src_expr_map.empty()) { - const replace_symbolt::expr_mapt::const_iterator - b_it=src.replace_const.expr_map.find(it->first); + // change if it was not top + changed=!expr_map.empty(); + + set_to_top(); - if(b_it==src.replace_const.expr_map.end()) + return changed; + } + + // remove those that are + // - different in src + // - do not exist in src + for(replace_symbolt::expr_mapt::iterator it=expr_map.begin(); + it!=expr_map.end();) + { + const irep_idt id=it->first; + const exprt &expr=it->second; + + replace_symbolt::expr_mapt::const_iterator s_it; + s_it=src_expr_map.find(id); + + if(s_it!=src_expr_map.end()) { - //cannot use set_to_top here - replace_const.expr_map.erase(it); - changed = true; - break; + // check value + const exprt &src_expr=s_it->second; + + if(expr!=src_expr) + { + it=expr_map.erase(it); + changed=true; + } + else + it++; } else { - const exprt previous=it->second; - replace_const.expr_map[b_it->first]=b_it->second; - if (it->second != previous) changed = true; - - it++; + it=expr_map.erase(it); + changed=true; } } + return changed; } @@ -574,16 +610,16 @@ bool constant_propagator_domaint::valuest::meet(const valuest &src) if(src.is_bottom || is_bottom) return false; - bool changed = false; + bool changed=false; - for(const auto &src_replace_pair : src.replace_const.expr_map) + for(const auto &m : src.replace_const.expr_map) { - replace_symbolt::expr_mapt::iterator c_it= - replace_const.expr_map.find(src_replace_pair.first); + replace_symbolt::expr_mapt::iterator + c_it=replace_const.expr_map.find(m.first); if(c_it!=replace_const.expr_map.end()) { - if(c_it->second!=src_replace_pair.second) + if(c_it->second!=m.second) { set_to_bottom(); changed=true; @@ -592,7 +628,7 @@ bool constant_propagator_domaint::valuest::meet(const valuest &src) } else { - set_to(src_replace_pair.first, src_replace_pair.second); + set_to(m.first, m.second); changed=true; } } @@ -642,34 +678,6 @@ void constant_propagator_ait::replace( /*******************************************************************\ -Function: constant_propagator_ait::replace_array_symbol - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -void constant_propagator_ait::replace_array_symbol(exprt &expr) -{ - if (expr.id()==ID_index) - expr = concatenate_array_id(expr.op0(), - expr.op1(), expr.type()); - - Forall_operands(it, expr) - { - if (it->id()==ID_equal) - replace_array_symbol(it->op0()); - else if (it->id()==ID_index) - replace_array_symbol(expr.op0()); - } - -} - -/*******************************************************************\ - Function: constant_propagator_ait::replace Inputs: @@ -686,9 +694,9 @@ void constant_propagator_ait::replace( { Forall_goto_program_instructions(it, goto_function.body) { - state_mapt::iterator s_it = state_map.find(it); + state_mapt::iterator s_it=state_map.find(it); - if(s_it == state_map.end()) + if(s_it==state_map.end()) continue; replace_types_rec(s_it->second.values.replace_const, it->code); @@ -696,32 +704,32 @@ void constant_propagator_ait::replace( if(it->is_goto() || it->is_assume() || it->is_assert()) { - replace_array_symbol(it->guard); s_it->second.values.replace_const(it->guard); - it->guard = simplify_expr(it->guard, ns); + simplify(it->guard, ns); } else if(it->is_assign()) { - exprt &rhs = to_code_assign(it->code).rhs(); + exprt &rhs=to_code_assign(it->code).rhs(); s_it->second.values.replace_const(rhs); - rhs = simplify_expr(rhs, ns); - if (rhs.id()==ID_constant) + simplify(rhs, ns); + if(rhs.id()==ID_constant) rhs.add_source_location()=it->code.op0().source_location(); } else if(it->is_function_call()) { s_it->second.values.replace_const( to_code_function_call(it->code).function()); - simplify_expr(to_code_function_call(it->code).function(), ns); - exprt::operandst &args = + simplify(to_code_function_call(it->code).function(), ns); + + exprt::operandst &args= to_code_function_call(it->code).arguments(); - for(exprt::operandst::iterator o_it = args.begin(); - o_it != args.end(); ++o_it) + for(exprt::operandst::iterator o_it=args.begin(); + o_it!=args.end(); ++o_it) { s_it->second.values.replace_const(*o_it); - *o_it = simplify_expr(*o_it, ns); + simplify(*o_it, ns); } } else if(it->is_other()) diff --git a/src/analyses/constant_propagator.h b/src/analyses/constant_propagator.h index 0766b458f7d..c2118752294 100644 --- a/src/analyses/constant_propagator.h +++ b/src/analyses/constant_propagator.h @@ -9,89 +9,138 @@ Author: Peter Schrammel #ifndef CPROVER_ANALYSES_CONSTANT_PROPAGATOR_H #define CPROVER_ANALYSES_CONSTANT_PROPAGATOR_H -#include "ai.h" +#include +#include -#include "replace_symbol_ext.h" +#include "ai.h" +#include "dirty.h" class constant_propagator_domaint:public ai_domain_baset { public: - void transform( - locationt, - locationt, - ai_baset &, - const namespacet &) final; - void output( - std::ostream &, - const ai_baset &, - const namespacet &) const final; - void make_top() final { values.set_to_top(); } - void make_bottom() final { values.set_to_bottom(); } - void make_entry() final { values.set_to_top(); } - bool merge(const constant_propagator_domaint &, locationt, locationt); + virtual void transform( + locationt from, + locationt to, + ai_baset &ai_base, + const namespacet &ns) final override; + + virtual void output( + std::ostream &out, + const ai_baset &ai_base, + const namespacet &ns) const override; + + bool merge( + const constant_propagator_domaint &other, + locationt from, + locationt to); + + virtual bool ai_simplify( + exprt &condition, + const namespacet &ns, + const bool lhs=false) const final override; + + virtual void make_bottom() final override + { + values.set_to_bottom(); + } + + virtual void make_top() final override + { + values.set_to_top(); + } + + virtual void make_entry() final override + { + make_top(); + } + + virtual bool is_bottom() const final override + { + return values.is_bot(); + } + + virtual bool is_top() const final override + { + return values.is_top(); + } struct valuest { public: - valuest():is_bottom(true) { } + valuest():is_bottom(true) {} // maps variables to constants - replace_symbol_extt replace_const; + replace_symbolt replace_const; bool is_bottom; - void output(std::ostream &, const namespacet &) const; - bool merge(const valuest &src); bool meet(const valuest &src); + // set whole state + void set_to_bottom() { replace_const.clear(); - is_bottom = true; + is_bottom=true; } - void set_to(const irep_idt &lhs_id, const exprt &rhs_val) + void set_to_top() { - replace_const.expr_map[lhs_id] = rhs_val; - is_bottom = false; + replace_const.clear(); + is_bottom=false; } - void set_to(const symbol_exprt &lhs, const exprt &rhs_val) + bool is_bot() const { - set_to(lhs.get_identifier(), rhs_val); + return is_bottom && replace_const.empty(); } - bool is_constant(const exprt &expr) const; - bool is_array_constant(const exprt &expr) const; - bool is_constant_address_of(const exprt &expr) const; - bool set_to_top(const irep_idt &id); + bool is_top() const + { + return !is_bottom && replace_const.empty(); + } + + // set single identifier + + void set_to(const irep_idt &lhs, const exprt &rhs) + { + replace_const.expr_map[lhs]=rhs; + is_bottom=false; + } + + void set_to(const symbol_exprt &lhs, const exprt &rhs) + { + set_to(lhs.get_identifier(), rhs); + } bool set_to_top(const symbol_exprt &expr) { return set_to_top(expr.get_identifier()); } - void set_to_top() + bool set_to_top(const irep_idt &id); + + void set_dirty_to_top(const dirtyt &dirty, const namespacet &ns); + + bool is_constant(const exprt &expr) const; + bool is_array_constant(const exprt &expr) const; + bool is_constant_address_of(const exprt &expr) const; + + bool is_empty() const { - replace_const.clear(); - is_bottom = false; + assert(replace_const.type_map.empty()); + return replace_const.expr_map.empty(); } + void output(std::ostream &out, const namespacet &ns) const; }; valuest values; -private: - void assign( - valuest &dest, - const symbol_exprt &lhs, - exprt rhs, - const namespacet &ns) const; - +protected: void assign_rec( valuest &values, - const exprt &lhs, - const exprt &rhs, + const exprt &lhs, const exprt &rhs, const namespacet &ns); bool two_way_propagate_rec( @@ -102,9 +151,17 @@ class constant_propagator_domaint:public ai_domain_baset class constant_propagator_ait:public ait { public: + explicit constant_propagator_ait( + const goto_functionst &goto_functions, + const bool ignore_unresolved_calls=false) : + dirty(goto_functions), + ignore_unresolved_calls(ignore_unresolved_calls) + { + } + constant_propagator_ait( goto_functionst &goto_functions, - const namespacet &ns) + const namespacet &ns) : dirty(goto_functions) { operator()(goto_functions, ns); replace(goto_functions, ns); @@ -112,18 +169,18 @@ class constant_propagator_ait:public ait constant_propagator_ait( goto_functionst::goto_functiont &goto_function, - const namespacet &ns) + const namespacet &ns) : dirty(goto_function) { operator()(goto_function, ns); replace(goto_function, ns); } + dirtyt dirty; + bool ignore_unresolved_calls; + protected: friend class constant_propagator_domaint; - void replace_array_symbol( - exprt &expr); - void replace( goto_functionst::goto_functiont &, const namespacet &); @@ -135,7 +192,6 @@ class constant_propagator_ait:public ait void replace_types_rec( const replace_symbolt &replace_const, exprt &expr); - }; #endif // CPROVER_ANALYSES_CONSTANT_PROPAGATOR_H diff --git a/src/analyses/custom_bitvector_analysis.h b/src/analyses/custom_bitvector_analysis.h index ceb2ba691be..e141988761e 100644 --- a/src/analyses/custom_bitvector_analysis.h +++ b/src/analyses/custom_bitvector_analysis.h @@ -32,32 +32,44 @@ class custom_bitvector_domaint:public ai_domain_baset locationt from, locationt to, ai_baset &ai, - const namespacet &ns) final; + const namespacet &ns) final override; void output( std::ostream &out, const ai_baset &ai, - const namespacet &ns) const final; + const namespacet &ns) const final override; - void make_bottom() final + void make_bottom() final override { may_bits.clear(); must_bits.clear(); has_values=tvt(false); } - void make_top() final + void make_top() final override { may_bits.clear(); must_bits.clear(); has_values=tvt(true); } - void make_entry() final + void make_entry() final override { make_top(); } + bool is_bottom() const final override + { + assert(!has_values.is_false() || (may_bits.empty() && must_bits.empty())); + return has_values.is_false(); + } + + bool is_top() const final override + { + assert(!has_values.is_true() || (may_bits.empty() && must_bits.empty())); + return has_values.is_true(); + } + bool merge( const custom_bitvector_domaint &b, locationt from, diff --git a/src/analyses/dependence_graph.cpp b/src/analyses/dependence_graph.cpp index 93588e209a7..686aecf6b4d 100644 --- a/src/analyses/dependence_graph.cpp +++ b/src/analyses/dependence_graph.cpp @@ -11,6 +11,9 @@ Date: August 2013 #include +#include +#include + #include "goto_rw.h" #include "dependence_graph.h" @@ -347,6 +350,46 @@ void dep_graph_domaint::output( /*******************************************************************\ +Function: dep_graph_domaint::output_json + + Inputs: The abstract interpreter and the namespace. + + Outputs: The domain, formatted as a JSON object. + + Purpose: Outputs the current value of the domain. + +\*******************************************************************/ + +jsont dep_graph_domaint::output_json( + const ai_baset &ai, + const namespacet &ns) const +{ + json_arrayt graph; + + for(const auto &cd : control_deps) + { + json_objectt &link=graph.push_back().make_object(); + link["locationNumber"]= + json_numbert(std::to_string(cd->location_number)); + link["sourceLocation"]=json(cd->source_location); + link["type"]=json_stringt("control"); + } + + for(const auto &dd : data_deps) + { + json_objectt &link=graph.push_back().make_object(); + link["locationNumber"]= + json_numbert(std::to_string(dd->location_number)); + link["sourceLocation"]=json(dd->source_location); + json_stringt(dd->source_location.as_string()); + link["type"]=json_stringt("data"); + } + + return graph; +} + +/*******************************************************************\ + Function: dependence_grapht::add_dep Inputs: diff --git a/src/analyses/dependence_graph.h b/src/analyses/dependence_graph.h index 8b627dd36b0..e03a78df68e 100644 --- a/src/analyses/dependence_graph.h +++ b/src/analyses/dependence_graph.h @@ -86,14 +86,18 @@ class dep_graph_domaint:public ai_domain_baset goto_programt::const_targett from, goto_programt::const_targett to, ai_baset &ai, - const namespacet &ns) final; + const namespacet &ns) final override; void output( std::ostream &out, const ai_baset &ai, - const namespacet &ns) const final; + const namespacet &ns) const final override; - void make_top() final + jsont output_json( + const ai_baset &ai, + const namespacet &ns) const override; + + void make_top() final override { assert(node_id!=std::numeric_limits::max()); @@ -102,7 +106,7 @@ class dep_graph_domaint:public ai_domain_baset data_deps.clear(); } - void make_bottom() final + void make_bottom() final override { assert(node_id!=std::numeric_limits::max()); @@ -111,11 +115,31 @@ class dep_graph_domaint:public ai_domain_baset data_deps.clear(); } - void make_entry() final + void make_entry() final override { make_top(); } + bool is_top() const final override + { + assert(node_id!=std::numeric_limits::max()); + + assert(!has_values.is_true() || + (control_deps.empty() && data_deps.empty())); + + return has_values.is_true(); + } + + bool is_bottom() const final override + { + assert(node_id!=std::numeric_limits::max()); + + assert(!has_values.is_false() || + (control_deps.empty() && data_deps.empty())); + + return has_values.is_false(); + } + void set_node_id(node_indext id) { node_id=id; diff --git a/src/analyses/escape_analysis.h b/src/analyses/escape_analysis.h index 948bed3fea8..834a9031a34 100644 --- a/src/analyses/escape_analysis.h +++ b/src/analyses/escape_analysis.h @@ -37,33 +37,45 @@ class escape_domaint:public ai_domain_baset locationt from, locationt to, ai_baset &ai, - const namespacet &ns) final; + const namespacet &ns) final override; void output( std::ostream &out, const ai_baset &ai, - const namespacet &ns) const final; + const namespacet &ns) const final override; bool merge( const escape_domaint &b, locationt from, locationt to); - void make_bottom() final + void make_bottom() final override { cleanup_map.clear(); aliases.clear(); has_values=tvt(false); } - void make_top() final + void make_top() final override { cleanup_map.clear(); aliases.clear(); has_values=tvt(true); } - void make_entry() final + bool is_bottom() const override final + { + assert(!has_values.is_false() || (cleanup_map.empty() && aliases.empty())); + return has_values.is_false(); + } + + bool is_top() const override final + { + assert(!has_values.is_true() || (cleanup_map.empty() && aliases.empty())); + return has_values.is_true(); + } + + void make_entry() override final { make_top(); } diff --git a/src/analyses/global_may_alias.h b/src/analyses/global_may_alias.h index 2f4a49b2d0a..9ed5b5ed78d 100644 --- a/src/analyses/global_may_alias.h +++ b/src/analyses/global_may_alias.h @@ -37,35 +37,47 @@ class global_may_alias_domaint:public ai_domain_baset locationt from, locationt to, ai_baset &ai, - const namespacet &ns) final; + const namespacet &ns) final override; void output( std::ostream &out, const ai_baset &ai, - const namespacet &ns) const final; + const namespacet &ns) const final override; bool merge( const global_may_alias_domaint &b, locationt from, locationt to); - void make_bottom() final + void make_bottom() final override { aliases.clear(); has_values=tvt(false); } - void make_top() final + void make_top() final override { aliases.clear(); has_values=tvt(true); } - void make_entry() final + void make_entry() final override { make_top(); } + bool is_bottom() const final override + { + assert(!has_values.is_false() || aliases.empty()); + return has_values.is_false(); + } + + bool is_top() const final override + { + assert(!has_values.is_true() || aliases.empty()); + return has_values.is_true(); + } + typedef union_find aliasest; aliasest aliases; diff --git a/src/analyses/interval_domain.cpp b/src/analyses/interval_domain.cpp index 1faf8c52364..18befbfe182 100644 --- a/src/analyses/interval_domain.cpp +++ b/src/analyses/interval_domain.cpp @@ -129,7 +129,7 @@ void interval_domaint::transform( /*******************************************************************\ -Function: interval_domaint::merge +Function: interval_domaint::join Inputs: @@ -139,10 +139,8 @@ Function: interval_domaint::merge \*******************************************************************/ -bool interval_domaint::merge( - const interval_domaint &b, - locationt from, - locationt to) +bool interval_domaint::join( + const interval_domaint &b) { if(b.bottom) return false; @@ -157,8 +155,8 @@ bool interval_domaint::merge( for(int_mapt::iterator it=int_map.begin(); it!=int_map.end(); ) // no it++ { - //search for the variable that needs to be merged - //containers have different size and variable order + // search for the variable that needs to be merged + // containers have different size and variable order const int_mapt::const_iterator b_it=b.int_map.find(it->first); if(b_it==b.int_map.end()) { @@ -527,3 +525,61 @@ exprt interval_domaint::make_expression(const symbol_exprt &src) const else return true_exprt(); } + +/*******************************************************************\ + +Function: interval_domaint::simplify + + Inputs: The expression to simplify. + + Outputs: A simplified version of the expression. + + Purpose: Uses the abstract state to simplify a given expression + using context-specific information. + +\*******************************************************************/ + +bool interval_domaint::ai_simplify( + exprt &condition, + const namespacet &ns, + const bool lhs) const +{ + bool unchanged=true; + + if(lhs) + { + // For now do not simplify the left hand side of assignments + return true; + } + + interval_domaint d(*this); + + // merge intervals to properly handle conjunction + if(condition.id()==ID_and) + { + interval_domaint a; + a.make_top(); + a.assume(condition, ns); + + if(!a.join(d)) + { + unchanged=condition.is_true(); + condition.make_true(); + } + } + else if(condition.id()==ID_symbol) + { + // TODO: we have to handle symbol expression + } + else + { + d.assume(not_exprt(condition), ns); + if(d.is_bottom()) + { + unchanged=condition.is_true(); + condition.make_true(); + } + } + + return unchanged; +} diff --git a/src/analyses/interval_domain.h b/src/analyses/interval_domain.h index 7e95c65e9de..d081ea2d9a8 100644 --- a/src/analyses/interval_domain.h +++ b/src/analyses/interval_domain.h @@ -33,20 +33,25 @@ class interval_domaint:public ai_domain_baset locationt from, locationt to, ai_baset &ai, - const namespacet &ns) final; + const namespacet &ns) final override; void output( std::ostream &out, const ai_baset &ai, - const namespacet &ns) const final; + const namespacet &ns) const override; + + bool join(const interval_domaint &b); bool merge( const interval_domaint &b, locationt from, - locationt to); + locationt to) + { + return join(b); + } // no states - void make_bottom() final + void make_bottom() final override { int_map.clear(); float_map.clear(); @@ -54,18 +59,30 @@ class interval_domaint:public ai_domain_baset } // all states - void make_top() final + void make_top() final override { int_map.clear(); float_map.clear(); bottom=false; } - void make_entry() final + void make_entry() final override { make_top(); } + bool is_bottom() const override final + { + // assert(!bottom || (int_map.empty() && float_map.empty())); + + return bottom; + } + + bool is_top() const override final + { + return !bottom && int_map.empty() && float_map.empty(); + } + exprt make_expression(const symbol_exprt &) const; void assume(const exprt &, const namespacet &); @@ -80,12 +97,12 @@ class interval_domaint:public ai_domain_baset return src.id()==ID_floatbv; } - bool is_bottom() const - { - return bottom; - } + virtual bool ai_simplify( + exprt &condition, + const namespacet &ns, + const bool lhs=false) const override final; -private: +protected: bool bottom; typedef std::map int_mapt; diff --git a/src/analyses/invariant_set_domain.h b/src/analyses/invariant_set_domain.h index 2e231524cbb..3031ac8d867 100644 --- a/src/analyses/invariant_set_domain.h +++ b/src/analyses/invariant_set_domain.h @@ -41,7 +41,7 @@ class invariant_set_domaint:public ai_domain_baset void output( std::ostream &out, const ai_baset &ai, - const namespacet &ns) const final + const namespacet &ns) const final override { if(has_values.is_known()) out << has_values.to_string() << '\n'; @@ -53,25 +53,35 @@ class invariant_set_domaint:public ai_domain_baset locationt from_l, locationt to_l, ai_baset &ai, - const namespacet &ns) final; + const namespacet &ns) final override; - void make_top() final + void make_top() final override { invariant_set.make_true(); has_values=tvt(true); } - void make_bottom() final + void make_bottom() final override { invariant_set.make_false(); has_values=tvt(false); } - void make_entry() final + void make_entry() final override { invariant_set.make_true(); has_values=tvt(true); } + + bool is_top() const override final + { + return has_values.is_true(); + } + + bool is_bottom() const override final + { + return has_values.is_false(); + } }; #endif // CPROVER_ANALYSES_INVARIANT_SET_DOMAIN_H diff --git a/src/analyses/is_threaded.cpp b/src/analyses/is_threaded.cpp index 905cd6b91ac..9567b343517 100644 --- a/src/analyses/is_threaded.cpp +++ b/src/analyses/is_threaded.cpp @@ -29,10 +29,7 @@ class is_threaded_domaint:public ai_domain_baset locationt from, locationt to) { - // assert(src.reachable); - - if(!src.reachable) - return false; + assert(src.reachable); bool old_reachable=reachable; bool old_is_threaded=is_threaded; @@ -48,34 +45,43 @@ class is_threaded_domaint:public ai_domain_baset locationt from, locationt to, ai_baset &ai, - const namespacet &ns) final + const namespacet &ns) final override { - // assert(reachable); - - if(!reachable) - return; + assert(reachable); if(from->is_start_thread()) is_threaded=true; } - void make_bottom() final + void make_bottom() final override { reachable=false; is_threaded=false; } - void make_top() final + void make_top() final override { reachable=true; is_threaded=true; } - void make_entry() final + void make_entry() final override { reachable=true; is_threaded=false; } + + bool is_bottom() const override final + { + assert(reachable || !is_threaded); + + return !reachable; + } + + bool is_top() const override final + { + return reachable && is_threaded; + } }; /*******************************************************************\ diff --git a/src/analyses/reaching_definitions.h b/src/analyses/reaching_definitions.h index a48a271a9a6..a08963bd379 100644 --- a/src/analyses/reaching_definitions.h +++ b/src/analyses/reaching_definitions.h @@ -112,17 +112,17 @@ class rd_range_domaint:public ai_domain_baset locationt from, locationt to, ai_baset &ai, - const namespacet &ns) final; + const namespacet &ns) final override; void output( std::ostream &out, const ai_baset &ai, - const namespacet &ns) const final + const namespacet &ns) const final override { output(out); } - void make_top() final + void make_top() final override { values.clear(); if(bv_container) @@ -130,7 +130,7 @@ class rd_range_domaint:public ai_domain_baset has_values=tvt(true); } - void make_bottom() final + void make_bottom() final override { values.clear(); if(bv_container) @@ -138,11 +138,23 @@ class rd_range_domaint:public ai_domain_baset has_values=tvt(false); } - void make_entry() final + void make_entry() final override { make_top(); } + bool is_top() const override final + { + assert(!has_values.is_true() || values.empty()); + return has_values.is_true(); + } + + bool is_bottom() const override final + { + assert(!has_values.is_false() || values.empty()); + return has_values.is_false(); + } + // returns true iff there is s.th. new bool merge( const rd_range_domaint &other, @@ -248,9 +260,9 @@ class reaching_definitions_analysist: virtual ~reaching_definitions_analysist(); virtual void initialize( - const goto_functionst &goto_functions); + const goto_functionst &goto_functions) override; - virtual statet &get_state(goto_programt::const_targett l) + virtual statet &get_state(goto_programt::const_targett l) override { statet &s=concurrency_aware_ait::get_state(l); diff --git a/src/analyses/replace_symbol_ext.cpp b/src/analyses/replace_symbol_ext.cpp deleted file mode 100644 index 568ea45e090..00000000000 --- a/src/analyses/replace_symbol_ext.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/*******************************************************************\ - -Module: Modified expression replacement for constant propagator - -Author: Peter Schrammel - -\*******************************************************************/ - -#include -#include - -#include "replace_symbol_ext.h" - -/*******************************************************************\ - -Function: replace_symbol_extt::replace - - Inputs: - - Outputs: - - Purpose: does not replace object in address_of expressions - -\*******************************************************************/ - -bool replace_symbol_extt::replace(exprt &dest) const -{ - bool result=true; - - // first look at type - - if(have_to_replace(dest.type())) - if(!replace_symbolt::replace(dest.type())) - result=false; - - // now do expression itself - - if(!have_to_replace(dest)) - return result; - - // do not replace object in address_of expressions - if(dest.id()==ID_address_of) - { - const exprt &object = to_address_of_expr(dest).object(); - if(object.id()==ID_symbol) - { - expr_mapt::const_iterator it= - expr_map.find(object.get(ID_identifier)); - - if(it!=expr_map.end()) - return false; - } - } - else if(dest.id()==ID_symbol) - { - expr_mapt::const_iterator it= - expr_map.find(dest.get(ID_identifier)); - - if(it!=expr_map.end()) - { - dest=it->second; - return false; - } - } - - Forall_operands(it, dest) - if(!replace(*it)) - result=false; - - const irept &c_sizeof_type=dest.find(ID_C_c_sizeof_type); - - if(c_sizeof_type.is_not_nil() && - !replace_symbolt::replace( - static_cast(dest.add(ID_C_c_sizeof_type)))) - result=false; - - const irept &va_arg_type=dest.find(ID_C_va_arg_type); - - if(va_arg_type.is_not_nil() && - !replace_symbolt::replace(static_cast(dest.add(ID_C_va_arg_type)))) - result=false; - - return result; -} diff --git a/src/analyses/replace_symbol_ext.h b/src/analyses/replace_symbol_ext.h deleted file mode 100644 index 5a2152db17f..00000000000 --- a/src/analyses/replace_symbol_ext.h +++ /dev/null @@ -1,20 +0,0 @@ -/*******************************************************************\ - -Module: Modified expression replacement for constant propagator - -Author: Peter Schrammel - -\*******************************************************************/ - -#ifndef CPROVER_ANALYSES_REPLACE_SYMBOL_EXT_H -#define CPROVER_ANALYSES_REPLACE_SYMBOL_EXT_H - -#include - -class replace_symbol_extt:public replace_symbolt -{ -public: - virtual bool replace(exprt &dest) const; -}; - -#endif // CPROVER_ANALYSES_REPLACE_SYMBOL_EXT_H diff --git a/src/analyses/uninitialized_domain.h b/src/analyses/uninitialized_domain.h index 6ca27f341b0..7323f08af80 100644 --- a/src/analyses/uninitialized_domain.h +++ b/src/analyses/uninitialized_domain.h @@ -30,30 +30,42 @@ class uninitialized_domaint:public ai_domain_baset locationt from, locationt to, ai_baset &ai, - const namespacet &ns) final; + const namespacet &ns) final override; void output( std::ostream &out, const ai_baset &ai, const namespacet &ns) const final; - void make_top() final + void make_top() final override { uninitialized.clear(); has_values=tvt(true); } - void make_bottom() final + void make_bottom() final override { uninitialized.clear(); has_values=tvt(false); } - void make_entry() final + void make_entry() final override { make_top(); } + bool is_top() const override final + { + assert(!has_values.is_true() || uninitialized.empty()); + return has_values.is_true(); + } + + bool is_bottom() const override final + { + assert(!has_values.is_false() || uninitialized.empty()); + return has_values.is_false(); + } + // returns true iff there is s.th. new bool merge( const uninitialized_domaint &other, diff --git a/src/analyses/variable-sensitivity/abstract_enviroment.cpp b/src/analyses/variable-sensitivity/abstract_enviroment.cpp new file mode 100644 index 00000000000..b16e0602c69 --- /dev/null +++ b/src/analyses/variable-sensitivity/abstract_enviroment.cpp @@ -0,0 +1,717 @@ +/*******************************************************************\ + + Module: analyses variable-sensitivity + + Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "abstract_enviroment.h" + +#ifdef DEBUG +#include +#endif + +/*******************************************************************\ + +Function: abstract_environmentt::eval + + Inputs: + expr - the expression to evaluate + ns - the current namespace + + Outputs: The abstract_object representing the value of the expression + + Purpose: Evaluate the value of an expression relative to the current domain + +\*******************************************************************/ + +abstract_object_pointert abstract_environmentt::eval( + const exprt &expr, const namespacet &ns) const +{ + if(bottom) + return abstract_object_factory(expr.type(), ns, false, true); + + // first try to canonicalise, including constant folding + const exprt &simplified_expr=simplify_expr(expr, ns); + + const irep_idt simplified_id=simplified_expr.id(); + if(simplified_id==ID_symbol) + { + const symbol_exprt &symbol(to_symbol_expr(simplified_expr)); + const auto &symbol_entry=map.find(symbol); + if(symbol_entry==map.cend()) + { + return abstract_object_factory(simplified_expr.type(), ns, true); + } + else + { + abstract_object_pointert found_symbol_value=symbol_entry->second; + return found_symbol_value; + } + } + else if(simplified_id==ID_member) + { + member_exprt member_expr(to_member_expr(simplified_expr)); + + sharing_ptrt struct_abstract_object= + std::dynamic_pointer_cast( + eval(member_expr.compound(), ns)); + + return struct_abstract_object->read_component(*this, member_expr, ns); + } + else if(simplified_id==ID_address_of) + { + sharing_ptrt pointer_object= + std::dynamic_pointer_cast( + abstract_object_factory(simplified_expr.type(), simplified_expr, ns)); + + // Store the abstract object in the pointer + return pointer_object; + } + else if(simplified_id==ID_dereference) + { + dereference_exprt dereference(to_dereference_expr(simplified_expr)); + sharing_ptrt pointer_abstract_object= + std::dynamic_pointer_cast( + eval(dereference.pointer(), ns)); + + return pointer_abstract_object->read_dereference(*this, ns); + } + else if(simplified_id==ID_index) + { + index_exprt index_expr(to_index_expr(simplified_expr)); + sharing_ptrt array_abstract_object= + std::dynamic_pointer_cast( + eval(index_expr.array(), ns)); + + return array_abstract_object->read_index(*this, index_expr, ns); + } + else if(simplified_id==ID_array) + { + return abstract_object_factory(simplified_expr.type(), simplified_expr, ns); + } + else if(simplified_id==ID_constant) + { + return abstract_object_factory( + simplified_expr.type(), to_constant_expr(simplified_expr), ns); + } + else + { + // No special handling required by the abstract environment + // delegate to the abstract object + if(simplified_expr.operands().size()>0) + { + return eval_expression(simplified_expr, ns); + } + else + { + // It is important that this is top as the abstract object may not know + // how to handle the expression + return abstract_object_factory(simplified_expr.type(), ns, true); + } + } +} + +/*******************************************************************\ + +Function: abstract_environmentt::assign + + Inputs: + expr - the expression to assign to + value - the value to assign to the expression + ns - the namespace + + Outputs: A boolean, true if the assignment has changed the domain. + + Purpose: Assign a value to an expression + + Assign is in principe simple, it updates the map with the new + abstract object. The challenge is how to handle write to compound + objects, for example: + a[i].x.y = 23; + In this case we clearly want to update a, but we need to delegate to + the object in a so that it updates the right part of it (depending on + what kind of array abstraction it is). So, as we find the variable + ('a' in this case) we build a stack of which part of it is accessed. + + As abstractions may split the assignment into multiple write (for + example pointers that could point to several locations, arrays with + non-constant indexes), each of which has to handle the rest of the + compound write, thus the stack is passed (to write, which does the + actual updating) as an explicit argument rather than just via + recursion. + + The same use case (but for the opposite reason; because you will only + update one of the multiple objects) is also why a merge_write flag is + needed. +\*******************************************************************/ + +bool abstract_environmentt::assign( + const exprt &expr, const abstract_object_pointert value, const namespacet &ns) +{ + assert(value); + + if(value->is_bottom()) + { + bool bottom_at_start=this->is_bottom(); + this->make_bottom(); + return !bottom_at_start; + } + + abstract_object_pointert lhs_value=nullptr; + // Build a stack of index, member and dereference accesses which + // we will work through the relevant abstract objects + exprt s = expr; + std::stack stactions; // I'm not a continuation, honest guv' + while(s.id() != ID_symbol) + { + if(s.id() == ID_index || s.id() == ID_member || s.id() == ID_dereference) + { + stactions.push(s); + s = s.op0(); + } + else + { + lhs_value=eval(s, ns); + break; + } + } + + if(!lhs_value) + { + assert(s.id()==ID_symbol); + const symbol_exprt &symbol_expr(to_symbol_expr(s)); + if(map.find(symbol_expr)==map.end()) + { + lhs_value=abstract_object_factory( + symbol_expr.type(), ns, true, false); + } + else + { + lhs_value=map[symbol_expr]; + } + } + + abstract_object_pointert final_value; + + // This is the root abstract object that is in the map of abstract objects + // It might not have the same type as value if the above stack isn't empty + + + if(!stactions.empty()) + { + // The symbol is not in the map - it is therefore top + final_value=write(lhs_value, value, stactions, ns, false); + } + else + { + // If we don't have a symbol on the LHS, then we must have some expression + // that we can write to (i.e. a pointer, an array, a struct) This appears + // to be none of that. + if(s.id()!=ID_symbol) + { + throw "invalid l-value"; + } + // We can assign the AO directly to the symbol + final_value=value; + } + + const typet &lhs_type=ns.follow(lhs_value->type()); + const typet &rhs_type=ns.follow(final_value->type()); + + // Write the value for the root symbol back into the map + assert(lhs_type==rhs_type); + // If LHS was directly the symbol + if(s.id()==ID_symbol) + { + symbol_exprt symbol_expr=to_symbol_expr(s); + if(final_value->is_top()) + { + map.erase(symbol_expr); + } + else + { + map[symbol_expr]=final_value; + } + } + return true; +} + +/*******************************************************************\ + +Function: abstract_object_pointert abstract_environmentt::write + + Inputs: + lhs - the abstract object for the left hand side of the write (i.e. the one + to update). + rhs - the value we are trying to write to the left hand side + remaining_stack - what is left of the stack before the rhs can replace or be + merged with the rhs + ns - the namespace + merge_write - Are re replacing the left hand side with the right hand side + (e.g. we know for a fact that we are overwriting this object) + or could the write in fact not take place and therefore we + should merge to model the case where it did not. + + Outputs: A modified version of the rhs after the write has taken place + + Purpose: Write an abstract object onto another respecting a stack of + member, index and dereference access. This ping-pongs between + this method and the relevant write methods in abstract_struct, + abstract_pointer and abstract_array until the stack is empty + +\*******************************************************************/ + +abstract_object_pointert abstract_environmentt::write( + abstract_object_pointert lhs, + abstract_object_pointert rhs, + std::stack remaining_stack, + const namespacet &ns, + bool merge_write) +{ + assert(!remaining_stack.empty()); + const exprt & next_expr=remaining_stack.top(); + remaining_stack.pop(); + + const irep_idt &stack_head_id=next_expr.id(); + + // Each handler takes the abstract object referenced, copies it, + // writes according to the type of expression (e.g. for ID_member) + // we would (should!) have an abstract_struct_objectt which has a + // write_member which will attempt to update the abstract object for the + // relevant member. This modified abstract object is returned and this + // is inserted back into the map + if(stack_head_id==ID_index) + { + sharing_ptrt array_abstract_object= + std::dynamic_pointer_cast(lhs); + + sharing_ptrt modified_array= + array_abstract_object->write_index( + *this, ns, remaining_stack, to_index_expr(next_expr), rhs, merge_write); + + return modified_array; + } + else if(stack_head_id==ID_member) + { + sharing_ptrt struct_abstract_object= + std::dynamic_pointer_cast(lhs); + + const member_exprt next_member_expr(to_member_expr(next_expr)); + sharing_ptrt modified_struct= + struct_abstract_object->write_component( + *this, ns, remaining_stack, next_member_expr, rhs, merge_write); + + return modified_struct; + } + else if(stack_head_id==ID_dereference) + { + sharing_ptrt pointer_abstract_object= + std::dynamic_pointer_cast(lhs); + + sharing_ptrt modified_pointer= + pointer_abstract_object->write_dereference( + *this, ns, remaining_stack, rhs, merge_write); + + return modified_pointer; + } + else + { + assert(0); + return nullptr; + } +} + +/*******************************************************************\ + +Function: abstract_environmentt::assume + + Inputs: + expr - the expression that is to be assumed + ns - the current namespace + + Outputs: True if the assume changed the domain. + + Purpose: Reduces the domain to (an over-approximation) of the cases + when the the expression holds. Used to implement assume + statements and conditional branches. + +\*******************************************************************/ + +bool abstract_environmentt::assume(const exprt &expr, const namespacet &ns) +{ + // We should only attempt to assume Boolean things + // This should be enforced by the well-structured-ness of the + // goto-program and the way assume is used. + + assert(expr.type().id()==ID_bool); + + // Evaluate the expression + abstract_object_pointert res = eval(expr, ns); + + exprt possibly_constant = res->to_constant(); + + if(possibly_constant.id()!=ID_nil) // I.E. actually a value + { + // Should be of the right type + assert(possibly_constant.type().id()==ID_bool); + + if(possibly_constant.is_false()) + { + bool currently_bottom = is_bottom(); + make_bottom(); + return !currently_bottom; + } + } + + /* TODO : full implementation here + * Note that this is *very* syntax dependent so some normalisation would help + * 1. split up conjucts, handle each part separately + * 2. check how many variables the term contains + * 0 = this should have been simplified away + * 2+ = ignore as this is a non-relational domain + * 1 = extract the expression for the variable, + * care must be taken for things like a[i] + * which can be used if i can be resolved to a constant + * 3. use abstract_object_factory to build an abstract_objectt + * of the correct type (requires a little extension) + * This allows constant domains to handle x==23, + * intervals to handle x < 4, etc. + * 4. eval the current value of the variable + * 5. compute the meet (not merge!) of the two abstract_objectt's + * 6. assign the new value back to the environment. + */ + + return false; +} + + +/*******************************************************************\ + +Function: abstract_environmentt::abstract_object_factory + + Inputs: + type - the type of the object whose state should be tracked + top - does the type of the object start as top + bottom - does the type of the object start as bottom in the two-value domain + + Outputs: The abstract object that has been created + + Purpose: Look at the configuration for the sensitivity and create an + appropriate abstract_object + +\*******************************************************************/ + +abstract_object_pointert abstract_environmentt::abstract_object_factory( + const typet &type, const namespacet &ns, bool top, bool bottom) const +{ + exprt empty_constant_expr=exprt(); + return abstract_object_factory( + type, top, bottom, empty_constant_expr, *this, ns); +} + +/*******************************************************************\ + +Function: abstract_environmentt::abstract_object_factory + + Inputs: + type - the type of the object whose state should be tracked + expr - the starting value of the symbol + + Outputs: The abstract object that has been created + + Purpose: Look at the configuration for the sensitivity and create an + appropriate abstract_object, assigning an appropriate value + +\*******************************************************************/ + +abstract_object_pointert abstract_environmentt::abstract_object_factory( + const typet &type, const exprt &e, const namespacet &ns) const +{ + return abstract_object_factory(type, false, false, e, *this, ns); +} + +/*******************************************************************\ + +Function: abstract_environmentt::abstract_object_factory + + Inputs: + type - the type of the object whose state should be tracked + top - does the type of the object start as top in the two-value domain + bottom - does the type of the object start as bottom in the two-value domain + expr - the starting value of the symbol if top and bottom are both false + + Outputs: The abstract object that has been created + + Purpose: Look at the configuration for the sensitivity and create an + appropriate abstract_object + +\*******************************************************************/ + +abstract_object_pointert abstract_environmentt::abstract_object_factory( + const typet &type, bool top, bool bottom, const exprt &e, + const abstract_environmentt &environment, const namespacet &ns) const +{ + return variable_sensitivity_object_factoryt::instance().get_abstract_object( + type, top, bottom, e, environment, ns); +} + +/*******************************************************************\ + +Function: abstract_environmentt::merge + + Inputs: + env - the other environment + + Outputs: A Boolean, true when the merge has changed something + + Purpose: Computes the join between "this" and "b" + +\*******************************************************************/ + +bool abstract_environmentt::merge(const abstract_environmentt &env) +{ + // Use the sharing_map's "iterative over all differences" functionality + // This should give a significant performance boost + // We can strip down to just the things that are in both + + // for each entry in the incoming environment we need to either add it + // if it is new, or merge with the existing key if it is not present + + if(bottom) + { + *this=env; + return !env.bottom; + } + else if(env.bottom) + { + return false; + } + else + { + // For each element in the intersection of map and env.map merge + // If the result of the merge is top, remove from the map + bool modified=false; + for(const auto &entry : env.map) + { + if(map.find(entry.first)!=map.end()) + { + bool object_modified=false; + abstract_object_pointert new_object= + abstract_objectt::merge( + map[entry.first], + entry.second, + object_modified); + + modified|=object_modified; + map[entry.first]=new_object; + + if(map[entry.first]->is_top()) + { + map.erase(entry.first); + modified=true; +#ifdef DEBUG + std::cout << "Removing " << entry.first.get_identifier() << std::endl; +#endif + } + } + else + { + // Map doesn't contain key so the resulting map shouldn't either + } + } + + // Remove all elements from the map that are not present in the map we are + // merging in since they must be top + const auto &end_iter=map.end(); + for(auto iter=map.begin(); iter!=end_iter;) + { + if(env.map.find(iter->first)==env.map.cend()) + { + // After calling erase, the iterator is no longer valid, so we increment + // the iterator first and return a copy of the original iterator + map.erase(iter++); + modified=true; + +#ifdef DEBUG + std::cout << "Removing " << iter->first.get_identifier() << std::endl; +#endif + } + else + { + ++iter; + } + } + + return modified; + } +} + +/*******************************************************************\ + +Function: abstract_environmentt::havoc + + Inputs: + havoc_string - diagnostic string to track down havoc causing. + + Outputs: None + + Purpose: Set the domain to top + +\*******************************************************************/ + +void abstract_environmentt::havoc(const std::string &havoc_string) +{ + // TODO(tkiley): error reporting + make_top(); +} + +/*******************************************************************\ + +Function: abstract_environmentt::make_top + + Inputs: None + + Outputs: None + + Purpose: Set the domain to top + +\*******************************************************************/ + +void abstract_environmentt::make_top() +{ + // since we assume anything is not in the map is top this is sufficient + map.clear(); + bottom=false; +} + +/*******************************************************************\ + +Function: abstract_environmentt::make_bottom + + Inputs: None + + Outputs: None + + Purpose: Set the domain to top + +\*******************************************************************/ + +void abstract_environmentt::make_bottom() +{ + map.clear(); + bottom=true; +} + +/*******************************************************************\ + +Function: abstract_environmentt::is_bottom + + Inputs: + + Outputs: + + Purpose: Gets whether the domain is bottom + +\*******************************************************************/ + +bool abstract_environmentt::is_bottom() const +{ + return map.empty() && bottom; +} + +/*******************************************************************\ + +Function: abstract_environmentt::is_top + + Inputs: + + Outputs: + + Purpose: Gets whether the domain is top + +\*******************************************************************/ + +bool abstract_environmentt::is_top() const +{ + return map.empty() && !bottom; +} + +/*******************************************************************\ + +Function: abstract_environmentt::output + + Inputs: + out - the stream to write to + ai - the abstract interpreter that contains this domain + ns - the current namespace + + Outputs: None + + Purpose: Print out all the values in the abstract object map + +\*******************************************************************/ + +void abstract_environmentt::output( + std::ostream &out, + const ai_baset &ai, + const namespacet &ns) const +{ + out << "{\n"; + + for(const auto &entry : map) + { + out << entry.first.get_identifier() + << " (" << ") -> "; + entry.second->output(out, ai, ns); + out << "\n"; + } + out << "}\n"; +} + +/*******************************************************************\ + +Function: abstract_environmentt::verify + + Inputs: + + Outputs: + + Purpose: Check there aren't any null pointer mapped values + +\*******************************************************************/ + +bool abstract_environmentt::verify() const +{ + for(const auto &entry : map) + { + if(!entry.second) + { + return false; + } + } + return true; +} + +abstract_object_pointert abstract_environmentt::eval_expression( + const exprt &e, const namespacet &ns) const +{ + // Delegate responsibility of resolving to a boolean abstract object + // to the abstract object being compared against + abstract_object_pointert eval_obj=abstract_object_factory(e.type(), e, ns); + return eval_obj->expression_transform(e, *this, ns); +} diff --git a/src/analyses/variable-sensitivity/abstract_enviroment.h b/src/analyses/variable-sensitivity/abstract_enviroment.h new file mode 100644 index 00000000000..bd6e9c0fdb0 --- /dev/null +++ b/src/analyses/variable-sensitivity/abstract_enviroment.h @@ -0,0 +1,88 @@ +/*******************************************************************\ + + Module: analyses variable-sensitivity + + Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ + +#ifndef CPROVER_ANALYSES_VARIABLE_SENSITIVITY_ABSTRACT_ENVIROMENT_H +#define CPROVER_ANALYSES_VARIABLE_SENSITIVITY_ABSTRACT_ENVIROMENT_H + +#include +#include +#include +#include + +#include +#include +#include + +class abstract_environmentt +{ +public: + // These three are really the heart of the method + virtual abstract_object_pointert eval( + const exprt &expr, const namespacet &ns) const; + virtual bool assign( + const exprt &expr, + const abstract_object_pointert value, + const namespacet &ns); + virtual bool assume(const exprt &expr, const namespacet &ns); + + virtual abstract_object_pointert write( + abstract_object_pointert lhs, + abstract_object_pointert rhs, + std::stack remaining_stack, + const namespacet &ns, + bool merge_write); + + virtual abstract_object_pointert abstract_object_factory( + const typet &type, + const namespacet &ns, + bool top=true, + bool bottom=false) const; + // For converting constants in the program + // Maybe these two should be compacted to one call... + virtual abstract_object_pointert abstract_object_factory( + const typet &type, const exprt &e, const namespacet &ns) const; + + virtual bool merge(const abstract_environmentt &env); + + // This should be used as a default case / everything else has failed + // The string is so that I can easily find and diagnose cases where this + // occurs + virtual void havoc(const std::string &havoc_string); + + void make_top(); + void make_bottom(); + + bool is_bottom() const; + bool is_top() const; + + void output( + std::ostream &out, const class ai_baset &ai, const namespacet &ns) const; + + bool verify() const; + +protected: + bool bottom; + + // We may need to break out more of these cases into these + virtual abstract_object_pointert eval_expression( + const exprt &e, const namespacet &ns) const; + + typedef symbol_exprt map_keyt; + std::map map; + +private: + abstract_object_pointert abstract_object_factory( + const typet &type, + bool top, + bool bottom, + const exprt &e, + const abstract_environmentt &eviroment, + const namespacet &ns) const; +}; + +#endif // CPROVER_ANALYSES_VARIABLE_SENSITIVITY_ABSTRACT_ENVIROMENT_H diff --git a/src/analyses/variable-sensitivity/abstract_object.cpp b/src/analyses/variable-sensitivity/abstract_object.cpp new file mode 100644 index 00000000000..15b21f6c27a --- /dev/null +++ b/src/analyses/variable-sensitivity/abstract_object.cpp @@ -0,0 +1,335 @@ +/*******************************************************************\ + + Module: analyses variable-sensitivity + + Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ + +#include + +#include +#include + +#include +#include +#include +#include + +#include "abstract_object.h" + +/*******************************************************************\ + +Function: abstract_objectt::abstract_objectt + + Inputs: + type - the type the abstract_object is representing + + Outputs: + + Purpose: + +\*******************************************************************/ + +abstract_objectt::abstract_objectt(const typet &type): +t(type), bottom(false), top(true) +{} + +/*******************************************************************\ + +Function: abstract_objectt::abstract_objectt + + Inputs: + type - the type the abstract_object is representing + top - is the abstract_object starting as top + bottom - is the abstract_object starting as bottom + + Outputs: + + Purpose: Start the abstract object at either top or bottom or neither + Asserts if both top and bottom are true + +\*******************************************************************/ + +abstract_objectt::abstract_objectt(const typet &type, bool top, bool bottom): + t(type), bottom(bottom), top(top) +{ + assert(!(top && bottom)); +} + +/*******************************************************************\ + +Function: abstract_objectt::abstract_objectt + + Inputs: + expr - the expression to use as the starting pointer for an abstract object + environment - The environment this abstract object is being created in + ns - the namespace + + Outputs: + + Purpose: Construct an abstract object from the expression + +\*******************************************************************/ + +abstract_objectt::abstract_objectt( + const exprt &expr, + const abstract_environmentt &environment, + const namespacet &ns): + t(expr.type()), bottom(false), top(true) +{} + +/*******************************************************************\ + +Function: abstract_objectt::type + + Inputs: + + Outputs: The program type this abstract object represents + + Purpose: Get the real type of the variable this abstract object is + representing. + +\*******************************************************************/ +const typet &abstract_objectt::type() const +{ + return t; +} + +/*******************************************************************\ + +Function: abstract_objectt::merge + + Inputs: + other - The object to merge with this + + Outputs: Returns the result of the merge. + + Purpose: Create a new abstract object that is the result of the merge, unless + the object would be unchanged, then would return itself. + +\*******************************************************************/ + +abstract_object_pointert abstract_objectt::merge( + abstract_object_pointert other) const +{ + return abstract_object_merge(other); +} + +/*******************************************************************\ + +Function: abstract_objectt::abstract_object_merge + + Inputs: + other - The object to merge with this + + Outputs: Returns the result of the abstract object. + + Purpose: Create a new abstract object that is the result of the merge, unless + the object would be unchanged, then would return itself. + +\*******************************************************************/ + +abstract_object_pointert abstract_objectt::abstract_object_merge( + const abstract_object_pointert other) const +{ + if(top) + return shared_from_this(); + if(other->bottom) + return shared_from_this(); + + + internal_abstract_object_pointert merged=mutable_clone(); + merged->top=true; + merged->bottom=false; + return merged; +} + +/*******************************************************************\ + +Function: abstract_objectt::expression_transform + + Inputs: + expr - the expression to evaluate and find the result of it. this will + be the symbol referred to be op0() + + Outputs: Returns the abstract_object representing the result of this expression + to the maximum precision available. + + Purpose: To try and resolve different expressions with the maximum level + of precision available. + +\*******************************************************************/ + +abstract_object_pointert abstract_objectt::expression_transform( + const exprt &expr, + const abstract_environmentt &environment, + const namespacet &ns) const +{ + exprt constant_replaced_expr=expr; + constant_replaced_expr.operands().clear(); + for(const exprt &op : expr.operands()) + { + abstract_object_pointert lhs_abstract_object=environment.eval(op, ns); + const exprt &lhs_value=lhs_abstract_object->to_constant(); + + if(lhs_value.is_nil()) + { + // One of the values is not resolvable to a constant + // so we can't really do anything more with + // this expression and should just return top for the result + return environment.abstract_object_factory(expr.type(), ns, true, false); + } + else + { + // rebuild the operands list with constant versions of + // any symbols + constant_replaced_expr.operands().push_back(lhs_value); + } + } + + exprt simplified=simplify_expr(constant_replaced_expr, ns); + return environment.abstract_object_factory(simplified.type(), simplified, ns); +} + +/*******************************************************************\ + +Function: abstract_objectt::is_top + + Inputs: + + Outputs: Returns true if the abstract object is representing the top (i.e. we + don't know anything about the value). + + Purpose: Find out if the abstract object is top + +\*******************************************************************/ + +bool abstract_objectt::is_top() const +{ + return top; +} + +/*******************************************************************\ + +Function: abstract_objectt::is_bottom + + Inputs: + + Outputs: Returns true if the abstract object is representing the bottom. + + Purpose: Find out if the abstract object is bottom + +\*******************************************************************/ + +bool abstract_objectt::is_bottom() const +{ + return bottom; +} + +/*******************************************************************\ + +Function: abstract_objectt::to_constant + + Inputs: + + Outputs: Returns an exprt representing the value if the value is known and + constant. Otherwise returns the nil expression + + Purpose: If abstract element represents a single value, then that value, + otherwise nil. E.G. if it is an interval then this will be x if it is + [x,x] This is the (sort of) dual to the constant_exprt constructor + that allows an object to be built from a value. + +\*******************************************************************/ + +exprt abstract_objectt::to_constant() const +{ + return nil_exprt(); +} + +/*******************************************************************\ + +Function: abstract_objectt::output + + Inputs: + out - the stream to write to + ai - the abstract interpreter that contains the abstract domain + (that contains the object ... ) + ns - the current namespace + + Outputs: + + Purpose: Print the value of the abstract object + +\*******************************************************************/ + +void abstract_objectt::output( + std::ostream &out, const ai_baset &ai, const namespacet &ns) const +{ + if(top) + { + out << "TOP"; + } + else if(bottom) + { + out << "BOTTOM"; + } + else + { + out << "Unknown"; + } +} + +/*******************************************************************\ + +Function: abstract_objectt::merge + + Inputs: + op1 - the first abstract object to merge, this object determines + the sensitivity of the output and is the object compared against + to choose whether this merge changed anything + op2 - the second abstract object to merge + + Outputs: The merged abstract object with the same sensitivity as the + first parameter. out_modifications will be true if the resulting + abstract object is different from op1 + + Purpose: Clones the first parameter and merges it with the second. + + +\*******************************************************************/ + +abstract_object_pointert abstract_objectt::merge( + abstract_object_pointert op1, + abstract_object_pointert op2, + bool &out_modifications) +{ + abstract_object_pointert result=op1->should_use_base_merge(op2)? + op1->abstract_object_merge(op2):op1->merge(op2); + // If no modifications, we will return the original pointer + out_modifications=result!=op1; + return result; +} + +/*******************************************************************\ + +Function: abstract_objectt::should_use_base_merge + + Inputs: + other - the object being merged with + + Outputs: Returns true if the base class is capable of doing a complete merge + + Purpose: To detect the cases where the base merge is sufficient to do a merge + We can't do if this->is_bottom() since we want the specific + +\*******************************************************************/ + +bool abstract_objectt::should_use_base_merge( + const abstract_object_pointert other) const +{ + return is_top() || other->is_bottom() || other->is_top(); +} + + diff --git a/src/analyses/variable-sensitivity/abstract_object.h b/src/analyses/variable-sensitivity/abstract_object.h new file mode 100644 index 00000000000..4eaf850d472 --- /dev/null +++ b/src/analyses/variable-sensitivity/abstract_object.h @@ -0,0 +1,194 @@ +/*******************************************************************\ + + Module: analyses variable-sensitivity + + Author: Thomas Kiley, thomas.kiley@diffblue.com + + abstract_objectt is the top of the inheritance heirarchy of objects + used to represent individual variables in the general non-relational + domain. It is a two element abstraction (i.e. it is either top or + bottom). Within the hierachy of objects under it, child classes are + more precise abstractions (the converse doesn't hold to avoid + diamonds and inheriting unnecessary fields). Thus the common parent + of two classes is an abstraction capable of representing both. This + is important for understanding merge. + + These objects are intended to be used in a copy-on-write style, which + is why their interface differs a bit from ai_domain_baset's + modify-in-place style of interface. + + Although these can represent bottom (this variable cannot take any + value) it is not common for them to do so. + +\*******************************************************************/ +#ifndef CPROVER_ANALYSES_VARIABLE_SENSITIVITY_ABSTRACT_OBJECT_H +#define CPROVER_ANALYSES_VARIABLE_SENSITIVITY_ABSTRACT_OBJECT_H + + + +#include +#include +#include +#include + +#include + +class typet; +class constant_exprt; +class abstract_environmentt; +class namespacet; + + +#define CLONE \ + virtual internal_abstract_object_pointert mutable_clone() const override \ + { \ + typedef std::remove_const::type \ + >::type current_typet; \ + return internal_abstract_object_pointert(new current_typet(*this)); \ + } \ + + +/* Merge is designed to allow different abstractions to be merged + * gracefully. There are two real use-cases for this: + * + * 1. Having different abstractions for the variable in different + * parts of the program. + * 2. Allowing different domains to write to ambiguous locations + * for example, if a stores multiple values (maybe one per + * location) with a constant for each, i does not represent one + * single value (top, non-unit interval, etc.) and v is something + * other than constant, then + * a[i] = v + * will cause this to happen. + * + * To handle this, merge is dispatched to the first abstract object being + * merged, which switches based on the type of the other object. If it can + * merge then it merges, otherwise it calls the parent merge. + */ + +template +using sharing_ptrt=std::shared_ptr; // NOLINT(*) + +typedef sharing_ptrt abstract_object_pointert; + +class abstract_objectt:public std::enable_shared_from_this +{ +public: + explicit abstract_objectt(const typet &type); + abstract_objectt(const typet &type, bool top, bool bottom); + abstract_objectt( + const exprt &expr, + const abstract_environmentt &environment, + const namespacet &ns); + + virtual ~abstract_objectt() {} + + const typet &type() const; + virtual bool is_top() const; + virtual bool is_bottom() const; + + // Interface for transforms + abstract_object_pointert expression_transform( + const exprt &expr, + const abstract_environmentt &environment, + const namespacet &ns) const; + + virtual exprt to_constant() const; + + virtual void output( + std::ostream &out, const class ai_baset &ai, const namespacet &ns) const; + + abstract_object_pointert clone() const + { + return abstract_object_pointert(mutable_clone()); + } + + static abstract_object_pointert merge( + abstract_object_pointert op1, + abstract_object_pointert op2, + bool &out_modifications); + +private: + // To enforce copy-on-write these are private and have read-only accessors + typet t; + bool bottom; + + abstract_object_pointert abstract_object_merge( + const abstract_object_pointert other) const; +protected: + template + using internal_sharing_ptrt=std::shared_ptr; + + typedef internal_sharing_ptrt + internal_abstract_object_pointert; + + // Macro is not used as this does not override + virtual internal_abstract_object_pointert mutable_clone() const + { + return internal_abstract_object_pointert(new abstract_objectt(*this)); + } + + bool top; + + // The one exception is merge in descendant classes, which needs this + void make_top() { top=true; } + + bool should_use_base_merge(const abstract_object_pointert other) const; + + // Sets the state of this object + virtual abstract_object_pointert merge(abstract_object_pointert other) const; + + template + static bool merge_maps( + const std::map &map1, + const std::map &map2, + std::map &out_map); +}; + +template +bool abstract_objectt::merge_maps( + const std::map &m1, + const std::map &m2, + std::map &out_map) +{ + out_map.clear(); + + typedef std::map abstract_object_mapt; + + bool modified=false; + + std::vector> intersection_set; + std::set_intersection( + m1.cbegin(), + m1.cend(), + m2.cbegin(), + m2.cend(), + std::back_inserter(intersection_set), + []( + const std::pair &op1, + const std::pair &op2) + { + return op1.first < op2.first; + }); + + for(const typename abstract_object_mapt::value_type &entry : intersection_set) + { + // merge entries + + const abstract_object_pointert &v1=m1.at(entry.first); + const abstract_object_pointert &v2=m2.at(entry.first); + + bool changes=false; + abstract_object_pointert v_new=abstract_objectt::merge(v1, v2, changes); + + + modified|=changes; + + out_map[entry.first]=v_new; + } + + return modified; +} + + +#endif // CPROVER_ANALYSES_VARIABLE_SENSITIVITY_ABSTRACT_OBJECT_H diff --git a/src/analyses/variable-sensitivity/abstract_value.cpp b/src/analyses/variable-sensitivity/abstract_value.cpp new file mode 100644 index 00000000000..6a2f75a8c55 --- /dev/null +++ b/src/analyses/variable-sensitivity/abstract_value.cpp @@ -0,0 +1,73 @@ +/*******************************************************************\ + + Module: Analyses Variable Sensitivity + + Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ + +#include +#include +#include +#include + +#include "abstract_value.h" + +/*******************************************************************\ + +Function: abstract_valuet::abstract_valuet + + Inputs: + type - the type the abstract_value is representing + + Outputs: + + Purpose: + +\*******************************************************************/ + +abstract_valuet::abstract_valuet(const typet &type): + abstract_objectt(type) +{} + +/*******************************************************************\ + +Function: abstract_valuet::abstract_valuet + + Inputs: + type - the type the abstract_value is representing + top - is the abstract_value starting as top + bottom - is the abstract_value starting as bottom + + Outputs: + + Purpose: Start the abstract object at either top or bottom or neither + Asserts if both top and bottom are true + +\*******************************************************************/ + +abstract_valuet::abstract_valuet(const typet &type, bool top, bool bottom): + abstract_objectt(type, top, bottom) +{} + +/*******************************************************************\ + +Function: abstract_valuet::abstract_valuet + + Inputs: + expr - the expression to use as the starting pointer for an abstract object + environment - The environment this abstract object is being created in + ns - the namespace + + Outputs: + + Purpose: Construct an abstract value from the expression + +\*******************************************************************/ + +abstract_valuet::abstract_valuet( + const exprt &expr, + const abstract_environmentt &environment, + const namespacet &ns): + abstract_objectt(expr, environment, ns) +{} diff --git a/src/analyses/variable-sensitivity/abstract_value.h b/src/analyses/variable-sensitivity/abstract_value.h new file mode 100644 index 00000000000..6f4ab8374c0 --- /dev/null +++ b/src/analyses/variable-sensitivity/abstract_value.h @@ -0,0 +1,30 @@ +/*******************************************************************\ + + Module: Analyses Variable Sensitivity + + Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ +#ifndef CPROVER_ANALYSES_VARIABLE_SENSITIVITY_ABSTRACT_VALUE_H +#define CPROVER_ANALYSES_VARIABLE_SENSITIVITY_ABSTRACT_VALUE_H + +#include + + +class abstract_valuet:public abstract_objectt +{ +public: + explicit abstract_valuet(const typet &type); + abstract_valuet(const typet &type, bool top, bool bottom); + abstract_valuet( + const exprt &expr, + const abstract_environmentt &environment, + const namespacet &ns); + + virtual ~abstract_valuet() {} + +protected: + CLONE +}; + +#endif // CPROVER_ANALYSES_VARIABLE_SENSITIVITY_ABSTRACT_VALUE_H diff --git a/src/analyses/variable-sensitivity/array_abstract_object.cpp b/src/analyses/variable-sensitivity/array_abstract_object.cpp new file mode 100644 index 00000000000..7e7d334cdac --- /dev/null +++ b/src/analyses/variable-sensitivity/array_abstract_object.cpp @@ -0,0 +1,152 @@ +/*******************************************************************\ + + Module: analyses variable-sensitivity + + Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ + +#include +#include +#include +#include "array_abstract_object.h" + + +/*******************************************************************\ + +Function: array_abstract_objectt::array_abstract_objectt + + Inputs: + type - the type the abstract_object is representing + + Outputs: + + Purpose: + +\*******************************************************************/ + +array_abstract_objectt::array_abstract_objectt(const typet &t): + abstract_objectt(t) +{ + assert(t.id()==ID_array); +} + +/*******************************************************************\ + +Function: array_abstract_objectt::array_abstract_objectt + + Inputs: + type - the type the abstract_object is representing + top - is the abstract_object starting as top + bottom - is the abstract_object starting as bottom + + Outputs: + + Purpose: Start the abstract object at either top or bottom or neither + Asserts if both top and bottom are true + +\*******************************************************************/ + +array_abstract_objectt::array_abstract_objectt( + const typet &t, bool tp, bool bttm): + abstract_objectt(t, tp, bttm) +{ + assert(t.id()==ID_array); +} + +/*******************************************************************\ + +Function: array_abstract_objectt::array_abstract_objectt + + Inputs: + expr - the expression to use as the starting pointer for an abstract object + environment - the environment the abstract object is being created in + ns - the namespace + + Outputs: + + Purpose: + +\*******************************************************************/ + +array_abstract_objectt::array_abstract_objectt( + const exprt &e, + const abstract_environmentt &environment, + const namespacet &ns): + abstract_objectt(e, environment, ns) +{ + assert(e.type().id()==ID_array); +} + +/*******************************************************************\ + +Function: array_abstract_objectt::read_index + + Inputs: + env - the environment + index - the expression used to access the specific value in the array + + Outputs: An abstract object representing the value in the array + + Purpose: A helper function to read elements from an array. More precise + abstractions may override this to provide more precise results. + +\*******************************************************************/ + +abstract_object_pointert array_abstract_objectt::read_index( + const abstract_environmentt &env, + const index_exprt &index, + const namespacet& ns) const +{ + array_typet array_type(to_array_type(type())); + const typet &subtype=array_type.subtype(); + + // if we are bottom then so are the values in the array + // otherwise the values are top + return env.abstract_object_factory(subtype, ns, !is_bottom(), is_bottom()); +} + +/*******************************************************************\ + +Function: array_abstract_objectt::write_index + + Inputs: + environment - the abstract environment + ns - the namespace + stack - the remaining stack of expressions on the LHS to evaluate + index_expr - the expression uses to access a specific index + value - the value we are trying to assign to that value in the array + merging_write - ? + + Outputs: The struct_abstract_objectt representing the result of writing + to a specific component. In this case this will always be top + as we are not tracking the value of this struct. + + Purpose: A helper function to evaluate writing to a component of a struct. + More precise abstractions may override this to + update what they are storing for a specific component. + +\*******************************************************************/ + +sharing_ptrt array_abstract_objectt::write_index( + abstract_environmentt &environment, + const namespacet &ns, + const std::stack stack, + const index_exprt &index_expr, + const abstract_object_pointert value, + bool merging_write) const +{ + // TODO(tkiley): Should this in fact havoc since we can't verify + // that we are not writing past the end of the array - Martin said + // default should be not to, but perhaps for soundness the base class should + // havoc and the default should derive from this. + if(is_top() || is_bottom()) + { + return std::dynamic_pointer_cast(clone()); + } + else + { + return sharing_ptrt( + new array_abstract_objectt(type(), true, false)); + } +} diff --git a/src/analyses/variable-sensitivity/array_abstract_object.h b/src/analyses/variable-sensitivity/array_abstract_object.h new file mode 100644 index 00000000000..8bc29db4b2c --- /dev/null +++ b/src/analyses/variable-sensitivity/array_abstract_object.h @@ -0,0 +1,46 @@ +/*******************************************************************\ + + Module: analyses variable-sensitivity + + Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ +#ifndef CPROVER_ANALYSES_VARIABLE_SENSITIVITY_ARRAY_ABSTRACT_OBJECT_H +#define CPROVER_ANALYSES_VARIABLE_SENSITIVITY_ARRAY_ABSTRACT_OBJECT_H + +#include +#include + +class abstract_environmentt; +class index_exprt; + + + +class array_abstract_objectt:public abstract_objectt +{ +public: + explicit array_abstract_objectt(const typet &type); + array_abstract_objectt(const typet &type, bool top, bool bottom); + explicit array_abstract_objectt( + const exprt &expr, + const abstract_environmentt &environment, + const namespacet &ns); + + virtual abstract_object_pointert read_index( + const abstract_environmentt &env, + const index_exprt &index, + const namespacet &ns) const; + + virtual sharing_ptrt write_index( + abstract_environmentt &environment, + const namespacet &ns, + const std::stack stack, + const index_exprt &index_expr, + const abstract_object_pointert value, + bool merging_write) const; + +protected: + CLONE +}; + +#endif // CPROVER_ANALYSES_VARIABLE_SENSITIVITY_ARRAY_ABSTRACT_OBJECT_H diff --git a/src/analyses/variable-sensitivity/constant_abstract_value.cpp b/src/analyses/variable-sensitivity/constant_abstract_value.cpp new file mode 100644 index 00000000000..53ce145f3cd --- /dev/null +++ b/src/analyses/variable-sensitivity/constant_abstract_value.cpp @@ -0,0 +1,120 @@ +/*******************************************************************\ + + Module: analyses variable-sensitivity + + Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ + +#include + +#include + +#include "constant_abstract_value.h" + +constant_abstract_valuet::constant_abstract_valuet(typet t): + abstract_valuet(t), value() +{} + +constant_abstract_valuet::constant_abstract_valuet(typet t, bool tp, bool bttm): + abstract_valuet(t, tp, bttm), value() +{} + +constant_abstract_valuet::constant_abstract_valuet( + const exprt e, + const abstract_environmentt &environment, + const namespacet &ns): + abstract_valuet(e.type(), false, false), value(e) +{} + +exprt constant_abstract_valuet::to_constant() const +{ + if(!is_top() && !is_bottom()) + { + return this->value; + } + else + { + return abstract_objectt::to_constant(); + } +} + +void constant_abstract_valuet::output( + std::ostream &out, const ai_baset &ai, const namespacet &ns) const +{ + if(!is_top() && !is_bottom()) + { + out << to_constant_expr(value).get_value(); + } + else + { + abstract_objectt::output(out, ai, ns); + } +} + +/*******************************************************************\ + +Function: constant_abstract_valuet::merge + + Inputs: + other - the abstract object to merge with + + Outputs: Returns the result of the merge + + Purpose: Attempts to do a constant/constant merge if both are constants, + otherwise falls back to the parent merge + + +\*******************************************************************/ + +abstract_object_pointert constant_abstract_valuet::merge( + abstract_object_pointert other) const +{ + constant_abstract_value_pointert cast_other= + std::dynamic_pointer_cast(other); + if(cast_other) + { + return merge_constant_constant(cast_other); + } + else + { + // TODO(tkiley): How do we set the result to be toppish? Does it matter? + return abstract_valuet::merge(other); + } +} + +/*******************************************************************\ + +Function: constant_abstract_valuet::merge_constant_constant + + Inputs: + other - the abstract object to merge with + + Outputs: Returns a new abstract object that is the result of the merge + unless the merge is the same as this abstract object, in which + case it returns this. + + Purpose: Merges another constant abstract value into this one + +\*******************************************************************/ + +abstract_object_pointert constant_abstract_valuet::merge_constant_constant( + constant_abstract_value_pointert other) const +{ + if(is_bottom()) + { + return std::make_shared(*other); + } + else + { + // Can we actually merge these value + if(value==other->value) + { + return shared_from_this(); + } + else + { + return abstract_valuet::merge(other); + } + } +} diff --git a/src/analyses/variable-sensitivity/constant_abstract_value.h b/src/analyses/variable-sensitivity/constant_abstract_value.h new file mode 100644 index 00000000000..752b48734b4 --- /dev/null +++ b/src/analyses/variable-sensitivity/constant_abstract_value.h @@ -0,0 +1,51 @@ +/*******************************************************************\ + + Module: analyses variable-sensitivity + + Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ +#ifndef CPROVER_ANALYSES_VARIABLE_SENSITIVITY_CONSTANT_ABSTRACT_VALUE_H +#define CPROVER_ANALYSES_VARIABLE_SENSITIVITY_CONSTANT_ABSTRACT_VALUE_H + +#include + +#include +#include + +class constant_abstract_valuet:public abstract_valuet +{ +private: + typedef sharing_ptrt + constant_abstract_value_pointert; + +public: + explicit constant_abstract_valuet(typet t); + constant_abstract_valuet(typet t, bool tp, bool bttm); + constant_abstract_valuet( + const exprt e, + const abstract_environmentt &environment, + const namespacet &ns); + + virtual ~constant_abstract_valuet() {} + + virtual exprt to_constant() const override; + + virtual void output( + std::ostream &out, + const class ai_baset &ai, + const class namespacet &ns) const override; + +protected: + CLONE + virtual abstract_object_pointert merge( + abstract_object_pointert other) const override; + +private : + abstract_object_pointert merge_constant_constant( + constant_abstract_value_pointert other) const; + + exprt value; +}; + +#endif // CPROVER_ANALYSES_VARIABLE_SENSITIVITY_CONSTANT_ABSTRACT_VALUE_H diff --git a/src/analyses/variable-sensitivity/constant_array_abstract_object.cpp b/src/analyses/variable-sensitivity/constant_array_abstract_object.cpp new file mode 100644 index 00000000000..c9b427e3eb1 --- /dev/null +++ b/src/analyses/variable-sensitivity/constant_array_abstract_object.cpp @@ -0,0 +1,419 @@ +/*******************************************************************\ + + Module: Variable Sensitivity + + Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ +#include + +#include +#include +#include +#include + +#include "constant_array_abstract_object.h" + +/*******************************************************************\ + +Function: constant_array_abstract_objectt::constant_array_abstract_objectt + + Inputs: + type - the type the abstract_object is representing + + Outputs: + + Purpose: + +\*******************************************************************/ + +constant_array_abstract_objectt::constant_array_abstract_objectt(typet type): +array_abstract_objectt(type) +{} + +/*******************************************************************\ + +Function: constant_array_abstract_objectt::constant_array_abstract_objectt + + Inputs: + type - the type the abstract_object is representing + top - is the abstract_object starting as top + bottom - is the abstract_object starting as bottom + + Outputs: + + Purpose: Start the abstract object at either top or bottom or neither + Asserts if both top and bottom are true + +\*******************************************************************/ + +constant_array_abstract_objectt::constant_array_abstract_objectt( + typet type, bool top, bool bottom): +array_abstract_objectt(type, top, bottom) +{} + +/*******************************************************************\ + +Function: constant_array_abstract_objectt::constant_array_abstract_objectt + + Inputs: + expr - the expression to use as the starting pointer for an abstract object + environment - the environment the abstract object is being created in + ns - the namespace + + Outputs: + + Purpose: + +\*******************************************************************/ + +constant_array_abstract_objectt::constant_array_abstract_objectt( + const exprt &expr, + const abstract_environmentt &environment, + const namespacet &ns): + array_abstract_objectt(expr, environment, ns) +{ + if(expr.id()==ID_array) + { + int index=0; + for(const exprt &entry : expr.operands()) + { + map[mp_integer(index)]=environment.eval(entry, ns); + ++index; + } + top=false; + } +} + +/*******************************************************************\ + +Function: constant_array_abstract_objectt::merge + + Inputs: + other - The object to merge in + + Outputs: Returns the result of the merge. + + Purpose: Tries to do an array/array merge if merging with a constant array + If it can't, falls back to parent merge + +\*******************************************************************/ + +abstract_object_pointert constant_array_abstract_objectt::merge( + abstract_object_pointert other) const +{ + auto cast_other= + std::dynamic_pointer_cast(other); + if(cast_other) + { + return constant_array_merge(cast_other); + } + else + { + // TODO(tkiley): How do we set the result to be toppish? Does it matter? + return array_abstract_objectt::merge(other); + } +} + +/*******************************************************************\ + +Function: constant_array_abstract_objectt::constant_array_merge + + Inputs: + other - The object to merge in + + Outputs: Returns a new abstract object that is the result of the merge + unless the merge is the same as this abstract object, in which + case it returns this.. + + Purpose: Merges an array into this array + +\*******************************************************************/ + +abstract_object_pointert constant_array_abstract_objectt::constant_array_merge( + const constant_array_pointert other) const +{ + if(is_bottom()) + { + return std::make_shared(*other); + } + else + { + array_mapt merged_map=array_mapt(); + bool modified= + abstract_objectt::merge_maps(map, other->map, merged_map); + if(!modified) + { + return shared_from_this(); + } + else + { + const auto &result= + std::dynamic_pointer_cast( + mutable_clone()); + + result->map=merged_map; + + assert(!result->is_top()); + assert(!result->is_bottom()); + return result; + } + } +} + +/*******************************************************************\ + +Function: constant_array_abstract_objectt::output + + Inputs: + out - the stream to write to + ai - the abstract interpreter that contains the abstract domain + (that contains the object ... ) + ns - the current namespace + + Outputs: + + Purpose: To provide a human readable string to the out representing + the current known value about this object. For this array we + print: { [0] - second; + } + } + else + { + // Reading from somewhere in the array + // TODO(tkiley): merge all the values of the array, we may be able to + // do better than returning top + return env.abstract_object_factory(type().subtype(), ns, true, false); + } + } +} + +/*******************************************************************\ + +Function: constant_array_abstract_objectt::write_index + + Inputs: + environment - the abstract environment + ns - the namespace + stack - the remaining stack of expressions on the LHS to evaluate + index_expr - the expression uses to access a specific index + value - the value we are trying to assign to that value in the array + merging_write - Should this and all future writes be merged with the current + value + + Outputs: The array_abstract_objectt representing the result of writing + to a specific index. + + Purpose: A helper function to evaluate writing to a index of an array. + +\*******************************************************************/ + +sharing_ptrt + constant_array_abstract_objectt::write_index( + abstract_environmentt &environment, + const namespacet &ns, + const std::stack stack, + const index_exprt &index_expr, + const abstract_object_pointert value, + bool merging_write) const +{ + if(is_bottom()) + { + return array_abstract_objectt::write_index( + environment, ns, stack, index_expr, value, merging_write); + } + else + { + if(stack.empty()) + { + auto copy= + internal_sharing_ptrt( + new constant_array_abstract_objectt(*this)); + + mp_integer index_value; + if(!merging_write && eval_index(index_expr, environment, ns, index_value)) + { + if(is_top()) + { + copy->top=false; + } + + copy->map[index_value]=value; + return copy; + } + else + { + // try to write to all + // TODO(tkiley): Merge with each entry + return array_abstract_objectt::write_index( + environment, ns, stack, index_expr, value, merging_write); + } + } + else + { + auto copy= + internal_sharing_ptrt( + new constant_array_abstract_objectt(*this)); + + mp_integer index_value; + if(eval_index(index_expr, environment, ns, index_value)) + { + // Here we assume the write is in bounds + abstract_object_pointert array_entry; + if(map.find(index_value)!=map.cend()) + { + array_entry=map.at(index_value); + } + else + { + array_entry=get_top_entry(environment, ns); + } + + if(is_top()) + { + copy->top=false; + } + copy->map[index_value]=environment.write( + array_entry, value, stack, ns, merging_write); + + return copy; + } + else + { + for(const auto &array_entry : map) + { + // Merging write since we don't know which index we are writing to + copy->map[array_entry.first]= + environment.write( + array_entry.second, value, stack, ns, true); + if(is_top()) + { + copy->top=false; + } + } + + return copy; + } + } + } +} + +/*******************************************************************\ + +Function: constant_array_abstract_objectt::get_top_entry + + Inputs: + environment - the abstract environment + ns - the namespace + + Outputs: An abstract object pointer of type type().subtype() (i.e. the + type of the array's values). + + Purpose: Short hand method for creating a top element of the array + +\*******************************************************************/ + +abstract_object_pointert constant_array_abstract_objectt::get_top_entry( + const abstract_environmentt &env, const namespacet &ns) const +{ + return env.abstract_object_factory(type().subtype(), ns, true, false); +} + +/*******************************************************************\ + +Function: constant_array_abstract_objectt::eval_index + + Inputs: + environment - the abstract environment + ns - the namespace + + Outputs: An abstract object pointer of type type().subtype() (i.e. the + type of the array's values). + + Purpose: Short hand method for creating a top element of the array + +\*******************************************************************/ + +bool constant_array_abstract_objectt::eval_index( + const index_exprt &index, + const abstract_environmentt &env, + const namespacet &ns, + mp_integer &out_index) const +{ + abstract_object_pointert index_abstract_object=env.eval(index.index(), ns); + exprt value=index_abstract_object->to_constant(); + if(value.is_constant()) + { + constant_exprt constant_index=to_constant_expr(value); + bool result=to_integer(constant_index, out_index); + return !result; + } + else + { + return false; + } +} diff --git a/src/analyses/variable-sensitivity/constant_array_abstract_object.h b/src/analyses/variable-sensitivity/constant_array_abstract_object.h new file mode 100644 index 00000000000..24a8c87799e --- /dev/null +++ b/src/analyses/variable-sensitivity/constant_array_abstract_object.h @@ -0,0 +1,77 @@ +/*******************************************************************\ + + Module: Variable Sensitivity + + Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ +#ifndef CPROVER_ANALYSES_VARIABLE_SENSITIVITY_CONSTANT_ARRAY_ABSTRACT_OBJECT_H +#define CPROVER_ANALYSES_VARIABLE_SENSITIVITY_CONSTANT_ARRAY_ABSTRACT_OBJECT_H + +#include +#include + +#include +#include + +class ai_baset; +class abstract_environmentt; + +class constant_array_abstract_objectt:public array_abstract_objectt +{ +public: + typedef sharing_ptrt const + constant_array_pointert; + + explicit constant_array_abstract_objectt(typet type); + constant_array_abstract_objectt(typet type, bool top, bool bottom); + constant_array_abstract_objectt( + const exprt &expr, + const abstract_environmentt &environment, + const namespacet &ns); + + virtual ~constant_array_abstract_objectt() {} + + void output( + std::ostream &out, const ai_baset &ai, const namespacet &ns) const override; + + virtual abstract_object_pointert read_index( + const abstract_environmentt &env, + const index_exprt &index, + const namespacet &ns) const override; + + virtual sharing_ptrt write_index( + abstract_environmentt &environment, + const namespacet &ns, + const std::stack stack, + const index_exprt &index_expr, + const abstract_object_pointert value, + bool merging_write) const override; + +protected: + CLONE + + virtual abstract_object_pointert merge( + abstract_object_pointert other) const override; + +private: + // Since we don't store for any index where the value is top + // we don't use a regular array but instead a map of array indices + // to the value at that index + typedef std::map array_mapt; + array_mapt map; + + bool eval_index( + const index_exprt &index, + const abstract_environmentt &env, + const namespacet &ns, + mp_integer &out_index) const; + + abstract_object_pointert get_top_entry( + const abstract_environmentt &env, const namespacet &ns) const; + + abstract_object_pointert constant_array_merge( + const constant_array_pointert other) const; +}; + +#endif // CPROVER_ANALYSES_VARIABLE_SENSITIVITY_CONSTANT_ARRAY_ABSTRACT_OBJECT_H diff --git a/src/analyses/variable-sensitivity/constant_pointer_abstract_object.cpp b/src/analyses/variable-sensitivity/constant_pointer_abstract_object.cpp new file mode 100644 index 00000000000..f4590b9ed94 --- /dev/null +++ b/src/analyses/variable-sensitivity/constant_pointer_abstract_object.cpp @@ -0,0 +1,397 @@ +/*******************************************************************\ + + Module: analyses variable-sensitivity + + Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ + +#include + +#include +#include +#include +#include +#include "constant_pointer_abstract_object.h" + +/*******************************************************************\ + +Function: constant_pointer_abstract_objectt::constant_pointer_abstract_objectt + + Inputs: + type - the type the abstract_object is representing + + Outputs: + + Purpose: + +\*******************************************************************/ + +constant_pointer_abstract_objectt::constant_pointer_abstract_objectt( + const typet &t): + pointer_abstract_objectt(t) +{ + assert(t.id()==ID_pointer); + value=nil_exprt(); +} + +/*******************************************************************\ + +Function: constant_pointer_abstract_objectt::constant_pointer_abstract_objectt + + Inputs: + type - the type the abstract_object is representing + top - is the abstract_object starting as top + bottom - is the abstract_object starting as bottom + + Outputs: + + Purpose: Start the abstract object at either top or bottom or neither + Asserts if both top and bottom are true + +\*******************************************************************/ + +constant_pointer_abstract_objectt::constant_pointer_abstract_objectt( + const typet &t, bool tp, bool bttm): + pointer_abstract_objectt(t, tp, bttm) +{ + assert(t.id()==ID_pointer); + value=nil_exprt(); +} + +/*******************************************************************\ + +Function: constant_pointer_abstract_objectt::constant_pointer_abstract_objectt + + Inputs: + old - the abstract object to copy from + + Outputs: + + Purpose: + +\*******************************************************************/ + +constant_pointer_abstract_objectt::constant_pointer_abstract_objectt( + const constant_pointer_abstract_objectt &old): + pointer_abstract_objectt(old), value(old.value) +{} + +/*******************************************************************\ + +Function: constant_pointer_abstract_objectt::constant_pointer_abstract_objectt + + Inputs: + expr - the expression to use as the starting pointer for an abstract object + + Outputs: + + Purpose: + +\*******************************************************************/ + +constant_pointer_abstract_objectt::constant_pointer_abstract_objectt( + const exprt &e, + const abstract_environmentt &environment, + const namespacet &ns): + pointer_abstract_objectt(e, environment, ns) +{ + assert(e.type().id()==ID_pointer); + value=nil_exprt(); + + if(e.id()==ID_address_of) + { + value=e; + top=false; + } + else if(e.id()==ID_constant) + { + constant_exprt constant_expr(to_constant_expr(e)); + if(constant_expr.get_value()==ID_NULL) + { + value=e; + top=false; + } + } + // Else unknown expression type - possibly we should handle more +} + +/*******************************************************************\ + +Function: constant_pointer_abstract_objectt::merge + + Inputs: + other - the pointer being merged + + Outputs: Returns the result of the merge. + + Purpose: Set this abstract object to be the result of merging this + abstract object. This calls the merge_constant_pointers if + we are trying to merge a constant pointer we use the constant pointer + constant pointer merge + +\*******************************************************************/ + +abstract_object_pointert constant_pointer_abstract_objectt::merge( + abstract_object_pointert other) const +{ + auto cast_other= + std::dynamic_pointer_cast(other); + if(cast_other) + { + return merge_constant_pointers(cast_other); + } + else + { + // TODO(tkiley): How do we set the result to be toppish? + return pointer_abstract_objectt::merge(other); + } +} + +/*******************************************************************\ + +Function: constant_pointer_abstract_objectt::merge_constant_pointers + + Inputs: + other - the pointer being merged + + Outputs: Returns a new abstract object that is the result of the merge + unless the merge is the same as this abstract object, in which + case it returns this. + + Purpose: Merges two constant pointers. If they are pointing at the same + value, we merge, otherwise we set to top. + +\*******************************************************************/ + +abstract_object_pointert + constant_pointer_abstract_objectt::merge_constant_pointers( + const constant_pointer_abstract_pointert other) const +{ + if(is_bottom()) + { + return std::make_shared(*other); + } + else + { + // Can we actually merge these value + if(value==other->value) + { + return shared_from_this(); + } + else + { + return pointer_abstract_objectt::merge(other); + } + } +} + +/*******************************************************************\ + +Function: constant_pointer_abstract_objectt::to_constant + + Inputs: + + Outputs: Returns an expression representing the value if it can. + Returns a nil expression if it can be more than one value. + Returns null_pointer expression if it must be null + Returns an address_of_exprt with the value set to the + result of to_constant called on whatever abstract object this + pointer is pointing to. + + Purpose: To try and find a constant expression for this abstract object + +\*******************************************************************/ + +exprt constant_pointer_abstract_objectt::to_constant() const +{ + if(is_top() || is_bottom()) + { + return pointer_abstract_objectt::to_constant(); + } + else + { + // TODO(tkiley): I think we would like to eval this before using it + // in the to_constant. + return value; + } +} + +/*******************************************************************\ + +Function: constant_pointer_abstract_objectt::output + + Inputs: + out - the stream to write to + ai - ? + ns - ? + + Outputs: + + Purpose: Print the value of the pointer. Either NULL if nullpointer or + ptr -> ( output of what the pointer is pointing to). + +\*******************************************************************/ + +void constant_pointer_abstract_objectt::output( + std::ostream &out, const ai_baset &ai, const namespacet &ns) const +{ + if(is_top() || is_bottom()) + { + pointer_abstract_objectt::output(out, ai, ns); + } + else + { + if(value.id()==ID_constant && value.get(ID_value)==ID_NULL) + { + out << "NULL"; + } + else + { + out << "ptr ->("; + if(value.id()==ID_address_of) + { + const address_of_exprt &address_expr(to_address_of_expr(value)); + if(address_expr.object().id()==ID_symbol) + { + const symbol_exprt &symbol_pointed_to( + to_symbol_expr(address_expr.object())); + + out << symbol_pointed_to.get_identifier(); + } + } + + out << ")"; + } + } +} + +/*******************************************************************\ + +Function: constant_pointer_abstract_objectt::read_dereference + + Inputs: + env - the environment + ns - the namespace + + Outputs: An abstract object representing the value this pointer is pointing + to + + Purpose: A helper function to dereference a value from a pointer. Providing + the pointer can only be pointing at one thing, returns an abstract + object representing that thing. If null or top will return top. + +\*******************************************************************/ + +abstract_object_pointert constant_pointer_abstract_objectt::read_dereference( + const abstract_environmentt &env, const namespacet &ns) const +{ + if(is_top() || is_bottom() || value.id()==ID_nil) + { + // Return top if dereferencing a null pointer or we are top + bool is_value_top = is_top() || value.id()==ID_nil; + return env.abstract_object_factory( + type().subtype(), ns, is_value_top, !is_value_top); + } + else + { + if(value.id()==ID_address_of) + { + return env.eval(value.op0(), ns); + } + else if(value.id()==ID_constant) + { + // Reading a null pointer, return top + return env.abstract_object_factory(type().subtype(), ns, true, false); + } + else + { + return env.abstract_object_factory(type().subtype(), ns, true, false); + } + } +} + +/*******************************************************************\ + +Function: constant_pointer_abstract_objectt::write_dereference + + Inputs: + environment - the environment + ns - the namespace + stack - the remaining stack + new_value - the value to write to the dereferenced pointer + merging_write - is it a merging write (i.e. we aren't certain + we are writing to this particular pointer therefore + the value should be merged with whatever is already there + or we are certain we are writing to this pointer so + therefore the value can be replaced + + Outputs: A modified abstract object representing this pointer after it + has been written to. + + Purpose: A helper function to evaluate writing to a pointers value. + If the pointer can only be pointing to one element that it overwrites + that element (or merges if merging_write) with the new value. + If don't know what we are pointing to, we delegate to the parent. + +\*******************************************************************/ + +sharing_ptrt + constant_pointer_abstract_objectt::write_dereference( + abstract_environmentt &environment, + const namespacet &ns, + const std::stack stack, + const abstract_object_pointert new_value, + bool merging_write) const +{ + if(is_top() || is_bottom()) + { + return pointer_abstract_objectt::write_dereference( + environment, ns, stack, new_value, merging_write); + } + else + { + // If not an address, we don't know what we are pointing to + if(value.id()!=ID_address_of) + { + return pointer_abstract_objectt::write_dereference( + environment, ns, stack, new_value, merging_write); + } + + const address_of_exprt &address_expr=to_address_of_expr(value); + + sharing_ptrt copy= + sharing_ptrt( + new constant_pointer_abstract_objectt(*this)); + + if(stack.empty()) + { + // We should not be changing the type of an abstract object + assert(new_value->type()==type().subtype()); + + + if(merging_write) + { + abstract_object_pointert pointed_value= + environment.eval(address_expr.object(), ns); + bool modifications; + abstract_object_pointert merged_value= + abstract_objectt::merge(pointed_value, new_value, modifications); + environment.assign(address_expr.object(), merged_value, ns); + } + else + { + environment.assign(address_expr.object(), new_value, ns); + } + } + else + { + abstract_object_pointert pointed_value= + environment.eval(address_expr.object(), ns); + environment.write(pointed_value, new_value, stack, ns, merging_write); + + // but the pointer itself does not change! + } + return copy; + } +} diff --git a/src/analyses/variable-sensitivity/constant_pointer_abstract_object.h b/src/analyses/variable-sensitivity/constant_pointer_abstract_object.h new file mode 100644 index 00000000000..afdf1bddffc --- /dev/null +++ b/src/analyses/variable-sensitivity/constant_pointer_abstract_object.h @@ -0,0 +1,63 @@ +/*******************************************************************\ + + Module: analyses variable-sensitivity + + Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ +#ifndef CPROVER_ANALYSES_VARIABLE_SENSITIVITY_CONSTANT_POINTER_ABSTRACT_OBJECT_H +#define CPROVER_ANALYSES_VARIABLE_SENSITIVITY_CONSTANT_POINTER_ABSTRACT_OBJECT_H + +#include + +#include + +class constant_pointer_abstract_objectt:public pointer_abstract_objectt +{ +private: + typedef sharing_ptrt + constant_pointer_abstract_pointert; +public: + explicit constant_pointer_abstract_objectt(const typet &type); + + constant_pointer_abstract_objectt( + const typet &type, + bool top, + bool bottom); + + constant_pointer_abstract_objectt( + const constant_pointer_abstract_objectt &old); + + constant_pointer_abstract_objectt( + const exprt &expr, + const abstract_environmentt &environment, + const namespacet &ns); + + exprt to_constant() const override; + void output( + std::ostream &out, const ai_baset &ai, const namespacet &ns) const override; + + abstract_object_pointert read_dereference( + const abstract_environmentt &env, const namespacet &ns) const override; + + sharing_ptrt write_dereference( + abstract_environmentt &environment, + const namespacet &ns, + const std::stack stack, + const abstract_object_pointert value, + bool merging_write) const override; + +protected: + virtual abstract_object_pointert merge( + abstract_object_pointert op1) const override; + + CLONE + +private: + abstract_object_pointert merge_constant_pointers( + const constant_pointer_abstract_pointert other) const; + + exprt value; +}; + +#endif // CPROVER_ANALYSES_VARIABLE_SENSITIVITY_CONSTANT_POINTER_ABSTRACT_OBJECT_H // NOLINT(*) diff --git a/src/analyses/variable-sensitivity/full_struct_abstract_object.cpp b/src/analyses/variable-sensitivity/full_struct_abstract_object.cpp new file mode 100644 index 00000000000..466816e468f --- /dev/null +++ b/src/analyses/variable-sensitivity/full_struct_abstract_object.cpp @@ -0,0 +1,391 @@ +/*******************************************************************\ + +Module: Struct abstract object + +Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ + +#include + +#include +#include +#include + +#include "full_struct_abstract_object.h" + +// #define DEBUG + +#ifdef DEBUG +#include +#endif + +/*******************************************************************\ + +Function: full_struct_abstract_objectt::struct_abstract_objectt + + Inputs: + type - the type the abstract_object is representing + + Outputs: + + Purpose: + +\*******************************************************************/ + +full_struct_abstract_objectt::full_struct_abstract_objectt(const typet &t): + struct_abstract_objectt(t) +{ + assert(t.id()==ID_struct); + assert(verify()); +} + +/*******************************************************************\ + +Function: struct_abstract_objectt::struct_abstract_objectt + + Inputs: + type - the type the abstract_object is representing + top - is the abstract_object starting as top + bottom - is the abstract_object starting as bottom + + Outputs: + + Purpose: Start the abstract object at either top or bottom or + neither asserts if both top and bottom are true + +\*******************************************************************/ + +full_struct_abstract_objectt::full_struct_abstract_objectt( + const typet &t, bool top, bool bottom): + struct_abstract_objectt(t, top, bottom) +{ + assert(t.id()==ID_struct); + assert(verify()); +} + +/*******************************************************************\ + +Function: full_struct_abstract_objectt::full_struct_abstract_objectt + + Inputs: + expr - the expression to use as the starting pointer for an + abstract object + + Outputs: + + Purpose: + +\*******************************************************************/ + +full_struct_abstract_objectt::full_struct_abstract_objectt( + const exprt &e, + const abstract_environmentt &environment, + const namespacet &ns): + struct_abstract_objectt(e, environment, ns) +{ + assert(verify()); +} + +/*******************************************************************\ + +Function: struct_abstract_objectt::read_component + + Inputs: + environment - the abstract environment + member_expr - the expression uses to access a specific component + + Outputs: The abstract object representing the value of that + component. For this abstraction this will always be top + since we are not tracking the struct. + + Purpose: A helper function to evaluate the abstract object contained + within a struct. More precise abstractions may override + this to return more precise results. + +\*******************************************************************/ + +abstract_object_pointert full_struct_abstract_objectt::read_component( + const abstract_environmentt &environment, + const member_exprt &member_expr, + const namespacet& ns) const +{ +#ifdef DEBUG + std::cout << "Reading component " << member_expr.get_component_name() + << std::endl; +#endif + + if(is_top()) + { + return environment.abstract_object_factory( + member_expr.type(), ns, true); + } + else + { + assert(!is_bottom()); + + irep_idt c=member_expr.get_component_name(); + + struct_mapt::const_iterator it=map.find(c); + + if(it!=map.cend()) + { + return it->second; + } + else + { + return environment.abstract_object_factory( + member_expr.type(), ns, true); + } + } +} + +/*******************************************************************\ + +Function: struct_abstract_objectt::write_component + + Inputs: + environment - the abstract environment + stack - the remaining stack of expressions on the LHS to evaluate + member_expr - the expression uses to access a specific component + value - the value we are trying to write to the component + + Outputs: The struct_abstract_objectt representing the result of + writing to a specific component. In this case this will + always be top as we are not tracking the value of this + struct. + + Purpose: A helper function to evaluate writing to a component of a + struct. More precise abstractions may override this to + update what they are storing for a specific component. + +\*******************************************************************/ + +sharing_ptrt + full_struct_abstract_objectt::write_component( + abstract_environmentt &environment, + const namespacet &ns, + const std::stack &stack, + const member_exprt &member_expr, + const abstract_object_pointert value, + bool merging_write) const +{ +#ifdef DEBUG + std::cout << "Writing component " << member_expr.get_component_name() + << std::endl; +#endif + + if(is_bottom()) + { + return sharing_ptrt( + new full_struct_abstract_objectt( + member_expr.compound().type(), false, true)); + } + + // we only handle one level currently + if(!stack.empty()) + { + internal_sharing_ptrt copy( + new full_struct_abstract_objectt(*this)); + + abstract_object_pointert starting_value; + irep_idt c=member_expr.get_component_name(); + if(map.find(c)==map.cend()) + { + starting_value= + environment.abstract_object_factory( + member_expr.type(), ns, true, false); + } + else + { + starting_value=map.at(c); + } + + copy->map[c]= + environment.write(starting_value, value, stack, ns, merging_write); + copy->top=false; + assert(copy->verify()); + return copy; + } + else + { + internal_sharing_ptrt copy( + new full_struct_abstract_objectt(*this)); + +#ifdef DEBUG + std::cout << "Setting component" << std::endl; +#endif + + irep_idt c=member_expr.get_component_name(); + + if(merging_write) + { + if(is_top()) // struct is top + { + assert(copy->verify()); + return copy; + } + + assert(!copy->map.empty()); + + struct_mapt &m=copy->map; + + struct_mapt::iterator it=m.find(c); + + if(it==m.end()) // component is top + { + assert(copy->verify()); + return copy; + } + + bool dummy; + + it->second=abstract_objectt::merge(it->second, value, dummy); + } + else + { + copy->map[c]=value; + + copy->top=false; + assert(!copy->is_bottom()); + } + + assert(copy->verify()); + return copy; + } +} + +/*******************************************************************\ + +Function: full_struct_abstract_objectt::output + + Inputs: + out - the stream to write to + ai - the abstract interpreter that contains the abstract domain + (that contains the object ... ) + ns - the current namespace + + Outputs: + + Purpose: To provide a human readable string to the out representing + the current known value about this object. For this array we + print: { .component_name=first) + { + out << ", "; + } + out << "." << entry.first << "="; + entry.second->output(out, ai, ns); + } + out << "}"; +} + +/*******************************************************************\ + +Function: full_struct_abstract_objectt::verify + + Inputs: + + Outputs: Returns true if the struct is valid + + Purpose: To validate that the struct object is in a valid state. + This means either it is top or bottom, or if neither of those + then there exists something in the map of components. + If there is something in the map, then it can't be top or bottom + +\*******************************************************************/ + +bool full_struct_abstract_objectt::verify() const +{ + // Either the object is top or bottom (=> map empty) + // or the map is not empty => neither top nor bottom + return (is_top() || is_bottom()) == map.empty(); +} + +/*******************************************************************\ + +Function: full_struct_abstract_objectt::merge + + Inputs: + other - the other object being merged + + Outputs: Returns the result of the merge. + + Purpose: To merge an abstract object into this abstract object. If + the other is also a struct, we perform a constant_structs merge + Otherwise we call back to the parent merge. + +\*******************************************************************/ + +abstract_object_pointert full_struct_abstract_objectt::merge( + abstract_object_pointert other) const +{ + constant_struct_pointert cast_other= + std::dynamic_pointer_cast(other); + if(cast_other) + { + return merge_constant_structs(cast_other); + } + else + { + // TODO(tkiley): How do we set the result to be toppish? Does it matter? + return struct_abstract_objectt::merge(other); + } +} + +/*******************************************************************\ + +Function: full_struct_abstract_objectt::merge_constant_structs + + Inputs: + other - the other object being merged + + Outputs: Returns a new abstract object that is the result of the merge + unless the merge is the same as this abstract object, in which + case it returns this. + + Purpose: Performs an element wise merge of the map for each struct + +\*******************************************************************/ + +abstract_object_pointert full_struct_abstract_objectt::merge_constant_structs( + constant_struct_pointert other) const +{ + if(is_bottom()) + { + return std::make_shared(*other); + } + else + { + struct_mapt merged_map; + bool modified= + abstract_objectt::merge_maps(map, other->map, merged_map); + if(!modified) + { + assert(verify()); + return shared_from_this(); + } + else + { + const auto &result= + std::dynamic_pointer_cast( + mutable_clone()); + + result->map=merged_map; + + assert(!result->is_top()); + assert(!result->is_bottom()); + assert(result->verify()); + return result; + } + } +} diff --git a/src/analyses/variable-sensitivity/full_struct_abstract_object.h b/src/analyses/variable-sensitivity/full_struct_abstract_object.h new file mode 100644 index 00000000000..2c8794903ca --- /dev/null +++ b/src/analyses/variable-sensitivity/full_struct_abstract_object.h @@ -0,0 +1,74 @@ +/*******************************************************************\ + +Module: Struct abstract object + +Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ + +#ifndef CPROVER_ANALYSES_VARIABLE_SENSITIVITY_FULL_STRUCT_ABSTRACT_OBJECT_H +#define CPROVER_ANALYSES_VARIABLE_SENSITIVITY_FULL_STRUCT_ABSTRACT_OBJECT_H + +#include +#include +#include +#include + +class abstract_environmentt; +class member_exprt; + +class full_struct_abstract_objectt:public struct_abstract_objectt +{ +public: + typedef sharing_ptrt constant_struct_pointert; + + explicit full_struct_abstract_objectt(const typet &type); + + full_struct_abstract_objectt(const typet &type, bool top, bool bottom); + + full_struct_abstract_objectt( + const exprt &expr, + const abstract_environmentt &environment, + const namespacet &ns); + + + // struct interface + virtual abstract_object_pointert read_component( + const abstract_environmentt &environment, + const member_exprt &member_expr, + const namespacet& ns) const override; + + virtual sharing_ptrt write_component( + abstract_environmentt &environment, + const namespacet &ns, + const std::stack &stack, + const member_exprt &member_expr, + const abstract_object_pointert value, + bool merging_write) const override; + + virtual void output( + std::ostream &out, + const class ai_baset &ai, + const class namespacet &ns) const override; + +private: + // no entry means component is top + typedef std::map struct_mapt; + struct_mapt map; + + + + abstract_object_pointert merge_constant_structs( + constant_struct_pointert other) const; + +protected: + CLONE + + bool verify() const; + // Set the state of this to the merge result of op1 and op2 and + // return if the result is different from op1 + virtual abstract_object_pointert merge( + abstract_object_pointert other) const override; +}; + +#endif // CPROVER_ANALYSES_VARIABLE_SENSITIVITY_FULL_STRUCT_ABSTRACT_OBJECT_H diff --git a/src/analyses/variable-sensitivity/pointer_abstract_object.cpp b/src/analyses/variable-sensitivity/pointer_abstract_object.cpp new file mode 100644 index 00000000000..74790fb8dd5 --- /dev/null +++ b/src/analyses/variable-sensitivity/pointer_abstract_object.cpp @@ -0,0 +1,146 @@ +/*******************************************************************\ + + Module: analyses variable-sensitivity + + Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ +#include +#include + +#include + +#include "pointer_abstract_object.h" + + +/*******************************************************************\ + +Function: pointer_abstract_objectt::pointer_abstract_objectt + + Inputs: + type - the type the abstract_object is representing + + Outputs: + + Purpose: + +\*******************************************************************/ + +pointer_abstract_objectt::pointer_abstract_objectt(const typet &t): + abstract_objectt(t) +{ + assert(t.id()==ID_pointer); +} + +/*******************************************************************\ + +Function: pointer_abstract_objectt::pointer_abstract_objectt + + Inputs: + type - the type the abstract_object is representing + top - is the abstract_object starting as top + bottom - is the abstract_object starting as bottom + + Outputs: + + Purpose: Start the abstract object at either top or bottom or neither + Asserts if both top and bottom are true + +\*******************************************************************/ + +pointer_abstract_objectt::pointer_abstract_objectt( + const typet &t, bool tp, bool bttm): + abstract_objectt(t, tp, bttm) +{ + assert(t.id()==ID_pointer); +} + +/*******************************************************************\ + +Function: pointer_abstract_objectt::pointer_abstract_objectt + + Inputs: + expr - the expression to use as the starting pointer for an abstract object + + Outputs: + + Purpose: + +\*******************************************************************/ + +pointer_abstract_objectt::pointer_abstract_objectt( + const exprt &e, + const abstract_environmentt &environment, + const namespacet &ns): + abstract_objectt(e, environment, ns) +{ + assert(e.type().id()==ID_pointer); +} + +/*******************************************************************\ + +Function: pointer_abstract_objectt::read_dereference + + Inputs: + env - the environment + ns - the namespace + + Outputs: An abstract object representing the value being pointed to + + Purpose: A helper function to read elements from an array. More precise + abstractions may override this to provide more precise results. + +\*******************************************************************/ + +abstract_object_pointert pointer_abstract_objectt::read_dereference( + const abstract_environmentt &env, const namespacet &ns) const +{ + pointer_typet pointer_type(to_pointer_type(type())); + const typet &pointed_to_type=pointer_type.subtype(); + + return env.abstract_object_factory(pointed_to_type, ns, true, false); +} + +/*******************************************************************\ + +Function: pointer_abstract_objectt::write_dereference + + Inputs: + environment - the abstract environment + ns - the namespace + stack - the remaining stack of expressions on the LHS to evaluate + value - the value we are trying to assign to what the pointer is + pointing to + merging_write - is it a merging write (i.e. we aren't certain + we are writing to this particular pointer therefore + the value should be merged with whatever is already there + or we are certain we are writing to this pointer so + therefore the value can be replaced + + Outputs: A modified abstract object representing this pointer after it + has been written to. + + Purpose: A helper function to evaluate writing to a pointers value. More + precise abstractions may override this provide more precise results. + +\*******************************************************************/ + +sharing_ptrt + pointer_abstract_objectt::write_dereference( + abstract_environmentt &environment, + const namespacet &ns, + const std::stack stack, + const abstract_object_pointert value, + bool merging_write) const +{ + if(is_top() || is_bottom()) + { + environment.havoc("Writing to a 2value pointer"); + return std::dynamic_pointer_cast(clone()); + } + else + { + return sharing_ptrt( + new pointer_abstract_objectt(type(), true, false)); + } +} diff --git a/src/analyses/variable-sensitivity/pointer_abstract_object.h b/src/analyses/variable-sensitivity/pointer_abstract_object.h new file mode 100644 index 00000000000..26d0632214f --- /dev/null +++ b/src/analyses/variable-sensitivity/pointer_abstract_object.h @@ -0,0 +1,45 @@ +/*******************************************************************\ + + Module: analyses variable-sensitivity + + Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ +#ifndef CPROVER_ANALYSES_VARIABLE_SENSITIVITY_POINTER_ABSTRACT_OBJECT_H +#define CPROVER_ANALYSES_VARIABLE_SENSITIVITY_POINTER_ABSTRACT_OBJECT_H + + +#include + +#include + +class typet; +class constant_exprt; +class abstract_environmentt; + +class pointer_abstract_objectt:public abstract_objectt +{ +public: + explicit pointer_abstract_objectt(const typet &type); + pointer_abstract_objectt(const typet &type, bool top, bool bottom); + explicit pointer_abstract_objectt( + const exprt &e, + const abstract_environmentt &environment, + const namespacet &ns); + + // pointer interface + virtual abstract_object_pointert read_dereference( + const abstract_environmentt &env, const namespacet &ns) const; + + virtual sharing_ptrt write_dereference( + abstract_environmentt &environment, + const namespacet &ns, + const std::stack stack, + const abstract_object_pointert value, + bool merging_write) const; + +protected: + CLONE +}; + +#endif // CPROVER_ANALYSES_VARIABLE_SENSITIVITY_POINTER_ABSTRACT_OBJECT_H diff --git a/src/analyses/variable-sensitivity/struct_abstract_object.cpp b/src/analyses/variable-sensitivity/struct_abstract_object.cpp new file mode 100644 index 00000000000..e559e390be4 --- /dev/null +++ b/src/analyses/variable-sensitivity/struct_abstract_object.cpp @@ -0,0 +1,147 @@ +/*******************************************************************\ + + Module: analyses variable-sensitivity + + Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ + +#include +#include +#include +#include + +#include "struct_abstract_object.h" + + +/*******************************************************************\ + +Function: struct_abstract_objectt::struct_abstract_objectt + + Inputs: + type - the type the abstract_object is representing + + Outputs: + + Purpose: + +\*******************************************************************/ + +struct_abstract_objectt::struct_abstract_objectt(const typet &t): + abstract_objectt(t) +{ + assert(t.id()==ID_struct); +} + +/*******************************************************************\ + +Function: struct_abstract_objectt::struct_abstract_objectt + + Inputs: + type - the type the abstract_object is representing + top - is the abstract_object starting as top + bottom - is the abstract_object starting as bottom + + Outputs: + + Purpose: Start the abstract object at either top or bottom or neither + Asserts if both top and bottom are true + +\*******************************************************************/ + +struct_abstract_objectt::struct_abstract_objectt( + const typet &t, bool tp, bool bttm): + abstract_objectt(t, tp, bttm) +{ + assert(t.id()==ID_struct); +} + +/*******************************************************************\ + +Function: struct_abstract_objectt::struct_abstract_objectt + + Inputs: + expr - the expression to use as the starting pointer for an abstract object + + Outputs: + + Purpose: + +\*******************************************************************/ + +struct_abstract_objectt::struct_abstract_objectt( + const exprt &e, + const abstract_environmentt &environment, + const namespacet &ns): + abstract_objectt(e, environment, ns) +{ + assert(ns.follow(e.type()).id()==ID_struct); +} + +/*******************************************************************\ + +Function: struct_abstract_objectt::read_component + + Inputs: + environment - the abstract environment + member_expr - the expression uses to access a specific component + + Outputs: The abstract object representing the value of that component. For + this abstraction this will always be top since we are not tracking + the struct. + + Purpose: A helper function to evaluate the abstract object contained + within a struct. More precise abstractions may override this + to return more precise results. + +\*******************************************************************/ + +abstract_object_pointert struct_abstract_objectt::read_component( + const abstract_environmentt &environment, + const member_exprt &member_expr, + const namespacet& ns) const +{ + // If we are bottom then so are the components + // otherwise the components could be anything + return environment.abstract_object_factory( + member_expr.type(), ns, !is_bottom(), is_bottom()); +} + +/*******************************************************************\ + +Function: struct_abstract_objectt::write_component + + Inputs: + environment - the abstract environment + stack - the remaining stack of expressions on the LHS to evaluate + member_expr - the expression uses to access a specific component + value - the value we are trying to write to the component + + Outputs: The struct_abstract_objectt representing the result of writing + to a specific component. In this case this will always be top + as we are not tracking the value of this struct. + + Purpose: A helper function to evaluate writing to a component of a struct. + More precise abstractions may override this to + update what they are storing for a specific component. + +\*******************************************************************/ + +sharing_ptrt struct_abstract_objectt::write_component( + abstract_environmentt &environment, + const namespacet &ns, + const std::stack &stack, + const member_exprt &member_expr, + const abstract_object_pointert value, + bool merging_write) const +{ + if(is_top() || is_bottom()) + { + return std::dynamic_pointer_cast(clone()); + } + else + { + return sharing_ptrt( + new struct_abstract_objectt(type(), true, false)); + } +} diff --git a/src/analyses/variable-sensitivity/struct_abstract_object.h b/src/analyses/variable-sensitivity/struct_abstract_object.h new file mode 100644 index 00000000000..bbded930463 --- /dev/null +++ b/src/analyses/variable-sensitivity/struct_abstract_object.h @@ -0,0 +1,46 @@ +/*******************************************************************\ + + Module: analyses variable-sensitivity + + Author: Thomas Kiley, thomas.kiley@diffblue.com + +\*******************************************************************/ + +#ifndef CPROVER_ANALYSES_VARIABLE_SENSITIVITY_STRUCT_ABSTRACT_OBJECT_H +#define CPROVER_ANALYSES_VARIABLE_SENSITIVITY_STRUCT_ABSTRACT_OBJECT_H + +#include +#include + +class abstract_environmentt; +class member_exprt; + +class struct_abstract_objectt:public abstract_objectt +{ +public: + explicit struct_abstract_objectt(const typet &type); + struct_abstract_objectt(const typet &type, bool top, bool bottom); + explicit struct_abstract_objectt( + const exprt &expr, + const abstract_environmentt &environment, + const namespacet &ns); + + // struct interface + virtual abstract_object_pointert read_component( + const abstract_environmentt &environment, + const member_exprt &member_expr, + const namespacet &ns) const; + + virtual sharing_ptrt write_component( + abstract_environmentt &environment, + const namespacet &ns, + const std::stack &stack, + const member_exprt &member_expr, + const abstract_object_pointert value, + bool merging_write) const; + +protected: + CLONE +}; + +#endif // CPROVER_ANALYSES_VARIABLE_SENSITIVITY_STRUCT_ABSTRACT_OBJECT_H diff --git a/src/analyses/variable-sensitivity/variable_sensitivity_domain.cpp b/src/analyses/variable-sensitivity/variable_sensitivity_domain.cpp new file mode 100644 index 00000000000..35bf7e2fe10 --- /dev/null +++ b/src/analyses/variable-sensitivity/variable_sensitivity_domain.cpp @@ -0,0 +1,392 @@ +/*******************************************************************\ + +Module: Abstract Interpretation + +Author: Martin Brain + +Date: April 2016 + +\*******************************************************************/ + +#include + +#include +#include + +#include "variable_sensitivity_domain.h" + +#ifdef DEBUG +#include +#endif + + +/*******************************************************************\ + +Function: variable_sensitivity_domaint::transform + + Inputs: The instruction before (from) and after (to) the abstract domain, + the abstract interpreter (ai) and the namespace (ns). + + Outputs: None + + Purpose: Compute the abstract transformer for a single instruction + +\*******************************************************************/ + +void variable_sensitivity_domaint::transform( + locationt from, + locationt to, + ai_baset &ai, + const namespacet &ns) +{ + #ifdef DEBUG + std::cout << "Transform from/to:\n"; + std::cout << from->location_number << " --> " + << to->location_number << std::endl; + #endif + + const goto_programt::instructiont &instruction=*from; + switch(instruction.type) + { + case DECL: + // Creates a new variable, which should be top + // but we don't store top so ... no action required + break; + + case DEAD: + { + // Assign to top is the same as removing + abstract_object_pointert top_object= + abstract_state.abstract_object_factory( + to_code_dead(instruction.code).symbol().type(), ns, true); + abstract_state.assign( + to_code_dead(instruction.code).symbol(), top_object, ns); + } + break; + + case ASSIGN: + { + const code_assignt &inst = to_code_assign(instruction.code); + + // TODO : check return values + abstract_object_pointert r = abstract_state.eval(inst.rhs(), ns); + abstract_state.assign(inst.lhs(), r, ns); + } + break; + + case GOTO: + { + if(1) // (flow_sensitivity == FLOW_SENSITIVE) + { + // Get the next line + locationt next=from; + next++; + // Is this a GOTO to the next line (i.e. pointless) + if(next!=from->get_target()) + { + if(to==from->get_target()) + { + // The AI is exploring the branch where the jump is taken + abstract_state.assume(instruction.guard, ns); + } + else + { + // Exploring the path where the jump is not taken - therefore assume + // the condition is false + abstract_state.assume(not_exprt(instruction.guard), ns); + } + } + // ignore jumps to the next line, we can assume nothing + } + } + break; + + case ASSUME: + abstract_state.assume(instruction.guard, ns); + break; + + case FUNCTION_CALL: + // FIXME : Ignore as not yet interprocedural + break; + + case END_FUNCTION: + // FIXME : Ignore as not yet interprocedural + break; + + /***************************************************************/ + + case ASSERT: + // Conditions on the program, do not alter the data or information + // flow and thus can be ignored. + // Checking of assertions can only be reasonably done once the fix-point + // has been computed, i.e. after all of the calls to transform. + break; + + case SKIP: + case LOCATION: + // Can ignore + break; + + case RETURN: + throw "return instructions should be removed first"; + + case START_THREAD: + case END_THREAD: + case ATOMIC_BEGIN: + case ATOMIC_END: + throw "threading not supported"; + + case THROW: + case CATCH: + throw "exceptions not handled"; + + case OTHER: +// throw "other"; + break; + + default: + throw "unrecognised instruction type"; + } + + assert(abstract_state.verify()); +} + +/*******************************************************************\ + +Function: variable_sensitivity_domaint::output + + Inputs: The output stream (out), the abstract interpreter (ai) and + the namespace. + + Outputs: None + + Purpose: Basic text output of the abstract domain + +\*******************************************************************/ +void variable_sensitivity_domaint::output( + std::ostream &out, + const ai_baset &ai, + const namespacet &ns) const +{ + abstract_state.output(out, ai, ns); +} + +/*******************************************************************\ + +Function: variable_sensitivity_domaint::make_bottom + + Inputs: None + + Outputs: None + + Purpose: Sets the domain to bottom (no relations). + +\*******************************************************************/ +void variable_sensitivity_domaint::make_bottom() +{ + abstract_state.make_bottom(); + return; +} + +/*******************************************************************\ + +Function: variable_sensitivity_domaint::make_top + + Inputs: None + + Outputs: None + + Purpose: Sets the domain to top (all relations). + +\*******************************************************************/ +void variable_sensitivity_domaint::make_top() +{ + abstract_state.make_top(); +} + + +/*******************************************************************\ + +Function: variable_sensitivity_domaint::make_entry + + Inputs: None + + Outputs: None + + Purpose: Set up a sane entry state. + +\*******************************************************************/ +void variable_sensitivity_domaint::make_entry() +{ + abstract_state.make_top(); +} + +/*******************************************************************\ + +Function: variable_sensitivity_domaint::merge + + Inputs: The other domain (b) and it's preceding location (from) and + current location (to). + + Outputs: True if something has changed. + + Purpose: Computes the join between "this" and "b". + +\*******************************************************************/ + +bool variable_sensitivity_domaint::merge( + const variable_sensitivity_domaint &b, + locationt from, + locationt to) +{ + #ifdef DEBUG + std::cout << "Merging from/to:\n " + << from->location_number << " --> " + << to->location_number << std::endl; + #endif + + // Use the abstract_environment merge + bool any_changes=abstract_state.merge(b.abstract_state); + + assert(abstract_state.verify()); + return any_changes; +} + +/*******************************************************************\ + +Function: variable_sensitivity_domaint::ai_simplify + + Inputs: + condition - the expression to simplify + ns - the namespace + lhs - is the expression on the left hand side + + Outputs: True if no simplification was made + + Purpose: Use the information in the domain to simplify the expression + with respect to the current location. This may be able to + reduce some values to constants. + +\*******************************************************************/ + +bool variable_sensitivity_domaint::ai_simplify( + exprt &condition, const namespacet &ns, const bool lhs) const +{ + if(lhs) + { + return ai_simplify_lhs(condition, ns); + } + else + { + sharing_ptrt res = abstract_state.eval(condition, ns); + exprt c = res->to_constant(); + + if(c.id() == ID_nil) // TODO : simplification within an expression + return true; + else + { + bool condition_changed = (condition!=c); + condition = c; + return !condition_changed; + } + } + assert(0); // All conditions should be handled +} + +/*******************************************************************\ + +Function: variable_sensitivity_domaint::is_bottom + + Inputs: + + Outputs: True if the domain is bottom (i.e. unreachable). + + Purpose: Find out if the domain is currently unreachable. + +\*******************************************************************/ + +bool variable_sensitivity_domaint::is_bottom() const +{ + return abstract_state.is_bottom(); +} + +/*******************************************************************\ + +Function: variable_sensitivity_domaint::is_top + + Inputs: + + Outputs: True if the domain is top + + Purpose: Is the domain completely top at this state + +\*******************************************************************/ +bool variable_sensitivity_domaint::is_top() const +{ + return abstract_state.is_top(); +} + +/*******************************************************************\ + +Function: variable_sensitivity_domaint::ai_simplify_lhs + + Inputs: + condition - the expression to simplify + ns - the namespace + + Outputs: True if condition did not change. False otherwise. condition + will be updated with the simplified condition if it has worked + + Purpose: Use the information in the domain to simplify the expression + on the LHS of an assignment. This for example won't simplify symbols + to their values, but does simplify indices in arrays, members of + structs and dereferencing of pointers + +\*******************************************************************/ + +bool variable_sensitivity_domaint::ai_simplify_lhs( + exprt &condition, const namespacet &ns) const +{ + // Care must be taken here to give something that is still writable + if(condition.id()==ID_index) + { + index_exprt ie = to_index_expr(condition); + exprt index = ie.index(); + bool changed = ai_simplify(index, ns, false); + if(changed) + { + ie.index() = index; + condition = simplify_expr(ie, ns); + } + + return !changed; + } + else if(condition.id()==ID_dereference) + { + dereference_exprt de = to_dereference_expr(condition); + exprt pointer = de.pointer(); + bool changed = ai_simplify(pointer, ns, false); + if(changed) + { + de.pointer() = pointer; + condition = simplify_expr(de, ns); // So *(&x) -> x + } + + return !changed; + } + else if(condition.id()==ID_member) + { + member_exprt me = to_member_expr(condition); + exprt compound = me.compound(); + bool changed = ai_simplify(compound, ns, true); // <-- true! + if(changed) + { + me.compound() = compound; + condition = simplify_expr(me, ns); + } + + return !changed; + } + else + return true; +} diff --git a/src/analyses/variable-sensitivity/variable_sensitivity_domain.h b/src/analyses/variable-sensitivity/variable_sensitivity_domain.h new file mode 100644 index 00000000000..de12a3f52bd --- /dev/null +++ b/src/analyses/variable-sensitivity/variable_sensitivity_domain.h @@ -0,0 +1,116 @@ +/*******************************************************************\ + + Module: analyses variable-sensitivity + + Author: Thomas Kiley, thomas.kiley@diffblue.com + +There are different ways of handling arrays, structures, unions and +pointers. Our existing solution basically ignores them which is +imprecise at best and out-right wrong at worst. For one project we +needed to do better. We could have implemented a particular way of +handling them in an existing domain, created a new one with it, etc. +This would work but it means duplicate code and it is is inflexible when +the same person / the next person comes along and says "actually, we +really care about the pointer precision but less so the array so could +you just ...". Thus the idea was to do this properly: + +1. Build a "non-relational domain" and allow the abstractions used for +individual variables to be different. + +2. Give the user the option of which abstractions are used for structs, +unions, arrays and pointers. These are the sensitivity options +discussed above. + +3. Have the domain options control which kind of abstractions are used +for the individual values, i.e. constants, intervals, etc. + + +This is implemented in three parts: + +abstract_objectt : The base / interface for abstractions of a single +variable. The interface for these is effectively create (as top, +bottom, from a constant or copy), transform, merge, convert to constant +if possible. Child classes add additional bits of interface, for +example array abstractions need a "read element" and a "write element" +method, structures need a "read field" and "write field", etc. These +objects are intended to be immutable and thus operations tend to produce +pointers. This is so that we can easily produce copy-on-write maps of +them which we need for scaling and performance. There are also children +of these for the constant abstraction of one value, the interval +abstraction of one value (to be implemented), etc. + +abstract_environment : This contains the map from variable names for +abstract_objectt's (the "non-relational" part of the domain). The map +itself if copy-on-write for performance and scalability but this is all +wrapped up nicely in @danpoe's sharing_map. The interface here is +evaluate (exprt -> abstract_objectt*), assign (name, abstract_objectt* +-> bool), assume (exprt -> bool) and merge. It has a factory to build +abstract_objectt* from types or constants but apart from that, doesn't +know anything about which actual abstract_objectt's are being used. As +long as program variables that are arrays have an abstract_objectt which +has the array interface, and so on for structs, unions, etc. then the +abstractions used for values can be freely mixed and matched in any way +the user can get the factory to build. + +variable_sensitivity_domaint : Implements the ai_domain_baset interface +using an abstract_environment. The only real code here is the +'transform' method which looks at the instruction type and converts that +into calls to eval, assume, assign and merge. + + +\*******************************************************************/ +#ifndef CPROVER_ANALYSES_VARIABLE_SENSITIVITY_VARIABLE_SENSITIVITY_DOMAIN_H +#define CPROVER_ANALYSES_VARIABLE_SENSITIVITY_VARIABLE_SENSITIVITY_DOMAIN_H + +#include +#include +#include + +#include +#include + +class variable_sensitivity_domaint:public ai_domain_baset +{ +public: + virtual void transform( + locationt from, + locationt to, + ai_baset &ai, + const namespacet &ns) override; + + // no states + virtual void make_bottom() override; + + // all states + virtual void make_top() override; + + // a reasonable entry-point state + virtual void make_entry() override; + + virtual void output( + std::ostream &out, + const ai_baset &ai, + const namespacet &ns) const override; + + virtual bool merge( + const variable_sensitivity_domaint &b, + locationt from, + locationt to); + + bool ai_simplify( + exprt &condition, + const namespacet &ns, + const bool lhs=false) const override; + + bool is_bottom() const override; + bool is_top() const override; + +private: + bool ai_simplify_lhs( + exprt &condition, + const namespacet &ns) const; + + abstract_environmentt abstract_state; +}; + +#endif // CPROVER_ANALYSES_VARIABLE_SENSITIVITY_VARIABLE_SENSITIVITY_DOMAIN_H diff --git a/src/analyses/variable-sensitivity/variable_sensitivity_object_factory.cpp b/src/analyses/variable-sensitivity/variable_sensitivity_object_factory.cpp new file mode 100644 index 00000000000..e68aeebee75 --- /dev/null +++ b/src/analyses/variable-sensitivity/variable_sensitivity_object_factory.cpp @@ -0,0 +1,153 @@ +/*******************************************************************\ + + Module: analyses variable-sensitivity + + Author: Owen Jones, owen.jones@diffblue.com + +\*******************************************************************/ +#include "variable_sensitivity_object_factory.h" +#include "util/namespace.h" + +variable_sensitivity_object_factoryt + variable_sensitivity_object_factoryt::s_instance; + +/*******************************************************************\ + +Function: variable_sensitivity_object_factoryt::get_abstract_object_type + + Inputs: + type - the type of the variable the abstract object is meant to represent + + Outputs: An enum indicating the abstract object type to use. + + Purpose: Decide which abstract object type to use for the variable in question. + +\*******************************************************************/ + +variable_sensitivity_object_factoryt::ABSTRACT_OBJECT_TYPET + variable_sensitivity_object_factoryt::get_abstract_object_type( + const typet type) +{ + ABSTRACT_OBJECT_TYPET abstract_object_type=TWO_VALUE; + + if(type.id()==ID_signedbv || type.id()==ID_unsignedbv || + type.id()==ID_floatbv || type.id()==ID_fixedbv || + type.id()==ID_c_bool || type.id()==ID_bool || type.id()==ID_integer) + { + abstract_object_type=CONSTANT; + } + else if(type.id()==ID_array) + { + abstract_object_type=has_arrays_flag?ARRAY_SENSITIVE:ARRAY_INSENSITIVE; + } + else if(type.id()==ID_pointer) + { + abstract_object_type= + has_pointers_flag?POINTER_SENSITIVE:POINTER_INSENSITIVE; + } + else if(type.id()==ID_struct) + { + abstract_object_type=has_structs_flag?STRUCT_SENSITIVE:STRUCT_INSENSITIVE; + } + else if(type.id()==ID_union) + { + // TODO: deal with unions + } + + return abstract_object_type; +} + +/*******************************************************************\ + +Function: variable_sensitivity_object_factoryt::get_abstract_object + + Inputs: + type - the type of the variable + top - whether the abstract object should be top in the two-value domain + bottom - whether the abstract object should be bottom in the two-value domain + e - if top and bottom are false this expression is used as the starting + pointer for the abstract object + ns - namespace, used when following the input type + + Outputs: An abstract object of the appropriate type. + + Purpose: Get the appropriate abstract object for the variable under + consideration. + +\*******************************************************************/ + +abstract_object_pointert variable_sensitivity_object_factoryt:: + get_abstract_object( + const typet type, + bool top, + bool bottom, + const exprt &e, + const abstract_environmentt &environment, + const namespacet &ns) +{ + if(!initialized) + { + throw "variable_sensitivity_object_factoryt::get_abstract_object() " \ + "called without first calling " \ + "variable_sensitivity_object_factoryt::set_options()\n"; + } + + typet followed_type=ns.follow(type); + ABSTRACT_OBJECT_TYPET abstract_object_type= + get_abstract_object_type(followed_type); + + switch(abstract_object_type) + { + case CONSTANT: + return initialize_abstract_object( + followed_type, top, bottom, e, environment, ns); + case ARRAY_SENSITIVE: + return initialize_abstract_object( + followed_type, top, bottom, e, environment, ns); + case ARRAY_INSENSITIVE: + return initialize_abstract_object( + followed_type, top, bottom, e, environment, ns); + case POINTER_SENSITIVE: + return initialize_abstract_object( + followed_type, top, bottom, e, environment, ns); + case POINTER_INSENSITIVE: + return initialize_abstract_object( + followed_type, top, bottom, e, environment, ns); + case STRUCT_SENSITIVE: + return initialize_abstract_object( + followed_type, top, bottom, e, environment, ns); + case STRUCT_INSENSITIVE: + return initialize_abstract_object( + followed_type, top, bottom, e, environment, ns); + case TWO_VALUE: + return initialize_abstract_object( + followed_type, top, bottom, e, environment, ns); + default: + assert(false); + return initialize_abstract_object( + followed_type, top, bottom, e, environment, ns); + } +} + +/*******************************************************************\ + +Function: variable_sensitivity_object_factoryt::set_options + + Inputs: + options - the command line options + + Outputs: + + Purpose: Called once to record the appropriate variables from the command line + options so that they can be accessed easily when they are needed. + +\*******************************************************************/ + +void variable_sensitivity_object_factoryt::set_options(optionst &options) +{ + has_variables_flag=options.get_bool_option("variable"); + has_structs_flag=options.get_bool_option("structs"); + has_arrays_flag=options.get_bool_option("arrays"); + has_pointers_flag=options.get_bool_option("pointers"); + initialized=true; +} diff --git a/src/analyses/variable-sensitivity/variable_sensitivity_object_factory.h b/src/analyses/variable-sensitivity/variable_sensitivity_object_factory.h new file mode 100644 index 00000000000..1d3eac20f9c --- /dev/null +++ b/src/analyses/variable-sensitivity/variable_sensitivity_object_factory.h @@ -0,0 +1,111 @@ +/*******************************************************************\ + + Module: analyses variable-sensitivity + + Author: Owen Jones owen.jones@diffblue.com + +\*******************************************************************/ +#ifndef CPROVER_ANALYSES_VARIABLE_SENSITIVITY_VARIABLE_SENSITIVITY_OBJECT_FACTORY_H +#define CPROVER_ANALYSES_VARIABLE_SENSITIVITY_VARIABLE_SENSITIVITY_OBJECT_FACTORY_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class variable_sensitivity_object_factoryt +{ +public: + static variable_sensitivity_object_factoryt &instance() + { + return s_instance; + } + abstract_object_pointert get_abstract_object( + const typet type, + bool top, + bool bottom, + const exprt &e, + const abstract_environmentt &environment, + const namespacet &ns); + void set_options(optionst &options); + +private: + variable_sensitivity_object_factoryt():initialized(false) + {} + static variable_sensitivity_object_factoryt s_instance; + enum ABSTRACT_OBJECT_TYPET + { + TWO_VALUE, + CONSTANT, + ARRAY_SENSITIVE, + ARRAY_INSENSITIVE, + POINTER_SENSITIVE, + POINTER_INSENSITIVE, + STRUCT_SENSITIVE, + STRUCT_INSENSITIVE + }; + ABSTRACT_OBJECT_TYPET get_abstract_object_type(const typet type); + template + abstract_object_pointert initialize_abstract_object( + const typet type, + bool top, + bool bottom, + const exprt &e, + const abstract_environmentt &enviroment, + const namespacet &ns); + bool has_variables_flag; + bool has_structs_flag; + bool has_arrays_flag; + bool has_pointers_flag; + bool initialized; +}; + +/*******************************************************************\ + +Function: variable_sensitivity_object_factoryt::initialize_abstract_object + + Inputs: + abstract_object_classt - the class to use for the abstract object + type - the type of the variable + top - whether the abstract object should be top in the two-value domain + bottom - whether the abstract object should be bottom in the two-value domain + e - if top and bottom are false this expression is used as the starting + pointer for the abstract object + ns - namespace, used when following the input type + + Outputs: An abstract object of the appropriate type. + + Purpose: Initialize the abstract object class and return it. + +\*******************************************************************/ + +template +abstract_object_pointert variable_sensitivity_object_factoryt:: + initialize_abstract_object( + const typet type, + bool top, + bool bottom, + const exprt &e, + const abstract_environmentt &enviroment, + const namespacet &ns) +{ + if(top || bottom) + { + return abstract_object_pointert( + new abstract_object_classt(type, top, bottom)); + } + else + { + assert(type==ns.follow(e.type())); + return abstract_object_pointert( + new abstract_object_classt(e, enviroment, ns)); + } +} + +#endif // CPROVER_ANALYSES_VARIABLE_SENSITIVITY_VARIABLE_SENSITIVITY_OBJECT_FACTORY_H // NOLINT(*) diff --git a/src/goto-analyzer/Makefile b/src/goto-analyzer/Makefile index 9eb45165f9c..a849e338848 100644 --- a/src/goto-analyzer/Makefile +++ b/src/goto-analyzer/Makefile @@ -1,6 +1,8 @@ SRC = goto_analyzer_main.cpp \ goto_analyzer_parse_options.cpp \ static_analyzer.cpp \ + static_show_domain.cpp \ + static_simplifier.cpp \ taint_analysis.cpp \ taint_parser.cpp \ unreachable_instructions.cpp \ diff --git a/src/goto-analyzer/goto_analyzer_parse_options.cpp b/src/goto-analyzer/goto_analyzer_parse_options.cpp index c783243a0d3..e712312642f 100644 --- a/src/goto-analyzer/goto_analyzer_parse_options.cpp +++ b/src/goto-analyzer/goto_analyzer_parse_options.cpp @@ -1,6 +1,6 @@ /*******************************************************************\ -Module: Goto-Analyser Command Line Option Processing +Module: Goto-Analyzer Command Line Option Processing Author: Daniel Kroening, kroening@kroening.com @@ -26,6 +26,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include +#include #include #include #include @@ -33,6 +34,8 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include +#include #include #include @@ -43,12 +46,16 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include + #include #include "goto_analyzer_parse_options.h" #include "taint_analysis.h" #include "unreachable_instructions.h" #include "static_analyzer.h" +#include "static_show_domain.h" +#include "static_simplifier.h" /*******************************************************************\ @@ -138,7 +145,7 @@ void goto_analyzer_parse_optionst::get_command_line_options(optionst &options) exit(1); } - #if 0 +#if 0 if(cmdline.isset("c89")) config.ansi_c.set_c89(); @@ -156,9 +163,9 @@ void goto_analyzer_parse_optionst::get_command_line_options(optionst &options) if(cmdline.isset("cpp11")) config.cpp.set_cpp11(); - #endif +#endif - #if 0 +#if 0 // check assertions if(cmdline.isset("no-assertions")) options.set_option("assertions", false); @@ -174,7 +181,118 @@ void goto_analyzer_parse_optionst::get_command_line_options(optionst &options) // magic error label if(cmdline.isset("error-label")) options.set_option("error-label", cmdline.get_values("error-label")); - #endif +#endif + + // Output format choice + options.set_option("text", false); + options.set_option("json", false); + options.set_option("xml", false); + options.set_option("dot", false); + options.set_option("outfile", "-"); + + if(cmdline.isset("text")) + { + options.set_option("text", true); + options.set_option("outfile", cmdline.get_value("text")); + } + else if(cmdline.isset("json")) + { + options.set_option("json", true); + options.set_option("outfile", cmdline.get_value("json")); + } + else if(cmdline.isset("xml")) + { + options.set_option("xml", true); + options.set_option("outfile", cmdline.get_value("xml")); + } + else if(cmdline.isset("dot")) + { + options.set_option("dot", true); + options.set_option("outfile", cmdline.get_value("dot")); + } + else + { + options.set_option("text", true); + } + + // Task options + options.set_option("show", false); + options.set_option("verify", false); + options.set_option("simplify", false); + + if(cmdline.isset("show") || + cmdline.isset("show-intervals") || + cmdline.isset("show-non-null")) + options.set_option("show", true); + else if(cmdline.isset("verify")) + options.set_option("verify", true); + else if(cmdline.isset("simplify")) + { + options.set_option("simplify", true); + options.set_option("outfile", cmdline.get_value("simplify")); + } + + if(!(options.get_bool_option("show") || + options.get_bool_option("verify") || + options.get_bool_option("simplify"))) + { + status() << "Task defaults to --show" << eom; + options.set_option("show", true); + } + + // For development allow slicing to be disabled in the simplify task + options.set_option( + "simplify-slicing", + !(cmdline.isset("no-simplify-slicing"))); + + // Abstract interpreter choice + options.set_option("flow-sensitive", false); + options.set_option("concurrent", false); + + if(cmdline.isset("flow-sensitive")) + options.set_option("flow-sensitive", true); + else if(cmdline.isset("concurrent")) + options.set_option("concurrent", true); + else + options.set_option("flow-sensitive", true); + + // Domain choice + options.set_option("constants", false); + options.set_option("intervals", false); + options.set_option("non-null", false); + options.set_option("variable", false); + options.set_option("dependence-graph", false); + + if(cmdline.isset("intervals") || + cmdline.isset("show-intervals")) + options.set_option("intervals", true); + else if(cmdline.isset("non-null") || + cmdline.isset("show-non-null")) + options.set_option("non-null", true); + else if(cmdline.isset("constants")) + options.set_option("constants", true); + else if(cmdline.isset("variable")) + options.set_option("variable", true); + else if(cmdline.isset("dependence-graph")) + options.set_option("dependence-graph", true); + + if(!(options.get_bool_option("constants") || + options.get_bool_option("intervals") || + options.get_bool_option("non-null") || + options.get_bool_option("dependence-graph") || + options.get_bool_option("variable"))) + { + status() << "Domain defaults to --constants" << eom; + options.set_option("constants", true); + } + + if(cmdline.isset("ignore-unresolved-calls")) + options.set_option("ignore-unresolved-calls", true); + + // Configuration of variable sensitivity + options.set_option("pointers", cmdline.isset("pointers")); + options.set_option("arrays", cmdline.isset("arrays")); + options.set_option("structs", cmdline.isset("structs")); } /*******************************************************************\ @@ -191,175 +309,241 @@ Function: goto_analyzer_parse_optionst::doit int goto_analyzer_parse_optionst::doit() { - if(cmdline.isset("version")) + try { - std::cout << CBMC_VERSION << std::endl; - return 0; - } + if(cmdline.isset("version")) + { + std::cout << CBMC_VERSION << std::endl; + return 0; + } - // - // command line options - // + // + // command line options + // + optionst options; + get_command_line_options(options); + eval_verbosity(); - optionst options; - get_command_line_options(options); - eval_verbosity(); + // + // Print a banner + // + status() << "GOTO-ANALYZER version " CBMC_VERSION " " + << sizeof(void *)*8 << "-bit " + << config.this_architecture() << " " + << config.this_operating_system() << eom; - // - // Print a banner - // - status() << "GOTO-ANALYSER version " CBMC_VERSION " " - << sizeof(void *)*8 << "-bit " - << config.this_architecture() << " " - << config.this_operating_system() << eom; + register_languages(); - register_languages(); + if(initialize_goto_model(goto_model, cmdline, get_message_handler())) + return 6; - if(initialize_goto_model(goto_model, cmdline, get_message_handler())) - return 6; + goto_functionst::function_mapt::const_iterator f_it= + goto_model.goto_functions.function_map.find( + goto_functionst::entry_point()); - if(process_goto_program(options)) - return 6; + if(f_it==goto_model.goto_functions.function_map.end()) + { + error() << "Entry point not found" << eom; + return 6; + } - if(cmdline.isset("taint")) - { - std::string taint_file=cmdline.get_value("taint"); + if(process_goto_program(options)) + return 6; + + status() << "Starting analysis" << eom; - if(cmdline.isset("show-taint")) + if(cmdline.isset("taint")) { - taint_analysis(goto_model, taint_file, get_message_handler(), true, ""); - return 0; + std::string taint_file=cmdline.get_value("taint"); + + if(cmdline.isset("show-taint")) + { + taint_analysis(goto_model, taint_file, get_message_handler(), true, ""); + return 0; + } + else + { + std::string json_file=cmdline.get_value("json"); + bool result=taint_analysis( + goto_model, + taint_file, + get_message_handler(), + false, + json_file); + return result?10:0; + } } - else + + if(cmdline.isset("unreachable-instructions")) { - std::string json_file=cmdline.get_value("json"); - bool result= - taint_analysis( - goto_model, taint_file, get_message_handler(), false, json_file); - return result?10:0; - } - } + const std::string json_file=cmdline.get_value("json"); - if(cmdline.isset("unreachable-instructions")) - { - const std::string json_file=cmdline.get_value("json"); + if(json_file.empty()) + unreachable_instructions(goto_model, false, std::cout); + else if(json_file=="-") + unreachable_instructions(goto_model, true, std::cout); + else + { + std::ofstream ofs(json_file); + if(!ofs) + { + error() << "Failed to open json output `" + << json_file << "'" << eom; + return 6; + } + + unreachable_instructions(goto_model, true, ofs); + } - if(json_file.empty()) - unreachable_instructions(goto_model, false, std::cout); - else if(json_file=="-") - unreachable_instructions(goto_model, true, std::cout); - else + return 0; + } + + if(cmdline.isset("unreachable-functions")) { - std::ofstream ofs(json_file); - if(!ofs) + const std::string json_file=cmdline.get_value("json"); + + if(json_file.empty()) + unreachable_functions(goto_model, false, std::cout); + else if(json_file=="-") + unreachable_functions(goto_model, true, std::cout); + else { - error() << "Failed to open json output `" - << json_file << "'" << eom; - return 6; + std::ofstream ofs(json_file); + if(!ofs) + { + error() << "Failed to open json output `" + << json_file << "'" << eom; + return 6; + } + + unreachable_functions(goto_model, true, ofs); } - unreachable_instructions(goto_model, true, ofs); + return 0; } - return 0; - } + if(cmdline.isset("reachable-functions")) + { + const std::string json_file=cmdline.get_value("json"); - if(cmdline.isset("unreachable-functions")) - { - const std::string json_file=cmdline.get_value("json"); + if(json_file.empty()) + reachable_functions(goto_model, false, std::cout); + else if(json_file=="-") + reachable_functions(goto_model, true, std::cout); + else + { + std::ofstream ofs(json_file); + if(!ofs) + { + error() << "Failed to open json output `" + << json_file << "'" << eom; + return 6; + } + + reachable_functions(goto_model, true, ofs); + } - if(json_file.empty()) - unreachable_functions(goto_model, false, std::cout); - else if(json_file=="-") - unreachable_functions(goto_model, true, std::cout); - else + return 0; + } + + if(cmdline.isset("show-local-may-alias")) { - std::ofstream ofs(json_file); - if(!ofs) + namespacet ns(goto_model.symbol_table); + + forall_goto_functions(it, goto_model.goto_functions) { - error() << "Failed to open json output `" - << json_file << "'" << eom; - return 6; + std::cout << ">>>>\n"; + std::cout << ">>>> " << it->first << '\n'; + std::cout << ">>>>\n"; + local_may_aliast local_may_alias(it->second); + local_may_alias.output(std::cout, it->second, ns); + std::cout << '\n'; } - unreachable_functions(goto_model, true, ofs); + return 0; } - return 0; - } + label_properties(goto_model); - if(cmdline.isset("reachable-functions")) - { - const std::string json_file=cmdline.get_value("json"); + if(cmdline.isset("show-properties")) + { + show_properties(goto_model, get_ui()); + return 0; + } + + if(set_properties()) + return 7; + + // Store options in static variable_sensitivity_object_factory object + variable_sensitivity_object_factoryt::instance().set_options(options); - if(json_file.empty()) - reachable_functions(goto_model, false, std::cout); - else if(json_file=="-") - reachable_functions(goto_model, true, std::cout); + // Output file factory + std::ostream *out; + const std::string outfile=options.get_option("outfile"); + if(outfile=="-") + out=&std::cout; else { - std::ofstream ofs(json_file); - if(!ofs) + if(options.get_bool_option("simplify")) + out=new std::ofstream(outfile, std::ios::binary); + else + out=new std::ofstream(outfile); + + if(!*out) { - error() << "Failed to open json output `" - << json_file << "'" << eom; + error() << "Failed to open output file `" << outfile << "'" << eom; return 6; } - - reachable_functions(goto_model, true, ofs); } - return 0; - } - - if(cmdline.isset("show-local-may-alias")) - { - namespacet ns(goto_model.symbol_table); - - forall_goto_functions(it, goto_model.goto_functions) + // Run the analysis + bool result=true; + if(options.get_bool_option("show")) + result= + static_show_domain( + goto_model, + options, + get_message_handler(), + *out); + else if(options.get_bool_option("verify")) + result=static_analyzer(goto_model, options, get_message_handler(), *out); + else if(options.get_bool_option("simplify")) + result= + static_simplifier( + goto_model, + options, + get_message_handler(), + *out); + else { - std::cout << ">>>>\n"; - std::cout << ">>>> " << it->first << '\n'; - std::cout << ">>>>\n"; - local_may_aliast local_may_alias(it->second); - local_may_alias.output(std::cout, it->second, ns); - std::cout << '\n'; + error() << "No task given" << eom; + return 6; } - return 0; - } - - label_properties(goto_model); + if(out!=&std::cout) + delete out; - if(cmdline.isset("show-properties")) + return result?10:0; + } + catch(const char *e) { - show_properties(goto_model, get_ui()); - return 0; + error() << e << eom; + return 6; } - - if(set_properties()) - return 7; - - if(cmdline.isset("show-intervals")) + catch(const std::string e) { - show_intervals(goto_model, std::cout); - return 0; + error() << e << eom; + return 6; } - - if(cmdline.isset("non-null") || - cmdline.isset("intervals")) + catch(int x) { - optionst options; - options.set_option("json", cmdline.get_value("json")); - options.set_option("xml", cmdline.get_value("xml")); - bool result= - static_analyzer(goto_model, options, get_message_handler()); - return result?10:0; + return x; + } + catch(std::bad_alloc) + { + error() << "Out of memory" << eom; + return 6; } - - error() << "no analysis option given -- consider reading --help" - << eom; - return 6; } /*******************************************************************\ @@ -381,19 +565,16 @@ bool goto_analyzer_parse_optionst::set_properties() if(cmdline.isset("property")) ::set_properties(goto_model, cmdline.get_values("property")); } - catch(const char *e) { error() << e << eom; return true; } - catch(const std::string e) { error() << e << eom; return true; } - catch(int) { return true; @@ -474,24 +655,20 @@ bool goto_analyzer_parse_optionst::process_goto_program( return true; } } - catch(const char *e) { error() << e << eom; return true; } - catch(const std::string e) { error() << e << eom; return true; } - catch(int) { return true; } - catch(std::bad_alloc) { error() << "Out of memory" << eom; @@ -517,7 +694,7 @@ void goto_analyzer_parse_optionst::help() { std::cout << "\n" - "* * GOTO-ANALYSER " CBMC_VERSION " - Copyright (C) 2016 "; + "* * GOTO-ANALYZER " CBMC_VERSION " - Copyright (C) 2017 "; std::cout << "(" << (sizeof(void *)*8) << "-bit version)"; @@ -532,8 +709,35 @@ void goto_analyzer_parse_optionst::help() " goto-analyzer [-h] [--help] show help\n" " goto-analyzer file.c ... source file names\n" "\n" - "Analyses:\n" + "Task options:\n" + " --show display the abstract domains\n" + // NOLINTNEXTLINE(whitespace/line_length) + " --verify use the abstract domains to check assertions\n" + // NOLINTNEXTLINE(whitespace/line_length) + " --simplify file_name use the abstract domains to simplify the program\n" + "\n" + "Abstract interpreter options:\n" + " --flow-sensitive use flow-sensitive abstract interpreter\n" + " --concurrent use concurrency-aware abstract interpreter\n" "\n" + "Domain options:\n" + " --constants constant domain\n" + " --intervals interval domain\n" + " --non-null non-null domain\n" + " --dependence-graph data and control dependencies between instructions\n" // NOLINT(*) + " --variable variable sensitivity domain\n" + " --arrays enable array sensitivity in the variable sensitivity domain\n" // NOLINT(*) + " --pointers enable pointer sensitivity in the variable sensitivity domain\n" // NOLINT(*) + " --structs enable struct sensitivity in the variable sensitivity domain\n" // NOLINT(*) + "\n" + "Output options:\n" + " --text file_name output results in plain text to given file\n" + // NOLINTNEXTLINE(whitespace/line_length) + " --json file_name output results in JSON format to given file\n" + " --xml file_name output results in XML format to given file\n" + " --dot file_name output results in DOT format to given file\n" + "\n" + "Other analyses:\n" // NOLINTNEXTLINE(whitespace/line_length) " --taint file_name perform taint analysis using rules in given file\n" " --unreachable-instructions list dead code\n" @@ -541,13 +745,6 @@ void goto_analyzer_parse_optionst::help() " --unreachable-functions list functions unreachable from the entry point\n" // NOLINTNEXTLINE(whitespace/line_length) " --reachable-functions list functions reachable from the entry point\n" - " --intervals interval analysis\n" - " --non-null non-null analysis\n" - "\n" - "Analysis options:\n" - // NOLINTNEXTLINE(whitespace/line_length) - " --json file_name output results in JSON format to given file\n" - " --xml file_name output results in XML format to given file\n" "\n" "C/C++ frontend options:\n" " -I path set include path (C/C++)\n" diff --git a/src/goto-analyzer/goto_analyzer_parse_options.h b/src/goto-analyzer/goto_analyzer_parse_options.h index 538bf47ac3e..fee5b84738a 100644 --- a/src/goto-analyzer/goto_analyzer_parse_options.h +++ b/src/goto-analyzer/goto_analyzer_parse_options.h @@ -4,6 +4,98 @@ Module: Goto-Analyser Command Line Option Processing Author: Daniel Kroening, kroening@kroening.com +Goto-analyze is the tool front-end for CPROVER's classic style abstract +interpretation analyses. By "classic style" I mean, domains are C++ +objects, transformers are computed using C++ functions and the +fix-points are computed by iteration. This is in contrast to 2LS's +approach where everything is computed using quantifier-elimination. + +The analyses are mostly in analyses/ and although they are used in other +places in the code, the goal is that goto-analyze should eventually +provide an executable front-end for all of them. + +There are a lot of different analyses and a lot of ways they can be +used. Goto-analyze has five, largely independent, sets of options: + +1. Task : What you do once you've computed the domains. +2. Abstract interpreter : What kind of abstract interpretation you do. +3. Domain : What domain you use. +4. Sensitivity : How that domain handles things like arrays, pointers, etc. + (see variable_sensitivity_domain.h) +5. Output : What you do with the results. + +Formally speaking, 2, 3 and 4 are an artificial distinction as they are +all really parts of the "what domain" question. However they correspond +to parts of our code architecture, so ... they should stay. + +Ideally, the cross product of options should be supported but ... in +practice there will always be ones that are not meaningful. Those +should give errors. In addition there are some analyses which are +currently stand alone as they don't fit directly in to this model. For +example the unwind bounds analysis, which is both the task, the abstract +interpreter and the output. Where possible these should be integrated / +support the other options. In the case of the unwind analysis this +means the domain and it's sensitivity should be configurable. + + +Task +---- + +Tasks are implemented by the relevant file in goto-analyze/static_*. At +the moment they are each responsible for building the domain / using the +other options. As much as possible of this code should be shared. Some +of these inherit from messaget. They all probably should. + +Show : Prints out the domains for inspection or further use. + +Verify : Uses the domain to check all assertions in the code, marking +each one "SUCCESS" (the assertion always holds), "FAILURE if +reachable" (the assertion never holds), "UNKNOWN" (the assertion may or +may not hold). This is implemented using domain_simplify(). + +Simplify : Generates a new goto program with branch conditions, +assertions, assumptions and assignments simplified using the information +in the domain (again using domain_simplify()). This task is intended to +be used as a preprocessing step for other analysis. + +Invariants : (Not implemented yet) Use the domains to add assume() +statements to the code giving invariants generated from the domain. +These assumes don't reduce the space of possible executions; they make +existing invariants explicit. Again, intended as a preprocessing step. + + +Abstract Interpreter +-------------------- + +This option is effectively about how we compute the fix-point(s) / +which child class of ai_baset we use. I.E. ait or +concurrency_aware_ait, etc. For migrating / refactor / +unifying with the pointer analysis code we might want a +location_insensitive_ait or something but this is not urgent. +We will need a context_aware_ait, quite possibly the one +@danpoe has written elsewhere. + + +Domain +------ + +Which child of ai_domain_baset we use to represent the abstract state at +each location / implement the transformers. I expect most of these will +be non-relational (i.e. an abstract object for each variable) due to the +cost of implementing effective non-relational domains in this style vs. +using 2LS. The exception might be equalities, which we could implement +here. + + +Output +------ + +Text, XML, JSON plus some others for specific domains such as dependence +graphs in DOT format. + + + + \*******************************************************************/ #ifndef CPROVER_GOTO_ANALYZER_GOTO_ANALYZER_PARSE_OPTIONS_H @@ -38,11 +130,19 @@ class optionst; "(gcc)(arch):" \ "(taint):(show-taint)" \ "(show-local-may-alias)" \ - "(json):(xml):" \ + "(json):(xml):(text):(dot):" \ "(unreachable-instructions)(unreachable-functions)" \ "(reachable-functions)" \ "(intervals)(show-intervals)" \ - "(non-null)(show-non-null)" + "(non-null)(show-non-null)" \ + "(variable)" \ + "(pointers)(arrays)(structs)" \ + "(constants)" \ + "(dependence-graph)" \ + "(show)(verify)(simplify):" \ + "(flow-sensitive)(concurrent)" \ + "(no-simplify-slicing)" \ + "(ignore-unresolved-calls)" class goto_analyzer_parse_optionst: public parse_options_baset, diff --git a/src/goto-analyzer/static_analyzer.cpp b/src/goto-analyzer/static_analyzer.cpp index 1168cff1a73..0cc30247635 100644 --- a/src/goto-analyzer/static_analyzer.cpp +++ b/src/goto-analyzer/static_analyzer.cpp @@ -8,25 +8,30 @@ Author: Daniel Kroening, kroening@kroening.com #include -#include #include +#include #include #include +#include +#include #include "static_analyzer.h" +template class static_analyzert:public messaget { public: static_analyzert( const goto_modelt &_goto_model, const optionst &_options, - message_handlert &_message_handler): + message_handlert &_message_handler, + std::ostream &_out): messaget(_message_handler), goto_functions(_goto_model.goto_functions), ns(_goto_model.symbol_table), - options(_options) + options(_options), + out(_out) { } @@ -36,38 +41,41 @@ class static_analyzert:public messaget const goto_functionst &goto_functions; const namespacet ns; const optionst &options; + std::ostream &out; // analyses - ait interval_analysis; + analyzerT domain; void plain_text_report(); - void json_report(const std::string &); - void xml_report(const std::string &); - - tvt eval(goto_programt::const_targett); + void json_report(); + void xml_report(); }; /*******************************************************************\ -Function: static_analyzert::operator() +Function: static_analyzert::operator() - Inputs: + Inputs: None. - Outputs: + Outputs: false on success, true on failure. - Purpose: + Purpose: Run the analysis, check the assertions and report in the + correct format. \*******************************************************************/ -bool static_analyzert::operator()() +template +bool static_analyzert::operator()() { - status() << "performing interval analysis" << eom; - interval_analysis(goto_functions, ns); + status() << "Computing abstract states" << eom; + domain(goto_functions, ns); + + status() << "Checking assertions" << eom; - if(!options.get_option("json").empty()) - json_report(options.get_option("json")); - else if(!options.get_option("xml").empty()) - xml_report(options.get_option("xml")); + if(options.get_bool_option("json")) + json_report(); + else if(options.get_bool_option("xml")) + xml_report(); else plain_text_report(); @@ -76,39 +84,18 @@ bool static_analyzert::operator()() /*******************************************************************\ -Function: static_analyzert::eval - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -tvt static_analyzert::eval(goto_programt::const_targett t) -{ - exprt guard=t->guard; - interval_domaint d=interval_analysis[t]; - d.assume(not_exprt(guard), ns); - if(d.is_bottom()) - return tvt(true); - return tvt::unknown(); -} - -/*******************************************************************\ - -Function: static_analyzert::plain_text_report +Function: static_analyzert::plain_text_report - Inputs: + Inputs: None. - Outputs: + Outputs: Text report via out. - Purpose: + Purpose: Check the assertions and give results as text. \*******************************************************************/ -void static_analyzert::plain_text_report() +template +void static_analyzert::plain_text_report() { unsigned pass=0, fail=0, unknown=0; @@ -127,51 +114,64 @@ void static_analyzert::plain_text_report() if(!i_it->is_assert()) continue; - tvt r=eval(i_it); + exprt e(i_it->guard); + domain[i_it].ai_simplify(e, ns); result() << '[' << i_it->source_location.get_property_id() << ']' << ' '; result() << i_it->source_location; + if(!i_it->source_location.get_comment().empty()) result() << ", " << i_it->source_location.get_comment(); + result() << ": "; - if(r.is_true()) - result() << "SUCCESS"; - else if(r.is_false()) - result() << "FAILURE"; - else - result() << "UNKNOWN"; - result() << eom; - if(r.is_true()) + if(e.is_true()) + { + result() << "Success"; pass++; - else if(r.is_false()) + } + else if(e.is_false()) + { + result() << "Failure (if reachable)"; fail++; + } + else if(domain[i_it].is_bottom()) + { + result() << "Success (unreachable)"; + pass++; + } else + { + result() << "Unknown"; unknown++; + } + + result() << eom; } status() << '\n'; } - status() << "SUMMARY: " << pass << " pass, " << fail << " fail, " + status() << "Summary: " << pass << " pass, " << fail << " fail if reachable, " << unknown << " unknown\n"; } /*******************************************************************\ -Function: static_analyzert::json_report +Function: static_analyzert::json_report - Inputs: + Inputs: None. - Outputs: + Outputs: JSON report via out. - Purpose: + Purpose: Check the assertions and give results as JSON. \*******************************************************************/ -void static_analyzert::json_report(const std::string &file_name) +template +void static_analyzert::json_report() { json_arrayt json_result; @@ -188,49 +188,39 @@ void static_analyzert::json_report(const std::string &file_name) if(!i_it->is_assert()) continue; - tvt r=eval(i_it); + exprt e(i_it->guard); + domain[i_it].ai_simplify(e, ns); json_objectt &j=json_result.push_back().make_object(); - if(r.is_true()) + if(e.is_true()) j["status"]=json_stringt("SUCCESS"); - else if(r.is_false()) - j["status"]=json_stringt("FAILURE"); + else if(e.is_false()) + j["status"]=json_stringt("FAILURE (if reachable)"); else j["status"]=json_stringt("UNKNOWN"); - j["file"]=json_stringt(id2string(i_it->source_location.get_file())); - j["line"]=json_numbert(id2string(i_it->source_location.get_line())); - j["description"]=json_stringt(id2string( - i_it->source_location.get_comment())); + j["sourceLocation"]=json(i_it->source_location); } } - - std::ofstream out(file_name); - if(!out) - { - error() << "failed to open JSON output file `" - << file_name << "'" << eom; - return; - } - - status() << "Writing report to `" << file_name << "'" << eom; + status() << "Writing JSON report" << eom; out << json_result; } /*******************************************************************\ -Function: static_analyzert::xml_report +Function: static_analyzert::xml_report - Inputs: + Inputs: None. - Outputs: + Outputs: XML report via out. - Purpose: + Purpose: Check the assertions and give results as XML. \*******************************************************************/ -void static_analyzert::xml_report(const std::string &file_name) +template +void static_analyzert::xml_report() { xmlt xml_result; @@ -247,33 +237,27 @@ void static_analyzert::xml_report(const std::string &file_name) if(!i_it->is_assert()) continue; - tvt r=eval(i_it); + exprt e(i_it->guard); + domain[i_it].ai_simplify(e, ns); xmlt &x=xml_result.new_element("result"); - if(r.is_true()) + if(e.is_true()) x.set_attribute("status", "SUCCESS"); - else if(r.is_false()) - x.set_attribute("status", "FAILURE"); + else if(e.is_false()) + x.set_attribute("status", "FAILURE (if reachable)"); else x.set_attribute("status", "UNKNOWN"); x.set_attribute("file", id2string(i_it->source_location.get_file())); x.set_attribute("line", id2string(i_it->source_location.get_line())); x.set_attribute( - "description", id2string(i_it->source_location.get_comment())); + "description", + id2string(i_it->source_location.get_comment())); } } - std::ofstream out(file_name); - if(!out) - { - error() << "failed to open XML output file `" - << file_name << "'" << eom; - return; - } - - status() << "Writing report to `" << file_name << "'" << eom; + status() << "Writing XML report" << eom; out << xml_result; } @@ -281,40 +265,63 @@ void static_analyzert::xml_report(const std::string &file_name) Function: static_analyzer - Inputs: + Inputs: The goto_model to check, options giving the domain and output, + the message handler and output stream. - Outputs: + Outputs: Report via out. - Purpose: + Purpose: Runs the analyzer, check assertions and generate a report. \*******************************************************************/ bool static_analyzer( const goto_modelt &goto_model, const optionst &options, - message_handlert &message_handler) + message_handlert &message_handler, + std::ostream &out) { - return static_analyzert( - goto_model, options, message_handler)(); -} + messaget m(message_handler); + m.status() << "Selecting abstract domain" << messaget::eom; -/*******************************************************************\ + if(options.get_bool_option("flow-sensitive")) + { + if(options.get_bool_option("constants")) + return static_analyzert> + (goto_model, options, message_handler, out)(); -Function: show_intervals + else if(options.get_bool_option("intervals")) + return static_analyzert> + (goto_model, options, message_handler, out)(); - Inputs: + else if(options.get_bool_option("variable")) + return static_analyzert>( + goto_model, options, message_handler, out)(); - Outputs: + // else if(options.get_bool_option("non-null")) + // return static_analyzert > + // (goto_model, options, message_handler, out)(); + } + else if(options.get_bool_option("concurrent")) + { + // Constant and interval don't have merge_shared yet +#if 0 + if(options.get_bool_option("constants")) + return static_analyzert> + (goto_model, options, message_handler, out)(); + + else if(options.get_bool_option("intervals")) + return static_analyzert > + (goto_model, options, message_handler, out)(); + + // else if(options.get_bool_option("non-null")) + // return static_analyzert > + // (goto_model, options, message_handler, out)(); +#endif + } - Purpose: + m.status() << "Task / Interpreter / Domain combination not supported" + << messaget::eom; -\*******************************************************************/ - -void show_intervals( - const goto_modelt &goto_model, - std::ostream &out) -{ - ait interval_analysis; - interval_analysis(goto_model); - interval_analysis.output(goto_model, out); + return true; } diff --git a/src/goto-analyzer/static_analyzer.h b/src/goto-analyzer/static_analyzer.h index 3d964a2964a..fc320ad734b 100644 --- a/src/goto-analyzer/static_analyzer.h +++ b/src/goto-analyzer/static_analyzer.h @@ -20,10 +20,7 @@ Author: Daniel Kroening, kroening@kroening.com bool static_analyzer( const goto_modelt &, const optionst &, - message_handlert &); - -void show_intervals( - const goto_modelt &, + message_handlert &, std::ostream &); #endif // CPROVER_GOTO_ANALYZER_STATIC_ANALYZER_H diff --git a/src/goto-analyzer/static_show_domain.cpp b/src/goto-analyzer/static_show_domain.cpp new file mode 100644 index 00000000000..9046bb56f07 --- /dev/null +++ b/src/goto-analyzer/static_show_domain.cpp @@ -0,0 +1,118 @@ +/*******************************************************************\ + +Module: + +Author: Martin Brain, martin.brain@cs.ox.ac.uk + +\*******************************************************************/ + +// #define DEBUG + +#ifdef DEBUG +#include +#endif + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "static_show_domain.h" + +/*******************************************************************\ + +Function: static_show_domain + + Inputs: The goto_model to analyze, options giving the domain and output, + the message handler and output stream. + + Outputs: The abstract domain via out. + + Purpose: Runs the analyzer and then prints out the domain. + +\*******************************************************************/ + +bool static_show_domain( + const goto_modelt &goto_model, + const optionst &options, + message_handlert &message_handler, + std::ostream &out) +{ + ai_baset *domain=nullptr; + + namespacet ns(goto_model.symbol_table); + messaget m(message_handler); + + m.status() << "Selecting abstract domain" << messaget::eom; + + if(options.get_bool_option("flow-sensitive")) + { + if(options.get_bool_option("constants")) + { + domain= + new constant_propagator_ait( + goto_model.goto_functions, + options.get_bool_option("ignore-unresolved-calls")); + } + else if(options.get_bool_option("intervals")) + domain=new ait(); + else if(options.get_bool_option("dependence-graph")) + domain=new dependence_grapht(ns); + else if(options.get_bool_option("variable")) + domain=new ait(); + } + else if(options.get_bool_option("concurrent")) + { + // Constant and interval don't have merge_shared yet +#if 0 + if(options.get_bool_option("constants")) + domain=new concurrency_aware_ait(); + + else if(options.get_bool_option("intervals")) + domain=new concurrency_aware_ait(); + + // else if(options.get_bool_option("non-null")) + // domain=new concurrency_aware_ait(); +#endif + } + + if(domain==nullptr) + { + m.status() << "Task / Interpreter / Domain combination not supported" + << messaget::eom; + return true; + } + + m.status() << "Computing abstract states" << messaget::eom; + (*domain)(goto_model); + + m.status() << "Outputting abstract states" << messaget::eom; + + if(options.get_bool_option("json")) + out << domain->output_json(goto_model); + else if(options.get_bool_option("xml")) + out << domain->output_xml(goto_model); + else if(options.get_bool_option("dot") && + options.get_bool_option("dependence-graph")) + { + dependence_grapht *d=dynamic_cast(domain); + assert(d!=NULL); + + out << "digraph g {\n"; + d->output_dot(out); + out << "}\n"; + } + else + domain->output(goto_model, out); + + delete domain; + + return false; +} diff --git a/src/goto-analyzer/static_show_domain.h b/src/goto-analyzer/static_show_domain.h new file mode 100644 index 00000000000..bedb1e7faed --- /dev/null +++ b/src/goto-analyzer/static_show_domain.h @@ -0,0 +1,25 @@ +/*******************************************************************\ + +Module: + +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 + +bool static_show_domain( + const goto_modelt &, + const optionst &, + message_handlert &, + std::ostream &); + +#endif diff --git a/src/goto-analyzer/static_simplifier.cpp b/src/goto-analyzer/static_simplifier.cpp new file mode 100644 index 00000000000..d3abcd7ee6b --- /dev/null +++ b/src/goto-analyzer/static_simplifier.cpp @@ -0,0 +1,289 @@ +/*******************************************************************\ + +Module: + +Author: Lucas Cordeiro, lucas.cordeiro@cs.ox.ac.uk + +\*******************************************************************/ + +// #define DEBUG + +#ifdef DEBUG +#include +#endif + +#include + +#include +#include +#include + +#include +#include +#include + +#include "static_simplifier.h" + +template +class static_simplifiert:public messaget +{ +public: + static_simplifiert( + goto_modelt &_goto_model, + const optionst &_options, + message_handlert &_message_handler, + std::ostream &_out): + messaget(_message_handler), + goto_functions(_goto_model.goto_functions), + ns(_goto_model.symbol_table), + options(_options), + out(_out) + { + } + + bool operator()(void); + +protected: + goto_functionst &goto_functions; + const namespacet ns; + const optionst &options; + std::ostream &out; + + // analyses + analyzerT domain; + + void simplify_program(void); + bool simplify_guard(goto_programt::instructionst::iterator &i_it); +}; + +/*******************************************************************\ + +Function: static_simplifiert::operator() + + Inputs: None. + + Outputs: false on success, true on failure. + + Purpose: Run the analysis, check the assertions and report in the + correct format. + +\*******************************************************************/ + +template +bool static_simplifiert::operator()(void) +{ + status() << "Computing abstract states" << eom; + domain(goto_functions, ns); + + status() << "Simplifying program" << eom; + simplify_program(); + + // Remove obviously unreachable things and (now) unconditional branches + if(options.get_bool_option("simplify-slicing")) + { + status() << "Removing unreachable instructions" << eom; + + remove_skip(goto_functions); // Removes goto false + goto_functions.update(); + + remove_unreachable(goto_functions); // Convert unreachable to skips + goto_functions.update(); + + remove_skip(goto_functions); // Remove all of the new skips + goto_functions.update(); + } + + status() << "Writing goto binary" << eom; + return write_goto_binary(out, ns.get_symbol_table(), goto_functions); +} + +/*******************************************************************\ + +Function: static_simplifiert::simplify_program + + Inputs: None. + + Outputs: None. + + Purpose: Simplifies the program using the information in the abstract + domain. + +\*******************************************************************/ + +template +void static_simplifiert::simplify_program() +{ + struct counterst + { + counterst() : + asserts(0), + assumes(0), + gotos(0), + assigns(0), + function_calls(0) {} + + unsigned asserts; + unsigned assumes; + unsigned gotos; + unsigned assigns; + unsigned function_calls; + }; + + counterst simplified; + counterst unmodified; + + Forall_goto_functions(f_it, goto_functions) + { + Forall_goto_program_instructions(i_it, f_it->second.body) + { + if(i_it->is_assert()) + { + bool unchanged=domain[i_it].ai_simplify(i_it->guard, ns); + + if(unchanged) + unmodified.asserts++; + else + simplified.asserts++; + } + else if(i_it->is_assume()) + { + bool unchanged=domain[i_it].ai_simplify(i_it->guard, ns); + + if(unchanged) + unmodified.assumes++; + else + simplified.assumes++; + } + else if(i_it->is_goto()) + { + bool unchanged=domain[i_it].ai_simplify(i_it->guard, ns); + + if(unchanged) + unmodified.gotos++; + else + simplified.gotos++; + } + else if(i_it->is_assign()) + { + code_assignt &assign=to_code_assign(i_it->code); + + // Simplification needs to be aware of which side of the + // expression it is handling as: + // i=j + // should simplify to i=1, not to 0=1. + + bool unchanged_lhs= + domain[i_it].ai_simplify(assign.lhs(), ns, true); + + bool unchanged_rhs= + domain[i_it].ai_simplify(assign.rhs(), ns, false); + + if(unchanged_lhs && unchanged_rhs) + unmodified.assigns++; + else + simplified.assigns++; + } + else if(i_it->is_function_call()) + { + code_function_callt &fcall=to_code_function_call(i_it->code); + + bool unchanged=domain[i_it].ai_simplify(fcall.function(), ns); + + exprt::operandst &args=fcall.arguments(); + + for(auto &o : args) + unchanged&=domain[i_it].ai_simplify(o, ns); + + if(unchanged) + unmodified.function_calls++; + else + simplified.function_calls++; + } + } + } + + // Make sure the references are correct. + goto_functions.update(); + + status() << "Simplified: " + << " assert: " << simplified.asserts + << ", assume: " << simplified.assumes + << ", goto: " << simplified.gotos + << ", assigns: " << simplified.assigns + << ", function calls: " << simplified.function_calls + << "\n" + << "Unmodified: " + << " assert: " << unmodified.asserts + << ", assume: " << unmodified.assumes + << ", goto: " << unmodified.gotos + << ", assigns: " << unmodified.assigns + << ", function calls: " << unmodified.function_calls + << eom; + + return; +} + +/*******************************************************************\ + +Function: static_simplifier + + Inputs: The goto_model to analyze and simplify, options giving the + domain, the message handler and output stream. + + Outputs: The simplified goto binary via out. + + Purpose: Runs the analyzer, simplifies and then outputs. + +\*******************************************************************/ + +bool static_simplifier( + goto_modelt &goto_model, + const optionst &options, + message_handlert &message_handler, + std::ostream &out) +{ + messaget m(message_handler); + m.status() << "Selecting abstract domain" << messaget::eom; + + if(options.get_bool_option("flow-sensitive")) + { + if(options.get_bool_option("constants")) + return static_simplifiert> + (goto_model, options, message_handler, out)(); + + else if(options.get_bool_option("intervals")) + return static_simplifiert> + (goto_model, options, message_handler, out)(); + + else if(options.get_bool_option("variable")) + return static_simplifiert>( + goto_model, options, message_handler, out)(); + + // else if(options.get_bool_option("non-null")) + // return static_simplifiert > + // (goto_model, options, message_handler, out)(); + } + else if(options.get_bool_option("concurrent")) + { + // Constant and interval don't have merge_shared yet +#if 0 + if(options.get_bool_option("constants")) + return static_simplifiert< + concurrency_aware_ait> + (goto_model, options, message_handler, out)(); + + else if(options.get_bool_option("intervals")) + return static_simplifiert > + (goto_model, options, message_handler, out)(); + + // else if(options.get_bool_option("non-null")) + // return static_simplifiert > + // (goto_model, options, message_handler, out)(); +#endif + } + + m.status() << "Task / Interpreter / Domain combination not supported" + << messaget::eom; + + return true; +} diff --git a/src/goto-analyzer/static_simplifier.h b/src/goto-analyzer/static_simplifier.h new file mode 100644 index 00000000000..61bb77dad1d --- /dev/null +++ b/src/goto-analyzer/static_simplifier.h @@ -0,0 +1,25 @@ +/*******************************************************************\ + +Module: + +Author: Lucas Cordeiro, lucas.cordeiro@cs.ox.ac.uk + +\*******************************************************************/ + +#ifndef CPROVER_GOTO_ANALYZER_STATIC_SIMPLIFIER_H +#define CPROVER_GOTO_ANALYZER_STATIC_SIMPLIFIER_H + +#include + +#include +#include + +#include + +bool static_simplifier( + goto_modelt &, + const optionst &, + message_handlert &, + std::ostream &); + +#endif diff --git a/src/goto-instrument/goto_instrument_parse_options.cpp b/src/goto-instrument/goto_instrument_parse_options.cpp index 66421b2e1e1..a30fdd4c92a 100644 --- a/src/goto-instrument/goto_instrument_parse_options.cpp +++ b/src/goto-instrument/goto_instrument_parse_options.cpp @@ -507,17 +507,7 @@ int goto_instrument_parse_optionst::doit() reaching_definitions_analysist rd_analysis(ns); rd_analysis(goto_functions, ns); - forall_goto_functions(f_it, goto_functions) - { - if(f_it->second.body_available()) - { - std::cout << "////" << std::endl; - std::cout << "//// Function: " << f_it->first << std::endl; - std::cout << "////" << std::endl; - std::cout << std::endl; - rd_analysis.output(ns, f_it->second.body, std::cout); - } - } + rd_analysis.output(ns, goto_functions, std::cout); return 0; } @@ -530,18 +520,7 @@ int goto_instrument_parse_optionst::doit() dependence_grapht dependence_graph(ns); dependence_graph(goto_functions, ns); - forall_goto_functions(f_it, goto_functions) - { - if(f_it->second.body_available()) - { - std::cout << "////" << std::endl; - std::cout << "//// Function: " << f_it->first << std::endl; - std::cout << "////" << std::endl; - std::cout << std::endl; - dependence_graph.output(ns, f_it->second.body, std::cout); - } - } - + dependence_graph.output(ns, goto_functions, std::cout); dependence_graph.output_dot(std::cout); return 0; diff --git a/src/goto-programs/remove_unreachable.cpp b/src/goto-programs/remove_unreachable.cpp index 14f92e97be1..ac6df4261a8 100644 --- a/src/goto-programs/remove_unreachable.cpp +++ b/src/goto-programs/remove_unreachable.cpp @@ -55,3 +55,9 @@ void remove_unreachable(goto_programt &goto_program) it->make_skip(); } } + +void remove_unreachable(goto_functionst &goto_functions) +{ + Forall_goto_functions(f_it, goto_functions) + remove_unreachable(f_it->second.body); +} diff --git a/src/goto-programs/remove_unreachable.h b/src/goto-programs/remove_unreachable.h index 694cd8c0af8..4fd423641f1 100644 --- a/src/goto-programs/remove_unreachable.h +++ b/src/goto-programs/remove_unreachable.h @@ -12,5 +12,6 @@ Author: Daniel Kroening, kroening@kroening.com #include "goto_functions.h" void remove_unreachable(goto_programt &goto_program); +void remove_unreachable(goto_functionst &goto_functions); #endif // CPROVER_GOTO_PROGRAMS_REMOVE_UNREACHABLE_H diff --git a/src/util/replace_symbol.cpp b/src/util/replace_symbol.cpp index 4dce48d8b93..c81a80fe7cc 100644 --- a/src/util/replace_symbol.cpp +++ b/src/util/replace_symbol.cpp @@ -74,9 +74,11 @@ Function: replace_symbolt::replace \*******************************************************************/ -bool replace_symbolt::replace(exprt &dest) const +bool replace_symbolt::replace( + exprt &dest, + const bool replace_with_const) const { - bool result=true; + bool result=true; // unchanged // first look at type @@ -89,33 +91,75 @@ bool replace_symbolt::replace(exprt &dest) const if(!have_to_replace(dest)) return result; - if(dest.id()==ID_symbol) + if(dest.id()==ID_member) + { + member_exprt &me=to_member_expr(dest); + + if(!replace(me.struct_op(), replace_with_const)) + result=false; + } + else if(dest.id()==ID_index) + { + index_exprt &ie=to_index_expr(dest); + + if(!replace(ie.array(), replace_with_const)) + result=false; + + if(!replace(ie.index())) + result=false; + } + else if(dest.id()==ID_address_of) + { + address_of_exprt &aoe=to_address_of_expr(dest); + + if(!replace(aoe.object(), false)) + result=false; + } + else if(dest.id()==ID_symbol) { + const symbol_exprt &s=to_symbol_expr(dest); + expr_mapt::const_iterator it= - expr_map.find(dest.get(ID_identifier)); + expr_map.find(s.get_identifier()); if(it!=expr_map.end()) { - dest=it->second; + const exprt &e=it->second; + + if(!replace_with_const && e.is_constant()) + return true; + + dest=e; + return false; } } - - Forall_operands(it, dest) - if(!replace(*it)) - result=false; + else + { + Forall_operands(it, dest) + if(!replace(*it)) + result=false; + } const irept &c_sizeof_type=dest.find(ID_C_c_sizeof_type); - if(c_sizeof_type.is_not_nil() && - !replace(static_cast(dest.add(ID_C_c_sizeof_type)))) - result=false; + if(c_sizeof_type.is_not_nil()) + { + typet &type=static_cast(dest.add(ID_C_c_sizeof_type)); + + if(!replace(type)) + result=false; + } const irept &va_arg_type=dest.find(ID_C_va_arg_type); - if(va_arg_type.is_not_nil() && - !replace(static_cast(dest.add(ID_C_va_arg_type)))) - result=false; + if(va_arg_type.is_not_nil()) + { + typet &type=static_cast(dest.add(ID_C_va_arg_type)); + + if(!replace(type)) + result=false; + } return result; } diff --git a/src/util/replace_symbol.h b/src/util/replace_symbol.h index f26c8eb067a..8a1e9b8e22e 100644 --- a/src/util/replace_symbol.h +++ b/src/util/replace_symbol.h @@ -37,7 +37,10 @@ class replace_symbolt type_map.insert(std::pair(identifier, type)); } - virtual bool replace(exprt &dest) const; + virtual bool replace( + exprt &dest, + const bool replace_with_const=true) const; + virtual bool replace(typet &dest) const; void operator()(exprt &dest) const @@ -56,6 +59,11 @@ class replace_symbolt type_map.clear(); } + bool empty() const + { + return expr_map.empty() && type_map.empty(); + } + replace_symbolt(); virtual ~replace_symbolt(); diff --git a/unit/Makefile b/unit/Makefile index d089a0ed540..c3cf1a1e06d 100644 --- a/unit/Makefile +++ b/unit/Makefile @@ -2,6 +2,10 @@ SRC = unit_tests.cpp \ catch_example.cpp \ + analyses/variable-sensitivity/abstract_object/merge.cpp \ + analyses/variable-sensitivity/constant_abstract_value/merge.cpp \ + analyses/variable-sensitivity/constant_array_abstract_object/merge.cpp \ + analyses/variable-sensitivity/full_struct_abstract_object/merge.cpp \ # Empty last line INCLUDES= -I ../src/ -I. diff --git a/unit/analyses/variable-sensitivity/abstract_object/merge.cpp b/unit/analyses/variable-sensitivity/abstract_object/merge.cpp new file mode 100644 index 00000000000..aa33c9bfcf5 --- /dev/null +++ b/unit/analyses/variable-sensitivity/abstract_object/merge.cpp @@ -0,0 +1,110 @@ +/*******************************************************************\ + + Module: Unit tests for variable/sensitivity/abstract_object::merge + + Author: DiffBlue Limited. All rights reserved. + +\*******************************************************************/ + +#include + +#include +#include + +SCENARIO("merge_abstract_object", + "[core][analyses][variable-sensitivity][abstract_object][merge]") +{ + GIVEN("Two abstract objects of type pointer") + { + const typet object_type=signedbv_typet(32); + WHEN("Both are top") + { + abstract_object_pointert op1= + std::make_shared(object_type, true, false); + + abstract_object_pointert op2= + std::make_shared(object_type, true, false); + + bool modifications; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modifications); + + THEN("The result is the original abstract object") + { + // Simple correctness of merge + REQUIRE_FALSE(modifications); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + } + } + WHEN("The first is top, the second is bottom") + { + abstract_object_pointert op1= + std::make_shared(object_type, true, false); + + abstract_object_pointert op2= + std::make_shared(object_type, false, true); + + bool modifications; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modifications); + + THEN("The result is the original abstract object") + { + // Simple correctness of merge + REQUIRE_FALSE(modifications); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + } + } + WHEN("The first is bottom and the second is top") + { + abstract_object_pointert op1= + std::make_shared(object_type, false, true); + abstract_object_pointert op2= + std::make_shared(object_type, true, false); + + bool modifications; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modifications); + + THEN("The result is top and a new abstract object") + { + // Simple correctness of merge + REQUIRE(modifications); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + REQUIRE_FALSE(op1==result); + } + } + WHEN("Both are bottom") + { + abstract_object_pointert op1= + std::make_shared(object_type, false, true); + abstract_object_pointert op2= + std::make_shared(object_type, false, true); + + bool modifications; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modifications); + + THEN("The result is the original abstract object") + { + // Simple correctness of merge + REQUIRE_FALSE(modifications); + REQUIRE_FALSE(result->is_top()); + REQUIRE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + } + } + } +} diff --git a/unit/analyses/variable-sensitivity/constant_abstract_value/merge.cpp b/unit/analyses/variable-sensitivity/constant_abstract_value/merge.cpp new file mode 100644 index 00000000000..3191ee9d132 --- /dev/null +++ b/unit/analyses/variable-sensitivity/constant_abstract_value/merge.cpp @@ -0,0 +1,582 @@ +/*******************************************************************\ + + Module: Unit tests for constant_abstract_valuet::merge + + Author: DiffBlue Limited. All rights reserved. + +\*******************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + + +// Debug printer for irept +std::ostream &operator<<(std::ostream &os, const irept &value) +{ + os << value.pretty(); + return os; +} + +SCENARIO("merge_constant_abstract_value", + "[core][analyses][variable-sensitivity][constant_abstract_value][merge]") +{ + GIVEN("An environment with two values: 1 and 2") + { + const exprt val1=constant_exprt::integer_constant(1); + const exprt val2=constant_exprt::integer_constant(2); + + abstract_environmentt enviroment; + enviroment.make_top(); + symbol_tablet symbol_table; + namespacet ns(symbol_table); + + WHEN("merging constant AO with value " + "with a constant AO with the same value") + { + abstract_object_pointert op1= + std::make_shared(val1, enviroment, ns); + abstract_object_pointert op2= + std::make_shared(val1, enviroment, ns); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast(result); + + THEN("The original abstract object should be returned unchanged") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE_FALSE(modified); + REQUIRE_FALSE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(cast_result->to_constant()==val1); + + // Is optimal + REQUIRE(result==op1); + } + } + WHEN("merging constant AO with value " + "with a constant AO with the different value") + { + abstract_object_pointert op1= + std::make_shared(val1, enviroment, ns); + abstract_object_pointert op2= + std::make_shared(val2, enviroment, ns); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast(result); + + THEN("A new constant abstract object set to top should be returned") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE(modified); + REQUIRE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + + // We currently don't require the value has any reasonable value + + // Since it has modified, we definitely shouldn't be reusing the pointer + REQUIRE_FALSE(result==op1); + } + } + WHEN("merging constant AO with value with a constant AO set to top") + { + abstract_object_pointert op1= + std::make_shared(val1, enviroment, ns); + abstract_object_pointert op2= + std::make_shared(val1.type(), true, false); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast(result); + + THEN("A new AO of the same type set to top ") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE(modified); + REQUIRE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + + // We currently don't require the value has any reasonable value + + // Since it has modified, we definitely shouldn't be reusing the pointer + REQUIRE_FALSE(result==op1); + } + } + WHEN("merging constant AO with value with a constant AO set to bottom") + { + abstract_object_pointert op1= + std::make_shared(val1, enviroment, ns); + abstract_object_pointert op2= + std::make_shared(val1.type(), false, true); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast(result); + + THEN("The original AO should be returned") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE_FALSE(modified); + REQUIRE_FALSE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(cast_result->to_constant()==val1); + + // Is optimal + REQUIRE(result==op1); + } + } + WHEN("merging constant AO set to top with a constant AO with a value") + { + abstract_object_pointert op1= + std::make_shared(val1.type(), true, false); + + abstract_object_pointert op2= + std::make_shared(val1, enviroment, ns); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + THEN("WE should return the same value") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + } + } + WHEN("merging constant AO set to top with a constant AO set to top") + { + abstract_object_pointert op1= + std::make_shared(val1.type(), true, false); + abstract_object_pointert op2= + std::make_shared(val1.type(), true, false); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + THEN("WE should return the same value") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + } + } + WHEN("merging constant AO set to top with a constant AO set to bottom") + { + abstract_object_pointert op1= + std::make_shared(val1.type(), true, false); + abstract_object_pointert op2= + std::make_shared(val1.type(), false, true); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + THEN("WE should return the same value") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + } + } + WHEN("merging constant AO set to bottom with a constant AO with a value") + { + abstract_object_pointert op1= + std::make_shared(val1.type(), false, true); + abstract_object_pointert op2= + std::make_shared(val1, enviroment, ns); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + THEN("We should get an abstract object that has the same value as op2") + { + // Simple correctness of merge + REQUIRE(modified); + REQUIRE_FALSE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + REQUIRE(result->to_constant()==val1); + } + } + WHEN("merging constant AO set to bottom with a constant AO set to top") + { + abstract_object_pointert op1= + std::make_shared(val1.type(), false, true); + abstract_object_pointert op2= + std::make_shared(val1.type(), true, false); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + THEN("We should get a top abstract object back") + { + // Simple correctness of merge + REQUIRE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + } + } + WHEN("merging constant AO set to bottom with a constant AO set to bottom") + { + abstract_object_pointert op1= + std::make_shared(val1.type(), false, true); + abstract_object_pointert op2= + std::make_shared(val1.type(), false, true); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + THEN("We should get the same (bottom) AO back") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE_FALSE(result->is_top()); + REQUIRE(result->is_bottom()); + + // Optimization correctness + REQUIRE(result==op1); + } + } + WHEN("merging constant AO with value with a abstract object set to top") + { + abstract_object_pointert op1= + std::make_shared(val1, enviroment, ns); + abstract_object_pointert op2= + std::make_shared(val1.type(), true, false); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast(result); + + THEN("We should get a new AO of the same type but set to top") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE(modified); + REQUIRE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + + // We currently don't require the value has any reasonable value + + // Since it has modified, we definitely shouldn't be reusing the pointer + REQUIRE_FALSE(result==op1); + } + } + WHEN("merging constant AO with value with a abstract object set to bottom") + { + abstract_object_pointert op1= + std::make_shared(val1, enviroment, ns); + abstract_object_pointert op2= + std::make_shared(val1.type(), false, true); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast(result); + THEN("We should get the same constant AO back") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE_FALSE(modified); + REQUIRE_FALSE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(cast_result->to_constant()==val1); + + // Is optimal + REQUIRE(result==op1); + } + } + WHEN("merging constant AO set to top with a abstract object set to top") + { + abstract_object_pointert op1= + std::make_shared(val1.type(), true, false); + abstract_object_pointert op2= + std::make_shared(val1.type(), true, false); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + THEN("We should get the same abstract object back") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + + // Is type still correct + const auto &cast_result= + std::dynamic_pointer_cast(result); + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + } + } + WHEN("merging constant AO set to top with a abstract object set to bottom") + { + abstract_object_pointert op1= + std::make_shared(val1.type(), true, false); + abstract_object_pointert op2= + std::make_shared(val1.type(), false, true); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + THEN("Should get the same abstract object back") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + + // Is type still correct + const auto &cast_result= + std::dynamic_pointer_cast(result); + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + } + } + WHEN("merging constant AO set to bottom with a abstract object set to top") + { + abstract_object_pointert op1= + std::make_shared(val1.type(), false, true); + abstract_object_pointert op2= + std::make_shared(val1.type(), true, false); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + THEN("Return a new top abstract object of the same type") + { + // Simple correctness of merge + REQUIRE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // We don't optimize for returning the second parameter if we can + + // Is type still correct + const auto &cast_result= + std::dynamic_pointer_cast(result); + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + } + } + WHEN("merging constant AO set to bottom with a AO set to bottom") + { + abstract_object_pointert op1= + std::make_shared(val1.type(), false, true); + abstract_object_pointert op2= + std::make_shared(val1.type(), false, true); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + THEN("Return the original abstract object") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE_FALSE(result->is_top()); + REQUIRE(result->is_bottom()); + + // Optimization check + REQUIRE(result==op1); + + // Is type still correct + const auto &cast_result= + std::dynamic_pointer_cast(result); + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + } + } + WHEN("merging AO set to top with a constant AO with a value") + { + abstract_object_pointert op1= + std::make_shared(val1.type(), true, false); + abstract_object_pointert op2= + std::make_shared(val1, enviroment, ns); + + bool modified; + + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + THEN("The original AO should be returned") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + } + } + WHEN("merging AO set to top with a constant AO set to top") + { + abstract_object_pointert op1= + std::make_shared(val1.type(), true, false); + abstract_object_pointert op2= + std::make_shared(val1.type(), true, false); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + THEN("The original AO should be returned") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + } + } + WHEN("merging AO set to top with a constant AO set to bottom") + { + abstract_object_pointert op1= + std::make_shared(val1.type(), true, false); + abstract_object_pointert op2= + std::make_shared(val1.type(), false, true); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + THEN("The original AO should be returned") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + } + } + WHEN("merging AO set to bottom with a constant AO with a value") + { + abstract_object_pointert op1= + std::make_shared(val1.type(), false, true); + abstract_object_pointert op2= + std::make_shared(val1, enviroment, ns); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + THEN("The a new top AO should be returned") + { + // Simple correctness of merge + REQUIRE(modified); + REQUIRE(typeid(result.get())==typeid(const abstract_objectt *)); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + } + + // We don't optimize for returning the second parameter if we can + } + WHEN("merging AO set to bottom with a constant AO set to top") + { + abstract_object_pointert op1= + std::make_shared(val1.type(), false, true); + abstract_object_pointert op2= + std::make_shared(val1.type(), true, false); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + THEN("The a new top AO should be returned") + { + // Simple correctness of merge + REQUIRE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // We don't optimize for returning the second parameter if we can + } + } + WHEN("merging AO set to bottom with a constant AO set to bottom") + { + abstract_object_pointert op1= + std::make_shared(val1.type(), false, true); + abstract_object_pointert op2= + std::make_shared(val1.type(), false, true); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + THEN("The original AO should be returned") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE_FALSE(result->is_top()); + REQUIRE(result->is_bottom()); + + REQUIRE(result==op1); + } + } + } +} diff --git a/unit/analyses/variable-sensitivity/constant_array_abstract_object/merge.cpp b/unit/analyses/variable-sensitivity/constant_array_abstract_object/merge.cpp new file mode 100644 index 00000000000..964084489a6 --- /dev/null +++ b/unit/analyses/variable-sensitivity/constant_array_abstract_object/merge.cpp @@ -0,0 +1,694 @@ +/*******************************************************************\ + + Module: Unit tests for constant_array_abstract_object::merge + + Author: DiffBlue Limited. All rights reserved. + +\*******************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +typedef constant_array_abstract_objectt::constant_array_pointert + constant_array_abstract_object_pointert; + +// Util + + +class array_utilt +{ +public: + array_utilt(const abstract_environmentt &enviroment, const namespacet &ns): + enviroment(enviroment), ns(ns) + {} + + constant_array_abstract_objectt::constant_array_pointert build_array( + const exprt &array_expr) + { + return std::make_shared( + array_expr, enviroment, ns); + } + + constant_array_abstract_objectt::constant_array_pointert build_top_array( + const typet &array_type) + { + return std::make_shared( + array_type, true, false); + } + + constant_array_abstract_objectt::constant_array_pointert build_bottom_array( + const typet &array_type) + { + return std::make_shared( + array_type, false, true); + } + + exprt read_index( + constant_array_abstract_object_pointert array_object, + const index_exprt &index) const + { + return array_object->read_index(enviroment, index, ns)->to_constant(); + } + +private: + const abstract_environmentt &enviroment; + const namespacet ns; +}; + +SCENARIO("merge_constant_array_abstract_object", + "[core]" + "[analyses][variable-sensitivity][constant_array_abstract_object][merge]") +{ + GIVEN("Two arrays of size 3, whose first elements are the same") + { + const array_typet array_type( + integer_typet(), constant_exprt::integer_constant(3)); + + // int val1[3] = {1, 2, 3} + exprt val1=array_exprt(array_type); + val1.operands().push_back(constant_exprt::integer_constant(1)); + val1.operands().push_back(constant_exprt::integer_constant(2)); + val1.operands().push_back(constant_exprt::integer_constant(3)); + + // int val2[3] = {1, 4, 5} + exprt val2=array_exprt(array_type); + val2.operands().push_back(constant_exprt::integer_constant(1)); + val2.operands().push_back(constant_exprt::integer_constant(4)); + val2.operands().push_back(constant_exprt::integer_constant(5)); + + // index_exprt for reading from an array + const index_exprt i0= + index_exprt(nil_exprt(), constant_exprt::integer_constant(0)); + const index_exprt i1= + index_exprt(nil_exprt(), constant_exprt::integer_constant(1)); + const index_exprt i2= + index_exprt(nil_exprt(), constant_exprt::integer_constant(2)); + + abstract_environmentt enviroment; + enviroment.make_top(); + symbol_tablet symbol_table; + namespacet ns(symbol_table); + + optionst options; + options.set_option("pointers", true); + options.set_option("arrays", true); + options.set_option("structs", true); + variable_sensitivity_object_factoryt::instance().set_options(options); + + array_utilt util(enviroment, ns); + + abstract_object_pointert result; + bool modified=false; + + WHEN("Merging two constant array AOs with the same array") + { + auto op1=util.build_array(val1); + auto op2=util.build_array(val1); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast( + result); + THEN("The original constant array AO should be returned") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE_FALSE(modified); + REQUIRE_FALSE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_index(cast_result, i0)==val1.op0()); + REQUIRE(util.read_index(cast_result, i1)==val1.op1()); + REQUIRE(util.read_index(cast_result, i2)==val1.op2()); + + // Is optimal + REQUIRE(result==op1); + } + } + WHEN("Merging two constant array AOs with different value arrays") + { + auto op1=util.build_array(val1); + auto op2=util.build_array(val2); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast( + result); + + THEN("A new constant array AO whose first value is the same and " + "the other two are top") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE(modified); + REQUIRE_FALSE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_index(cast_result, i0)==val1.op0()); + REQUIRE(util.read_index(cast_result, i1)==nil_exprt()); + REQUIRE(util.read_index(cast_result, i2)==nil_exprt()); + + // Since it has modified, we definitely shouldn't be reusing the pointer + REQUIRE_FALSE(result==op1); + } + } + WHEN("Merging a constant array AO with a value " + "with a constant array AO set to top") + { + auto op1=util.build_array(val1); + auto op2=util.build_top_array(array_type); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast( + result); + THEN("A new constant array AO set to top should be returned") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE(modified); + REQUIRE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_index(cast_result, i0)==nil_exprt()); + REQUIRE(util.read_index(cast_result, i1)==nil_exprt()); + REQUIRE(util.read_index(cast_result, i2)==nil_exprt()); + + // We can't reuse the abstract object as the value has changed + REQUIRE(result!=op1); + } + } + WHEN("Merging a constant array AO with a value " + "with a constant array AO set to bottom") + { + auto op1=util.build_array(val1); + auto op2=util.build_bottom_array(array_type); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast( + result); + THEN("The original const AO should be returned") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE_FALSE(modified); + REQUIRE_FALSE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_index(cast_result, i0)==val1.op0()); + REQUIRE(util.read_index(cast_result, i1)==val1.op1()); + REQUIRE(util.read_index(cast_result, i2)==val1.op2()); + + // Is optimal + REQUIRE(result==op1); + } + } + WHEN("Merging a constant array AO set to top " + "with a constant array AO with a value") + { + auto op1=util.build_top_array(array_type); + auto op2=util.build_array(val1); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast( + result); + THEN("The original constant array AO should be returned") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_index(cast_result, i0)==nil_exprt()); + REQUIRE(util.read_index(cast_result, i1)==nil_exprt()); + REQUIRE(util.read_index(cast_result, i2)==nil_exprt()); + + // Is optimal + REQUIRE(result==op1); + } + } + WHEN("Merging a constant array AO set to top " + "with a constant array AO set to top") + { + auto op1=util.build_top_array(array_type); + auto op2=util.build_top_array(array_type); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast( + result); + THEN("The original constant array AO should be returned") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_index(cast_result, i0)==nil_exprt()); + REQUIRE(util.read_index(cast_result, i1)==nil_exprt()); + REQUIRE(util.read_index(cast_result, i2)==nil_exprt()); + + // Is optimal + REQUIRE(result==op1); + } + } + WHEN("Merging a constant array AO set to top " + "with a constant array AO set to bottom") + { + auto op1=util.build_top_array(array_type); + auto op2=util.build_bottom_array(array_type); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast( + result); + THEN("The original constant array AO should be returned") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_index(cast_result, i0)==nil_exprt()); + REQUIRE(util.read_index(cast_result, i1)==nil_exprt()); + REQUIRE(util.read_index(cast_result, i2)==nil_exprt()); + + // Is optimal + REQUIRE(result==op1); + } + } + WHEN("Merging a constant array AO set to bottom " + "with a constant array AO with a value") + { + auto op1=util.build_bottom_array(array_type); + auto op2=util.build_array(val1); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast( + result); + THEN("A new AO should be returned with op2s valuee") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE(modified); + REQUIRE_FALSE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_index(cast_result, i0)==val1.op0()); + REQUIRE(util.read_index(cast_result, i1)==val1.op1()); + REQUIRE(util.read_index(cast_result, i2)==val1.op2()); + + // Is optimal + REQUIRE(result!=op1); + } + } + WHEN("Merging a constant array AO set to bottom " + "with a constant array AO set to top") + { + auto op1=util.build_bottom_array(array_type); + auto op2=util.build_top_array(array_type); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast( + result); + THEN("A new constant array AO should be returned set to top ") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE(modified); + REQUIRE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_index(cast_result, i0)==nil_exprt()); + REQUIRE(util.read_index(cast_result, i1)==nil_exprt()); + REQUIRE(util.read_index(cast_result, i2)==nil_exprt()); + + // Is optimal + REQUIRE(result!=op1); + } + } + WHEN("Merging a constant array AO set to bottom " + "with a constant array AO set to bottom") + { + auto op1=util.build_bottom_array(array_type); + auto op2=util.build_bottom_array(array_type); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast( + result); + THEN("The original bottom AO should be returned") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE_FALSE(modified); + REQUIRE_FALSE(cast_result->is_top()); + REQUIRE(cast_result->is_bottom()); + + // Is optimal + REQUIRE(result==op1); + } + } + WHEN("Merging constant array AO with value " + "with a abstract object set to top") + { + const auto &op1=util.build_array(val1); + const auto &op2= + std::make_shared(val1.type(), true, false); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast( + result); + + THEN("We should get a new AO of the same type but set to top") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE(modified); + REQUIRE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + + // Since it has modified, we definitely shouldn't be reusing the pointer + REQUIRE_FALSE(result==op1); + } + } + WHEN("Merging constant array AO with value " + "with a abstract object set to bottom") + { + const auto &op1=util.build_array(val1); + const auto &op2= + std::make_shared(val1.type(), false, true); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast( + result); + THEN("We should get the same constant array AO back") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE_FALSE(modified); + REQUIRE_FALSE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_index(cast_result, i0)==val1.op0()); + REQUIRE(util.read_index(cast_result, i1)==val1.op1()); + REQUIRE(util.read_index(cast_result, i2)==val1.op2()); + + // Is optimal + REQUIRE(result==op1); + } + } + WHEN("Merging constant array AO set to top " + "with a abstract object set to top") + { + const auto &op1= + util.build_top_array(array_type); + const auto &op2= + std::make_shared(val1.type(), true, false); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + THEN("We should get the same abstract object back") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + + // Is type still correct + const auto &cast_result= + std::dynamic_pointer_cast( + result); + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + } + } + WHEN("Merging constant array AO set to top " + "with a abstract object set to bottom") + { + const auto &op1= + util.build_top_array(array_type); + const auto &op2= + std::make_shared(val1.type(), false, true); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + THEN("Should get the same abstract object back") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + + // Is type still correct + const auto &cast_result= + std::dynamic_pointer_cast( + result); + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + } + } + WHEN("Merging constant array AO set to bottom " + " with a abstract object set to top") + { + const auto &op1= + util.build_bottom_array(array_type); + const auto &op2= + std::make_shared(val1.type(), true, false); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + THEN("Return a new top abstract object of the same type") + { + // Simple correctness of merge + REQUIRE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // We don't optimize for returning the second parameter if we can + + // Is type still correct + const auto &cast_result= + std::dynamic_pointer_cast( + result); + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + } + } + WHEN("Merging constant array AO set to bottom with a AO set to bottom") + { + const auto &op1= + util.build_bottom_array(array_type); + const auto &op2= + std::make_shared(val1.type(), false, true); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + THEN("Return the original abstract object") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE_FALSE(result->is_top()); + REQUIRE(result->is_bottom()); + + // Optimization check + REQUIRE(result==op1); + + // Is type still correct + const auto &cast_result= + std::dynamic_pointer_cast( + result); + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + } + } + WHEN("Merging AO set to top with a constant array AO with a value") + { + const auto &op1= + std::make_shared(val1.type(), true, false); + const auto &op2=util.build_array(val1); + + bool modified; + + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + THEN("The original AO should be returned") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + } + } + WHEN("Merging AO set to top with a constant array AO set to top") + { + const auto &op1= + std::make_shared(val1.type(), true, false); + const auto &op2= + util.build_top_array(array_type); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + THEN("The original AO should be returned") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + } + } + WHEN("Merging AO set to top with a constant array AO set to bottom") + { + const auto &op1= + std::make_shared(val1.type(), true, false); + const auto &op2= + util.build_bottom_array(array_type); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + THEN("The original AO should be returned") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + } + } + WHEN("Merging AO set to bottom with a constant array AO with a value") + { + const auto &op1= + std::make_shared(val1.type(), false, true); + const auto &op2=util.build_array(val1); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + THEN("The a new top AO should be returned") + { + // Simple correctness of merge + REQUIRE(modified); + REQUIRE(typeid(result.get())==typeid(const abstract_objectt *)); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + } + + // We don't optimize for returning the second parameter if we can + } + WHEN("Merging AO set to bottom with a constant array AO set to top") + { + const auto &op1= + std::make_shared(val1.type(), false, true); + const auto &op2= + util.build_top_array(array_type); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + THEN("The a new top AO should be returned") + { + // Simple correctness of merge + REQUIRE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // We don't optimize for returning the second parameter if we can + } + } + WHEN("Merging AO set to bottom with a constant array AO set to bottom") + { + const auto &op1= + std::make_shared(val1.type(), false, true); + const auto &op2= + util.build_bottom_array(array_type); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + THEN("The original AO should be returned") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE_FALSE(result->is_top()); + REQUIRE(result->is_bottom()); + + REQUIRE(result==op1); + } + } + } +} diff --git a/unit/analyses/variable-sensitivity/full_struct_abstract_object/merge.cpp b/unit/analyses/variable-sensitivity/full_struct_abstract_object/merge.cpp new file mode 100644 index 00000000000..7c888c38421 --- /dev/null +++ b/unit/analyses/variable-sensitivity/full_struct_abstract_object/merge.cpp @@ -0,0 +1,709 @@ +/*******************************************************************\ + + Module: Unit tests for full_struct_abstract_object::merge + + Author: DiffBlue Limited. All rights reserved. + +\*******************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + + +#include + +typedef constant_array_abstract_objectt::constant_array_pointert + constant_array_abstract_object_pointert; + +// Util + + +class struct_utilt +{ +public: + struct_utilt(abstract_environmentt &enviroment, const namespacet &ns): + enviroment(enviroment), ns(ns) + {} + + exprt read_component( + full_struct_abstract_objectt::constant_struct_pointert struct_object, + const member_exprt &component) const + { + return struct_object->read_component( + enviroment, component, ns)->to_constant(); + } + + // At the moment the full_struct_abstract_object does not support + // initialization directly from an exprt so we manually write the components + full_struct_abstract_objectt::constant_struct_pointert build_struct( + const struct_exprt &starting_value) + { + std::shared_ptr result= + std::make_shared( + starting_value, enviroment, ns); + + struct_typet struct_type(to_struct_type(starting_value.type())); + size_t comp_index=0; + for(const exprt &op : starting_value.operands()) + { + const auto &component=struct_type.components()[comp_index]; + std::shared_ptr new_result= + result->write_component( + enviroment, + ns, + std::stack(), + member_exprt(nil_exprt(), component.get_name()), + enviroment.eval(op, ns), + false); + result= + std::dynamic_pointer_cast( + new_result); + + ++comp_index; + } + + return result; + } + + full_struct_abstract_objectt::constant_struct_pointert build_top_struct( + const typet &struct_type) + { + return std::make_shared( + struct_type, true, false); + } + + full_struct_abstract_objectt::constant_struct_pointert build_bottom_struct( + const typet &struct_type) + { + return std::make_shared( + struct_type, false, true); + } + +private: + abstract_environmentt &enviroment; + const namespacet ns; +}; + +SCENARIO("merge_full_struct_abstract_object", + "[core]" + "[analyses][variable-sensitivity][full_struct_abstract_object][merge]") +{ + GIVEN("Two structs with 3 components, whose 1st component are the same") + { + // struct val1 = {.a = 1, .b = 2, .c = 3} + struct_typet struct_type; + struct_union_typet::componentt comp_a("a", integer_typet()); + struct_union_typet::componentt comp_b("b", integer_typet()); + struct_union_typet::componentt comp_c("c", integer_typet()); + struct_type.components().push_back(comp_a); + struct_type.components().push_back(comp_b); + struct_type.components().push_back(comp_c); + + struct_exprt val1(struct_type); + val1.operands().push_back(constant_exprt::integer_constant(1)); + val1.operands().push_back(constant_exprt::integer_constant(2)); + val1.operands().push_back(constant_exprt::integer_constant(3)); + + // struct val1 = {.a = 1, .b = 4, .c = 5} + struct_exprt val2(struct_type); + val2.operands().push_back(constant_exprt::integer_constant(1)); + val2.operands().push_back(constant_exprt::integer_constant(4)); + val2.operands().push_back(constant_exprt::integer_constant(5)); + + // index_exprt for reading from an array + const member_exprt a(nil_exprt(), "a"); + const member_exprt b(nil_exprt(), "b"); + const member_exprt c(nil_exprt(), "c"); + + abstract_environmentt enviroment; + enviroment.make_top(); + symbol_tablet symbol_table; + namespacet ns(symbol_table); + + optionst options; + options.set_option("pointers", true); + options.set_option("arrays", true); + options.set_option("structs", true); + variable_sensitivity_object_factoryt::instance().set_options(options); + + struct_utilt util(enviroment, ns); + + abstract_object_pointert result; + bool modified=false; + + WHEN("Merging two constant struct AOs with the same contents") + { + auto op1=util.build_struct(val1); + auto op2=util.build_struct(val1); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast(result); + THEN("The original struct AO should be returned") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE_FALSE(modified); + REQUIRE_FALSE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_component(cast_result, a)==val1.op0()); + REQUIRE(util.read_component(cast_result, b)==val1.op1()); + REQUIRE(util.read_component(cast_result, c)==val1.op2()); + + // Is optimal + REQUIRE(result==op1); + } + } + WHEN("Merging two constant struct AOs with the different contents") + { + auto op1=util.build_struct(val1); + auto op2=util.build_struct(val2); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast(result); + THEN("A new constant struct AO whose a component is the same and the " + "b and c are set to top") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE(modified); + REQUIRE_FALSE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_component(cast_result, a)==val1.op0()); + REQUIRE(util.read_component(cast_result, b)==nil_exprt()); + REQUIRE(util.read_component(cast_result, c)==nil_exprt()); + + + // Since it has modified, we definitely shouldn't be reusing the pointer + REQUIRE_FALSE(result==op1); + } + } + WHEN("Merging a constant struct AO with a value " + "with a constant struct AO set to top") + { + auto op1=util.build_struct(val1); + auto op2=util.build_top_struct(struct_type); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast(result); + THEN("A new constant struct AO set to top should be returned") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE(modified); + REQUIRE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_component(cast_result, a)==nil_exprt()); + REQUIRE(util.read_component(cast_result, b)==nil_exprt()); + REQUIRE(util.read_component(cast_result, c)==nil_exprt()); + + // We can't reuse the abstract object as the value has changed + REQUIRE(result!=op1); + } + } + WHEN("Merging a constant struct AO with a value " + "with a constant struct AO set to bottom") + { + auto op1=util.build_struct(val1); + auto op2=util.build_bottom_struct(struct_type); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast(result); + THEN("The original const AO should be returned") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE_FALSE(modified); + REQUIRE_FALSE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_component(cast_result, a)==val1.op0()); + REQUIRE(util.read_component(cast_result, b)==val1.op1()); + REQUIRE(util.read_component(cast_result, c)==val1.op2()); + + // Is optimal + REQUIRE(result==op1); + } + } + WHEN("Merging a constant struct AO set to top " + "with a constant struct AO with a value") + { + auto op1=util.build_top_struct(struct_type); + auto op2=util.build_struct(val1); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast(result); + THEN("The original constant struct AO should be returned") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_component(cast_result, a)==nil_exprt()); + REQUIRE(util.read_component(cast_result, b)==nil_exprt()); + REQUIRE(util.read_component(cast_result, c)==nil_exprt()); + + // Is optimal + REQUIRE(result==op1); + } + } + WHEN("Merging a constant struct AO set to top " + "with a constant struct AO set to top") + { + auto op1=util.build_top_struct(struct_type); + auto op2=util.build_top_struct(struct_type); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast(result); + THEN("The original constant struct AO should be returned") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_component(cast_result, a)==nil_exprt()); + REQUIRE(util.read_component(cast_result, b)==nil_exprt()); + REQUIRE(util.read_component(cast_result, c)==nil_exprt()); + + // Is optimal + REQUIRE(result==op1); + } + } + WHEN("Merging a constant struct AO set to top " + "with a constant struct AO set to bottom") + { + auto op1=util.build_top_struct(struct_type); + auto op2=util.build_bottom_struct(struct_type); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast(result); + THEN("The original constant struct AO should be returned") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_component(cast_result, a)==nil_exprt()); + REQUIRE(util.read_component(cast_result, b)==nil_exprt()); + REQUIRE(util.read_component(cast_result, c)==nil_exprt()); + + // Is optimal + REQUIRE(result==op1); + } + } + WHEN("Merging a constant struct AO set to bottom " + "with a constant struct AO with a value") + { + auto op1=util.build_bottom_struct(struct_type); + auto op2=util.build_struct(val1); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast(result); + THEN("A new AO should be returned with op2s valuee") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE(modified); + REQUIRE_FALSE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_component(cast_result, a)==val1.op0()); + REQUIRE(util.read_component(cast_result, b)==val1.op1()); + REQUIRE(util.read_component(cast_result, c)==val1.op2()); + + // Is optimal + REQUIRE(result!=op1); + } + } + WHEN("Merging a constant struct AO set to bottom " + "with a constant struct AO set to top") + { + auto op1=util.build_bottom_struct(struct_type); + auto op2=util.build_top_struct(struct_type); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast(result); + THEN("A new constant struct AO should be returned set to top ") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE(modified); + REQUIRE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_component(cast_result, a)==nil_exprt()); + REQUIRE(util.read_component(cast_result, b)==nil_exprt()); + REQUIRE(util.read_component(cast_result, c)==nil_exprt()); + + // Is optimal + REQUIRE(result!=op1); + } + } + WHEN("Merging a constant struct AO set to bottom " + "with a constant struct AO set to bottom") + { + auto op1=util.build_bottom_struct(struct_type); + auto op2=util.build_bottom_struct(struct_type); + + result=abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast(result); + THEN("The original bottom AO should be returned") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE_FALSE(modified); + REQUIRE_FALSE(cast_result->is_top()); + REQUIRE(cast_result->is_bottom()); + + // Is optimal + REQUIRE(result==op1); + } + } + WHEN("Merging constant struct AO with value " + "with a abstract object set to top") + { + const auto &op1=util.build_struct(val1); + const auto &op2= + std::make_shared(val1.type(), true, false); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast(result); + + THEN("We should get a new AO of the same type but set to top") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE(modified); + REQUIRE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + + // Since it has modified, we definitely shouldn't be reusing the pointer + REQUIRE_FALSE(result==op1); + } + } + WHEN("Merging constant struct AO with value " + "with a abstract object set to bottom") + { + const auto &op1=util.build_struct(val1); + const auto &op2= + std::make_shared(val1.type(), false, true); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + const auto &cast_result= + std::dynamic_pointer_cast(result); + THEN("We should get the same constant struct AO back") + { + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + + // Correctness of merge + REQUIRE_FALSE(modified); + REQUIRE_FALSE(cast_result->is_top()); + REQUIRE_FALSE(cast_result->is_bottom()); + REQUIRE(util.read_component(cast_result, a)==val1.op0()); + REQUIRE(util.read_component(cast_result, b)==val1.op1()); + REQUIRE(util.read_component(cast_result, c)==val1.op2()); + + // Is optimal + REQUIRE(result==op1); + } + } + WHEN("Merging constant struct AO set to top " + "with a abstract object set to top") + { + const auto &op1= + util.build_top_struct(struct_type); + const auto &op2= + std::make_shared(val1.type(), true, false); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + THEN("We should get the same abstract object back") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + + // Is type still correct + const auto &cast_result= + std::dynamic_pointer_cast(result); + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + } + } + WHEN("Merging constant struct AO set to top " + "with a abstract object set to bottom") + { + const auto &op1= + util.build_top_struct(struct_type); + const auto &op2= + std::make_shared(val1.type(), false, true); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + THEN("Should get the same abstract object back") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + + // Is type still correct + const auto &cast_result= + std::dynamic_pointer_cast(result); + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + } + } + WHEN("Merging constant struct AO set to bottom " + " with a abstract object set to top") + { + const auto &op1= + util.build_bottom_struct(struct_type); + const auto &op2= + std::make_shared(val1.type(), true, false); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + THEN("Return a new top abstract object of the same type") + { + // Simple correctness of merge + REQUIRE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // We don't optimize for returning the second parameter if we can + + // Is type still correct + const auto &cast_result= + std::dynamic_pointer_cast(result); + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + } + } + WHEN("Merging constant struct AO set to bottom with a AO set to bottom") + { + const auto &op1= + util.build_bottom_struct(struct_type); + const auto &op2= + std::make_shared(val1.type(), false, true); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + THEN("Return the original abstract object") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE_FALSE(result->is_top()); + REQUIRE(result->is_bottom()); + + // Optimization check + REQUIRE(result==op1); + + // Is type still correct + const auto &cast_result= + std::dynamic_pointer_cast(result); + // Though we may become top or bottom, the type should be unchanged + REQUIRE(cast_result); + } + } + WHEN("Merging AO set to top with a constant struct AO with a value") + { + const auto &op1= + std::make_shared(val1.type(), true, false); + const auto &op2=util.build_struct(val1); + + bool modified; + + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + THEN("The original AO should be returned") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + } + } + WHEN("Merging AO set to top with a constant struct AO set to top") + { + const auto &op1= + std::make_shared(val1.type(), true, false); + const auto &op2= + util.build_top_struct(struct_type); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + THEN("The original AO should be returned") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + } + } + WHEN("Merging AO set to top with a constant struct AO set to bottom") + { + const auto &op1= + std::make_shared(val1.type(), true, false); + const auto &op2= + util.build_bottom_struct(struct_type); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + THEN("The original AO should be returned") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // Is optimal + REQUIRE(op1==result); + } + } + WHEN("Merging AO set to bottom with a constant struct AO with a value") + { + const auto &op1= + std::make_shared(val1.type(), false, true); + const auto &op2=util.build_struct(val1); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + THEN("The a new top AO should be returned") + { + // Simple correctness of merge + REQUIRE(modified); + REQUIRE(typeid(result.get())==typeid(const abstract_objectt *)); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + } + + // We don't optimize for returning the second parameter if we can + } + WHEN("Merging AO set to bottom with a constant struct AO set to top") + { + const auto &op1= + std::make_shared(val1.type(), false, true); + const auto &op2= + util.build_top_struct(struct_type); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + THEN("The a new top AO should be returned") + { + // Simple correctness of merge + REQUIRE(modified); + REQUIRE(result->is_top()); + REQUIRE_FALSE(result->is_bottom()); + + // We don't optimize for returning the second parameter if we can + } + } + WHEN("Merging AO set to bottom with a constant struct AO set to bottom") + { + const auto &op1= + std::make_shared(val1.type(), false, true); + const auto &op2= + util.build_bottom_struct(struct_type); + + bool modified; + abstract_object_pointert result= + abstract_objectt::merge(op1, op2, modified); + + THEN("The original AO should be returned") + { + // Simple correctness of merge + REQUIRE_FALSE(modified); + REQUIRE_FALSE(result->is_top()); + REQUIRE(result->is_bottom()); + + REQUIRE(result==op1); + } + } + } +}