diff --git a/.gitignore b/.gitignore index 1aaff666b..773f472e9 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,7 @@ tests.log # binaries src/2ls/2ls + +*.orig +*.bak +*\# diff --git a/regression/kiki-modular/Makefile b/regression/kiki-modular/Makefile new file mode 100644 index 000000000..d2ff74910 --- /dev/null +++ b/regression/kiki-modular/Makefile @@ -0,0 +1,20 @@ +default: tests.log + +FLAGS = --verbosity 10 + +test: + @../test.pl -c "../../../src/summarizer/2ls $(FLAGS)" + +tests.log: ../test.pl + @../test.pl -c "../../../src/summarizer/2ls $(FLAGS)" + +show: + @for dir in *; do \ + if [ -d "$$dir" ]; then \ + vim -o "$$dir/*.c" "$$dir/*.out"; \ + fi; \ + done; + +clean: + @rm -f *.log + @for dir in *; do rm -f $$dir/*.out; done; diff --git a/regression/kiki-modular/cex-struct1/main.c b/regression/kiki-modular/cex-struct1/main.c new file mode 100644 index 000000000..a9a9139fa --- /dev/null +++ b/regression/kiki-modular/cex-struct1/main.c @@ -0,0 +1,180 @@ + +#include +#include + +typedef struct{ int x; int y; int z; int w; int p; int q; int a; } foo; + +foo func_1(foo f); +foo func_2(foo f); +foo func_3(foo f); +foo func_4(foo f); +foo func_5(foo f); +foo func_6(foo f); +foo func_7(foo f); +foo func_8(foo f); + +foo func_1(foo f) +{ + f.x = 23 + 12; + f.x = 4 - 1; + if(f.w > f.x) {f.q = 21 * f.z;} else {f.q = 4 / f.p;} + f.a = f.a + 1; + f.z = f.y * f.x; + f.x = 11 - f.p; + f.y = 1 - 19; + f.y = f.w - 14; + return f; +} + +/**********************************************************************/ + +foo func_2(foo f) +{ + if(f.y < f.q) {f.x = f.w / 24;} else {f.w = 18 / 3;} + f.w = f.p * f.q; + if(f.q < 6) {f.y = 25 - f.x;} else {f.q = f.y / f.w;} + f.a = f.a + 1; + if(f.x <= f.x) {f.z = 9 + f.x;} else {f.y = 1 + f.x;} + f.x = f.q / 25; + f.w = f.x - f.y; + f.x = 9 + f.y; + f.y = 24 - 2; + f.w = 10 + f.z; + return f; +} + +/**********************************************************************/ + +foo func_3(foo f) +{ + if(f.p == 12) {f.w = 22 + 7;} else {f.p = f.x + f.q;} + f.y = f.p + f.x; + f.w = 6 * f.y; + if(f.z <= 20) {f.q = 21 / 24;} else {f.w = f.q * f.w;} + f.w = f.y - 10; + f.q = 2 - 20; + f.x = f.x / 10; + f.p = 16 * 23; + f.w = 18 - 13; + f.w = f.p - 2; + f.z = 7 + f.w; + f.a = f.a + 1; + f.x = 16 / f.x; + return f; +} + +/**********************************************************************/ + +foo func_4(foo f) +{ + f.w = f.y + f.y; + f.q = 18 * 13; + f.y = f.z * f.y; + f.x = 1 * 25; + f.y = 4 / f.q; + f.x = f.p / 9; + f.a = f.a + 1; + if(f.x >= 7) {f.q = f.q / 8;} else {if(f.x < 9) {f.z = 16 + f.p;} else {f.x = f.w - 18;}} + f.y = 2 * 4; + f.q = 16 + f.x; + f.q = 16 * f.w; + if(f.w > 14) {f.q = 20 + 20;} else {f.x = 25 + 9;} + return f; +} + +/**********************************************************************/ + +foo func_5(foo f) +{ + f.a = f.a + 1; + if(f.x == 13) {f.p = 13 * f.x;} else {f.w = f.q / f.w;} + f.y = 21 * f.x; + f.p = 4 * 25; + if(f.p >= 24) {f.x = 11 * 6;} else {f.p = 9 * f.p;} + f.x = 3 + f.z; + f.x = f.x + 22; + f.z = 8 / 8; + f.q = 18 + f.x; + f.x = 5 * f.z; + f.y = f.w + f.w; + return f; +} + +/**********************************************************************/ + +foo func_6(foo f) +{ + f.y = f.w / f.q; + f.p = f.x + 8; + f.a = f.a + 1; + f.z = f.w * 20; + if(f.x < f.p) {f.x = f.z + 2;} else {f.y = f.y * f.x;} + if(f.y <= f.y) {f.q = f.y * f.w;} else {f.q = f.w - 13;} + f.p = 9 + f.y; + f.q = f.y / 14; + f.p = 18 / f.z; + if(f.w < f.p) {f.w = 17 * f.p;} else {f.p = f.y - 10;} + f.p = 3 / 14; + f.q = 10 - f.w; + if(f.y > 12) {f.z = f.q - 24;} else {f.x = f.z / 17;} + return f; +} + +/**********************************************************************/ + +foo func_7(foo f) +{ + f.q = f.q * 23; + f.w = 25 - f.w; + if(f.q < f.y) {f.w = 21 + f.z;} else {f.p = 16 - 1;} + f.y = f.z * f.z; + f.x = 5 * 16; + f.x = 11 + f.x; + f.z = f.y - f.y; + f.q = 11 - f.z; + f.a = f.a + 1; + return f; +} + +/**********************************************************************/ + +foo func_8(foo f) +{ + f.w = f.y - 15; + f.q = f.x + f.z; + f.y = 5 / 1; + if(f.q < 3) {f.p = 6 * f.x; } else {f.w = 8 + 21;} + f.p = 19 / f.p; + f.z = 4 / f.z; + if(f.x < 12) {f.p = f.y - 4; } else {f.x = 15 + 2;} + f.q = 19 / f.w; + if(f.p > 24) {f.z = 5 / 9;} else {f.w = f.x + f.z;} + f.z = f.z + 1; + f.a = f.a + 1; + if(f.z > f.y) {f.y = f.y + f.x;} else {f.y = 13 - 18;} + return f; +} + + +/**********************************************************************/ + +int main() +{ + foo f0, f1, f2, f3, f4, f5, f6, f7, f8; + +// __CPROVER_assume((f0.a >= 0) && (f0.a <= 9)); + f0.a = 0; + + f1 = func_1(f0); +/* f2 = func_2(f1); + f3 = func_3(f2); + f4 = func_4(f3); + f5 = func_5(f4); + f6 = func_6(f5); + f7 = func_7(f6); + f8 = func_8(f7);*/ + + assert(/*(f8.x + f8.y + f8.z + f8.w + f8.p + f8.q > 0) &&*/ (f1.a != 1)); // unsafe assertion + + return 0; +} diff --git a/regression/kiki-modular/cex-struct1/test.desc b/regression/kiki-modular/cex-struct1/test.desc new file mode 100644 index 000000000..b5b4ee326 --- /dev/null +++ b/regression/kiki-modular/cex-struct1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/kiki-modular/cex-struct2/main.c b/regression/kiki-modular/cex-struct2/main.c new file mode 100644 index 000000000..a5d7032f4 --- /dev/null +++ b/regression/kiki-modular/cex-struct2/main.c @@ -0,0 +1,22 @@ + +#include +#include + +typedef struct{ int a; } foo; + +foo func_1(foo f) +{ + f.a = f.a + 1; + return f; +} + +int main() +{ + foo f0, f1; + f0.a = 0; + + f1 = func_1(f0); + + assert((f1.a) != 1); + return 0; +} diff --git a/regression/kiki-modular/cex-struct2/test.desc b/regression/kiki-modular/cex-struct2/test.desc new file mode 100644 index 000000000..b5b4ee326 --- /dev/null +++ b/regression/kiki-modular/cex-struct2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/kiki-modular/cex-struct3/main.c b/regression/kiki-modular/cex-struct3/main.c new file mode 100644 index 000000000..1715861bf --- /dev/null +++ b/regression/kiki-modular/cex-struct3/main.c @@ -0,0 +1,23 @@ + +#include +#include + +typedef struct{ int x; int a; } foo; + +foo func_1(foo f) +{ + f.a = f.a + 1; + f.x = f.a; + return f; +} + +int main() +{ + foo f0, f1; + f0.a = 0; + + f1 = func_1(f0); + assert(f1.a != 1); // unsafe assertion + + return 0; +} diff --git a/regression/kiki-modular/cex-struct3/test.desc b/regression/kiki-modular/cex-struct3/test.desc new file mode 100644 index 000000000..b5b4ee326 --- /dev/null +++ b/regression/kiki-modular/cex-struct3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/kiki-modular/cex1/main.c b/regression/kiki-modular/cex1/main.c new file mode 100644 index 000000000..53451cf50 --- /dev/null +++ b/regression/kiki-modular/cex1/main.c @@ -0,0 +1,15 @@ +#include + +int foo(int x) +{ + assert(x>5); +} + +int main(int argc, char** argv) +{ + int y; + if(y<=0) foo(y); + + return 0; +} + diff --git a/regression/kiki-modular/cex1/test.desc b/regression/kiki-modular/cex1/test.desc new file mode 100644 index 000000000..b5b4ee326 --- /dev/null +++ b/regression/kiki-modular/cex1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/kiki-modular/cex10/main.c b/regression/kiki-modular/cex10/main.c new file mode 100644 index 000000000..5908a46cc --- /dev/null +++ b/regression/kiki-modular/cex10/main.c @@ -0,0 +1,21 @@ +#include + +int error(int k){ + assert(k != 3); +} + +int inc(int x){ + return (x+1); +}; + +int main(){ + int num = 0; + num = inc(num); + num = inc(num); + num = inc(num); + error(num); + return 0; +} + + + diff --git a/regression/kiki-modular/cex10/test.desc b/regression/kiki-modular/cex10/test.desc new file mode 100644 index 000000000..b5b4ee326 --- /dev/null +++ b/regression/kiki-modular/cex10/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/kiki-modular/cex13/main.c b/regression/kiki-modular/cex13/main.c new file mode 100644 index 000000000..242217d45 --- /dev/null +++ b/regression/kiki-modular/cex13/main.c @@ -0,0 +1,16 @@ + +#include + +void foo(int x) +{ + assert(x==5); +} + +int main(int argc, char** argv) +{ + int y = 4; + foo(y); + + return 0; +} + diff --git a/regression/kiki-modular/cex13/test.desc b/regression/kiki-modular/cex13/test.desc new file mode 100644 index 000000000..b5b4ee326 --- /dev/null +++ b/regression/kiki-modular/cex13/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/kiki-modular/cex2/main.c b/regression/kiki-modular/cex2/main.c new file mode 100644 index 000000000..cd18d78fc --- /dev/null +++ b/regression/kiki-modular/cex2/main.c @@ -0,0 +1,16 @@ + +#include + +void foo(int x) +{ + assert(x!=5); +} + +int main(int argc, char** argv) +{ + int y = 5; + foo(y); + + return 0; +} + diff --git a/regression/kiki-modular/cex2/test.desc b/regression/kiki-modular/cex2/test.desc new file mode 100644 index 000000000..b5b4ee326 --- /dev/null +++ b/regression/kiki-modular/cex2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/kiki-modular/cex3/main.c b/regression/kiki-modular/cex3/main.c new file mode 100644 index 000000000..952a3137b --- /dev/null +++ b/regression/kiki-modular/cex3/main.c @@ -0,0 +1,16 @@ + +#include + +int foo(int x) +{ + assert(x!=5); +} + +int main(int argc, char** argv) +{ + int y; + if(y > 0) foo(y); + + return 0; +} + diff --git a/regression/kiki-modular/cex3/test.desc b/regression/kiki-modular/cex3/test.desc new file mode 100644 index 000000000..b5b4ee326 --- /dev/null +++ b/regression/kiki-modular/cex3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/kiki-modular/cex4/main.c b/regression/kiki-modular/cex4/main.c new file mode 100644 index 000000000..8463fe610 --- /dev/null +++ b/regression/kiki-modular/cex4/main.c @@ -0,0 +1,11 @@ + +#include + +int main(int argc, char** argv) +{ + int y = 5; + assert(y != 5); + + return 0; +} + diff --git a/regression/kiki-modular/cex4/test.desc b/regression/kiki-modular/cex4/test.desc new file mode 100644 index 000000000..b5b4ee326 --- /dev/null +++ b/regression/kiki-modular/cex4/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/kiki-modular/cex5/main.c b/regression/kiki-modular/cex5/main.c new file mode 100644 index 000000000..0eabc5796 --- /dev/null +++ b/regression/kiki-modular/cex5/main.c @@ -0,0 +1,15 @@ +#include + +int foo(int x) +{ + assert(x>5); +} + +int main(int argc, char** argv) +{ + int y; + if(y>0) foo(y); + + return 0; +} + diff --git a/regression/kiki-modular/cex5/test.desc b/regression/kiki-modular/cex5/test.desc new file mode 100644 index 000000000..b5b4ee326 --- /dev/null +++ b/regression/kiki-modular/cex5/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/kiki-modular/cex6/main.c b/regression/kiki-modular/cex6/main.c new file mode 100644 index 000000000..80de0138d --- /dev/null +++ b/regression/kiki-modular/cex6/main.c @@ -0,0 +1,20 @@ + +#include + +void foo(int x) +{ + assert(x<1); +} + +int main() +{ + int y; + + while(y < 2){ + y++; + foo(y); + } + + return 0; +} + diff --git a/regression/kiki-modular/cex6/test.desc b/regression/kiki-modular/cex6/test.desc new file mode 100644 index 000000000..b5b4ee326 --- /dev/null +++ b/regression/kiki-modular/cex6/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/kiki-modular/cex7/main.c b/regression/kiki-modular/cex7/main.c new file mode 100644 index 000000000..8ab3e91f9 --- /dev/null +++ b/regression/kiki-modular/cex7/main.c @@ -0,0 +1,15 @@ + +#include + +int main(int argc, char** argv) +{ + int y = 1; + + while(y<30){ + y++; + assert(y<4); + } + + return 0; +} + diff --git a/regression/kiki-modular/cex7/test.desc b/regression/kiki-modular/cex7/test.desc new file mode 100644 index 000000000..b5b4ee326 --- /dev/null +++ b/regression/kiki-modular/cex7/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/kiki-modular/cex8/main.c b/regression/kiki-modular/cex8/main.c new file mode 100644 index 000000000..3bb7e471c --- /dev/null +++ b/regression/kiki-modular/cex8/main.c @@ -0,0 +1,20 @@ +#include + +int error(int k){ + assert(k != 2); +} + +int inc(int x){ + return (x+1); +}; + +int main(){ + int num = 0; + num = inc(num); + num = inc(num); + error(num); + return 0; +} + + + diff --git a/regression/kiki-modular/cex8/test.desc b/regression/kiki-modular/cex8/test.desc new file mode 100644 index 000000000..b5b4ee326 --- /dev/null +++ b/regression/kiki-modular/cex8/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/kiki-modular/cex9/main.c b/regression/kiki-modular/cex9/main.c new file mode 100644 index 000000000..675f72f26 --- /dev/null +++ b/regression/kiki-modular/cex9/main.c @@ -0,0 +1,24 @@ +#include + +int error(int k){ + assert(k != 2); +} + +int inc(int x){ + return (x+1); +}; + +int inc_copy(int x){ + return (x+1); +}; + +int main(){ + int num = 0; + num = inc_copy(num); + num = inc(num); + error(num); + return 0; +} + + + diff --git a/regression/kiki-modular/cex9/test.desc b/regression/kiki-modular/cex9/test.desc new file mode 100644 index 000000000..b5b4ee326 --- /dev/null +++ b/regression/kiki-modular/cex9/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/kiki-modular/induction1/main.c b/regression/kiki-modular/induction1/main.c new file mode 100644 index 000000000..23a7e0054 --- /dev/null +++ b/regression/kiki-modular/induction1/main.c @@ -0,0 +1,12 @@ +void main() +{ + int x = 1; + + while(1) + { + if(x==2) x=-x; + if(x>0) x++; + if(x==0) assert(0); + if(-10<=x && x<0) x--; + } +} diff --git a/regression/kiki-modular/induction1/test.desc b/regression/kiki-modular/induction1/test.desc new file mode 100644 index 000000000..e35a0daa7 --- /dev/null +++ b/regression/kiki-modular/induction1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/induction2/main.c b/regression/kiki-modular/induction2/main.c new file mode 100644 index 000000000..76f88d6eb --- /dev/null +++ b/regression/kiki-modular/induction2/main.c @@ -0,0 +1,12 @@ +void main() +{ + int x = 1, y = -1, z = 1; + + while(1) + { + z = y; + y = x; + x = -x; + assert(x==z); + } +} diff --git a/regression/kiki-modular/induction2/test.desc b/regression/kiki-modular/induction2/test.desc new file mode 100644 index 000000000..0544a23e5 --- /dev/null +++ b/regression/kiki-modular/induction2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/induction3/main.c b/regression/kiki-modular/induction3/main.c new file mode 100644 index 000000000..38ef4b24f --- /dev/null +++ b/regression/kiki-modular/induction3/main.c @@ -0,0 +1,12 @@ +void main() +{ + int x = 0, y = 0, z = 0; + + while(1) + { + z = -y; + y = -x; + x++; + assert(x<=z+2); + } +} diff --git a/regression/kiki-modular/induction3/test.desc b/regression/kiki-modular/induction3/test.desc new file mode 100644 index 000000000..0544a23e5 --- /dev/null +++ b/regression/kiki-modular/induction3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/induction4/main.c b/regression/kiki-modular/induction4/main.c new file mode 100644 index 000000000..241e31944 --- /dev/null +++ b/regression/kiki-modular/induction4/main.c @@ -0,0 +1,16 @@ +#define a 2 + +extern int nondet_int(); + +int main() { + int i=0, n=3; + + int sn0 = nondet_int(); + int sn = sn0; + + while(i=10) { + x = y = z = 0; + } +// if(x>z+2) break; +// assert(x<=z+2); + } + assert(0); //this works with assertion hoisting +} diff --git a/regression/kiki-modular/induction8/test.desc b/regression/kiki-modular/induction8/test.desc new file mode 100644 index 000000000..e35a0daa7 --- /dev/null +++ b/regression/kiki-modular/induction8/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/inline-refine1/main.c b/regression/kiki-modular/inline-refine1/main.c new file mode 100644 index 000000000..5662b4933 --- /dev/null +++ b/regression/kiki-modular/inline-refine1/main.c @@ -0,0 +1,17 @@ +#include + +int inc(int x) +{ + return x+1; +} + +void main() +{ + int x = 0; + int y = 0; + + x = inc(x); + y = inc(y); + + assert(x==1); +} diff --git a/regression/kiki-modular/inline-refine1/test.desc b/regression/kiki-modular/inline-refine1/test.desc new file mode 100644 index 000000000..af2fdc37b --- /dev/null +++ b/regression/kiki-modular/inline-refine1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --no-propagation --spurious-check concrete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/inline-refine2/main.c b/regression/kiki-modular/inline-refine2/main.c new file mode 100644 index 000000000..100ddaec6 --- /dev/null +++ b/regression/kiki-modular/inline-refine2/main.c @@ -0,0 +1,16 @@ + +#include + +void foo(int x) +{ + assert(x==5); +} + +int main(int argc, char** argv) +{ + int y = 5; + foo(y); + + return 0; +} + diff --git a/regression/kiki-modular/inline-refine2/test.desc b/regression/kiki-modular/inline-refine2/test.desc new file mode 100644 index 000000000..75b577755 --- /dev/null +++ b/regression/kiki-modular/inline-refine2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check concrete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/inline-refine3/main.c b/regression/kiki-modular/inline-refine3/main.c new file mode 100644 index 000000000..257e8fc7a --- /dev/null +++ b/regression/kiki-modular/inline-refine3/main.c @@ -0,0 +1,18 @@ + +#include + +int bar(){ + return 1; +} + +void foo(int x) { + assert(x != 5); +} + +int main() { + int y = bar(); + foo(y); + return 0; +} + + diff --git a/regression/kiki-modular/inline-refine3/test.desc b/regression/kiki-modular/inline-refine3/test.desc new file mode 100644 index 000000000..75b577755 --- /dev/null +++ b/regression/kiki-modular/inline-refine3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check concrete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/inline-refine4/main.c b/regression/kiki-modular/inline-refine4/main.c new file mode 100644 index 000000000..4e96e8e89 --- /dev/null +++ b/regression/kiki-modular/inline-refine4/main.c @@ -0,0 +1,20 @@ + +#include + +int bar(int k){ + return (k+1); +} + +void foo(int x) { + x = bar(x); + assert(x>5); +} + +int main() { + int y; + __CPROVER_assume(y<100000); + if(y > 10) foo(y); + return 0; +} + + diff --git a/regression/kiki-modular/inline-refine4/test.desc b/regression/kiki-modular/inline-refine4/test.desc new file mode 100644 index 000000000..75b577755 --- /dev/null +++ b/regression/kiki-modular/inline-refine4/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check concrete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/inline-refine5/main.c b/regression/kiki-modular/inline-refine5/main.c new file mode 100644 index 000000000..b225c7ce8 --- /dev/null +++ b/regression/kiki-modular/inline-refine5/main.c @@ -0,0 +1,30 @@ + +#include + +int foobar(int a){ + int i; + if(i < a) + return i+a; + else + return i-a; +} + +int bar(int k){ + return (k+1); +} + +void foo(int x, int s) { + int m; + s = foobar(m); + x = bar(x); + assert(x>5); +} + +int main() { + int y,k; + __CPROVER_assume(y<100000); + if(y > 10) foo(y,k); + return 0; +} + + diff --git a/regression/kiki-modular/inline-refine5/test.desc b/regression/kiki-modular/inline-refine5/test.desc new file mode 100644 index 000000000..75b577755 --- /dev/null +++ b/regression/kiki-modular/inline-refine5/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check concrete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/inline-refine6/main.c b/regression/kiki-modular/inline-refine6/main.c new file mode 100644 index 000000000..309c06dd9 --- /dev/null +++ b/regression/kiki-modular/inline-refine6/main.c @@ -0,0 +1,15 @@ + +#include + +int main(int argc, char** argv) +{ + int y = 1; + + while(y<30){ + y++; + assert(y<5); + } + + return 0; +} + diff --git a/regression/kiki-modular/inline-refine6/test.desc b/regression/kiki-modular/inline-refine6/test.desc new file mode 100644 index 000000000..dbc94b93b --- /dev/null +++ b/regression/kiki-modular/inline-refine6/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --unwind 2 --k-induction --spurious-check concrete +^EXIT=5$ +^SIGNAL=0$ +^VERIFICATION INCONCLUSIVE$ diff --git a/regression/kiki-modular/inline-refine7/main.c b/regression/kiki-modular/inline-refine7/main.c new file mode 100644 index 000000000..6faa3e65d --- /dev/null +++ b/regression/kiki-modular/inline-refine7/main.c @@ -0,0 +1,15 @@ +#include + +int foo(int x) +{ + assert(x>5); +} + +int main(int argc, char** argv) +{ + int y; + if(y>10) foo(y); + + return 0; +} + diff --git a/regression/kiki-modular/inline-refine7/test.desc b/regression/kiki-modular/inline-refine7/test.desc new file mode 100644 index 000000000..75b577755 --- /dev/null +++ b/regression/kiki-modular/inline-refine7/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check concrete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/inline-refine8/main.c b/regression/kiki-modular/inline-refine8/main.c new file mode 100644 index 000000000..d9ee4be0c --- /dev/null +++ b/regression/kiki-modular/inline-refine8/main.c @@ -0,0 +1,16 @@ + +#include + +void fail(void) +{ + assert(0); +} + +int main(void) +{ + int tmp = 0; + if(tmp) + fail(); + return 0; +} + diff --git a/regression/kiki-modular/inline-refine8/test.desc b/regression/kiki-modular/inline-refine8/test.desc new file mode 100644 index 000000000..75b577755 --- /dev/null +++ b/regression/kiki-modular/inline-refine8/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check concrete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/inline-refine9/main.c b/regression/kiki-modular/inline-refine9/main.c new file mode 100644 index 000000000..47067bc2f --- /dev/null +++ b/regression/kiki-modular/inline-refine9/main.c @@ -0,0 +1,11 @@ +#include + +void main() +{ + int x = 0; + int y = 0; + + while(y<10) { x++; } + + assert(x==11); +} diff --git a/regression/kiki-modular/inline-refine9/test.desc b/regression/kiki-modular/inline-refine9/test.desc new file mode 100644 index 000000000..842d3328d --- /dev/null +++ b/regression/kiki-modular/inline-refine9/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check concrete --no-propagation +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/kind1/main.c b/regression/kiki-modular/kind1/main.c new file mode 100644 index 000000000..679c7c8be --- /dev/null +++ b/regression/kiki-modular/kind1/main.c @@ -0,0 +1,22 @@ +#include + +//Simple K-Induction safe example for K=4 +//No procedure calls; loop inv required: a != b != c + +int main(int argc, char** argv) +{ + unsigned int limit; + int a,b,c,sc, i = 0; + __CPROVER_assume(a != b && b != c && c != a); + + while (i < limit) + { + assert(a != b); + sc = c; c = b; b = a; a = sc; + //a, b, c = c, a, b; parallel assignment; + i++; + } + + return 0; +} + diff --git a/regression/kiki-modular/kind1/test.desc b/regression/kiki-modular/kind1/test.desc new file mode 100644 index 000000000..0544a23e5 --- /dev/null +++ b/regression/kiki-modular/kind1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/kind2/main.c b/regression/kiki-modular/kind2/main.c new file mode 100644 index 000000000..0925661c3 --- /dev/null +++ b/regression/kiki-modular/kind2/main.c @@ -0,0 +1,28 @@ +#include + + +int foo(int a, int b, int c) +{ + return a+1; +} + +// This main illustrates K-induction with proc call +// Safety can be shown for K = 4 after using summary TRUE for foo +// Only unwinding loop is required +int main(int argc, char** argv) +{ + unsigned int limit; + int a,b,c,sc, i = 0; + __CPROVER_assume(a != b && b != c && c != a); + + while (i < limit) { + assert(a != b); + sc = c; c = b; b = a; a = sc; + //a, b, c = c, a, b; parallel assignment; + if (b == c) a = foo(a,b,c); + i++; + } + + return 0; +} + diff --git a/regression/kiki-modular/kind2/test.desc b/regression/kiki-modular/kind2/test.desc new file mode 100644 index 000000000..0544a23e5 --- /dev/null +++ b/regression/kiki-modular/kind2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/kind3/main.c b/regression/kiki-modular/kind3/main.c new file mode 100644 index 000000000..813307dda --- /dev/null +++ b/regression/kiki-modular/kind3/main.c @@ -0,0 +1,26 @@ +#include + + +int bar(int a, int b, int c) +{ + return c; +} + +//This main illustrates need for refinement of bar +//based on spurious CEX +int main(int argc, char** argv) +{ + unsigned int limit; + int a,b,c,sc, i = 0; + __CPROVER_assume(a != b && b != c && c != a); + + while (i < limit) { + assert(a != b); + sc = c; c = b; b = a; a = bar(a,b,sc); + //a, b, c = bar(a,b,c), a, b; parallel assignment; + i++; + } + + return 0; +} + diff --git a/regression/kiki-modular/kind3/test.desc b/regression/kiki-modular/kind3/test.desc new file mode 100644 index 000000000..0544a23e5 --- /dev/null +++ b/regression/kiki-modular/kind3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/kind4/main.c b/regression/kiki-modular/kind4/main.c new file mode 100644 index 000000000..5b4106e35 --- /dev/null +++ b/regression/kiki-modular/kind4/main.c @@ -0,0 +1,37 @@ +#include + + +int foo(int a, int b, int c) +{ + return a+1; +} + +int bar(int a, int b, int c) +{ + assert(a != b); + return c; +} + + +// This main illustrates K-induction with proc call +// Safety can be shown for K = 4 after using summary TRUE for foo +// Only unwinding loop is required +int main(int argc, char** argv) +{ + unsigned int limit; + int a,b,c,sc, i = 0; + __CPROVER_assume(a != b && b != c && c != a); + + while (i < limit) { +// assert(a != b); + sc = c; c = b; b = a; a = sc; + //a, b, c = c, a, b; parallel assignment; + if (b == c) a = foo(a,b,c); + //else //TODO: investigate why k-ind doesn't terminate if the call to bar is here + c = bar(a,b,c); + i++; + } + + return 0; +} + diff --git a/regression/kiki-modular/kind4/test.desc b/regression/kiki-modular/kind4/test.desc new file mode 100644 index 000000000..0544a23e5 --- /dev/null +++ b/regression/kiki-modular/kind4/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/kind5/main.c b/regression/kiki-modular/kind5/main.c new file mode 100644 index 000000000..6f6d29b27 --- /dev/null +++ b/regression/kiki-modular/kind5/main.c @@ -0,0 +1,18 @@ +#include + +int main(int argc, char** argv) +{ + unsigned int limit; + int a,b,sc, i = 0; + __CPROVER_assume(a != b); + + while (i < limit) + { + assert(a != b); + sc = b; b = a; a = sc; + i++; + } + + return 0; +} + diff --git a/regression/kiki-modular/kind5/test.desc b/regression/kiki-modular/kind5/test.desc new file mode 100644 index 000000000..0544a23e5 --- /dev/null +++ b/regression/kiki-modular/kind5/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/kind6/main.c b/regression/kiki-modular/kind6/main.c new file mode 100644 index 000000000..4b957b301 --- /dev/null +++ b/regression/kiki-modular/kind6/main.c @@ -0,0 +1,34 @@ + +#include + +int inc(int c) +{ + return c+1; +} + +int dec(int b) +{ + return b-1; +} + +int add(int i, int j) +{ + int b = i; + int c = j; + int ret = c; + + while(b > 0){ + b = dec(b); + c = inc(c); + ret = c; + assert((ret + b) == (i + j)); //loop invariant + } + assert(ret == (i + j)); + return ret; +} + +void main() { + int x = 5; + int y = 3; + int result = add(x, y); +} diff --git a/regression/kiki-modular/kind6/test.desc b/regression/kiki-modular/kind6/test.desc new file mode 100644 index 000000000..0544a23e5 --- /dev/null +++ b/regression/kiki-modular/kind6/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/kind7/main.c b/regression/kiki-modular/kind7/main.c new file mode 100644 index 000000000..30592979f --- /dev/null +++ b/regression/kiki-modular/kind7/main.c @@ -0,0 +1,35 @@ + +// for complete to work faster: introduce a function call to modify an irrelevant variable + +#include + +unsigned nondet_int(); + +int foo(int a){ + + a = a + (2*a) + (3*a); + a = a - (2*a) - (3*a); + a = -a; + + return a; + +} + +int main(){ + + int x; + int y; + + __CPROVER_assume(x > 0 and x < 10); + + while(x < 10000){ + x = x + 1; + y = foo(y); + + if(nondet_int()) + break; + } + + assert(x < 10001); + +} diff --git a/regression/kiki-modular/kind7/test.desc b/regression/kiki-modular/kind7/test.desc new file mode 100644 index 000000000..0544a23e5 --- /dev/null +++ b/regression/kiki-modular/kind7/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/kind8/main.c b/regression/kiki-modular/kind8/main.c new file mode 100644 index 000000000..dbebaeb45 --- /dev/null +++ b/regression/kiki-modular/kind8/main.c @@ -0,0 +1,40 @@ + +// for concrete to work faster: a false assertion such that all counterexamples are valid counterexamples + +#include + +unsigned nondet_int(); + +int bar(int x){ + if((x > 0) || (x <= 0)) + assert(0); + + return 0; +} + +int inc_or_dec(int x){ + if(nondet_int()) + x = x + 1; + else + x = x - 1; + + return x; +} + +int main(){ + + int k; + int counter = 0 + + while(counter < 100000){ + k = inc_or_dec(k); + if(nondet_int()) + break; + counter++; + } + + bar(k); + + return 0; + +} diff --git a/regression/kiki-modular/kind8/test.desc b/regression/kiki-modular/kind8/test.desc new file mode 100644 index 000000000..0544a23e5 --- /dev/null +++ b/regression/kiki-modular/kind8/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/loop25/main.c b/regression/kiki-modular/loop25/main.c new file mode 100644 index 000000000..8febd85d7 --- /dev/null +++ b/regression/kiki-modular/loop25/main.c @@ -0,0 +1,12 @@ +void main() +{ + int x = 1, y = -1, z = 1; + + while(x==z) + { + z = y; + y = x; + x = -x; + } + assert(0); +} diff --git a/regression/kiki-modular/loop25/test.desc b/regression/kiki-modular/loop25/test.desc new file mode 100644 index 000000000..0544a23e5 --- /dev/null +++ b/regression/kiki-modular/loop25/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/loop27/main.c b/regression/kiki-modular/loop27/main.c new file mode 100644 index 000000000..ca9acda4c --- /dev/null +++ b/regression/kiki-modular/loop27/main.c @@ -0,0 +1,13 @@ +void main() +{ + int x = 1, y = -1, z = 1; + + do + { + z = y; + y = x; + x = -x; + } + while(x==z); + assert(0); +} diff --git a/regression/kiki-modular/loop27/test.desc b/regression/kiki-modular/loop27/test.desc new file mode 100644 index 000000000..0544a23e5 --- /dev/null +++ b/regression/kiki-modular/loop27/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/loop28/main.c b/regression/kiki-modular/loop28/main.c new file mode 100644 index 000000000..7ae8d5301 --- /dev/null +++ b/regression/kiki-modular/loop28/main.c @@ -0,0 +1,8 @@ +void main() { + int b = 3; + unsigned int j=0; + while (j<1 && b!=3) { + j++; + } + assert(j<1); +} diff --git a/regression/kiki-modular/loop28/test.desc b/regression/kiki-modular/loop28/test.desc new file mode 100644 index 000000000..e35a0daa7 --- /dev/null +++ b/regression/kiki-modular/loop28/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/nested11/main.c b/regression/kiki-modular/nested11/main.c new file mode 100644 index 000000000..790b6c4b3 --- /dev/null +++ b/regression/kiki-modular/nested11/main.c @@ -0,0 +1,19 @@ +void main() +{ + int x,y; + for(x=0;x<10;) + { + for(y=0;y + +int foo(int x) +{ + assert(x>5); +} + +int main(int argc, char** argv) +{ + int y; + if(y>10) foo(y); + + return 0; +} + diff --git a/regression/kiki-modular/nocex1/test.desc b/regression/kiki-modular/nocex1/test.desc new file mode 100644 index 000000000..0544a23e5 --- /dev/null +++ b/regression/kiki-modular/nocex1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/nocex2/main.c b/regression/kiki-modular/nocex2/main.c new file mode 100644 index 000000000..100ddaec6 --- /dev/null +++ b/regression/kiki-modular/nocex2/main.c @@ -0,0 +1,16 @@ + +#include + +void foo(int x) +{ + assert(x==5); +} + +int main(int argc, char** argv) +{ + int y = 5; + foo(y); + + return 0; +} + diff --git a/regression/kiki-modular/nocex2/test.desc b/regression/kiki-modular/nocex2/test.desc new file mode 100644 index 000000000..0544a23e5 --- /dev/null +++ b/regression/kiki-modular/nocex2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/nocex3/main.c b/regression/kiki-modular/nocex3/main.c new file mode 100644 index 000000000..257e8fc7a --- /dev/null +++ b/regression/kiki-modular/nocex3/main.c @@ -0,0 +1,18 @@ + +#include + +int bar(){ + return 1; +} + +void foo(int x) { + assert(x != 5); +} + +int main() { + int y = bar(); + foo(y); + return 0; +} + + diff --git a/regression/kiki-modular/nocex3/test.desc b/regression/kiki-modular/nocex3/test.desc new file mode 100644 index 000000000..0544a23e5 --- /dev/null +++ b/regression/kiki-modular/nocex3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/nocex4/main.c b/regression/kiki-modular/nocex4/main.c new file mode 100644 index 000000000..4e96e8e89 --- /dev/null +++ b/regression/kiki-modular/nocex4/main.c @@ -0,0 +1,20 @@ + +#include + +int bar(int k){ + return (k+1); +} + +void foo(int x) { + x = bar(x); + assert(x>5); +} + +int main() { + int y; + __CPROVER_assume(y<100000); + if(y > 10) foo(y); + return 0; +} + + diff --git a/regression/kiki-modular/nocex4/test.desc b/regression/kiki-modular/nocex4/test.desc new file mode 100644 index 000000000..0544a23e5 --- /dev/null +++ b/regression/kiki-modular/nocex4/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/nocex5/main.c b/regression/kiki-modular/nocex5/main.c new file mode 100644 index 000000000..b225c7ce8 --- /dev/null +++ b/regression/kiki-modular/nocex5/main.c @@ -0,0 +1,30 @@ + +#include + +int foobar(int a){ + int i; + if(i < a) + return i+a; + else + return i-a; +} + +int bar(int k){ + return (k+1); +} + +void foo(int x, int s) { + int m; + s = foobar(m); + x = bar(x); + assert(x>5); +} + +int main() { + int y,k; + __CPROVER_assume(y<100000); + if(y > 10) foo(y,k); + return 0; +} + + diff --git a/regression/kiki-modular/nocex5/test.desc b/regression/kiki-modular/nocex5/test.desc new file mode 100644 index 000000000..0544a23e5 --- /dev/null +++ b/regression/kiki-modular/nocex5/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/nocex6/main.c b/regression/kiki-modular/nocex6/main.c new file mode 100644 index 000000000..309c06dd9 --- /dev/null +++ b/regression/kiki-modular/nocex6/main.c @@ -0,0 +1,15 @@ + +#include + +int main(int argc, char** argv) +{ + int y = 1; + + while(y<30){ + y++; + assert(y<5); + } + + return 0; +} + diff --git a/regression/kiki-modular/nocex6/test.desc b/regression/kiki-modular/nocex6/test.desc new file mode 100644 index 000000000..f0edbd788 --- /dev/null +++ b/regression/kiki-modular/nocex6/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --unwind 2 --k-induction --spurious-check complete +^EXIT=5$ +^SIGNAL=0$ +^VERIFICATION INCONCLUSIVE$ diff --git a/regression/kiki-modular/nocex8/main.c b/regression/kiki-modular/nocex8/main.c new file mode 100644 index 000000000..d9ee4be0c --- /dev/null +++ b/regression/kiki-modular/nocex8/main.c @@ -0,0 +1,16 @@ + +#include + +void fail(void) +{ + assert(0); +} + +int main(void) +{ + int tmp = 0; + if(tmp) + fail(); + return 0; +} + diff --git a/regression/kiki-modular/nocex8/test.desc b/regression/kiki-modular/nocex8/test.desc new file mode 100644 index 000000000..0544a23e5 --- /dev/null +++ b/regression/kiki-modular/nocex8/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/nocex9/main.c b/regression/kiki-modular/nocex9/main.c new file mode 100644 index 000000000..47067bc2f --- /dev/null +++ b/regression/kiki-modular/nocex9/main.c @@ -0,0 +1,11 @@ +#include + +void main() +{ + int x = 0; + int y = 0; + + while(y<10) { x++; } + + assert(x==11); +} diff --git a/regression/kiki-modular/nocex9/test.desc b/regression/kiki-modular/nocex9/test.desc new file mode 100644 index 000000000..312f3d84e --- /dev/null +++ b/regression/kiki-modular/nocex9/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete --no-propagation +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/s3_clnt_1/main.c b/regression/kiki-modular/s3_clnt_1/main.c new file mode 100644 index 000000000..f958efad6 --- /dev/null +++ b/regression/kiki-modular/s3_clnt_1/main.c @@ -0,0 +1,64 @@ +#include + +extern int __VERIFIER_nondet_int(); + +int ssl3_connect(void) +{ + int s__state ; + int blastFlag ; + + s__state = 12292; + blastFlag = 0; + + while (1) { + if (s__state == 12292) { + goto switch_1_12292; + } else { + if (s__state == 4368) { + goto switch_1_4368; + } else { + if (s__state == 4384) { + goto switch_1_4384; + } else { + if (s__state == 4400) { + goto switch_1_4400; + } else { + return 0; + if (0) { + switch_1_12292: /* CIL Label */ + s__state = 4368; + continue; + switch_1_4368: /* CIL Label */ ; + blastFlag++; + s__state = 4384; + continue; + switch_1_4384: /* CIL Label */ ; + blastFlag++; + s__state = 4400; + continue; + switch_1_4400: /* CIL Label */ ; + if (blastFlag == 2) { + break; + } + continue; + } + } + } + } + } + } + assert(0); + return -1; +} +int main(void) +{ + ssl3_connect(); + return 0; +} + +/* +We get hoisted assertion: +(C) $guard#ls50%2 && ($cond#22%2 || $cond#36%2 || $cond#49%2) ==> ($guard#51 ==> FALSE) + +But $cond#36%2 is a return and no break condition! +*/ diff --git a/regression/kiki-modular/s3_clnt_1/test.desc b/regression/kiki-modular/s3_clnt_1/test.desc new file mode 100644 index 000000000..62a74380a --- /dev/null +++ b/regression/kiki-modular/s3_clnt_1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --spurious-check complete +^EXIT=10$ +^SIGNAL=0$ +^.*FAILURE$ diff --git a/regression/kiki-modular/scope1/main.c b/regression/kiki-modular/scope1/main.c new file mode 100644 index 000000000..ec678aac1 --- /dev/null +++ b/regression/kiki-modular/scope1/main.c @@ -0,0 +1,11 @@ +void main() +{ + int y = 5; + int i; + for(i=0; i<10; i+=y) + { + int y = 20; + } + assert(y==5); + assert(i==10); +} diff --git a/regression/kiki-modular/scope1/test.desc b/regression/kiki-modular/scope1/test.desc new file mode 100644 index 000000000..e35a0daa7 --- /dev/null +++ b/regression/kiki-modular/scope1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--k-induction --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki-modular/unwind-refine1/main.c b/regression/kiki-modular/unwind-refine1/main.c new file mode 100644 index 000000000..6852ba883 --- /dev/null +++ b/regression/kiki-modular/unwind-refine1/main.c @@ -0,0 +1,15 @@ +#include + +void main() +{ + int x = 0; + int y = 0; + int c; + + while(x<10) ++x; + + int c; + while(c) ++y; + + assert(x==10); +} diff --git a/regression/kiki-modular/unwind-refine1/test.desc b/regression/kiki-modular/unwind-refine1/test.desc new file mode 100644 index 000000000..80195020a --- /dev/null +++ b/regression/kiki-modular/unwind-refine1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --k-induction --no-propagation --spurious-check complete +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki/Makefile b/regression/kiki/Makefile index b5f2484a2..569e1b125 100644 --- a/regression/kiki/Makefile +++ b/regression/kiki/Makefile @@ -1,6 +1,6 @@ default: tests.log -FLAGS = --verbosity 10 +FLAGS = --verbosity 10 --inline test: @../test.pl -c "../../../src/2ls/2ls $(FLAGS)" diff --git a/regression/kiki/induction7a/main.c b/regression/kiki/induction7a/main.c new file mode 100644 index 000000000..5a9e3cf63 --- /dev/null +++ b/regression/kiki/induction7a/main.c @@ -0,0 +1,12 @@ +void main() +{ + int s=0; + int x=0; + while(1) + { + s += 2; + if(x==1) s++; + x++; + assert(s == 2*x); + } +} diff --git a/regression/kiki/induction7a/test.desc b/regression/kiki/induction7a/test.desc new file mode 100644 index 000000000..b3256a114 --- /dev/null +++ b/regression/kiki/induction7a/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--k-induction --havoc +^EXIT=10$ +^SIGNAL=0$ +^.*FAILURE$ diff --git a/regression/kiki/unwind21/test.desc b/regression/kiki/unwind21/test.desc index f4c56630b..f2e264817 100644 --- a/regression/kiki/unwind21/test.desc +++ b/regression/kiki/unwind21/test.desc @@ -1,4 +1,4 @@ -KNOWNBUG +CORE main.c --k-induction ^EXIT=10$ diff --git a/regression/spurious-check-abstract/Makefile b/regression/spurious-check-abstract/Makefile new file mode 100644 index 000000000..3a92d5017 --- /dev/null +++ b/regression/spurious-check-abstract/Makefile @@ -0,0 +1,20 @@ +default: tests.log + +FLAGS = --verbosity 10 --spurious-check abstract + +test: + @../test.pl -c "../../../src/summarizer/2ls $(FLAGS)" + +tests.log: ../test.pl + @../test.pl -c "../../../src/summarizer/2ls $(FLAGS)" + +show: + @for dir in *; do \ + if [ -d "$$dir" ]; then \ + vim -o "$$dir/*.c" "$$dir/*.out"; \ + fi; \ + done; + +clean: + @rm -f *.log + @for dir in *; do rm -f $$dir/*.out; done; diff --git a/regression/spurious-check-abstract/cex-struct1/main.c b/regression/spurious-check-abstract/cex-struct1/main.c new file mode 100644 index 000000000..a9a9139fa --- /dev/null +++ b/regression/spurious-check-abstract/cex-struct1/main.c @@ -0,0 +1,180 @@ + +#include +#include + +typedef struct{ int x; int y; int z; int w; int p; int q; int a; } foo; + +foo func_1(foo f); +foo func_2(foo f); +foo func_3(foo f); +foo func_4(foo f); +foo func_5(foo f); +foo func_6(foo f); +foo func_7(foo f); +foo func_8(foo f); + +foo func_1(foo f) +{ + f.x = 23 + 12; + f.x = 4 - 1; + if(f.w > f.x) {f.q = 21 * f.z;} else {f.q = 4 / f.p;} + f.a = f.a + 1; + f.z = f.y * f.x; + f.x = 11 - f.p; + f.y = 1 - 19; + f.y = f.w - 14; + return f; +} + +/**********************************************************************/ + +foo func_2(foo f) +{ + if(f.y < f.q) {f.x = f.w / 24;} else {f.w = 18 / 3;} + f.w = f.p * f.q; + if(f.q < 6) {f.y = 25 - f.x;} else {f.q = f.y / f.w;} + f.a = f.a + 1; + if(f.x <= f.x) {f.z = 9 + f.x;} else {f.y = 1 + f.x;} + f.x = f.q / 25; + f.w = f.x - f.y; + f.x = 9 + f.y; + f.y = 24 - 2; + f.w = 10 + f.z; + return f; +} + +/**********************************************************************/ + +foo func_3(foo f) +{ + if(f.p == 12) {f.w = 22 + 7;} else {f.p = f.x + f.q;} + f.y = f.p + f.x; + f.w = 6 * f.y; + if(f.z <= 20) {f.q = 21 / 24;} else {f.w = f.q * f.w;} + f.w = f.y - 10; + f.q = 2 - 20; + f.x = f.x / 10; + f.p = 16 * 23; + f.w = 18 - 13; + f.w = f.p - 2; + f.z = 7 + f.w; + f.a = f.a + 1; + f.x = 16 / f.x; + return f; +} + +/**********************************************************************/ + +foo func_4(foo f) +{ + f.w = f.y + f.y; + f.q = 18 * 13; + f.y = f.z * f.y; + f.x = 1 * 25; + f.y = 4 / f.q; + f.x = f.p / 9; + f.a = f.a + 1; + if(f.x >= 7) {f.q = f.q / 8;} else {if(f.x < 9) {f.z = 16 + f.p;} else {f.x = f.w - 18;}} + f.y = 2 * 4; + f.q = 16 + f.x; + f.q = 16 * f.w; + if(f.w > 14) {f.q = 20 + 20;} else {f.x = 25 + 9;} + return f; +} + +/**********************************************************************/ + +foo func_5(foo f) +{ + f.a = f.a + 1; + if(f.x == 13) {f.p = 13 * f.x;} else {f.w = f.q / f.w;} + f.y = 21 * f.x; + f.p = 4 * 25; + if(f.p >= 24) {f.x = 11 * 6;} else {f.p = 9 * f.p;} + f.x = 3 + f.z; + f.x = f.x + 22; + f.z = 8 / 8; + f.q = 18 + f.x; + f.x = 5 * f.z; + f.y = f.w + f.w; + return f; +} + +/**********************************************************************/ + +foo func_6(foo f) +{ + f.y = f.w / f.q; + f.p = f.x + 8; + f.a = f.a + 1; + f.z = f.w * 20; + if(f.x < f.p) {f.x = f.z + 2;} else {f.y = f.y * f.x;} + if(f.y <= f.y) {f.q = f.y * f.w;} else {f.q = f.w - 13;} + f.p = 9 + f.y; + f.q = f.y / 14; + f.p = 18 / f.z; + if(f.w < f.p) {f.w = 17 * f.p;} else {f.p = f.y - 10;} + f.p = 3 / 14; + f.q = 10 - f.w; + if(f.y > 12) {f.z = f.q - 24;} else {f.x = f.z / 17;} + return f; +} + +/**********************************************************************/ + +foo func_7(foo f) +{ + f.q = f.q * 23; + f.w = 25 - f.w; + if(f.q < f.y) {f.w = 21 + f.z;} else {f.p = 16 - 1;} + f.y = f.z * f.z; + f.x = 5 * 16; + f.x = 11 + f.x; + f.z = f.y - f.y; + f.q = 11 - f.z; + f.a = f.a + 1; + return f; +} + +/**********************************************************************/ + +foo func_8(foo f) +{ + f.w = f.y - 15; + f.q = f.x + f.z; + f.y = 5 / 1; + if(f.q < 3) {f.p = 6 * f.x; } else {f.w = 8 + 21;} + f.p = 19 / f.p; + f.z = 4 / f.z; + if(f.x < 12) {f.p = f.y - 4; } else {f.x = 15 + 2;} + f.q = 19 / f.w; + if(f.p > 24) {f.z = 5 / 9;} else {f.w = f.x + f.z;} + f.z = f.z + 1; + f.a = f.a + 1; + if(f.z > f.y) {f.y = f.y + f.x;} else {f.y = 13 - 18;} + return f; +} + + +/**********************************************************************/ + +int main() +{ + foo f0, f1, f2, f3, f4, f5, f6, f7, f8; + +// __CPROVER_assume((f0.a >= 0) && (f0.a <= 9)); + f0.a = 0; + + f1 = func_1(f0); +/* f2 = func_2(f1); + f3 = func_3(f2); + f4 = func_4(f3); + f5 = func_5(f4); + f6 = func_6(f5); + f7 = func_7(f6); + f8 = func_8(f7);*/ + + assert(/*(f8.x + f8.y + f8.z + f8.w + f8.p + f8.q > 0) &&*/ (f1.a != 1)); // unsafe assertion + + return 0; +} diff --git a/regression/spurious-check-abstract/cex-struct1/test.desc b/regression/spurious-check-abstract/cex-struct1/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-abstract/cex-struct1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-abstract/cex-struct2/main.c b/regression/spurious-check-abstract/cex-struct2/main.c new file mode 100644 index 000000000..a5d7032f4 --- /dev/null +++ b/regression/spurious-check-abstract/cex-struct2/main.c @@ -0,0 +1,22 @@ + +#include +#include + +typedef struct{ int a; } foo; + +foo func_1(foo f) +{ + f.a = f.a + 1; + return f; +} + +int main() +{ + foo f0, f1; + f0.a = 0; + + f1 = func_1(f0); + + assert((f1.a) != 1); + return 0; +} diff --git a/regression/spurious-check-abstract/cex-struct2/test.desc b/regression/spurious-check-abstract/cex-struct2/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-abstract/cex-struct2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-abstract/cex-struct3/main.c b/regression/spurious-check-abstract/cex-struct3/main.c new file mode 100644 index 000000000..1715861bf --- /dev/null +++ b/regression/spurious-check-abstract/cex-struct3/main.c @@ -0,0 +1,23 @@ + +#include +#include + +typedef struct{ int x; int a; } foo; + +foo func_1(foo f) +{ + f.a = f.a + 1; + f.x = f.a; + return f; +} + +int main() +{ + foo f0, f1; + f0.a = 0; + + f1 = func_1(f0); + assert(f1.a != 1); // unsafe assertion + + return 0; +} diff --git a/regression/spurious-check-abstract/cex-struct3/test.desc b/regression/spurious-check-abstract/cex-struct3/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-abstract/cex-struct3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-abstract/cex1/main.c b/regression/spurious-check-abstract/cex1/main.c new file mode 100644 index 000000000..53451cf50 --- /dev/null +++ b/regression/spurious-check-abstract/cex1/main.c @@ -0,0 +1,15 @@ +#include + +int foo(int x) +{ + assert(x>5); +} + +int main(int argc, char** argv) +{ + int y; + if(y<=0) foo(y); + + return 0; +} + diff --git a/regression/spurious-check-abstract/cex1/test.desc b/regression/spurious-check-abstract/cex1/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-abstract/cex1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-abstract/cex10/main.c b/regression/spurious-check-abstract/cex10/main.c new file mode 100644 index 000000000..5908a46cc --- /dev/null +++ b/regression/spurious-check-abstract/cex10/main.c @@ -0,0 +1,21 @@ +#include + +int error(int k){ + assert(k != 3); +} + +int inc(int x){ + return (x+1); +}; + +int main(){ + int num = 0; + num = inc(num); + num = inc(num); + num = inc(num); + error(num); + return 0; +} + + + diff --git a/regression/spurious-check-abstract/cex10/test.desc b/regression/spurious-check-abstract/cex10/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-abstract/cex10/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-abstract/cex13/main.c b/regression/spurious-check-abstract/cex13/main.c new file mode 100644 index 000000000..242217d45 --- /dev/null +++ b/regression/spurious-check-abstract/cex13/main.c @@ -0,0 +1,16 @@ + +#include + +void foo(int x) +{ + assert(x==5); +} + +int main(int argc, char** argv) +{ + int y = 4; + foo(y); + + return 0; +} + diff --git a/regression/spurious-check-abstract/cex13/test.desc b/regression/spurious-check-abstract/cex13/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-abstract/cex13/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-abstract/cex2/main.c b/regression/spurious-check-abstract/cex2/main.c new file mode 100644 index 000000000..cd18d78fc --- /dev/null +++ b/regression/spurious-check-abstract/cex2/main.c @@ -0,0 +1,16 @@ + +#include + +void foo(int x) +{ + assert(x!=5); +} + +int main(int argc, char** argv) +{ + int y = 5; + foo(y); + + return 0; +} + diff --git a/regression/spurious-check-abstract/cex2/test.desc b/regression/spurious-check-abstract/cex2/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-abstract/cex2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-abstract/cex3/main.c b/regression/spurious-check-abstract/cex3/main.c new file mode 100644 index 000000000..952a3137b --- /dev/null +++ b/regression/spurious-check-abstract/cex3/main.c @@ -0,0 +1,16 @@ + +#include + +int foo(int x) +{ + assert(x!=5); +} + +int main(int argc, char** argv) +{ + int y; + if(y > 0) foo(y); + + return 0; +} + diff --git a/regression/spurious-check-abstract/cex3/test.desc b/regression/spurious-check-abstract/cex3/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-abstract/cex3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-abstract/cex4/main.c b/regression/spurious-check-abstract/cex4/main.c new file mode 100644 index 000000000..8463fe610 --- /dev/null +++ b/regression/spurious-check-abstract/cex4/main.c @@ -0,0 +1,11 @@ + +#include + +int main(int argc, char** argv) +{ + int y = 5; + assert(y != 5); + + return 0; +} + diff --git a/regression/spurious-check-abstract/cex4/test.desc b/regression/spurious-check-abstract/cex4/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-abstract/cex4/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-abstract/cex5/main.c b/regression/spurious-check-abstract/cex5/main.c new file mode 100644 index 000000000..0eabc5796 --- /dev/null +++ b/regression/spurious-check-abstract/cex5/main.c @@ -0,0 +1,15 @@ +#include + +int foo(int x) +{ + assert(x>5); +} + +int main(int argc, char** argv) +{ + int y; + if(y>0) foo(y); + + return 0; +} + diff --git a/regression/spurious-check-abstract/cex5/test.desc b/regression/spurious-check-abstract/cex5/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-abstract/cex5/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-abstract/cex6/main.c b/regression/spurious-check-abstract/cex6/main.c new file mode 100644 index 000000000..80de0138d --- /dev/null +++ b/regression/spurious-check-abstract/cex6/main.c @@ -0,0 +1,20 @@ + +#include + +void foo(int x) +{ + assert(x<1); +} + +int main() +{ + int y; + + while(y < 2){ + y++; + foo(y); + } + + return 0; +} + diff --git a/regression/spurious-check-abstract/cex6/test.desc b/regression/spurious-check-abstract/cex6/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-abstract/cex6/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-abstract/cex7/main.c b/regression/spurious-check-abstract/cex7/main.c new file mode 100644 index 000000000..8ab3e91f9 --- /dev/null +++ b/regression/spurious-check-abstract/cex7/main.c @@ -0,0 +1,15 @@ + +#include + +int main(int argc, char** argv) +{ + int y = 1; + + while(y<30){ + y++; + assert(y<4); + } + + return 0; +} + diff --git a/regression/spurious-check-abstract/cex7/test.desc b/regression/spurious-check-abstract/cex7/test.desc new file mode 100644 index 000000000..696fce3b5 --- /dev/null +++ b/regression/spurious-check-abstract/cex7/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --unwind 3 +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-abstract/cex8/main.c b/regression/spurious-check-abstract/cex8/main.c new file mode 100644 index 000000000..3bb7e471c --- /dev/null +++ b/regression/spurious-check-abstract/cex8/main.c @@ -0,0 +1,20 @@ +#include + +int error(int k){ + assert(k != 2); +} + +int inc(int x){ + return (x+1); +}; + +int main(){ + int num = 0; + num = inc(num); + num = inc(num); + error(num); + return 0; +} + + + diff --git a/regression/spurious-check-abstract/cex8/test.desc b/regression/spurious-check-abstract/cex8/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-abstract/cex8/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-abstract/cex9/main.c b/regression/spurious-check-abstract/cex9/main.c new file mode 100644 index 000000000..675f72f26 --- /dev/null +++ b/regression/spurious-check-abstract/cex9/main.c @@ -0,0 +1,24 @@ +#include + +int error(int k){ + assert(k != 2); +} + +int inc(int x){ + return (x+1); +}; + +int inc_copy(int x){ + return (x+1); +}; + +int main(){ + int num = 0; + num = inc_copy(num); + num = inc(num); + error(num); + return 0; +} + + + diff --git a/regression/spurious-check-abstract/cex9/test.desc b/regression/spurious-check-abstract/cex9/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-abstract/cex9/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-abstract/nocex1/main.c b/regression/spurious-check-abstract/nocex1/main.c new file mode 100644 index 000000000..6faa3e65d --- /dev/null +++ b/regression/spurious-check-abstract/nocex1/main.c @@ -0,0 +1,15 @@ +#include + +int foo(int x) +{ + assert(x>5); +} + +int main(int argc, char** argv) +{ + int y; + if(y>10) foo(y); + + return 0; +} + diff --git a/regression/spurious-check-abstract/nocex1/test.desc b/regression/spurious-check-abstract/nocex1/test.desc new file mode 100644 index 000000000..dc053e6ab --- /dev/null +++ b/regression/spurious-check-abstract/nocex1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/spurious-check-abstract/nocex10/main.c b/regression/spurious-check-abstract/nocex10/main.c new file mode 100644 index 000000000..5e3d522a4 --- /dev/null +++ b/regression/spurious-check-abstract/nocex10/main.c @@ -0,0 +1,11 @@ +#include + +void main() +{ + int x = 0; + int y = 0; + + while(y<10); + + assert(x==11); +} diff --git a/regression/spurious-check-abstract/nocex10/test.desc b/regression/spurious-check-abstract/nocex10/test.desc new file mode 100644 index 000000000..329fdf02a --- /dev/null +++ b/regression/spurious-check-abstract/nocex10/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --no-propagation +^EXIT=5$ +^SIGNAL=0$ +^VERIFICATION INCONCLUSIVE$ diff --git a/regression/spurious-check-abstract/nocex2/main.c b/regression/spurious-check-abstract/nocex2/main.c new file mode 100644 index 000000000..100ddaec6 --- /dev/null +++ b/regression/spurious-check-abstract/nocex2/main.c @@ -0,0 +1,16 @@ + +#include + +void foo(int x) +{ + assert(x==5); +} + +int main(int argc, char** argv) +{ + int y = 5; + foo(y); + + return 0; +} + diff --git a/regression/spurious-check-abstract/nocex2/test.desc b/regression/spurious-check-abstract/nocex2/test.desc new file mode 100644 index 000000000..dc053e6ab --- /dev/null +++ b/regression/spurious-check-abstract/nocex2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/spurious-check-abstract/nocex3/main.c b/regression/spurious-check-abstract/nocex3/main.c new file mode 100644 index 000000000..257e8fc7a --- /dev/null +++ b/regression/spurious-check-abstract/nocex3/main.c @@ -0,0 +1,18 @@ + +#include + +int bar(){ + return 1; +} + +void foo(int x) { + assert(x != 5); +} + +int main() { + int y = bar(); + foo(y); + return 0; +} + + diff --git a/regression/spurious-check-abstract/nocex3/test.desc b/regression/spurious-check-abstract/nocex3/test.desc new file mode 100644 index 000000000..dc053e6ab --- /dev/null +++ b/regression/spurious-check-abstract/nocex3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/spurious-check-abstract/nocex4/main.c b/regression/spurious-check-abstract/nocex4/main.c new file mode 100644 index 000000000..4e96e8e89 --- /dev/null +++ b/regression/spurious-check-abstract/nocex4/main.c @@ -0,0 +1,20 @@ + +#include + +int bar(int k){ + return (k+1); +} + +void foo(int x) { + x = bar(x); + assert(x>5); +} + +int main() { + int y; + __CPROVER_assume(y<100000); + if(y > 10) foo(y); + return 0; +} + + diff --git a/regression/spurious-check-abstract/nocex4/test.desc b/regression/spurious-check-abstract/nocex4/test.desc new file mode 100644 index 000000000..dc053e6ab --- /dev/null +++ b/regression/spurious-check-abstract/nocex4/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/spurious-check-abstract/nocex5/main.c b/regression/spurious-check-abstract/nocex5/main.c new file mode 100644 index 000000000..b225c7ce8 --- /dev/null +++ b/regression/spurious-check-abstract/nocex5/main.c @@ -0,0 +1,30 @@ + +#include + +int foobar(int a){ + int i; + if(i < a) + return i+a; + else + return i-a; +} + +int bar(int k){ + return (k+1); +} + +void foo(int x, int s) { + int m; + s = foobar(m); + x = bar(x); + assert(x>5); +} + +int main() { + int y,k; + __CPROVER_assume(y<100000); + if(y > 10) foo(y,k); + return 0; +} + + diff --git a/regression/spurious-check-abstract/nocex5/test.desc b/regression/spurious-check-abstract/nocex5/test.desc new file mode 100644 index 000000000..dc053e6ab --- /dev/null +++ b/regression/spurious-check-abstract/nocex5/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/spurious-check-abstract/nocex6/main.c b/regression/spurious-check-abstract/nocex6/main.c new file mode 100644 index 000000000..309c06dd9 --- /dev/null +++ b/regression/spurious-check-abstract/nocex6/main.c @@ -0,0 +1,15 @@ + +#include + +int main(int argc, char** argv) +{ + int y = 1; + + while(y<30){ + y++; + assert(y<5); + } + + return 0; +} + diff --git a/regression/spurious-check-abstract/nocex6/test.desc b/regression/spurious-check-abstract/nocex6/test.desc new file mode 100644 index 000000000..1f240717a --- /dev/null +++ b/regression/spurious-check-abstract/nocex6/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --unwind 2 +^EXIT=5$ +^SIGNAL=0$ +^VERIFICATION INCONCLUSIVE$ diff --git a/regression/spurious-check-abstract/nocex8/main.c b/regression/spurious-check-abstract/nocex8/main.c new file mode 100644 index 000000000..d9ee4be0c --- /dev/null +++ b/regression/spurious-check-abstract/nocex8/main.c @@ -0,0 +1,16 @@ + +#include + +void fail(void) +{ + assert(0); +} + +int main(void) +{ + int tmp = 0; + if(tmp) + fail(); + return 0; +} + diff --git a/regression/spurious-check-abstract/nocex8/test.desc b/regression/spurious-check-abstract/nocex8/test.desc new file mode 100644 index 000000000..dc053e6ab --- /dev/null +++ b/regression/spurious-check-abstract/nocex8/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/spurious-check-abstract/nocex9/main.c b/regression/spurious-check-abstract/nocex9/main.c new file mode 100644 index 000000000..47067bc2f --- /dev/null +++ b/regression/spurious-check-abstract/nocex9/main.c @@ -0,0 +1,11 @@ +#include + +void main() +{ + int x = 0; + int y = 0; + + while(y<10) { x++; } + + assert(x==11); +} diff --git a/regression/spurious-check-abstract/nocex9/test.desc b/regression/spurious-check-abstract/nocex9/test.desc new file mode 100644 index 000000000..329fdf02a --- /dev/null +++ b/regression/spurious-check-abstract/nocex9/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --no-propagation +^EXIT=5$ +^SIGNAL=0$ +^VERIFICATION INCONCLUSIVE$ diff --git a/regression/spurious-check-complete/Makefile b/regression/spurious-check-complete/Makefile new file mode 100644 index 000000000..2a3b5cb15 --- /dev/null +++ b/regression/spurious-check-complete/Makefile @@ -0,0 +1,20 @@ +default: tests.log + +FLAGS = --verbosity 10 --spurious-check complete + +test: + @../test.pl -c "../../../src/summarizer/2ls $(FLAGS)" + +tests.log: ../test.pl + @../test.pl -c "../../../src/summarizer/2ls $(FLAGS)" + +show: + @for dir in *; do \ + if [ -d "$$dir" ]; then \ + vim -o "$$dir/*.c" "$$dir/*.out"; \ + fi; \ + done; + +clean: + @rm -f *.log + @for dir in *; do rm -f $$dir/*.out; done; diff --git a/regression/spurious-check-complete/cex-struct1/main.c b/regression/spurious-check-complete/cex-struct1/main.c new file mode 100644 index 000000000..a9a9139fa --- /dev/null +++ b/regression/spurious-check-complete/cex-struct1/main.c @@ -0,0 +1,180 @@ + +#include +#include + +typedef struct{ int x; int y; int z; int w; int p; int q; int a; } foo; + +foo func_1(foo f); +foo func_2(foo f); +foo func_3(foo f); +foo func_4(foo f); +foo func_5(foo f); +foo func_6(foo f); +foo func_7(foo f); +foo func_8(foo f); + +foo func_1(foo f) +{ + f.x = 23 + 12; + f.x = 4 - 1; + if(f.w > f.x) {f.q = 21 * f.z;} else {f.q = 4 / f.p;} + f.a = f.a + 1; + f.z = f.y * f.x; + f.x = 11 - f.p; + f.y = 1 - 19; + f.y = f.w - 14; + return f; +} + +/**********************************************************************/ + +foo func_2(foo f) +{ + if(f.y < f.q) {f.x = f.w / 24;} else {f.w = 18 / 3;} + f.w = f.p * f.q; + if(f.q < 6) {f.y = 25 - f.x;} else {f.q = f.y / f.w;} + f.a = f.a + 1; + if(f.x <= f.x) {f.z = 9 + f.x;} else {f.y = 1 + f.x;} + f.x = f.q / 25; + f.w = f.x - f.y; + f.x = 9 + f.y; + f.y = 24 - 2; + f.w = 10 + f.z; + return f; +} + +/**********************************************************************/ + +foo func_3(foo f) +{ + if(f.p == 12) {f.w = 22 + 7;} else {f.p = f.x + f.q;} + f.y = f.p + f.x; + f.w = 6 * f.y; + if(f.z <= 20) {f.q = 21 / 24;} else {f.w = f.q * f.w;} + f.w = f.y - 10; + f.q = 2 - 20; + f.x = f.x / 10; + f.p = 16 * 23; + f.w = 18 - 13; + f.w = f.p - 2; + f.z = 7 + f.w; + f.a = f.a + 1; + f.x = 16 / f.x; + return f; +} + +/**********************************************************************/ + +foo func_4(foo f) +{ + f.w = f.y + f.y; + f.q = 18 * 13; + f.y = f.z * f.y; + f.x = 1 * 25; + f.y = 4 / f.q; + f.x = f.p / 9; + f.a = f.a + 1; + if(f.x >= 7) {f.q = f.q / 8;} else {if(f.x < 9) {f.z = 16 + f.p;} else {f.x = f.w - 18;}} + f.y = 2 * 4; + f.q = 16 + f.x; + f.q = 16 * f.w; + if(f.w > 14) {f.q = 20 + 20;} else {f.x = 25 + 9;} + return f; +} + +/**********************************************************************/ + +foo func_5(foo f) +{ + f.a = f.a + 1; + if(f.x == 13) {f.p = 13 * f.x;} else {f.w = f.q / f.w;} + f.y = 21 * f.x; + f.p = 4 * 25; + if(f.p >= 24) {f.x = 11 * 6;} else {f.p = 9 * f.p;} + f.x = 3 + f.z; + f.x = f.x + 22; + f.z = 8 / 8; + f.q = 18 + f.x; + f.x = 5 * f.z; + f.y = f.w + f.w; + return f; +} + +/**********************************************************************/ + +foo func_6(foo f) +{ + f.y = f.w / f.q; + f.p = f.x + 8; + f.a = f.a + 1; + f.z = f.w * 20; + if(f.x < f.p) {f.x = f.z + 2;} else {f.y = f.y * f.x;} + if(f.y <= f.y) {f.q = f.y * f.w;} else {f.q = f.w - 13;} + f.p = 9 + f.y; + f.q = f.y / 14; + f.p = 18 / f.z; + if(f.w < f.p) {f.w = 17 * f.p;} else {f.p = f.y - 10;} + f.p = 3 / 14; + f.q = 10 - f.w; + if(f.y > 12) {f.z = f.q - 24;} else {f.x = f.z / 17;} + return f; +} + +/**********************************************************************/ + +foo func_7(foo f) +{ + f.q = f.q * 23; + f.w = 25 - f.w; + if(f.q < f.y) {f.w = 21 + f.z;} else {f.p = 16 - 1;} + f.y = f.z * f.z; + f.x = 5 * 16; + f.x = 11 + f.x; + f.z = f.y - f.y; + f.q = 11 - f.z; + f.a = f.a + 1; + return f; +} + +/**********************************************************************/ + +foo func_8(foo f) +{ + f.w = f.y - 15; + f.q = f.x + f.z; + f.y = 5 / 1; + if(f.q < 3) {f.p = 6 * f.x; } else {f.w = 8 + 21;} + f.p = 19 / f.p; + f.z = 4 / f.z; + if(f.x < 12) {f.p = f.y - 4; } else {f.x = 15 + 2;} + f.q = 19 / f.w; + if(f.p > 24) {f.z = 5 / 9;} else {f.w = f.x + f.z;} + f.z = f.z + 1; + f.a = f.a + 1; + if(f.z > f.y) {f.y = f.y + f.x;} else {f.y = 13 - 18;} + return f; +} + + +/**********************************************************************/ + +int main() +{ + foo f0, f1, f2, f3, f4, f5, f6, f7, f8; + +// __CPROVER_assume((f0.a >= 0) && (f0.a <= 9)); + f0.a = 0; + + f1 = func_1(f0); +/* f2 = func_2(f1); + f3 = func_3(f2); + f4 = func_4(f3); + f5 = func_5(f4); + f6 = func_6(f5); + f7 = func_7(f6); + f8 = func_8(f7);*/ + + assert(/*(f8.x + f8.y + f8.z + f8.w + f8.p + f8.q > 0) &&*/ (f1.a != 1)); // unsafe assertion + + return 0; +} diff --git a/regression/spurious-check-complete/cex-struct1/test.desc b/regression/spurious-check-complete/cex-struct1/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-complete/cex-struct1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-complete/cex-struct2/main.c b/regression/spurious-check-complete/cex-struct2/main.c new file mode 100644 index 000000000..a5d7032f4 --- /dev/null +++ b/regression/spurious-check-complete/cex-struct2/main.c @@ -0,0 +1,22 @@ + +#include +#include + +typedef struct{ int a; } foo; + +foo func_1(foo f) +{ + f.a = f.a + 1; + return f; +} + +int main() +{ + foo f0, f1; + f0.a = 0; + + f1 = func_1(f0); + + assert((f1.a) != 1); + return 0; +} diff --git a/regression/spurious-check-complete/cex-struct2/test.desc b/regression/spurious-check-complete/cex-struct2/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-complete/cex-struct2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-complete/cex-struct3/main.c b/regression/spurious-check-complete/cex-struct3/main.c new file mode 100644 index 000000000..1715861bf --- /dev/null +++ b/regression/spurious-check-complete/cex-struct3/main.c @@ -0,0 +1,23 @@ + +#include +#include + +typedef struct{ int x; int a; } foo; + +foo func_1(foo f) +{ + f.a = f.a + 1; + f.x = f.a; + return f; +} + +int main() +{ + foo f0, f1; + f0.a = 0; + + f1 = func_1(f0); + assert(f1.a != 1); // unsafe assertion + + return 0; +} diff --git a/regression/spurious-check-complete/cex-struct3/test.desc b/regression/spurious-check-complete/cex-struct3/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-complete/cex-struct3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-complete/cex1/main.c b/regression/spurious-check-complete/cex1/main.c new file mode 100644 index 000000000..53451cf50 --- /dev/null +++ b/regression/spurious-check-complete/cex1/main.c @@ -0,0 +1,15 @@ +#include + +int foo(int x) +{ + assert(x>5); +} + +int main(int argc, char** argv) +{ + int y; + if(y<=0) foo(y); + + return 0; +} + diff --git a/regression/spurious-check-complete/cex1/test.desc b/regression/spurious-check-complete/cex1/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-complete/cex1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-complete/cex10/main.c b/regression/spurious-check-complete/cex10/main.c new file mode 100644 index 000000000..5908a46cc --- /dev/null +++ b/regression/spurious-check-complete/cex10/main.c @@ -0,0 +1,21 @@ +#include + +int error(int k){ + assert(k != 3); +} + +int inc(int x){ + return (x+1); +}; + +int main(){ + int num = 0; + num = inc(num); + num = inc(num); + num = inc(num); + error(num); + return 0; +} + + + diff --git a/regression/spurious-check-complete/cex10/test.desc b/regression/spurious-check-complete/cex10/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-complete/cex10/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-complete/cex13/main.c b/regression/spurious-check-complete/cex13/main.c new file mode 100644 index 000000000..242217d45 --- /dev/null +++ b/regression/spurious-check-complete/cex13/main.c @@ -0,0 +1,16 @@ + +#include + +void foo(int x) +{ + assert(x==5); +} + +int main(int argc, char** argv) +{ + int y = 4; + foo(y); + + return 0; +} + diff --git a/regression/spurious-check-complete/cex13/test.desc b/regression/spurious-check-complete/cex13/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-complete/cex13/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-complete/cex2/main.c b/regression/spurious-check-complete/cex2/main.c new file mode 100644 index 000000000..cd18d78fc --- /dev/null +++ b/regression/spurious-check-complete/cex2/main.c @@ -0,0 +1,16 @@ + +#include + +void foo(int x) +{ + assert(x!=5); +} + +int main(int argc, char** argv) +{ + int y = 5; + foo(y); + + return 0; +} + diff --git a/regression/spurious-check-complete/cex2/test.desc b/regression/spurious-check-complete/cex2/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-complete/cex2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-complete/cex3/main.c b/regression/spurious-check-complete/cex3/main.c new file mode 100644 index 000000000..952a3137b --- /dev/null +++ b/regression/spurious-check-complete/cex3/main.c @@ -0,0 +1,16 @@ + +#include + +int foo(int x) +{ + assert(x!=5); +} + +int main(int argc, char** argv) +{ + int y; + if(y > 0) foo(y); + + return 0; +} + diff --git a/regression/spurious-check-complete/cex3/test.desc b/regression/spurious-check-complete/cex3/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-complete/cex3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-complete/cex4/main.c b/regression/spurious-check-complete/cex4/main.c new file mode 100644 index 000000000..8463fe610 --- /dev/null +++ b/regression/spurious-check-complete/cex4/main.c @@ -0,0 +1,11 @@ + +#include + +int main(int argc, char** argv) +{ + int y = 5; + assert(y != 5); + + return 0; +} + diff --git a/regression/spurious-check-complete/cex4/test.desc b/regression/spurious-check-complete/cex4/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-complete/cex4/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-complete/cex5/main.c b/regression/spurious-check-complete/cex5/main.c new file mode 100644 index 000000000..0eabc5796 --- /dev/null +++ b/regression/spurious-check-complete/cex5/main.c @@ -0,0 +1,15 @@ +#include + +int foo(int x) +{ + assert(x>5); +} + +int main(int argc, char** argv) +{ + int y; + if(y>0) foo(y); + + return 0; +} + diff --git a/regression/spurious-check-complete/cex5/test.desc b/regression/spurious-check-complete/cex5/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-complete/cex5/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-complete/cex6/main.c b/regression/spurious-check-complete/cex6/main.c new file mode 100644 index 000000000..80de0138d --- /dev/null +++ b/regression/spurious-check-complete/cex6/main.c @@ -0,0 +1,20 @@ + +#include + +void foo(int x) +{ + assert(x<1); +} + +int main() +{ + int y; + + while(y < 2){ + y++; + foo(y); + } + + return 0; +} + diff --git a/regression/spurious-check-complete/cex6/test.desc b/regression/spurious-check-complete/cex6/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-complete/cex6/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-complete/cex7/main.c b/regression/spurious-check-complete/cex7/main.c new file mode 100644 index 000000000..8ab3e91f9 --- /dev/null +++ b/regression/spurious-check-complete/cex7/main.c @@ -0,0 +1,15 @@ + +#include + +int main(int argc, char** argv) +{ + int y = 1; + + while(y<30){ + y++; + assert(y<4); + } + + return 0; +} + diff --git a/regression/spurious-check-complete/cex7/test.desc b/regression/spurious-check-complete/cex7/test.desc new file mode 100644 index 000000000..696fce3b5 --- /dev/null +++ b/regression/spurious-check-complete/cex7/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --unwind 3 +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-complete/cex8/main.c b/regression/spurious-check-complete/cex8/main.c new file mode 100644 index 000000000..3bb7e471c --- /dev/null +++ b/regression/spurious-check-complete/cex8/main.c @@ -0,0 +1,20 @@ +#include + +int error(int k){ + assert(k != 2); +} + +int inc(int x){ + return (x+1); +}; + +int main(){ + int num = 0; + num = inc(num); + num = inc(num); + error(num); + return 0; +} + + + diff --git a/regression/spurious-check-complete/cex8/test.desc b/regression/spurious-check-complete/cex8/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-complete/cex8/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-complete/cex9/main.c b/regression/spurious-check-complete/cex9/main.c new file mode 100644 index 000000000..675f72f26 --- /dev/null +++ b/regression/spurious-check-complete/cex9/main.c @@ -0,0 +1,24 @@ +#include + +int error(int k){ + assert(k != 2); +} + +int inc(int x){ + return (x+1); +}; + +int inc_copy(int x){ + return (x+1); +}; + +int main(){ + int num = 0; + num = inc_copy(num); + num = inc(num); + error(num); + return 0; +} + + + diff --git a/regression/spurious-check-complete/cex9/test.desc b/regression/spurious-check-complete/cex9/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-complete/cex9/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-complete/nocex1/main.c b/regression/spurious-check-complete/nocex1/main.c new file mode 100644 index 000000000..6faa3e65d --- /dev/null +++ b/regression/spurious-check-complete/nocex1/main.c @@ -0,0 +1,15 @@ +#include + +int foo(int x) +{ + assert(x>5); +} + +int main(int argc, char** argv) +{ + int y; + if(y>10) foo(y); + + return 0; +} + diff --git a/regression/spurious-check-complete/nocex1/test.desc b/regression/spurious-check-complete/nocex1/test.desc new file mode 100644 index 000000000..dc053e6ab --- /dev/null +++ b/regression/spurious-check-complete/nocex1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/spurious-check-complete/nocex10/main.c b/regression/spurious-check-complete/nocex10/main.c new file mode 100644 index 000000000..5e3d522a4 --- /dev/null +++ b/regression/spurious-check-complete/nocex10/main.c @@ -0,0 +1,11 @@ +#include + +void main() +{ + int x = 0; + int y = 0; + + while(y<10); + + assert(x==11); +} diff --git a/regression/spurious-check-complete/nocex10/test.desc b/regression/spurious-check-complete/nocex10/test.desc new file mode 100644 index 000000000..329fdf02a --- /dev/null +++ b/regression/spurious-check-complete/nocex10/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --no-propagation +^EXIT=5$ +^SIGNAL=0$ +^VERIFICATION INCONCLUSIVE$ diff --git a/regression/spurious-check-complete/nocex2/main.c b/regression/spurious-check-complete/nocex2/main.c new file mode 100644 index 000000000..100ddaec6 --- /dev/null +++ b/regression/spurious-check-complete/nocex2/main.c @@ -0,0 +1,16 @@ + +#include + +void foo(int x) +{ + assert(x==5); +} + +int main(int argc, char** argv) +{ + int y = 5; + foo(y); + + return 0; +} + diff --git a/regression/spurious-check-complete/nocex2/test.desc b/regression/spurious-check-complete/nocex2/test.desc new file mode 100644 index 000000000..dc053e6ab --- /dev/null +++ b/regression/spurious-check-complete/nocex2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/spurious-check-complete/nocex3/main.c b/regression/spurious-check-complete/nocex3/main.c new file mode 100644 index 000000000..257e8fc7a --- /dev/null +++ b/regression/spurious-check-complete/nocex3/main.c @@ -0,0 +1,18 @@ + +#include + +int bar(){ + return 1; +} + +void foo(int x) { + assert(x != 5); +} + +int main() { + int y = bar(); + foo(y); + return 0; +} + + diff --git a/regression/spurious-check-complete/nocex3/test.desc b/regression/spurious-check-complete/nocex3/test.desc new file mode 100644 index 000000000..dc053e6ab --- /dev/null +++ b/regression/spurious-check-complete/nocex3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/spurious-check-complete/nocex4/main.c b/regression/spurious-check-complete/nocex4/main.c new file mode 100644 index 000000000..4e96e8e89 --- /dev/null +++ b/regression/spurious-check-complete/nocex4/main.c @@ -0,0 +1,20 @@ + +#include + +int bar(int k){ + return (k+1); +} + +void foo(int x) { + x = bar(x); + assert(x>5); +} + +int main() { + int y; + __CPROVER_assume(y<100000); + if(y > 10) foo(y); + return 0; +} + + diff --git a/regression/spurious-check-complete/nocex4/test.desc b/regression/spurious-check-complete/nocex4/test.desc new file mode 100644 index 000000000..dc053e6ab --- /dev/null +++ b/regression/spurious-check-complete/nocex4/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/spurious-check-complete/nocex5/main.c b/regression/spurious-check-complete/nocex5/main.c new file mode 100644 index 000000000..b225c7ce8 --- /dev/null +++ b/regression/spurious-check-complete/nocex5/main.c @@ -0,0 +1,30 @@ + +#include + +int foobar(int a){ + int i; + if(i < a) + return i+a; + else + return i-a; +} + +int bar(int k){ + return (k+1); +} + +void foo(int x, int s) { + int m; + s = foobar(m); + x = bar(x); + assert(x>5); +} + +int main() { + int y,k; + __CPROVER_assume(y<100000); + if(y > 10) foo(y,k); + return 0; +} + + diff --git a/regression/spurious-check-complete/nocex5/test.desc b/regression/spurious-check-complete/nocex5/test.desc new file mode 100644 index 000000000..dc053e6ab --- /dev/null +++ b/regression/spurious-check-complete/nocex5/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/spurious-check-complete/nocex6/main.c b/regression/spurious-check-complete/nocex6/main.c new file mode 100644 index 000000000..309c06dd9 --- /dev/null +++ b/regression/spurious-check-complete/nocex6/main.c @@ -0,0 +1,15 @@ + +#include + +int main(int argc, char** argv) +{ + int y = 1; + + while(y<30){ + y++; + assert(y<5); + } + + return 0; +} + diff --git a/regression/spurious-check-complete/nocex6/test.desc b/regression/spurious-check-complete/nocex6/test.desc new file mode 100644 index 000000000..1f240717a --- /dev/null +++ b/regression/spurious-check-complete/nocex6/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --unwind 2 +^EXIT=5$ +^SIGNAL=0$ +^VERIFICATION INCONCLUSIVE$ diff --git a/regression/spurious-check-complete/nocex8/main.c b/regression/spurious-check-complete/nocex8/main.c new file mode 100644 index 000000000..d9ee4be0c --- /dev/null +++ b/regression/spurious-check-complete/nocex8/main.c @@ -0,0 +1,16 @@ + +#include + +void fail(void) +{ + assert(0); +} + +int main(void) +{ + int tmp = 0; + if(tmp) + fail(); + return 0; +} + diff --git a/regression/spurious-check-complete/nocex8/test.desc b/regression/spurious-check-complete/nocex8/test.desc new file mode 100644 index 000000000..dc053e6ab --- /dev/null +++ b/regression/spurious-check-complete/nocex8/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/spurious-check-complete/nocex9/main.c b/regression/spurious-check-complete/nocex9/main.c new file mode 100644 index 000000000..47067bc2f --- /dev/null +++ b/regression/spurious-check-complete/nocex9/main.c @@ -0,0 +1,11 @@ +#include + +void main() +{ + int x = 0; + int y = 0; + + while(y<10) { x++; } + + assert(x==11); +} diff --git a/regression/spurious-check-complete/nocex9/test.desc b/regression/spurious-check-complete/nocex9/test.desc new file mode 100644 index 000000000..329fdf02a --- /dev/null +++ b/regression/spurious-check-complete/nocex9/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --no-propagation +^EXIT=5$ +^SIGNAL=0$ +^VERIFICATION INCONCLUSIVE$ diff --git a/regression/spurious-check-concrete/Makefile b/regression/spurious-check-concrete/Makefile new file mode 100644 index 000000000..c26b769b2 --- /dev/null +++ b/regression/spurious-check-concrete/Makefile @@ -0,0 +1,20 @@ +default: tests.log + +FLAGS = --verbosity 10 --spurious-check concrete + +test: + @../test.pl -c "../../../src/summarizer/2ls $(FLAGS)" + +tests.log: ../test.pl + @../test.pl -c "../../../src/summarizer/2ls $(FLAGS)" + +show: + @for dir in *; do \ + if [ -d "$$dir" ]; then \ + vim -o "$$dir/*.c" "$$dir/*.out"; \ + fi; \ + done; + +clean: + @rm -f *.log + @for dir in *; do rm -f $$dir/*.out; done; diff --git a/regression/spurious-check-concrete/cex-struct1/main.c b/regression/spurious-check-concrete/cex-struct1/main.c new file mode 100644 index 000000000..a9a9139fa --- /dev/null +++ b/regression/spurious-check-concrete/cex-struct1/main.c @@ -0,0 +1,180 @@ + +#include +#include + +typedef struct{ int x; int y; int z; int w; int p; int q; int a; } foo; + +foo func_1(foo f); +foo func_2(foo f); +foo func_3(foo f); +foo func_4(foo f); +foo func_5(foo f); +foo func_6(foo f); +foo func_7(foo f); +foo func_8(foo f); + +foo func_1(foo f) +{ + f.x = 23 + 12; + f.x = 4 - 1; + if(f.w > f.x) {f.q = 21 * f.z;} else {f.q = 4 / f.p;} + f.a = f.a + 1; + f.z = f.y * f.x; + f.x = 11 - f.p; + f.y = 1 - 19; + f.y = f.w - 14; + return f; +} + +/**********************************************************************/ + +foo func_2(foo f) +{ + if(f.y < f.q) {f.x = f.w / 24;} else {f.w = 18 / 3;} + f.w = f.p * f.q; + if(f.q < 6) {f.y = 25 - f.x;} else {f.q = f.y / f.w;} + f.a = f.a + 1; + if(f.x <= f.x) {f.z = 9 + f.x;} else {f.y = 1 + f.x;} + f.x = f.q / 25; + f.w = f.x - f.y; + f.x = 9 + f.y; + f.y = 24 - 2; + f.w = 10 + f.z; + return f; +} + +/**********************************************************************/ + +foo func_3(foo f) +{ + if(f.p == 12) {f.w = 22 + 7;} else {f.p = f.x + f.q;} + f.y = f.p + f.x; + f.w = 6 * f.y; + if(f.z <= 20) {f.q = 21 / 24;} else {f.w = f.q * f.w;} + f.w = f.y - 10; + f.q = 2 - 20; + f.x = f.x / 10; + f.p = 16 * 23; + f.w = 18 - 13; + f.w = f.p - 2; + f.z = 7 + f.w; + f.a = f.a + 1; + f.x = 16 / f.x; + return f; +} + +/**********************************************************************/ + +foo func_4(foo f) +{ + f.w = f.y + f.y; + f.q = 18 * 13; + f.y = f.z * f.y; + f.x = 1 * 25; + f.y = 4 / f.q; + f.x = f.p / 9; + f.a = f.a + 1; + if(f.x >= 7) {f.q = f.q / 8;} else {if(f.x < 9) {f.z = 16 + f.p;} else {f.x = f.w - 18;}} + f.y = 2 * 4; + f.q = 16 + f.x; + f.q = 16 * f.w; + if(f.w > 14) {f.q = 20 + 20;} else {f.x = 25 + 9;} + return f; +} + +/**********************************************************************/ + +foo func_5(foo f) +{ + f.a = f.a + 1; + if(f.x == 13) {f.p = 13 * f.x;} else {f.w = f.q / f.w;} + f.y = 21 * f.x; + f.p = 4 * 25; + if(f.p >= 24) {f.x = 11 * 6;} else {f.p = 9 * f.p;} + f.x = 3 + f.z; + f.x = f.x + 22; + f.z = 8 / 8; + f.q = 18 + f.x; + f.x = 5 * f.z; + f.y = f.w + f.w; + return f; +} + +/**********************************************************************/ + +foo func_6(foo f) +{ + f.y = f.w / f.q; + f.p = f.x + 8; + f.a = f.a + 1; + f.z = f.w * 20; + if(f.x < f.p) {f.x = f.z + 2;} else {f.y = f.y * f.x;} + if(f.y <= f.y) {f.q = f.y * f.w;} else {f.q = f.w - 13;} + f.p = 9 + f.y; + f.q = f.y / 14; + f.p = 18 / f.z; + if(f.w < f.p) {f.w = 17 * f.p;} else {f.p = f.y - 10;} + f.p = 3 / 14; + f.q = 10 - f.w; + if(f.y > 12) {f.z = f.q - 24;} else {f.x = f.z / 17;} + return f; +} + +/**********************************************************************/ + +foo func_7(foo f) +{ + f.q = f.q * 23; + f.w = 25 - f.w; + if(f.q < f.y) {f.w = 21 + f.z;} else {f.p = 16 - 1;} + f.y = f.z * f.z; + f.x = 5 * 16; + f.x = 11 + f.x; + f.z = f.y - f.y; + f.q = 11 - f.z; + f.a = f.a + 1; + return f; +} + +/**********************************************************************/ + +foo func_8(foo f) +{ + f.w = f.y - 15; + f.q = f.x + f.z; + f.y = 5 / 1; + if(f.q < 3) {f.p = 6 * f.x; } else {f.w = 8 + 21;} + f.p = 19 / f.p; + f.z = 4 / f.z; + if(f.x < 12) {f.p = f.y - 4; } else {f.x = 15 + 2;} + f.q = 19 / f.w; + if(f.p > 24) {f.z = 5 / 9;} else {f.w = f.x + f.z;} + f.z = f.z + 1; + f.a = f.a + 1; + if(f.z > f.y) {f.y = f.y + f.x;} else {f.y = 13 - 18;} + return f; +} + + +/**********************************************************************/ + +int main() +{ + foo f0, f1, f2, f3, f4, f5, f6, f7, f8; + +// __CPROVER_assume((f0.a >= 0) && (f0.a <= 9)); + f0.a = 0; + + f1 = func_1(f0); +/* f2 = func_2(f1); + f3 = func_3(f2); + f4 = func_4(f3); + f5 = func_5(f4); + f6 = func_6(f5); + f7 = func_7(f6); + f8 = func_8(f7);*/ + + assert(/*(f8.x + f8.y + f8.z + f8.w + f8.p + f8.q > 0) &&*/ (f1.a != 1)); // unsafe assertion + + return 0; +} diff --git a/regression/spurious-check-concrete/cex-struct1/test.desc b/regression/spurious-check-concrete/cex-struct1/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-concrete/cex-struct1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-concrete/cex-struct2/main.c b/regression/spurious-check-concrete/cex-struct2/main.c new file mode 100644 index 000000000..a5d7032f4 --- /dev/null +++ b/regression/spurious-check-concrete/cex-struct2/main.c @@ -0,0 +1,22 @@ + +#include +#include + +typedef struct{ int a; } foo; + +foo func_1(foo f) +{ + f.a = f.a + 1; + return f; +} + +int main() +{ + foo f0, f1; + f0.a = 0; + + f1 = func_1(f0); + + assert((f1.a) != 1); + return 0; +} diff --git a/regression/spurious-check-concrete/cex-struct2/test.desc b/regression/spurious-check-concrete/cex-struct2/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-concrete/cex-struct2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-concrete/cex-struct3/main.c b/regression/spurious-check-concrete/cex-struct3/main.c new file mode 100644 index 000000000..1715861bf --- /dev/null +++ b/regression/spurious-check-concrete/cex-struct3/main.c @@ -0,0 +1,23 @@ + +#include +#include + +typedef struct{ int x; int a; } foo; + +foo func_1(foo f) +{ + f.a = f.a + 1; + f.x = f.a; + return f; +} + +int main() +{ + foo f0, f1; + f0.a = 0; + + f1 = func_1(f0); + assert(f1.a != 1); // unsafe assertion + + return 0; +} diff --git a/regression/spurious-check-concrete/cex-struct3/test.desc b/regression/spurious-check-concrete/cex-struct3/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-concrete/cex-struct3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-concrete/cex1/main.c b/regression/spurious-check-concrete/cex1/main.c new file mode 100644 index 000000000..53451cf50 --- /dev/null +++ b/regression/spurious-check-concrete/cex1/main.c @@ -0,0 +1,15 @@ +#include + +int foo(int x) +{ + assert(x>5); +} + +int main(int argc, char** argv) +{ + int y; + if(y<=0) foo(y); + + return 0; +} + diff --git a/regression/spurious-check-concrete/cex1/test.desc b/regression/spurious-check-concrete/cex1/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-concrete/cex1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-concrete/cex10/main.c b/regression/spurious-check-concrete/cex10/main.c new file mode 100644 index 000000000..5908a46cc --- /dev/null +++ b/regression/spurious-check-concrete/cex10/main.c @@ -0,0 +1,21 @@ +#include + +int error(int k){ + assert(k != 3); +} + +int inc(int x){ + return (x+1); +}; + +int main(){ + int num = 0; + num = inc(num); + num = inc(num); + num = inc(num); + error(num); + return 0; +} + + + diff --git a/regression/spurious-check-concrete/cex10/test.desc b/regression/spurious-check-concrete/cex10/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-concrete/cex10/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-concrete/cex13/main.c b/regression/spurious-check-concrete/cex13/main.c new file mode 100644 index 000000000..242217d45 --- /dev/null +++ b/regression/spurious-check-concrete/cex13/main.c @@ -0,0 +1,16 @@ + +#include + +void foo(int x) +{ + assert(x==5); +} + +int main(int argc, char** argv) +{ + int y = 4; + foo(y); + + return 0; +} + diff --git a/regression/spurious-check-concrete/cex13/test.desc b/regression/spurious-check-concrete/cex13/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-concrete/cex13/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-concrete/cex2/main.c b/regression/spurious-check-concrete/cex2/main.c new file mode 100644 index 000000000..cd18d78fc --- /dev/null +++ b/regression/spurious-check-concrete/cex2/main.c @@ -0,0 +1,16 @@ + +#include + +void foo(int x) +{ + assert(x!=5); +} + +int main(int argc, char** argv) +{ + int y = 5; + foo(y); + + return 0; +} + diff --git a/regression/spurious-check-concrete/cex2/test.desc b/regression/spurious-check-concrete/cex2/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-concrete/cex2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-concrete/cex3/main.c b/regression/spurious-check-concrete/cex3/main.c new file mode 100644 index 000000000..952a3137b --- /dev/null +++ b/regression/spurious-check-concrete/cex3/main.c @@ -0,0 +1,16 @@ + +#include + +int foo(int x) +{ + assert(x!=5); +} + +int main(int argc, char** argv) +{ + int y; + if(y > 0) foo(y); + + return 0; +} + diff --git a/regression/spurious-check-concrete/cex3/test.desc b/regression/spurious-check-concrete/cex3/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-concrete/cex3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-concrete/cex4/main.c b/regression/spurious-check-concrete/cex4/main.c new file mode 100644 index 000000000..8463fe610 --- /dev/null +++ b/regression/spurious-check-concrete/cex4/main.c @@ -0,0 +1,11 @@ + +#include + +int main(int argc, char** argv) +{ + int y = 5; + assert(y != 5); + + return 0; +} + diff --git a/regression/spurious-check-concrete/cex4/test.desc b/regression/spurious-check-concrete/cex4/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-concrete/cex4/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-concrete/cex5/main.c b/regression/spurious-check-concrete/cex5/main.c new file mode 100644 index 000000000..0eabc5796 --- /dev/null +++ b/regression/spurious-check-concrete/cex5/main.c @@ -0,0 +1,15 @@ +#include + +int foo(int x) +{ + assert(x>5); +} + +int main(int argc, char** argv) +{ + int y; + if(y>0) foo(y); + + return 0; +} + diff --git a/regression/spurious-check-concrete/cex5/test.desc b/regression/spurious-check-concrete/cex5/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-concrete/cex5/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-concrete/cex6/main.c b/regression/spurious-check-concrete/cex6/main.c new file mode 100644 index 000000000..80de0138d --- /dev/null +++ b/regression/spurious-check-concrete/cex6/main.c @@ -0,0 +1,20 @@ + +#include + +void foo(int x) +{ + assert(x<1); +} + +int main() +{ + int y; + + while(y < 2){ + y++; + foo(y); + } + + return 0; +} + diff --git a/regression/spurious-check-concrete/cex6/test.desc b/regression/spurious-check-concrete/cex6/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-concrete/cex6/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-concrete/cex7/main.c b/regression/spurious-check-concrete/cex7/main.c new file mode 100644 index 000000000..8ab3e91f9 --- /dev/null +++ b/regression/spurious-check-concrete/cex7/main.c @@ -0,0 +1,15 @@ + +#include + +int main(int argc, char** argv) +{ + int y = 1; + + while(y<30){ + y++; + assert(y<4); + } + + return 0; +} + diff --git a/regression/spurious-check-concrete/cex7/test.desc b/regression/spurious-check-concrete/cex7/test.desc new file mode 100644 index 000000000..696fce3b5 --- /dev/null +++ b/regression/spurious-check-concrete/cex7/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --unwind 3 +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-concrete/cex8/main.c b/regression/spurious-check-concrete/cex8/main.c new file mode 100644 index 000000000..3bb7e471c --- /dev/null +++ b/regression/spurious-check-concrete/cex8/main.c @@ -0,0 +1,20 @@ +#include + +int error(int k){ + assert(k != 2); +} + +int inc(int x){ + return (x+1); +}; + +int main(){ + int num = 0; + num = inc(num); + num = inc(num); + error(num); + return 0; +} + + + diff --git a/regression/spurious-check-concrete/cex8/test.desc b/regression/spurious-check-concrete/cex8/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-concrete/cex8/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-concrete/cex9/main.c b/regression/spurious-check-concrete/cex9/main.c new file mode 100644 index 000000000..675f72f26 --- /dev/null +++ b/regression/spurious-check-concrete/cex9/main.c @@ -0,0 +1,24 @@ +#include + +int error(int k){ + assert(k != 2); +} + +int inc(int x){ + return (x+1); +}; + +int inc_copy(int x){ + return (x+1); +}; + +int main(){ + int num = 0; + num = inc_copy(num); + num = inc(num); + error(num); + return 0; +} + + + diff --git a/regression/spurious-check-concrete/cex9/test.desc b/regression/spurious-check-concrete/cex9/test.desc new file mode 100644 index 000000000..429367b44 --- /dev/null +++ b/regression/spurious-check-concrete/cex9/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/spurious-check-concrete/nocex1/main.c b/regression/spurious-check-concrete/nocex1/main.c new file mode 100644 index 000000000..6faa3e65d --- /dev/null +++ b/regression/spurious-check-concrete/nocex1/main.c @@ -0,0 +1,15 @@ +#include + +int foo(int x) +{ + assert(x>5); +} + +int main(int argc, char** argv) +{ + int y; + if(y>10) foo(y); + + return 0; +} + diff --git a/regression/spurious-check-concrete/nocex1/test.desc b/regression/spurious-check-concrete/nocex1/test.desc new file mode 100644 index 000000000..dc053e6ab --- /dev/null +++ b/regression/spurious-check-concrete/nocex1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/spurious-check-concrete/nocex10/main.c b/regression/spurious-check-concrete/nocex10/main.c new file mode 100644 index 000000000..5e3d522a4 --- /dev/null +++ b/regression/spurious-check-concrete/nocex10/main.c @@ -0,0 +1,11 @@ +#include + +void main() +{ + int x = 0; + int y = 0; + + while(y<10); + + assert(x==11); +} diff --git a/regression/spurious-check-concrete/nocex10/test.desc b/regression/spurious-check-concrete/nocex10/test.desc new file mode 100644 index 000000000..329fdf02a --- /dev/null +++ b/regression/spurious-check-concrete/nocex10/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --no-propagation +^EXIT=5$ +^SIGNAL=0$ +^VERIFICATION INCONCLUSIVE$ diff --git a/regression/spurious-check-concrete/nocex2/main.c b/regression/spurious-check-concrete/nocex2/main.c new file mode 100644 index 000000000..100ddaec6 --- /dev/null +++ b/regression/spurious-check-concrete/nocex2/main.c @@ -0,0 +1,16 @@ + +#include + +void foo(int x) +{ + assert(x==5); +} + +int main(int argc, char** argv) +{ + int y = 5; + foo(y); + + return 0; +} + diff --git a/regression/spurious-check-concrete/nocex2/test.desc b/regression/spurious-check-concrete/nocex2/test.desc new file mode 100644 index 000000000..dc053e6ab --- /dev/null +++ b/regression/spurious-check-concrete/nocex2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/spurious-check-concrete/nocex3/main.c b/regression/spurious-check-concrete/nocex3/main.c new file mode 100644 index 000000000..257e8fc7a --- /dev/null +++ b/regression/spurious-check-concrete/nocex3/main.c @@ -0,0 +1,18 @@ + +#include + +int bar(){ + return 1; +} + +void foo(int x) { + assert(x != 5); +} + +int main() { + int y = bar(); + foo(y); + return 0; +} + + diff --git a/regression/spurious-check-concrete/nocex3/test.desc b/regression/spurious-check-concrete/nocex3/test.desc new file mode 100644 index 000000000..dc053e6ab --- /dev/null +++ b/regression/spurious-check-concrete/nocex3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/spurious-check-concrete/nocex4/main.c b/regression/spurious-check-concrete/nocex4/main.c new file mode 100644 index 000000000..4e96e8e89 --- /dev/null +++ b/regression/spurious-check-concrete/nocex4/main.c @@ -0,0 +1,20 @@ + +#include + +int bar(int k){ + return (k+1); +} + +void foo(int x) { + x = bar(x); + assert(x>5); +} + +int main() { + int y; + __CPROVER_assume(y<100000); + if(y > 10) foo(y); + return 0; +} + + diff --git a/regression/spurious-check-concrete/nocex4/test.desc b/regression/spurious-check-concrete/nocex4/test.desc new file mode 100644 index 000000000..dc053e6ab --- /dev/null +++ b/regression/spurious-check-concrete/nocex4/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/spurious-check-concrete/nocex5/main.c b/regression/spurious-check-concrete/nocex5/main.c new file mode 100644 index 000000000..b225c7ce8 --- /dev/null +++ b/regression/spurious-check-concrete/nocex5/main.c @@ -0,0 +1,30 @@ + +#include + +int foobar(int a){ + int i; + if(i < a) + return i+a; + else + return i-a; +} + +int bar(int k){ + return (k+1); +} + +void foo(int x, int s) { + int m; + s = foobar(m); + x = bar(x); + assert(x>5); +} + +int main() { + int y,k; + __CPROVER_assume(y<100000); + if(y > 10) foo(y,k); + return 0; +} + + diff --git a/regression/spurious-check-concrete/nocex5/test.desc b/regression/spurious-check-concrete/nocex5/test.desc new file mode 100644 index 000000000..dc053e6ab --- /dev/null +++ b/regression/spurious-check-concrete/nocex5/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/spurious-check-concrete/nocex6/main.c b/regression/spurious-check-concrete/nocex6/main.c new file mode 100644 index 000000000..309c06dd9 --- /dev/null +++ b/regression/spurious-check-concrete/nocex6/main.c @@ -0,0 +1,15 @@ + +#include + +int main(int argc, char** argv) +{ + int y = 1; + + while(y<30){ + y++; + assert(y<5); + } + + return 0; +} + diff --git a/regression/spurious-check-concrete/nocex6/test.desc b/regression/spurious-check-concrete/nocex6/test.desc new file mode 100644 index 000000000..1f240717a --- /dev/null +++ b/regression/spurious-check-concrete/nocex6/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --unwind 2 +^EXIT=5$ +^SIGNAL=0$ +^VERIFICATION INCONCLUSIVE$ diff --git a/regression/spurious-check-concrete/nocex8/main.c b/regression/spurious-check-concrete/nocex8/main.c new file mode 100644 index 000000000..d9ee4be0c --- /dev/null +++ b/regression/spurious-check-concrete/nocex8/main.c @@ -0,0 +1,16 @@ + +#include + +void fail(void) +{ + assert(0); +} + +int main(void) +{ + int tmp = 0; + if(tmp) + fail(); + return 0; +} + diff --git a/regression/spurious-check-concrete/nocex8/test.desc b/regression/spurious-check-concrete/nocex8/test.desc new file mode 100644 index 000000000..dc053e6ab --- /dev/null +++ b/regression/spurious-check-concrete/nocex8/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/spurious-check-concrete/nocex9/main.c b/regression/spurious-check-concrete/nocex9/main.c new file mode 100644 index 000000000..47067bc2f --- /dev/null +++ b/regression/spurious-check-concrete/nocex9/main.c @@ -0,0 +1,11 @@ +#include + +void main() +{ + int x = 0; + int y = 0; + + while(y<10) { x++; } + + assert(x==11); +} diff --git a/regression/spurious-check-concrete/nocex9/test.desc b/regression/spurious-check-concrete/nocex9/test.desc new file mode 100644 index 000000000..329fdf02a --- /dev/null +++ b/regression/spurious-check-concrete/nocex9/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--havoc --no-propagation +^EXIT=5$ +^SIGNAL=0$ +^VERIFICATION INCONCLUSIVE$ diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index b1363d104..046249b2e 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -60,6 +60,8 @@ Author: Daniel Kroening, Peter Schrammel #define IGNORE_THREADS 1 #define EXPLICIT_NONDET_LOCALS 0 #define FILTER_ASSERTIONS 1 +#define ASSUME_AFTER_ASSERT 0 + /*******************************************************************\ @@ -277,10 +279,17 @@ void twols_parse_optionst::get_command_line_options(optionst &options) } // check for spuriousness of assertion failures + /* if(cmdline.isset("no-spurious-check")) options.set_option("spurious-check", false); else options.set_option("spurious-check", true); + */ + + if(cmdline.isset("spurious-check")) + options.set_option("spurious-check", cmdline.get_value("spurious-check")); + else + options.set_option("spurious-check", "all"); // all properties (default) if(cmdline.isset("stop-on-fail")) @@ -840,7 +849,7 @@ void twols_parse_optionst::require_entry( if(goto_model.symbol_table.symbols.find(entry_point)== symbol_table.symbols.end()) - throw "The program has no entry point; please complete linking"; + throw "the program has no entry point; please complete linking"; } /*******************************************************************\ @@ -1094,10 +1103,12 @@ bool twols_parse_optionst::process_goto_program( inline_main(goto_model); } +#ifdef ASSUME_AFTER_ASSERT if(!cmdline.isset("independent-properties")) { add_assumptions_after_assertions(goto_model); } +#endif #ifdef FILTER_ASSERTIONS filter_assertions(goto_model); diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index d564b1279..1a2037028 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -53,6 +53,7 @@ class optionst; "(no-simplify)(no-fixed-point)" \ "(graphml-witness):(json-cex):" \ "(no-spurious-check)(stop-on-fail)" \ + "(spurious-check):" \ "(competition-mode)(slice)(no-propagation)(independent-properties)" \ "(no-unwinding-assertions)" // the last line is for CBMC-regression testing only diff --git a/src/2ls/Makefile b/src/2ls/Makefile index 06b9d4486..b3a785bfd 100644 --- a/src/2ls/Makefile +++ b/src/2ls/Makefile @@ -29,6 +29,7 @@ OBJ+= $(CBMC)/src/ansi-c/ansi-c$(LIBEXT) \ ../domains/domains$(LIBEXT) \ ../ssa/ssa$(LIBEXT) \ ../solver/solver$(LIBEXT) \ + # empty last line CP_CXXFLAGS+= $(TWOLSFLAGS) diff --git a/src/2ls/cover_goals_ext.cpp b/src/2ls/cover_goals_ext.cpp index 60c06909f..fc8c3a234 100644 --- a/src/2ls/cover_goals_ext.cpp +++ b/src/2ls/cover_goals_ext.cpp @@ -174,84 +174,76 @@ Function: cover_goals_extt::assignment void cover_goals_extt::assignment() { - // check loop head choices in model - bool invariants_involved=false; - if(spurious_check) + std::list::const_iterator g_it=goals.begin(); + for(goal_mapt::const_iterator it=goal_map.begin(); + it!=goal_map.end(); it++, g_it++) { - for(exprt::operandst::const_iterator l_it=loophead_selects.begin(); - l_it!=loophead_selects.end(); l_it++) + if(property_map[it->first].result==property_checkert::UNKNOWN && + solver.l_get(g_it->condition).is_true()) { - if(solver.get(l_it->op0()).is_true()) +#if 1 + // otherwise this would interfere with necessary preconditions + solver.pop_context(); + + summarizer_bw_cex.summarize(g_it->cond_expression); + property_map[it->first].result=summarizer_bw_cex.check(); + solver.new_context(); +#else // THE ASSERTIONS THAT FAIL COULD BE RATHER ARBITRARY SINCE THE FORMULA + // IS NOT "ROOTED" IN AN INITIAL STATE. + assert((g_it->cond_expression).id()==ID_not); + exprt conjunct_expr=(g_it->cond_expression).op0(); +#if 0 + std::cout << "FAILED EXPR: " + << from_expr(SSA.ns, "", conjunct_expr) << std::endl; +#endif + + if(conjunct_expr.id()!=ID_and) { - invariants_involved=true; - break; + // otherwise this would interfere with necessary preconditions + solver.pop_context(); + summarizer_bw_cex.summarize(g_it->cond_expression); + property_map[it->first].result=summarizer_bw_cex.check(); + solver.new_context(); } - } - } - if(!invariants_involved || !spurious_check) - { - std::list::const_iterator g_it=goals.begin(); - for(goal_mapt::const_iterator it=goal_map.begin(); - it!=goal_map.end(); it++, g_it++) - { - if(property_map[it->first].result==property_checkert::UNKNOWN && - solver.l_get(g_it->condition).is_true()) + else { - property_map[it->first].result=property_checkert::FAIL; - if(build_error_trace) + // filter out assertion instances that are not violated + exprt::operandst failed_exprs; + for(exprt::operandst::const_iterator c_it= + conjunct_expr.operands().begin(); + c_it!=conjunct_expr.operands().end(); c_it++) { - ssa_build_goto_tracet build_goto_trace(SSA, solver.get_solver()); - build_goto_trace(property_map[it->first].error_trace); - if(!all_properties) - break; + literalt conjunct_literal=solver.convert(*c_it); + if(solver.l_get(conjunct_literal).is_false()) + { + failed_exprs.push_back(*c_it); +#if 0 + std::cout << "failed_expr: " + << from_expr(SSA.ns, "", *c_it) << std::endl; +#endif + } } + // otherwise this would interfere with necessary preconditions + solver.pop_context(); + + summarizer_bw_cex.summarize(not_exprt(conjunction(failed_exprs))); + property_map[it->first].result=summarizer_bw_cex.check(); + solver.new_context(); } +#endif } - return; - } - - solver.new_context(); - // force avoiding paths going through invariants - - solver << conjunction(loophead_selects); - - switch(solver()) - { - case decision_proceduret::D_SATISFIABLE: - { - std::list::const_iterator g_it=goals.begin(); - for(goal_mapt::const_iterator it=goal_map.begin(); - it!=goal_map.end(); it++, g_it++) + if(property_map[it->first].result==property_checkert::FAIL) { - if(property_map[it->first].result==property_checkert::UNKNOWN && - solver.l_get(g_it->condition).is_true()) + if(build_error_trace) { - property_map[it->first].result=property_checkert::FAIL; - if(build_error_trace) - { - ssa_build_goto_tracet build_goto_trace(SSA, solver.get_solver()); - build_goto_trace(property_map[it->first].error_trace); - -#if 0 - show_raw_countermodel( - it->first, SSA, *solver.solver, debug(), get_message_handler()); -#endif - if(!all_properties) - break; - } + ssa_build_goto_tracet build_goto_trace(SSA, solver.get_solver()); + build_goto_trace(property_map[it->first].error_trace); } } - break; - } - case decision_proceduret::D_UNSATISFIABLE: - break; - - case decision_proceduret::D_ERROR: - default: - throw "error from decision procedure"; - } - - solver.pop_context(); + if(!all_properties && + property_map[it->first].result==property_checkert::FAIL) + break; + } _iterations++; // statistics } diff --git a/src/2ls/cover_goals_ext.h b/src/2ls/cover_goals_ext.h index d777a8a66..9a40f4693 100644 --- a/src/2ls/cover_goals_ext.h +++ b/src/2ls/cover_goals_ext.h @@ -12,9 +12,10 @@ Author: Daniel Kroening, kroening@kroening.com #include #include -#include "../ssa/local_ssa.h" -#include "../ssa/unwindable_local_ssa.h" -#include "../domains/incremental_solver.h" +#include +#include +#include +#include /*******************************************************************\ @@ -47,20 +48,19 @@ struct goalt class cover_goals_extt:public messaget { public: - explicit inline cover_goals_extt( + cover_goals_extt( unwindable_local_SSAt &_SSA, incremental_solvert &_solver, - const exprt::operandst& _loophead_selects, property_checkert::property_mapt &_property_map, - bool _spurious_check, bool _all_properties, - bool _build_error_trace): + bool _all_properties, + bool _build_error_trace, + summarizer_bw_cex_baset &_summarizer_bw_cex): SSA(_SSA), solver(_solver), property_map(_property_map), - spurious_check(_spurious_check), all_properties(_all_properties), build_error_trace(_build_error_trace), - loophead_selects(_loophead_selects) + summarizer_bw_cex(_summarizer_bw_cex) { } @@ -74,6 +74,7 @@ class cover_goals_extt:public messaget { literalt condition; bool covered; + exprt cond_expression; cover_goalt():covered(false) { @@ -105,10 +106,11 @@ class cover_goals_extt:public messaget // managing the goals - inline void add(const literalt condition) + inline void add(const exprt cond_expression) { goals.push_back(cover_goalt()); - goals.back().condition=condition; + goals.back().condition=!solver.convert(cond_expression); + goals.back().cond_expression=cond_expression; } protected: @@ -116,8 +118,8 @@ class cover_goals_extt:public messaget unsigned _number_covered, _iterations; incremental_solvert &solver; property_checkert::property_mapt &property_map; - bool spurious_check, all_properties, build_error_trace; - exprt::operandst loophead_selects; + bool all_properties, build_error_trace; + summarizer_bw_cex_baset &summarizer_bw_cex; // this method is called for each satisfying assignment virtual void assignment(); diff --git a/src/2ls/dynamic_cfg.cpp b/src/2ls/dynamic_cfg.cpp index 807ec5ed3..c747a59e2 100644 --- a/src/2ls/dynamic_cfg.cpp +++ b/src/2ls/dynamic_cfg.cpp @@ -284,7 +284,8 @@ void dynamic_cfgt::build_from_invariants( if(summary.fw_invariant.id()==ID_implies) { build_from_invariant( - ssa, summary.fw_invariant, + ssa, + summary.fw_invariant, assumptions); } else if(summary.fw_invariant.id()==ID_and) @@ -293,9 +294,9 @@ void dynamic_cfgt::build_from_invariants( { assert(summary.fw_invariant.operands()[i].id()==ID_implies); build_from_invariant( - ssa, summary.fw_invariant.operands()[i], + ssa, + summary.fw_invariant.operands()[i], assumptions); } } } - diff --git a/src/2ls/graphml_witness_ext.h b/src/2ls/graphml_witness_ext.h index df62a2b6d..0b573dba5 100644 --- a/src/2ls/graphml_witness_ext.h +++ b/src/2ls/graphml_witness_ext.h @@ -27,8 +27,10 @@ class graphml_witness_extt:public graphml_witnesst void operator()(const summary_checker_baset &summary_checker); protected: + typedef std::map loc_to_node_mapt; + graphmlt::node_indext add_node( - std::map &loc_to_node, + loc_to_node_mapt &loc_to_node, goto_programt::const_targett it); void add_edge( diff --git a/src/2ls/instrument_goto.cpp b/src/2ls/instrument_goto.cpp index 3e550c6e1..647aaab10 100644 --- a/src/2ls/instrument_goto.cpp +++ b/src/2ls/instrument_goto.cpp @@ -115,8 +115,7 @@ Function: instrument_gotot::instrument_body void instrument_gotot::instrument_body( const local_SSAt &SSA, const exprt &expr, - goto_functionst::goto_functiont &function -) + goto_functionst::goto_functiont &function) { // expected format (/\_j g_j)=> inv const exprt &impl=expr.op0(); diff --git a/src/2ls/summary_checker_ai.cpp b/src/2ls/summary_checker_ai.cpp index 6cda09787..65259c40c 100644 --- a/src/2ls/summary_checker_ai.cpp +++ b/src/2ls/summary_checker_ai.cpp @@ -77,7 +77,10 @@ property_checkert::resultt summary_checker_ait::operator()( return property_checkert::UNKNOWN; #endif - property_checkert::resultt result=check_properties(); + property_checkert::resultt result= + options.get_bool_option("all-functions")? + check_properties(): + check_properties(goto_model.goto_functions.entry_point()); report_statistics(); return result; } diff --git a/src/2ls/summary_checker_base.cpp b/src/2ls/summary_checker_base.cpp index c910b184c..57f5e8581 100644 --- a/src/2ls/summary_checker_base.cpp +++ b/src/2ls/summary_checker_base.cpp @@ -29,6 +29,12 @@ Author: Peter Schrammel #include #include #include +#include +#include +#include +#include +#include +#include #ifdef SHOW_CALLING_CONTEXTS #include @@ -98,7 +104,7 @@ void summary_checker_baset::summarize( bool forward, bool termination) { - summarizer_baset *summarizer=NULL; + summarizer_baset *summarizer=nullptr; #ifdef SHOW_CALLING_CONTEXTS if(options.get_bool_option("show-calling-contexts")) @@ -120,7 +126,7 @@ void summary_checker_baset::summarize( summarizer=new summarizer_bw_termt( options, summary_db, ssa_db, ssa_unwinder, ssa_inliner); } - assert(summarizer!=NULL); + assert(summarizer!=nullptr); summarizer->set_message_handler(get_message_handler()); @@ -138,11 +144,15 @@ void summary_checker_baset::summarize( delete summarizer; } + /*******************************************************************\ Function: summary_checker_baset::check_properties - Inputs: + Inputs: function_name!=nil + checks all functions in the call graph from the entry point + else + checks all functions Outputs: @@ -152,36 +162,104 @@ Function: summary_checker_baset::check_properties summary_checker_baset::resultt summary_checker_baset::check_properties() { - // analyze all the functions - for(ssa_dbt::functionst::const_iterator f_it=ssa_db.functions().begin(); - f_it!=ssa_db.functions().end(); f_it++) + std::set seen_function_calls; + return check_properties("", "", seen_function_calls, false); +} + +summary_checker_baset::resultt summary_checker_baset::check_properties(irep_idt entry_function) +{ + std::set seen_function_calls; + return check_properties(entry_function, entry_function, seen_function_calls, false); +} + +summary_checker_baset::resultt summary_checker_baset::check_properties( + irep_idt function_name, + irep_idt entry_function, + std::set seen_function_calls, + bool is_inlined) +{ + if(function_name!="") { - status() << "Checking properties of " << f_it->first << messaget::eom; + ssa_dbt::functionst::const_iterator f_it= + ssa_db.functions().find(function_name); + assert(f_it!=ssa_db.functions().end()); + local_SSAt &SSA=*f_it->second; + // call recursively for all function calls first + for(local_SSAt::nodest::const_iterator n_it=SSA.nodes.begin(); + n_it!=SSA.nodes.end(); ++n_it) + { + for(local_SSAt::nodet::function_callst::const_iterator ff_it= + n_it->function_calls.begin(); + ff_it!=n_it->function_calls.end(); ff_it++) + { + assert(ff_it->function().id()==ID_symbol); // no function pointers + irep_idt fname=to_symbol_expr(ff_it->function()).get_identifier(); + + // ENHANCE?: can the return value be exploited? + if(ssa_db.functions().find(fname)!=ssa_db.functions().end() && + (!summary_db.exists(fname) || + summary_db.get(fname).bw_transformer.is_nil())) + { #if 0 - // for debugging - show_ssa_symbols(*f_it->second, std::cerr); + debug() << "Checking call " << fname << messaget::eom; #endif + if(seen_function_calls.find(fname)==seen_function_calls.end()) + { + seen_function_calls.insert(fname); + check_properties( + fname, + entry_function, + seen_function_calls, + n_it->function_calls_inlined); + } + } + } + } - check_properties(f_it); - - if(options.get_bool_option("show-invariants")) + if(!is_inlined) { - if(!summary_db.exists(f_it->first)) - continue; - show_invariants(*(f_it->second), summary_db.get(f_it->first), result()); - result() << eom; + // now check function itself + status() << "Checking properties of " << f_it->first << messaget::eom; + check_properties(f_it, entry_function); + } + } + else // check all the functions + { + for(ssa_dbt::functionst::const_iterator f_it=ssa_db.functions().begin(); + f_it!=ssa_db.functions().end(); f_it++) + { + status() << "Checking properties of " << f_it->first << messaget::eom; + +#if 0 + // for debugging + show_ssa_symbols(*f_it->second, std::cerr); +#endif + + check_properties(f_it, f_it->first); + + if(options.get_bool_option("show-invariants")) + { + if(!summary_db.exists(f_it->first)) + continue; + show_invariants(*(f_it->second), summary_db.get(f_it->first), result()); + result() << eom; + } } } summary_checker_baset::resultt result=property_checkert::PASS; - for(property_mapt::const_iterator - p_it=property_map.begin(); p_it!=property_map.end(); p_it++) + if(function_name=="" || function_name==entry_function) { - if(p_it->second.result==FAIL) - return property_checkert::FAIL; - if(p_it->second.result==UNKNOWN) - result=property_checkert::UNKNOWN; + // determine overall status + for(property_mapt::const_iterator + p_it=property_map.begin(); p_it!=property_map.end(); p_it++) + { + if(p_it->second.result==FAIL) + return property_checkert::FAIL; + if(p_it->second.result==UNKNOWN) + result=property_checkert::UNKNOWN; + } } return result; @@ -200,11 +278,20 @@ Function: summary_checker_baset::check_properties \*******************************************************************/ void summary_checker_baset::check_properties( - const ssa_dbt::functionst::const_iterator f_it) + const ssa_dbt::functionst::const_iterator f_it, + irep_idt entry_function) { unwindable_local_SSAt &SSA=*f_it->second; + // check whether function has assertions + if(!has_assertion(f_it->first)) + return; + bool all_properties=options.get_bool_option("all-properties"); + bool build_error_trace= + options.get_bool_option("show-trace") || + options.get_option("graphml-witness")!="" || + options.get_option("json-cex")!=""; SSA.output_verbose(debug()); debug() << eom; @@ -226,31 +313,96 @@ void summary_checker_baset::check_properties( // invariant, calling contexts if(summary_db.exists(f_it->first)) { - solver << summary_db.get(f_it->first).fw_invariant; - solver << summary_db.get(f_it->first).fw_precondition; + if(!summary_db.get(f_it->first).fw_invariant.is_nil()) + solver << summary_db.get(f_it->first).fw_invariant; + if(!summary_db.get(f_it->first).fw_precondition.is_nil()) + solver << summary_db.get(f_it->first).fw_precondition; } // callee summaries solver << ssa_inliner.get_summaries(SSA); - // freeze loop head selects - exprt::operandst loophead_selects= - get_loophead_selects(f_it->first, SSA, *solver.solver); - // check whether loops have been fully unwound - exprt::operandst loop_continues= - get_loop_continues(f_it->first, SSA, *solver.solver); - bool fully_unwound= - is_fully_unwound(loop_continues, loophead_selects, solver); - status() << "Loops " << (fully_unwound ? "" : "not ") - << "fully unwound" << eom; + // spuriousness checkers + summarizer_bw_cex_baset *summarizer_bw_cex=nullptr; + incremental_solvert *cex_complete_solver= + incremental_solvert::allocate( + SSA.ns, + options.get_bool_option("refine")); +#if 1 + cex_complete_solver->set_message_handler(get_message_handler()); +#endif + if(options.get_option("spurious-check")=="abstract") + { + summarizer_bw_cex=new summarizer_bw_cex_ait( + options, + summary_db, + ssa_db, + ssa_unwinder, + ssa_inliner, + entry_function, + f_it->first); + } + else if(options.get_option("spurious-check")=="complete") + { + summarizer_bw_cex=new summarizer_bw_cex_completet( + options, + summary_db, + ssa_db, + ssa_unwinder, + ssa_inliner, + *cex_complete_solver, + entry_function, + f_it->first); + } + else if(options.get_option("spurious-check")=="wp") + { + summarizer_bw_cex=new summarizer_bw_cex_wpt( + options, + summary_db, + ssa_db, + ssa_unwinder, + ssa_inliner, + *cex_complete_solver, + entry_function, + f_it->first); + } + else if(options.get_option("spurious-check")=="all") + { + summarizer_bw_cex=new summarizer_bw_cex_allt( + options, + summary_db, + ssa_db, + ssa_unwinder, + ssa_inliner, + *cex_complete_solver, + entry_function, + f_it->first); + } + else //NOLINT(*) +#if 0 + if(options.get_bool_option("inline") || + options.get_option("spurious-check")=="concrete") +#endif + { + summarizer_bw_cex=new summarizer_bw_cex_concretet( + options, + summary_db, + ssa_db, + ssa_unwinder, + ssa_inliner, + entry_function, + f_it->first); + } + assert(summarizer_bw_cex!=nullptr); + summarizer_bw_cex->set_message_handler(get_message_handler()); cover_goals_extt cover_goals( - SSA, solver, loophead_selects, property_map, - !fully_unwound && options.get_bool_option("spurious-check"), + SSA, + solver, + property_map, all_properties, - options.get_bool_option("show-trace") || - options.get_option("graphml-witness")!="" || - options.get_option("json-cex")!=""); + build_error_trace, + *summarizer_bw_cex); #if 0 debug() << "(C) " << from_expr(SSA.ns, "", enabling_expr) << eom; @@ -320,8 +472,7 @@ void summary_checker_baset::check_properties( { // Our goal is to falsify a property. // The following is TRUE if the conjunction is empty. - literalt p=!solver.convert(conjunction(it->second.conjuncts)); - cover_goals.add(p); + cover_goals.add(conjunction(it->second.conjuncts)); } status() << "Running " << solver.solver->decision_procedure_text() << eom; @@ -422,206 +573,77 @@ void summary_checker_baset::do_show_vcc( /*******************************************************************\ -Function: summary_checker_baset::get_loophead_selects +Function: summary_checker_baset::instrument_and_output Inputs: Outputs: - Purpose: returns the select guards at the loop heads - in order to check whether a countermodel is spurious + Purpose: instruments the code with the inferred information + and outputs it to a goto-binary \*******************************************************************/ -exprt::operandst summary_checker_baset::get_loophead_selects( - const irep_idt &function_name, - const local_SSAt &SSA, prop_convt &solver) +void summary_checker_baset::instrument_and_output(goto_modelt &goto_model) { - // TODO: this should be provided by unwindable_local_SSA - exprt::operandst loophead_selects; - for(local_SSAt::nodest::const_iterator n_it=SSA.nodes.begin(); - n_it!=SSA.nodes.end(); n_it++) - { - if(n_it->loophead==SSA.nodes.end()) - continue; - symbol_exprt lsguard= - SSA.name(SSA.guard_symbol(), local_SSAt::LOOP_SELECT, n_it->location); - ssa_unwinder.get(function_name).unwinder_rename(lsguard, *n_it, true); - loophead_selects.push_back(not_exprt(lsguard)); - solver.set_frozen(solver.convert(lsguard)); - } - literalt loophead_selects_literal= - solver.convert(conjunction(loophead_selects)); - if(!loophead_selects_literal.is_constant()) - solver.set_frozen(loophead_selects_literal); - -#if 0 - std::cout << "loophead_selects: " - << from_expr(SSA.ns, "", conjunction(loophead_selects)) - << std::endl; -#endif - - return loophead_selects; + instrument_gotot instrument_goto(options, ssa_db, summary_db); + instrument_goto(goto_model); + std::string filename=options.get_option("instrument-output"); + status() << "Writing instrumented goto-binary " << filename << eom; + write_goto_binary( + filename, + goto_model.symbol_table, + goto_model.goto_functions, + get_message_handler()); } -/*******************************************************************\ - -Function: summary_checker_baset::get_loop_continues - - Inputs: - - Outputs: - - Purpose: returns the loop continuation guards at the end of the - loops in order to check whether we can unroll further - -\*******************************************************************/ - -exprt::operandst summary_checker_baset::get_loop_continues( - const irep_idt &function_name, - const local_SSAt &SSA, prop_convt &solver) -{ - // TODO: this should be provided by unwindable_local_SSA - exprt::operandst loop_continues; - - ssa_unwinder.get(function_name).loop_continuation_conditions(loop_continues); - if(loop_continues.size()==0) - { - // TODO: this should actually be done transparently by the unwinder - for(local_SSAt::nodest::const_iterator n_it=SSA.nodes.begin(); - n_it!=SSA.nodes.end(); n_it++) - { - if(n_it->loophead==SSA.nodes.end()) - continue; - symbol_exprt guard=SSA.guard_symbol(n_it->location); - symbol_exprt cond=SSA.cond_symbol(n_it->location); - loop_continues.push_back(and_exprt(guard, cond)); - } - } - -#if 0 - std::cout << "loophead_continues: " - << from_expr(SSA.ns, "", disjunction(loop_continues)) << std::endl; -#endif - - return loop_continues; -} /*******************************************************************\ -Function: summary_checker_baset::is_fully_unwound +Function: summary_checker_baset::has_assertion Inputs: Outputs: - Purpose: checks whether the loops have been fully unwound + Purpose: searches recursively for assertions in inlined functions \*******************************************************************/ -bool summary_checker_baset::is_fully_unwound( - const exprt::operandst &loop_continues, - const exprt::operandst &loophead_selects, - incremental_solvert &solver) +bool summary_checker_baset::has_assertion(irep_idt function_name) { - solver.new_context(); - solver << - and_exprt(conjunction(loophead_selects), disjunction(loop_continues)); - - solver_calls++; // statistics - - switch(solver()) - { - case decision_proceduret::D_SATISFIABLE: - solver.pop_context(); - return false; - break; - - case decision_proceduret::D_UNSATISFIABLE: - solver.pop_context(); - solver << conjunction(loophead_selects); - return true; - break; - - case decision_proceduret::D_ERROR: - default: - throw "error from decision procedure"; - } -} - -/*******************************************************************\ + // SSA.goto_function.body.has_assertion() has become too semantic + bool _has_assertion=false; + const local_SSAt &SSA=ssa_db.get(function_name); -Function: summary_checker_baset::is_spurious - - Inputs: - - Outputs: - - Purpose: checks whether a countermodel is spurious - -\*******************************************************************/ - -bool summary_checker_baset::is_spurious( - const exprt::operandst &loophead_selects, - incremental_solvert &solver) -{ - // check loop head choices in model - bool invariants_involved=false; - for(exprt::operandst::const_iterator l_it=loophead_selects.begin(); - l_it!=loophead_selects.end(); l_it++) + for(local_SSAt::nodest::const_iterator + n_it=SSA.nodes.begin(); n_it!=SSA.nodes.end(); ++n_it) { - if(solver.get(l_it->op0()).is_true()) + for(local_SSAt::nodet::assertionst::const_iterator + a_it=n_it->assertions.begin(); a_it!=n_it->assertions.end(); ++a_it) { - invariants_involved=true; - break; - } - } - if(!invariants_involved) - return false; - - // force avoiding paths going through invariants - solver << conjunction(loophead_selects); + irep_idt property_id=n_it->location->source_location.get_property_id(); - solver_calls++; // statistics - - switch(solver()) - { - case decision_proceduret::D_SATISFIABLE: - return false; - break; + if(n_it->location->guard.is_true()) + property_map[property_id].result=PASS; + else + _has_assertion=true; + } + if(!n_it->function_calls_inlined) + continue; - case decision_proceduret::D_UNSATISFIABLE: - return true; - break; + for(local_SSAt::nodet::function_callst::const_iterator + f_it=n_it->function_calls.begin(); + f_it!=n_it->function_calls.end(); ++f_it) + { + irep_idt fname=to_symbol_expr(f_it->function()).get_identifier(); + if(ssa_db.functions().find(fname)==ssa_db.functions().end()) + continue; - case decision_proceduret::D_ERROR: - default: - throw "error from decision procedure"; + bool new_has_assertion=has_assertion(fname); // recurse + _has_assertion=_has_assertion || new_has_assertion; + } } -} -/*******************************************************************\ - -Function: summary_checker_baset::instrument_and_output - - Inputs: - - Outputs: - - Purpose: instruments the code with the inferred information - and outputs it to a goto-binary - -\*******************************************************************/ - -void summary_checker_baset::instrument_and_output(goto_modelt &goto_model) -{ - instrument_gotot instrument_goto(options, ssa_db, summary_db); - instrument_goto(goto_model); - std::string filename=options.get_option("instrument-output"); - status() << "Writing instrumented goto-binary " << filename << eom; - write_goto_binary( - filename, - goto_model.symbol_table, - goto_model.goto_functions, - get_message_handler()); + return _has_assertion; } diff --git a/src/2ls/summary_checker_base.h b/src/2ls/summary_checker_base.h index d4b1ad0e5..c758f4ed9 100644 --- a/src/2ls/summary_checker_base.h +++ b/src/2ls/summary_checker_base.h @@ -34,7 +34,7 @@ class summary_checker_baset:public property_checkert options(_options), ssa_db(_options), summary_db(), ssa_unwinder(ssa_db), - ssa_inliner(summary_db), + ssa_inliner(summary_db, ssa_db), solver_instances(0), solver_calls(0), summaries_used(0), @@ -81,20 +81,17 @@ class summary_checker_baset:public property_checkert bool termination=false); property_checkert::resultt check_properties(); + property_checkert::resultt check_properties(irep_idt entry_function); + property_checkert::resultt check_properties( + irep_idt function_name, + irep_idt entry_function, + std::set seen_function_calls, + bool is_inlined); void check_properties( - const ssa_dbt::functionst::const_iterator f_it); - - exprt::operandst get_loophead_selects( - const irep_idt &function_name, const local_SSAt &, prop_convt &); - bool is_spurious( - const exprt::operandst& loophead_selects, - incremental_solvert&); - exprt::operandst get_loop_continues( - const irep_idt &function_name, const local_SSAt &, prop_convt &); - bool is_fully_unwound( - const exprt::operandst& loop_continues, - const exprt::operandst& loophead_selects, - incremental_solvert&); + const ssa_dbt::functionst::const_iterator f_it, + irep_idt entry_function=""); + + bool has_assertion(irep_idt function_name); friend graphml_witness_extt; }; diff --git a/src/domains/Makefile b/src/domains/Makefile index 82b6a23b8..86018b186 100644 --- a/src/domains/Makefile +++ b/src/domains/Makefile @@ -7,7 +7,8 @@ SRC = tpolyhedra_domain.cpp equality_domain.cpp domain.cpp predabs_domain.cpp\ template_generator_base.cpp template_generator_summary.cpp \ template_generator_callingcontext.cpp template_generator_ranking.cpp \ strategy_solver_binsearch2.cpp strategy_solver_binsearch3.cpp \ - strategy_solver_predabs.cpp + strategy_solver_predabs.cpp disjunctive_analyzer.cpp \ + simplify_transformer.cpp simplify_bounds.cpp #solver_enumeration.cpp include ../config.inc diff --git a/src/domains/disjunctive_analyzer.cpp b/src/domains/disjunctive_analyzer.cpp new file mode 100644 index 000000000..28d506624 --- /dev/null +++ b/src/domains/disjunctive_analyzer.cpp @@ -0,0 +1,315 @@ +/*******************************************************************\ + +Module: Data Flow Analysis + +Author: Peter Schrammel, Kumar Madhukar + +\*******************************************************************/ + +#include +#include + +#include "ssa_analyzer.h" +#include "disjunctive_analyzer.h" + +/*******************************************************************\ + +Function: disjunctive_analyzert::eliminate_implication() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void disjunctive_analyzert::eliminate_implication(exprt &formula) +{ + if(formula.id()==ID_implies) + formula=or_exprt(not_exprt(formula.op0()), formula.op1()); + + Forall_operands(it, formula) + eliminate_implication(*it); +} + +/*******************************************************************\ + +Function: disjunctive_analyzert::push_negation_to_atoms() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void disjunctive_analyzert::push_negation_to_atoms(exprt &formula) +{ + if(formula.id()==ID_not) + { + if((formula.op0()).id()==ID_not) + { + formula=(formula.op0()).op0(); + } + else + { + exprt::operandst operands; + Forall_operands(it, formula.op0()) + operands.push_back(not_exprt(*it)); + + if((formula.op0()).id()==ID_and) + { + formula=disjunction(operands); + } + else + { + if((formula.op0()).id()==ID_or) + { + formula=conjunction(operands); + } + } + } + } + + Forall_operands(it, formula) + push_negation_to_atoms(*it); +} + +/*******************************************************************\ + +Function: disjunctive_analyzert::convert_to_dnf() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void disjunctive_analyzert::convert_to_dnf(exprt &formula) +{ + eliminate_implication(formula); + push_negation_to_atoms(formula); + convert_to_dnf_rec(formula); +} + +/*******************************************************************\ + +Function: disjunctive_analyzert::convert_to_dnf_rec() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void disjunctive_analyzert::convert_to_dnf_rec(exprt &formula) +{ + if(formula.id()==ID_or) + { + Forall_operands(it, formula) + convert_to_dnf_rec(*it); + } + else + { + if(formula.id()==ID_and) + { + Forall_operands(it, formula) + convert_to_dnf_rec(*it); + + while((formula.operands()).size()>1) + { + exprt::operandst first_operands, second_operands, combination; + + if(((formula.operands()).back()).id()==ID_or) + first_operands=((formula.operands()).back()).operands(); + else + first_operands.push_back((formula.operands()).back()); + formula.operands().pop_back(); + + if(((formula.operands()).back()).id()==ID_or) + second_operands=((formula.operands()).back()).operands(); + else + second_operands.push_back((formula.operands()).back()); + formula.operands().pop_back(); + + for(const auto &fo : first_operands) + { + for(const auto &so : second_operands) + { + combination.push_back(and_exprt(fo, so)); + } + } + + formula.operands().push_back(disjunction(combination)); + } + formula=formula.op0(); + } + } +} + +/*******************************************************************\ + +Function: disjunctive_analyzert::operator() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool disjunctive_analyzert::operator()( + incremental_solvert &solver, + local_SSAt &SSA, + const exprt &side_conditions, + template_generator_baset &template_generator, + const exprt &disjunctive_conditions, + exprt &result_expr, + const domaint::var_sett &vars) +{ + bool response=true; + exprt::operandst result; + + exprt simple_disjunctive_conditions= + simplify_expr(disjunctive_conditions, SSA.ns); // disjunctive_conditions + + // converting simple_disjunctive_conditions into DNF + convert_to_dnf(simple_disjunctive_conditions); + + if(simple_disjunctive_conditions.id()==ID_or) + { + exprt::operandst processed_disjuncts; + + exprt::operandst disjuncts=simple_disjunctive_conditions.operands(); + for(auto &d : disjuncts) + { + if(d.id()==ID_not) + { + exprt::operandst ops=d.operands(); + for(auto &op : ops) + { + if(op.id()==ID_equal) + { + exprt::operandst ops_equality=op.operands(); + equal_exprt equal_expr_in_not=to_equal_expr(op); + + bool constant_comparison=false; + for(auto &oe : ops_equality) + { + if(oe.id()==ID_constant) + constant_comparison=true; + } + if(constant_comparison) + { + processed_disjuncts.push_back( + binary_relation_exprt( + equal_expr_in_not.rhs(), ID_gt, equal_expr_in_not.lhs())); + processed_disjuncts.push_back( + binary_relation_exprt( + equal_expr_in_not.rhs(), ID_lt, equal_expr_in_not.lhs())); + } + else + { + processed_disjuncts.push_back(d); + } + } + else + { + processed_disjuncts.push_back(d); + } + } + } + else + { + processed_disjuncts.push_back(d); + } + } + + for(auto &d : processed_disjuncts) + { + std::set disjunct_symbols; + find_symbols(d, disjunct_symbols); + + // TODO: decompose into convex regions for all variables + // assert(disjunct_symbols.size()==1); + + // TODO: unclear what this loop should be doing + symbol_exprt var; + for(const auto &ds : disjunct_symbols) + { + var=ds; + } + + exprt::operandst split_disjuncts; + + if((var.type().id()==ID_signedbv) || (var.type().id()==ID_unsignedbv)) + { + exprt smallest; + if(var.type().id()==ID_signedbv) + smallest=to_signedbv_type(var.type()).smallest_expr(); + if(var.type().id()==ID_unsignedbv) + smallest=to_unsignedbv_type(var.type()).smallest_expr(); + + split_disjuncts.push_back( + and_exprt( + d, + binary_relation_exprt( + var, + ID_ge, + plus_exprt(smallest, from_integer(mp_integer(1), var.type()))))); + + split_disjuncts.push_back( + and_exprt(d, binary_relation_exprt(var, ID_equal, smallest))); + } + else + { + split_disjuncts.push_back(d); + } + + for(auto &sd : split_disjuncts) + { + ssa_analyzert analyzer; + analyzer.set_message_handler(get_message_handler()); + exprt cc=simplify_expr((and_exprt(side_conditions, sd)), SSA.ns); + response=response && (analyzer(solver, SSA, cc, template_generator)); + + exprt res; + analyzer.get_result(res, vars); + result.push_back(res); + + // statistics + solver_instances+=analyzer.get_number_of_solver_instances(); + solver_calls+=analyzer.get_number_of_solver_calls(); + } + } + } + else + { + // for the complete disjunctive_conditions at once + ssa_analyzert analyzer; + analyzer.set_message_handler(get_message_handler()); + exprt cc=simplify_expr( + and_exprt(side_conditions, simple_disjunctive_conditions), SSA.ns); + + response=analyzer(solver, SSA, cc, template_generator); + + exprt res; + analyzer.get_result(res, vars); + result.push_back(res); + + // statistics + solver_instances+=analyzer.get_number_of_solver_instances(); + solver_calls+=analyzer.get_number_of_solver_calls(); + } + + result_expr=disjunction(result); + return response; +} + diff --git a/src/domains/disjunctive_analyzer.h b/src/domains/disjunctive_analyzer.h new file mode 100644 index 000000000..1b021bbb3 --- /dev/null +++ b/src/domains/disjunctive_analyzer.h @@ -0,0 +1,50 @@ +/*******************************************************************\ + +Module: Data Flow Analysis + +Author: Peter Schrammel, Kumar Madhukar + +\*******************************************************************/ + +#ifndef CPROVER_2LS_DOMAINS_DISJUNCTIVE_ANALYZER_H +#define CPROVER_2LS_DOMAINS_DISJUNCTIVE_ANALYZER_H + +class disjunctive_analyzert:public messaget +{ + public: + disjunctive_analyzert(): + solver_instances(0), + solver_calls(0) + { + } + + ~disjunctive_analyzert() + { + } + + void eliminate_implication(exprt &formula); + void push_negation_to_atoms(exprt &formula); + void convert_to_dnf(exprt &formula); + void convert_to_dnf_rec(exprt &formula); + + bool operator()( + incremental_solvert &solver, + local_SSAt &SSA, + const exprt &side_conditions, + template_generator_baset &template_generator, + const exprt &disjunctive_conditions, + exprt &result_expr, + const domaint::var_sett &vars); + + unsigned get_number_of_solver_instances() { return solver_instances; } + unsigned get_number_of_solver_calls() { return solver_calls; } + +protected: + // statistics + unsigned solver_instances; + unsigned solver_calls; +}; + + +#endif + diff --git a/src/domains/domain.h b/src/domains/domain.h index cdc10fa83..59487f28a 100644 --- a/src/domains/domain.h +++ b/src/domains/domain.h @@ -109,6 +109,8 @@ class domaint result=true_exprt(); } + virtual bool is_spec_empty() const { assert(false); } + static kindt merge_kinds(kindt k1, kindt k2); static void output_var_specs( diff --git a/src/domains/domain_refinement.h b/src/domains/domain_refinement.h new file mode 100644 index 000000000..7cd6155ae --- /dev/null +++ b/src/domains/domain_refinement.h @@ -0,0 +1,39 @@ +/*******************************************************************\ + +Module: Domain Refinement Interface + +Author: Peter Schrammel + +\*******************************************************************/ + +#ifndef CPROVER_2LS_DOMAINS_DOMAIN_REFINEMENT_H +#define CPROVER_2LS_DOMAINS_DOMAIN_REFINEMENT_H + +#include "incremental_solver.h" +#include "template_generator_base.h" +#include + +class domain_refinementt +{ +public: + explicit domain_refinementt( + const local_SSAt &_SSA, + incremental_solvert &_solver) + : + SSA(_SSA), + solver(_solver) + {} + + // refine, returns true if there are no more refinements + virtual bool operator()() { return true; } + + // template generators associated with this SSA and solver + typedef std::map template_generatorst; + template_generatorst template_generators; + +protected: + const local_SSAt &SSA; + incremental_solvert &solver; +}; + +#endif // CPROVER_2LS_DOMAINS_DOMAIN_REFINEMENT_H diff --git a/src/domains/domain_refinement_variables.cpp b/src/domains/domain_refinement_variables.cpp new file mode 100644 index 000000000..cb906d8d1 --- /dev/null +++ b/src/domains/domain_refinement_variables.cpp @@ -0,0 +1,20 @@ +/*******************************************************************\ + +Module: Domain Refinement: Choice of Variables + +Author: Peter Schrammel + +\*******************************************************************/ + +bool domain_refinementt::operator()() +{ + // TODO: analyze counterexample + for(template_generatorst::iterator it=template_generators.begin(); + it!=template_generators.end(); ++it) + { + // TODO: select refinement to be performed + + // TODO: update template and domain + // it->add_template(); + } +} diff --git a/src/domains/incremental_solver.cpp b/src/domains/incremental_solver.cpp index f25f23cdf..750073850 100644 --- a/src/domains/incremental_solver.cpp +++ b/src/domains/incremental_solver.cpp @@ -150,14 +150,23 @@ Function: incremental_solvert::debug_add_to_formula \*******************************************************************/ -void incremental_solvert::debug_add_to_formula(const exprt &expr) +void incremental_solvert::debug_add_to_formula( + const exprt &_expr, exprt activation) { + if(_expr.id()!=ID_and) + { #ifdef NON_INCREMENTAL - // no debug mode for non-incremental yet + // no debug mode for non-incremental yet + assert(0); #else - literalt l=solver->convert(expr); - if(l.is_false()) - { + exprt expr; + if(activation.is_nil()) + expr=_expr; + else + expr=or_exprt(_expr, activation); + literalt l=solver->convert(expr); + if(l.is_false()) + { #ifdef DEBUG_OUTPUT debug() << "literal " << l << ": false=" << from_expr(ns, "", expr) < #include #include +#include #include "domain.h" #include "util.h" -// #define DISPLAY_FORMULA // #define NO_ARITH_REFINEMENT // #define NON_INCREMENTAL // (experimental) @@ -94,8 +94,38 @@ class incremental_solvert:public messaget solver->set_assumptions(whole_formula); #endif #endif - +#if defined(DEBUG_FORMULA) || defined(DISPLAY_FORMULA) + decision_proceduret::resultt result=(*solver)(); +#endif +#if defined(DEBUG_FORMULA) && defined(DEBUG_OUTPUT) + if(result==decision_proceduret::D_UNSATISFIABLE) + { + for(unsigned i=0; iis_in_conflict(formula[i])) + std::cout << "is_in_conflict: " + << from_expr(ns, "", formula_expr[i]) << std::endl; + } + } +#endif +#if (defined(DEBUG_FORMULA) && defined(DEBUG_OUTPUT)) || defined(DISPLAY_FORMULA) // NOLINT(whitespace/line_length) + if(result==decision_proceduret::D_SATISFIABLE) + { + std::set vars; + for(unsigned i=0; i::const_iterator it=vars.begin(); + it!=vars.end(); ++it) + { + std::cout << "assignment: " << from_expr(ns, "", *it) << "=" + << from_expr(ns, "", solver->get(*it)) << std::endl; + } + } + return result; +#endif +#if !defined(DEBUG_FORMULA) && !defined(DISPLAY_FORMULA) return (*solver)(); +#endif } exprt get(const exprt& expr) { return solver->get(expr); } @@ -125,7 +155,8 @@ class incremental_solvert:public messaget // for debugging bvt formula; - void debug_add_to_formula(const exprt &expr); + exprt::operandst formula_expr; + void debug_add_to_formula(const exprt &expr, exprt activation=nil_exprt()); // context assumption literals bvt activation_literals; @@ -190,6 +221,7 @@ static inline incremental_solvert &operator<<( else std::cerr << "add_to_solver: " << from_expr(dest.ns, "", src) << std::endl; + dest.formula_expr.push_back(src); #endif #ifdef NON_INCREMENTAL @@ -204,7 +236,9 @@ static inline incremental_solvert &operator<<( #else if(!dest.activation_literals.empty()) dest.debug_add_to_formula( - or_exprt(src, literal_exprt(!dest.activation_literals.back()))); + or_exprt( + src, + literal_exprt(!dest.activation_literals.back()))); else dest.debug_add_to_formula(src); #endif diff --git a/src/domains/lexlinrank_solver_enumeration.cpp b/src/domains/lexlinrank_solver_enumeration.cpp index bd87b6af5..68633968f 100644 --- a/src/domains/lexlinrank_solver_enumeration.cpp +++ b/src/domains/lexlinrank_solver_enumeration.cpp @@ -1,6 +1,6 @@ /*******************************************************************\ -Module: Enumeration-based solver for lexicographic linear ranking +Module: Enumeration-based solver for lexicographic linear ranking functions Author: Peter Schrammel @@ -32,12 +32,13 @@ Function: lexlinrank_solver_enumerationt::iterate \*******************************************************************/ -bool lexlinrank_solver_enumerationt::iterate(invariantt &_rank) +lexlinrank_solver_enumerationt::progresst +lexlinrank_solver_enumerationt::iterate(invariantt &_rank) { lexlinrank_domaint::templ_valuet &rank= static_cast(_rank); - bool improved=false; + progresst progress=CONVERGED; static std::vector number_elements_per_row; number_elements_per_row.resize(rank.size()); @@ -45,7 +46,6 @@ bool lexlinrank_solver_enumerationt::iterate(invariantt &_rank) solver.new_context(); - // choose round to even rounding mode for template computations // not clear what its implications on soundness and // termination of the synthesis are @@ -190,7 +190,7 @@ bool lexlinrank_solver_enumerationt::iterate(invariantt &_rank) } } - improved=true; + progress=CHANGED; // update the current template lexlinrank_domain.set_row_value(row, new_row_values, rank); @@ -221,7 +221,7 @@ bool lexlinrank_solver_enumerationt::iterate(invariantt &_rank) if(lexlinrank_domain.refine()) { debug() << "refining..." << eom; - improved=true; // refinement possible + progress=CHANGED; // refinement possible if(!refinement_constraint.is_true()) inner_solver->pop_context(); @@ -254,7 +254,7 @@ bool lexlinrank_solver_enumerationt::iterate(invariantt &_rank) debug() << "Inner solver: " << "the number of inner iterations for row " << row << " was reset to " << number_inner_iterations << eom; - improved=true; + progress=CHANGED; } } } @@ -278,5 +278,5 @@ bool lexlinrank_solver_enumerationt::iterate(invariantt &_rank) } solver.pop_context(); - return improved; + return progress; } diff --git a/src/domains/lexlinrank_solver_enumeration.h b/src/domains/lexlinrank_solver_enumeration.h index b31e87382..257be310f 100644 --- a/src/domains/lexlinrank_solver_enumeration.h +++ b/src/domains/lexlinrank_solver_enumeration.h @@ -1,6 +1,6 @@ /*******************************************************************\ -Module: Enumeration-based solver for lexicographic linear ranking +Module: Enumeration-based solver for lexicographic linear ranking functions Author: Peter Schrammel @@ -26,7 +26,7 @@ class lexlinrank_solver_enumerationt:public strategy_solver_baset const namespacet &_ns, unsigned _max_elements, // lexicographic components unsigned _max_inner_iterations): - strategy_solver_baset(_solver, _ns), + strategy_solver_baset(_solver, const_literal(true), _ns), lexlinrank_domain(_lexlinrank_domain), max_elements(_max_elements), max_inner_iterations(_max_inner_iterations), @@ -36,7 +36,7 @@ class lexlinrank_solver_enumerationt:public strategy_solver_baset solver_instances++; } - virtual bool iterate(invariantt &inv); + virtual progresst iterate(invariantt &inv); protected: lexlinrank_domaint &lexlinrank_domain; diff --git a/src/domains/predabs_domain.h b/src/domains/predabs_domain.h index b63e8520c..cb3095e85 100644 --- a/src/domains/predabs_domain.h +++ b/src/domains/predabs_domain.h @@ -73,8 +73,8 @@ class predabs_domaint:public domaint // printing virtual void output_value( std::ostream &out, - const valuet &value, const - namespacet &ns) const; + const valuet &value, + const namespacet &ns) const; virtual void output_domain(std::ostream &out, const namespacet &ns) const; // projection diff --git a/src/domains/ranking_solver_enumeration.cpp b/src/domains/ranking_solver_enumeration.cpp index 9d196369b..bd04196d9 100644 --- a/src/domains/ranking_solver_enumeration.cpp +++ b/src/domains/ranking_solver_enumeration.cpp @@ -28,12 +28,13 @@ Function: ranking_solver_enumerationt::iterate \*******************************************************************/ -bool ranking_solver_enumerationt::iterate(invariantt &_rank) +ranking_solver_enumerationt::progresst +ranking_solver_enumerationt::iterate(invariantt &_rank) { linrank_domaint::templ_valuet &rank= static_cast(_rank); - bool improved=false; + progresst progress=CONVERGED; // context for "outer" solver solver.new_context(); @@ -142,7 +143,7 @@ bool ranking_solver_enumerationt::iterate(invariantt &_rank) // update the current template linrank_domain.set_row_value(row, new_row_values, rank); - improved=true; + progress=CHANGED; } else { @@ -151,7 +152,7 @@ bool ranking_solver_enumerationt::iterate(invariantt &_rank) if(linrank_domain.refine()) { debug() << "refining..." << eom; - improved=true; // refinement possible + progress=CHANGED; // refinement possible } else { @@ -174,5 +175,5 @@ bool ranking_solver_enumerationt::iterate(invariantt &_rank) solver.pop_context(); - return improved; + return progress; } diff --git a/src/domains/ranking_solver_enumeration.h b/src/domains/ranking_solver_enumeration.h index f51928b7c..b6e810b35 100644 --- a/src/domains/ranking_solver_enumeration.h +++ b/src/domains/ranking_solver_enumeration.h @@ -24,7 +24,7 @@ class ranking_solver_enumerationt:public strategy_solver_baset incremental_solvert &_solver, const namespacet &_ns, unsigned _max_inner_iterations): - strategy_solver_baset(_solver, _ns), + strategy_solver_baset(_solver, literalt(), _ns), linrank_domain(_linrank_domain), max_inner_iterations(_max_inner_iterations), inner_solver(_ns), @@ -33,7 +33,7 @@ class ranking_solver_enumerationt:public strategy_solver_baset solver_instances++; } - virtual bool iterate(invariantt &inv); + virtual progresst iterate(invariantt &inv); protected: linrank_domaint &linrank_domain; diff --git a/src/domains/simplify_bounds.cpp b/src/domains/simplify_bounds.cpp new file mode 100644 index 000000000..8c63fa646 --- /dev/null +++ b/src/domains/simplify_bounds.cpp @@ -0,0 +1,454 @@ +/*******************************************************************\ + +Module: Bounds simplification + +Author: Peter Schrammel + +\*******************************************************************/ + +#include + +#include "simplify_bounds.h" +#include "simplify_bounds_class.h" +#include + +#define DEBUGX + +#ifdef DEBUGX +#include +#include +#endif + +/*******************************************************************\ + +Function: simplify_boundst::get_min_bound + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool simplify_boundst::get_min_bound(const exprt &expr, mp_integer &value) +{ +#ifdef DEBUGX + std::cout << "get_min_bound: " << from_expr(ns, "", expr) + << "\n"; +#endif + + if(!is_bitvector_type(expr.type())) + return false; + + if(expr.id()==ID_symbol) + { + value=get_smallest(expr.type()); + return true; + } + else if(expr.id()==ID_typecast) + { + return get_min_bound(to_typecast_expr(expr).op(), value); + } + else if(expr.id()==ID_unary_minus) + { + bool result=get_max_bound(to_unary_minus_expr(expr).op(), value); + value=-value; + return result; + } + else if(expr.id()==ID_plus) + { + mp_integer vr, vl; + bool rr=get_min_bound(expr.op0(), vr); + bool rl=get_min_bound(expr.op1(), vl); + if(rr && rl) + { + value=vr+vl; + return true; + } + } + else if(expr.id()==ID_minus) + { + mp_integer vr, vl; + bool rr=get_min_bound(expr.op0(), vr); + bool rl=get_max_bound(expr.op1(), vl); + if(rr && rl) + { + value=vr-vl; + return true; + } + } + + return false; +} + +/*******************************************************************\ + +Function: simplify_boundst::get_max_bound + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool simplify_boundst::get_max_bound(const exprt &expr, mp_integer &value) +{ +#ifdef DEBUGX + std::cout << "get_max_bound: " << from_expr(ns, "", expr) + << "\n"; +#endif + + if(!is_bitvector_type(expr.type())) + return false; + + if(expr.id()==ID_symbol) + { + value=get_largest(expr.type()); + return true; + } + else if(expr.id()==ID_typecast) + { + return get_max_bound(to_typecast_expr(expr).op(), value); + } + else if(expr.id()==ID_unary_minus) + { + bool result=get_min_bound(to_unary_minus_expr(expr).op(), value); + value=-value; + return result; + } + else if(expr.id()==ID_plus) + { + mp_integer vr, vl; + bool rr=get_max_bound(expr.op0(), vr); + bool rl=get_max_bound(expr.op1(), vl); + if(rr && rl) + { + value=vr+vl; + return true; + } + } + else if(expr.id()==ID_minus) + { + mp_integer vr, vl; + bool rr=get_max_bound(expr.op0(), vr); + bool rl=get_min_bound(expr.op1(), vl); + if(rr && rl) + { + value=vr-vl; + return true; + } + } + + return false; +} + +/*******************************************************************\ + +Function: simplify_boundst::simplify_rec + + Inputs: + + Outputs: returns true if expression unchanged; + returns false if changed + + Purpose: + +\*******************************************************************/ + +bool simplify_boundst::simplify_rec(exprt &expr) +{ +#ifdef DEBUGX + exprt old(expr); +#endif + + bool result=true; + if(expr.id()==ID_le) + { + binary_relation_exprt &e=to_binary_relation_expr(expr); + if(is_bitvector_type(e.rhs().type()) && e.rhs().id()==ID_constant && + e.lhs().id()!=ID_symbol) + { + mp_integer rhs_value, lhs_max, lhs_min; + to_integer(e.rhs(), rhs_value); + if(get_max_bound(e.lhs(), lhs_max)) + { + if(lhs_max<=rhs_value) + { + expr=true_exprt(); + result=false; + } + else + result=clean_up_typecast(expr, rhs_value); + } + else if(get_min_bound(e.lhs(), lhs_min)) + { + if(lhs_min>rhs_value) + { + expr=false_exprt(); + result=false; + } + } + } + } + else if(expr.id()==ID_ge) + { + binary_relation_exprt &e=to_binary_relation_expr(expr); + if(is_bitvector_type(e.rhs().type()) && e.rhs().id()==ID_constant && + e.lhs().id()!=ID_symbol) + { + mp_integer rhs_value, lhs_max, lhs_min; + to_integer(e.rhs(), rhs_value); + if(get_max_bound(e.lhs(), lhs_max)) + { + if(lhs_max=rhs_value) + { + expr=true_exprt(); + result=false; + } + } + } + } + else if(expr.id()==ID_lt) + { + binary_relation_exprt &e=to_binary_relation_expr(expr); + if(is_bitvector_type(e.rhs().type()) && e.rhs().id()==ID_constant && + e.lhs().id()!=ID_symbol) + { + mp_integer rhs_value, lhs_max, lhs_min; + to_integer(e.rhs(), rhs_value); + if(get_max_bound(e.lhs(), lhs_max)) + { + if(lhs_max=rhs_value) + { + expr=false_exprt(); + result=false; + } + } + } + } + else if(expr.id()==ID_gt) + { + binary_relation_exprt &e=to_binary_relation_expr(expr); + if(is_bitvector_type(e.rhs().type()) && e.rhs().id()==ID_constant && + e.lhs().id()!=ID_symbol) + { + mp_integer rhs_value, lhs_max, lhs_min; + to_integer(e.rhs(), rhs_value); + if(get_max_bound(e.lhs(), lhs_max)) + { + if(lhs_max<=rhs_value) + { + expr=false_exprt(); + result=false; + } + } + else if(get_min_bound(e.lhs(), lhs_min)) + { + if(lhs_min>rhs_value) + { + expr=true_exprt(); + result=false; + } + } + } + } + else + { + Forall_operands(it, expr) + if(!simplify_rec(*it)) + result=false; + } +#ifdef DEBUGX + std::cout << "===== " << from_expr(ns, "", old) + << "\n ---> " << from_expr(ns, "", expr) + << "\n"; +#endif + + return result; +} + +/*******************************************************************\ + +Function: simplify_boundst::clean_up_typecast + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool simplify_boundst::clean_up_typecast(exprt &expr, + const mp_integer &rhs_value) +{ + if(expr.id()==ID_le && expr.op0().id()==ID_unary_minus && + expr.op0().op0().id()==ID_typecast) + { + const typet &inner_type=expr.op0().op0().op0().type(); + if(-rhs_value>get_smallest(inner_type)) + { + expr=binary_relation_exprt(expr.op0().op0().op0(), ID_ge, + from_integer(-rhs_value, inner_type)); + return true; + } + } + return false; +} + +/*******************************************************************\ + +Function: simplify_boundst::clean_up_implications + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool simplify_boundst::clean_up_implications(exprt &expr) +{ + bool result=true; + if(expr.id()==ID_and) + { + Forall_operands(it, expr) + if(!clean_up_implications(*it)) + result=false; + exprt::operandst::iterator it=expr.operands().begin(); + while(it!=expr.operands().end()) + { + if(it->is_true()) + it=expr.operands().erase(it); + else + ++it; + } + if(expr.operands().empty()) + expr=true_exprt(); + else if(expr.operands().size()==1) + expr=expr.op0(); + } + else if(expr.id()==ID_implies) + { + if(expr.op1().is_true()) + { + expr=true_exprt(); + result=false; + } + } + return result; +} + +/*******************************************************************\ + +Function: simplify_boundst::clean_up_implications + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool simplify_boundst::regroup_implications(exprt &expr) +{ + std::map implication_map; + exprt::operandst r; + if(expr.id()==ID_and) + { + Forall_operands(it, expr) + if(it->id()==ID_implies) + implication_map[it->op0()].push_back(it->op1()); + else + r.push_back(*it); + } + else + return true; + for(auto &i : implication_map) + r.push_back(implies_exprt(i.first, conjunction(i.second))); + expr=conjunction(r); + return false; +} + +/*******************************************************************\ + +Function: simplify_boundst::operator() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool simplify_boundst::operator()(exprt &expr) +{ + bool result=simplify_rec(expr); + if(!clean_up_implications(expr)) + result=false; + if(!regroup_implications(expr)) + result=false; + return result; +} + +/*******************************************************************\ + +Function: simplify + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool simplify_bounds(exprt &expr, + const namespacet &ns) +{ + return simplify_boundst(ns)(expr); +} + +/*******************************************************************\ + +Function: simplify_bounds + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +exprt simplify_bounds(const exprt &src, + const namespacet &ns) +{ + exprt tmp=src; + simplify_boundst simplify_bounds(ns); + simplify_bounds(tmp); + return tmp; +} + diff --git a/src/domains/simplify_bounds.h b/src/domains/simplify_bounds.h new file mode 100644 index 000000000..df8ce143c --- /dev/null +++ b/src/domains/simplify_bounds.h @@ -0,0 +1,32 @@ +/*******************************************************************\ + +Module: Bounds simplification + +Author: Peter Schrammel + +\*******************************************************************/ + +#ifndef CPROVER_2LS_DOMAINS_SIMPLIFY_BOUNDS_H +#define CPROVER_2LS_DOMAINS_SIMPLIFY_BOUNDS_H + +#include + +class exprt; +class namespacet; + +// +// simplify bounds +// +// true: did nothing +// false: simplified something +// + +bool simplify_bounds( + exprt &expr, + const namespacet &ns); + +exprt simplify_bounds( + const exprt &src, + const namespacet &ns); + +#endif // CPROVER_2LS_DOMAINS_SIMPLIFY_BOUNDS_H diff --git a/src/domains/simplify_bounds_class.h b/src/domains/simplify_bounds_class.h new file mode 100644 index 000000000..c4622c100 --- /dev/null +++ b/src/domains/simplify_bounds_class.h @@ -0,0 +1,69 @@ +/*******************************************************************\ + +Module: Bounds Simplification + +Author: Peter Schrammel + +\*******************************************************************/ + +#ifndef CPROVER_2LS_DOMAINS_SIMPLIFY_BOUNDS_CLASS_H +#define CPROVER_2LS_DOMAINS_SIMPLIFY_BOUNDS_CLASS_H + +#include +#include + +class exprt; +class namespacet; + +class simplify_boundst +{ +public: + explicit simplify_boundst(const namespacet &_ns): + ns(_ns) + { + } + + virtual ~simplify_boundst() + { + } + + // These below all return 'true' if the simplification wasn't applicable. + // If false is returned, the expression has changed. + + virtual bool operator()(exprt &expr); + + inline static bool is_bitvector_type(const typet &type) + { + return type.id()==ID_unsignedbv || + type.id()==ID_signedbv; + } + inline static mp_integer get_largest(const typet &type) + { + if(type.id()==ID_signedbv) + return to_signedbv_type(type).largest(); + else if(type.id()==ID_unsignedbv) + return to_unsignedbv_type(type).largest(); + assert(false); + } + inline static mp_integer get_smallest(const typet &type) + { + if(type.id()==ID_signedbv) + return to_signedbv_type(type).smallest(); + else if(type.id()==ID_unsignedbv) + return to_unsignedbv_type(type).smallest(); + assert(false); + } + +protected: + const namespacet &ns; + + bool simplify_rec(exprt &expr); + bool get_min_bound(const exprt &expr, mp_integer &value); + bool get_max_bound(const exprt &expr, mp_integer &value); + + bool clean_up_implications(exprt &expr); + bool regroup_implications(exprt &expr); + bool clean_up_typecast(exprt &expr, const mp_integer &value); +}; + +#endif // CPROVER_2LS_DOMAINS_SIMPLIFY_BOUNDS_CLASS_H diff --git a/src/domains/simplify_transformer.cpp b/src/domains/simplify_transformer.cpp new file mode 100644 index 000000000..ebddc12ea --- /dev/null +++ b/src/domains/simplify_transformer.cpp @@ -0,0 +1,259 @@ +/*******************************************************************\ + +Module: Transformer simplification + +Author: Peter Schrammel + +\*******************************************************************/ + +#include + +#include "simplify_transformer.h" +#include "simplify_transformer_class.h" +#include + +#define DEBUGX + +#ifdef DEBUGX +#include +#include +#endif + +/*******************************************************************\ + +Function: simplify_transformert::collect_node + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void simplify_transformert::collect_node( + const exprt &expr, + replace_mapt &substitutions, + bool frozen_only, + bool make_copy) +{ + if(expr.id()==ID_equal) + { + const equal_exprt &e=to_equal_expr(expr); + + bool rhs_is_constant=e.rhs().id()==ID_constant; + bool rhs_is_symbol=e.rhs().id()==ID_symbol || + e.rhs().id()==ID_nondet_symbol; + bool rhs_is_frozen=rhs_is_symbol && + frozen_symbols.find(e.rhs().get(ID_identifier))!=frozen_symbols.end(); + bool lhs_is_constant=e.lhs().id()==ID_constant; + bool lhs_is_symbol=e.lhs().id()==ID_symbol || + e.lhs().id()==ID_nondet_symbol; + bool lhs_is_frozen=lhs_is_symbol && + frozen_symbols.find(e.lhs().get(ID_identifier))!=frozen_symbols.end(); + + exprt lhs, rhs; + lhs.make_nil(); + rhs.make_nil(); + // stupid matching + if((rhs_is_frozen || rhs_is_constant || !frozen_only) && + lhs_is_symbol && !lhs_is_frozen) + { + lhs=e.lhs(); + rhs=e.rhs(); + } + if((lhs_is_frozen || lhs_is_constant || !frozen_only) && + rhs_is_symbol && !rhs_is_frozen) + { + rhs=e.lhs(); + lhs=e.rhs(); + } + if(rhs.is_not_nil() && lhs.is_not_nil()) + { + if(make_copy) // make lazy copy + { + replace_mapt _subst=substitutions; + substitutions=_subst; + } + substitutions[lhs]=rhs; + } + } + +#ifdef DEBUGX + std::cout << "COLLECT: " << from_expr(ns, "", expr) << std::endl; + for(const auto &it : substitutions) + std::cout << from_expr(ns, "", it.first) + << "---> " << from_expr(ns, "", it.second) + << "\n"; +#endif +} + +/*******************************************************************\ + +Function: simplify_transformert::simplify_node + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool simplify_transformert::simplify_node( + exprt &expr, + const replace_mapt &substitutions) +{ + return replace_expr(substitutions, expr); +} + +/*******************************************************************\ + +Function: simplify_transformert::simplify_rec + + Inputs: + + Outputs: returns true if expression unchanged; + returns false if changed + + Purpose: + +\*******************************************************************/ + +bool simplify_transformert::simplify_rec( + exprt &expr, + replace_mapt &substitutions) +{ +#ifdef DEBUGX + exprt old(expr); +#endif + + bool result=true; + if(expr.id()==ID_and) + { + // first propagate from frozen symbols + bool res=false; + do + { + Forall_operands(it, expr) + collect_node(*it, substitutions, true, false); + + Forall_operands(it, expr) + if(!simplify_rec(*it, substitutions)) + result=false; + + res=simplify_node(expr, substitutions); + if(!res) result=false; + } + while(!res); + + // simplify remaining equalities + Forall_operands(it, expr) + collect_node(*it, substitutions, false, false); + + res=false; + do + { + res=simplify_node(expr, substitutions); + if(!res) result=false; + } + while(!res); + } + +#if 0 // for later extension to disjunctions + // TODO: handle negation, too + else if(expr.id()==ID_or || expr.id()==ID_implies) + { + Forall_operands(it, expr) + { + collect_node(*it, substitutions, true); + if(!simplify_rec(*it, substitutions)) + result=false; + + bool res=false; + do + { + res=simplify_node(*it, substitutions); + if(!res) result=false; + } + while(!res); + } + } +#endif + +#ifdef DEBUGX + std::cout << "===== " << from_expr(ns, "", old) + << "\n ---> " << from_expr(ns, "", expr) + << "\n"; +#endif + + return result; +} + +/*******************************************************************\ + +Function: simplify_transformert::operator() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool simplify_transformert::operator()(exprt &expr) +{ + replace_mapt substitutions; + return simplify_rec(expr, substitutions); +} + +/*******************************************************************\ + +Function: simplify + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool simplify( + exprt &expr, + const std::set &frozen_vars, + const namespacet &ns) +{ + return simplify_transformert(ns, frozen_vars)(expr); +} + +/*******************************************************************\ + +Function: simplify_transformer + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +exprt simplify_transformer( + const exprt &src, + const std::set &frozen_vars, + const namespacet &ns) +{ +#ifdef DEBUGX + std::cout << "FROZEN:"; + for(const auto &it : frozen_vars) + std::cout << " " << it; + std::cout << "\n"; +#endif + + exprt tmp=src; + simplify_transformert(ns, frozen_vars)(tmp); + return tmp; +} + diff --git a/src/domains/simplify_transformer.h b/src/domains/simplify_transformer.h new file mode 100644 index 000000000..31779d6f0 --- /dev/null +++ b/src/domains/simplify_transformer.h @@ -0,0 +1,35 @@ +/*******************************************************************\ + +Module: Transformer simplification + +Author: Peter Schrammel + +\*******************************************************************/ + +#ifndef CPROVER_2LS_DOMAINS_SIMPLIFY_TRANSFORMER_H +#define CPROVER_2LS_DOMAINS_SIMPLIFY_TRANSFORMER_H + +#include +#include + +class exprt; +class namespacet; + +// +// simplify transformers by best-effort intermediate variable elimination +// +// true: did nothing +// false: simplified something +// + +bool simplify( + exprt &expr, + const std::set &frozen_vars, // do not eliminate these + const namespacet &ns); + +exprt simplify_transformer( + const exprt &src, + const std::set &frozen_vars, // do not eliminate these + const namespacet &ns); + +#endif // CPROVER_2LS_DOMAINS_SIMPLIFY_TRANSFORMER_H diff --git a/src/domains/simplify_transformer_class.h b/src/domains/simplify_transformer_class.h new file mode 100644 index 000000000..9a9218516 --- /dev/null +++ b/src/domains/simplify_transformer_class.h @@ -0,0 +1,61 @@ +/*******************************************************************\ + +Module: Transformer Simplification + +Author: Peter Schrammel + +\*******************************************************************/ + +#ifndef CPROVER_2LS_DOMAINS_SIMPLIFY_TRANSFORMER_CLASS_H +#define CPROVER_2LS_DOMAINS_SIMPLIFY_TRANSFORMER_CLASS_H + +#include +#include + +class exprt; +class namespacet; + +class simplify_transformert +{ +public: + simplify_transformert( + const namespacet &_ns, + const std::set &_frozen_symbols): + ns(_ns), + frozen_symbols(_frozen_symbols) + { + } + + virtual ~simplify_transformert() + { + } + + // These below all return 'true' if the simplification wasn't applicable. + // If false is returned, the expression has changed. + + // main recursion + bool simplify_rec(exprt &expr, replace_mapt &substitutions); + + virtual bool operator()(exprt &expr); + + inline static bool is_bitvector_type(const typet &type) + { + return type.id()==ID_unsignedbv || + type.id()==ID_signedbv || + type.id()==ID_bv; + } + +protected: + const namespacet &ns; + const std::set &frozen_symbols; + + void collect_node( + const exprt &expr, + replace_mapt &substitutions, + bool frozen_only, + bool make_copy); + + bool simplify_node(exprt &expr, const replace_mapt &substitutions); +}; + +#endif // CPROVER_2LS_DOMAINS_SIMPLIFY_TRANSFORMER_CLASS_H diff --git a/src/domains/ssa_analyzer.cpp b/src/domains/ssa_analyzer.cpp index 993ba4eea..8546b5186 100644 --- a/src/domains/ssa_analyzer.cpp +++ b/src/domains/ssa_analyzer.cpp @@ -32,13 +32,16 @@ Author: Peter Schrammel #include "strategy_solver_predabs.h" #include "ssa_analyzer.h" -#define BINSEARCH_SOLVER strategy_solver_binsearcht(\ - *static_cast(domain), solver, SSA.ns) +#define BINSEARCH_SOLVER strategy_solver_binsearcht( \ + *static_cast(domain), \ + solver, assertions_check, SSA.ns) #if 0 -#define BINSEARCH_SOLVER strategy_solver_binsearch2t(\ - *static_cast(domain), solver, SSA.ns) -#define BINSEARCH_SOLVER strategy_solver_binsearch3t(\ - *static_cast(domain), solver, SSA, SSA.ns) +#define BINSEARCH_SOLVER strategy_solver_binsearch2t( \ + *static_cast(domain), solver, \ + assertions_check, SSA.ns) +#define BINSEARCH_SOLVER strategy_solver_binsearch3t( \ + *static_cast(domain), solver, \ + assertions_check, SSA, SSA.ns) #endif /*******************************************************************\ @@ -47,20 +50,21 @@ Function: ssa_analyzert::operator() Inputs: - Outputs: - + Outputs: true if the computation was not aborted due to + assertion_checks that did not pass Purpose: \*******************************************************************/ -void ssa_analyzert::operator()( +bool ssa_analyzert::operator()( incremental_solvert &solver, local_SSAt &SSA, const exprt &precondition, - template_generator_baset &template_generator) + template_generator_baset &template_generator, + bool check_assertions) { if(SSA.goto_function.body.instructions.empty()) - return; + return true; solver << SSA; SSA.mark_nodes(); @@ -73,6 +77,30 @@ void ssa_analyzert::operator()( domain=template_generator.domain(); + // get assertions if check_assertions is requested + literalt assertions_check=const_literal(false); + bvt assertion_literals; + if(check_assertions) + { + exprt::operandst ll; + for(local_SSAt::nodest::iterator n_it=SSA.nodes.begin(); + n_it!=SSA.nodes.end(); n_it++) + { + assert(n_it->assertions.size()<=1); + for(local_SSAt::nodet::assertionst::const_iterator + a_it=n_it->assertions.begin(); + a_it!=n_it->assertions.end(); + a_it++) + { + literalt l=solver.solver->convert(*a_it); + assertion_literals.push_back(!l); + ll.push_back(literal_exprt(!l)); + nonpassed_assertions.push_back(n_it); + } + } + assertions_check=solver.solver->convert(disjunction(ll)); + } + // get strategy solver from options strategy_solver_baset *strategy_solver; if(template_generator.options.get_bool_option("compute-ranking-functions")) @@ -100,7 +128,8 @@ void ssa_analyzert::operator()( else if(template_generator.options.get_bool_option("equalities")) { strategy_solver=new strategy_solver_equalityt( - *static_cast(domain), solver, SSA.ns); + *static_cast(domain), + solver, assertions_check, SSA.ns); result=new equality_domaint::equ_valuet(); } else @@ -109,13 +138,15 @@ void ssa_analyzert::operator()( { result=new tpolyhedra_domaint::templ_valuet(); strategy_solver=new strategy_solver_enumerationt( - *static_cast(domain), solver, SSA.ns); + *static_cast(domain), + solver, assertions_check, SSA.ns); } else if(template_generator.options.get_bool_option("predabs-solver")) { result=new predabs_domaint::templ_valuet(); strategy_solver=new strategy_solver_predabst( - *static_cast(domain), solver, SSA.ns); + *static_cast(domain), + solver, assertions_check, SSA.ns); } else if(template_generator.options.get_bool_option("binsearch-solver")) { @@ -131,17 +162,39 @@ void ssa_analyzert::operator()( // initialize inv domain->initialize(*result); - // iterate - while(strategy_solver->iterate(*result)) {} + strategy_solver_baset::progresst status; + + do + { + status=strategy_solver->iterate(*result); + } + while(status==strategy_solver_baset::CHANGED); + + // get status of assertions + if(!assertions_check.is_false() && + status==strategy_solver_baset::FAILED) + { + nonpassed_assertionst::iterator it=nonpassed_assertions.begin(); + for(unsigned i=0; il_get(assertion_literals[i]).is_true()) + nonpassed_assertions.erase(it++); + else + ++it; + } + } + else + nonpassed_assertions.clear(); solver.pop_context(); // statistics - solver_instances+=strategy_solver->get_number_of_solver_instances(); solver_calls+=strategy_solver->get_number_of_solver_calls(); solver_instances+=strategy_solver->get_number_of_solver_instances(); delete strategy_solver; + + return (status==strategy_solver_baset::CONVERGED); } /*******************************************************************\ diff --git a/src/domains/ssa_analyzer.h b/src/domains/ssa_analyzer.h index 1758f4711..35cc63626 100644 --- a/src/domains/ssa_analyzer.h +++ b/src/domains/ssa_analyzer.h @@ -23,7 +23,7 @@ class ssa_analyzert:public messaget typedef strategy_solver_baset::var_listt var_listt; ssa_analyzert(): - result(NULL), + result(nullptr), solver_instances(0), solver_calls(0) { @@ -31,24 +31,33 @@ class ssa_analyzert:public messaget ~ssa_analyzert() { - if(result!=NULL) + if(result!=nullptr) delete result; } - void operator()( + bool operator()( incremental_solvert &solver, local_SSAt &SSA, const exprt &precondition, - template_generator_baset &template_generator); + template_generator_baset &template_generator, + bool check_assertions=false); + // retrieve the result if operator() returned true void get_result(exprt &result, const domaint::var_sett &vars); + // retrieve the non-passed assertions if operator() returned false + typedef std::list + nonpassed_assertionst; + nonpassed_assertionst get_nonpassed_assertions() + { return nonpassed_assertions; } + inline unsigned get_number_of_solver_instances() { return solver_instances; } inline unsigned get_number_of_solver_calls() { return solver_calls; } protected: domaint *domain; // template generator is responsable for the domain object domaint::valuet *result; + nonpassed_assertionst nonpassed_assertions; // statistics unsigned solver_instances; @@ -56,4 +65,3 @@ class ssa_analyzert:public messaget }; #endif - diff --git a/src/domains/strategy_solver_base.h b/src/domains/strategy_solver_base.h index 2e33c0946..1244a7bdc 100644 --- a/src/domains/strategy_solver_base.h +++ b/src/domains/strategy_solver_base.h @@ -19,23 +19,27 @@ class strategy_solver_baset:public messaget typedef std::list constraintst; typedef std::vector var_listt; typedef domaint::valuet invariantt; + typedef enum {CHANGED, CONVERGED, FAILED} progresst; explicit strategy_solver_baset( incremental_solvert &_solver, + literalt _assertion_check, const namespacet &_ns): solver(_solver), + assertion_check(_assertion_check), ns(_ns), solver_instances(0), solver_calls(0) {} - virtual bool iterate(invariantt &inv) { assert(false); } + virtual progresst iterate(invariantt &inv) { assert(false); } - inline unsigned get_number_of_solver_calls() { return solver_calls; } - inline unsigned get_number_of_solver_instances() { return solver_instances; } + unsigned get_number_of_solver_calls() { return solver_calls; } + unsigned get_number_of_solver_instances() { return solver_instances; } protected: incremental_solvert &solver; + literalt assertion_check; const namespacet &ns; // handles on values to retrieve from model diff --git a/src/domains/strategy_solver_binsearch.cpp b/src/domains/strategy_solver_binsearch.cpp index 398d66ddd..687eed4da 100644 --- a/src/domains/strategy_solver_binsearch.cpp +++ b/src/domains/strategy_solver_binsearch.cpp @@ -25,12 +25,13 @@ Function: strategy_solver_binsearcht::iterate \*******************************************************************/ -bool strategy_solver_binsearcht::iterate(invariantt &_inv) +strategy_solver_baset::progresst strategy_solver_binsearcht::iterate( + invariantt &_inv) { tpolyhedra_domaint::templ_valuet &inv= static_cast(_inv); - bool improved=false; + progresst progress=CONVERGED; solver.new_context(); // for improvement check @@ -65,7 +66,8 @@ bool strategy_solver_binsearcht::iterate(invariantt &_inv) debug() << eom; #endif - solver << disjunction(strategy_cond_exprs); + solver << or_exprt(disjunction(strategy_cond_exprs), + literal_exprt(assertion_check)); #if 0 debug() << "solve(): "; @@ -115,6 +117,13 @@ bool strategy_solver_binsearcht::iterate(invariantt &_inv) break; // we've found a row to improve } + if(row==strategy_cond_literals.size()) + { // No, we haven't found one. + // This can only happen if the assertions failed. + solver.pop_context(); + return FAILED; + } + debug() << "improving row: " << row << eom; std::set improve_rows; improve_rows.insert(row); @@ -224,10 +233,8 @@ bool strategy_solver_binsearcht::iterate(invariantt &_inv) debug() << "update value: " << from_expr(ns, "", lower) << eom; - solver.pop_context(); // symbolic value system - tpolyhedra_domain.set_row_value(row, lower, inv); - improved=true; + progress=CHANGED; } else { @@ -248,5 +255,5 @@ bool strategy_solver_binsearcht::iterate(invariantt &_inv) solver.pop_context(); // improvement check } - return improved; + return progress; } diff --git a/src/domains/strategy_solver_binsearch.h b/src/domains/strategy_solver_binsearch.h index 8bcdf7f4b..e47c6cfef 100644 --- a/src/domains/strategy_solver_binsearch.h +++ b/src/domains/strategy_solver_binsearch.h @@ -18,13 +18,14 @@ class strategy_solver_binsearcht:public strategy_solver_baset strategy_solver_binsearcht( tpolyhedra_domaint &_tpolyhedra_domain, incremental_solvert &_solver, + literalt _assertion_check, const namespacet &_ns): - strategy_solver_baset(_solver, _ns), + strategy_solver_baset(_solver, _assertion_check, _ns), tpolyhedra_domain(_tpolyhedra_domain) { } - virtual bool iterate(invariantt &inv); + virtual progresst iterate(invariantt &inv); protected: tpolyhedra_domaint &tpolyhedra_domain; diff --git a/src/domains/strategy_solver_binsearch2.cpp b/src/domains/strategy_solver_binsearch2.cpp index 8aa25032f..d97bb40a8 100644 --- a/src/domains/strategy_solver_binsearch2.cpp +++ b/src/domains/strategy_solver_binsearch2.cpp @@ -32,12 +32,13 @@ Function: strategy_solver_binsearch2t::iterate \*******************************************************************/ -bool strategy_solver_binsearch2t::iterate(invariantt &_inv) +strategy_solver_binsearch2t::progresst +strategy_solver_binsearch2t::iterate(invariantt &_inv) { tpolyhedra_domaint::templ_valuet &inv= static_cast(_inv); - bool improved=false; + progresst progress=CONVERGED; solver.new_context(); // for improvement check @@ -87,7 +88,7 @@ bool strategy_solver_binsearch2t::iterate(invariantt &_inv) #if 0 debug() << "SAT" << eom; #endif - improved=true; + progress=CHANGED; std::size_t row=0; for(; row(_inv); - bool improved=false; + progresst progress=CONVERGED; solver.new_context(); // for improvement check @@ -84,7 +85,7 @@ bool strategy_solver_binsearch3t::iterate(invariantt &_inv) #if 0 debug() << "SAT" << eom; #endif - improved=true; + progress=CHANGED; std::size_t row=0; for(; row(_inv); - bool improved=false; + progresst progress=CONVERGED; solver.new_context(); @@ -68,7 +69,8 @@ bool strategy_solver_enumerationt::iterate(invariantt &_inv) debug() << eom; #endif - solver << disjunction(strategy_cond_exprs); + solver << or_exprt(disjunction(strategy_cond_exprs), + literal_exprt(assertion_check)); #ifdef DEBUG_OUTPUT debug() << "solve(): "; @@ -144,9 +146,14 @@ bool strategy_solver_enumerationt::iterate(invariantt &_inv) << ", simplified value: " << from_expr(ns, "", v) << eom; tpolyhedra_domain.set_row_value(row, v, inv); + progress=CHANGED; } } - improved=true; + if(!progress==CHANGED) // only possible if assertion check fails + { + solver.pop_context(); + return FAILED; + } } else { @@ -166,5 +173,5 @@ bool strategy_solver_enumerationt::iterate(invariantt &_inv) } solver.pop_context(); - return improved; + return progress; } diff --git a/src/domains/strategy_solver_enumeration.h b/src/domains/strategy_solver_enumeration.h index e4363246c..4383e4d0e 100644 --- a/src/domains/strategy_solver_enumeration.h +++ b/src/domains/strategy_solver_enumeration.h @@ -18,13 +18,14 @@ class strategy_solver_enumerationt:public strategy_solver_baset strategy_solver_enumerationt( tpolyhedra_domaint &_tpolyhedra_domain, incremental_solvert &_solver, + literalt _assertion_check, const namespacet &_ns): - strategy_solver_baset(_solver, _ns), + strategy_solver_baset(_solver, _assertion_check, _ns), tpolyhedra_domain(_tpolyhedra_domain) { } - virtual bool iterate(invariantt &inv); + virtual progresst iterate(invariantt &inv); protected: tpolyhedra_domaint &tpolyhedra_domain; diff --git a/src/domains/strategy_solver_equality.cpp b/src/domains/strategy_solver_equality.cpp index bf83742b7..43602e881 100644 --- a/src/domains/strategy_solver_equality.cpp +++ b/src/domains/strategy_solver_equality.cpp @@ -21,11 +21,12 @@ Function: strategy_solver_equalityt::iterate Outputs: - Purpose: + Purpose: Comment: assertion check is not possible + because this is a gfp solver \*******************************************************************/ -bool strategy_solver_equalityt::iterate(invariantt &_inv) +strategy_solver_baset::progresst strategy_solver_equalityt::iterate(invariantt &_inv) { equality_domaint::equ_valuet &inv= static_cast(_inv); @@ -83,7 +84,7 @@ bool strategy_solver_equalityt::iterate(invariantt &_inv) { e_it=todo_disequs.begin(); if(e_it==todo_disequs.end()) - return false; // done + return CONVERGED; // done solver.new_context(); @@ -122,5 +123,5 @@ bool strategy_solver_equalityt::iterate(invariantt &_inv) todo_disequs.erase(e_it); } - return true; + return CHANGED; } diff --git a/src/domains/strategy_solver_equality.h b/src/domains/strategy_solver_equality.h index 6a7407a75..ae011cdf9 100644 --- a/src/domains/strategy_solver_equality.h +++ b/src/domains/strategy_solver_equality.h @@ -18,14 +18,15 @@ class strategy_solver_equalityt:public strategy_solver_baset strategy_solver_equalityt( equality_domaint &_equality_domain, incremental_solvert &_solver, + literalt _assertion_check, const namespacet &_ns): - strategy_solver_baset(_solver, _ns), + strategy_solver_baset(_solver, _assertion_check, _ns), equality_domain(_equality_domain) { equality_domain.get_index_set(todo_equs); } - virtual bool iterate(invariantt &inv); + virtual progresst iterate(invariantt &inv); protected: equality_domaint &equality_domain; diff --git a/src/domains/strategy_solver_predabs.cpp b/src/domains/strategy_solver_predabs.cpp index c3f5fe2ca..353c0ea4f 100644 --- a/src/domains/strategy_solver_predabs.cpp +++ b/src/domains/strategy_solver_predabs.cpp @@ -26,7 +26,8 @@ Function: strategy_solver_predabst::iterate \*******************************************************************/ -bool strategy_solver_predabst::iterate(invariantt &_inv) +strategy_solver_predabst::progresst +strategy_solver_predabst::iterate(invariantt &_inv) { predabs_domaint::templ_valuet &inv= static_cast(_inv); @@ -96,8 +97,8 @@ bool strategy_solver_predabst::iterate(invariantt &_inv) todo_preds.erase(e_it); - return true; + return CHANGED; } - return false; + return CONVERGED; } diff --git a/src/domains/strategy_solver_predabs.h b/src/domains/strategy_solver_predabs.h index 1654e9729..b7ec0695d 100644 --- a/src/domains/strategy_solver_predabs.h +++ b/src/domains/strategy_solver_predabs.h @@ -18,14 +18,15 @@ class strategy_solver_predabst:public strategy_solver_baset explicit strategy_solver_predabst( predabs_domaint &_predabs_domain, incremental_solvert &_solver, + literalt _assertion_check, const namespacet &_ns): - strategy_solver_baset(_solver, _ns), + strategy_solver_baset(_solver, _assertion_check, _ns), predabs_domain(_predabs_domain) { predabs_domain.get_row_set(todo_preds); } - virtual bool iterate(invariantt &inv); + virtual progresst iterate(invariantt &inv); protected: predabs_domaint &predabs_domain; diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index e62fa1649..8a423b426 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -337,6 +337,29 @@ Function: template_generator_baset::add_vars \*******************************************************************/ +void template_generator_baset::add_vars( + const std::set &vars_to_add, + const domaint::guardt &pre_guard, + const domaint::guardt &post_guard, + const domaint::kindt &kind, + domaint::var_specst &var_specs) +{ + for(const auto &v : vars_to_add) + add_var(v, pre_guard, post_guard, kind, var_specs); +} + +/*******************************************************************\ + +Function: template_generator_baset::add_vars + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + void template_generator_baset::add_vars( const local_SSAt::var_listt &vars_to_add, const domaint::guardt &pre_guard, diff --git a/src/domains/template_generator_base.h b/src/domains/template_generator_base.h index 1c9428da2..031d4ac49 100644 --- a/src/domains/template_generator_base.h +++ b/src/domains/template_generator_base.h @@ -50,8 +50,12 @@ class template_generator_baset:public messaget } virtual domaint::var_sett all_vars(); - - inline domaint *domain() { assert(domain_ptr!=NULL); return domain_ptr; } + bool empty() + { + assert(domain_ptr!=nullptr); + return domain_ptr->is_spec_empty(); + } + domaint *domain() { assert(domain_ptr!=nullptr); return domain_ptr; } domaint::var_specst var_specs; replace_mapt post_renaming_map; @@ -80,6 +84,12 @@ class template_generator_baset:public messaget domaint::guardt post_guard, const domaint::kindt &kind, domaint::var_specst &var_specs); + void add_vars( + const std::set &vars_to_add, + const domaint::guardt &pre_guard, + const domaint::guardt &post_guard, + const domaint::kindt &kind, + domaint::var_specst &var_specs); void add_vars( const var_listt &vars_to_add, const domaint::guardt &pre_guard, @@ -102,7 +112,8 @@ class template_generator_baset:public messaget void get_pre_post_guards( const local_SSAt &SSA, local_SSAt::nodest::const_iterator n_it, - exprt &pre_guard, exprt &post_guard); + exprt &pre_guard, + exprt &post_guard); void get_pre_var( const local_SSAt &SSA, local_SSAt::objectst::const_iterator o_it, diff --git a/src/domains/template_generator_summary.cpp b/src/domains/template_generator_summary.cpp index becceba5f..b9fc4f68b 100644 --- a/src/domains/template_generator_summary.cpp +++ b/src/domains/template_generator_summary.cpp @@ -103,6 +103,12 @@ void template_generator_summaryt::collect_variables_inout( last_guard, forward ? domaint::OUT : domaint::IN, var_specs); + + // add nondets for backwards analysis + if(!forward) + { + add_vars(SSA.nondets, first_guard, first_guard, domaint::OUT, var_specs); + } } /*******************************************************************\ diff --git a/src/domains/tpolyhedra_domain.cpp b/src/domains/tpolyhedra_domain.cpp index 470931c05..b2c7a2075 100644 --- a/src/domains/tpolyhedra_domain.cpp +++ b/src/domains/tpolyhedra_domain.cpp @@ -17,6 +17,7 @@ Author: Peter Schrammel #include "tpolyhedra_domain.h" #include "util.h" +#include "simplify_bounds.h" #define SYMB_BOUND_VAR "symb_bound#" @@ -50,6 +51,8 @@ void tpolyhedra_domaint::initialize(valuet &value) else v[row]=false_exprt(); // marker for -oo } + + refine(); // initialise refinements } /*******************************************************************\ @@ -694,6 +697,8 @@ void tpolyhedra_domaint::project_on_vars( } } result=conjunction(c); + simplify_bounds(result, ns); + simplify_bounds(result, ns); } /*******************************************************************\ @@ -731,7 +736,7 @@ void tpolyhedra_domaint::set_row_value( \*******************************************************************/ tpolyhedra_domaint::row_valuet tpolyhedra_domaint::get_max_row_value( - const tpolyhedra_domaint::rowt &row) + const tpolyhedra_domaint::rowt &row) const { const template_rowt &templ_row=templ[row]; if(templ_row.expr.type().id()==ID_signedbv) @@ -764,7 +769,7 @@ tpolyhedra_domaint::row_valuet tpolyhedra_domaint::get_max_row_value( \*******************************************************************/ tpolyhedra_domaint::row_valuet tpolyhedra_domaint::get_min_row_value( - const tpolyhedra_domaint::rowt &row) + const tpolyhedra_domaint::rowt &row) const { const template_rowt &templ_row=templ[row]; if(templ_row.expr.type().id()==ID_signedbv) @@ -907,6 +912,25 @@ bool tpolyhedra_domaint::is_row_value_neginf( return row_value.get(ID_value)==ID_false; } +/*******************************************************************\ + + Function: tpolyhedra_domaint::is_row_value_neginf + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool tpolyhedra_domaint::is_row_value_neginf( + const valuet &value, const rowt &row) const +{ + const templ_valuet &v=static_cast(value); + return v.at(row).get(ID_value)==ID_false; +} + /*******************************************************************\ Function: tpolyhedra_domaint::is_row_value_inf @@ -924,6 +948,48 @@ bool tpolyhedra_domaint::is_row_value_inf(const row_valuet & row_value) const return row_value.get(ID_value)==ID_true; } +/*******************************************************************\ + + Function: tpolyhedra_domaint::is_row_value_inf + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool tpolyhedra_domaint::is_row_value_inf( + const valuet &value, const rowt &row) const +{ + const templ_valuet &v=static_cast(value); + const row_valuet &row_value=v.at(row); + if(row_value.get(ID_value)==ID_true) + return true; + if(row_value==get_max_row_value(row)) + return true; + const row_exprt &row_expr=templ[row].expr; + if(row_expr.id()==ID_unary_minus && + row_expr.op0().id()==ID_typecast) + { + mp_integer rvalue; + to_integer(row_value, rvalue); + const typet &inner_type=row_expr.op0().op0().type(); + mp_integer smallest; + if(inner_type.id()==ID_unsignedbv) + smallest=to_unsignedbv_type(inner_type).smallest(); + else if(inner_type.id()==ID_signedbv) + smallest=to_signedbv_type(inner_type).smallest(); + else + return false; + if(smallest==rvalue) + return true; + } + + return false; +} + /*******************************************************************\ Function: tpolyhedra_domaint::rename_for_row @@ -962,7 +1028,7 @@ void tpolyhedra_domaint::rename_for_row(exprt &expr, const rowt &row) Outputs: - Purpose: + Purpose: +-x<=c \*******************************************************************/ @@ -1166,3 +1232,56 @@ void tpolyhedra_domaint::add_sum_template( } } } + +/*******************************************************************\ + +Function: tpolyhedra_domaint::refine + + Inputs: + + Outputs: + + Purpose: non-monotone condition refinement + +\*******************************************************************/ + +void tpolyhedra_domaint::replace_comparison(exprt &expr, bool greater) +{ + // TODO +} + +bool tpolyhedra_domaint::refine() +{ + return false; + + // TODO + if(current_refinement==0) // initialise + { + if(refinement_exprs.size()==0) + { + max_refinements=0; + return false; + } + max_refinements=3; + current_refinement=1; + exprt::operandst c; + // TODO + current_refinement_expr=conjunction(c); + return true; + } + + if(current_refinement>max_refinements) + return false; + + if(current_refinement==1) + { + exprt::operandst c; + // TODO + current_refinement_expr=conjunction(c); + } + else if(current_refinement==2) + current_refinement_expr=true_exprt(); + + current_refinement++; + return true; +} diff --git a/src/domains/tpolyhedra_domain.h b/src/domains/tpolyhedra_domain.h index 866a5accb..efe7ad4b6 100644 --- a/src/domains/tpolyhedra_domain.h +++ b/src/domains/tpolyhedra_domain.h @@ -50,6 +50,10 @@ class tpolyhedra_domaint:public domaint // initialize value virtual void initialize(valuet &value); + virtual void reset_refinements() { current_refinement=0; } + virtual bool refine(); // non-monotone condition refinement + std::vector &refinement_expressions() { return refinement_exprs; } + virtual void join(valuet &value1, const valuet &value2); // value -> constraints @@ -73,7 +77,8 @@ class tpolyhedra_domaint:public domaint exprt to_symb_post_constraints(const std::set &symb_rows); exprt get_row_symb_value_constraint( const rowt &row, - const row_valuet &row_value, bool geq=false); + const row_valuet &row_value, + bool geq=false); exprt get_row_symb_pre_constraint( const rowt &row, const row_valuet &row_value); @@ -88,12 +93,14 @@ class tpolyhedra_domaint:public domaint templ_valuet &value); // max, min, comparison - row_valuet get_max_row_value(const rowt &row); - row_valuet get_min_row_value(const rowt &row); + row_valuet get_max_row_value(const rowt &row) const; + row_valuet get_min_row_value(const rowt &row) const; row_valuet between(const row_valuet &lower, const row_valuet &upper); bool less_than(const row_valuet &v1, const row_valuet &v2); bool is_row_value_inf(const row_valuet & row_value) const; bool is_row_value_neginf(const row_valuet & row_value) const; + bool is_row_value_inf(const valuet &value, const rowt & row) const; + bool is_row_value_neginf(const valuet &value, const rowt & row) const; // printing virtual void output_value( @@ -106,6 +113,7 @@ class tpolyhedra_domaint:public domaint valuet &value, const var_sett &vars, exprt &result); unsigned template_size(); + virtual bool is_spec_empty() const { return templ.size()==0; } // generating templates template_rowt &add_template_row( @@ -133,6 +141,13 @@ class tpolyhedra_domaint:public domaint friend class strategy_solver_enumerationt; templatet templ; + + // non-monotone condition refinement + std::vector refinement_exprs; + unsigned current_refinement, max_refinements; + exprt current_refinement_expr; + + void replace_comparison(exprt &expr, bool greater); }; #endif diff --git a/src/domains/util.cpp b/src/domains/util.cpp index ec12ad55a..159a813d8 100644 --- a/src/domains/util.cpp +++ b/src/domains/util.cpp @@ -51,6 +51,7 @@ void extend_expr_types(exprt &expr) } if(expr.id()==ID_constant || expr.id()==ID_symbol || + expr.id()==ID_nondet_symbol || expr.id()==ID_index) return; if(expr.id()==ID_unary_minus) @@ -122,7 +123,6 @@ void extend_expr_types(exprt &expr) extend_expr_types(expr.op0()); extend_expr_types(expr.op1()); unsigned size0=get_bitvector_width(expr.op0()); -// std::cerr << "expr1: " << expr.op1() << std::endl; unsigned size1=get_bitvector_width(expr.op1()); assert(size0>0); assert(size1>0); @@ -132,8 +132,9 @@ void extend_expr_types(exprt &expr) expr.op1().type().id()==ID_signedbv)) { typet new_type=signedbv_typet(size0+size1+1); - expr=mult_exprt(typecast_exprt(expr.op0(), new_type), - typecast_exprt(expr.op1(), new_type)); + expr=mult_exprt( + typecast_exprt(expr.op0(), new_type), + typecast_exprt(expr.op1(), new_type)); return; } else if(expr.op0().type().id()==ID_floatbv && @@ -241,10 +242,10 @@ mp_integer simplify_const_int(const exprt &expr) assert(d!=0); return simplify_const_int(expr.op0())/d; } - if(expr.id()==ID_symbol) + if(expr.id()==ID_symbol || expr.id()==ID_nondet_symbol) { #if 0 - std::cout << "substituting default value for " << expr << std::endl; + std::cerr << "substituting default value for " << expr << std::endl; #endif return 0; // default value if not substituted in expr } @@ -332,13 +333,16 @@ ieee_floatt simplify_const_float(const exprt &expr) v1/=v2; return v1; } - if(expr.id()==ID_symbol) // default value if not substituted in expr + // default value if not substituted in expr + if(expr.id()==ID_symbol || expr.id()==ID_nondet_symbol) { ieee_floatt v; v.make_zero(); + #if 0 - std::cout << "substituting default value for " << expr << std::endl; + std::cerr << "substituting default value for " << expr << std::endl; #endif + return v; } if(expr.id()==ID_index) diff --git a/src/solver/Makefile b/src/solver/Makefile index bd0fe97b7..e473705db 100644 --- a/src/solver/Makefile +++ b/src/solver/Makefile @@ -1,7 +1,18 @@ -SRC = summarizer_base.cpp summarizer_bw.cpp \ - summarizer_bw_term.cpp summarizer_fw_contexts.cpp \ - summarizer_fw.cpp summarizer_fw_term.cpp \ - summary.cpp summary_db.cpp +SRC = summarizer_base.cpp \ + summarizer_bw.cpp \ + summarizer_bw_term.cpp \ + summarizer_bw_cex.cpp \ + summarizer_bw_cex_ai.cpp \ + summarizer_bw_cex_complete.cpp \ + summarizer_bw_cex_concrete.cpp \ + summarizer_bw_cex_all.cpp \ + summarizer_bw_cex_wp.cpp \ + summarizer_fw_contexts.cpp \ + summarizer_fw.cpp \ + summarizer_fw_term.cpp \ + summary.cpp \ + summary_db.cpp \ + # empty last line include ../config.inc include $(CBMC)/src/config.inc @@ -12,6 +23,8 @@ CP_CXXFLAGS += $(TWOLSFLAGS) INCLUDES= -I $(CBMC)/src -I .. +CP_CXXFLAGS += $(SUMMARIZERFLAGS) + CLEANFILES = solver$(LIBEXT) all: solver$(LIBEXT) diff --git a/src/solver/summarizer_bw_cex.cpp b/src/solver/summarizer_bw_cex.cpp new file mode 100644 index 000000000..33501d783 --- /dev/null +++ b/src/solver/summarizer_bw_cex.cpp @@ -0,0 +1,274 @@ +/*******************************************************************\ + +Module: Counterexample-based Backward Analysis + +Author: Kumar Madhukar, Peter Schrammel + +\*******************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include "summarizer_bw_cex.h" +#include "summary_db.h" + +#include +#include +#include + +#include +#include + + +/*******************************************************************\ + +Function: summarizer_bw_cex_baset::summarize() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void summarizer_bw_cex_baset::summarize() +{ + assert(false); // unused +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_baset::summarize() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void summarizer_bw_cex_baset::summarize(const function_namet &function_name) +{ + exprt postcondition=true_exprt(); // initial calling context + + status() << "\nSummarizing function " << function_name << eom; + compute_summary_rec(function_name, postcondition, true); +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_baset::summarize() + + Inputs: + + Outputs: + + Purpose: summarize backwards from given assertion + +\*******************************************************************/ + +void summarizer_bw_cex_baset::summarize(const exprt &_error_assertion) +{ + status() << "\nBackward error analysis..." << eom; + error_assertion=_error_assertion; + + summarize(entry_function); +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_baset::check() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +property_checkert::resultt summarizer_bw_cex_baset::check() +{ + assert(false); +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_baset::get_loophead_selects + + Inputs: + + Outputs: + + Purpose: returns the select guards at the loop heads + in order to check whether a countermodel is spurious + +\*******************************************************************/ + +void summarizer_bw_cex_baset::get_loophead_selects( + const irep_idt &function_name, + const local_SSAt &SSA, + prop_convt &solver, + exprt::operandst &loophead_selects) +{ + // TODO: this should be provided by unwindable_local_SSA + for(local_SSAt::nodest::const_iterator n_it=SSA.nodes.begin(); + n_it!=SSA.nodes.end(); n_it++) + { + if(n_it->loophead==SSA.nodes.end()) + continue; + symbol_exprt lsguard= + SSA.name(SSA.guard_symbol(), local_SSAt::LOOP_SELECT, n_it->location); + ssa_unwinder.get(function_name).unwinder_rename(lsguard, *n_it, true); + loophead_selects.push_back(not_exprt(lsguard)); + solver.set_frozen(solver.convert(lsguard)); + } + literalt loophead_selects_literal= + solver.convert(conjunction(loophead_selects)); + if(!loophead_selects_literal.is_constant()) + solver.set_frozen(loophead_selects_literal); + +#if 0 + std::cout << "loophead_selects: " + << from_expr(SSA.ns, "", conjunction(loophead_selects)) + << std::endl; +#endif +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_baset::get_loop_continues + + Inputs: + + Outputs: + + Purpose: returns the loop continuation guards at the end of the + loops in order to check whether we can unroll further + +\*******************************************************************/ + +void summarizer_bw_cex_baset::get_loop_continues( + const irep_idt &function_name, + const local_SSAt &SSA, + prop_convt &solver, + exprt::operandst &loop_continues) +{ + // TODO: this should be provided by unwindable_local_SSA + ssa_unwinder.get(function_name).loop_continuation_conditions(loop_continues); + if(loop_continues.size()==0) + { + // TODO: this should actually be done transparently by the unwinder + for(local_SSAt::nodest::const_iterator n_it=SSA.nodes.begin(); + n_it!=SSA.nodes.end(); n_it++) + { + if(n_it->loophead==SSA.nodes.end()) + continue; + symbol_exprt guard=SSA.guard_symbol(n_it->location); + symbol_exprt cond=SSA.cond_symbol(n_it->location); + loop_continues.push_back(and_exprt(guard, cond)); + } + } + +#if 0 + std::cout << "loophead_continues: " + << from_expr(SSA.ns, "", disjunction(loop_continues)) << std::endl; +#endif +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_baset::get_loop_continues + + Inputs: + + Outputs: + + Purpose: returns the loop continuation guards at the end of the + given loop in order to check whether we can unroll further + +\*******************************************************************/ + +void summarizer_bw_cex_baset::get_loop_continues( + const irep_idt &function_name, + const local_SSAt &SSA, + const local_SSAt::locationt &loop_id, + exprt::operandst &loop_continues) +{ + // TODO: need to ask ssa_inliner regarding inlined functions + + // TODO: this should be provided by unwindable_local_SSA + + ssa_unwinder.get(function_name) + .loop_continuation_conditions(loop_id, loop_continues); + if(loop_continues.empty()) + { + // TODO: this should actually be done transparently by the unwinder + for(local_SSAt::nodest::const_iterator n_it=SSA.nodes.begin(); + n_it!=SSA.nodes.end(); n_it++) + { + if(n_it->loophead==SSA.nodes.end()) + continue; + if(n_it->loophead->location!=loop_id) + continue; + symbol_exprt guard=SSA.guard_symbol(n_it->location); + symbol_exprt cond=SSA.cond_symbol(n_it->location); + loop_continues.push_back(and_exprt(guard, cond)); + break; + } + } + +#if 0 + std::cout << "loophead_continues: " + << from_expr(SSA.ns, "", disjunction(loop_continues)) << std::endl; +#endif +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_baset::is_fully_unwound + + Inputs: + + Outputs: + + Purpose: checks whether the loops have been fully unwound + +\*******************************************************************/ + +bool summarizer_bw_cex_baset::is_fully_unwound( + const exprt::operandst &loop_continues, + const exprt::operandst &loophead_selects, + incremental_solvert &solver) +{ + solver.new_context(); + solver << + and_exprt(conjunction(loophead_selects), disjunction(loop_continues)); + + solver_calls++; // statistics + + switch(solver()) + { + case decision_proceduret::D_SATISFIABLE: + solver.pop_context(); + return false; + break; + + case decision_proceduret::D_UNSATISFIABLE: + solver.pop_context(); + solver << conjunction(loophead_selects); + return true; + break; + + case decision_proceduret::D_ERROR: + default: + throw "error from decision procedure"; + } +} diff --git a/src/solver/summarizer_bw_cex.h b/src/solver/summarizer_bw_cex.h new file mode 100644 index 000000000..8e3f70e1b --- /dev/null +++ b/src/solver/summarizer_bw_cex.h @@ -0,0 +1,80 @@ +/*******************************************************************\ + +Module: Counterexample-based Backward Analysis Base + +Author: Kumar Madhukar, Peter Schrammel + +\*******************************************************************/ + +#ifndef CPROVER_2LS_SOLVER_SUMMARIZER_BW_CEX_H +#define CPROVER_2LS_SOLVER_SUMMARIZER_BW_CEX_H + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "summarizer_bw.h" + +class summarizer_bw_cex_baset:public summarizer_bwt +{ +public: + typedef ssa_refiner_selectivet::reasont reasont; + + virtual void summarize(); + virtual void summarize(const function_namet &entry_function); + virtual void summarize(const exprt &_error_assertion); + + virtual property_checkert::resultt check(); + virtual void get_reason(reasont &_reason) { _reason.merge(reason); } + +protected: + function_namet entry_function; + function_namet error_function; + exprt error_assertion; + reasont reason; + + summarizer_bw_cex_baset( + optionst &_options, + summary_dbt &_summary_db, + ssa_dbt &_ssa_db, + ssa_unwindert &_ssa_unwinder, + ssa_inlinert &_ssa_inliner, + function_namet _entry_function, + function_namet _error_function): + summarizer_bwt(_options, _summary_db, _ssa_db, _ssa_unwinder, _ssa_inliner), + entry_function(_entry_function), + error_function(_error_function) + { + } + + void get_loophead_selects( + const irep_idt &function_name, + const local_SSAt &, + prop_convt &, + exprt::operandst &loophead_selects); + + void get_loop_continues( + const irep_idt &function_name, + const local_SSAt &, + prop_convt &, + exprt::operandst &loop_continues); + + void get_loop_continues( + const irep_idt &function_name, + const local_SSAt &SSA, + const local_SSAt::locationt &loop_id, + exprt::operandst &loop_continues); + + bool is_fully_unwound( + const exprt::operandst& loop_continues, + const exprt::operandst& loophead_selects, + incremental_solvert&); +}; + +#endif // CPROVER_2LS_SOLVER_SUMMARIZER_BW_CEX_H diff --git a/src/solver/summarizer_bw_cex_ai.cpp b/src/solver/summarizer_bw_cex_ai.cpp new file mode 100644 index 000000000..8607afa5c --- /dev/null +++ b/src/solver/summarizer_bw_cex_ai.cpp @@ -0,0 +1,529 @@ +/*******************************************************************\ + +Module: Summarizer for Backward Analysis + +Author: Peter Schrammel + +\*******************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include "summarizer_bw_cex_ai.h" +#include "summary_db.h" + +#include "../domains/ssa_analyzer.h" +#include "../domains/template_generator_summary.h" +#include "../domains/template_generator_callingcontext.h" + +#include "../domains/disjunctive_analyzer.h" + +#include "../ssa/local_ssa.h" +#include "../ssa/simplify_ssa.h" + + +/*******************************************************************\ + +Function: summarizer_bw_cex_ait::summarize() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void summarizer_bw_cex_ait::summarize(const function_namet &function_name) +{ + exprt postcondition=true_exprt(); // initial calling context + + status() << "\nSummarizing function " << function_name << eom; + compute_summary_rec( + function_name, summaryt::entry_call_site, postcondition, true); +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_ait::summarize() + + Inputs: + + Outputs: + + Purpose: summarize backwards from given assertion + +\*******************************************************************/ + +void summarizer_bw_cex_ait::summarize(const exprt &_error_assertion) +{ + status() << "\nBackward error analysis (abstract)..." << eom; + error_assertion=_error_assertion; + + summarize(entry_function); +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_ait::check() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +property_checkert::resultt summarizer_bw_cex_ait::check() +{ + property_checkert::resultt result=property_checkert::FAIL; + if(!summary_db.exists(entry_function)) + { + result=property_checkert::UNKNOWN; + } + else + { + const summaryt &summary=summary_db.get(entry_function); + if(summary.error_summaries.empty() || + summary.error_summaries.begin()->second.is_nil() || + summary.error_summaries.begin()->second.is_true()) + result=property_checkert::UNKNOWN; + } + + // we are only complete if we are in the entry function + if(result==property_checkert::UNKNOWN && + entry_function==error_function) + { + incremental_solvert &solver=ssa_db.get_solver(entry_function); + const local_SSAt &ssa=ssa_db.get(entry_function); + exprt::operandst loophead_selects; + exprt::operandst loop_continues; + get_loophead_selects( + entry_function, ssa, *solver.solver, loophead_selects); + get_loop_continues(entry_function, ssa, *solver.solver, loop_continues); + // check whether loops have been fully unwound + bool fully_unwound= + is_fully_unwound(loop_continues, loophead_selects, solver); + status() << "Loops " << (fully_unwound ? "" : "not ") + << "fully unwound" << eom; + + if(fully_unwound) + result=property_checkert::PASS; + } + + return result; +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_ait::compute_summary_rec() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void summarizer_bw_cex_ait::compute_summary_rec( + const function_namet &function_name, + const summaryt::call_sitet &call_site, + const exprt &_postcondition, + bool context_sensitive) +{ + local_SSAt &SSA=ssa_db.get(function_name); + + summaryt summary; + if(summary_db.exists(function_name)) + summary=summary_db.get(function_name); + else + { + summary.params=SSA.params; + summary.globals_in=SSA.globals_in; + summary.globals_out=SSA.globals_out; + summary.nondets=SSA.nondets; + } + + // insert assertion + exprt end_guard=SSA.guard_symbol(--SSA.goto_function.body.instructions.end()); + exprt postcondition=implies_exprt(end_guard, _postcondition); + if(function_name==error_function) + { + postcondition=and_exprt(postcondition, not_exprt(error_assertion)); + } + + summary.bw_postcondition=_postcondition; + +#if 0 + debug() << "Postcondition: " << + from_expr(SSA.ns, "", postcondition) << eom; +#endif + + if(_postcondition.is_false()) + { + summary.error_summaries[call_site]=false_exprt(); + } + else + { + // recursively compute summaries for function calls + inline_summaries( + function_name, + SSA, + summary, + postcondition, + context_sensitive, + true); + + status() << "Analyzing function " << function_name << eom; + + do_summary( + function_name, + call_site, + SSA, + summary, + summary, + postcondition, + context_sensitive); + + if(function_name==error_function) + summary.has_assertion=true; + } + + summary_db.set(function_name, summary); + + { + std::ostringstream out; + out << std::endl << "Summary for function " << function_name << std::endl; + summary_db.get(function_name).output(out, SSA.ns); + debug() << out.str() << eom; + } +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_ait::do_summary() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void summarizer_bw_cex_ait::do_summary( + const function_namet &function_name, + const summaryt::call_sitet &call_site, + local_SSAt &SSA, + const summaryt &old_summary, + summaryt &summary, + const exprt &postcondition, + bool context_sensitive) +{ + status() << "Computing error summary" << eom; + + // solver + incremental_solvert &solver=ssa_db.get_solver(function_name); + solver.set_message_handler(get_message_handler()); + + // TODO: maybe allow setting this separately on the command line + optionst _options=options; + _options.set_option("intervals", true); + _options.set_option("binsearch-solver", true); + + // TODO: use a template generator without invariants + template_generator_summaryt template_generator( + _options, ssa_db, ssa_unwinder.get(function_name)); + template_generator.set_message_handler(get_message_handler()); + template_generator(solver.next_domain_number(), SSA, false); + + exprt::operandst c; + // add forward information if available + if(!old_summary.fw_precondition.is_nil()) + c.push_back(old_summary.fw_precondition); + if(!old_summary.fw_invariant.is_nil()) + c.push_back(old_summary.fw_invariant); + c.push_back(ssa_inliner.get_summaries(SSA)); // forward summaries + exprt::operandst assert_postcond, noassert_postcond; + // add error summaries for function calls + bool assertion_flag; + // backward summaries + assertion_flag= + ssa_inliner.get_summaries( + SSA, call_site, false, assert_postcond, noassert_postcond, c); + + assert_postcond.push_back(postcondition); // context + + // add nondet variables from callees to summary.nondets + std::set summary_vars; + find_symbols(conjunction(assert_postcond), summary_vars); + for(const auto &var : summary_vars) + { + if(var.id()==ID_nondet_symbol) + summary.nondets.insert(var); + } + + // assumptions must hold + for(const auto &node : SSA.nodes) + for(const auto &assumption : node.assumptions) + c.push_back(assumption); + +#if 0 + std::cout << from_expr(SSA.ns, "", cc) << std::endl; +#endif + + // TODO: pushing loophead_selects into the solver + + summary.error_summaries[call_site]; + if(!template_generator.empty()) + { + // with negative information would need: not_exprt + c.push_back(conjunction(assert_postcond)); + // with negative information would need: not_exprt dis + c.push_back(conjunction(noassert_postcond)); + + exprt cc=simplify_expr(conjunction(c), SSA.ns); + + disjunctive_analyzert disjunctive_analyzer; + disjunctive_analyzer.set_message_handler(get_message_handler()); + disjunctive_analyzer( + solver, + SSA, + cc, + template_generator, + cc, + summary.error_summaries[call_site], + template_generator.inout_vars()); + +#if 0 + std::cout << "SUM: " + << from_expr(SSA.ns, "", summary.error_summaries[call_site]) + << std::endl; +#endif + + summary.error_summaries[call_site]= + simplify_expr(summary.error_summaries[call_site], SSA.ns); + +#if 0 + std::cout << "SUM (post simplification): " + << from_expr(SSA.ns, "", summary.error_summaries[call_site]) + << std::endl; +#endif + + // statistics + solver_instances+=disjunctive_analyzer.get_number_of_solver_instances(); + solver_calls+=disjunctive_analyzer.get_number_of_solver_calls(); + } + else + { + // TODO: yet another workaround for ssa_analyzer + // not being able to handle empty templates properly + + // with negative information would need: not_exprt + c.push_back(conjunction(assert_postcond)); + // with negative information would need: not_exprt dis + c.push_back(conjunction(noassert_postcond)); + // c.push_back(not_exprt(conjunction(assert_postcond))); + // c.push_back(not_exprt(disjunction(noassert_postcond))); + + exprt cc=simplify_expr(conjunction(c), SSA.ns); + + solver << SSA; + solver.new_context(); + solver << SSA.get_enabling_exprs(); + solver << cc; + exprt result=true_exprt(); + if(solver()!=decision_proceduret::D_SATISFIABLE) + result=false_exprt(); + solver.pop_context(); + summary.error_summaries[call_site]=result; + +#if 0 + std::cout << "SUM: " + << from_expr(SSA.ns, "", summary.error_summaries[call_site]) + << std::endl; +#endif + } + + summary.error_summaries[call_site]= + simplify_expr((summary.error_summaries[call_site]), SSA.ns); // not_exprt + + summary.has_assertion=assertion_flag; +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_ait::inline_summaries() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void summarizer_bw_cex_ait::inline_summaries( + const function_namet &function_name, + local_SSAt &SSA, + const summaryt &old_summary, + const exprt &postcondition, + bool context_sensitive, + bool sufficient) +{ + for(local_SSAt::nodest::const_iterator n_it=SSA.nodes.end(); + n_it!=SSA.nodes.begin(); ) + { + n_it--; + + for(local_SSAt::nodet::function_callst::const_iterator f_it= + n_it->function_calls.begin(); + f_it!=n_it->function_calls.end(); f_it++) + { + assert(f_it->function().id()==ID_symbol); // no function pointers + + exprt postcondition_call=true_exprt(); + postcondition_call=compute_calling_context2( + function_name, SSA, old_summary, n_it, f_it, postcondition, sufficient); + + irep_idt fname=to_symbol_expr(f_it->function()).get_identifier(); + status() << "Recursively summarizing function " << fname << eom; + compute_summary_rec( + fname, + summaryt::call_sitet(n_it->location), + postcondition_call, + context_sensitive); + } + } +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_ait::compute_calling_context2() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +exprt summarizer_bw_cex_ait::compute_calling_context2( + const function_namet &function_name, + local_SSAt &SSA, + summaryt old_summary, + local_SSAt::nodest::const_iterator n_it, + local_SSAt::nodet::function_callst::const_iterator f_it, + const exprt &postcondition, + bool sufficient) +{ + assert(f_it->function().id()==ID_symbol); // no function pointers + irep_idt fname=to_symbol_expr(f_it->function()).get_identifier(); + + status() << "Computing calling context for function " << fname << eom; + + // solver + incremental_solvert &solver=ssa_db.get_solver(function_name); + solver.set_message_handler(get_message_handler()); + + // analyze + disjunctive_analyzert disjunctive_analyzer; + disjunctive_analyzer.set_message_handler(get_message_handler()); + + // TODO: maybe allow setting this separately on the command line + optionst _options=options; + _options.set_option("intervals", true); + _options.set_option("binsearch-solver", true); + + // TODO: use a template generator without invariants + template_generator_callingcontextt template_generator( + _options, ssa_db, ssa_unwinder.get(function_name)); + template_generator.set_message_handler(get_message_handler()); + template_generator(solver.next_domain_number(), SSA, n_it, f_it, false); + + // collect globals at call site + std::map< + local_SSAt::nodet::function_callst::const_iterator, + local_SSAt::var_sett> + cs_globals_out; + SSA.get_globals(n_it->location, cs_globals_out[f_it], false); + + exprt::operandst c; + + // add forward information if available + if(!old_summary.fw_precondition.is_nil()) + c.push_back(old_summary.fw_precondition); + if(!old_summary.fw_invariant.is_nil()) + c.push_back(old_summary.fw_invariant); + c.push_back(ssa_inliner.get_summaries(SSA)); // forward summaries + + exprt::operandst assert_postcond, noassert_postcond; + // add error summaries for function calls + ssa_inliner.get_summaries(SSA, summaryt::call_sitet(n_it->location), false, + assert_postcond, noassert_postcond, c); // backward summaries + assert_postcond.push_back(postcondition); // context + + + // TODO: pushing loophead_selects into the solver + + // set preconditions + local_SSAt &fSSA=ssa_db.get(fname); + + exprt postcondition_call; + + if(!template_generator.empty()) + { + // with negative information would need: not_exprt + c.push_back(conjunction(assert_postcond)); + // with negative information would need: not_exprt dis + c.push_back(conjunction(noassert_postcond)); + + disjunctive_analyzer(solver, SSA, conjunction(c), template_generator, + conjunction(c), postcondition_call, + template_generator.callingcontext_vars()); + + ssa_inliner.rename_to_callee( + f_it, + fSSA.params, + cs_globals_out[f_it], + fSSA.globals_out, + postcondition_call); + } + else + { + // TODO: yet another workaround for ssa_analyzer + // not being able to handle empty templates properly + + c.push_back(not_exprt(conjunction(assert_postcond))); + c.push_back(not_exprt(disjunction(noassert_postcond))); + + solver << SSA; + solver.new_context(); + solver << SSA.get_enabling_exprs(); + solver << conjunction(c); + + postcondition_call=false_exprt(); + if(solver()!=decision_proceduret::D_SATISFIABLE) + postcondition_call=true_exprt(); + solver.pop_context(); + } + + debug() << "Backward calling context for " + << from_expr(SSA.ns, "", *f_it) << ": " + << from_expr(SSA.ns, "", postcondition_call) << eom; + + // statistics + solver_instances+=disjunctive_analyzer.get_number_of_solver_instances(); + solver_calls+=disjunctive_analyzer.get_number_of_solver_calls(); + + return postcondition_call; +} + diff --git a/src/solver/summarizer_bw_cex_ai.h b/src/solver/summarizer_bw_cex_ai.h new file mode 100644 index 000000000..af779376f --- /dev/null +++ b/src/solver/summarizer_bw_cex_ai.h @@ -0,0 +1,84 @@ +/*******************************************************************\ + +Module: Summarizer for Backwards Error Analysis + +Author: Kumar Madhukar, Peter Schrammel + +\*******************************************************************/ + +#ifndef CPROVER_2LS_SOLVER_SUMMARIZER_BW_CEX_AI_H +#define CPROVER_2LS_SOLVER_SUMMARIZER_BW_CEX_AI_H + +#include +#include +#include +#include +#include +#include + +#include + +#include "summarizer_bw_cex.h" + +class summarizer_bw_cex_ait:public summarizer_bw_cex_baset +{ +public: + summarizer_bw_cex_ait( + optionst &_options, + summary_dbt &_summary_db, + ssa_dbt &_ssa_db, + ssa_unwindert &_ssa_unwinder, + ssa_inlinert &_ssa_inliner, + function_namet _entry_function, + function_namet _error_function): + summarizer_bw_cex_baset( + _options, + _summary_db, + _ssa_db, + _ssa_unwinder, + _ssa_inliner, + _entry_function, + _error_function) + { + } + + virtual void summarize(const function_namet &entry_function); + virtual void summarize(const exprt &_error_assertion); + + virtual property_checkert::resultt check(); + +protected: + virtual void compute_summary_rec( + const function_namet &function_name, + const summaryt::call_sitet &call_site, + const exprt &postcondition, + bool context_sensitive); + + virtual void inline_summaries( + const function_namet &function_name, + local_SSAt &SSA, + const summaryt &old_summary, + const exprt &postcondition, + bool context_sensitive, + bool sufficient); + + virtual void do_summary( + const function_namet &function_name, + const summaryt::call_sitet &call_site, + local_SSAt &SSA, + const summaryt &old_summary, + summaryt &summary, + const exprt &postcondition, + bool context_sensitive); + + virtual exprt compute_calling_context2( + const function_namet &function_name, + local_SSAt &SSA, + summaryt old_summary, + local_SSAt::nodest::const_iterator n_it, + local_SSAt::nodet::function_callst::const_iterator f_it, + const exprt &postcondition, + bool sufficient); +}; + +#endif // CPROVER_2LS_SOLVER_SUMMARIZER_BW_CEX_AI_H diff --git a/src/solver/summarizer_bw_cex_all.cpp b/src/solver/summarizer_bw_cex_all.cpp new file mode 100644 index 000000000..4b1052fcc --- /dev/null +++ b/src/solver/summarizer_bw_cex_all.cpp @@ -0,0 +1,75 @@ +/*******************************************************************\ + +Module: Counterexample-based Backward Analysis + +Author: Kumar Madhukar, Peter Schrammel + +\*******************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include "summarizer_bw_cex_all.h" + +#include "../domains/ssa_analyzer.h" +#include "../domains/template_generator_summary.h" +#include "../domains/template_generator_callingcontext.h" + +#include "../ssa/local_ssa.h" +#include "../ssa/simplify_ssa.h" + + +/*******************************************************************\ + +Function: summarizer_bw_cex_allt::summarize() + + Inputs: + + Outputs: + + Purpose: calls multiple strategies + +\*******************************************************************/ + +void summarizer_bw_cex_allt::summarize(const exprt &_error_assertion) +{ + status() << "\nBackward error analysis (all)..." << eom; + error_assertion=_error_assertion; + + summarizer_bw_cex_concrete.summarize(error_assertion); + result=summarizer_bw_cex_concrete.check(); + + if(result==property_checkert::UNKNOWN) + { + summarizer_bw_cex_ai.summarize(error_assertion); + result=summarizer_bw_cex_ai.check(); + + if(result==property_checkert::UNKNOWN) + { + summarizer_bw_cex_complete.summarize(error_assertion); + result=summarizer_bw_cex_complete.check(); + } + } +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_allt::check() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +property_checkert::resultt summarizer_bw_cex_allt::check() +{ + return result; +} diff --git a/src/solver/summarizer_bw_cex_all.h b/src/solver/summarizer_bw_cex_all.h new file mode 100644 index 000000000..c12afcf8b --- /dev/null +++ b/src/solver/summarizer_bw_cex_all.h @@ -0,0 +1,93 @@ +/*******************************************************************\ + +Module: Counterexample-based Backward Analysis All + +Author: Kumar Madhukar, Peter Schrammel + +\*******************************************************************/ + +#ifndef CPROVER_2LS_SOLVER_SUMMARIZER_BW_CEX_ALL_H +#define CPROVER_2LS_SOLVER_SUMMARIZER_BW_CEX_ALL_H + +#include +#include +#include +#include +#include +#include +#include + +#include "summarizer_bw_cex.h" +#include "summarizer_bw_cex_concrete.h" +#include "summarizer_bw_cex_ai.h" +#include "summarizer_bw_cex_complete.h" + +class summarizer_bw_cex_allt:public summarizer_bw_cex_baset +{ +public: + summarizer_bw_cex_allt( + optionst &_options, + summary_dbt &_summary_db, + ssa_dbt &_ssa_db, + ssa_unwindert &_ssa_unwinder, + ssa_inlinert &_ssa_inliner, + incremental_solvert &_solver, + function_namet _entry_function, + function_namet _error_function): + summarizer_bw_cex_baset( + _options, + _summary_db, + _ssa_db, + _ssa_unwinder, + _ssa_inliner, + _entry_function, + _error_function), + summarizer_bw_cex_concrete( + _options, + _summary_db, + _ssa_db, + _ssa_unwinder, + _ssa_inliner, + _entry_function, + _error_function), + summarizer_bw_cex_ai( + _options, + _summary_db, + _ssa_db, + _ssa_unwinder, + _ssa_inliner, + _entry_function, + _error_function), + summarizer_bw_cex_complete( + _options, + _summary_db, + _ssa_db, + _ssa_unwinder, + _ssa_inliner, + _solver, + _entry_function, + _error_function), + result(property_checkert::UNKNOWN) + { + } + + virtual void summarize(const exprt &_error_assertion); + + virtual void set_message_handler(message_handlert &handler) + { + summarizer_bw_cex_concrete.set_message_handler(handler); + summarizer_bw_cex_ai.set_message_handler(handler); + summarizer_bw_cex_complete.set_message_handler(handler); + messaget::set_message_handler(handler); + } + + virtual property_checkert::resultt check(); + + protected: + summarizer_bw_cex_concretet summarizer_bw_cex_concrete; + summarizer_bw_cex_ait summarizer_bw_cex_ai; + summarizer_bw_cex_completet summarizer_bw_cex_complete; + property_checkert::resultt result; +}; + +#endif // CPROVER_2LS_SOLVER_SUMMARIZER_BW_CEX_ALL_H diff --git a/src/solver/summarizer_bw_cex_complete.cpp b/src/solver/summarizer_bw_cex_complete.cpp new file mode 100644 index 000000000..7df4f3c23 --- /dev/null +++ b/src/solver/summarizer_bw_cex_complete.cpp @@ -0,0 +1,735 @@ +/*******************************************************************\ + +Module: Simple Complete Counterexample-based Backward Analysis + +Author: Madhukar Kumar, Peter Schrammel + +\*******************************************************************/ + +#ifdef DEBUG +#include +#endif + +#include +#include +#include +#include +#include + +#include "summary_db.h" + +#include +#include +#include + +#include +#include +#include + +#include "summarizer_bw_cex_complete.h" + +#define REFINE_ALL + +/*******************************************************************\ + +Function: summarizer_bw_cex_completet::summarize() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void summarizer_bw_cex_completet::summarize +( + const function_namet &entry_function) +{ + // no dependencies to begin with + find_symbols_sett dependency_set; + + status() << "\nSummarizing function " << entry_function << eom; + compute_summary_rec(entry_function, dependency_set, -1); +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_completet::summarize() + + Inputs: + + Outputs: + + Purpose: summarize backwards from given assertion + +\*******************************************************************/ + +void summarizer_bw_cex_completet::summarize(const exprt &_error_assertion) +{ + status() << "\nBackward error analysis (complete)..." << eom; + error_assertion=_error_assertion; + ssa_inliner.rename(error_assertion, -1, false); + /* + std::cout << "error assertion: " + << from_expr(ssa_db.get(entry_function).ns, "", error_assertion) + << "\n"; + */ + summarize(entry_function); +} + + +/*******************************************************************\ + +Function: summarizer_bw_cex_completet::inline_summaries() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +find_symbols_sett summarizer_bw_cex_completet::inline_summaries +( + const function_namet &function_name, + find_symbols_sett &dependency_set, + int counter) +{ + local_SSAt &SSA=ssa_db.get(function_name); +#if 0 + ssa_local_unwindert &ssa_local_unwinder=ssa_unwinder.get(function_name); + ssa_local_unwinder.compute_loop_continuation_conditions(); +#endif + // add enabling expressions + exprt enable_exprs=SSA.get_enabling_exprs(); + ssa_inliner.rename(enable_exprs, counter); + + solver << enable_exprs; + + // assumptions must hold + for(local_SSAt::nodest::const_iterator + n_it=SSA.nodes.begin(); n_it!=SSA.nodes.end(); ++n_it) + for(local_SSAt::nodet::assumptionst::const_iterator + a_it=n_it->assumptions.begin(); a_it!=n_it->assumptions.end(); ++a_it) + { + exprt assumption=*a_it; + ssa_inliner.rename(assumption, counter); + solver << assumption; + } + +#ifdef REFINE_ALL + // TODO: let's just put all loops into the reason + for(const auto node : SSA.nodes) + if(node.loophead!=SSA.nodes.end()) + reason[function_name].loops.insert(node.loophead->location); +#endif + + ssa_dependency_grapht &ssa_depgraph=ssa_db.get_depgraph(function_name); + + struct worknodet + { + int node_index; + find_symbols_sett dependency_set; + }; + + worknodet start_node; + start_node.node_index=0; + start_node.dependency_set=dependency_set; + + typedef std::list worklistt; + worklistt worklist, work_waitlist; + std::vector covered_nodes; + + worklist.push_back(start_node); + + while(!worklist.empty()) + { +#ifdef DEBUG + std::cout << "worklist: "; + for(worklistt::const_iterator w_it=worklist.begin(); + w_it!=worklist.end(); w_it++) + { + std::cout << w_it->node_index << " "; + } + std::cout << "\n"; + + std::cout << "\t waitlist: "; + for(worklistt::const_iterator w_it=work_waitlist.begin(); + w_it!=work_waitlist.end(); w_it++) + { + std::cout << w_it->node_index << " "; + } + std::cout << "\n"; +#endif + + worknodet &worknode=worklist.front(); + const ssa_dependency_grapht::depnodet &depnode= + ssa_depgraph.depnodes_map[worknode.node_index]; + +#ifdef DEBUG + std::cout << "working node: " << function_name << ": " + << worknode.node_index << "\n"; + std::cout << "\t size of dependency set: " + << worknode.dependency_set.size() << "\n"; + std::cout << "\t dependency set: "; + for(find_symbols_sett::iterator d_it=worknode.dependency_set.begin(); + d_it!=worknode.dependency_set.end(); d_it++) + { + std::cout << *d_it; + } + std::cout << "\n\n\n"; +#endif + + // return if the top most node is reached + if(worknode.node_index==ssa_depgraph.top_node_index) + return worknode.dependency_set; + + // modify worknode_dependency_set if the node is an assertion + if(depnode.is_assertion==true) + { +#ifdef DEBUG + std::cout << "\t\t an assertion node\n"; +#endif + for(find_symbols_sett::const_iterator d_it=depnode.used_symbols.begin(); + d_it!=depnode.used_symbols.end(); d_it++) + { + worknode.dependency_set.insert(*d_it); + } + +#ifdef DEBUG + std::cout << "\t size of dependency set: " + << worknode.dependency_set.size() << "\n"; + + std::cout << "\t dependency set: "; + for(find_symbols_sett::iterator d_it=worknode.dependency_set.begin(); + d_it!=worknode.dependency_set.end(); d_it++) + { + std::cout << *d_it; + } + std::cout << "\n"; +#endif + } + + // if this is a function call + if(depnode.is_function_call==true) + { +#ifdef DEBUG + std::cout << "fcall: working node: " << function_name << ": " + << worknode.node_index << "\n"; +#endif + irep_idt fname= + to_symbol_expr( + (to_function_application_expr(depnode.node_info)).function()) + .get_identifier(); + + find_symbols_sett renamed_dependencies; + +#ifdef DEBUG + std::cout << "\t size of dependency set: " + << worknode.dependency_set.size() << "\n"; + + std::cout << "\t dependency set: "; + for(find_symbols_sett::iterator d_it=worknode.dependency_set.begin(); + d_it!=worknode.dependency_set.end(); d_it++) + { + std::cout << *d_it; + } + std::cout << "\n"; +#endif + + for(find_symbols_sett::iterator d_it=worknode.dependency_set.begin(); + d_it!=worknode.dependency_set.end(); d_it++) + { + irep_idt renamed_id=*d_it; + // detach the '@' symbol if there + ssa_inliner.rename(renamed_id, depnode.rename_counter, false); + renamed_dependencies.insert(renamed_id); + } + + worknode.dependency_set=renamed_dependencies; + + if(!worknode.dependency_set.empty()) + { + find_symbols_sett guard_dependencies; + find_symbols(depnode.guard, guard_dependencies); + for(find_symbols_sett::const_iterator d_it=guard_dependencies.begin(); + d_it!=guard_dependencies.end(); d_it++) + { + worknode.dependency_set.insert(*d_it); + } + } + +#ifdef DEBUG + std::cout << "\t size of dependency set: " + << worknode.dependency_set.size() << "\n"; + + std::cout << "\t dependency set: "; + for(find_symbols_sett::iterator d_it=worknode.dependency_set.begin(); + d_it!=worknode.dependency_set.end(); d_it++) + { + std::cout << *d_it; + } + std::cout << "\n"; +#endif + +#ifdef REFINE_ALL + // TODO: just put all function calls into reason + reason[function_name].functions.insert(depnode.location); +#endif + + // recurse + worknode.dependency_set= + compute_summary_rec( + fname, worknode.dependency_set, depnode.rename_counter); + + renamed_dependencies.clear(); + + for(find_symbols_sett::iterator d_it=worknode.dependency_set.begin(); + d_it!=worknode.dependency_set.end(); d_it++) + { + irep_idt renamed_id=*d_it; + // attach the '@' symbol if not already there + ssa_inliner.rename(renamed_id, depnode.rename_counter, true); + renamed_dependencies.insert(renamed_id); + } + + worknode.dependency_set=renamed_dependencies; + + if(!worknode.dependency_set.empty()) + { + find_symbols_sett guard_dependencies; + find_symbols(depnode.guard, guard_dependencies); + for(find_symbols_sett::const_iterator d_it=guard_dependencies.begin(); + d_it!=guard_dependencies.end(); d_it++) + { + worknode.dependency_set.insert(*d_it); + } + } + } + + // if the dependency set is non-empty + if(!worknode.dependency_set.empty()) + { + exprt worknode_info=depnode.node_info; + + bool is_error_assertion=false; + if(depnode.is_assertion) + { +#ifdef DEBUG + std::cout << "assertion: " << from_expr(SSA.ns, "", error_assertion) + << std::endl; + std::cout << "to check: " << from_expr(SSA.ns, "", worknode_info) + << std::endl; +#endif + assert(error_assertion.id()==ID_not); + if(error_assertion.op0().id()!=ID_and) + is_error_assertion=(worknode_info==error_assertion.op0()); + else + { + forall_operands(a_it, error_assertion.op0()) + { + if(worknode_info==*a_it) + { + is_error_assertion=true; + break; + } + } + } + } + + if(worknode.node_index!=0) + { + if(!(depnode.is_function_call)) + { + if(!depnode.is_assertion || is_error_assertion) + { +#ifdef DEBUG + std::cout << "Solver <-- " << function_name << ": (node) node#:" + << worknode.node_index << "\t original info ~ " + << from_expr( + (ssa_db.get(function_name)).ns, "", worknode_info) + << "\n"; +#endif + ssa_inliner.rename(worknode_info, counter); +#if 0 + std::cout << "Solver <-- renamed assertion: " + << from_expr( + (ssa_db.get(function_name)).ns, "", worknode_info) + << "\n"; + std::cout << "Solver <-- " << function_name << ": (node) node#:" + << worknode.node_index << "\t renamed info ~ " + << from_expr( + (ssa_db.get(function_name)).ns, "", worknode_info) + << "\n"; +#endif + + if(depnode.is_assertion) // keep for later + renamed_error_assertion.push_back(worknode_info); + else + solver << worknode_info; + + if(depnode.is_loop) + { + // loop head selects + exprt lsguard=depnode.guard; + ssa_inliner.rename(lsguard, counter); + loophead_selects.push_back(lsguard); + add_reason_to_check( + lsguard, function_name, false, depnode.location); + + // loop continuations + exprt::operandst local_loop_continues; + get_loop_continues( + function_name, SSA, depnode.location, local_loop_continues); + for(size_t i=0; inode_index==pred_node_index) + { + dependencies_merged=true; + + for(find_symbols_sett::const_iterator + a_it=pred_annotation.begin(); + a_it!=pred_annotation.end(); a_it++) + { + if(worknode.dependency_set.find(*a_it)!= + worknode.dependency_set.end()) + { + if((w_it->dependency_set).find(*a_it)== + (w_it->dependency_set).end()) + { + (w_it->dependency_set).insert(*a_it); + } + } + } + break; + } + } + + if(dependencies_merged==false) + { + worknodet new_worknode; + new_worknode.node_index=pred_node_index; + + for(find_symbols_sett::const_iterator + a_it=pred_annotation.begin(); a_it!=pred_annotation.end(); a_it++) + { + if(worknode.dependency_set.find(*a_it)!=worknode.dependency_set.end()) + new_worknode.dependency_set.insert(*a_it); + } + + work_waitlist.push_back(new_worknode); + } + } + +#if 0 + std::cout << function_name << ": worklist: "; + for(worklistt::const_iterator w_it=worklist.begin(); + w_it!=worklist.end(); w_it++) + { + std::cout << w_it->node_index << " "; + } + std::cout << "\n"; + + + std::cout << "\t" << function_name << ": waitlist: "; + for(worklistt::const_iterator w_it=work_waitlist.begin(); + w_it!=work_waitlist.end(); w_it++) + { + std::cout << w_it->node_index << " "; + } + std::cout << "\n"; +#endif + + covered_nodes.push_back(worknode.node_index); + worklist.pop_front(); + +#if 0 + std::cout << function_name << ": covered : "; + for(int l=0; l &waitlisted_worknode_successors= + ssa_depgraph.depnodes_map[waitlisted_worknode.node_index].successors; + + for(unsigned i=0; iconvert(not_exprt(conjunction(renamed_error_assertion)))); + solver.solver->set_assumptions(formula); +#endif + + solver_calls++; // for statistics + if(solver()==decision_proceduret::D_SATISFIABLE) + { + // pop_context() not necessary + return property_checkert::FAIL; + } +#ifndef REFINE_ALL + else + { + const namespacet &ns=ssa_db.get(entry_function).ns; + // get reasons for spuriousness + for(unsigned i=0; iis_in_conflict(formula[i])) + { + debug() << "is_in_conflict: " + << from_expr(ns, "", formula_expr[i]) << eom; + const reason_to_checkt &r=reasons_to_check[i]; + if(r.is_function) + reason[r.function_name].functions.insert(r.info); + else + reason[r.function_name].loops.insert(r.info); + } + } + bvt assumptions; + solver.solver->set_assumptions(assumptions); + for(unsigned i=0; i " << function_name + << " ; dependency_set -> "; + for(find_symbols_sett::iterator d_it=dependency_set.begin(); + d_it!=dependency_set.end(); d_it++) + { + std::cout << *d_it << ", "; + } + std::cout << "\n"; +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_completet::add_reason_to_check + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void summarizer_bw_cex_completet::add_reason_to_check( + const exprt &expr, + const function_namet &function_name, + bool is_function, + const local_SSAt::locationt & info) +{ + literalt l=solver.solver->convert(expr); + if(l.is_false()) + { + literalt dummy= + solver.solver->convert(symbol_exprt("goto_symex::\\dummy", bool_typet())); + formula.push_back(dummy); + formula.push_back(!dummy); + } + else if(!l.is_true()) + { + formula.push_back(l); + formula_expr.push_back(expr); + reasons_to_check.push_back(reason_to_checkt()); + reason_to_checkt &r=reasons_to_check.back(); + r.function_name=function_name; + r.info=info; + r.is_function=is_function; + } +} diff --git a/src/solver/summarizer_bw_cex_complete.h b/src/solver/summarizer_bw_cex_complete.h new file mode 100644 index 000000000..098395872 --- /dev/null +++ b/src/solver/summarizer_bw_cex_complete.h @@ -0,0 +1,88 @@ +/*******************************************************************\ + +Module: Simple Complete Counterexample-based Backward Analysis + +Author: Madhukar Kumar, Peter Schrammel + +\*******************************************************************/ + +#ifndef CPROVER_2LS_SOLVER_SUMMARIZER_BW_CEX_COMPLETE_H +#define CPROVER_2LS_SOLVER_SUMMARIZER_BW_CEX_COMPLETE_H + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "summarizer_bw_cex.h" + +class summarizer_bw_cex_completet:public summarizer_bw_cex_baset +{ +public: + summarizer_bw_cex_completet( + optionst &_options, + summary_dbt &_summary_db, + ssa_dbt &_ssa_db, + ssa_unwindert &_ssa_unwinder, + ssa_inlinert &_ssa_inliner, + incremental_solvert &_solver, + function_namet _entry_function, + function_namet _error_function): + summarizer_bw_cex_baset( + _options, + _summary_db, + _ssa_db, + _ssa_unwinder, + _ssa_inliner, + _entry_function, + _error_function), + solver(_solver) + { + } + + virtual void summarize(const function_namet &entry_function); + virtual void summarize(const exprt &_error_assertion); + + virtual property_checkert::resultt check(); + + protected: + incremental_solvert &solver; + bvt formula; // for UNSAT core + exprt::operandst formula_expr; // for debugging + exprt::operandst loophead_selects; + exprt::operandst loop_continues; + exprt::operandst renamed_error_assertion; + + struct reason_to_checkt + { + function_namet function_name; + bool is_function; + local_SSAt::locationt info; + }; + std::vector reasons_to_check; + void add_reason_to_check( + const exprt &expr, + const function_namet &function_name, + bool is_function, + const local_SSAt::locationt &info); + + virtual find_symbols_sett inline_summaries( + const function_namet &function_name, + find_symbols_sett &dependency_set, + int counter); + + virtual find_symbols_sett compute_summary_rec( + const function_namet &function_name, + find_symbols_sett &dependency_set, + int counter); + virtual void debug_print( + const function_namet &function_name, + find_symbols_sett &dependency_set); +}; + +#endif // CPROVER_2LS_SOLVER_SUMMARIZER_BW_CEX_COMPLETE_H diff --git a/src/solver/summarizer_bw_cex_concrete.cpp b/src/solver/summarizer_bw_cex_concrete.cpp new file mode 100644 index 000000000..0e08832bf --- /dev/null +++ b/src/solver/summarizer_bw_cex_concrete.cpp @@ -0,0 +1,657 @@ +/*******************************************************************\ + +Module: Simple Counterexample-based Backward Analysis + +Author: Kumar Madhukar, Peter Schrammel + +\*******************************************************************/ + +// #define OPT_11 // simplify before pushing to solver +#define OPT_12 // collect, conjunct, simplify and then push to the solver + +// #define OPT_2 // a fresh solver each time + +// TODO: a bug in the fresh solver case; does not compute +// calling contexts (see struct tests in regression) + +// #define DEBUG + +#ifdef DEBUG +#include +#endif + +#include +#include +#include +#include +#include + +#include "summarizer_bw_cex_concrete.h" +#include "summary_db.h" + +#include +#include +#include + +#include +#include + +/*******************************************************************\ + +Function: summarizer_bw_cex_concretet::summarize() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void summarizer_bw_cex_concretet::summarize(const function_namet &function_name) +{ + exprt postcondition=true_exprt(); // initial calling context + + status() << "\nSummarizing function " << function_name << eom; + compute_summary_rec( + function_name, summaryt::entry_call_site, postcondition, true); +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_concretet::summarize() + + Inputs: + + Outputs: + + Purpose: summarize backwards from given assertion + +\*******************************************************************/ + +void summarizer_bw_cex_concretet::summarize(const exprt &_error_assertion) +{ + status() << "\nBackward error analysis (concrete)..." << eom; + error_assertion=_error_assertion; + + summarize(entry_function); +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_concretet::check() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +property_checkert::resultt summarizer_bw_cex_concretet::check() +{ + property_checkert::resultt result=property_checkert::UNKNOWN; + if(summary_db.exists(entry_function)) + { + const summaryt &summary=summary_db.get(entry_function); + if(!summary.error_summaries.empty() && + !summary.error_summaries.begin()->second.is_nil()) + { + if(summary.error_summaries.begin()->second.is_false()) + result=property_checkert::PASS; + else + result=property_checkert::FAIL; + } + } + + // we are only complete if everything was inlined + if(result==property_checkert::UNKNOWN && + options.get_bool_option("inline")) + { + incremental_solvert &solver=ssa_db.get_solver(entry_function); + const local_SSAt &ssa=ssa_db.get(entry_function); + exprt::operandst loophead_selects; + exprt::operandst loop_continues; + get_loophead_selects( + entry_function, ssa, *solver.solver, loophead_selects); + get_loop_continues(entry_function, ssa, *solver.solver, loop_continues); + // check whether loops have been fully unwound + bool fully_unwound= + is_fully_unwound(loop_continues, loophead_selects, solver); + status() << "Loops " << (fully_unwound ? "" : "not ") + << "fully unwound" << eom; + + if(fully_unwound) + result=property_checkert::PASS; + } + + return result; +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_concretet::compute_summary_rec() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void summarizer_bw_cex_concretet::compute_summary_rec( + const function_namet &function_name, + const summaryt::call_sitet &call_site, + const exprt &_postcondition, + bool context_sensitive) +{ + local_SSAt &SSA=ssa_db.get(function_name); + + // TODO: let's just put all loops into the reason + for(const auto &node : SSA.nodes) + if(node.loophead!=SSA.nodes.end()) + reason[function_name].loops.insert(node.loophead->location); + + summaryt summary; + if(summary_db.exists(function_name)) + summary=summary_db.get(function_name); + else + { + summary.params=SSA.params; + summary.globals_in=SSA.globals_in; + summary.globals_out=SSA.globals_out; + summary.nondets=SSA.nondets; + } + + // insert assertion + exprt end_guard=SSA.guard_symbol(--SSA.goto_function.body.instructions.end()); + exprt postcondition=implies_exprt(end_guard, _postcondition); + if(function_name==error_function) + { + postcondition=and_exprt(postcondition, not_exprt(error_assertion)); + } + + summary.bw_postcondition=_postcondition; + +#if 0 + debug() << "Postcondition: " << from_expr(SSA.ns, "", postcondition) << eom; +#endif + + // recursively compute summaries for function calls + inline_summaries( + function_name, + SSA, + summary, + postcondition, + context_sensitive, + true); + + status() << "Analyzing function " << function_name << eom; + + do_summary( + function_name, + call_site, + SSA, + summary, + summary, + postcondition, + context_sensitive); + + if(function_name==error_function) + summary.has_assertion=true; + + summary_db.set(function_name, summary); + + { + std::ostringstream out; + out << std::endl << "Summary for function " << function_name << std::endl; + summary_db.get(function_name).output(out, SSA.ns); + debug() << out.str() << eom; + } +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_concretet::do_summary() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void summarizer_bw_cex_concretet::do_summary( + const function_namet &function_name, + const summaryt::call_sitet &call_site, + local_SSAt &SSA, + const summaryt &old_summary, + summaryt &summary, + const exprt &postcondition, + bool context_sensitive) +{ + status() << "Computing error summary" << eom; + + // solver + +#ifdef OPT_2 + incremental_solvert *fresh_solver= + incremental_solvert::allocate(SSA.ns, options.get_bool_option("refine")); + incremental_solvert &solver=(*fresh_solver); + SSA.unmark_nodes(); + exprt::operandst store; +#else + incremental_solvert &solver=ssa_db.get_solver(function_name); +#endif + + solver.set_message_handler(get_message_handler()); + + // ENHANCE: we could reuse the solver state, but it's difficult + // (the function maybe called several times) + exprt::operandst c; + +#ifdef OPT_12 + exprt::operandst store; +#endif + + // add forward information if available + if(!old_summary.fw_precondition.is_nil()) + c.push_back(old_summary.fw_precondition); + if(!old_summary.fw_invariant.is_nil()) + c.push_back(old_summary.fw_invariant); + c.push_back(ssa_inliner.get_summaries(SSA)); // forward summaries + + exprt::operandst assert_postcond, noassert_postcond; + // add error summaries for function calls + bool assertion_flag; + // backward summaries + assertion_flag=ssa_inliner.get_summaries( + SSA, call_site, false, assert_postcond, noassert_postcond, c); + assert_postcond.push_back(postcondition); // context + + // add nondet variables from callees to summary.nondets + std::set summary_vars; + find_symbols(conjunction(assert_postcond), summary_vars); + for(std::set::const_iterator it=summary_vars.begin(); + it!=summary_vars.end(); ++it) + if(it->id()==ID_nondet_symbol) + summary.nondets.insert(*it); + +#ifdef DEBUG + std::cout << "Assert Summary: " + << from_expr(SSA.ns, "", conjunction(assert_postcond)) << "\n\n"; + std::cout << "Noassert Summary: " + << from_expr(SSA.ns, "", conjunction(noassert_postcond)) << "\n\n"; +#endif + + c.push_back(not_exprt(conjunction(assert_postcond))); + c.push_back(not_exprt(disjunction(noassert_postcond))); + +#ifdef DEBUG + debug() << "Backward summaries: " << + from_expr(SSA.ns, "", simplify_expr(conjunction(c), SSA.ns)) << eom; +#endif + +#ifdef OPT_12 + store << SSA; +#else +#ifdef OPT_2 + store << SSA; +#else + solver << SSA; +#endif +#endif + +#ifndef OPT_2 + solver.new_context(); +#endif + + // assumptions must hold + for(const auto &node : SSA.nodes) + { + for(const auto &a : node.assumptions) + { +#ifdef OPT_11 + solver << simplify_expr(a, SSA.ns); +#else +#ifdef OPT_12 + store.push_back(a); +#else +#ifdef OPT_2 + store.push_back(a); +#else + solver << a; +#endif +#endif +#endif + } + } + +#ifdef OPT_12 + store.push_back(SSA.get_enabling_exprs()); +#else +#ifdef OPT_2 + store.push_back(SSA.get_enabling_exprs()); +#else + solver << SSA.get_enabling_exprs(); +#endif +#endif + +#ifdef OPT_11 + solver << simplify_expr(conjunction(c), SSA.ns); +#else +#ifdef OPT_12 + store.push_back(conjunction(c)); +#else +#ifdef OPT_2 + store.push_back(conjunction(c)); +#else + solver << conjunction(c); +#endif +#endif +#endif + + exprt::operandst loophead_selects; + get_loophead_selects(function_name, SSA, *solver.solver, loophead_selects); + +#ifdef OPT_11 + solver << simplify_expr(conjunction(loophead_selects), SSA.ns); +#else +#ifdef OPT_12 + store.push_back(conjunction(loophead_selects)); +#else +#ifdef OPT_2 + store.push_back(conjunction(loophead_selects)); +#else + solver << conjunction(loophead_selects); +#endif +#endif +#endif + +#ifdef OPT_12 +#ifdef DEBUG + std::cout << "\n\n\n pushing to the solver in do_summary:" + << from_expr(SSA.ns, "", conjunction(store)) << "\n\n\n"; +#endif + solver << simplify_expr(conjunction(store), SSA.ns); +#endif +#ifdef OPT_2 +#ifdef DEBUG + std::cout << "\n\n\n pushing to the solver in do_summary:" + << from_expr(SSA.ns, "", simplify_expr(conjunction(store), SSA.ns)) + << "\n\n\n"; +#endif + solver << simplify_expr(conjunction(store), SSA.ns); +#endif + + // statistics + solver_calls++; + + // solve + if(solver()==decision_proceduret::D_UNSATISFIABLE) + { + // TODO: this is likely to be incomplete + summary.error_summaries[call_site]=true_exprt(); + summary.has_assertion=assertion_flag; +#ifndef OPT_2 + solver.pop_context(); +#endif + + return; + } + + // build error summary and add to summary + exprt::operandst var_values; + + for(const auto &var : SSA.params) + { + exprt summ_value=solver.get(var); + if(!summ_value.is_nil()) + var_values.push_back(equal_exprt(var, summ_value)); + } + + for(const auto &var : SSA.globals_in) + { + exprt summ_value=solver.get(var); + if(!summ_value.is_nil()) + var_values.push_back(equal_exprt(var, summ_value)); + } + + for(const auto &var : SSA.globals_out) + { + exprt summ_value=solver.get(var); + if(!summ_value.is_nil()) + var_values.push_back(equal_exprt(var, summ_value)); + } + + for(const auto &var : SSA.nondets) + { + exprt summ_value=solver.get(var); + if(!summ_value.is_nil()) + var_values.push_back(equal_exprt(var, summ_value)); + } + + summary.error_summaries[call_site]=not_exprt(conjunction(var_values)); + summary.has_assertion=assertion_flag; + +#ifndef OPT_2 + solver.pop_context(); +#endif + +#ifdef OPT_2 + delete fresh_solver; +#endif +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_concretet::inline_summaries() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void summarizer_bw_cex_concretet::inline_summaries( + const function_namet &function_name, + local_SSAt &SSA, + const summaryt &old_summary, + const exprt &postcondition, + bool context_sensitive, + bool sufficient) +{ + for(local_SSAt::nodest::const_iterator n_it=SSA.nodes.end(); + n_it!=SSA.nodes.begin(); ) + { + n_it--; + + for(local_SSAt::nodet::function_callst::const_iterator f_it= + n_it->function_calls.begin(); + f_it!=n_it->function_calls.end(); f_it++) + { + assert(f_it->function().id()==ID_symbol); // no function pointers + + exprt postcondition_call=true_exprt(); + postcondition_call=compute_calling_context2( + function_name, SSA, old_summary, n_it, f_it, postcondition, sufficient); + + // TODO: just put all function calls into reason + reason[function_name].functions.insert(n_it->location); + + irep_idt fname=to_symbol_expr(f_it->function()).get_identifier(); + status() << "Recursively summarizing function " << fname << eom; + compute_summary_rec(fname, summaryt::call_sitet(n_it->location), + postcondition_call, context_sensitive); + } + } +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_concretet::compute_calling_context2() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +exprt summarizer_bw_cex_concretet::compute_calling_context2( + const function_namet &function_name, + local_SSAt &SSA, + summaryt old_summary, + local_SSAt::nodest::const_iterator n_it, + local_SSAt::nodet::function_callst::const_iterator f_it, + const exprt &postcondition, + bool sufficient) +{ + assert(f_it->function().id()==ID_symbol); // no function pointers + irep_idt fname=to_symbol_expr(f_it->function()).get_identifier(); + + status() << "Computing calling context for function " << fname << eom; + + // solver + +#ifdef OPT_2 + incremental_solvert *fresh_solver= + incremental_solvert::allocate(SSA.ns, options.get_bool_option("refine")); + incremental_solvert &solver=(*fresh_solver); +#else + incremental_solvert &solver=ssa_db.get_solver(function_name); +#endif + + solver.set_message_handler(get_message_handler()); + + // collect globals at call site + std::map< + local_SSAt::nodet::function_callst::const_iterator, + local_SSAt::var_sett> + cs_globals_out; + SSA.get_globals(n_it->location, cs_globals_out[f_it], false); + + exprt::operandst c; + +#ifdef OPT_12 + exprt::operandst store; +#endif + + // add forward information if available + if(!old_summary.fw_precondition.is_nil()) + c.push_back(old_summary.fw_precondition); + if(!old_summary.fw_invariant.is_nil()) + c.push_back(old_summary.fw_invariant); + c.push_back(ssa_inliner.get_summaries(SSA)); // forward summaries + + exprt::operandst assert_postcond, noassert_postcond; + // add error summaries for function calls + ssa_inliner.get_summaries( + SSA, + summaryt::call_sitet(n_it->location), + false, + assert_postcond, + noassert_postcond, + c); + assert_postcond.push_back(postcondition); // context + c.push_back(not_exprt(conjunction(assert_postcond))); + c.push_back(not_exprt(disjunction(noassert_postcond))); + +#ifdef OPT_12 + store << SSA; +#else + solver << SSA; +#endif + + solver.new_context(); + +#ifdef OPT_12 + store.push_back(SSA.get_enabling_exprs()); +#else + solver << SSA.get_enabling_exprs(); +#endif + +#ifdef OPT_11 + solver << simplify_expr(conjunction(c), SSA.ns); +#else +#ifdef OPT_12 + store.push_back(conjunction(c)); +#else + solver << conjunction(c); +#endif +#endif + + exprt::operandst loophead_selects; + get_loophead_selects(function_name, SSA, *solver.solver, loophead_selects); + +#ifdef OPT_11 + solver << simplify_expr(conjunction(loophead_selects), SSA.ns); +#else +#ifdef OPT_12 + store.push_back(conjunction(loophead_selects)); +#else + solver << conjunction(loophead_selects); +#endif +#endif + +#ifdef OPT_12 +#ifdef DEBUG + std::cout << "\n\n\n pushing to the solver in compute_calling_context2:" + << from_expr(SSA.ns, "", conjunction(store)) << "\n\n\n"; +#endif + solver << simplify_expr(conjunction(store), SSA.ns); +#endif + + + // build postcondition + exprt postcondition_call; + + if(solver()!=decision_proceduret::D_SATISFIABLE) + { + postcondition_call=true_exprt(); // TODO: this is likely to be incomplete + solver.pop_context(); + return postcondition_call; + } + + bool result=solver()==decision_proceduret::D_SATISFIABLE; + assert(result); + + exprt::operandst postcond_values; + for(local_SSAt::var_sett::const_iterator it=cs_globals_out[f_it].begin(); + it!=cs_globals_out[f_it].end(); it++) + { + exprt postc_value=solver.get(*it); + postcond_values.push_back(equal_exprt(*it, postc_value)); + } + postcondition_call=conjunction(postcond_values); + + solver.pop_context(); + + // get callee SSA and rename + local_SSAt &fSSA=ssa_db.get(fname); + ssa_inliner.rename_to_callee( + f_it, + fSSA.params, + cs_globals_out[f_it], + fSSA.globals_out, + postcondition_call); + + debug() << "Backward calling context for " + << from_expr(SSA.ns, "", *f_it) << ": " + << from_expr(SSA.ns, "", postcondition_call) << eom; + + // statistics + solver_calls++; + +#ifdef OPT_2 + delete fresh_solver; +#endif + + return not_exprt(postcondition_call); +} diff --git a/src/solver/summarizer_bw_cex_concrete.h b/src/solver/summarizer_bw_cex_concrete.h new file mode 100644 index 000000000..b13d9509c --- /dev/null +++ b/src/solver/summarizer_bw_cex_concrete.h @@ -0,0 +1,84 @@ +/*******************************************************************\ + +Module: Simple Counterexample-based Backward Analysis + +Author: Kumar Madhukar, Peter Schrammel + +\*******************************************************************/ + +#ifndef CPROVER_2LS_SOLVER_SUMMARIZER_BW_CEX_CONCRETE_H +#define CPROVER_2LS_SOLVER_SUMMARIZER_BW_CEX_CONCRETE_H + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "summarizer_bw_cex.h" + +class summarizer_bw_cex_concretet:public summarizer_bw_cex_baset +{ +public: + summarizer_bw_cex_concretet( + optionst &_options, + summary_dbt &_summary_db, + ssa_dbt &_ssa_db, + ssa_unwindert &_ssa_unwinder, + ssa_inlinert &_ssa_inliner, + function_namet _entry_function, + function_namet _error_function): + summarizer_bw_cex_baset( + _options, + _summary_db, + _ssa_db, + _ssa_unwinder, + _ssa_inliner, + _entry_function, + _error_function) + {} + + virtual void summarize(const function_namet &entry_function); + virtual void summarize(const exprt &_error_assertion); + + virtual property_checkert::resultt check(); + +protected: + virtual void compute_summary_rec( + const function_namet &function_name, + const summaryt::call_sitet &call_site, + const exprt &postcondition, + bool context_sensitive); + + virtual void inline_summaries( + const function_namet &function_name, + local_SSAt &SSA, + const summaryt &old_summary, + const exprt &postcondition, + bool context_sensitive, + bool sufficient); + + virtual void do_summary( + const function_namet &function_name, + const summaryt::call_sitet &call_site, + local_SSAt &SSA, + const summaryt &old_summary, + summaryt &summary, + const exprt &postcondition, + bool context_sensitive); + + virtual exprt compute_calling_context2( + const function_namet &function_name, + local_SSAt &SSA, + summaryt old_summary, + local_SSAt::nodest::const_iterator n_it, + local_SSAt::nodet::function_callst::const_iterator f_it, + const exprt &postcondition, + bool sufficient); +}; + +#endif // CPROVER_2LS_SOLVER_SUMMARIZER_BW_CEX_CONCRETE_H diff --git a/src/solver/summarizer_bw_cex_wp.cpp b/src/solver/summarizer_bw_cex_wp.cpp new file mode 100644 index 000000000..5f4d43e0f --- /dev/null +++ b/src/solver/summarizer_bw_cex_wp.cpp @@ -0,0 +1,768 @@ +/*******************************************************************\ + +Module: Slicing-based WP Counterexample-based Backward Analysis + +Author: Madhukar Kumar, Peter Schrammel + +\*******************************************************************/ + +// #define DEBUG + +#ifdef DEBUG +#include +#endif + +#include +#include +#include +#include +#include + +#include "summary_db.h" + +#include +#include +#include + +#include +#include +#include + +#include "summarizer_bw_cex_wp.h" + +/*******************************************************************\ + +Function: summarizer_bw_cex_wpt::summarize() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void summarizer_bw_cex_wpt::summarize( + const function_namet &entry_function) +{ + // no dependencies to begin with + find_symbols_sett dependency_set; + + status() << "\nSummarizing function " << entry_function << eom; + compute_summary_rec( + entry_function, dependency_set, -1, summaryt::entry_call_site); +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_wpt::summarize() + + Inputs: + + Outputs: + + Purpose: summarize backwards from given assertion + +\*******************************************************************/ + +void summarizer_bw_cex_wpt::summarize(const exprt &_error_assertion) +{ + status() << "\nBackward error analysis (WP)..." << eom; + error_assertion=_error_assertion; +#ifdef DEBUG + std::cout << "error assertion: " + << from_expr(ssa_db.get(entry_function).ns, "", error_assertion) + << "\n"; +#endif + summarize(entry_function); +} + + +/*******************************************************************\ + +Function: summarizer_bw_cex_wpt::inline_summaries() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +find_symbols_sett summarizer_bw_cex_wpt::inline_summaries( + const function_namet &function_name, + const find_symbols_sett &dependency_set, + int counter, + exprt &error_summary) +{ + exprt::operandst slice; + + local_SSAt &SSA=ssa_db.get(function_name); + + exprt::operandst loophead_selects; + get_loophead_selects(function_name, SSA, *solver.solver, loophead_selects); + exprt c=conjunction(loophead_selects); + +#ifdef DEBUG + std::cout << "Solver <-- " << function_name + << ": (conjunction of loophead_selects):" + << "\t original info ~ " + << from_expr(ssa_db.get(function_name).ns, "", c) << "\n"; +#endif + + slice.push_back(c); + ssa_inliner.rename(c, counter); + +#ifdef DEBUG + std::cout << "Solver <-- " << function_name + << ": (conjunction of loophead_selects):" + << "\t renamed info ~ " + << from_expr(ssa_db.get(function_name).ns, "", c) << "\n"; +#endif + + solver << c; + + ssa_dependency_grapht &ssa_depgraph=ssa_db.get_depgraph(function_name); + + struct worknodet + { + int node_index; + find_symbols_sett dependency_set; + }; + + worknodet start_node; + start_node.node_index=0; + start_node.dependency_set=dependency_set; + + typedef std::list worklistt; + worklistt worklist, work_waitlist; + std::vector covered_nodes; + + worklist.push_back(start_node); + + while(!worklist.empty()) + { +#ifdef DEBUG + std::cout << "worklist: "; + for(worklistt::const_iterator w_it=worklist.begin(); + w_it!=worklist.end(); w_it++) + { + std::cout << w_it->node_index << " "; + } + std::cout << "\n"; + + std::cout << "\t waitlist: "; + for(worklistt::const_iterator w_it=work_waitlist.begin(); + w_it!=work_waitlist.end(); w_it++) + { + std::cout << w_it->node_index << " "; + } + std::cout << "\n"; +#endif + + worknodet &worknode=worklist.front(); + +#ifdef DEBUG + std::cout << "working node: " << function_name + << ": " << worknode.node_index << "\n"; + std::cout << "\t size of dependency set: " + << worknode.dependency_set.size() << "\n"; + std::cout << "\t dependency set: "; + for(find_symbols_sett::iterator d_it=worknode.dependency_set.begin(); + d_it!=worknode.dependency_set.end(); d_it++) + { + std::cout << *d_it; + } + std::cout << "\n\n\n"; +#endif + + // return if the top most node is reached + if(worknode.node_index==ssa_depgraph.top_node_index) + { + find_symbols_sett vars=worknode.dependency_set; + vars.insert(dependency_set.begin(), dependency_set.end()); + error_summary=simplify_summary(SSA.ns, conjunction(slice), vars); + return worknode.dependency_set; + } + + // modify worknode_dependency_set if the node is an assertion + if(ssa_depgraph.depnodes_map[worknode.node_index].is_assertion==true) + { +#ifdef DEBUG + std::cout << "\t\t an assertion node\n"; +#endif + for(find_symbols_sett::const_iterator d_it= + ssa_depgraph.depnodes_map[worknode.node_index].used_symbols.begin(); + d_it!= + ssa_depgraph.depnodes_map[worknode.node_index].used_symbols.end(); + d_it++) + { + worknode.dependency_set.insert(*d_it); + } + +#ifdef DEBUG + std::cout << "\t size of dependency set: " + << worknode.dependency_set.size() << "\n"; + + std::cout << "\t dependency set: "; + for(find_symbols_sett::iterator d_it=worknode.dependency_set.begin(); + d_it!=worknode.dependency_set.end(); d_it++) + { + std::cout << *d_it; + } + std::cout << "\n"; +#endif + } + + // if this is a function call + if(ssa_depgraph.depnodes_map[worknode.node_index].is_function_call==true) + { +#ifdef DEBUG + std::cout << "fcall: working node: " << function_name << ": " + << worknode.node_index << "\n"; +#endif + irep_idt fname= + to_symbol_expr( + to_function_application_expr( + ssa_depgraph.depnodes_map[worknode.node_index].node_info) + .function()).get_identifier(); + + find_symbols_sett renamed_dependencies; + +#ifdef DEBUG + std::cout << "\t size of dependency set: " + << worknode.dependency_set.size() << "\n"; + + std::cout << "\t dependency set: "; + for(find_symbols_sett::iterator d_it=worknode.dependency_set.begin(); + d_it!=worknode.dependency_set.end(); d_it++) + { + std::cout << *d_it; + } + std::cout << "\n"; +#endif + + for(find_symbols_sett::iterator d_it=worknode.dependency_set.begin(); + d_it!=worknode.dependency_set.end(); d_it++) + { + irep_idt renamed_id=*d_it; + // detach the '@' symbol if there + ssa_inliner.rename( + renamed_id, + ssa_depgraph.depnodes_map[worknode.node_index].rename_counter, + false); + renamed_dependencies.insert(renamed_id); + } + + worknode.dependency_set=renamed_dependencies; + + if(!worknode.dependency_set.empty()) + { + find_symbols_sett guard_dependencies; + find_symbols( + ssa_depgraph.depnodes_map[worknode.node_index].guard, + guard_dependencies); + for(find_symbols_sett::const_iterator d_it=guard_dependencies.begin(); + d_it!=guard_dependencies.end(); d_it++) + { + worknode.dependency_set.insert(*d_it); + } + } + +#ifdef DEBUG + std::cout << "\t size of dependency set: " + << worknode.dependency_set.size() << "\n"; + + std::cout << "\t dependency set: "; + for(find_symbols_sett::iterator d_it=worknode.dependency_set.begin(); + d_it!=worknode.dependency_set.end(); d_it++) + { + std::cout << *d_it; + } + std::cout << "\n"; +#endif + + worknode.dependency_set= + compute_summary_rec( + fname, + worknode.dependency_set, + ssa_depgraph.depnodes_map[worknode.node_index].rename_counter, + summaryt::call_sitet( + ssa_depgraph.depnodes_map[worknode.node_index].location)); + slice.push_back(ssa_depgraph.depnodes_map[worknode.node_index].node_info); + + renamed_dependencies.clear(); + + for(find_symbols_sett::iterator d_it=worknode.dependency_set.begin(); + d_it!=worknode.dependency_set.end(); d_it++) + { + irep_idt renamed_id=*d_it; + // detach the '@' symbol if there + ssa_inliner.rename( + renamed_id, + ssa_depgraph.depnodes_map[worknode.node_index].rename_counter, + false); + renamed_dependencies.insert(renamed_id); + } + + worknode.dependency_set=renamed_dependencies; + + if(!worknode.dependency_set.empty()) + { + find_symbols_sett guard_dependencies; + find_symbols( + ssa_depgraph.depnodes_map[worknode.node_index].guard, + guard_dependencies); + for(find_symbols_sett::const_iterator d_it=guard_dependencies.begin(); + d_it!=guard_dependencies.end(); d_it++) + { + worknode.dependency_set.insert(*d_it); + } + } + } + + // if the dependency set is non-empty + if(!worknode.dependency_set.empty()) + { + exprt worknode_info= + ssa_depgraph.depnodes_map[worknode.node_index].node_info; + if(ssa_depgraph.depnodes_map[worknode.node_index].is_assertion==true) + worknode_info=not_exprt(worknode_info); + + if(worknode.node_index!=0) + { + if(!(ssa_depgraph.depnodes_map[worknode.node_index].is_function_call)) + { + if((ssa_depgraph.depnodes_map[worknode.node_index] + .is_assertion==false) || + (worknode_info==error_assertion)) + { +#ifdef DEBUG + std::cout << "Solver <-- " << function_name << ": (node) node#:" + << worknode.node_index << "\t original info ~ " + << from_expr( + (ssa_db.get(function_name)).ns, "", worknode_info) + << "\n"; +#endif + + slice.push_back(worknode_info); + ssa_inliner.rename(worknode_info, counter); + +#ifdef DEBUG + std::cout << "Solver <-- renamed assertion: " + << from_expr( + (ssa_db.get(function_name)).ns, "", worknode_info) + << "\n"; + std::cout << "Solver <-- " << function_name << ": (node) node#:" + << worknode.node_index << "\t renamed info ~ " + << from_expr( + (ssa_db.get(function_name)).ns, "", worknode_info) + << "\n"; +#endif + solver << worknode_info; + } + } + else + { + exprt guard_binding= + ssa_depgraph.depnodes_map[worknode.node_index].guard; +#ifdef DEBUG + std::cout << "Solver <-- " << function_name << ": (bind) node#:" + << worknode.node_index << "\t original info ~ " + << from_expr(ssa_db.get(function_name).ns, "", guard_binding) + << "\n"; +#endif + + ssa_inliner.rename(guard_binding, counter); + +#ifdef DEBUG + std::cout << "Solver <-- " << function_name << ": (bind) node#:" + << worknode.node_index << "\t renamed info ~ " + << from_expr( + ssa_db.get(function_name).ns, "", guard_binding) + << "\n"; +#endif + solver << guard_binding; + slice.push_back(guard_binding); + } + } + } + + // if not a function call and the dependency set is non-empty + if((ssa_depgraph.depnodes_map[worknode.node_index] + .is_function_call==false) && + (!worknode.dependency_set.empty())) + { + exprt worknode_info= + ssa_depgraph.depnodes_map[worknode.node_index].node_info; + if(ssa_depgraph.depnodes_map[worknode.node_index].is_assertion==true) + worknode_info=not_exprt(worknode_info); + + if((ssa_depgraph.depnodes_map[worknode.node_index].is_assertion==false) || + (worknode_info==error_assertion)) + { + worknode.dependency_set= + ssa_depgraph.depnodes_map[worknode.node_index].used_symbols; + } + } + + for(ssa_dependency_grapht::annotated_predecessorst::const_iterator + p_it=ssa_depgraph.depnodes_map[worknode.node_index] + .predecessors.begin(); + p_it!=ssa_depgraph.depnodes_map[worknode.node_index].predecessors.end(); + p_it++) + { + ssa_dependency_grapht::annotated_predecessort pred=*p_it; + int pred_node_index=pred.predecessor_node_index; + find_symbols_sett pred_annotation=pred.annotation; + + bool dependencies_merged=false; + for(worklistt::iterator w_it=work_waitlist.begin(); + w_it!=work_waitlist.end(); w_it++) + { + if(w_it->node_index==pred_node_index) + { + dependencies_merged=true; + + for(find_symbols_sett::const_iterator + a_it=pred_annotation.begin(); + a_it!=pred_annotation.end(); a_it++) + { + if(worknode.dependency_set.find(*a_it)!= + worknode.dependency_set.end()) + { + if((w_it->dependency_set).find(*a_it)== + (w_it->dependency_set).end()) + { + (w_it->dependency_set).insert(*a_it); + } + } + } + break; + } + } + + if(dependencies_merged==false) + { + worknodet new_worknode; + new_worknode.node_index=pred_node_index; + + for(find_symbols_sett::const_iterator + a_it=pred_annotation.begin(); a_it!=pred_annotation.end(); a_it++) + { + if(worknode.dependency_set.find(*a_it)!=worknode.dependency_set.end()) + new_worknode.dependency_set.insert(*a_it); + } + + work_waitlist.push_back(new_worknode); + } + } + +#ifdef DEBUG + std::cout << function_name << ": worklist: "; + for(worklistt::const_iterator w_it=worklist.begin(); + w_it!=worklist.end(); w_it++) + { + std::cout << w_it->node_index << " "; + } + std::cout << "\n"; + + std::cout << "\t" << function_name << ": waitlist: "; + for(worklistt::const_iterator w_it=work_waitlist.begin(); + w_it!=work_waitlist.end(); w_it++) + { + std::cout << w_it->node_index << " "; + } + std::cout << "\n"; +#endif + + covered_nodes.push_back(worknode.node_index); + worklist.pop_front(); + +#ifdef DEBUG + std::cout << function_name << ": covered : "; + for(int l=0; l &waitlisted_worknode_successors= + ssa_depgraph.depnodes_map[waitlisted_worknode.node_index].successors; + + for(unsigned i=0; i " << function_name + << " ; dependency_set -> "; + for(find_symbols_sett::iterator d_it=dependency_set.begin(); + d_it!=dependency_set.end(); d_it++) + { + std::cout << *d_it << ", "; + } + std::cout << "\n"; +} + +/*******************************************************************\ + +Function: summarizer_bw_cex_wpt::simplify_summary() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void summarizer_bw_cex_wpt::simplify_summary_build_map( + replace_mapt &replace_map, const exprt &expr) +{ + if(expr.id()==ID_equal) + { + replace_map[expr.op0()]=expr.op1(); + return; + } + forall_operands(it, expr) + simplify_summary_build_map(replace_map, *it); +} + + +/*******************************************************************\ + +Function: summarizer_bw_cex_wpt::simplify_summary_replace() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool summarizer_bw_cex_wpt::simplify_summary_replace( + const replace_mapt &replace_map, exprt &expr) +{ + if(expr.id()==ID_function_application) + { + bool result=true; + exprt::operandst &args=to_function_application_expr(expr).arguments(); + for(size_t i=0; i +#include +#include +#include +#include +#include +#include + +#include + +#include "summarizer_bw_cex.h" + +class summarizer_bw_cex_wpt:public summarizer_bw_cex_baset +{ +public: + summarizer_bw_cex_wpt( + optionst &_options, + summary_dbt &_summary_db, + ssa_dbt &_ssa_db, + ssa_unwindert &_ssa_unwinder, + ssa_inlinert &_ssa_inliner, + incremental_solvert &_solver, + function_namet _entry_function, + function_namet _error_function): + summarizer_bw_cex_baset( + _options, + _summary_db, + _ssa_db, + _ssa_unwinder, + _ssa_inliner, + _entry_function, + _error_function), + solver(_solver) + {} + + virtual void summarize(const function_namet &entry_function); + virtual void summarize(const exprt &_error_assertion); + + virtual property_checkert::resultt check(); + +protected: + incremental_solvert &solver; + + virtual find_symbols_sett inline_summaries( + const function_namet &function_name, + const find_symbols_sett &dependency_set, + int counter, + exprt &error_summary); + + virtual find_symbols_sett compute_summary_rec( + const function_namet &function_name, + const find_symbols_sett &dependency_set, + int counter, + const summaryt::call_sitet &call_site); + + virtual void debug_print( + const function_namet &function_name, + find_symbols_sett &dependency_set); + + exprt simplify_summary( + const namespacet &ns, + exprt summary, + const find_symbols_sett &vars); + + void simplify_summary_build_map( + replace_mapt &replace_map, const exprt &expr); + + bool simplify_summary_replace( + const replace_mapt &replace_map, exprt &expr); + + void simplify_summary_cleanup( + const find_symbols_sett &vars, exprt &expr); +}; + +#endif // CPROVER_2LS_SOLVER_SUMMARIZER_BW_CEX_WP_H diff --git a/src/solver/summary.cpp b/src/solver/summary.cpp index 3a74ba628..547002037 100644 --- a/src/solver/summary.cpp +++ b/src/solver/summary.cpp @@ -16,6 +16,8 @@ Author: Peter Schrammel // #define PRETTY_PRINT +const summaryt::call_sitet summaryt::entry_call_site; + /*******************************************************************\ Function: summaryt::output @@ -77,6 +79,18 @@ void summaryt::output(std::ostream &out, const namespacet &ns) const #endif out << std::endl; out << "terminates: " << threeval2string(terminates) << std::endl; + for(error_summariest::const_iterator + it=error_summaries.begin(); + it!=error_summaries.end(); it++) + { + out << "error summary for "; + if(it->first==entry_call_site) + out << "entry point"; + else + out << "location " << it->first.location_number; + out << ": " << std::endl + << " " << from_expr(ns, "", it->second) << std::endl; + } } /*******************************************************************\ diff --git a/src/solver/summary.h b/src/solver/summary.h index 840a42230..c7e68a6c6 100644 --- a/src/solver/summary.h +++ b/src/solver/summary.h @@ -9,11 +9,14 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_2LS_SOLVER_SUMMARY_H #define CPROVER_2LS_SOLVER_SUMMARY_H +#include #include #include #include +#include + typedef enum {YES, NO, UNKNOWN} threevalt; class summaryt @@ -23,6 +26,7 @@ class summaryt typedef std::list var_listt; typedef std::set var_sett; + typedef std::set expr_sett; summaryt() : fw_precondition(nil_exprt()), @@ -38,7 +42,7 @@ class summaryt var_listt params; var_sett globals_in, globals_out; - + expr_sett nondets; predicatet fw_precondition; // accumulated calling contexts (over-approx) // predicatet fw_postcondition; // we are not projecting that out currently predicatet fw_transformer; // forward summary (over-approx) @@ -51,6 +55,37 @@ class summaryt predicatet termination_argument; threevalt terminates; + // -------------- + // the following is for generating interprocedural counterexample + + bool has_assertion; + + std::list nonpassed_assertions; + + struct call_sitet + { // TODO: we also need unwinding information here + call_sitet():location_number(UINT_MAX) {} + explicit call_sitet(local_SSAt::locationt loc): + location_number(loc->location_number) + { + } + unsigned location_number; + + bool operator<(const call_sitet &other) const + { + return (location_number error_summariest; + error_summariest error_summaries; + // -------------- + bool mark_recompute; // to force recomputation of the summary // (used for invariant reuse in k-induction) diff --git a/src/solver/summary_db.h b/src/solver/summary_db.h index 44264bead..04145d8a5 100644 --- a/src/solver/summary_db.h +++ b/src/solver/summary_db.h @@ -25,6 +25,8 @@ class summary_dbt:public messaget summaryt get(const function_namet &function_name) const { return store.at(function_name); } + void set(const function_namet &function_name, const summaryt &summary) + { store[function_name]=summary; } bool exists(const function_namet &function_name) const { return store.find(function_name)!=store.end(); } void put(const function_namet &function_name, const summaryt &summary); diff --git a/src/ssa/Makefile b/src/ssa/Makefile index 0c4c0263f..b997fff90 100644 --- a/src/ssa/Makefile +++ b/src/ssa/Makefile @@ -1,9 +1,23 @@ SRC = local_ssa.cpp \ - ssa_domain.cpp translate_union_member.cpp malloc_ssa.cpp \ - guard_map.cpp ssa_object.cpp assignments.cpp ssa_dereference.cpp \ - ssa_value_set.cpp address_canonizer.cpp simplify_ssa.cpp \ - ssa_build_goto_trace.cpp ssa_inliner.cpp ssa_unwinder.cpp \ - unwindable_local_ssa.cpp ssa_db.cpp + ssa_domain.cpp \ + translate_union_member.cpp \ + malloc_ssa.cpp \ + guard_map.cpp \ + ssa_object.cpp \ + assignments.cpp \ + ssa_dereference.cpp \ + ssa_value_set.cpp \ + address_canonizer.cpp \ + simplify_ssa.cpp \ + ssa_build_goto_trace.cpp \ + ssa_inliner.cpp \ + ssa_unwinder.cpp \ + unwindable_local_ssa.cpp \ + ssa_const_propagator.cpp \ + ssa_dependency_graph.cpp \ + ssa_refiner_monolithic.cpp \ + ssa_refiner_selective.cpp \ + # empty last line include ../config.inc include $(CBMC)/src/config.inc diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index f86fbb092..e997d27d3 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -19,6 +19,9 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include + + #include #include "local_ssa.h" @@ -57,6 +60,7 @@ void local_SSAt::build_SSA() build_cond(i_it); build_guard(i_it); build_assertions(i_it); + build_assumptions(i_it); build_function_call(i_it); } @@ -81,6 +85,8 @@ Function: local_SSAt::get_entry_exit_vars void local_SSAt::get_entry_exit_vars() { + goto_programt::const_targett first=goto_function.body.instructions.begin(); + // get parameters const code_typet::parameterst ¶meter_types= goto_function.type.parameters(); @@ -94,19 +100,79 @@ void local_SSAt::get_entry_exit_vars() if(ns.lookup(identifier, symbol)) continue; - params.push_back(symbol->symbol_expr()); + if(ns.follow(symbol->type).id()==ID_struct) + { + exprt param=read_rhs(symbol->symbol_expr(), first); +#if 0 + std::cout << "param: " + << from_expr(ns, "", param) << std::endl; +#endif + forall_operands(it, param) + params.push_back(to_symbol_expr(*it)); + } + else + params.push_back(symbol->symbol_expr()); } // get globals in - goto_programt::const_targett first=goto_function.body.instructions.begin(); get_globals(first, globals_in, true, false); // filters out #return_value // get globals out (includes return value) goto_programt::const_targett last=goto_function.body.instructions.end(); last--; get_globals(last, globals_out, true, true, last->function); + + // get nondeterministic variables + get_nondet_vars(); +} + +/*******************************************************************\ + +Function: local_SSAt::get_nondet_vars + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void local_SSAt::get_nondet_vars(const exprt &expr) +{ + if(expr.id()==ID_nondet_symbol) + nondets.insert(expr); + else + forall_operands(it, expr) + get_nondet_vars(*it); +} + +void local_SSAt::get_nondet_vars() +{ + for(nodest::iterator n_it=nodes.begin(); + n_it!=nodes.end(); n_it++) + { + for(nodet::equalitiest::const_iterator + e_it=n_it->equalities.begin(); + e_it!=n_it->equalities.end(); + e_it++) + get_nondet_vars(*e_it); + + for(nodet::constraintst::const_iterator + c_it=n_it->constraints.begin(); + c_it!=n_it->constraints.end(); + c_it++) + get_nondet_vars(*c_it); + + for(nodet::assertionst::const_iterator + a_it=n_it->assertions.begin(); + a_it!=n_it->assertions.end(); + a_it++) + get_nondet_vars(*a_it); + } } + /*******************************************************************\ Function: local_SSAt::get_globals @@ -136,21 +202,26 @@ void local_SSAt::get_globals( << from_expr(ns, "", read_lhs(it->get_expr(), loc)) << std::endl; #endif - if(!with_returns && - id2string(it->get_identifier()).find( - "#return_value")!=std::string::npos) + bool is_return=id2string(it->get_identifier()).find( + "#return_value")!=std::string::npos; + if(!with_returns && is_return) continue; // filter out return values of other functions if(with_returns && returns_for_function!="" && - id2string(it->get_identifier()).find( - "#return_value")!=std::string::npos && + is_return && id2string(it->get_identifier()).find( id2string(returns_for_function)+"#return_value")==std::string::npos) continue; if(rhs_value) { + // workaround for the problem that + // rhs() for a return value is always the "input" return value + #if 0 // --loc may be invalid + const exprt &expr=is_return ? + read_lhs(it->get_expr(), --loc) : read_rhs(it->get_expr(), loc); + #endif const exprt &expr=read_rhs(it->get_expr(), loc); globals.insert(to_symbol_expr(expr)); } @@ -271,6 +342,29 @@ void local_SSAt::find_nodes( /*******************************************************************\ +Function: local_SSAt::find_location_by_number + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +local_SSAt::locationt local_SSAt::find_location_by_number( + unsigned location_number) const +{ + for(const auto &node : nodes) + { + if(node.location->location_number==location_number) + return node.location; + } + assert(false); +} + +/*******************************************************************\ + Function: local_SSAt::edge_guard Inputs: @@ -333,7 +427,8 @@ void local_SSAt::build_phi_nodes(locationt loc) // ignore custom template variables if(id2string(o_it->get_identifier()). - find(TEMPLATE_PREFIX)!=std::string::npos) continue; + find(TEMPLATE_PREFIX)!=std::string::npos) + continue; // Yes. Get the source -> def map. const ssa_domaint::loc_def_mapt &incoming=p_it->second; @@ -536,9 +631,23 @@ void local_SSAt::build_function_call(locationt loc) for(exprt::operandst::iterator it=f.arguments().begin(); it!=f.arguments().end(); ++it, ++i) { - symbol_exprt arg(id2string(fname)+"#"+i2string(loc->location_number)+ - "#arg"+i2string(i), it->type()); - n_it->equalities.push_back(equal_exprt(*it, arg)); + symbol_exprt arg( + id2string(fname)+"#"+i2string(loc->location_number)+ + "#arg"+i2string(i), it->type()); + const typet &argtype=ns.follow(it->type()); + if(argtype.id()==ID_struct) + { + exprt lhs=read_rhs(arg, loc); + for(size_t j=0; jequalities.push_back( + equal_exprt(lhs.operands()[j], it->operands()[j])); + } + } + else + { + n_it->equalities.push_back(equal_exprt(arg, *it)); + } *it=arg; } @@ -679,6 +788,27 @@ void local_SSAt::build_assertions(locationt loc) /*******************************************************************\ +Function: local_SSAt::build_assumptions + + Inputs: + + Outputs: + + Purpose: collect assumptions (required for backwards analysis) + +\*******************************************************************/ + +void local_SSAt::build_assumptions(locationt loc) +{ + if(loc->is_assume()) + { + exprt c=read_rhs(loc->guard, loc); + (--nodes.end())->assumptions.push_back(c); + } +} + +/*******************************************************************\ + Function: local_SSAt::assertions_to_constraints Inputs: @@ -800,7 +930,6 @@ exprt local_SSAt::read_lhs( #ifdef DEBUG std::cout << from_expr(ns, "", tmp1) << "is_object" << '\n'; #endif - // yes, it is if(assignments.assigns(loc, object)) return name(object, OUT, loc); @@ -1146,7 +1275,10 @@ symbol_exprt local_SSAt::name( unsigned cnt=loc->location_number; irep_idt new_id=id2string(id)+"#"+ - (kind==PHI?"phi":kind==LOOP_BACK?"lb":kind==LOOP_SELECT?"ls":"")+ + (kind==PHI?"phi": + kind==LOOP_BACK?"lb": + kind==LOOP_SELECT?"ls": + "")+ i2string(cnt)+ (kind==LOOP_SELECT?std::string(""):suffix); @@ -1364,7 +1496,7 @@ void local_SSAt::assign_rec( assign_rec(new_lhs, new_rhs, guard, loc); } else - throw "UNKNOWN LHS: "+lhs.id_string(); + throw "UNKNOWN LHS: "+lhs.id_string(); // NOLINT(readability/throw) } /*******************************************************************\ @@ -1442,6 +1574,8 @@ void local_SSAt::nodet::output( std::ostream &out, const namespacet &ns) const { + if(!enabling_expr.is_true()) + out << "(enable) " << from_expr(ns, "", enabling_expr) << "\n"; #if 0 if(!marked) out << "(not marked)" << "\n"; @@ -1531,14 +1665,56 @@ Function: local_SSAt::operator << \*******************************************************************/ +std::vector &operator<<( + std::vector &dest, + const local_SSAt &src) +{ + for(local_SSAt::nodest::const_iterator n_it=src.nodes.begin(); + n_it!=src.nodes.end(); n_it++) + { + if(n_it->marked) + continue; + for(local_SSAt::nodet::equalitiest::const_iterator + e_it=n_it->equalities.begin(); + e_it!=n_it->equalities.end(); + e_it++) + { + if(!n_it->enabling_expr.is_true()) + dest.push_back(implies_exprt(n_it->enabling_expr, *e_it)); + else + dest.push_back(*e_it); + } + + for(local_SSAt::nodet::constraintst::const_iterator + c_it=n_it->constraints.begin(); + c_it!=n_it->constraints.end(); + c_it++) + { + if(!n_it->enabling_expr.is_true()) + dest.push_back(implies_exprt(n_it->enabling_expr, *c_it)); + else + dest.push_back(*c_it); + } + } + return dest; +} + +/*******************************************************************\ + +Function: local_SSAt::operator << + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + std::list &operator<<( std::list &dest, const local_SSAt &src) { -#ifdef SLICING - ssa_slicert ssa_slicer; - ssa_slicer(dest, src); -#else for(local_SSAt::nodest::const_iterator n_it=src.nodes.begin(); n_it!=src.nodes.end(); n_it++) { @@ -1549,7 +1725,10 @@ std::list &operator<<( e_it!=n_it->equalities.end(); e_it++) { - dest.push_back(*e_it); + if(!n_it->enabling_expr.is_true()) + dest.push_back(implies_exprt(n_it->enabling_expr, *e_it)); + else + dest.push_back(*e_it); } for(local_SSAt::nodet::constraintst::const_iterator @@ -1557,11 +1736,12 @@ std::list &operator<<( c_it!=n_it->constraints.end(); c_it++) { - dest.push_back(*c_it); + if(!n_it->enabling_expr.is_true()) + dest.push_back(implies_exprt(n_it->enabling_expr, *c_it)); + else + dest.push_back(*c_it); } } -#endif - return dest; } @@ -1581,13 +1761,6 @@ decision_proceduret &operator<<( decision_proceduret &dest, const local_SSAt &src) { -#ifdef SLICING - std::list tmp; - tmp << src; - for(std::list::const_iterator it=tmp.begin(); - it!=tmp.end(); it++) - dest << *it; -#else for(local_SSAt::nodest::const_iterator n_it=src.nodes.begin(); n_it!=src.nodes.end(); n_it++) { @@ -1598,7 +1771,24 @@ decision_proceduret &operator<<( e_it!=n_it->equalities.end(); e_it++) { - dest << *e_it; + if(!n_it->enabling_expr.is_true()) + dest << implies_exprt(n_it->enabling_expr, *e_it); + else + dest << *e_it; + +#if 0 + // freeze cond variables + if(e_it->op0().id()==ID_symbol && + e_it->op0().type().id()==ID_bool) + { + const symbol_exprt &symbol=to_symbol_expr(e_it->op0()); + if(id2string(symbol.get_identifier()).find("ssa::$cond")!= + std::string::npos) + { + dest.solver->set_frozen(dest.solver->convert(symbol)); + } + } +#endif } for(local_SSAt::nodet::constraintst::const_iterator @@ -1606,10 +1796,12 @@ decision_proceduret &operator<<( c_it!=n_it->constraints.end(); c_it++) { - dest << *c_it; + if(!n_it->enabling_expr.is_true()) + dest << implies_exprt(n_it->enabling_expr, *c_it); + else + dest << *c_it; } } -#endif return dest; } @@ -1629,13 +1821,6 @@ incremental_solvert &operator<<( incremental_solvert &dest, const local_SSAt &src) { -#ifdef SLICING - std::list tmp; - tmp << src; - for(std::list::const_iterator it=tmp.begin(); - it!=tmp.end(); it++) - dest << *it; -#else for(local_SSAt::nodest::const_iterator n_it=src.nodes.begin(); n_it!=src.nodes.end(); n_it++) { @@ -1677,7 +1862,6 @@ incremental_solvert &operator<<( dest << *c_it; } } -#endif return dest; } @@ -1697,10 +1881,10 @@ exprt local_SSAt::get_enabling_exprs() const { exprt::operandst result; result.reserve(enabling_exprs.size()); - for(std::list::const_iterator it=enabling_exprs.begin(); + for(std::vector::const_iterator it=enabling_exprs.begin(); it!=enabling_exprs.end(); ++it) { - std::list::const_iterator lh=it; ++lh; + std::vector::const_iterator lh=it; ++lh; if(lh!=enabling_exprs.end()) result.push_back(not_exprt(*it)); else @@ -1735,4 +1919,3 @@ bool local_SSAt::has_function_calls() const } return found; } - diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 0f8fcc477..7e70a5e97 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -13,7 +13,8 @@ Author: Daniel Kroening, kroening@kroening.com #include -#include "../domains/incremental_solver.h" +#include + #include "ssa_domain.h" #include "guard_map.h" #include "ssa_object.h" @@ -57,10 +58,10 @@ class local_SSAt public: inline nodet( locationt _location, - std::list::iterator _loophead) - : + std::list::iterator _loophead): + function_calls_inlined(false), enabling_expr(true_exprt()), - marked(false), + marked(false), location(_location), loophead(_loophead) { @@ -75,8 +76,12 @@ class local_SSAt typedef std::vector assertionst; assertionst assertions; + typedef std::vector assumptionst; + assertionst assumptions; + typedef std::vector function_callst; function_callst function_calls; + bool function_calls_inlined; exprt enabling_expr; // for incremental unwinding bool marked; // for incremental unwinding @@ -107,17 +112,17 @@ class local_SSAt void mark_nodes() { - for(nodest::iterator n_it=nodes.begin(); - n_it!=nodes.end(); n_it++) n_it->marked=true; + for(auto &n : nodes) + n.marked=true; } void unmark_nodes() { - for(nodest::iterator n_it=nodes.begin(); - n_it!=nodes.end(); n_it++) n_it->marked=false; + for(auto &n : nodes) + n.marked=false; } // for incremental unwinding - std::list enabling_exprs; + std::vector enabling_exprs; exprt get_enabling_exprs() const; // function entry and exit variables @@ -125,6 +130,7 @@ class local_SSAt typedef std::set var_sett; var_listt params; var_sett globals_in, globals_out; + std::set nondets; bool has_function_calls() const; @@ -198,6 +204,7 @@ class local_SSAt assert(it!=location_map.end()); return it->second; } + locationt find_location_by_number(unsigned location_number) const; protected: typedef std::map location_mapt; @@ -212,13 +219,20 @@ class local_SSAt void build_guard(locationt loc); void build_function_call(locationt loc); void build_assertions(locationt loc); + void build_assumptions(locationt loc); // custom templates void collect_custom_templates(); replace_mapt template_newvars; exprt template_last_newvar; + + void get_nondet_vars(const exprt &expr); + void get_nondet_vars(); }; +std::vector & operator << + (std::vector &dest, const local_SSAt &src); + std::list & operator << (std::list &dest, const local_SSAt &src); diff --git a/src/ssa/ssa_const_propagator.cpp b/src/ssa/ssa_const_propagator.cpp new file mode 100644 index 000000000..ab5c9fd68 --- /dev/null +++ b/src/ssa/ssa_const_propagator.cpp @@ -0,0 +1,307 @@ +/*******************************************************************\ + +Module: SSA Constant Propagator + +Author: Kumar Madhukar + +\*******************************************************************/ + +// #define DEBUG + +#ifdef DEBUG +#include +#include +#endif + +#include +#include +#include + +#include "ssa_const_propagator.h" + +/*******************************************************************\ + +Function: ssa_const_propagatort::operator() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void ssa_const_propagatort::operator()( + std::list &dest, const local_SSAt &src) +{ + values.iterate=true; + while(values.iterate) + { + values.iterate=false; + for(local_SSAt::nodest::const_iterator n_it=src.nodes.begin(); + n_it!=src.nodes.end(); n_it++) + { + const local_SSAt::nodet &node=*n_it; + + // check if node is active; 'continue' if not active + if(!node.enabling_expr.is_true()) + continue; + + // if src.enabling_exprs does not have a true in the end, + // then also continue + if(src.enabling_exprs.size()>0) + if((src.enabling_exprs.back()).is_true()) + continue; + + for(local_SSAt::nodet::equalitiest::const_iterator e_it= + node.equalities.begin(); + e_it!=node.equalities.end(); e_it++) + { + equal_exprt e=to_equal_expr(*e_it); + const exprt &lhs=e.lhs(); + exprt &temprhs=e.rhs(); + + // resolving conditional expressions + while(temprhs.id()==ID_if) + { + exprt simp_guard; +#ifdef DEBUG + std::cout << "guard: " << from_expr(src.ns, "", temprhs.op0()) + << std::endl; +#endif + simp_guard=simplify_expr(temprhs.op0(), src.ns); +#ifdef DEBUG + std::cout << "simplified: " << from_expr(src.ns, "", simp_guard) + << std::endl; +#endif + if(simp_guard.is_true()) + temprhs=temprhs.op1(); + else if(simp_guard.is_false()) + temprhs=temprhs.op2(); + else + break; + } + + const exprt &rhs=temprhs; + valuest copy_values=values; + + if(!copy_values.maps_to_top(rhs)) + assign(copy_values, lhs, rhs, src.ns); + else + copy_values.set_to_top(lhs); + +#ifdef DEBUG + copy_values.output(std::cout, src.ns); +#endif + + if(rhs.id()==ID_symbol) + { + if(!values.maps_to_top(lhs)) + assign(values, rhs, lhs, src.ns); + else + values.set_to_top(rhs); + } + +#ifdef DEBUG + values.output(std::cout, src.ns); +#endif + + values.merge(copy_values); + +#ifdef DEBUG + values.output(std::cout, src.ns); +#endif + } + + for(local_SSAt::nodet::constraintst::const_iterator c_it= + n_it->constraints.begin(); + c_it!=n_it->constraints.end(); c_it++) + { + if(c_it->id()!=ID_equal) + continue; + + const equal_exprt e=to_equal_expr(*c_it); + const exprt &lhs=e.lhs(); + const exprt &rhs=e.rhs(); + + // if lhs is a variable and rhs is a constant expression + + valuest copy_values=values; + + if(!copy_values.maps_to_top(rhs)) + assign(copy_values, lhs, rhs, src.ns); + else + copy_values.set_to_top(lhs); + +#ifdef DEBUG + copy_values.output(std::cout, src.ns); +#endif + + // if rhs is a variable and lhs is a constant expression + + if(!values.maps_to_top(lhs)) + assign(values, rhs, lhs, src.ns); + else + values.set_to_top(rhs); + +#ifdef DEBUG + values.output(std::cout, src.ns); +#endif + + values.merge(copy_values); + +#ifdef DEBUG + values.output(std::cout, src.ns); +#endif + } + } + } + +#ifdef DEBUG + values.output(std::cout, src.ns); +#endif + + // iterate over values and get all equalities + for(replace_symbolt::expr_mapt::const_iterator + it=values.replace_const.expr_map.begin(); + it!=values.replace_const.expr_map.end(); + ++it) + { + dest.push_back( + equal_exprt( + symbol_exprt(it->first, it->second.type()), it->second)); + } +} + +bool ssa_const_propagatort::valuest::maps_to_top(const exprt &expr) const +{ + find_symbols_sett symbols; + find_symbols(expr, symbols); + for(find_symbols_sett::const_iterator it=symbols.begin(); + it!=symbols.end(); ++it) + { + if(replace_const.expr_map.find(*it)== + replace_const.expr_map.end()) + return true; + } + return false; +} + +void ssa_const_propagatort::assign( + valuest &dest, + const exprt &lhs, + exprt rhs, + const namespacet &ns) const +{ +#ifdef DEBUG + std::cout << "assign: " << from_expr(ns, "", lhs) + << " := " << from_expr(ns, "", rhs) << std::endl; +#endif + + values.replace_const(rhs); + +#ifdef DEBUG + std::cout << "replace: " << from_expr(ns, "", lhs) + << " := " << from_expr(ns, "", rhs) << std::endl; +#endif + + rhs=simplify_expr(rhs, ns); + +#ifdef DEBUG + std::cout << "simplified: " << from_expr(ns, "", lhs) + << " := " << from_expr(ns, "", rhs) << std::endl; +#endif + + dest.set_to(lhs, rhs); +} + +bool ssa_const_propagatort::valuest::set_to_top(const irep_idt &id) +{ + bool result=false; + replace_symbolt::expr_mapt::iterator r_it= + replace_const.expr_map.find(id); + if(r_it!=replace_const.expr_map.end()) + { + replace_const.expr_map.erase(r_it); + result=true; + } + if(top_ids.find(id)==top_ids.end()) + { + top_ids.insert(id); + result=true; + } + return result; +} + +bool ssa_const_propagatort::valuest::set_to_top(const exprt &expr) +{ + return set_to_top(to_symbol_expr(expr).get_identifier()); +} + +void ssa_const_propagatort::valuest::set_to( + const irep_idt &lhs_id, + const exprt &rhs_val) +{ + if(replace_const.expr_map[lhs_id]!=rhs_val) + { + replace_const.expr_map[lhs_id]=rhs_val; + iterate=true; + } + std::set::iterator it=top_ids.find(lhs_id); + if(it!=top_ids.end()) + top_ids.erase(it); +} + +void ssa_const_propagatort::valuest::set_to( + const exprt &lhs, + const exprt &rhs_val) +{ + const irep_idt &lhs_id=to_symbol_expr(lhs).get_identifier(); + set_to(lhs_id, rhs_val); +} + +void ssa_const_propagatort::valuest::output( + std::ostream &out, + const namespacet &ns) const +{ + out << "const map: " << std::endl; + for(replace_symbolt::expr_mapt::const_iterator + it=replace_const.expr_map.begin(); + it!=replace_const.expr_map.end(); + ++it) + out << ' ' << it->first << "=" + << from_expr(ns, "", it->second) << std::endl; + out << "top ids: " << std::endl; + for(std::set::const_iterator + it=top_ids.begin(); + it!=top_ids.end(); + ++it) + out << ' ' << *it << std::endl; +} + +bool ssa_const_propagatort::valuest::merge(const valuest &src) +{ + bool changed=false; + for(replace_symbolt::expr_mapt::const_iterator + it=src.replace_const.expr_map.begin(); + it!=src.replace_const.expr_map.end(); ++it) + { + replace_symbolt::expr_mapt::iterator + c_it=replace_const.expr_map.find(it->first); + if(c_it!=replace_const.expr_map.end()) + { + if(c_it->second!=it->second) + { + set_to_top(it->first); + changed=true; + } + } + else if(top_ids.find(it->first)==top_ids.end()) + { + set_to(it->first, it->second); + changed=true; + } + } + + return changed; +} diff --git a/src/ssa/ssa_const_propagator.h b/src/ssa/ssa_const_propagator.h new file mode 100644 index 000000000..c8db8df51 --- /dev/null +++ b/src/ssa/ssa_const_propagator.h @@ -0,0 +1,75 @@ +/*******************************************************************\ + +Module: SSA Constant Propagator + +Author: Kumar Madhukar + +\*******************************************************************/ + +#ifndef CPROVER_2LS_SSA_SSA_CONST_PROPAGATOR_H +#define CPROVER_2LS_SSA_SSA_CONST_PROPAGATOR_H + +#include +#include + +#include "local_ssa.h" + +class ssa_const_propagatort:public messaget +{ +public: + void operator()( + std::list &dest, + const local_SSAt &src); + + struct valuest + { + public: + // maps variables to constants + replace_symbolt replace_const; + std::set top_ids; + + void output(std::ostream &, const namespacet &) const; + + bool merge(const valuest &src); + + + void clear() + { + replace_const.expr_map.clear(); + replace_const.type_map.clear(); + top_ids.clear(); + } + + bool empty() const + { + return replace_const.expr_map.empty() && + replace_const.type_map.empty() && + top_ids.empty(); + } + + void set_to(const exprt &lhs, const exprt &rhs_val); + void set_to(const irep_idt &lhs_id, const exprt &rhs_val); + + bool maps_to_top(const exprt &expr) const; + bool set_to_top(const exprt &expr); + bool set_to_top(const irep_idt &id); + + bool iterate; + }; + + valuest values; + +protected: + void assign( + valuest &dest, + const exprt &lhs, + exprt rhs, + const namespacet &ns) const; + + exprt evaluate_casts_in_constants( + exprt expr, + const typet& parent_type, + bool &valid) const; +}; + +#endif // CPROVER_2LS_SSA_SSA_CONST_PROPAGATOR_H diff --git a/src/ssa/ssa_db.cpp b/src/ssa/ssa_db.cpp index 669fdae28..cfb570f0e 100644 --- a/src/ssa/ssa_db.cpp +++ b/src/ssa/ssa_db.cpp @@ -7,3 +7,15 @@ Author: Peter Schrammel \*******************************************************************/ #include "ssa_db.h" + +void ssa_dbt::depgraph_create( + const function_namet &function_name, + const namespacet &ns, + ssa_inlinert &ssa_inliner, + bool entry) +{ + depgraph_store[function_name]=new ssa_dependency_grapht(*this, ns); + const local_SSAt &SSA=this->get(function_name); + depgraph_store[function_name]->create(SSA, ssa_inliner, entry); +} + diff --git a/src/ssa/ssa_db.h b/src/ssa/ssa_db.h index c7c92ed91..c3c332074 100644 --- a/src/ssa/ssa_db.h +++ b/src/ssa/ssa_db.h @@ -12,14 +12,19 @@ Author: Peter Schrammel #include #include +#include #include #include +class ssa_inlinert; +class ssa_dependency_grapht; + class ssa_dbt { public: typedef irep_idt function_namet; typedef std::map functionst; + typedef std::map depgrapht; typedef std::map solverst; explicit ssa_dbt(const optionst &_options): @@ -33,14 +38,22 @@ class ssa_dbt delete item.second; for(auto &item : the_solvers) delete item.second; + for(auto &item : depgraph_store) + delete item.second; } - inline local_SSAt &get(const function_namet &function_name) const + local_SSAt &get(const function_namet &function_name) const { return *store.at(function_name); } - inline incremental_solvert &get_solver(const function_namet &function_name) + ssa_dependency_grapht &get_depgraph( + const function_namet &function_name) const + { + return *depgraph_store.at(function_name); + } + + incremental_solvert &get_solver(const function_namet &function_name) { solverst::iterator it=the_solvers.find(function_name); if(it!=the_solvers.end()) @@ -53,15 +66,15 @@ class ssa_dbt return *the_solvers.at(function_name); } - inline functionst &functions() { return store; } - inline solverst &solvers() { return the_solvers; } + functionst &functions() { return store; } + solverst &solvers() { return the_solvers; } - inline bool exists(const function_namet &function_name) const + bool exists(const function_namet &function_name) const { return store.find(function_name)!=store.end(); } - inline void create( + void create( const function_namet &function_name, const goto_functionst::goto_functiont &goto_function, const namespacet &ns) @@ -69,9 +82,22 @@ class ssa_dbt store[function_name]=new unwindable_local_SSAt(goto_function, ns); } + void depgraph_create( + const function_namet &function_name, + const namespacet &ns, + ssa_inlinert &ssa_inliner, + bool entry) + { + depgraph_store[function_name]=new ssa_dependency_grapht(*this, ns); + const local_SSAt &SSA=this->get(function_name); + depgraph_store[function_name]->create(SSA, ssa_inliner, entry); + } + + protected: const optionst &options; functionst store; + depgrapht depgraph_store; solverst the_solvers; }; diff --git a/src/ssa/ssa_dependency_graph.cpp b/src/ssa/ssa_dependency_graph.cpp new file mode 100644 index 000000000..e7490c685 --- /dev/null +++ b/src/ssa/ssa_dependency_graph.cpp @@ -0,0 +1,457 @@ +/*******************************************************************\ + +Module: SSA Dependency Graph + +Author: Madhukar Kumar + +\*******************************************************************/ + +#include +#include +#include + +#include + +#include "ssa_dependency_graph.h" + +void ssa_dependency_grapht::output(std::ostream &out) const +{ + for(unsigned index=0; index Used Symbols: "; + for(find_symbols_sett::const_iterator u_it= + depnodes_map[index].used_symbols.begin(); + u_it!=depnodes_map[index].used_symbols.end(); u_it++) + { + out << *u_it << " "; + } + out << "\n"; + + out << "Node#" << index << "; -> Modified Symbols: "; + for(find_symbols_sett::const_iterator m_it= + depnodes_map[index].modified_symbols.begin(); + m_it!=depnodes_map[index].modified_symbols.end(); m_it++) + { + out << *m_it << " "; + } + out << "\n"; + + out << "Successors: "; + for(unsigned i=0; ilocation; + + // loop-head select + // TODO: this is an ugly hack (this can be changed + // as soon as unwindable_local_SSA provides + // smooth renaming with odometers) + if(e_it->op1().id()==ID_if && + e_it->op1().op0().id()==ID_symbol) + { + std::string var_string=id2string(e_it->op1().op0().get(ID_identifier)); + if(((var_string.substr(0, 14))=="ssa::$guard#ls")) + { + temp_node.is_loop=true; + temp_node.guard=not_exprt(e_it->op1().op0()); + } + } + + equal_exprt e=to_equal_expr(*e_it); + exprt &lhs=e.lhs(); exprt &rhs=e.rhs(); + + find_symbols(rhs, temp_node.used_symbols); + find_symbols(lhs, temp_node.modified_symbols); + + if(!ignore_equality_done) + { + std::string var_string=id2string(to_symbol_expr(lhs).get_identifier()); + if(((var_string.substr(0, 11))=="ssa::$guard") && (rhs.is_true())) + { + ignore_equality=true; + ignore_equality_done=true; + } + } + + if(first_node && ignore_equality) + { + if(entry) + { + depnodes_map.push_back(temp_node); + } + ignore_equality=false; + } + else + { + depnodes_map.push_back(temp_node); + } + } + + // collecting symbols from constraints and populating dependency graph nodes + for(local_SSAt::nodet::constraintst::const_iterator c_it= + node.constraints.begin(); + c_it!=node.constraints.end(); c_it++) + { + find_symbols(*c_it, all_ssa_symbols); + + depnodet temp_node; + temp_node.is_assertion=false; + temp_node.is_function_call=false; + temp_node.is_loop=false; + temp_node.node_info=*c_it; + temp_node.location=n_it->location; + find_symbols(*c_it, temp_node.used_symbols); + find_symbols(*c_it, temp_node.modified_symbols); + depnodes_map.push_back(temp_node); + } + + // collecting symbols from assertionst and populating dependency graph nodes + for(local_SSAt::nodet::assertionst::const_iterator a_it= + node.assertions.begin(); + a_it!=node.assertions.end(); a_it++) + { + find_symbols(*a_it, all_ssa_symbols); + + depnodet temp_node; + temp_node.is_assertion=true; + temp_node.is_function_call=false; + temp_node.is_loop=false; + temp_node.node_info=*a_it; + temp_node.location=n_it->location; + find_symbols(*a_it, temp_node.used_symbols); + depnodes_map.push_back(temp_node); + } + +#if 0 + // collecting symbols from assumptionst + // and populating dependency graph nodes + for(local_SSAt::nodet::assumptionst::const_iterator a_it= + node.assumptions.begin(); + a_it!=node.assumptions.end(); a_it++) + { + find_symbols(*a_it, all_ssa_symbols); + + depnodet temp_node; + temp_node.is_assertion=false; + temp_node.is_function_call=false; + temp_node.node_info=*a_it; + find_symbols(*a_it, temp_node.used_symbols); + find_symbols(*a_it, temp_node.modified_symbols); + depnodes_map.push_back(temp_node); + } +#endif + + // collecting symbols from function_callst + // and populating dependency graph nodes + for(local_SSAt::nodet::function_callst::const_iterator f_it= + node.function_calls.begin(); + f_it!=node.function_calls.end(); f_it++) + { + irep_idt fname=to_symbol_expr(f_it->function()).get_identifier(); + if(ssa_db.exists(fname)) + { + const local_SSAt &fSSA=ssa_db.get(fname); + + /******************************************************************/ + /******* additional nodes needed to fix the dependency tree *******/ + + exprt guard_binding; + exprt::operandst bindings_in, bindings_out; + int counter=ssa_inliner.get_rename_counter(); + + ssa_inliner.get_guard_binding(SSA, fSSA, n_it, guard_binding, counter); + +#if 0 + { + depnodet temp_node; + temp_node.is_assertion=false; + temp_node.is_function_call=false; + temp_node.node_info=guard_binding; + + equal_exprt e=to_equal_expr(guard_binding); + exprt &lhs=e.lhs(); exprt &rhs=e.rhs(); + + find_symbols(rhs, temp_node.used_symbols); + find_symbols(lhs, temp_node.modified_symbols); + depnodes_map.push_back(temp_node); + } +#endif + + ssa_inliner.get_bindings( + SSA, fSSA, n_it, f_it, bindings_in, bindings_out, counter); + + for(exprt::operandst::const_iterator b_it=bindings_in.begin(); + b_it!=bindings_in.end(); b_it++) + { + depnodet temp_node; + temp_node.is_assertion=false; + temp_node.is_function_call=false; + temp_node.is_loop=false; + temp_node.node_info=*b_it; + temp_node.location=n_it->location; + + equal_exprt e=to_equal_expr(*b_it); + exprt &lhs=e.lhs(); exprt &rhs=e.rhs(); + + find_symbols(rhs, temp_node.used_symbols); + find_symbols(lhs, temp_node.modified_symbols); + depnodes_map.push_back(temp_node); + } + + for(exprt::operandst::const_iterator b_it=bindings_out.begin(); + b_it!=bindings_out.end(); b_it++) + { + depnodet temp_node; + temp_node.is_assertion=false; + temp_node.is_function_call=false; + temp_node.is_loop=false; + temp_node.node_info=*b_it; + temp_node.location=n_it->location; + + equal_exprt e=to_equal_expr(*b_it); + exprt &lhs=e.lhs(); exprt &rhs=e.rhs(); + + find_symbols(rhs, temp_node.used_symbols); + find_symbols(lhs, temp_node.modified_symbols); + depnodes_map.push_back(temp_node); + } + + /******************************************************************/ + + depnodet temp_node; + temp_node.guard=guard_binding; + temp_node.is_assertion=false; + temp_node.is_function_call=true; + temp_node.is_loop=false; + temp_node.node_info=*f_it; + temp_node.rename_counter=counter; + temp_node.location=n_it->location; + + find_symbols(guard_binding, temp_node.used_symbols); + + for(local_SSAt::var_listt::const_iterator p_it=fSSA.params.begin(); + p_it!=fSSA.params.end(); p_it++) + { + irep_idt id=(*p_it).get(ID_identifier); + ssa_inliner.rename(id, counter); + all_ssa_symbols.insert(id); + temp_node.used_symbols.insert(id); + } + + for(local_SSAt::var_sett::const_iterator g_it=fSSA.globals_in.begin(); + g_it!=fSSA.globals_in.end(); g_it++) + { + irep_idt id=(*g_it).get(ID_identifier); + ssa_inliner.rename(id, counter); + all_ssa_symbols.insert(id); + temp_node.used_symbols.insert(id); + } + + for(local_SSAt::var_sett::const_iterator g_it=fSSA.globals_out.begin(); + g_it!=fSSA.globals_out.end(); g_it++) + { + irep_idt id=(*g_it).get(ID_identifier); + ssa_inliner.rename(id, counter); + all_ssa_symbols.insert(id); + temp_node.modified_symbols.insert(id); + } + + depnodes_map.push_back(temp_node); + } + } + } + first_node=false; + + depnodet source_node; + source_node.is_assertion=false; + source_node.is_function_call=false; + source_node.is_loop=false; + + // params and globals_in are the modified_symbols at source_node + + for(local_SSAt::var_listt::const_iterator p_it=SSA.params.begin(); + p_it!=SSA.params.end(); p_it++) + { + irep_idt id=(*p_it).get(ID_identifier); + source_node.modified_symbols.insert(id); + } + + for(local_SSAt::var_sett::const_iterator g_it=SSA.globals_in.begin(); + g_it!=SSA.globals_in.end(); g_it++) + { + irep_idt id=(*g_it).get(ID_identifier); + source_node.modified_symbols.insert(id); + } + + depnodes_map.push_back(source_node); // source_node + + top_node_index=depnodes_map.size()-1; + + for(find_symbols_sett::const_iterator + s_it=all_ssa_symbols.begin(); s_it!=all_ssa_symbols.end(); s_it++) + { + for(unsigned m_index=0; m_index +#include + +#include "local_ssa.h" + +class ssa_inlinert; +class ssa_dbt; + +class ssa_dependency_grapht +{ +public: + ssa_dependency_grapht(ssa_dbt &_db, const namespacet &_ns): + ssa_db(_db), + ns(_ns) + { + } + + struct annotated_predecessort + { + int predecessor_node_index; + find_symbols_sett annotation; + }; + + typedef std::list annotated_predecessorst; + + struct depnodet + { + exprt node_info; + exprt guard; // guard binding or loop-head select + bool is_assertion; + bool is_function_call; + bool is_loop; + // bool trivial_guard; + int rename_counter; + find_symbols_sett used_symbols; + find_symbols_sett modified_symbols; + annotated_predecessorst predecessors; + std::vector successors; + local_SSAt::locationt location; + }; + + // typedef std::map depnodest; + typedef std::vector depnodest; + depnodest depnodes_map; + + int top_node_index; + + // special source_node and sink_node + // depnodet source_node=depnodes_map[top_node_index]; + // depnodet sink_node=depnodes_map[0]; + + void create(const local_SSAt &SSA, ssa_inlinert &ssa_inliner, bool entry); + void output(std::ostream &) const; + +protected: + ssa_dbt &ssa_db; + const namespacet &ns; +}; + +#endif // CPROVER_2LS_SSA_SSA_DEPENDENCY_GRAPH_H diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index 2f68901a0..9949eb0dc 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -2,7 +2,7 @@ Module: SSA Inliner -Author: Peter Schrammel +Author: Peter Schrammel, Madhukar Kumar \*******************************************************************/ @@ -11,6 +11,182 @@ Author: Peter Schrammel #include "ssa_inliner.h" +/*******************************************************************\ + +Function: ssa_inlinert::get_guard_binding + + Inputs: + + Outputs: + + Purpose: get guard binding for function call + +\*******************************************************************/ + +void ssa_inlinert::get_guard_binding( + const local_SSAt &SSA, + const local_SSAt &fSSA, + local_SSAt::nodest::const_iterator n_it, + exprt &guard_binding, + int counter) +{ + exprt callee_guard, caller_guard; + callee_guard=fSSA.guard_symbol(fSSA.goto_function.body.instructions.begin()); + rename(callee_guard, counter); + caller_guard=SSA.guard_symbol(n_it->location); + + guard_binding=equal_exprt(callee_guard, caller_guard); +} + +/*******************************************************************\ + +Function: ssa_inlinert::get_bindings + + Inputs: + + Outputs: + + Purpose: get bindings for function call + +\*******************************************************************/ + +void ssa_inlinert::get_bindings( + const local_SSAt &SSA, + const local_SSAt &fSSA, + local_SSAt::nodest::const_iterator n_it, + local_SSAt::nodet::function_callst::const_iterator f_it, + exprt::operandst &bindings_in, + exprt::operandst &bindings_out, + int counter) +{ + // getting globals at call site + local_SSAt::var_sett cs_globals_in, cs_globals_out; + goto_programt::const_targett loc=n_it->location; + + SSA.get_globals(loc, cs_globals_in); + SSA.get_globals(loc, cs_globals_out, false); + +#if 0 + std::cout << "cs_globals_in: "; + for(summaryt::var_sett::const_iterator it=cs_globals_in.begin(); + it!=cs_globals_in.end(); it++) + std::cout << from_expr(SSA.ns, "", *it) << " "; + std::cout << std::endl; + + std::cout << "cs_globals_out: "; + for(summaryt::var_sett::const_iterator it=cs_globals_out.begin(); + it!=cs_globals_out.end(); it++) + std::cout << from_expr(SSA.ns, "", *it) << " "; + std::cout << std::endl; +#endif + + // equalities for arguments + get_replace_params(SSA, fSSA.params, n_it, *f_it, bindings_in, counter); + + // equalities for globals_in + get_replace_globals_in( + fSSA.globals_in, *f_it, cs_globals_in, bindings_in, counter); + + // equalities for globals out (including unmodified globals) + get_replace_globals_out( + fSSA.globals_out, + *f_it, + cs_globals_in, + cs_globals_out, + bindings_out, + counter); +} + +/*******************************************************************\ + +Function: ssa_inlinert::get_inlined + + Inputs: + + Outputs: + + Purpose: get inlined function call + + +\*******************************************************************/ + +bool ssa_inlinert::get_inlined( + const local_SSAt &SSA, + local_SSAt::nodest::const_iterator n_it, + local_SSAt::nodet::function_callst::const_iterator f_it, + bool forward, + exprt::operandst &assert_summaries, + exprt::operandst &noassert_summaries, + exprt::operandst &bindings, + assertion_mapt &assertion_map, + int counter, + bool error_summ) +{ + irep_idt fname=to_symbol_expr(f_it->function()).get_identifier(); + const local_SSAt &fSSA=ssa_db.get(fname); + + bool assertion_flag=get_summaries( + fSSA, + summaryt::call_sitet(fSSA.goto_function.body.instructions.end()), + forward, + assert_summaries, + noassert_summaries, + bindings, + assertion_map, + error_summ); + + // bindings + exprt guard_binding; + get_guard_binding(SSA, fSSA, n_it, guard_binding, counter); + bindings.push_back(guard_binding); + get_bindings(SSA, fSSA, n_it, f_it, bindings, bindings, counter); + + bool first_equality=true; + for(local_SSAt::nodest::const_iterator n_it=fSSA.nodes.begin(); + n_it!=fSSA.nodes.end(); n_it++) + { + const local_SSAt::nodet &fnode=*n_it; + + for(local_SSAt::nodet::equalitiest::const_iterator e_it= + fnode.equalities.begin(); e_it!=fnode.equalities.end(); e_it++) + { + // unless lhs starts with "ssa::guard" and rhs is true + // because that one is replaced by the guard binding + const equal_exprt &e=to_equal_expr(*e_it); + const exprt &lhs=e.lhs(); const exprt &rhs=e.rhs(); + std::string var_string=id2string(to_symbol_expr(lhs).get_identifier()); + if((var_string.substr(0, 11)=="ssa::$guard") && + rhs.is_true() && first_equality) + { + first_equality=false; + } + else + { + noassert_summaries.push_back(*e_it); + rename(noassert_summaries.back(), counter); + } + } + for(local_SSAt::nodet::constraintst::const_iterator c_it= + fnode.constraints.begin(); c_it!=fnode.constraints.end(); c_it++) + { + noassert_summaries.push_back(*c_it); + rename(noassert_summaries.back(), counter); + } + for(local_SSAt::nodet::assertionst::const_iterator a_it= + fnode.assertions.begin(); a_it!=fnode.assertions.end(); a_it++) + { +#if 0 + assert_summaries.push_back(*a_it); + rename(assert_summaries.back(), counter); +#endif + assertion_flag=true; + } + } + + return assertion_flag; +} + + /*******************************************************************\ Function: ssa_inlinert::get_summary @@ -19,34 +195,29 @@ Function: ssa_inlinert::get_summary Outputs: - Purpose: get summary for function call + Purpose: get summary for non-inlined function calls \*******************************************************************/ -void ssa_inlinert::get_summary( +bool ssa_inlinert::get_summary( const local_SSAt &SSA, local_SSAt::nodest::const_iterator n_it, local_SSAt::nodet::function_callst::const_iterator f_it, - const summaryt &summary, bool forward, - exprt::operandst &summaries, - exprt::operandst &bindings) + exprt::operandst &assert_summaries, + exprt::operandst &noassert_summaries, + exprt::operandst &bindings, + int counter, + bool error_summ) { - counter++; + irep_idt fname=to_symbol_expr(f_it->function()).get_identifier(); + const summaryt &summary=summary_db.get(fname); // getting globals at call site local_SSAt::var_sett cs_globals_in, cs_globals_out; goto_programt::const_targett loc=n_it->location; - if(forward) - { - SSA.get_globals(loc, cs_globals_in); - SSA.get_globals(loc, cs_globals_out, false); - } - else - { - SSA.get_globals(loc, cs_globals_out); - SSA.get_globals(loc, cs_globals_in, false); - } + SSA.get_globals(loc, cs_globals_in); + SSA.get_globals(loc, cs_globals_out, false); #if 0 std::cout << "cs_globals_in: "; @@ -63,43 +234,60 @@ void ssa_inlinert::get_summary( #endif // equalities for arguments - bindings.push_back(get_replace_params(summary.params, *f_it)); + get_replace_params(SSA, summary.params, n_it, *f_it, bindings, counter); // equalities for globals_in - if(forward) - bindings.push_back( - get_replace_globals_in(summary.globals_in, cs_globals_in)); - else - bindings.push_back( - get_replace_globals_in(summary.globals_out, cs_globals_out)); + get_replace_globals_in( + summary.globals_in, *f_it, cs_globals_in, bindings, counter); // constraints for transformer + exprt transformer; - if(forward) - transformer=summary.fw_transformer.is_nil() ? true_exprt() : - summary.fw_transformer; + + if(error_summ) + { + // update transformer using the error_summaries map + summaryt::call_sitet call_site(loc); + summaryt::error_summariest::const_iterator e_it= + summary.error_summaries.find(call_site); + if(e_it!=summary.error_summaries.end() && + !e_it->second.is_nil()) + transformer=e_it->second; + else + transformer=true_exprt(); + } else { - transformer=summary.bw_transformer.is_nil() ? true_exprt() : - summary.bw_transformer; + if(forward) + transformer=summary.fw_transformer.is_nil() ? true_exprt() : + summary.fw_transformer; + else + transformer=summary.bw_transformer.is_nil() ? true_exprt() : + summary.bw_transformer; } - rename(transformer); - summaries.push_back( - implies_exprt(SSA.guard_symbol(n_it->location), transformer)); - // equalities for globals out (including unmodified globals) - if(forward) - bindings.push_back( - get_replace_globals_out( - summary.globals_out, - cs_globals_in, - cs_globals_out)); + rename(transformer, counter); + if(summary.has_assertion) + { + assert_summaries.push_back( + implies_exprt(SSA.guard_symbol(n_it->location), transformer)); + } else - bindings.push_back( - get_replace_globals_out( - summary.globals_in, - cs_globals_out, - cs_globals_in)); + { + noassert_summaries.push_back( + implies_exprt(SSA.guard_symbol(n_it->location), transformer)); + } + + // equalities for globals out (including unmodified globals) + get_replace_globals_out( + summary.globals_out, + *f_it, + cs_globals_in, + cs_globals_out, + bindings, + counter); + + return summary.has_assertion; } /*******************************************************************\ @@ -121,6 +309,41 @@ exprt ssa_inlinert::get_summaries(const local_SSAt &SSA) return and_exprt(conjunction(bindings), conjunction(summaries)); } +exprt ssa_inlinert::get_summaries( + const local_SSAt &SSA, + assertion_mapt &assertion_map) +{ + exprt::operandst summaries, bindings; + get_summaries(SSA, true, summaries, bindings, assertion_map); + return and_exprt(conjunction(bindings), conjunction(summaries)); +} + +void ssa_inlinert::get_summaries( + const local_SSAt &SSA, + bool forward, + exprt::operandst &summaries, + exprt::operandst &bindings) +{ + assertion_mapt assertion_map; + get_summaries( + SSA, + summaryt::call_sitet(SSA.goto_function.body.instructions.end()), + forward, summaries, summaries, bindings, assertion_map); +} + +void ssa_inlinert::get_summaries( + const local_SSAt &SSA, + bool forward, + exprt::operandst &summaries, + exprt::operandst &bindings, + assertion_mapt &assertion_map) +{ + get_summaries( + SSA, + summaryt::call_sitet(SSA.goto_function.body.instructions.end()), + forward, summaries, summaries, bindings, assertion_map); +} + /*******************************************************************\ Function: ssa_inlinert::get_summaries @@ -133,31 +356,82 @@ Function: ssa_inlinert::get_summaries \*******************************************************************/ -void ssa_inlinert::get_summaries( +bool ssa_inlinert::get_summaries( const local_SSAt &SSA, + const summaryt::call_sitet ¤t_call_site, bool forward, - exprt::operandst &summaries, - exprt::operandst &bindings) + exprt::operandst &assert_summaries, + exprt::operandst &noassert_summaries, + exprt::operandst &bindings, + bool error_summ) { + assertion_mapt assertion_map; + return get_summaries( + SSA, + summaryt::call_sitet(SSA.goto_function.body.instructions.end()), + forward, assert_summaries, noassert_summaries, bindings, assertion_map); +} + +bool ssa_inlinert::get_summaries( + const local_SSAt &SSA, + const summaryt::call_sitet ¤t_call_site, + bool forward, + exprt::operandst &assert_summaries, + exprt::operandst &noassert_summaries, + exprt::operandst &bindings, + assertion_mapt &assertion_map, + bool error_summ) +{ + bool assertion_flag=false; for(local_SSAt::nodest::const_iterator n_it=SSA.nodes.begin(); n_it!=SSA.nodes.end(); n_it++) { + for(local_SSAt::nodet::assertionst::const_iterator a_it= + n_it->assertions.begin(); + a_it!=n_it->assertions.end(); a_it++) + { + assertion_map[n_it->location].push_back(*a_it); + rename(assertion_map[n_it->location].back(), counter); + } for(local_SSAt::nodet::function_callst::const_iterator f_it= n_it->function_calls.begin(); f_it!=n_it->function_calls.end(); f_it++) { - assert(f_it->function().id()==ID_symbol); // no function pointers + // do not use summary for current call site + summaryt::call_sitet this_call_site(n_it->location); + if(current_call_site==this_call_site) + continue; + irep_idt fname=to_symbol_expr(f_it->function()).get_identifier(); - if(summary_db.exists(fname)) + // get inlined function + if(n_it->function_calls_inlined) { - get_summary(SSA, n_it, f_it, summary_db.get(fname), - forward, summaries, bindings); + counter++; + bool new_assertion_flag= + get_inlined( + SSA, n_it, f_it, + forward, assert_summaries, noassert_summaries, + bindings, assertion_map, counter, error_summ); + assertion_flag=assertion_flag || new_assertion_flag; + } + // get summary + else if(summary_db.exists(fname)) + { + counter++; + bool new_assertion_flag= + get_summary( + SSA, n_it, f_it, + forward, assert_summaries, noassert_summaries, + bindings, counter, error_summ); + assertion_flag=assertion_flag || new_assertion_flag; } } } + return assertion_flag; } + /*******************************************************************\ Function: ssa_inlinert::replace @@ -175,7 +449,8 @@ Function: ssa_inlinert::replace void ssa_inlinert::replace( local_SSAt &SSA, bool forward, - bool preconditions_as_assertions) + bool preconditions_as_assertions, + int counter) { for(local_SSAt::nodest::iterator n_it=SSA.nodes.begin(); n_it!=SSA.nodes.end(); n_it++) @@ -202,7 +477,7 @@ void ssa_inlinert::replace( // replace replace( SSA, n_it, f_it, cs_globals_in, cs_globals_out, summary, - forward, preconditions_as_assertions); + forward, preconditions_as_assertions, counter); // remove function_call rm_function_calls.insert(f_it); @@ -232,7 +507,9 @@ Function: ssa_inlinert::replace void ssa_inlinert::replace( local_SSAt &SSA, const ssa_dbt &ssa_db, - bool recursive, bool rename) + int counter, + bool recursive, + bool rename) { for(local_SSAt::nodest::iterator n_it=SSA.nodes.begin(); n_it!=SSA.nodes.end(); n_it++) @@ -259,11 +536,14 @@ void ssa_inlinert::replace( if(recursive) { - replace(fSSA, ssa_db, true); + replace(fSSA, ssa_db, true, counter); } // replace - replace(SSA.nodes, n_it, f_it, cs_globals_in, cs_globals_out, fSSA); + replace( + SSA.nodes, n_it, f_it, + cs_globals_in, cs_globals_out, + fSSA, counter); } else // just add to nodes { @@ -305,15 +585,14 @@ void ssa_inlinert::replace( const local_SSAt::var_sett &cs_globals_out, const summaryt &summary, bool forward, - bool preconditions_as_assertions) + bool preconditions_as_assertions, + int counter) { - counter++; - // equalities for arguments - replace_params(summary.params, *f_it); + replace_params(summary.params, *f_it, counter); // equalities for globals_in - replace_globals_in(summary.globals_in, cs_globals_in); + replace_globals_in(summary.globals_in, cs_globals_in, counter); // constraints for precondition and transformer exprt precondition; @@ -323,17 +602,19 @@ void ssa_inlinert::replace( precondition=summary.bw_precondition; if(!preconditions_as_assertions) { - rename(precondition); + rename(precondition, counter); node->constraints.push_back( - implies_exprt(SSA.guard_symbol(node->location), - precondition)); + implies_exprt( + SSA.guard_symbol(node->location), + precondition)); } else { - rename(precondition); + rename(precondition, counter); node->assertions.push_back( - implies_exprt(SSA.guard_symbol(node->location), - precondition)); + implies_exprt( + SSA.guard_symbol(node->location), + precondition)); } exprt transformer; if(forward) @@ -342,13 +623,14 @@ void ssa_inlinert::replace( transformer=summary.bw_transformer; node->constraints.push_back(transformer); // copy exprt &_transformer=node->constraints.back(); - rename(_transformer); + rename(_transformer, counter); // remove function call rm_function_calls.insert(f_it); // equalities for globals out (including unmodified globals) - replace_globals_out(summary.globals_out, cs_globals_in, cs_globals_out); + replace_globals_out( + summary.globals_out, cs_globals_in, cs_globals_out, counter); } /*******************************************************************\ @@ -373,22 +655,21 @@ void ssa_inlinert::replace( local_SSAt::nodet::function_callst::iterator f_it, const local_SSAt::var_sett &cs_globals_in, const local_SSAt::var_sett &cs_globals_out, - const local_SSAt &function) + const local_SSAt &function, + int counter) { - counter++; - // equalities for arguments - replace_params(function.params, *f_it); + replace_params(function.params, *f_it, counter); // equalities for globals_in - replace_globals_in(function.globals_in, cs_globals_in); + replace_globals_in(function.globals_in, cs_globals_in, counter); // add function body for(local_SSAt::nodest::const_iterator n_it=function.nodes.begin(); n_it!=function.nodes.end(); n_it++) { local_SSAt::nodet n=*n_it; // copy - rename(n); + rename(n, counter); new_nodes.push_back(n); } @@ -396,7 +677,8 @@ void ssa_inlinert::replace( rm_function_calls.insert(f_it); // equalities for globals out (including unmodified globals) - replace_globals_out(function.globals_out, cs_globals_in, cs_globals_out); + replace_globals_out( + function.globals_out, cs_globals_in, cs_globals_out, counter); } /*******************************************************************\ @@ -411,20 +693,26 @@ Function: ssa_inlinert::get_replace_globals_in \*******************************************************************/ -exprt ssa_inlinert::get_replace_globals_in( +void ssa_inlinert::get_replace_globals_in( const local_SSAt::var_sett &globals_in, - const local_SSAt::var_sett &globals) + const function_application_exprt &funapp_expr, + const local_SSAt::var_sett &globals, + exprt::operandst &c, + int counter) { + std::string suffix=id2string(funapp_expr.get(ID_suffix)); + // equalities for globals_in - exprt::operandst c; for(summaryt::var_sett::const_iterator it=globals_in.begin(); it!=globals_in.end(); it++) { symbol_exprt lhs=*it; // copy - rename(lhs); + rename(lhs, counter); symbol_exprt rhs; if(find_corresponding_symbol(*it, globals, rhs)) { + rhs.set_identifier(id2string(rhs.get_identifier())+suffix); + debug() << "binding: " << lhs.get_identifier() << "==" << rhs.get_identifier() << eom; c.push_back(equal_exprt(lhs, rhs)); @@ -435,31 +723,20 @@ exprt ssa_inlinert::get_replace_globals_in( << "' not bound in caller" << eom; #endif } - return conjunction(c); + // return conjunction(c); } -/*******************************************************************\ - -Function: ssa_inlinert::replace_globals_in - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - void ssa_inlinert::replace_globals_in( const local_SSAt::var_sett &globals_in, - const local_SSAt::var_sett &globals) + const local_SSAt::var_sett &globals, + int counter) { // equalities for globals_in for(summaryt::var_sett::const_iterator it=globals_in.begin(); it!=globals_in.end(); it++) { symbol_exprt lhs=*it; // copy - rename(lhs); + rename(lhs, counter); symbol_exprt rhs; if(find_corresponding_symbol(*it, globals, rhs)) { @@ -487,16 +764,25 @@ Function: ssa_inlinert::get_replace_params \*******************************************************************/ -exprt ssa_inlinert::get_replace_params( +void ssa_inlinert::get_replace_params( + const local_SSAt &SSA, const local_SSAt::var_listt ¶ms, - const function_application_exprt &funapp_expr) + local_SSAt::nodest::const_iterator n_it, + const function_application_exprt &funapp_expr, + exprt::operandst &c, + int counter) { // equalities for arguments - exprt::operandst c; local_SSAt::var_listt::const_iterator p_it=params.begin(); for(exprt::operandst::const_iterator it=funapp_expr.arguments().begin(); it!=funapp_expr.arguments().end(); it++, p_it++) { +#if 0 + std::cout << "replace param " << from_expr(SSA.ns, "", *p_it) + << "==" << from_expr(SSA.ns, "", *it) << std::endl; +#endif + +#if 0 local_SSAt::var_listt::const_iterator next_p_it=p_it; if(funapp_expr.arguments().size()!=params.size() && ++next_p_it==params.end()) // TODO: handle ellipsis @@ -504,29 +790,41 @@ exprt ssa_inlinert::get_replace_params( warning() << "ignoring excess function arguments" << eom; break; } +#endif - exprt lhs=*p_it; // copy - rename(lhs); - c.push_back(equal_exprt(lhs, *it)); + if(SSA.ns.follow(it->type()).id()==ID_struct) + { + exprt rhs=SSA.read_rhs(*it, n_it->location); // copy +#if 0 + std::cout << "split param " << from_expr(SSA.ns, "", *it) + << " into " << from_expr(SSA.ns, "", rhs) << std::endl; +#endif + forall_operands(o_it, rhs) + { + assert(p_it!=params.end()); + exprt lhs=*p_it; // copy + rename(lhs, counter); +#if 0 + std::cout << "split replace param " << from_expr(SSA.ns, "", *p_it) + << "==" << from_expr(SSA.ns, "", *o_it) << std::endl; +#endif + c.push_back(equal_exprt(lhs, *o_it)); + ++p_it; + } + } + else + { + exprt lhs=*p_it; // copy + rename(lhs, counter); + c.push_back(equal_exprt(lhs, *it)); + } } - return conjunction(c); } -/*******************************************************************\ - -Function: ssa_inlinert::replace_params - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - void ssa_inlinert::replace_params( const local_SSAt::var_listt ¶ms, - const function_application_exprt &funapp_expr) + const function_application_exprt &funapp_expr, + int counter) { // equalities for arguments local_SSAt::var_listt::const_iterator p_it=params.begin(); @@ -542,14 +840,14 @@ void ssa_inlinert::replace_params( } exprt lhs=*p_it; // copy - rename(lhs); + rename(lhs, counter); new_equs.push_back(equal_exprt(lhs, *it)); } } /*******************************************************************\ -Function: ssa_inlinert::get_replace_globals_out +Function: ssa_inlinert::replace_globals_out Inputs: @@ -559,43 +857,42 @@ Function: ssa_inlinert::get_replace_globals_out \*******************************************************************/ -exprt ssa_inlinert::get_replace_globals_out( +void ssa_inlinert::get_replace_globals_out( const local_SSAt::var_sett &globals_out, + const function_application_exprt &funapp_expr, const local_SSAt::var_sett &cs_globals_in, - const local_SSAt::var_sett &cs_globals_out) + const local_SSAt::var_sett &cs_globals_out, + exprt::operandst &c, + int counter) { + std::string suffix=id2string(funapp_expr.get(ID_suffix)); + // equalities for globals_out - exprt::operandst c; for(summaryt::var_sett::const_iterator it=cs_globals_out.begin(); it!=cs_globals_out.end(); it++) { - symbol_exprt rhs=*it; // copy - symbol_exprt lhs; - if(find_corresponding_symbol(*it, globals_out, lhs)) - rename(lhs); + symbol_exprt lhs=*it; // copy + + lhs.set_identifier(id2string(lhs.get_identifier())+suffix); + + symbol_exprt rhs; + if(find_corresponding_symbol(*it, globals_out, rhs)) + rename(rhs, counter); else - assert(find_corresponding_symbol(*it, cs_globals_in, lhs)); + { + bool found=find_corresponding_symbol(*it, cs_globals_in, rhs); + assert(found); + rhs.set_identifier(id2string(rhs.get_identifier())+suffix); + } c.push_back(equal_exprt(lhs, rhs)); } - return conjunction (c); } -/*******************************************************************\ - -Function: ssa_inlinert::replace_globals_out - - Inputs: - - Outputs: - - Purpose: equalities for globals out (including unmodified globals) - -\*******************************************************************/ - void ssa_inlinert::replace_globals_out( const local_SSAt::var_sett &globals_out, const local_SSAt::var_sett &cs_globals_in, - const local_SSAt::var_sett &cs_globals_out) + const local_SSAt::var_sett &cs_globals_out, + int counter) { // equalities for globals_out for(summaryt::var_sett::const_iterator it=cs_globals_out.begin(); @@ -604,7 +901,7 @@ void ssa_inlinert::replace_globals_out( symbol_exprt rhs=*it; // copy symbol_exprt lhs; if(find_corresponding_symbol(*it, globals_out, lhs)) - rename(lhs); + rename(lhs, counter); else assert(find_corresponding_symbol(*it, cs_globals_in, lhs)); new_equs.push_back(equal_exprt(lhs, rhs)); @@ -643,16 +940,36 @@ Function: ssa_inlinert::rename \*******************************************************************/ -void ssa_inlinert::rename(exprt &expr) +void ssa_inlinert::rename(irep_idt &id, int counter, bool attach) { - if(expr.id()==ID_symbol) + std::string id_str=id2string(id); + + if(!attach) { - symbol_exprt &sexpr=to_symbol_expr(expr); - irep_idt id=id2string(sexpr.get_identifier())+"@"+i2string(counter); - sexpr.set_identifier(id); + // find first @ where afterwards there are no letters + size_t pos=std::string::npos; + for(size_t i=0; i=0) + id=id_str+"@"+i2string(counter); } - Forall_operands(op, expr) - rename(*op); } /*******************************************************************\ @@ -667,16 +984,57 @@ Function: ssa_inlinert::rename \*******************************************************************/ -void ssa_inlinert::rename(local_SSAt::nodet &node) +void ssa_inlinert::rename(exprt &expr, int counter, bool attach) { - for(auto &e : node.equalities) - rename(e); - for(auto &c : node.constraints) - rename(c); - for(auto &a : node.assertions) - rename(a); - for(auto &f : node.function_calls) - rename(f); + if(expr.id()==ID_symbol || expr.id()==ID_nondet_symbol) + { + irep_idt id=expr.get(ID_identifier); + rename(id, counter, attach); + + expr.set(ID_identifier, id); + } + for(exprt::operandst::iterator it=expr.operands().begin(); + it!=expr.operands().end(); it++) + { + rename(*it, counter, attach); + } +} + +/*******************************************************************\ + +Function: ssa_inlinert::rename + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void ssa_inlinert::rename(local_SSAt::nodet &node, int counter) +{ + for(local_SSAt::nodet::equalitiest::iterator e_it=node.equalities.begin(); + e_it!=node.equalities.end(); e_it++) + { + rename(*e_it, counter); + } + for(local_SSAt::nodet::constraintst::iterator c_it=node.constraints.begin(); + c_it!=node.constraints.end(); c_it++) + { + rename(*c_it, counter); + } + for(local_SSAt::nodet::assertionst::iterator a_it=node.assertions.begin(); + a_it!=node.assertions.end(); a_it++) + { + rename(*a_it, counter); + } + for(local_SSAt::nodet::function_callst::iterator + f_it=node.function_calls.begin(); + f_it!=node.function_calls.end(); f_it++) + { + rename(*f_it, counter); + } } /*******************************************************************\ @@ -772,6 +1130,11 @@ void ssa_inlinert::rename_to_callee( replace_map[*it]=*p_it; } + /* replace_expr(replace_map, expr); + + replace_map.clear(); // arguments might contain globals, + // thus, we have to replace them separately + */ for(summaryt::var_sett::const_iterator it=cs_globals_in.begin(); it!=cs_globals_in.end(); it++) { @@ -919,4 +1282,3 @@ irep_idt ssa_inlinert::get_original_identifier(const symbol_exprt &s) id=id.substr(0, pos); return id; } - diff --git a/src/ssa/ssa_inliner.h b/src/ssa/ssa_inliner.h index 7cf8d0730..f8aaae6bc 100644 --- a/src/ssa/ssa_inliner.h +++ b/src/ssa/ssa_inliner.h @@ -2,7 +2,7 @@ Module: SSA Inliner -Author: Peter Schrammel +Author: Peter Schrammel, Kumar Madhukar \*******************************************************************/ @@ -19,58 +19,118 @@ Author: Peter Schrammel class ssa_inlinert:public messaget { -public: - explicit ssa_inlinert(summary_dbt &_summary_db): - counter(0), - summary_db(_summary_db) + public: + ssa_inlinert( + summary_dbt &_summary_db, + ssa_dbt &_ssa_db): + counter(-1), + summary_db(_summary_db), + ssa_db(_ssa_db) { } - void get_summary( + typedef std::map assertion_mapt; + + void get_guard_binding( + const local_SSAt &SSA, + const local_SSAt &fSSA, + local_SSAt::nodest::const_iterator n_it, + exprt &guard_binding, + int counter); + void get_bindings( + const local_SSAt &SSA, + const local_SSAt &fSSA, + local_SSAt::nodest::const_iterator n_it, + local_SSAt::nodet::function_callst::const_iterator f_it, + exprt::operandst &bindings_in, + exprt::operandst &bindings_out, + int counter); + bool get_summary( const local_SSAt &SSA, local_SSAt::nodest::const_iterator n_it, local_SSAt::nodet::function_callst::const_iterator f_it, - const summaryt &summary, + bool forward, + exprt::operandst &assert_summaries, + exprt::operandst &noassert_summaries, + exprt::operandst &bindings, + int counter, + bool error_summ=false); + bool get_inlined( + const local_SSAt &SSA, + local_SSAt::nodest::const_iterator n_it, + local_SSAt::nodet::function_callst::const_iterator f_it, + bool forward, + exprt::operandst &assert_summaries, + exprt::operandst &noassert_summaries, + exprt::operandst &bindings, + assertion_mapt &assertion_map, + int counter, + bool error_summ); + void get_summaries( + const local_SSAt &SSA, bool forward, exprt::operandst &summaries, - exprt::operandst &bindings); + exprt::operandst &bindings, + assertion_mapt &assertion_map); void get_summaries( const local_SSAt &SSA, bool forward, exprt::operandst &summaries, exprt::operandst &bindings); + bool get_summaries( + const local_SSAt &SSA, + const summaryt::call_sitet ¤t_call_site, + bool forward, + exprt::operandst &assert_summaries, + exprt::operandst &noassert_summaries, + exprt::operandst &bindings, + bool error_summ=false); + bool get_summaries( + const local_SSAt &SSA, + const summaryt::call_sitet ¤t_call_site, + bool forward, + exprt::operandst &assert_summaries, + exprt::operandst &noassert_summaries, + exprt::operandst &bindings, + assertion_mapt &assertion_map, + bool error_summ=false); + + // TODO: need to explicitly pass the correct counter exprt get_summaries(const local_SSAt &SSA); + exprt get_summaries( + const local_SSAt &SSA, + assertion_mapt &assertion_map); void replace( local_SSAt &SSA, local_SSAt::nodest::iterator node, local_SSAt::nodet::function_callst::iterator f_it, - const local_SSAt::var_sett &cs_globals_in, - // incoming globals at call site - const local_SSAt::var_sett &cs_globals_out, - // outgoing globals at call site + const local_SSAt::var_sett &cs_globals_in, // incoming globals at call site + const local_SSAt::var_sett &cs_globals_out, // outgoing globals at call site const summaryt &summary, bool forward, - bool preconditions_as_assertions); + bool preconditions_as_assertions, + int counter); void replace( local_SSAt &SSA, bool forward, - bool preconditions_as_assertions); + bool preconditions_as_assertions, + int counter); void replace( local_SSAt::nodest &nodes, local_SSAt::nodest::iterator node, local_SSAt::nodet::function_callst::iterator f_it, - const local_SSAt::var_sett &cs_globals_in, - // incoming globals at call site - const local_SSAt::var_sett &cs_globals_out, - // outgoing globals at call site - const local_SSAt &function); + const local_SSAt::var_sett &cs_globals_in, // incoming globals at call site + const local_SSAt::var_sett &cs_globals_out, // outgoing globals at call site + const local_SSAt &function, + int counter); void replace( local_SSAt &SSA, const ssa_dbt &ssa_db, + int counter, bool recursive=false, bool rename=true); @@ -105,9 +165,17 @@ class ssa_inlinert:public messaget static irep_idt get_original_identifier(const symbol_exprt &s); + void rename(irep_idt &id, int counter, bool attach=true); + + int get_rename_counter() { return ++counter; } + + // moved from protected to public, for use in summarizer_bw_cex_complete + void rename(exprt &expr, int counter, bool attach=true); + protected: - unsigned counter; + int counter; summary_dbt &summary_db; + ssa_dbt &ssa_db; local_SSAt::nodest new_nodes; local_SSAt::nodet::equalitiest new_equs; @@ -115,28 +183,40 @@ class ssa_inlinert:public messaget void replace_globals_in( const local_SSAt::var_sett &globals_in, - const local_SSAt::var_sett &globals); + const local_SSAt::var_sett &globals, + int counter); void replace_params( const local_SSAt::var_listt ¶ms, - const function_application_exprt &funapp_expr); + const function_application_exprt &funapp_expr, + int counter); void replace_globals_out( const local_SSAt::var_sett &globals_out, const local_SSAt::var_sett &cs_globals_in, - const local_SSAt::var_sett &cs_globals_out); + const local_SSAt::var_sett &cs_globals_out, + int counter); - exprt get_replace_globals_in( + void get_replace_globals_in( const local_SSAt::var_sett &globals_in, - const local_SSAt::var_sett &globals); - exprt get_replace_params( + const function_application_exprt &funapp_expr, + const local_SSAt::var_sett &globals, + exprt::operandst &c, + int counter); + void get_replace_params( + const local_SSAt &SSA, const local_SSAt::var_listt ¶ms, - const function_application_exprt &funapp_expr); - exprt get_replace_globals_out( + local_SSAt::nodest::const_iterator n_it, + const function_application_exprt &funapp_expr, + exprt::operandst &c, + int counter); + void get_replace_globals_out( const local_SSAt::var_sett &globals_out, + const function_application_exprt &funapp_expr, const local_SSAt::var_sett &cs_globals_in, - const local_SSAt::var_sett &cs_globals_out); + const local_SSAt::var_sett &cs_globals_out, + exprt::operandst &c, + int counter); - void rename(exprt &expr); - void rename(local_SSAt::nodet &node); + void rename(local_SSAt::nodet &node, int counter); }; #endif diff --git a/src/ssa/ssa_object.cpp b/src/ssa/ssa_object.cpp index d3aa56993..4f27c722c 100644 --- a/src/ssa/ssa_object.cpp +++ b/src/ssa/ssa_object.cpp @@ -37,6 +37,18 @@ bool is_ptr_object(const exprt &src) src.get(ID_ptr_object)!=irep_idt(); } +/*******************************************************************\ + +Function: collect_objects_rec + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + void collect_objects_rec( const exprt &src, const namespacet &ns, diff --git a/src/ssa/ssa_refiner.h b/src/ssa/ssa_refiner.h new file mode 100644 index 000000000..087dd2e91 --- /dev/null +++ b/src/ssa/ssa_refiner.h @@ -0,0 +1,21 @@ +/*******************************************************************\ + +Module: SSA Refiner Base Class + +Author: Peter Schrammel + +\*******************************************************************/ + +#ifndef CPROVER_SSA_SSA_REFINER_H +#define CPROVER_SSA_SSA_REFINER_H + +#include + +class ssa_refinert:public messaget +{ + public: + virtual bool operator()() { assert(false); } + virtual unsigned get_unwind() { assert(false); } +}; + +#endif // CPROVER_SSA_SSA_REFINER_H diff --git a/src/ssa/ssa_refiner_monolithic.cpp b/src/ssa/ssa_refiner_monolithic.cpp new file mode 100644 index 000000000..6d168fc23 --- /dev/null +++ b/src/ssa/ssa_refiner_monolithic.cpp @@ -0,0 +1,30 @@ +/*******************************************************************\ + +Module: SSA Refiner for Monolithic Analysis + +Author: Peter Schrammel + +\*******************************************************************/ + +#include "ssa_refiner_monolithic.h" + +/*******************************************************************\ + +Function: ssa_refiner_monolithict::operator() + + Inputs: + + Outputs: + + Purpose: refine all + +\*******************************************************************/ + +bool ssa_refiner_monolithict::operator()() +{ + status() << "Unwinding (k=" << unwind << ")" << eom; + summary_db.mark_recompute_all(); // TODO: recompute only functions with loops + ssa_unwinder.unwind_all(unwind); + + return unwind++<=max_unwind; +} diff --git a/src/ssa/ssa_refiner_monolithic.h b/src/ssa/ssa_refiner_monolithic.h new file mode 100644 index 000000000..e14e23b01 --- /dev/null +++ b/src/ssa/ssa_refiner_monolithic.h @@ -0,0 +1,44 @@ +/*******************************************************************\ + +Module: SSA Refiner for Monolithic Analysis + +Author: Peter Schrammel + +\*******************************************************************/ + +#ifndef CPROVER_2LS_SSA_SSA_REFINER_MONOLITHIC_H +#define CPROVER_2LS_SSA_SSA_REFINER_MONOLITHIC_H + +#include "ssa_refiner.h" + +#include +#include "ssa_unwinder.h" + +class summary_dbt; +class ssa_unwindert; + +class ssa_refiner_monolithict:public ssa_refinert +{ +public: + ssa_refiner_monolithict( + summary_dbt &_summary_db, + ssa_unwindert &_ssa_unwinder, + unsigned _max_unwind): + summary_db(_summary_db), + ssa_unwinder(_ssa_unwinder), + max_unwind(_max_unwind), + unwind(0) + { + } + + virtual bool operator()(); + virtual unsigned get_unwind() { return unwind>0 ? unwind-1 : 0; } + +protected: + summary_dbt &summary_db; + ssa_unwindert &ssa_unwinder; + const unsigned max_unwind; + unsigned unwind; +}; + +#endif // CPROVER_2LS_SSA_SSA_REFINER_MONOLITHIC_H diff --git a/src/ssa/ssa_refiner_selective.cpp b/src/ssa/ssa_refiner_selective.cpp new file mode 100644 index 000000000..ae16ad2bc --- /dev/null +++ b/src/ssa/ssa_refiner_selective.cpp @@ -0,0 +1,60 @@ +/*******************************************************************\ + +Module: SSA Refiner for selective unwinding and inlining + +Author: Peter Schrammel, Madhukar Kumar + +\*******************************************************************/ + +#include "ssa_refiner_selective.h" + +/*******************************************************************\ + +Function: ssa_refiner_selectivet::operator() + + Inputs: + + Outputs: + + Purpose: refine selectively according to the given reason + +\*******************************************************************/ + +bool ssa_refiner_selectivet::operator()() +{ + // unwind loops "selectively" (those that seem to be the "reason") + for(reasont::const_iterator it=reason.begin(); it!=reason.end(); ++it) + { + for(std::set::const_iterator l_it= + it->second.loops.begin(); + l_it!=it->second.loops.end(); l_it++) + { + unsigned new_unwind= + ssa_unwinder.unwind_loop_once_more(it->first, (*l_it)->location_number); + debug() << "Refining function " << it->first << ": unwinding loop at " + << (*l_it)->location_number << " (k=" << new_unwind << ")" << eom; + unwind=std::max(unwind, new_unwind); + } + } + + // inline functions "selectively" (those that seem to be the "reason") + for(reasont::const_iterator it=reason.begin(); it!=reason.end(); ++it) + { + for(std::set::const_iterator f_it= + it->second.functions.begin(); + f_it!=it->second.functions.end(); f_it++) + { + local_SSAt &SSA=ssa_db.get(it->first); + local_SSAt::nodest::iterator n_it=SSA.find_node(*f_it); + assert(n_it->function_calls.size()==1); + n_it->function_calls_inlined=true; + + irep_idt fname=to_symbol_expr(n_it->function_calls.begin() + ->function()).get_identifier(); + debug() << "Refining function " << it->first << ": inlining call to " + << fname << " at " << (*f_it)->location_number<< eom; + } + } + + return unwind<=max_unwind; +} diff --git a/src/ssa/ssa_refiner_selective.h b/src/ssa/ssa_refiner_selective.h new file mode 100644 index 000000000..2ffcd166c --- /dev/null +++ b/src/ssa/ssa_refiner_selective.h @@ -0,0 +1,76 @@ +/*******************************************************************\ + +Module: SSA Refiner for selective unwinding and inlining + +Author: Peter Schrammel, Madhukar Kumar + +\*******************************************************************/ + +#ifndef CPROVER_2LS_SSA_SSA_REFINER_SELECTIVE_H +#define CPROVER_2LS_SSA_SSA_REFINER_SELECTIVE_H + +#include "ssa_refiner.h" + +#include +#include "ssa_inliner.h" +#include "ssa_unwinder.h" + +class ssa_dbt; + +class ssa_refiner_selectivet:public ssa_refinert +{ +public: + struct reason_infot + { + // call_site; restriction: + // we assume that there is a single function call in an SSA node + typedef local_SSAt::locationt function_infot; + typedef local_SSAt::locationt loop_infot; + std::set functions; + std::set loops; + }; + + class reasont:public std::map + { + public: + void merge(const reasont &other) + { + for(const auto &reason : other) + { + reason_infot &r=(*this)[reason.first]; + r.functions.insert( + reason.second.functions.begin(), + reason.second.functions.end()); + r.loops.insert(reason.second.loops.begin(), reason.second.loops.end()); + } + } + }; + + ssa_refiner_selectivet( + ssa_dbt &_ssa_db, + ssa_unwindert &_ssa_unwinder, + unsigned _max_unwind, + ssa_inlinert &_ssa_inliner, + reasont &_reason): + ssa_db(_ssa_db), + ssa_unwinder(_ssa_unwinder), + max_unwind(_max_unwind), + ssa_inliner(_ssa_inliner), + unwind(0), + reason(_reason) + { + } + + virtual bool operator()(); + virtual unsigned get_unwind() { return unwind; } + + protected: + ssa_dbt &ssa_db; + ssa_unwindert &ssa_unwinder; + const unsigned max_unwind; + ssa_inlinert &ssa_inliner; + unsigned unwind; + reasont &reason; +}; + +#endif // CPROVER_2LS_SSA_SSA_REFINER_SELECTIVE_H diff --git a/src/ssa/ssa_unwinder.cpp b/src/ssa/ssa_unwinder.cpp index aecf2166c..1c8dead21 100644 --- a/src/ssa/ssa_unwinder.cpp +++ b/src/ssa/ssa_unwinder.cpp @@ -30,6 +30,7 @@ void ssa_local_unwindert::init() build_pre_post_map(); build_exit_conditions(); unwind(0); + compute_enable_expr(); #ifdef DEBUG SSA.output_verbose(std::cout); #endif @@ -137,8 +138,8 @@ void ssa_local_unwindert::build_pre_post_map() const ssa_domaint::phi_nodest &phi_nodes= SSA.ssa_analysis[pre_loc].phi_nodes; for(local_SSAt::objectst::const_iterator o_it= - SSA.ssa_objects.objects.begin(); - o_it!=SSA.ssa_objects.objects.end(); o_it++) + SSA.ssa_objects.objects.begin(); + o_it!=SSA.ssa_objects.objects.end(); o_it++) { ssa_domaint::phi_nodest::const_iterator p_it=phi_nodes.find( o_it->get_identifier()); @@ -188,8 +189,8 @@ void ssa_local_unwindert::build_exit_conditions() // need disjunction of all exit conditions // for each symbol name at exit location for(exprt::operandst::const_iterator - s_it=it->second.modified_vars.begin(); - s_it!=it->second.modified_vars.end(); s_it++) + s_it=it->second.modified_vars.begin(); + s_it!=it->second.modified_vars.end(); s_it++) { exprt e=SSA.read_rhs(*s_it, n_it->location); it->second.exit_map[e].push_back(and_exprt(g, c)); @@ -210,8 +211,8 @@ void ssa_local_unwindert::build_exit_conditions() exprt g=SSA.guard_symbol(n_it->location); exprt c=SSA.cond_symbol(n_it->location); for(exprt::operandst::const_iterator - s_it=it->second.modified_vars.begin(); - s_it!=it->second.modified_vars.end(); s_it++) + s_it=it->second.modified_vars.begin(); + s_it!=it->second.modified_vars.end(); s_it++) { exprt e=SSA.read_rhs(*s_it, n_it->location); it->second.exit_map[e].push_back( @@ -253,7 +254,7 @@ void ssa_local_unwindert::build_exit_conditions() if(n_it==prev) --prev; for(local_SSAt::nodet::assertionst::const_iterator a_it= - n_it->assertions.begin(); a_it!=n_it->assertions.end(); a_it++) + n_it->assertions.begin(); a_it!=n_it->assertions.end(); a_it++) { h_it->second.assertions.push_back(*a_it); } @@ -262,6 +263,69 @@ void ssa_local_unwindert::build_exit_conditions() } } +/***************************************************************************** + * + * Function : ssa_local_unwindert::unwind_loop_at_location() + * + * Input : + * + * Output : + * + * Purpose : unwind the loop at the given location, up to k starting from + * previous unwindings + * + * + *****************************************************************************/ + +unsigned ssa_local_unwindert::unwind_loop_at_location(unsigned loc) +{ + unsigned k=loops.at(loc).current_unwinding+1; + unwind_loop_at_location(loc, k); + return k; +} + +void ssa_local_unwindert::unwind_loop_at_location(unsigned loc, unsigned k) +{ + if(SSA.current_unwinding>=(long)k) + return; + + loopt &loop=loops[loc]; + loop.loop_enabling_exprs.push_back( + symbol_exprt( + "unwind$"+id2string(fname)+"$loc"+i2string(loc)+"$enable"+i2string(k), + bool_typet())); + + // TODO: just for exploratory integration, must go away + SSA.current_unwinding=k; + + // recursively unwind everything + SSA.current_unwindings.clear(); + + for(loop_mapt::iterator it=loops.begin(); it!=loops.end(); ++it) + { + if(!it->second.is_root) + continue; + + if(it->first==loc) + unwind(it->second, k, false, false); // recursive + else + unwind(it->second, it->second.current_unwinding, false, true, k, loc); + // recursive + + assert(SSA.current_unwindings.empty()); + } + + // update current unwinding + for(loop_mapt::iterator it=loops.begin(); it!=loops.end(); ++it) + { + if(it->first==loc) + it->second.current_unwinding=k; + } + + compute_enable_expr(); + return; +} + /*******************************************************************\ Function: ssa_local_unwindert::unwind @@ -280,9 +344,16 @@ void ssa_local_unwindert::unwind(unsigned k) return; current_enabling_expr= - symbol_exprt("unwind::"+id2string(fname)+"::enable"+i2string(k), + symbol_exprt("unwind$"+id2string(fname)+"$enable"+i2string(k), bool_typet()); - SSA.enabling_exprs.push_back(current_enabling_expr); + for(loop_mapt::iterator it=loops.begin(); it!=loops.end(); ++it) + { + it->second.loop_enabling_exprs.push_back( + symbol_exprt( + "unwind$"+id2string(fname)+"$loc"+i2string(it->first)+ + "$enable"+i2string(k), + bool_typet())); + } // TODO: just for exploratory integration, must go away SSA.current_unwinding=k; @@ -293,7 +364,8 @@ void ssa_local_unwindert::unwind(unsigned k) { if(!it->second.is_root) continue; - unwind(it->second, k, false); // recursive + // unwind(it->second, k, false, false); // recursive + unwind(it->second, k, false, true, k, 0, true); // recursive assert(SSA.current_unwindings.empty()); } // update current unwinding @@ -301,6 +373,8 @@ void ssa_local_unwindert::unwind(unsigned k) { it->second.current_unwinding=k; } + + compute_enable_expr(); } /*******************************************************************\ @@ -316,7 +390,14 @@ Function: ssa_local_unwindert::unwind \*******************************************************************/ -void ssa_local_unwindert::unwind(loopt &loop, unsigned k, bool is_new_parent) +void ssa_local_unwindert::unwind( + loopt &loop, + unsigned k, + bool is_new_parent, + bool propagate, + unsigned prop_unwind, + unsigned prop_loc, + bool propagate_all) { odometert context=SSA.current_unwindings; #ifdef DEBUG @@ -379,11 +460,50 @@ void ssa_local_unwindert::unwind(loopt &loop, unsigned k, bool is_new_parent) #ifdef DEBUG std::cout << i << ">" << loop.current_unwinding << std::endl; #endif - unwind(loops[l], k, i>loop.current_unwinding || is_new_parent); + if(propagate_all==true) + { + unwind( + loops[l], k, i>loop.current_unwinding || is_new_parent, false); + } + else + { + if(propagate==true) + { + // if this child loop is the desired loop then unwind k + // and do not propagate + // else unwind loop.current_unwinding and propagate + if(l==prop_loc) + { + unwind( + loops[l], k, i>loop.current_unwinding || is_new_parent, false); + } + else + { + unwind( + loops[l], + loops[l].current_unwinding, + i>loop.current_unwinding || is_new_parent, + true, + prop_unwind, + prop_loc); + } + } + else + { + unwind( + loops[l], + loops[l].current_unwinding, + i>loop.current_unwinding || is_new_parent, + false); + } + } } SSA.increment_unwindings(0); } SSA.increment_unwindings(-1); +#if 0 + std::cout << "calling add_exit_merge with k=" << k << "\n"; +#endif add_exit_merges(loop, k); } @@ -419,18 +539,18 @@ void ssa_local_unwindert::add_loop_body(loopt &loop) node.loophead=SSA.nodes.end(); node.marked=false; for(local_SSAt::nodet::equalitiest::iterator e_it= - node.equalities.begin(); e_it!=node.equalities.end(); e_it++) + node.equalities.begin(); e_it!=node.equalities.end(); e_it++) { SSA.rename(*e_it, node.location); } for(local_SSAt::nodet::constraintst::iterator c_it= - node.constraints.begin(); c_it!=node.constraints.end(); c_it++) + node.constraints.begin(); c_it!=node.constraints.end(); c_it++) { SSA.rename(*c_it, node.location); } for(local_SSAt::nodet::function_callst::iterator f_it= - node.function_calls.begin(); - f_it!=node.function_calls.end(); f_it++) + node.function_calls.begin(); + f_it!=node.function_calls.end(); f_it++) { SSA.rename(*f_it, node.location); } @@ -465,7 +585,7 @@ void ssa_local_unwindert::add_assertions(loopt &loop, bool is_last) node.assertions=it->assertions; SSA.current_location=node.location; // TODO: must go away for(local_SSAt::nodet::assertionst::iterator a_it= - node.assertions.begin(); a_it!=node.assertions.end(); a_it++) + node.assertions.begin(); a_it!=node.assertions.end(); a_it++) { SSA.rename(*a_it, node.location); if(!is_last) // only add assumptions if we are not in %0 iteration @@ -512,7 +632,7 @@ void ssa_local_unwindert::add_loop_head(loopt &loop) node.marked=false; node.enabling_expr=current_enabling_expr; for(local_SSAt::nodet::equalitiest::iterator e_it= - node.equalities.begin(); e_it!=node.equalities.end(); e_it++) + node.equalities.begin(); e_it!=node.equalities.end(); e_it++) { SSA.rename(*e_it, node.location); } @@ -545,8 +665,8 @@ void ssa_local_unwindert::add_loop_connector(loopt &loop) local_SSAt::nodet &node=SSA.nodes.back(); SSA.current_location=node.location; // TODO: must go away for(local_SSAt::nodet::equalitiest::const_iterator e_it= - orig_node.equalities.begin(); - e_it!=orig_node.equalities.end(); e_it++) + orig_node.equalities.begin(); + e_it!=orig_node.equalities.end(); e_it++) { if(e_it->rhs().id()==ID_if) { @@ -597,7 +717,7 @@ void ssa_local_unwindert::add_exit_merges(loopt &loop, unsigned k) node.enabling_expr=current_enabling_expr; for(loopt::exit_mapt::const_iterator x_it=loop.exit_map.begin(); - x_it!=loop.exit_map.end(); x_it++) + x_it!=loop.exit_map.end(); x_it++) { node.equalities.push_back( build_exit_merge( @@ -676,6 +796,37 @@ void ssa_local_unwindert::add_hoisted_assertions(loopt &loop, bool is_last) } } +/*****************************************************************************\ + * + * Function : ssa_local_unwindert::compute_enable_expr + * + * Input : + * + * Output : + * + * Purpose : updates the enable_expr + * + *****************************************************************************/ + +void ssa_local_unwindert::compute_enable_expr() +{ + SSA.enabling_exprs.clear(); + for(loop_mapt::const_iterator it=loops.begin(); it!=loops.end(); ++it) + { + for(exprt::operandst::const_iterator + e_it=((it->second).loop_enabling_exprs).begin(); + e_it!=((it->second).loop_enabling_exprs).end(); e_it++) + { + exprt::operandst::const_iterator lh=e_it; lh++; + if(lh!=((it->second).loop_enabling_exprs).end()) + SSA.enabling_exprs.push_back(not_exprt(*e_it)); + else + SSA.enabling_exprs.push_back(*e_it); + } + } +} + + /*******************************************************************\ Function: ssa_local_unwindert::loop_continuation_conditions @@ -692,17 +843,42 @@ void ssa_local_unwindert::loop_continuation_conditions( exprt::operandst& loop_cont) const { SSA.current_unwindings.clear(); - for(loop_mapt::const_iterator it=loops.begin(); it!=loops.end(); ++it) + for(const auto &l : loops) { - if(!it->second.is_root) + if(l.second.is_root) continue; - loop_continuation_conditions(it->second, loop_cont); // recursive + loop_continuation_conditions(l.second, loop_cont); // recursive assert(SSA.current_unwindings.empty()); } } /*******************************************************************\ +Function: ssa_local_unwindert::loop_continuation_conditions + + Inputs: + + Outputs: + + Purpose: return loop continuation conditions for all instances + of the given loop in this function + +\*******************************************************************/ + +void ssa_local_unwindert::loop_continuation_conditions( + const locationt& loop_id, + exprt::operandst &loop_cont) const +{ + if(loops.empty()) // ignore silently, TBD + return; + + const loopt &loop=loops.at(loop_id->location_number); + loop_cont.insert(loop_cont.end(), + loop.current_continuation_conditions.begin(), + loop.current_continuation_conditions.end()); +} +/*******************************************************************\ + Function: ssa_local_unwindert::get_continuation_condition Inputs: @@ -739,7 +915,7 @@ void ssa_local_unwindert::loop_continuation_conditions( loop_cont.push_back(get_continuation_condition(loop)); // %0 for(long i=0; i<=loop.current_unwinding; ++i) { - // recurse into child loops + // recur into child loops for(const auto &l : loop.loop_nodes) { loop_continuation_conditions(loops.at(l), loop_cont); @@ -808,6 +984,51 @@ void ssa_local_unwindert::unwinder_rename( #endif } +/*******************************************************************\ + +Function: ssa_local_unwindert::unwind_loop_alone + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void ssa_unwindert::unwind_loop_alone( + const irep_idt fname, + unsigned loc, + unsigned int k) +{ + assert(is_initialized); + unwinder_mapt::iterator it=unwinder_map.find(fname); + assert(it!=unwinder_map.end()); + it->second.unwind_loop_at_location(loc, k); +} + +/*******************************************************************\ + +Function: ssa_local_unwindert::unwind_loop_once_more + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +unsigned ssa_unwindert::unwind_loop_once_more( + const irep_idt fname, + unsigned loc) +{ + assert(is_initialized); + unwinder_mapt::iterator it=unwinder_map.find(fname); + assert(it!=unwinder_map.end()); + return it->second.unwind_loop_at_location(loc); +} + /*******************************************************************\ @@ -895,9 +1116,10 @@ void ssa_unwindert::init(bool is_kinduction, bool is_bmc) ssa_dbt::functionst& funcs=ssa_db.functions(); for(auto &f : funcs) { - unwinder_map.insert(unwinder_pairt( - f.first, - ssa_local_unwindert(f.first, (*(f.second)), is_kinduction, is_bmc))); + unwinder_map.insert( + unwinder_pairt( + f.first, + ssa_local_unwindert(f.first, (*(f.second)), is_kinduction, is_bmc))); } } diff --git a/src/ssa/ssa_unwinder.h b/src/ssa/ssa_unwinder.h index 62b7a20d7..57a02c007 100644 --- a/src/ssa/ssa_unwinder.h +++ b/src/ssa/ssa_unwinder.h @@ -32,6 +32,8 @@ class ssa_local_unwindert void init(); + void unwind_loop_at_location(unsigned loc, unsigned k); + unsigned unwind_loop_at_location(unsigned loc); void unwind(unsigned k); #if 0 @@ -44,7 +46,11 @@ class ssa_local_unwindert // TODO: this should be loop specific in future, // maybe move to unwindable_local_ssa as it is not really unwinder related - void loop_continuation_conditions(exprt::operandst& loop_cont) const; + void compute_enable_expr(); + void loop_continuation_conditions(exprt::operandst &loop_cont) const; + void loop_continuation_conditions( + const locationt& loop_id, + exprt::operandst &loop_cont) const; #if 0 // TODO: these two should be possible with unwindable_local_ssa facilities @@ -55,7 +61,9 @@ class ssa_local_unwindert // TODO: this must go away, should use SSA.rename instead void unwinder_rename( - symbol_exprt &var, const local_SSAt::nodet &node, bool pre) const; + symbol_exprt &var, + const local_SSAt::nodet &node, + bool pre) const; class loopt // loop tree { @@ -74,6 +82,12 @@ class ssa_local_unwindert bool is_dowhile; bool is_root; long current_unwinding; + + // to have an enabling_expr and current_unwindings (odometert) + exprt::operandst loop_enabling_exprs; + + exprt::operandst current_continuation_conditions; + typedef std::map exit_mapt; exit_mapt exit_map; std::map pre_post_map; @@ -106,7 +120,14 @@ class ssa_local_unwindert void build_pre_post_map(); void build_exit_conditions(); - void unwind(loopt &loop, unsigned k, bool is_new_parent); + void unwind( + loopt &loop, + unsigned k, + bool is_new_parent, + bool propagate=false, + unsigned prop_unwind=0, + unsigned prop_loc=0, + bool propagate_all=false); exprt get_continuation_condition(const loopt& loop) const; void loop_continuation_conditions( @@ -137,15 +158,17 @@ class ssa_unwindert:public messaget void init(bool is_kinduction, bool is_bmc); void init_localunwinders(); + void unwind_loop_alone(const irep_idt fname, unsigned loc, unsigned k); + unsigned unwind_loop_once_more(const irep_idt fname, unsigned loc); void unwind(const irep_idt fname, unsigned k); void unwind_all(unsigned k); - inline ssa_local_unwindert &get(const irep_idt& fname) + ssa_local_unwindert &get(const irep_idt& fname) { return unwinder_map.at(fname); } - inline const ssa_local_unwindert &get(const irep_idt& fname) const + const ssa_local_unwindert &get(const irep_idt& fname) const { return unwinder_map.at(fname); } @@ -156,4 +179,4 @@ class ssa_unwindert:public messaget unwinder_mapt unwinder_map; }; -#endif +#endif // CPROVER_2LS_SSA_SSA_UNWINDER_H diff --git a/src/ssa/unwindable_local_ssa.cpp b/src/ssa/unwindable_local_ssa.cpp index 8b49f8e76..4dc6d1c99 100644 --- a/src/ssa/unwindable_local_ssa.cpp +++ b/src/ssa/unwindable_local_ssa.cpp @@ -279,6 +279,12 @@ Function: unwindable_local_SSAt::rename void unwindable_local_SSAt::rename(exprt &expr, locationt current_loc) { + if(expr.id()==ID_function_application) + { + std::string unwind_suffix= + odometer_to_string(current_unwindings, current_unwindings.size()); + expr.set(ID_suffix, unwind_suffix); + } if(expr.id()==ID_symbol) { symbol_exprt &s=to_symbol_expr(expr); @@ -292,7 +298,7 @@ void unwindable_local_SSAt::rename(exprt &expr, locationt current_loc) std::string unwind_suffix= odometer_to_string(current_unwindings, def_level); s.set_identifier(id2string(id)+unwind_suffix); - + s.set(ID_suffix, unwind_suffix); #if 0 std::cout << "DEF_LOC: " << def_loc->location_number << std::endl; std::cout << "DEF_LEVEL: " << def_level << std::endl; @@ -307,13 +313,9 @@ void unwindable_local_SSAt::rename(exprt &expr, locationt current_loc) { std::string unwind_suffix= odometer_to_string(current_unwindings, current_unwindings.size()); - std::string identifier=id2string(expr.get(ID_identifier)); - std::size_t pos=identifier.find("%"); - if(pos!=std::string::npos) - identifier=identifier.substr(0, pos); - expr.set( - ID_identifier, - identifier+unwind_suffix+suffix); + expr.set(ID_suffix, unwind_suffix); + expr.set(ID_identifier, + id2string(expr.get(ID_identifier))+unwind_suffix+suffix); } Forall_operands(it, expr) rename(*it, current_loc);