From 87b142883b344eaa2c48607e569137d599b0ed24 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Fri, 9 Jun 2017 18:07:45 +0100 Subject: [PATCH 001/322] Name CBMC support branch for 2LS 0.5 --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index c72d8988e..596b2c259 100755 --- a/install.sh +++ b/install.sh @@ -1,7 +1,7 @@ #!/bin/bash CBMC_REPO=https://github.com/peterschrammel/cbmc -CBMC_VERSION=d95e7da28018fd315b04a1201d5b7cfe8195cbc6 +CBMC_VERSION=2ls-prerequisites-0.5 if [ "$1" != "" ] then From 7c979dfdba2f15e2d4ce59359240d3edb186621e Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Thu, 20 Jul 2017 18:17:12 +0100 Subject: [PATCH 002/322] Whitespace clean-up --- regression/graphml/Makefile | 2 +- regression/graphml/loop23/main.c | 4 +- regression/graphml/loop29/main.c | 6 +- regression/graphml/malloc1/main.c | 8 +- regression/interprocedural/abort1/main.c | 2 +- .../interprocedural/contextsensitive1/main.c | 32 +++-- .../interprocedural/contextsensitive2/main.c | 54 ++++----- .../interprocedural/contextsensitive3/main.c | 54 ++++----- .../interprocedural/contextsensitive4/main.c | 56 +++++---- .../interprocedural/contextsensitive5/main.c | 29 +++-- .../interprocedural/contextsensitive6/main.c | 22 ++-- regression/interprocedural/equal1/main.c | 4 +- regression/interprocedural/equal2/main.c | 4 +- regression/interprocedural/equal3/main.c | 4 +- regression/interprocedural/equal4/main.c | 4 +- regression/interprocedural/equal7/main.c | 4 +- .../equality_through_array7/main.c | 2 +- regression/interprocedural/global1/main.c | 41 +++---- regression/interprocedural/global2/main.c | 43 ++++--- regression/interprocedural/global3/main.c | 4 +- regression/interprocedural/global4/main.c | 8 +- regression/interprocedural/ite2/main.c | 10 +- regression/interprocedural/ite3/main.c | 10 +- regression/interprocedural/ite4/main.c | 8 +- regression/interprocedural/pointer1/main.c | 4 +- regression/interprocedural/pointer2/main.c | 4 +- regression/interprocedural/simple1/main.c | 10 +- regression/interprocedural/simple2/main.c | 4 +- regression/interprocedural/sum1/main.c | 54 ++++----- regression/invariants/array_safe5/main.c | 4 +- regression/invariants/complexity1/main.c | 2 +- regression/invariants/complexity2/main.c | 2 +- regression/invariants/custom1/main.c | 2 +- regression/invariants/custom2/main.c | 2 +- regression/invariants/equal6/main.c | 2 +- .../invariants/equality_through_array8/main.c | 2 +- regression/invariants/float1/main.c | 2 +- regression/invariants/float2/main.c | 2 +- regression/invariants/float3/main.c | 2 +- regression/invariants/float4/main.c | 2 +- regression/invariants/gotoloop1/main.c | 2 +- regression/invariants/gotoloop2/main.c | 2 +- regression/invariants/ite1/main.c | 26 ++-- regression/invariants/loop1/main.c | 2 +- regression/invariants/loop10/main.c | 2 +- regression/invariants/loop11/main.c | 2 +- regression/invariants/loop13/main.c | 2 +- regression/invariants/loop14/main.c | 2 +- regression/invariants/loop15/main.c | 2 +- regression/invariants/loop16/main.c | 4 +- regression/invariants/loop17/main.c | 2 +- regression/invariants/loop18/main.c | 2 +- regression/invariants/loop2/main.c | 2 +- regression/invariants/loop21/main.c | 2 +- regression/invariants/loop22/main.c | 2 +- regression/invariants/loop3/main.c | 4 +- regression/invariants/loop5/main.c | 2 +- regression/invariants/loop6/main.c | 4 +- regression/invariants/loop7/main.c | 2 +- regression/invariants/nested4/main.c | 6 +- regression/invariants/nested5/main.c | 8 +- regression/invariants/nonmonotone1/main.c | 2 +- regression/invariants/nonmonotone2/main.c | 2 +- regression/invariants/predabs1/main.c | 2 +- regression/invariants/predabs4/main.c | 2 +- regression/invariants/unwind1/main.c | 2 +- regression/invariants/unwind12/main.c | 2 +- regression/invariants/unwind14/main.c | 4 +- regression/invariants/unwind15/main.c | 2 +- regression/invariants/unwind16/main.c | 4 +- regression/invariants/unwind17/main.c | 6 +- regression/invariants/unwind18/main.c | 2 +- regression/invariants/unwind19/main.c | 2 +- regression/invariants/unwind2/main.c | 2 +- regression/invariants/unwind3/main.c | 2 +- regression/invariants/unwind4/main.c | 2 +- regression/invariants/unwind5/main.c | 4 +- regression/invariants/unwind6/main.c | 2 +- regression/invariants/unwind9/main.c | 2 +- regression/kiki/array1/main.c | 2 +- regression/kiki/byte_add/main.c | 2 +- regression/kiki/elevator_13_21/main.c | 8 +- regression/kiki/encoder1/main.c | 20 +-- regression/kiki/induction1/main.c | 2 +- regression/kiki/induction2/main.c | 2 +- regression/kiki/induction3/main.c | 2 +- regression/kiki/induction4/main.c | 32 ++--- regression/kiki/induction5/main.c | 32 ++--- regression/kiki/induction6/main.c | 114 +++++++++--------- regression/kiki/induction7/main.c | 46 +++---- regression/kiki/induction8/main.c | 38 +++--- regression/kiki/loop12/main.c | 2 +- regression/kiki/loop23/main.c | 4 +- regression/kiki/loop24/main.c | 26 ++-- regression/kiki/loop25/main.c | 24 ++-- regression/kiki/loop25/test.desc | 2 +- regression/kiki/loop26/main.c | 26 ++-- regression/kiki/loop27/main.c | 26 ++-- regression/kiki/loop28/main.c | 16 +-- regression/kiki/loop29/main.c | 6 +- regression/kiki/loop30/main.c | 6 +- regression/kiki/loop9/main.c | 2 +- regression/kiki/malloc1/main.c | 8 +- regression/kiki/malloc3/main.c | 2 +- regression/kiki/nested11/main.c | 2 +- regression/kiki/nested12/main.c | 36 +++--- regression/kiki/s3_clnt_1/main.c | 8 +- regression/kiki/trafficlight1/main.c | 4 +- regression/preconditions/precond1/main.c | 4 +- regression/preconditions/precond2/main.c | 4 +- regression/preconditions/precond3/main.c | 4 +- regression/preconditions/precond4/main.c | 6 +- regression/preconditions/precond5/main.c | 4 +- regression/preconditions/precond6/main.c | 4 +- .../precond_contextsensitive1/main.c | 30 ++--- .../precond_contextsensitive2/main.c | 22 ++-- regression/termination/abe_createBack1/main.c | 2 +- regression/termination/abort1/main.c | 2 +- regression/termination/abort3/main.c | 2 +- regression/termination/array_safe5/main.c | 4 +- regression/termination/array_safe5/test.desc | 2 +- regression/termination/bubble_sort2/main.c | 2 +- regression/termination/cav08_1/main.c | 8 +- regression/termination/cav08_1p/main.c | 8 +- regression/termination/cav08_2/main.c | 8 +- regression/termination/cav08_2p/main.c | 8 +- regression/termination/cav08_3/main.c | 6 +- regression/termination/cav08_3p/main.c | 6 +- regression/termination/cav08_4/main.c | 10 +- regression/termination/cav08_4p/main.c | 10 +- regression/termination/cav08_5/main.c | 8 +- regression/termination/cav08_5p/main.c | 8 +- regression/termination/cav08_6/main.c | 10 +- regression/termination/cav08_6p/main.c | 10 +- regression/termination/cav08_7/main.c | 12 +- regression/termination/cav08_7p/main.c | 12 +- .../termination/contextsensitive1/main.c | 34 +++--- .../termination/contextsensitive2/main.c | 56 ++++----- .../termination/contextsensitive3/main.c | 56 ++++----- .../termination/contextsensitive4/main.c | 58 ++++----- .../termination/contextsensitive5/main.c | 30 ++--- .../termination/contextsensitive6/main.c | 24 ++-- regression/termination/equal1/main.c | 4 +- regression/termination/equal2/main.c | 4 +- regression/termination/equal3/main.c | 4 +- regression/termination/equal4/main.c | 4 +- regression/termination/equal6/main.c | 2 +- regression/termination/equal7/main.c | 4 +- .../equality_through_array7/main.c | 2 +- .../equality_through_array7/main.c | 2 +- .../equality_through_array8/main.c | 2 +- regression/termination/float1/main.c | 2 +- regression/termination/float2/main.c | 2 +- regression/termination/float3/main.c | 2 +- regression/termination/float4/main.c | 2 +- regression/termination/float5/main.c | 2 +- regression/termination/float6/main.c | 2 +- regression/termination/global1/main.c | 42 +++---- regression/termination/global2/main.c | 44 +++---- regression/termination/global3/main.c | 4 +- regression/termination/global4/main.c | 8 +- regression/termination/ite1/main.c | 26 ++-- regression/termination/ite2/main.c | 10 +- regression/termination/ite3/main.c | 10 +- regression/termination/ite4/main.c | 8 +- regression/termination/locks1/main.c | 4 +- regression/termination/locks2/main.c | 4 +- regression/termination/loop1/main.c | 2 +- regression/termination/loop2/main.c | 2 +- regression/termination/loop3/main.c | 4 +- regression/termination/loop5/main.c | 2 +- regression/termination/loop6/main.c | 4 +- regression/termination/loop7/main.c | 2 +- regression/termination/loop9/main.c | 2 +- regression/termination/loops/array_false.c | 12 +- regression/termination/loops/array_true.c | 12 +- .../termination/loops/bubble_sort_false.c | 28 ++--- .../termination/loops/eureka_01_false.c | 2 +- regression/termination/loops/eureka_01_true.c | 2 +- regression/termination/loops/eureka_05_true.c | 2 +- .../termination/loops/insertion_sort_false.c | 10 +- .../termination/loops/insertion_sort_true.c | 10 +- .../termination/loops/invert_string_false.c | 4 +- .../termination/loops/invert_string_true.c | 4 +- .../termination/loops/linear_sea.ch_true.c | 2 +- .../termination/loops/linear_search_false.c | 2 +- regression/termination/loops/lu.cmp_true.c | 6 +- regression/termination/loops/ludcmp_false.c | 6 +- regression/termination/loops/matrix_false.c | 14 +-- regression/termination/loops/matrix_true.c | 16 +-- regression/termination/loops/n.c11_true.c | 6 +- regression/termination/loops/n.c24_true.c | 30 ++--- regression/termination/loops/n.c40_true.c | 6 +- regression/termination/loops/nec11_false.c | 6 +- regression/termination/loops/nec20_false.c | 6 +- regression/termination/loops/nec40_true.c | 6 +- regression/termination/loops/string_false.c | 22 ++-- regression/termination/loops/string_true.c | 22 ++-- .../termination/loops/sum01_bug02_false.c | 4 +- .../sum01_bug02_sum01_bug02_base.case_false.c | 2 +- regression/termination/loops/sum01_false.c | 2 +- regression/termination/loops/sum01_true.c | 2 +- regression/termination/loops/sum03_false.c | 2 +- regression/termination/loops/sum03_true.c | 2 +- regression/termination/loops/sum04_false.c | 2 +- regression/termination/loops/sum04_true.c | 2 +- .../termination/loops/sum_array_false.c | 6 +- regression/termination/loops/sum_array_true.c | 6 +- .../termination/loops/terminator_01_false.c | 6 +- .../termination/loops/terminator_02_false.c | 8 +- .../termination/loops/terminator_02_true.c | 6 +- .../termination/loops/terminator_03_false.c | 6 +- .../termination/loops/terminator_03_true.c | 8 +- regression/termination/loops/trex03_false.c | 2 +- regression/termination/loops/trex03_true.c | 2 +- regression/termination/loops/trex04_true.c | 2 +- ...c_OpenSER__cases1_stripFullBoth_arr_true.c | 6 +- ..._OpenSER__cases1_stripFullBoth_arr_false.c | 6 +- regression/termination/loops/vogal_false.c | 14 +-- regression/termination/loops/vogal_true.c | 14 +-- .../loops/while_infinite_loop_1_true.c | 2 +- .../loops/while_infinite_loop_2_true.c | 2 +- .../loops/while_infinite_loop_3_true.c | 4 +- .../loops/while_infinite_loop_4_false.c | 4 +- regression/termination/phase1/main.c | 4 +- regression/termination/phase2/main.c | 6 +- regression/termination/phase3/main.c | 4 +- regression/termination/phase4/main.c | 4 +- regression/termination/phase5/main.c | 4 +- regression/termination/phase6/main.c | 4 +- regression/termination/phase7/debug.c | 4 +- regression/termination/phase7/main.c | 4 +- regression/termination/phase7/main_verify.c | 8 +- regression/termination/phase8/debug.c | 4 +- regression/termination/phase8/main.c | 6 +- regression/termination/phase8/main_verify.c | 8 +- regression/termination/phase9/main.c | 4 +- regression/termination/pointer1/main.c | 4 +- regression/termination/pointer2/main.c | 4 +- regression/termination/precond_term4/main.c | 4 +- regression/termination/refinement1/main.c | 4 +- regression/termination/refinement2/main.c | 4 +- regression/termination/refinement3/main.c | 4 +- regression/termination/runall.sh | 4 +- regression/termination/running1/main.c | 10 +- regression/termination/running2/main.c | 12 +- regression/termination/running3/main.c | 22 ++-- regression/termination/running4/main.c | 22 ++-- regression/termination/simple1/main.c | 10 +- regression/termination/simple2/main.c | 4 +- regression/termination/sum1/main.c | 54 ++++----- 251 files changed, 1203 insertions(+), 1216 deletions(-) diff --git a/regression/graphml/Makefile b/regression/graphml/Makefile index bfa217de8..7a53bfe32 100644 --- a/regression/graphml/Makefile +++ b/regression/graphml/Makefile @@ -1,6 +1,6 @@ #FLAGS = --k-induction --competition-mode --32 FLAGS = --unwind 11 --no-unwinding-assertions -#2LS = ../../../src/summarizer/2ls +#2LS = ../../../src/summarizer/2ls 2LS = $W/svncprover/branches/peter-incremental-unwinding/src/cbmc/cbmc CPACHECKER = $W/svncpachecker ULTIMATE = $W/UltimateAutomizer diff --git a/regression/graphml/loop23/main.c b/regression/graphml/loop23/main.c index ac7fc9378..5b2e53f86 100644 --- a/regression/graphml/loop23/main.c +++ b/regression/graphml/loop23/main.c @@ -6,10 +6,10 @@ int main() int y; if(x) { return x;} - for(x=0;x<2;x++) + for(x=0;x<2;x++) { if(x==y) { return x;} - + } __VERIFIER_assert(0); return 0; diff --git a/regression/graphml/loop29/main.c b/regression/graphml/loop29/main.c index ec555a910..da0ea8cbe 100644 --- a/regression/graphml/loop29/main.c +++ b/regression/graphml/loop29/main.c @@ -7,6 +7,6 @@ void main() { int y; if(-3>y || y>-1) return; x += y; - } - __VERIFIER_assert(x==0 || x==-2); -} + } + __VERIFIER_assert(x==0 || x==-2); +} diff --git a/regression/graphml/malloc1/main.c b/regression/graphml/malloc1/main.c index 30f3fc751..36eda4d94 100644 --- a/regression/graphml/malloc1/main.c +++ b/regression/graphml/malloc1/main.c @@ -1029,7 +1029,7 @@ int ssl3_connect(SSL *s ) { blastFlag = 0; - s->state = 12292; + s->state = 12292; while (1) { if (s->state == 12292) { goto switch_1_12292; @@ -1047,15 +1047,15 @@ int ssl3_connect(SSL *s ) switch_1_4368: ; if (blastFlag == 0) { blastFlag = 1; - } + } s->state = 4384; goto switch_1_break; switch_1_4384: ; if (blastFlag == 1) { blastFlag = 2; goto ERROR; - } - + } + goto end; switch_1_default: goto end; diff --git a/regression/interprocedural/abort1/main.c b/regression/interprocedural/abort1/main.c index 6d591ee39..84b6451b0 100644 --- a/regression/interprocedural/abort1/main.c +++ b/regression/interprocedural/abort1/main.c @@ -7,6 +7,6 @@ int foo(int x) void main() { int x; - x = foo(x); + x = foo(x); assert(x<=0); } diff --git a/regression/interprocedural/contextsensitive1/main.c b/regression/interprocedural/contextsensitive1/main.c index c1b928562..ecfa72170 100644 --- a/regression/interprocedural/contextsensitive1/main.c +++ b/regression/interprocedural/contextsensitive1/main.c @@ -1,17 +1,15 @@ - -int sign(int x) -{ - if(x>0) return 1; - else if (x==0) return 0; - return -1; -} - -void main() -{ - int x = 1; - int y = sign(x); - x = -x; - int z = sign(x); - assert(-1<=y && y<=1 && -1<=z && z<=1); -} - +int sign(int x) +{ + if(x>0) return 1; + else if (x==0) return 0; + return -1; +} + +void main() +{ + int x = 1; + int y = sign(x); + x = -x; + int z = sign(x); + assert(-1<=y && y<=1 && -1<=z && z<=1); +} diff --git a/regression/interprocedural/contextsensitive2/main.c b/regression/interprocedural/contextsensitive2/main.c index b228a31b4..70fd27c8b 100644 --- a/regression/interprocedural/contextsensitive2/main.c +++ b/regression/interprocedural/contextsensitive2/main.c @@ -1,28 +1,26 @@ - -int sign(int x) -{ - if(x>0) return 1; - else if (x==0) return 0; - return -1; -} - -int do1(int x) -{ - return sign(x); -} - -int do2(int x) -{ - return sign(x); -} - -void main() -{ - int x = 1; - int y = do1(x); - assert(y==1); - x = -x; - int z = do2(x); - assert(-1<=z && z<=1); -} - +int sign(int x) +{ + if(x>0) return 1; + else if (x==0) return 0; + return -1; +} + +int do1(int x) +{ + return sign(x); +} + +int do2(int x) +{ + return sign(x); +} + +void main() +{ + int x = 1; + int y = do1(x); + assert(y==1); + x = -x; + int z = do2(x); + assert(-1<=z && z<=1); +} diff --git a/regression/interprocedural/contextsensitive3/main.c b/regression/interprocedural/contextsensitive3/main.c index deab63659..b4cd07854 100644 --- a/regression/interprocedural/contextsensitive3/main.c +++ b/regression/interprocedural/contextsensitive3/main.c @@ -1,28 +1,26 @@ - -int sign(int x) -{ - if(x>0) return 1; - else if (x==0) return 0; - return -1; -} - -int do1(int x) -{ - return sign(x); -} - -int do2(int x) -{ - return sign(x); -} - -void main() -{ - int x = 1; - int y = do2(x); - assert(y==1); - x = -x; - int z = do1(x); - assert(-1<=z && z<=1); -} - +int sign(int x) +{ + if(x>0) return 1; + else if (x==0) return 0; + return -1; +} + +int do1(int x) +{ + return sign(x); +} + +int do2(int x) +{ + return sign(x); +} + +void main() +{ + int x = 1; + int y = do2(x); + assert(y==1); + x = -x; + int z = do1(x); + assert(-1<=z && z<=1); +} diff --git a/regression/interprocedural/contextsensitive4/main.c b/regression/interprocedural/contextsensitive4/main.c index 9f1348396..05af1ee45 100644 --- a/regression/interprocedural/contextsensitive4/main.c +++ b/regression/interprocedural/contextsensitive4/main.c @@ -1,29 +1,27 @@ - -int x = 1; - -int sign(int x) -{ - if(x>0) return 1; - else if (x==0) return 0; - return -1; -} - -int do1(int x) -{ - return sign(x); -} - -int do2(int x) -{ - return sign(x); -} - -void main() -{ - int y = do1(x); - assert(y==1); - x = -x; - int z = do2(x); - assert(-1<=z && z<=1); -} - +int x = 1; + +int sign(int x) +{ + if(x>0) return 1; + else if (x==0) return 0; + return -1; +} + +int do1(int x) +{ + return sign(x); +} + +int do2(int x) +{ + return sign(x); +} + +void main() +{ + int y = do1(x); + assert(y==1); + x = -x; + int z = do2(x); + assert(-1<=z && z<=1); +} diff --git a/regression/interprocedural/contextsensitive5/main.c b/regression/interprocedural/contextsensitive5/main.c index fb0251140..a23d53997 100644 --- a/regression/interprocedural/contextsensitive5/main.c +++ b/regression/interprocedural/contextsensitive5/main.c @@ -1,15 +1,14 @@ -#include - -void foo(int* x) -{ - assert(x!=NULL); - *x = 0; -} - -void main() -{ - int x; - int *y = &x; - foo(y); -} - +#include + +void foo(int* x) +{ + assert(x!=NULL); + *x = 0; +} + +void main() +{ + int x; + int *y = &x; + foo(y); +} diff --git a/regression/interprocedural/contextsensitive6/main.c b/regression/interprocedural/contextsensitive6/main.c index be4631faa..b9267eb75 100644 --- a/regression/interprocedural/contextsensitive6/main.c +++ b/regression/interprocedural/contextsensitive6/main.c @@ -1,12 +1,10 @@ - -void foo(int x) -{ - assert(x!=0); -} - -void main() -{ - int x = 1; - foo(x); -} - +void foo(int x) +{ + assert(x!=0); +} + +void main() +{ + int x = 1; + foo(x); +} diff --git a/regression/interprocedural/equal1/main.c b/regression/interprocedural/equal1/main.c index e4434c38e..44bbd284d 100644 --- a/regression/interprocedural/equal1/main.c +++ b/regression/interprocedural/equal1/main.c @@ -1,5 +1,5 @@ -int foo(int x, int y) -{ +int foo(int x, int y) +{ return x; } diff --git a/regression/interprocedural/equal2/main.c b/regression/interprocedural/equal2/main.c index 5dffe2105..5280ce06f 100644 --- a/regression/interprocedural/equal2/main.c +++ b/regression/interprocedural/equal2/main.c @@ -1,5 +1,5 @@ -unsigned foo(unsigned x, unsigned y) -{ +unsigned foo(unsigned x, unsigned y) +{ __CPROVER_assume(x<10*y && y>10); return x/y; } diff --git a/regression/interprocedural/equal3/main.c b/regression/interprocedural/equal3/main.c index 6e0366b24..64deebaa1 100644 --- a/regression/interprocedural/equal3/main.c +++ b/regression/interprocedural/equal3/main.c @@ -1,5 +1,5 @@ -unsigned foo(unsigned x, unsigned y) -{ +unsigned foo(unsigned x, unsigned y) +{ if(x) return y+1; return y-1; } diff --git a/regression/interprocedural/equal4/main.c b/regression/interprocedural/equal4/main.c index 876f00c5c..62fc9aadd 100644 --- a/regression/interprocedural/equal4/main.c +++ b/regression/interprocedural/equal4/main.c @@ -3,10 +3,10 @@ int foo(int x, int y) while(x<10) { y++; - x++; + x++; y--; } - + return y; } diff --git a/regression/interprocedural/equal7/main.c b/regression/interprocedural/equal7/main.c index e44115507..305bb780d 100644 --- a/regression/interprocedural/equal7/main.c +++ b/regression/interprocedural/equal7/main.c @@ -1,5 +1,5 @@ -int foo(int x) -{ +int foo(int x) +{ __CPROVER_assume(x==0); return -x; } diff --git a/regression/interprocedural/equality_through_array7/main.c b/regression/interprocedural/equality_through_array7/main.c index 2fc0c7e03..8432f2840 100644 --- a/regression/interprocedural/equality_through_array7/main.c +++ b/regression/interprocedural/equality_through_array7/main.c @@ -14,6 +14,6 @@ void main (void) { a[1] = 0; pass_through_array(); - + assert(a[0] == 0 && a[1] == 0); } diff --git a/regression/interprocedural/global1/main.c b/regression/interprocedural/global1/main.c index ecb897b62..1436e7631 100644 --- a/regression/interprocedural/global1/main.c +++ b/regression/interprocedural/global1/main.c @@ -1,21 +1,20 @@ -#include - -int g; - -int foo(int y) -{ - __CPROVER_assume(g=1); - assert(z==0); -} - +#include + +int g; + +int foo(int y) +{ + __CPROVER_assume(g=1); + assert(z==0); +} diff --git a/regression/interprocedural/global2/main.c b/regression/interprocedural/global2/main.c index f653bce18..b41dd7bf4 100644 --- a/regression/interprocedural/global2/main.c +++ b/regression/interprocedural/global2/main.c @@ -1,22 +1,21 @@ -int g; - -void foo() -{ - g=10; -} - -int bar() -{ - return 20; -} - -void main() -{ - g = 1; - int x; - foo(); - x = bar(); - assert(g==10); - assert(x==20); -} - +int g; + +void foo() +{ + g=10; +} + +int bar() +{ + return 20; +} + +void main() +{ + g = 1; + int x; + foo(); + x = bar(); + assert(g==10); + assert(x==20); +} diff --git a/regression/interprocedural/global3/main.c b/regression/interprocedural/global3/main.c index 965a7f015..347464275 100644 --- a/regression/interprocedural/global3/main.c +++ b/regression/interprocedural/global3/main.c @@ -1,8 +1,8 @@ int x; int z; -void foo() -{ +void foo() +{ for(x=0;x<10;x++); } diff --git a/regression/interprocedural/global4/main.c b/regression/interprocedural/global4/main.c index 80e8b6e50..646b6a47b 100644 --- a/regression/interprocedural/global4/main.c +++ b/regression/interprocedural/global4/main.c @@ -1,6 +1,6 @@ int g = 1; -void modify_global() +void modify_global() { g = g; } @@ -11,12 +11,12 @@ void main() //g = g; - if(x) + if(x) { - modify_global(); + modify_global(); } - modify_global(); + modify_global(); assert(g==1); } diff --git a/regression/interprocedural/ite2/main.c b/regression/interprocedural/ite2/main.c index e6b24818f..fbb4eddee 100644 --- a/regression/interprocedural/ite2/main.c +++ b/regression/interprocedural/ite2/main.c @@ -1,11 +1,11 @@ -int foo(int x, int y) -{ +int foo(int x, int y) +{ int res = y; if(x) res = y+1; return res; } -int bar(int x) -{ +int bar(int x) +{ if(x) return 1; return 2; } @@ -13,7 +13,7 @@ int bar(int x) void main() { int x; - int y = 0; + int y = 0; int z = bar(x); int w = foo(z,y); diff --git a/regression/interprocedural/ite3/main.c b/regression/interprocedural/ite3/main.c index 0bd206af3..624104931 100644 --- a/regression/interprocedural/ite3/main.c +++ b/regression/interprocedural/ite3/main.c @@ -1,14 +1,14 @@ -int foo(int x) -{ +int foo(int x) +{ int res = 0; if(x) res = 1; return res; } -int bar(int x) -{ +int bar(int x) +{ int res = 2; if(x) res = 1; - return res; + return res; } void main() diff --git a/regression/interprocedural/ite4/main.c b/regression/interprocedural/ite4/main.c index fd030a9a5..cd12c0013 100644 --- a/regression/interprocedural/ite4/main.c +++ b/regression/interprocedural/ite4/main.c @@ -1,13 +1,13 @@ -int foo(int x) -{ +int foo(int x) +{ int res; if(x) return 0; else return 1; } -int bar(int x) -{ +int bar(int x) +{ int res; if(x) res = 0; else res = 1; diff --git a/regression/interprocedural/pointer1/main.c b/regression/interprocedural/pointer1/main.c index 34c87bb31..da5aa119a 100644 --- a/regression/interprocedural/pointer1/main.c +++ b/regression/interprocedural/pointer1/main.c @@ -1,5 +1,5 @@ -void foo(int *x) -{ +void foo(int *x) +{ *x = 10; } diff --git a/regression/interprocedural/pointer2/main.c b/regression/interprocedural/pointer2/main.c index 02f54b869..318e03ee5 100644 --- a/regression/interprocedural/pointer2/main.c +++ b/regression/interprocedural/pointer2/main.c @@ -1,5 +1,5 @@ -void foo(int *x) -{ +void foo(int *x) +{ x++; *x = 10; } diff --git a/regression/interprocedural/simple1/main.c b/regression/interprocedural/simple1/main.c index 8a95214f7..0b9154bec 100644 --- a/regression/interprocedural/simple1/main.c +++ b/regression/interprocedural/simple1/main.c @@ -1,10 +1,10 @@ -int foo() -{ +int foo() +{ return 1; } -int bar() -{ - return 2; +int bar() +{ + return 2; } void main() diff --git a/regression/interprocedural/simple2/main.c b/regression/interprocedural/simple2/main.c index e1f62b82d..984b32921 100644 --- a/regression/interprocedural/simple2/main.c +++ b/regression/interprocedural/simple2/main.c @@ -1,5 +1,5 @@ -int foo(int x) -{ +int foo(int x) +{ if(x) return 9; return 10; } diff --git a/regression/interprocedural/sum1/main.c b/regression/interprocedural/sum1/main.c index df354feeb..c6f4ab383 100644 --- a/regression/interprocedural/sum1/main.c +++ b/regression/interprocedural/sum1/main.c @@ -1,27 +1,27 @@ -#include - -int max(int x, int y) -{ - if(x>y) return x; - return y; -} - -int inv(int x) -{ - __CPROVER_assume(x>INT_MIN); //would not be needed if we did not extend the bitvector sizes - return -x; -} - -void main() -{ - int x; - __CPROVER_assume(2<=x && x<=3); - - int y=inv(x); - int z=max(y,0); - - assert(y<=-2); - assert(y==-x); - assert(z>=0); - assert(z>=y); -} +#include + +int max(int x, int y) +{ + if(x>y) return x; + return y; +} + +int inv(int x) +{ + __CPROVER_assume(x>INT_MIN); //would not be needed if we did not extend the bitvector sizes + return -x; +} + +void main() +{ + int x; + __CPROVER_assume(2<=x && x<=3); + + int y=inv(x); + int z=max(y,0); + + assert(y<=-2); + assert(y==-x); + assert(z>=0); + assert(z>=y); +} diff --git a/regression/invariants/array_safe5/main.c b/regression/invariants/array_safe5/main.c index 20cd3eb88..9e3671eb3 100644 --- a/regression/invariants/array_safe5/main.c +++ b/regression/invariants/array_safe5/main.c @@ -4,10 +4,10 @@ void main (void) { unsigned a[SIZE] = {0, }; //without initializtion a[i] for i>0 are not initialized in the 1st iteration, and hence we cannot do better than UINT_MAX for the upper bounds - for(unsigned i=0; i0) { diff --git a/regression/invariants/float2/main.c b/regression/invariants/float2/main.c index 235de6c53..a0c2c4a5d 100644 --- a/regression/invariants/float2/main.c +++ b/regression/invariants/float2/main.c @@ -1,6 +1,6 @@ void main() { - float x = 10.0; + float x = 10.0; while(x>0) { diff --git a/regression/invariants/float3/main.c b/regression/invariants/float3/main.c index 06b63a8f0..f1f7fdd07 100644 --- a/regression/invariants/float3/main.c +++ b/regression/invariants/float3/main.c @@ -1,6 +1,6 @@ void main() { - float x = 10.0; + float x = 10.0; while(x>0) // does not terminate { diff --git a/regression/invariants/float4/main.c b/regression/invariants/float4/main.c index a3edc4f6e..87b35329f 100644 --- a/regression/invariants/float4/main.c +++ b/regression/invariants/float4/main.c @@ -1,6 +1,6 @@ void main() { - float x = 10.0; + float x = 10.0; while(x>0.0) // does not terminate { diff --git a/regression/invariants/gotoloop1/main.c b/regression/invariants/gotoloop1/main.c index 57fde266c..06b649e04 100644 --- a/regression/invariants/gotoloop1/main.c +++ b/regression/invariants/gotoloop1/main.c @@ -2,7 +2,7 @@ void main() { int x,y; if(x<-5) goto LOOP; - + x = 0; while(x<10) { diff --git a/regression/invariants/gotoloop2/main.c b/regression/invariants/gotoloop2/main.c index 7f9c3ea57..8a457218e 100644 --- a/regression/invariants/gotoloop2/main.c +++ b/regression/invariants/gotoloop2/main.c @@ -2,7 +2,7 @@ void main() { int x,y; if(x<-5) goto LOOP; - + x = 0; while(x<10) { diff --git a/regression/invariants/ite1/main.c b/regression/invariants/ite1/main.c index d34a2cd40..f846c9438 100644 --- a/regression/invariants/ite1/main.c +++ b/regression/invariants/ite1/main.c @@ -1,13 +1,13 @@ -void main() -{ - int x; - int y = 0; - - while(y==0) //need to distinguish first iteration - { - if(x>=5) y=x; - else y=5; - } - - assert(y>=5); -} +void main() +{ + int x; + int y = 0; + + while(y==0) //need to distinguish first iteration + { + if(x>=5) y=x; + else y=5; + } + + assert(y>=5); +} diff --git a/regression/invariants/loop1/main.c b/regression/invariants/loop1/main.c index f35f1c6ae..e67fdcb0f 100644 --- a/regression/invariants/loop1/main.c +++ b/regression/invariants/loop1/main.c @@ -1,6 +1,6 @@ void main() { - int x = 0; + int x = 0; while(x<10) { diff --git a/regression/invariants/loop10/main.c b/regression/invariants/loop10/main.c index 72ee9fdf3..4c44c5306 100644 --- a/regression/invariants/loop10/main.c +++ b/regression/invariants/loop10/main.c @@ -1,6 +1,6 @@ void main() { - int x = 0; + int x = 0; int y; while(y) diff --git a/regression/invariants/loop11/main.c b/regression/invariants/loop11/main.c index 47a26ae58..3a6b50399 100644 --- a/regression/invariants/loop11/main.c +++ b/regression/invariants/loop11/main.c @@ -2,7 +2,7 @@ void main() { int n; __CPROVER_assume(n==0); - int x = 0; + int x = 0; while(x=0); do diff --git a/regression/invariants/loop14/main.c b/regression/invariants/loop14/main.c index bb35394d4..be0199467 100644 --- a/regression/invariants/loop14/main.c +++ b/regression/invariants/loop14/main.c @@ -1,6 +1,6 @@ void main() { - int x,y,z; + int x,y,z; __CPROVER_assume(x>=0); __CPROVER_assume(-20<=z && z<=-1); diff --git a/regression/invariants/loop15/main.c b/regression/invariants/loop15/main.c index 03b3a0c55..7e336dc14 100644 --- a/regression/invariants/loop15/main.c +++ b/regression/invariants/loop15/main.c @@ -1,6 +1,6 @@ void main() { - int x,y,z; + int x,y,z; __CPROVER_assume(x>=0); __CPROVER_assume(x==y); __CPROVER_assume(-1<=z && z<=-1); diff --git a/regression/invariants/loop16/main.c b/regression/invariants/loop16/main.c index 93a2dec12..771672940 100644 --- a/regression/invariants/loop16/main.c +++ b/regression/invariants/loop16/main.c @@ -1,7 +1,7 @@ void main() { - int x = 0; + int x = 0; int y = 0; do @@ -10,7 +10,7 @@ void main() } while(x<10); - do + do { ++y; } diff --git a/regression/invariants/loop17/main.c b/regression/invariants/loop17/main.c index 71d68b591..db66138b0 100644 --- a/regression/invariants/loop17/main.c +++ b/regression/invariants/loop17/main.c @@ -1,6 +1,6 @@ void main() { - int x; + int x; __CPROVER_assume(x>=0); do diff --git a/regression/invariants/loop18/main.c b/regression/invariants/loop18/main.c index c60b7b07d..22575a138 100644 --- a/regression/invariants/loop18/main.c +++ b/regression/invariants/loop18/main.c @@ -1,6 +1,6 @@ void main() { - int x,y,z; + int x,y,z; __CPROVER_assume(x>=0); __CPROVER_assume(x==y); __CPROVER_assume(-20<=z && z<=-1); diff --git a/regression/invariants/loop2/main.c b/regression/invariants/loop2/main.c index e67632a94..dd5d9c810 100644 --- a/regression/invariants/loop2/main.c +++ b/regression/invariants/loop2/main.c @@ -1,7 +1,7 @@ void main() { - int x = 0; + int x = 0; int y = 0; while(x<10) diff --git a/regression/invariants/loop21/main.c b/regression/invariants/loop21/main.c index 1a80bc24f..85f265c5d 100644 --- a/regression/invariants/loop21/main.c +++ b/regression/invariants/loop21/main.c @@ -1,6 +1,6 @@ void main() { - int x = 0, y = 100; + int x = 0, y = 100; while(x<100 && y>0) { diff --git a/regression/invariants/loop22/main.c b/regression/invariants/loop22/main.c index 3346995c0..7a13c955d 100644 --- a/regression/invariants/loop22/main.c +++ b/regression/invariants/loop22/main.c @@ -1,6 +1,6 @@ void main() { - int x = 0, y = 100; + int x = 0, y = 100; while(x<100 && y>0) { diff --git a/regression/invariants/loop3/main.c b/regression/invariants/loop3/main.c index 21a30e139..6ddb8924c 100644 --- a/regression/invariants/loop3/main.c +++ b/regression/invariants/loop3/main.c @@ -4,13 +4,13 @@ void main() int y; x=0; y=0; - + while(x<10 && y<20) { ++x; ++y; } - + int z=x+y; assert(z>=0); diff --git a/regression/invariants/loop5/main.c b/regression/invariants/loop5/main.c index f301dde9d..2fd0a019f 100644 --- a/regression/invariants/loop5/main.c +++ b/regression/invariants/loop5/main.c @@ -1,6 +1,6 @@ void main() { - unsigned x = 0; + unsigned x = 0; while(x<10) ++x; diff --git a/regression/invariants/loop6/main.c b/regression/invariants/loop6/main.c index 2c4213934..c7bd862fe 100644 --- a/regression/invariants/loop6/main.c +++ b/regression/invariants/loop6/main.c @@ -4,13 +4,13 @@ void main() { int x = 0; unsigned y = 0; - + while(x<10 && y<20) { ++x; ++y; } - + int z=x+y; assert(z<=20); } diff --git a/regression/invariants/loop7/main.c b/regression/invariants/loop7/main.c index 3c7dea455..1707acb1d 100644 --- a/regression/invariants/loop7/main.c +++ b/regression/invariants/loop7/main.c @@ -1,6 +1,6 @@ void main() { - int x; + int x; unsigned y; x = -10; y = 10; diff --git a/regression/invariants/nested4/main.c b/regression/invariants/nested4/main.c index 35b9f5b5a..799dc282f 100644 --- a/regression/invariants/nested4/main.c +++ b/regression/invariants/nested4/main.c @@ -5,10 +5,10 @@ void main() int n; __CPROVER_assume(0<=n && n<=N); int cost0 = 0; -for(int i=0;i=0); int y = 0; do - { + { if(z) y = y + x; else break; x -= 3; diff --git a/regression/invariants/unwind15/main.c b/regression/invariants/unwind15/main.c index fb6137ec8..022ea24fa 100644 --- a/regression/invariants/unwind15/main.c +++ b/regression/invariants/unwind15/main.c @@ -2,7 +2,7 @@ extern int nondet(); void main() { - int x; + int x; __CPROVER_assume(x>=0); int y = 0; diff --git a/regression/invariants/unwind16/main.c b/regression/invariants/unwind16/main.c index 41f3f2dbf..5d6334051 100644 --- a/regression/invariants/unwind16/main.c +++ b/regression/invariants/unwind16/main.c @@ -1,11 +1,11 @@ void main() { - int x, z; + int x, z; __CPROVER_assume(x>=0); int y = 0; while(x>0) - { + { if(z) y = y + x; else break; x -= 3; diff --git a/regression/invariants/unwind17/main.c b/regression/invariants/unwind17/main.c index fee7987dc..b2a0505e4 100644 --- a/regression/invariants/unwind17/main.c +++ b/regression/invariants/unwind17/main.c @@ -1,16 +1,16 @@ void main() { - int x, z, w; + int x, z, w; __CPROVER_assume(x>=0); int y = 0; while(x>0) - { + { x = x; if(z) y = y + x; else break; x--; - if(w) break; + if(w) break; else x++; x -= 3; } diff --git a/regression/invariants/unwind18/main.c b/regression/invariants/unwind18/main.c index b67d02ce0..44ff548cf 100644 --- a/regression/invariants/unwind18/main.c +++ b/regression/invariants/unwind18/main.c @@ -1,6 +1,6 @@ void main() { - int x = 0; + int x = 0; int y; while(x<10) diff --git a/regression/invariants/unwind19/main.c b/regression/invariants/unwind19/main.c index 635faa760..8fa6b264b 100644 --- a/regression/invariants/unwind19/main.c +++ b/regression/invariants/unwind19/main.c @@ -1,6 +1,6 @@ void main() { - int x = 0; + int x = 0; int y; do diff --git a/regression/invariants/unwind2/main.c b/regression/invariants/unwind2/main.c index f8b4ebbd8..703691405 100644 --- a/regression/invariants/unwind2/main.c +++ b/regression/invariants/unwind2/main.c @@ -1,6 +1,6 @@ void main() { - int x = 0; + int x = 0; if(x>=5) { diff --git a/regression/invariants/unwind3/main.c b/regression/invariants/unwind3/main.c index 9eb900bc9..a13c56059 100644 --- a/regression/invariants/unwind3/main.c +++ b/regression/invariants/unwind3/main.c @@ -1,6 +1,6 @@ void main() { - int x; + int x; __CPROVER_assume(5<=x && x<=100); for(int y=0;y<5;y++) x++; diff --git a/regression/invariants/unwind4/main.c b/regression/invariants/unwind4/main.c index 1e6dc4576..d395ee75e 100644 --- a/regression/invariants/unwind4/main.c +++ b/regression/invariants/unwind4/main.c @@ -1,6 +1,6 @@ void main() { - int x = 0; + int x = 0; while(x<10) ++x; diff --git a/regression/invariants/unwind5/main.c b/regression/invariants/unwind5/main.c index 6fdd141b1..5bcf04154 100644 --- a/regression/invariants/unwind5/main.c +++ b/regression/invariants/unwind5/main.c @@ -1,7 +1,7 @@ void main() { - int x = 0; - int y = 0; + int x = 0; + int y = 0; while(x<10) { diff --git a/regression/invariants/unwind6/main.c b/regression/invariants/unwind6/main.c index 5742ddea5..ea0047ea3 100644 --- a/regression/invariants/unwind6/main.c +++ b/regression/invariants/unwind6/main.c @@ -1,6 +1,6 @@ void main() { - int x = 0; + int x = 0; while(x<10) { diff --git a/regression/invariants/unwind9/main.c b/regression/invariants/unwind9/main.c index b8a4fea79..6c9b96fa1 100644 --- a/regression/invariants/unwind9/main.c +++ b/regression/invariants/unwind9/main.c @@ -10,7 +10,7 @@ void main() y++; } while(y=x); + assert(y>=x); x++; } assert(x==10); diff --git a/regression/kiki/array1/main.c b/regression/kiki/array1/main.c index 056e454f9..76764b015 100644 --- a/regression/kiki/array1/main.c +++ b/regression/kiki/array1/main.c @@ -8,7 +8,7 @@ int main(int argc, char** argv) { int y = 2; int x; - if(1 == x) + if(1 == x) s[i] = x; else y = x; } diff --git a/regression/kiki/byte_add/main.c b/regression/kiki/byte_add/main.c index b7010d14d..b4cd4b941 100644 --- a/regression/kiki/byte_add/main.c +++ b/regression/kiki/byte_add/main.c @@ -15,7 +15,7 @@ unsigned int mp_add(unsigned int a, unsigned int b) i = i; r0 = r0; r1 = r1; } */ - + while (i < (unsigned char)2) { if (i == (unsigned char)0) { r0 = (unsigned char)0; } if (i == (unsigned char)1) { r1 = (unsigned char)0; } diff --git a/regression/kiki/elevator_13_21/main.c b/regression/kiki/elevator_13_21/main.c index 48217ef19..7b50321f6 100644 --- a/regression/kiki/elevator_13_21/main.c +++ b/regression/kiki/elevator_13_21/main.c @@ -38,7 +38,7 @@ void main() goto _L___6; } } else { - _L___6: + _L___6: if (i___0 == 1) { if (floorButtons_1) { retValue_acc = 1; @@ -47,7 +47,7 @@ void main() goto _L___5; } } else { - _L___5: + _L___5: if (i___0 == 2) { if (floorButtons_2) { retValue_acc = 1; @@ -56,7 +56,7 @@ void main() goto _L___4; } } else { - _L___4: + _L___4: if (i___0 == 3) { if (floorButtons_3) { retValue_acc = 1; @@ -65,7 +65,7 @@ void main() goto _L___3; } } else { - _L___3: + _L___3: if (i___0 == 4) { if (floorButtons_4) { retValue_acc = 1; diff --git a/regression/kiki/encoder1/main.c b/regression/kiki/encoder1/main.c index 4223e9cd8..e1695894e 100644 --- a/regression/kiki/encoder1/main.c +++ b/regression/kiki/encoder1/main.c @@ -8,33 +8,33 @@ int main () { int outputBytes = 0; int encodedBytes = 0; - int last = EOF; + int last = EOF; unsigned char count = 1; int current; - do + do { current = getchar(); inputBytes += (current == EOF) ? 0 : 1; - if ((current == last) && (count < 5 /*UCHAR_MAX - 1*/)) + if ((current == last) && (count < 5 /*UCHAR_MAX - 1*/)) { ++count; - } - else + } + else { - if (last != EOF) + if (last != EOF) { - if (count > 1) + if (count > 1) { putchar(UCHAR_MAX); ++outputBytes; putchar(count); ++outputBytes; } - if (last == UCHAR_MAX) + if (last == UCHAR_MAX) { putchar(UCHAR_MAX); ++outputBytes; } - putchar(last); + putchar(last); ++outputBytes; encodedBytes += count; } @@ -42,7 +42,7 @@ int main () { last = current; count = 1; } - } + } while (last != EOF); assert(inputBytes != encodedBytes); //should fail diff --git a/regression/kiki/induction1/main.c b/regression/kiki/induction1/main.c index 23a7e0054..0ecf6a0c3 100644 --- a/regression/kiki/induction1/main.c +++ b/regression/kiki/induction1/main.c @@ -1,6 +1,6 @@ void main() { - int x = 1; + int x = 1; while(1) { diff --git a/regression/kiki/induction2/main.c b/regression/kiki/induction2/main.c index 76f88d6eb..5114dc168 100644 --- a/regression/kiki/induction2/main.c +++ b/regression/kiki/induction2/main.c @@ -1,6 +1,6 @@ void main() { - int x = 1, y = -1, z = 1; + int x = 1, y = -1, z = 1; while(1) { diff --git a/regression/kiki/induction3/main.c b/regression/kiki/induction3/main.c index 38ef4b24f..aaa525389 100644 --- a/regression/kiki/induction3/main.c +++ b/regression/kiki/induction3/main.c @@ -1,6 +1,6 @@ void main() { - int x = 0, y = 0, z = 0; + int x = 0, y = 0, z = 0; while(1) { diff --git a/regression/kiki/induction4/main.c b/regression/kiki/induction4/main.c index c55adf781..7a7096e3c 100644 --- a/regression/kiki/induction4/main.c +++ b/regression/kiki/induction4/main.c @@ -1,16 +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 -} +int main() { + int x,y,z; + __CPROVER_assume(x==y && y==z && -10<=x && x<0); + +// while(1) + while(x<=z+2) + { +// __CPROVER_assume(x<=z+2); + z = -y; + y = -x; + if(nondet()) x = x+1; + if(x>=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/loop12/main.c b/regression/kiki/loop12/main.c index 171881bda..43464f4fb 100644 --- a/regression/kiki/loop12/main.c +++ b/regression/kiki/loop12/main.c @@ -1,6 +1,6 @@ void main() { - int x = 0; + int x = 0; int y; while(y) diff --git a/regression/kiki/loop23/main.c b/regression/kiki/loop23/main.c index 274fe8975..944133675 100644 --- a/regression/kiki/loop23/main.c +++ b/regression/kiki/loop23/main.c @@ -5,10 +5,10 @@ int main() int y; if(x) { return x;} - for(x=0;x<2;x++) + for(x=0;x<2;x++) { if(x==y) { return x;} - + } assert(0); return 0; diff --git a/regression/kiki/loop24/main.c b/regression/kiki/loop24/main.c index 8833d199d..9266d50b7 100644 --- a/regression/kiki/loop24/main.c +++ b/regression/kiki/loop24/main.c @@ -1,13 +1,13 @@ -void main() -{ - int x = 1, y = -1, z = 1; - - while(1) - { - if(x!=z) break; - z = y; - y = x; - x = -x; - } - assert(0); -} +void main() +{ + int x = 1, y = -1, z = 1; + + while(1) + { + if(x!=z) break; + z = y; + y = x; + x = -x; + } + assert(0); +} diff --git a/regression/kiki/loop25/main.c b/regression/kiki/loop25/main.c index 8febd85d7..e05732e45 100644 --- a/regression/kiki/loop25/main.c +++ b/regression/kiki/loop25/main.c @@ -1,12 +1,12 @@ -void main() -{ - int x = 1, y = -1, z = 1; - - while(x==z) - { - z = y; - y = x; - x = -x; - } - assert(0); -} +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/loop25/test.desc b/regression/kiki/loop25/test.desc index 6755e58a3..34e465e33 100644 --- a/regression/kiki/loop25/test.desc +++ b/regression/kiki/loop25/test.desc @@ -1,6 +1,6 @@ CORE main.c ---k-induction +--k-induction ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/kiki/loop26/main.c b/regression/kiki/loop26/main.c index ae5c34f7d..f9f6ed3fd 100644 --- a/regression/kiki/loop26/main.c +++ b/regression/kiki/loop26/main.c @@ -1,15 +1,15 @@ -void main() -{ - int x = 1, y = -1, z = 1; - - while(1) - { - z = y; - y = x; - x = -x; - if(x!=z) break; - } - assert(0); -} +void main() +{ + int x = 1, y = -1, z = 1; + + while(1) + { + z = y; + y = x; + x = -x; + if(x!=z) break; + } + assert(0); +} diff --git a/regression/kiki/loop27/main.c b/regression/kiki/loop27/main.c index ca9acda4c..3c5aa9703 100644 --- a/regression/kiki/loop27/main.c +++ b/regression/kiki/loop27/main.c @@ -1,13 +1,13 @@ -void main() -{ - int x = 1, y = -1, z = 1; - - do - { - z = y; - y = x; - x = -x; - } - while(x==z); - assert(0); -} +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/loop28/main.c b/regression/kiki/loop28/main.c index 7ae8d5301..bd0509336 100644 --- a/regression/kiki/loop28/main.c +++ b/regression/kiki/loop28/main.c @@ -1,8 +1,8 @@ -void main() { - int b = 3; - unsigned int j=0; - while (j<1 && b!=3) { - j++; - } - assert(j<1); -} +void main() { + int b = 3; + unsigned int j=0; + while (j<1 && b!=3) { + j++; + } + assert(j<1); +} diff --git a/regression/kiki/loop29/main.c b/regression/kiki/loop29/main.c index 0135d5b6d..bbde2d56a 100644 --- a/regression/kiki/loop29/main.c +++ b/regression/kiki/loop29/main.c @@ -5,6 +5,6 @@ void main() { int y; __CPROVER_assume(-3<=y && y<=-1); x += y; - } - assert(x==0 || x==-2); -} + } + assert(x==0 || x==-2); +} diff --git a/regression/kiki/loop30/main.c b/regression/kiki/loop30/main.c index c0ae436c1..e77a78ef8 100644 --- a/regression/kiki/loop30/main.c +++ b/regression/kiki/loop30/main.c @@ -4,6 +4,6 @@ void main() { { x += 1; assert(x<5); - } - while(x<10); -} + } + while(x<10); +} diff --git a/regression/kiki/loop9/main.c b/regression/kiki/loop9/main.c index 13cf22ccd..763566845 100644 --- a/regression/kiki/loop9/main.c +++ b/regression/kiki/loop9/main.c @@ -1,6 +1,6 @@ void main() { - int x = 0; + int x = 0; int y; while(y) diff --git a/regression/kiki/malloc1/main.c b/regression/kiki/malloc1/main.c index 4f3bca21f..2b5cb01c3 100644 --- a/regression/kiki/malloc1/main.c +++ b/regression/kiki/malloc1/main.c @@ -1035,7 +1035,7 @@ int ssl3_connect(SSL *s ) { blastFlag = 0; - s->state = 12292; + s->state = 12292; while (1) { if (s->state == 12292) { goto switch_1_12292; @@ -1053,15 +1053,15 @@ int ssl3_connect(SSL *s ) switch_1_4368: ; if (blastFlag == 0) { blastFlag = 1; - } + } s->state = 4384; goto switch_1_break; switch_1_4384: ; if (blastFlag == 1) { blastFlag = 2; goto ERROR; - } - + } + goto end; switch_1_default: goto end; diff --git a/regression/kiki/malloc3/main.c b/regression/kiki/malloc3/main.c index 2c823a1ec..33bc7c05d 100644 --- a/regression/kiki/malloc3/main.c +++ b/regression/kiki/malloc3/main.c @@ -13,7 +13,7 @@ void main() w = x; }*/ float *f; - + for(int z=0;z<1;z++) { //assert(w==5); diff --git a/regression/kiki/nested11/main.c b/regression/kiki/nested11/main.c index 790b6c4b3..d6f5d20a3 100644 --- a/regression/kiki/nested11/main.c +++ b/regression/kiki/nested11/main.c @@ -3,7 +3,7 @@ void main() int x,y; for(x=0;x<10;) { - for(y=0;y=0); } diff --git a/regression/preconditions/precond2/main.c b/regression/preconditions/precond2/main.c index b67310cdc..5b50bb943 100644 --- a/regression/preconditions/precond2/main.c +++ b/regression/preconditions/precond2/main.c @@ -1,5 +1,5 @@ -void foo(int x) -{ +void foo(int x) +{ int y = x; assert(y>=0); } diff --git a/regression/preconditions/precond3/main.c b/regression/preconditions/precond3/main.c index 0045d70a5..7a25fd03b 100644 --- a/regression/preconditions/precond3/main.c +++ b/regression/preconditions/precond3/main.c @@ -1,5 +1,5 @@ -void foo(char* x) -{ +void foo(char* x) +{ assert(x!=0); *x = 0; } diff --git a/regression/preconditions/precond4/main.c b/regression/preconditions/precond4/main.c index e612011ba..f458914de 100644 --- a/regression/preconditions/precond4/main.c +++ b/regression/preconditions/precond4/main.c @@ -1,9 +1,9 @@ -int FirstOccurrence(int len, int a[]) -{ +int FirstOccurrence(int len, int a[]) +{ if(len<=0) return -1; int i = 0; assert(i=0) { assert(len>=3); diff --git a/regression/preconditions/precond6/main.c b/regression/preconditions/precond6/main.c index b67310cdc..5b50bb943 100644 --- a/regression/preconditions/precond6/main.c +++ b/regression/preconditions/precond6/main.c @@ -1,5 +1,5 @@ -void foo(int x) -{ +void foo(int x) +{ int y = x; assert(y>=0); } diff --git a/regression/preconditions/precond_contextsensitive1/main.c b/regression/preconditions/precond_contextsensitive1/main.c index ccf80ffd1..39cc080fa 100644 --- a/regression/preconditions/precond_contextsensitive1/main.c +++ b/regression/preconditions/precond_contextsensitive1/main.c @@ -1,15 +1,15 @@ - -int sign(int x) -{ - if(x>0) return 1; - else if (x==0) return 0; - return -1; -} - -void main() -{ - int x; - int y = sign(x); - assert(y==0); -} - + +int sign(int x) +{ + if(x>0) return 1; + else if (x==0) return 0; + return -1; +} + +void main() +{ + int x; + int y = sign(x); + assert(y==0); +} + diff --git a/regression/preconditions/precond_contextsensitive2/main.c b/regression/preconditions/precond_contextsensitive2/main.c index d1713f3e3..72b6f0cf7 100644 --- a/regression/preconditions/precond_contextsensitive2/main.c +++ b/regression/preconditions/precond_contextsensitive2/main.c @@ -1,11 +1,11 @@ - -void foo(int x) -{ - assert(x!=1); -} - -int main(int argc, char** argv) -{ - foo(argc); -} - + +void foo(int x) +{ + assert(x!=1); +} + +int main(int argc, char** argv) +{ + foo(argc); +} + diff --git a/regression/termination/abe_createBack1/main.c b/regression/termination/abe_createBack1/main.c index 8bfbfb993..5397ab702 100644 --- a/regression/termination/abe_createBack1/main.c +++ b/regression/termination/abe_createBack1/main.c @@ -59,7 +59,7 @@ void createBack(struct SDL_Surface back_surface) // SDL_UpperBlit(img, (struct SDL_Rect *)NULL, *back_surface, &pos); } //assert(-y>-(y+img.h)); - // assert(-y+(y+img.h)>0); + // assert(-y+(y+img.h)>0); assert(img.h!=0); } } diff --git a/regression/termination/abort1/main.c b/regression/termination/abort1/main.c index ab6bd07ef..3e8ad47a7 100644 --- a/regression/termination/abort1/main.c +++ b/regression/termination/abort1/main.c @@ -8,7 +8,7 @@ int foo(int x) int main(int argc, char** argv) { int x = argc; - x = foo(x); + x = foo(x); assert(x>=1); return x; } diff --git a/regression/termination/abort3/main.c b/regression/termination/abort3/main.c index ecc2f25b9..84dc211a7 100644 --- a/regression/termination/abort3/main.c +++ b/regression/termination/abort3/main.c @@ -7,7 +7,7 @@ int foo(int x) int main(int argc, char** argv) { int x = argc; - x = foo(x); + x = foo(x); assert(x>=1); return x; } diff --git a/regression/termination/array_safe5/main.c b/regression/termination/array_safe5/main.c index 20cd3eb88..9e3671eb3 100644 --- a/regression/termination/array_safe5/main.c +++ b/regression/termination/array_safe5/main.c @@ -4,10 +4,10 @@ void main (void) { unsigned a[SIZE] = {0, }; //without initializtion a[i] for i>0 are not initialized in the 1st iteration, and hence we cannot do better than UINT_MAX for the upper bounds - for(unsigned i=0; i 0 || l_var<0 || l_var>=1073741824); // precondition for termination int i=0; - if (l_var >= 0) + if (l_var >= 0) { - while (l_var < 1073741824) + while (l_var < 1073741824) { i++; l_var = l_var << 1; @@ -21,7 +21,7 @@ void f(int l_var) int main() { int l_var = nondet_int(); - + f(l_var); return 0; diff --git a/regression/termination/cav08_1p/main.c b/regression/termination/cav08_1p/main.c index e30cb8c9d..9f0ebeb54 100644 --- a/regression/termination/cav08_1p/main.c +++ b/regression/termination/cav08_1p/main.c @@ -1,4 +1,4 @@ -/* +/* Example from Cook et al, CAV 2008 */ @@ -8,9 +8,9 @@ void f(int l_var) { // __CPROVER_assume(l_var> 0 || l_var<0 || l_var>=1073741824); // precondition for termination int i=0; - if (l_var >= 0) + if (l_var >= 0) { - while (l_var < 1073741824) + while (l_var < 1073741824) { i++; l_var = l_var << 1; @@ -21,7 +21,7 @@ void f(int l_var) int main() { int l_var = nondet_int(); - + f(l_var); return 0; diff --git a/regression/termination/cav08_2/main.c b/regression/termination/cav08_2/main.c index 67b296232..3c0991765 100644 --- a/regression/termination/cav08_2/main.c +++ b/regression/termination/cav08_2/main.c @@ -1,4 +1,4 @@ -/* +/* Example from Cook et al, CAV 2008 */ @@ -15,7 +15,7 @@ void f(int cbSrcLength, int cbHeader, int nBlockAlignment, DWORD *pbSrc, DWORD * { __CPROVER_assume(cbSrcLength < cbHeader || nBlockAlignment > 0 && cbHeader > 0); // precondition for termination - while (cbSrcLength >= cbHeader) + while (cbSrcLength >= cbHeader) { DWORD dwHeader; UINT cbBlockLength; @@ -28,7 +28,7 @@ void f(int cbSrcLength, int cbHeader, int nBlockAlignment, DWORD *pbSrc, DWORD * int nStepIndex = (int)(BYTE)HIWORD(dwHeader); if( !imaadpcmValidStepIndex(nStepIndex) ) return 0; *pbDst++ = (BYTE)((nPredSample >> 8) + 128); */ - while (cbBlockLength--) + while (cbBlockLength--) { /* DWORD bSample = *pbSrc++; DWORD nEncSample = (bSample & (BYTE)0x0F); @@ -56,7 +56,7 @@ int main() int nBlockAlignment = nondet_int(); DWORD *pbSrc, *pbDst; int *step; - + f(cbSrcLength, cbHeader, nBlockAlignment, pbSrc, pbSrc, step); return 0; diff --git a/regression/termination/cav08_2p/main.c b/regression/termination/cav08_2p/main.c index ab173d9ae..72a0c3c9d 100644 --- a/regression/termination/cav08_2p/main.c +++ b/regression/termination/cav08_2p/main.c @@ -1,4 +1,4 @@ -/* +/* Example from Cook et al, CAV 2008 */ @@ -15,7 +15,7 @@ void f(int cbSrcLength, int cbHeader, int nBlockAlignment, DWORD *pbSrc, DWORD * { // __CPROVER_assume(cbSrcLength < cbHeader || nBlockAlignment > 0 && cbHeader > 0); // precondition for termination - while (cbSrcLength >= cbHeader) + while (cbSrcLength >= cbHeader) { DWORD dwHeader; UINT cbBlockLength; @@ -28,7 +28,7 @@ void f(int cbSrcLength, int cbHeader, int nBlockAlignment, DWORD *pbSrc, DWORD * int nStepIndex = (int)(BYTE)HIWORD(dwHeader); if( !imaadpcmValidStepIndex(nStepIndex) ) return 0; *pbDst++ = (BYTE)((nPredSample >> 8) + 128); */ - while (cbBlockLength--) + while (cbBlockLength--) { /* DWORD bSample = *pbSrc++; DWORD nEncSample = (bSample & (BYTE)0x0F); @@ -56,7 +56,7 @@ int main() int nBlockAlignment = nondet_int(); DWORD *pbSrc, *pbDst; int *step; - + f(cbSrcLength, cbHeader, nBlockAlignment, pbSrc, pbSrc, step); return 0; diff --git a/regression/termination/cav08_3/main.c b/regression/termination/cav08_3/main.c index fff20a220..efc7bce87 100644 --- a/regression/termination/cav08_3/main.c +++ b/regression/termination/cav08_3/main.c @@ -1,4 +1,4 @@ -/* +/* Example from Cook et al, CAV 2008 */ @@ -8,7 +8,7 @@ void f(int x, int y, int z) { __CPROVER_assume(x<=0 || x+y<=0 || x+2*y+z<=0 || x+3*y+3*z<=0 || z<0 || z<=0 && y<=0); // precondition for termination - while (x>0) + while (x>0) { x = x + y; y = y + z; @@ -20,7 +20,7 @@ int main() int x = nondet_int(); int y = nondet_int(); int z = nondet_int(); - + f(x,y,z); return 0; diff --git a/regression/termination/cav08_3p/main.c b/regression/termination/cav08_3p/main.c index 3d56eff51..7a6fa2b39 100644 --- a/regression/termination/cav08_3p/main.c +++ b/regression/termination/cav08_3p/main.c @@ -1,4 +1,4 @@ -/* +/* Example from Cook et al, CAV 2008 */ @@ -8,7 +8,7 @@ void f(int x, int y, int z) { // __CPROVER_assume(x<=0 || x+y<=0 || x+2*y+z<=0 || x+3*y+3*z<=0 || z<0 || z<=0 && y<=0); // precondition for termination - while (x>0) + while (x>0) { x = x + y; y = y + z; @@ -20,7 +20,7 @@ int main() int x = nondet_int(); int y = nondet_int(); int z = nondet_int(); - + f(x,y,z); return 0; diff --git a/regression/termination/cav08_4/main.c b/regression/termination/cav08_4/main.c index 61fb56ac3..4e6b8ca57 100644 --- a/regression/termination/cav08_4/main.c +++ b/regression/termination/cav08_4/main.c @@ -1,4 +1,4 @@ -/* +/* Example from Cook et al, CAV 2008 */ @@ -7,11 +7,11 @@ unsigned nondet_int(); void f(int x, int y, int N) { __CPROVER_assume(x>N || x+y>=0); // precondition for termination - - while (x<=N) + + while (x<=N) { int c; - if(c) + if(c) { x = 2*x + y; y = y + 1; @@ -28,7 +28,7 @@ int main() int x = nondet_int(); int y = nondet_int(); int N = nondet_int(); - + f(x,y,N); return 0; diff --git a/regression/termination/cav08_4p/main.c b/regression/termination/cav08_4p/main.c index 6016788b8..f87616cd0 100644 --- a/regression/termination/cav08_4p/main.c +++ b/regression/termination/cav08_4p/main.c @@ -1,4 +1,4 @@ -/* +/* Example from Cook et al, CAV 2008 */ @@ -7,11 +7,11 @@ unsigned nondet_int(); void f(int x, int y, int N) { // __CPROVER_assume(x>N || x+y>=0); // precondition for termination - - while (x<=N) + + while (x<=N) { int c; - if(c) + if(c) { x = 2*x + y; y = y + 1; @@ -28,7 +28,7 @@ int main() int x = nondet_int(); int y = nondet_int(); int N = nondet_int(); - + f(x,y,N); return 0; diff --git a/regression/termination/cav08_5/main.c b/regression/termination/cav08_5/main.c index e101bf65a..8c01cbd34 100644 --- a/regression/termination/cav08_5/main.c +++ b/regression/termination/cav08_5/main.c @@ -1,4 +1,4 @@ -/* +/* Example from Cook et al, CAV 2008 */ @@ -7,8 +7,8 @@ unsigned nondet_int(); void f(int x) { __CPROVER_assume(x>5 || x<0); - - while (x>=0) + + while (x>=0) { x = -2*x + 10; } @@ -17,7 +17,7 @@ void f(int x) int main() { int x = nondet_int(); - + f(x); return 0; diff --git a/regression/termination/cav08_5p/main.c b/regression/termination/cav08_5p/main.c index 991ef5997..f96dd606d 100644 --- a/regression/termination/cav08_5p/main.c +++ b/regression/termination/cav08_5p/main.c @@ -1,4 +1,4 @@ -/* +/* Example from Cook et al, CAV 2008 */ @@ -7,8 +7,8 @@ unsigned nondet_int(); void f(int x) { // __CPROVER_assume(x>5 || x<0); - - while (x>=0) + + while (x>=0) { x = -2*x + 10; } @@ -17,7 +17,7 @@ void f(int x) int main() { int x = nondet_int(); - + f(x); return 0; diff --git a/regression/termination/cav08_6/main.c b/regression/termination/cav08_6/main.c index 75719e100..21436c6be 100644 --- a/regression/termination/cav08_6/main.c +++ b/regression/termination/cav08_6/main.c @@ -1,4 +1,4 @@ -/* +/* Example from Cook et al, CAV 2008 */ @@ -9,10 +9,10 @@ void f(int y, int n) __CPROVER_assume(n>200 && y<9); //additional assumption given __CPROVER_assume(y>0); // precondition for termination int x = 0; - while (1) + while (1) { - if (x= 200) break; } @@ -23,7 +23,7 @@ int main() { int y = nondet_int(); int n = nondet_int(); - + f(y,n); return 0; diff --git a/regression/termination/cav08_6p/main.c b/regression/termination/cav08_6p/main.c index 9194b0fdb..54a1d9499 100644 --- a/regression/termination/cav08_6p/main.c +++ b/regression/termination/cav08_6p/main.c @@ -1,4 +1,4 @@ -/* +/* Example from Cook et al, CAV 2008 */ @@ -9,10 +9,10 @@ void f(int y, int n) __CPROVER_assume(n>200 && y<9); //additional assumption given // __CPROVER_assume(y>0); // precondition for termination int x = 0; - while (1) + while (1) { - if (x= 200) break; } @@ -23,7 +23,7 @@ int main() { int y = nondet_int(); int n = nondet_int(); - + f(y,n); return 0; diff --git a/regression/termination/cav08_7/main.c b/regression/termination/cav08_7/main.c index 337ee200b..eb88a2ae8 100644 --- a/regression/termination/cav08_7/main.c +++ b/regression/termination/cav08_7/main.c @@ -1,4 +1,4 @@ -/* +/* Example from Cook et al, CAV 2008 */ @@ -8,12 +8,12 @@ void f(int x, int y) { __CPROVER_assume(x==y || x>0 && y>0); // precondition for termination - while (x!=y) - { - if (x>y) + while (x!=y) + { + if (x>y) { x=x-y; - } + } else { y=y-x; @@ -25,7 +25,7 @@ int main() { int x = nondet_int(); int y = nondet_int(); - + f(x,y); return 0; diff --git a/regression/termination/cav08_7p/main.c b/regression/termination/cav08_7p/main.c index 7de383b19..3579f823a 100644 --- a/regression/termination/cav08_7p/main.c +++ b/regression/termination/cav08_7p/main.c @@ -1,4 +1,4 @@ -/* +/* Example from Cook et al, CAV 2008 */ @@ -8,12 +8,12 @@ void f(int x, int y) { // __CPROVER_assume(x==y || x>0 && y>0); // precondition for termination - while (x!=y) - { - if (x>y) + while (x!=y) + { + if (x>y) { x=x-y; - } + } else { y=y-x; @@ -25,7 +25,7 @@ int main() { int x = nondet_int(); int y = nondet_int(); - + f(x,y); return 0; diff --git a/regression/termination/contextsensitive1/main.c b/regression/termination/contextsensitive1/main.c index c1b928562..80cbc563c 100644 --- a/regression/termination/contextsensitive1/main.c +++ b/regression/termination/contextsensitive1/main.c @@ -1,17 +1,17 @@ - -int sign(int x) -{ - if(x>0) return 1; - else if (x==0) return 0; - return -1; -} - -void main() -{ - int x = 1; - int y = sign(x); - x = -x; - int z = sign(x); - assert(-1<=y && y<=1 && -1<=z && z<=1); -} - + +int sign(int x) +{ + if(x>0) return 1; + else if (x==0) return 0; + return -1; +} + +void main() +{ + int x = 1; + int y = sign(x); + x = -x; + int z = sign(x); + assert(-1<=y && y<=1 && -1<=z && z<=1); +} + diff --git a/regression/termination/contextsensitive2/main.c b/regression/termination/contextsensitive2/main.c index b228a31b4..bcd5eb7ed 100644 --- a/regression/termination/contextsensitive2/main.c +++ b/regression/termination/contextsensitive2/main.c @@ -1,28 +1,28 @@ - -int sign(int x) -{ - if(x>0) return 1; - else if (x==0) return 0; - return -1; -} - -int do1(int x) -{ - return sign(x); -} - -int do2(int x) -{ - return sign(x); -} - -void main() -{ - int x = 1; - int y = do1(x); - assert(y==1); - x = -x; - int z = do2(x); - assert(-1<=z && z<=1); -} - + +int sign(int x) +{ + if(x>0) return 1; + else if (x==0) return 0; + return -1; +} + +int do1(int x) +{ + return sign(x); +} + +int do2(int x) +{ + return sign(x); +} + +void main() +{ + int x = 1; + int y = do1(x); + assert(y==1); + x = -x; + int z = do2(x); + assert(-1<=z && z<=1); +} + diff --git a/regression/termination/contextsensitive3/main.c b/regression/termination/contextsensitive3/main.c index deab63659..a67b572d0 100644 --- a/regression/termination/contextsensitive3/main.c +++ b/regression/termination/contextsensitive3/main.c @@ -1,28 +1,28 @@ - -int sign(int x) -{ - if(x>0) return 1; - else if (x==0) return 0; - return -1; -} - -int do1(int x) -{ - return sign(x); -} - -int do2(int x) -{ - return sign(x); -} - -void main() -{ - int x = 1; - int y = do2(x); - assert(y==1); - x = -x; - int z = do1(x); - assert(-1<=z && z<=1); -} - + +int sign(int x) +{ + if(x>0) return 1; + else if (x==0) return 0; + return -1; +} + +int do1(int x) +{ + return sign(x); +} + +int do2(int x) +{ + return sign(x); +} + +void main() +{ + int x = 1; + int y = do2(x); + assert(y==1); + x = -x; + int z = do1(x); + assert(-1<=z && z<=1); +} + diff --git a/regression/termination/contextsensitive4/main.c b/regression/termination/contextsensitive4/main.c index 9f1348396..f90baaa2d 100644 --- a/regression/termination/contextsensitive4/main.c +++ b/regression/termination/contextsensitive4/main.c @@ -1,29 +1,29 @@ - -int x = 1; - -int sign(int x) -{ - if(x>0) return 1; - else if (x==0) return 0; - return -1; -} - -int do1(int x) -{ - return sign(x); -} - -int do2(int x) -{ - return sign(x); -} - -void main() -{ - int y = do1(x); - assert(y==1); - x = -x; - int z = do2(x); - assert(-1<=z && z<=1); -} - + +int x = 1; + +int sign(int x) +{ + if(x>0) return 1; + else if (x==0) return 0; + return -1; +} + +int do1(int x) +{ + return sign(x); +} + +int do2(int x) +{ + return sign(x); +} + +void main() +{ + int y = do1(x); + assert(y==1); + x = -x; + int z = do2(x); + assert(-1<=z && z<=1); +} + diff --git a/regression/termination/contextsensitive5/main.c b/regression/termination/contextsensitive5/main.c index fb0251140..81be7a8ed 100644 --- a/regression/termination/contextsensitive5/main.c +++ b/regression/termination/contextsensitive5/main.c @@ -1,15 +1,15 @@ -#include - -void foo(int* x) -{ - assert(x!=NULL); - *x = 0; -} - -void main() -{ - int x; - int *y = &x; - foo(y); -} - +#include + +void foo(int* x) +{ + assert(x!=NULL); + *x = 0; +} + +void main() +{ + int x; + int *y = &x; + foo(y); +} + diff --git a/regression/termination/contextsensitive6/main.c b/regression/termination/contextsensitive6/main.c index be4631faa..ed39a132c 100644 --- a/regression/termination/contextsensitive6/main.c +++ b/regression/termination/contextsensitive6/main.c @@ -1,12 +1,12 @@ - -void foo(int x) -{ - assert(x!=0); -} - -void main() -{ - int x = 1; - foo(x); -} - + +void foo(int x) +{ + assert(x!=0); +} + +void main() +{ + int x = 1; + foo(x); +} + diff --git a/regression/termination/equal1/main.c b/regression/termination/equal1/main.c index e4434c38e..44bbd284d 100644 --- a/regression/termination/equal1/main.c +++ b/regression/termination/equal1/main.c @@ -1,5 +1,5 @@ -int foo(int x, int y) -{ +int foo(int x, int y) +{ return x; } diff --git a/regression/termination/equal2/main.c b/regression/termination/equal2/main.c index 5dffe2105..5280ce06f 100644 --- a/regression/termination/equal2/main.c +++ b/regression/termination/equal2/main.c @@ -1,5 +1,5 @@ -unsigned foo(unsigned x, unsigned y) -{ +unsigned foo(unsigned x, unsigned y) +{ __CPROVER_assume(x<10*y && y>10); return x/y; } diff --git a/regression/termination/equal3/main.c b/regression/termination/equal3/main.c index 6e0366b24..64deebaa1 100644 --- a/regression/termination/equal3/main.c +++ b/regression/termination/equal3/main.c @@ -1,5 +1,5 @@ -unsigned foo(unsigned x, unsigned y) -{ +unsigned foo(unsigned x, unsigned y) +{ if(x) return y+1; return y-1; } diff --git a/regression/termination/equal4/main.c b/regression/termination/equal4/main.c index 876f00c5c..62fc9aadd 100644 --- a/regression/termination/equal4/main.c +++ b/regression/termination/equal4/main.c @@ -3,10 +3,10 @@ int foo(int x, int y) while(x<10) { y++; - x++; + x++; y--; } - + return y; } diff --git a/regression/termination/equal6/main.c b/regression/termination/equal6/main.c index e439e7892..22e381c9d 100644 --- a/regression/termination/equal6/main.c +++ b/regression/termination/equal6/main.c @@ -4,7 +4,7 @@ void main() while(x<10) { - x++; + x++; while(y0) { diff --git a/regression/termination/float2/main.c b/regression/termination/float2/main.c index 9a5d17658..46d257f96 100644 --- a/regression/termination/float2/main.c +++ b/regression/termination/float2/main.c @@ -2,7 +2,7 @@ int main(int argc, char** argv) { - float x = 10.0; + float x = 10.0; while(x>0) { diff --git a/regression/termination/float3/main.c b/regression/termination/float3/main.c index ba27d41b6..9915bcd95 100644 --- a/regression/termination/float3/main.c +++ b/regression/termination/float3/main.c @@ -1,6 +1,6 @@ void main() { - float x = 10.0; + float x = 10.0; while(x>0) // does not terminate { diff --git a/regression/termination/float4/main.c b/regression/termination/float4/main.c index 98c97c5d9..e52a531f4 100644 --- a/regression/termination/float4/main.c +++ b/regression/termination/float4/main.c @@ -1,6 +1,6 @@ void main() { - float x = 10.0; + float x = 10.0; while(x>0.0) // does not terminate { diff --git a/regression/termination/float5/main.c b/regression/termination/float5/main.c index 411a1d54e..3b93d22ed 100644 --- a/regression/termination/float5/main.c +++ b/regression/termination/float5/main.c @@ -2,7 +2,7 @@ int main(int argc, char** argv) { float x; - __CPROVER_assume(-FLT_MAX<=x && x<=FLT_MAX); + __CPROVER_assume(-FLT_MAX<=x && x<=FLT_MAX); while(x>0.0f) { x *= 0.1f; //terminates diff --git a/regression/termination/float6/main.c b/regression/termination/float6/main.c index 2625189cd..2db9b4007 100644 --- a/regression/termination/float6/main.c +++ b/regression/termination/float6/main.c @@ -5,7 +5,7 @@ int main(int argc, char** argv) while(x>=0) //doesn't terminate { x -= 0.15f; - if(0>x && x>-0.15f) + if(0>x && x>-0.15f) { x = 15.0f; } diff --git a/regression/termination/global1/main.c b/regression/termination/global1/main.c index ecb897b62..368fcddd7 100644 --- a/regression/termination/global1/main.c +++ b/regression/termination/global1/main.c @@ -1,21 +1,21 @@ -#include - -int g; - -int foo(int y) -{ - __CPROVER_assume(g=1); - assert(z==0); -} - +#include + +int g; + +int foo(int y) +{ + __CPROVER_assume(g=1); + assert(z==0); +} + diff --git a/regression/termination/global2/main.c b/regression/termination/global2/main.c index f653bce18..32734b1a1 100644 --- a/regression/termination/global2/main.c +++ b/regression/termination/global2/main.c @@ -1,22 +1,22 @@ -int g; - -void foo() -{ - g=10; -} - -int bar() -{ - return 20; -} - -void main() -{ - g = 1; - int x; - foo(); - x = bar(); - assert(g==10); - assert(x==20); -} - +int g; + +void foo() +{ + g=10; +} + +int bar() +{ + return 20; +} + +void main() +{ + g = 1; + int x; + foo(); + x = bar(); + assert(g==10); + assert(x==20); +} + diff --git a/regression/termination/global3/main.c b/regression/termination/global3/main.c index 965a7f015..347464275 100644 --- a/regression/termination/global3/main.c +++ b/regression/termination/global3/main.c @@ -1,8 +1,8 @@ int x; int z; -void foo() -{ +void foo() +{ for(x=0;x<10;x++); } diff --git a/regression/termination/global4/main.c b/regression/termination/global4/main.c index 80e8b6e50..646b6a47b 100644 --- a/regression/termination/global4/main.c +++ b/regression/termination/global4/main.c @@ -1,6 +1,6 @@ int g = 1; -void modify_global() +void modify_global() { g = g; } @@ -11,12 +11,12 @@ void main() //g = g; - if(x) + if(x) { - modify_global(); + modify_global(); } - modify_global(); + modify_global(); assert(g==1); } diff --git a/regression/termination/ite1/main.c b/regression/termination/ite1/main.c index b4829d864..4f98ef44c 100644 --- a/regression/termination/ite1/main.c +++ b/regression/termination/ite1/main.c @@ -1,13 +1,13 @@ -void main() -{ - int x; - int y = 0; - - while(y==0) - { - if(x>=5) y=x; - else y=5; - } - - assert(y>=5); -} +void main() +{ + int x; + int y = 0; + + while(y==0) + { + if(x>=5) y=x; + else y=5; + } + + assert(y>=5); +} diff --git a/regression/termination/ite2/main.c b/regression/termination/ite2/main.c index e6b24818f..fbb4eddee 100644 --- a/regression/termination/ite2/main.c +++ b/regression/termination/ite2/main.c @@ -1,11 +1,11 @@ -int foo(int x, int y) -{ +int foo(int x, int y) +{ int res = y; if(x) res = y+1; return res; } -int bar(int x) -{ +int bar(int x) +{ if(x) return 1; return 2; } @@ -13,7 +13,7 @@ int bar(int x) void main() { int x; - int y = 0; + int y = 0; int z = bar(x); int w = foo(z,y); diff --git a/regression/termination/ite3/main.c b/regression/termination/ite3/main.c index 0bd206af3..624104931 100644 --- a/regression/termination/ite3/main.c +++ b/regression/termination/ite3/main.c @@ -1,14 +1,14 @@ -int foo(int x) -{ +int foo(int x) +{ int res = 0; if(x) res = 1; return res; } -int bar(int x) -{ +int bar(int x) +{ int res = 2; if(x) res = 1; - return res; + return res; } void main() diff --git a/regression/termination/ite4/main.c b/regression/termination/ite4/main.c index fd030a9a5..cd12c0013 100644 --- a/regression/termination/ite4/main.c +++ b/regression/termination/ite4/main.c @@ -1,13 +1,13 @@ -int foo(int x) -{ +int foo(int x) +{ int res; if(x) return 0; else return 1; } -int bar(int x) -{ +int bar(int x) +{ int res; if(x) res = 0; else res = 1; diff --git a/regression/termination/locks1/main.c b/regression/termination/locks1/main.c index 99ddf6417..4f76b0c20 100644 --- a/regression/termination/locks1/main.c +++ b/regression/termination/locks1/main.c @@ -10,7 +10,7 @@ int acquire_lock(char tid) return 0; } -void release_lock() +void release_lock() { lock = 0; } @@ -20,7 +20,7 @@ void thread1() if(acquire_lock(1)) { //do_stuff1(); - exit=1; + exit=1; release_lock(); } } diff --git a/regression/termination/locks2/main.c b/regression/termination/locks2/main.c index 5d2948237..789f0d094 100644 --- a/regression/termination/locks2/main.c +++ b/regression/termination/locks2/main.c @@ -10,7 +10,7 @@ int acquire_lock(char tid) return 0; } -void release_lock() +void release_lock() { lock = 0; } @@ -20,7 +20,7 @@ void thread1() if(acquire_lock(1)) { //do_stuff1(); - exit=1; + exit=1; //release_lock(); } } diff --git a/regression/termination/loop1/main.c b/regression/termination/loop1/main.c index 6750175ea..6c0d1f808 100644 --- a/regression/termination/loop1/main.c +++ b/regression/termination/loop1/main.c @@ -1,6 +1,6 @@ void main() { - int x = 0; + int x = 0; while(x<10) { diff --git a/regression/termination/loop2/main.c b/regression/termination/loop2/main.c index e67632a94..dd5d9c810 100644 --- a/regression/termination/loop2/main.c +++ b/regression/termination/loop2/main.c @@ -1,7 +1,7 @@ void main() { - int x = 0; + int x = 0; int y = 0; while(x<10) diff --git a/regression/termination/loop3/main.c b/regression/termination/loop3/main.c index 21a30e139..6ddb8924c 100644 --- a/regression/termination/loop3/main.c +++ b/regression/termination/loop3/main.c @@ -4,13 +4,13 @@ void main() int y; x=0; y=0; - + while(x<10 && y<20) { ++x; ++y; } - + int z=x+y; assert(z>=0); diff --git a/regression/termination/loop5/main.c b/regression/termination/loop5/main.c index f301dde9d..2fd0a019f 100644 --- a/regression/termination/loop5/main.c +++ b/regression/termination/loop5/main.c @@ -1,6 +1,6 @@ void main() { - unsigned x = 0; + unsigned x = 0; while(x<10) ++x; diff --git a/regression/termination/loop6/main.c b/regression/termination/loop6/main.c index 2c4213934..c7bd862fe 100644 --- a/regression/termination/loop6/main.c +++ b/regression/termination/loop6/main.c @@ -4,13 +4,13 @@ void main() { int x = 0; unsigned y = 0; - + while(x<10 && y<20) { ++x; ++y; } - + int z=x+y; assert(z<=20); } diff --git a/regression/termination/loop7/main.c b/regression/termination/loop7/main.c index 3c7dea455..1707acb1d 100644 --- a/regression/termination/loop7/main.c +++ b/regression/termination/loop7/main.c @@ -1,6 +1,6 @@ void main() { - int x; + int x; unsigned y; x = -10; y = 10; diff --git a/regression/termination/loop9/main.c b/regression/termination/loop9/main.c index ca602a19a..201463c41 100644 --- a/regression/termination/loop9/main.c +++ b/regression/termination/loop9/main.c @@ -1,6 +1,6 @@ void main() { - int x = 10; + int x = 10; while(x>0) { diff --git a/regression/termination/loops/array_false.c b/regression/termination/loops/array_false.c index 8e391d4b1..eeb8a1f76 100644 --- a/regression/termination/loops/array_false.c +++ b/regression/termination/loops/array_false.c @@ -11,16 +11,16 @@ main() unsigned int SIZE=1; unsigned int j,k; int array[SIZE], menor; - + menor = __VERIFIER_nondet_int(); for(j=0;jmenor); + menor = array[j]; + } + + __VERIFIER_assert(array[0]>menor); } diff --git a/regression/termination/loops/array_true.c b/regression/termination/loops/array_true.c index e40b4725c..7cb2de419 100644 --- a/regression/termination/loops/array_true.c +++ b/regression/termination/loops/array_true.c @@ -11,16 +11,16 @@ main() unsigned int SIZE=1; unsigned int j,k; int array[SIZE], menor; - + menor = __VERIFIER_nondet_int(); for(j=0;j=menor); + menor = array[j]; + } + + __VERIFIER_assert(array[0]>=menor); } diff --git a/regression/termination/loops/bubble_sort_false.c b/regression/termination/loops/bubble_sort_false.c index fa4558983..603a86c21 100644 --- a/regression/termination/loops/bubble_sort_false.c +++ b/regression/termination/loops/bubble_sort_false.c @@ -24,8 +24,8 @@ extern __attribute__((__nothrow__, __noreturn__)) void abort(void) ; #line 5 "test-0180.c" extern int __VERIFIER_nondet_int(void); #line 7 "test-0180.c" -static void fail(void) -{ +static void fail(void) +{ { ERROR: assert(0); @@ -35,7 +35,7 @@ static void fail(void) #line 39 "test-0180.c" struct list_head gl_list = {& gl_list, & gl_list}; #line 41 "test-0180.c" -static void inspect(struct list_head const *head ) +static void inspect(struct list_head const *head ) { struct node const *node ; unsigned int __cil_tmp3 ; struct list_head *__cil_tmp4 ; @@ -744,7 +744,7 @@ static void inspect(struct list_head const *head ) } } #line 74 "test-0180.c" -__inline static void __list_add(struct list_head *new , struct list_head *prev , struct list_head *next ) +__inline static void __list_add(struct list_head *new , struct list_head *prev , struct list_head *next ) { unsigned int __cil_tmp4 ; unsigned int __cil_tmp5 ; unsigned int __cil_tmp6 ; @@ -772,7 +772,7 @@ __inline static void __list_add(struct list_head *new , struct list_head *prev , } } #line 84 "test-0180.c" -__inline static void __list_del(struct list_head *prev , struct list_head *next ) +__inline static void __list_del(struct list_head *prev , struct list_head *next ) { unsigned int __cil_tmp3 ; unsigned int __cil_tmp4 ; @@ -790,7 +790,7 @@ __inline static void __list_del(struct list_head *prev , struct list_head *next } } #line 90 "test-0180.c" -__inline static void list_add(struct list_head *new , struct list_head *head ) +__inline static void list_add(struct list_head *new , struct list_head *head ) { struct list_head *__cil_tmp3 ; { @@ -805,7 +805,7 @@ __inline static void list_add(struct list_head *new , struct list_head *head ) } } #line 95 "test-0180.c" -__inline static void list_move(struct list_head *list , struct list_head *head ) +__inline static void list_move(struct list_head *list , struct list_head *head ) { unsigned int __cil_tmp3 ; unsigned int __cil_tmp4 ; struct list_head *__cil_tmp5 ; @@ -831,7 +831,7 @@ __inline static void list_move(struct list_head *list , struct list_head *head ) } } #line 101 "test-0180.c" -static void gl_insert(int value ) +static void gl_insert(int value ) { struct node *node ; void *tmp ; unsigned int __cil_tmp4 ; @@ -910,7 +910,7 @@ static void gl_insert(int value ) } } #line 112 "test-0180.c" -static void gl_read(void) +static void gl_read(void) { int tmp ; int tmp___0 ; @@ -941,7 +941,7 @@ static void gl_read(void) } } #line 120 "test-0180.c" -static void gl_destroy(void) +static void gl_destroy(void) { struct list_head *next ; struct list_head *__cil_tmp2 ; unsigned int __cil_tmp3 ; @@ -1012,7 +1012,7 @@ static void gl_destroy(void) } } #line 129 "test-0180.c" -static int val_from_node(struct list_head *head ) +static int val_from_node(struct list_head *head ) { struct node *entry ; struct node *__cil_tmp3 ; unsigned int __cil_tmp4 ; @@ -1044,7 +1044,7 @@ static int val_from_node(struct list_head *head ) } } #line 134 "test-0180.c" -static _Bool gl_sort_pass(void) +static _Bool gl_sort_pass(void) { _Bool any_change ; struct list_head *pos0 ; struct list_head *pos1 ; @@ -1113,7 +1113,7 @@ static _Bool gl_sort_pass(void) } } #line 156 "test-0180.c" -static void gl_sort(void) +static void gl_sort(void) { _Bool tmp ; { @@ -1139,7 +1139,7 @@ static void gl_sort(void) } } #line 162 "test-0180.c" -int main(void) +int main(void) { struct list_head const *__cil_tmp1 ; struct list_head const *__cil_tmp2 ; diff --git a/regression/termination/loops/eureka_01_false.c b/regression/termination/loops/eureka_01_false.c index 87e5d9f0e..61c73651c 100644 --- a/regression/termination/loops/eureka_01_false.c +++ b/regression/termination/loops/eureka_01_false.c @@ -18,7 +18,7 @@ void main(){ int distance[5]; int x,y; int i,j; - + for(i = 0; i < nodecount; i++){ if(i == source){ distance[i] = 0; diff --git a/regression/termination/loops/eureka_01_true.c b/regression/termination/loops/eureka_01_true.c index 2f67ad9fe..1d519eeda 100644 --- a/regression/termination/loops/eureka_01_true.c +++ b/regression/termination/loops/eureka_01_true.c @@ -16,7 +16,7 @@ int main(){ int distance[5]; int x,y; int i,j; - + for(i = 0; i < nodecount; i++){ if(i == source){ distance[i] = 0; diff --git a/regression/termination/loops/eureka_05_true.c b/regression/termination/loops/eureka_05_true.c index 5345b95f1..ec315384c 100644 --- a/regression/termination/loops/eureka_05_true.c +++ b/regression/termination/loops/eureka_05_true.c @@ -16,7 +16,7 @@ void SelectionSort() for (lh = 0; lh < n; lh++) { rh = lh; - for (i = lh + 1; i < n; i++) + for (i = lh + 1; i < n; i++) if (array[i] < array[rh]) rh = i; temp = array[lh]; array[lh] = array[rh]; diff --git a/regression/termination/loops/insertion_sort_false.c b/regression/termination/loops/insertion_sort_false.c index e11e4d208..8efc0cb0d 100644 --- a/regression/termination/loops/insertion_sort_false.c +++ b/regression/termination/loops/insertion_sort_false.c @@ -8,8 +8,8 @@ unsigned int __VERIFIER_nondet_uint(); int main() { unsigned int SIZE=__VERIFIER_nondet_uint(); int i, j, k, key; - int v[SIZE]; - for (j=1;j=0) && (v[i]>key)) { @@ -17,9 +17,9 @@ int main() { v[i+1] = v[i]; i = i - 1; } - v[i+1] = key; - } + v[i+1] = key; + } for (k=1;k=0) && (v[i]>key)) { v[i+1] = v[i]; i = i - 1; } - v[i+1] = key; - } + v[i+1] = key; + } for (k=1;k= 0; i--) { str2[j] = str1[0]; j++; diff --git a/regression/termination/loops/invert_string_true.c b/regression/termination/loops/invert_string_true.c index cb62c80f5..14d7e1864 100644 --- a/regression/termination/loops/invert_string_true.c +++ b/regression/termination/loops/invert_string_true.c @@ -18,7 +18,7 @@ int main() { str1[max-1]= '\0'; j = 0; - + for (i = max - 1; i >= 0; i--) { str2[j] = str1[i]; j++; @@ -28,6 +28,6 @@ int main() { for (i=0; imaior) - maior = matriz[j][k]; - } - + maior = matriz[j][k]; + } + for(j=0;j=maior) - maior = matriz[j][k]; - } - - __VERIFIER_assert(matriz[0][0]<=maior); + maior = matriz[j][k]; + } + + __VERIFIER_assert(matriz[0][0]<=maior); } diff --git a/regression/termination/loops/n.c11_true.c b/regression/termination/loops/n.c11_true.c index 90df007e5..7fa8a09e6 100644 --- a/regression/termination/loops/n.c11_true.c +++ b/regression/termination/loops/n.c11_true.c @@ -15,10 +15,10 @@ int main(){ while(__VERIFIER_nondet_bool()){ - + if (len==4) len =0; - + a[len]=0; len++; @@ -26,6 +26,6 @@ int main(){ __VERIFIER_assert(len>=0 && len<5); return 1; - + } diff --git a/regression/termination/loops/n.c24_true.c b/regression/termination/loops/n.c24_true.c index 6aa4889c4..8d5fb6f16 100644 --- a/regression/termination/loops/n.c24_true.c +++ b/regression/termination/loops/n.c24_true.c @@ -23,7 +23,7 @@ int main(){ for (i = 0; i < 1000; ++i) x[i]= __VERIFIER_nondet_int(); - + for (i= 0; i < 1000; ++i){ ret = __VERIFIER_nondet_int(); @@ -32,50 +32,50 @@ int main(){ tmp_cnt = __VERIFIER_nondet_int(); if (tmp_cnt < 0) return -1; - - + + for ( offset = 0; offset < tmp_cnt; offset++ ) { ret = foo(&tel_data ) ; if ( ( ret == 0 ) || ( ret == 1 ) ) { - + return 1 ; } else if ( ret == -1 ) { - + continue ; } - + for ( j = 0; x[j] != 0; j++ ) { - + if ( x[i] == 1) { - + memmove( &x[i], &x[i + 1], (1001) - ( i + 1 ) ) ; } } - + ret = bar( x) ; - + if ( ret != -1 ) { - + continue ; } - + klen = strlen(x ) ; - + if ( klen > 20 ) { - + x[i]=0; - + } else if ( klen > 0 ) { diff --git a/regression/termination/loops/n.c40_true.c b/regression/termination/loops/n.c40_true.c index 51401c6c1..482b5ba07 100644 --- a/regression/termination/loops/n.c40_true.c +++ b/regression/termination/loops/n.c40_true.c @@ -3,16 +3,16 @@ int __VERIFIER_nondet_int(); char x[100], y[100]; int i,j,k; -void main() { +void main() { k = __VERIFIER_nondet_int(); - + i = 0; while(x[i] != 0){ y[i] = x[i]; i++; } y[i] = 0; - + if(k >= 0 && k < i) if(y[k] == 0) {ERROR: goto ERROR;} diff --git a/regression/termination/loops/nec11_false.c b/regression/termination/loops/nec11_false.c index 839657cb3..cdc6710a6 100644 --- a/regression/termination/loops/nec11_false.c +++ b/regression/termination/loops/nec11_false.c @@ -15,10 +15,10 @@ int main(){ while(c){ - + if (len==4) len =0; - + a[len]=0; len++; @@ -26,5 +26,5 @@ int main(){ __VERIFIER_assert(len==5); return 1; - + } diff --git a/regression/termination/loops/nec20_false.c b/regression/termination/loops/nec20_false.c index 2558467f4..dacfb5f99 100644 --- a/regression/termination/loops/nec20_false.c +++ b/regression/termination/loops/nec20_false.c @@ -10,7 +10,7 @@ int main(){ _Bool k=__VERIFIER_nondet_bool(); int i,n,j; int a[1025]; - + if (k){ n=0; } else { @@ -32,7 +32,7 @@ int main(){ a[b]=1; else a[b%1023] =1; - + return 1; - + } diff --git a/regression/termination/loops/nec40_true.c b/regression/termination/loops/nec40_true.c index d113517f0..13f7d086e 100644 --- a/regression/termination/loops/nec40_true.c +++ b/regression/termination/loops/nec40_true.c @@ -9,16 +9,16 @@ int __VERIFIER_nondet_int(); char x[100], y[100]; int i,j,k; -void main() { +void main() { k = __VERIFIER_nondet_int(); - + i = 0; while(x[i] != 0){ y[i] = x[i]; i++; } y[i] = 0; - + if(k >= 0 && k < i) if(y[k] != 0) {__VERIFIER_assert(0);} diff --git a/regression/termination/loops/string_false.c b/regression/termination/loops/string_false.c index ec8a43f07..5e30e6305 100644 --- a/regression/termination/loops/string_false.c +++ b/regression/termination/loops/string_false.c @@ -14,14 +14,14 @@ main() { char string_A[MAX], string_B[MAX]; int i, j, nc_A, nc_B, found=0; - - + + for(i=0; i= nc_A); - - + + i=j=0; while((inc_B-1)<= nc_A); - - + + i=j=0; while((inc_B-1); - + __VERIFIER_assert(found == 0 || found == 1); } diff --git a/regression/termination/loops/sum01_bug02_false.c b/regression/termination/loops/sum01_bug02_false.c index 1f98f5e30..bcdd3b7a2 100644 --- a/regression/termination/loops/sum01_bug02_false.c +++ b/regression/termination/loops/sum01_bug02_false.c @@ -6,10 +6,10 @@ void __VERIFIER_assert(int cond) { } #define a (2) extern unsigned int __VERIFIER_nondet_uint(); -int main() { +int main() { int i, j=10, n=__VERIFIER_nondet_uint(), sn=0; for(i=1; i<=n; i++) { - if (i=100 || z<=100); } diff --git a/regression/termination/loops/terminator_03_false.c b/regression/termination/loops/terminator_03_false.c index 6554eb44b..3d44d6e58 100644 --- a/regression/termination/loops/terminator_03_false.c +++ b/regression/termination/loops/terminator_03_false.c @@ -13,12 +13,12 @@ main() if (y>0) { - while(x<100) + while(x<100) { x=x+y; } - } - __VERIFIER_assert(y<=0 || (y<0 && x>=100)); + } + __VERIFIER_assert(y<=0 || (y<0 && x>=100)); } diff --git a/regression/termination/loops/terminator_03_true.c b/regression/termination/loops/terminator_03_true.c index fcfa5948a..5f923a55b 100644 --- a/regression/termination/loops/terminator_03_true.c +++ b/regression/termination/loops/terminator_03_true.c @@ -14,13 +14,13 @@ main() if (y>0) { - while(x<100) + while(x<100) { x=x+y; } - } - - __VERIFIER_assert(y<=0 || (y>0 && x>=100)); + } + + __VERIFIER_assert(y<=0 || (y>0 && x>=100)); } diff --git a/regression/termination/loops/trex03_false.c b/regression/termination/loops/trex03_false.c index 3d540b049..bb1c139d4 100644 --- a/regression/termination/loops/trex03_false.c +++ b/regression/termination/loops/trex03_false.c @@ -14,7 +14,7 @@ int main() unsigned int x1=__VERIFIER_nondet_uint(), x2=__VERIFIER_nondet_uint(), x3=__VERIFIER_nondet_uint(); unsigned int d1=1, d2=1, d3=1; bool c1=__VERIFIER_nondet_bool(), c2=__VERIFIER_nondet_bool(); - + while(x1>0 && x2>0 && x3>0) { if (c1) x1=x1-d1; diff --git a/regression/termination/loops/trex03_true.c b/regression/termination/loops/trex03_true.c index ebdd7c14a..62bf91091 100644 --- a/regression/termination/loops/trex03_true.c +++ b/regression/termination/loops/trex03_true.c @@ -12,7 +12,7 @@ int main() unsigned int x1=__VERIFIER_nondet_uint(), x2=__VERIFIER_nondet_uint(), x3=__VERIFIER_nondet_uint(); unsigned int d1=1, d2=1, d3=1; _Bool c1=__VERIFIER_nondet_bool(), c2=__VERIFIER_nondet_bool(); - + while(x1>0 && x2>0 && x3>0) { if (c1) x1=x1-d1; diff --git a/regression/termination/loops/trex04_true.c b/regression/termination/loops/trex04_true.c index b0e1926e8..6dee2e188 100644 --- a/regression/termination/loops/trex04_true.c +++ b/regression/termination/loops/trex04_true.c @@ -29,7 +29,7 @@ int main() if (c1) foo(); if (c2) d = d - 1; - + while(x>0) { x=x-d; diff --git a/regression/termination/loops/veris.c_OpenSER__cases1_stripFullBoth_arr_true.c b/regression/termination/loops/veris.c_OpenSER__cases1_stripFullBoth_arr_true.c index 57033331f..e27f33c65 100644 --- a/regression/termination/loops/veris.c_OpenSER__cases1_stripFullBoth_arr_true.c +++ b/regression/termination/loops/veris.c_OpenSER__cases1_stripFullBoth_arr_true.c @@ -133,11 +133,11 @@ struct sockaddr_un -static int parse_expression_list(char *str) +static int parse_expression_list(char *str) { int start=0, i=-1, j=-1; char str2[EXPRESSION_LENGTH]; - + if (!str) return -1; do { @@ -177,7 +177,7 @@ static int parse_expression_list(char *str) start = i+1; } } while (str[i] != EOS); - + return 0; } diff --git a/regression/termination/loops/verisec_OpenSER__cases1_stripFullBoth_arr_false.c b/regression/termination/loops/verisec_OpenSER__cases1_stripFullBoth_arr_false.c index c1990a839..4609139d0 100644 --- a/regression/termination/loops/verisec_OpenSER__cases1_stripFullBoth_arr_false.c +++ b/regression/termination/loops/verisec_OpenSER__cases1_stripFullBoth_arr_false.c @@ -133,11 +133,11 @@ struct sockaddr_un -static int parse_expression_list(char *str) +static int parse_expression_list(char *str) { int start=0, i=-1, j=-1; char str2[EXPRESSION_LENGTH]; - + if (!str) return -1; do { @@ -175,7 +175,7 @@ static int parse_expression_list(char *str) start = i+1; } } while (str[i] != EOS); - + return 0; } diff --git a/regression/termination/loops/vogal_false.c b/regression/termination/loops/vogal_false.c index 006a9596f..6b8cfb03c 100644 --- a/regression/termination/loops/vogal_false.c +++ b/regression/termination/loops/vogal_false.c @@ -10,14 +10,14 @@ extern char __VERIFIER_nondet_char(); main(void) { - char string_entrada[MAX], vetor_vogais[]={'a','A','e','E','i','I','o','O','u','U','\0'};; + char string_entrada[MAX], vetor_vogais[]={'a','A','e','E','i','I','o','O','u','U','\0'};; unsigned int i,j,cont, tam_string, n_caracter; for(i=0;i0) { diff --git a/regression/termination/phase2/main.c b/regression/termination/phase2/main.c index 71187b9b3..069c660a0 100644 --- a/regression/termination/phase2/main.c +++ b/regression/termination/phase2/main.c @@ -1,8 +1,8 @@ void main() { - unsigned char x = 1; - unsigned char y = 1; - unsigned char w = 0; + unsigned char x = 1; + unsigned char y = 1; + unsigned char w = 0; while(x>0) //terminates after overflow of x // -w, -y, -x { diff --git a/regression/termination/phase3/main.c b/regression/termination/phase3/main.c index 0bba05b6d..67c31f21f 100644 --- a/regression/termination/phase3/main.c +++ b/regression/termination/phase3/main.c @@ -1,7 +1,7 @@ void main() { - unsigned char x = 1; - unsigned char y = 1; + unsigned char x = 1; + unsigned char y = 1; while(x>0) //does not terminate { diff --git a/regression/termination/phase4/main.c b/regression/termination/phase4/main.c index 6f3a905d8..f80f66a97 100644 --- a/regression/termination/phase4/main.c +++ b/regression/termination/phase4/main.c @@ -1,7 +1,7 @@ void main() { - unsigned char x = 1; - unsigned char y = 1; + unsigned char x = 1; + unsigned char y = 1; while(x>0) //does not terminate { diff --git a/regression/termination/phase5/main.c b/regression/termination/phase5/main.c index 603f6ff90..e74f5ff72 100644 --- a/regression/termination/phase5/main.c +++ b/regression/termination/phase5/main.c @@ -1,7 +1,7 @@ void main() { - int x = 1; - int y = 1; + int x = 1; + int y = 1; while(x>0) { diff --git a/regression/termination/phase6/main.c b/regression/termination/phase6/main.c index be3c469a8..938fe91f1 100644 --- a/regression/termination/phase6/main.c +++ b/regression/termination/phase6/main.c @@ -1,7 +1,7 @@ void main() { - int x = 1; - int y = 1; + int x = 1; + int y = 1; while(x>0) { diff --git a/regression/termination/phase7/debug.c b/regression/termination/phase7/debug.c index dab17127b..4c26f0e6c 100644 --- a/regression/termination/phase7/debug.c +++ b/regression/termination/phase7/debug.c @@ -20,11 +20,11 @@ void main() { /* __CPROVER_assume(y29 == 1 + yphi21); */ /* __CPROVER_assume(uphi29 == (cond27 && guard27 ? uphi21 : u28)); */ /* __CPROVER_assume(guard29 == (cond27 && guard27 || guard28)); */ - + // assert(!(guard21 && guardls30 && guard29 && cond30 && (-(long)ylb30 <= -(long)y29 || -(long)ulb30 < -(long)uphi29) && -(long)ulb30 <= -(long)uphi29)); //assert(!(guard21 && guardls30 && guard29 && cond30 && (-ylb30 <= -y29 || -ulb30 < -uphi29) && -ulb30 <= -uphi29)); - __CPROVER_bitvector[32] c0$1$0, c0$1$1, c0$1$2, c0$0$0, c0$0$1, c0$0$2; + __CPROVER_bitvector[32] c0$1$0, c0$1$1, c0$1$2, c0$0$0, c0$0$1, c0$0$2; /* assert(c0$1$0 * 4194304 + c0$1$1 * 2147483647 + c0$1$2 * -1656643584 > c0$1$0 * 4194303 + c0$1$1 * -2147483648 + c0$1$2 * -1656643583 || */ /* c0$0$0 * 4194304 + c0$0$1 * 2147483647 + c0$0$2 * -1656643584 > c0$0$0 * 4194303 + c0$0$1 * -2147483648 + c0$0$2 * -1656643583 && c0$1$0 * 4194304 + c0$1$1 * 2147483647 + c0$1$2 * -1656643584 >= c0$1$0 * 4194303 + c0$1$1 * -2147483648 + c0$1$2 * -1656643583); */ diff --git a/regression/termination/phase7/main.c b/regression/termination/phase7/main.c index 36e0c4de6..17f57a84b 100644 --- a/regression/termination/phase7/main.c +++ b/regression/termination/phase7/main.c @@ -2,8 +2,8 @@ void main() { - int x = 1; - int y = 1; + int x = 1; + int y = 1; int u = 0; while(x>0 && u < INT_MAX) //-u, -y, x diff --git a/regression/termination/phase7/main_verify.c b/regression/termination/phase7/main_verify.c index 0fdaf7e94..57a821083 100644 --- a/regression/termination/phase7/main_verify.c +++ b/regression/termination/phase7/main_verify.c @@ -2,8 +2,8 @@ void main() { - int x;// = 1; - int y;// = 1; + int x;// = 1; + int y;// = 1; int u;// = 0; assert(verify(x, y, u) != 0); @@ -34,8 +34,8 @@ int verify(int x, int y, int u) { //if(-u0 <= -u && (-u0 != -u || -y0 <= -y)) //if(-(long)u0+(long)x0 <= -(long)u+(long)x && (-(long)u0+(long)x0 != -(long)u+(long)x || ( -(long)u0-(long)x0 <= -(long)u-(long)x && (-(long)u0-(long)x0 != -(long)u-(long)x || (long)u0+(long)x0 <= (long)u+(long)x)))) //if((long)x0 <= (long)x && ((long)x0 != (long)x || -(long)u0-(long)x0 <= -(long)u-(long)x)) - // if(-(long)u0+(long)x0 <= -(long)u+(long)x && (-(long)u0+(long)x0 != -(long)u+(long)x || - // (-(long)u0-(long)x0 <= -(long)u-(long)x && (-(long)u0-(long)x0 != -(long)u-(long)x || + // if(-(long)u0+(long)x0 <= -(long)u+(long)x && (-(long)u0+(long)x0 != -(long)u+(long)x || + // (-(long)u0-(long)x0 <= -(long)u-(long)x && (-(long)u0-(long)x0 != -(long)u-(long)x || // (long)u0+(long)x0 <= (long)u+(long)x)))) return 0; } diff --git a/regression/termination/phase8/debug.c b/regression/termination/phase8/debug.c index dab17127b..4c26f0e6c 100644 --- a/regression/termination/phase8/debug.c +++ b/regression/termination/phase8/debug.c @@ -20,11 +20,11 @@ void main() { /* __CPROVER_assume(y29 == 1 + yphi21); */ /* __CPROVER_assume(uphi29 == (cond27 && guard27 ? uphi21 : u28)); */ /* __CPROVER_assume(guard29 == (cond27 && guard27 || guard28)); */ - + // assert(!(guard21 && guardls30 && guard29 && cond30 && (-(long)ylb30 <= -(long)y29 || -(long)ulb30 < -(long)uphi29) && -(long)ulb30 <= -(long)uphi29)); //assert(!(guard21 && guardls30 && guard29 && cond30 && (-ylb30 <= -y29 || -ulb30 < -uphi29) && -ulb30 <= -uphi29)); - __CPROVER_bitvector[32] c0$1$0, c0$1$1, c0$1$2, c0$0$0, c0$0$1, c0$0$2; + __CPROVER_bitvector[32] c0$1$0, c0$1$1, c0$1$2, c0$0$0, c0$0$1, c0$0$2; /* assert(c0$1$0 * 4194304 + c0$1$1 * 2147483647 + c0$1$2 * -1656643584 > c0$1$0 * 4194303 + c0$1$1 * -2147483648 + c0$1$2 * -1656643583 || */ /* c0$0$0 * 4194304 + c0$0$1 * 2147483647 + c0$0$2 * -1656643584 > c0$0$0 * 4194303 + c0$0$1 * -2147483648 + c0$0$2 * -1656643583 && c0$1$0 * 4194304 + c0$1$1 * 2147483647 + c0$1$2 * -1656643584 >= c0$1$0 * 4194303 + c0$1$1 * -2147483648 + c0$1$2 * -1656643583); */ diff --git a/regression/termination/phase8/main.c b/regression/termination/phase8/main.c index 26b7587d8..39fac0a35 100644 --- a/regression/termination/phase8/main.c +++ b/regression/termination/phase8/main.c @@ -2,11 +2,11 @@ void main() { - int x = 1; - int y = 1; + int x = 1; + int y = 1; int u = 0; int w = 0; - + while(x>0 && w0) { diff --git a/regression/termination/pointer1/main.c b/regression/termination/pointer1/main.c index 34c87bb31..da5aa119a 100644 --- a/regression/termination/pointer1/main.c +++ b/regression/termination/pointer1/main.c @@ -1,5 +1,5 @@ -void foo(int *x) -{ +void foo(int *x) +{ *x = 10; } diff --git a/regression/termination/pointer2/main.c b/regression/termination/pointer2/main.c index 02f54b869..318e03ee5 100644 --- a/regression/termination/pointer2/main.c +++ b/regression/termination/pointer2/main.c @@ -1,5 +1,5 @@ -void foo(int *x) -{ +void foo(int *x) +{ x++; *x = 10; } diff --git a/regression/termination/precond_term4/main.c b/regression/termination/precond_term4/main.c index ff0e4f92e..70fbe40c6 100644 --- a/regression/termination/precond_term4/main.c +++ b/regression/termination/precond_term4/main.c @@ -16,9 +16,9 @@ signed long int full_write(signed int fd, const void *buf, unsigned long int len void main() { - signed int fd; + signed int fd; char buf[256]; - unsigned long int len; + unsigned long int len; signed long int cc; full_write(fd,buf,len,cc); } diff --git a/regression/termination/refinement1/main.c b/regression/termination/refinement1/main.c index 8b5cf8474..da4da16df 100644 --- a/regression/termination/refinement1/main.c +++ b/regression/termination/refinement1/main.c @@ -1,7 +1,7 @@ void main() { - int x = 10; - int y = 0; + int x = 10; + int y = 0; while(x>2*y) { diff --git a/regression/termination/refinement2/main.c b/regression/termination/refinement2/main.c index ccdcfb657..f4b7f0407 100644 --- a/regression/termination/refinement2/main.c +++ b/regression/termination/refinement2/main.c @@ -1,7 +1,7 @@ void main() { - int x = 10; - int y = 0; + int x = 10; + int y = 0; while(x>y) { diff --git a/regression/termination/refinement3/main.c b/regression/termination/refinement3/main.c index 8b5cf8474..da4da16df 100644 --- a/regression/termination/refinement3/main.c +++ b/regression/termination/refinement3/main.c @@ -1,7 +1,7 @@ void main() { - int x = 10; - int y = 0; + int x = 10; + int y = 0; while(x>2*y) { diff --git a/regression/termination/runall.sh b/regression/termination/runall.sh index dd85b93a6..14e5d0498 100755 --- a/regression/termination/runall.sh +++ b/regression/termination/runall.sh @@ -12,8 +12,8 @@ do do cd $d rm -f ../$d.$o.log - for f in *.c - do + for f in *.c + do echo $d/$f "using" $o echo "FILE:" $f >> ../$d.$o.log (time (perl -e 'alarm shift @ARGV; exec @ARGV' $TIMEOUT $SUMMARIZER $CHECKS $f --$o)) &>> ../$d.$o.log diff --git a/regression/termination/running1/main.c b/regression/termination/running1/main.c index 7345364ba..e4e9fcdac 100644 --- a/regression/termination/running1/main.c +++ b/regression/termination/running1/main.c @@ -1,12 +1,12 @@ -/* +/* C version of the lapack library http://www.netlib.org/clapack/cblas/sasum.c - + run with - + ../../../src/summarizer/summarizer main.c --termination --context-sensitive - + */ int nondet_int(); @@ -22,7 +22,7 @@ int main() { int n =nondet_int(), incx=nondet_int(); - + __CPROVER_assume(incx > 0 && incx < 1000); __CPROVER_assume(n < 1000 && n > 0); diff --git a/regression/termination/running2/main.c b/regression/termination/running2/main.c index cc4656778..6ec3b7437 100644 --- a/regression/termination/running2/main.c +++ b/regression/termination/running2/main.c @@ -1,12 +1,12 @@ -/* +/* C version of the lapack library http://www.netlib.org/clapack/cblas/sasum.c - + run with - + ../../../src/summarizer/summarizer main.c --termination --context-sensitive - + */ int nondet_int(); @@ -31,8 +31,8 @@ int g(int n, int incx) int main() { int n = nondet_int(), incx = nondet_int(); - + g(n,incx); - + return 0; } diff --git a/regression/termination/running3/main.c b/regression/termination/running3/main.c index 5fba32973..85b6c59cb 100644 --- a/regression/termination/running3/main.c +++ b/regression/termination/running3/main.c @@ -1,32 +1,32 @@ -/* +/* C version of the lapack library http://www.netlib.org/clapack/cblas/sasum.c - + run with - + ../../../src/summarizer/summarizer main.c --termination --context-sensitive - + */ int nondet_int(); -int foo(int *sx, int n, int incx) -{ +int foo(int *sx, int n, int incx) +{ int nincx = n * incx; int stemp=0; int i; - for (i=0; incx < 0 ? i >= nincx : i <= nincx; i += incx) - { + for (i=0; incx < 0 ? i >= nincx : i <= nincx; i += incx) + { stemp += sx[i-1]; } return stemp; } -int bar(int n, int incx) +int bar(int n, int incx) { int sx[n]; - if(100 <= n && n <= 10000 && 0 < incx && incx <= 1000) + if(100 <= n && n <= 10000 && 0 < incx && incx <= 1000) { int stemp = foo(&sx, n, incx); } @@ -35,6 +35,6 @@ int bar(int n, int incx) int main() { - int n = nondet_int(), incx = nondet_int(); + int n = nondet_int(), incx = nondet_int(); bar(n,incx); } diff --git a/regression/termination/running4/main.c b/regression/termination/running4/main.c index ffb76a47c..2bd727165 100644 --- a/regression/termination/running4/main.c +++ b/regression/termination/running4/main.c @@ -1,32 +1,32 @@ -/* +/* C version of the lapack library http://www.netlib.org/clapack/cblas/sasum.c - + run with - + ../../../src/summarizer/summarizer main.c --termination --context-sensitive - + */ int nondet_int(); -int foo(int *sx, int n, int incx) -{ +int foo(int *sx, int n, int incx) +{ int nincx = n * incx; int stemp=0; int i; - for (i=0; incx < 0 ? i >= nincx : i <= nincx; i += incx) - { + for (i=0; incx < 0 ? i >= nincx : i <= nincx; i += incx) + { stemp += sx[i-1]; } return stemp; } -int bar(int n, int incx) +int bar(int n, int incx) { int sx[n]; - if(100 <= n && n <= 10000 && 0 <= incx && incx <= 1000) + if(100 <= n && n <= 10000 && 0 <= incx && incx <= 1000) { int stemp = foo(&sx, n, incx); } @@ -35,6 +35,6 @@ int bar(int n, int incx) int main() { - int n = nondet_int(), incx = nondet_int(); + int n = nondet_int(), incx = nondet_int(); bar(n,incx); } diff --git a/regression/termination/simple1/main.c b/regression/termination/simple1/main.c index 8a95214f7..0b9154bec 100644 --- a/regression/termination/simple1/main.c +++ b/regression/termination/simple1/main.c @@ -1,10 +1,10 @@ -int foo() -{ +int foo() +{ return 1; } -int bar() -{ - return 2; +int bar() +{ + return 2; } void main() diff --git a/regression/termination/simple2/main.c b/regression/termination/simple2/main.c index e1f62b82d..984b32921 100644 --- a/regression/termination/simple2/main.c +++ b/regression/termination/simple2/main.c @@ -1,5 +1,5 @@ -int foo(int x) -{ +int foo(int x) +{ if(x) return 9; return 10; } diff --git a/regression/termination/sum1/main.c b/regression/termination/sum1/main.c index df354feeb..c6f4ab383 100644 --- a/regression/termination/sum1/main.c +++ b/regression/termination/sum1/main.c @@ -1,27 +1,27 @@ -#include - -int max(int x, int y) -{ - if(x>y) return x; - return y; -} - -int inv(int x) -{ - __CPROVER_assume(x>INT_MIN); //would not be needed if we did not extend the bitvector sizes - return -x; -} - -void main() -{ - int x; - __CPROVER_assume(2<=x && x<=3); - - int y=inv(x); - int z=max(y,0); - - assert(y<=-2); - assert(y==-x); - assert(z>=0); - assert(z>=y); -} +#include + +int max(int x, int y) +{ + if(x>y) return x; + return y; +} + +int inv(int x) +{ + __CPROVER_assume(x>INT_MIN); //would not be needed if we did not extend the bitvector sizes + return -x; +} + +void main() +{ + int x; + __CPROVER_assume(2<=x && x<=3); + + int y=inv(x); + int z=max(y,0); + + assert(y<=-2); + assert(y==-x); + assert(z>=0); + assert(z>=y); +} From b7bc0469122b65a0feff6b66f5105bdc09a4d008 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Thu, 20 Jul 2017 15:47:56 +0100 Subject: [PATCH 003/322] BMC option --- src/2ls/2ls_parse_options.cpp | 249 +++++++++++++++++-------------- src/2ls/2ls_parse_options.h | 2 +- src/2ls/cover_goals_ext.h | 3 +- src/2ls/summary_checker_base.cpp | 12 +- src/2ls/summary_checker_bmc.cpp | 7 +- 5 files changed, 153 insertions(+), 120 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index b1363d104..3426fbd14 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -141,7 +141,15 @@ void twols_parse_optionst::get_command_line_options(optionst &options) options.set_option("unwindset", cmdline.get_value("unwindset")); if(cmdline.isset("unwind")) + { options.set_option("unwind", cmdline.get_value("unwind")); + options.set_option("unwind-min", cmdline.get_value("unwind")); + } + else + { + options.set_option("unwind", 0); + options.set_option("unwind-min", 0); + } if(cmdline.isset("inline-partial")) options.set_option("inline-partial", cmdline.get_value("inline-partial")); @@ -263,7 +271,9 @@ void twols_parse_optionst::get_command_line_options(optionst &options) options.set_option("k-induction", true); options.set_option("inline", true); if(!cmdline.isset("unwind")) - options.set_option("unwind", UINT_MAX); + options.set_option("unwind", std::numeric_limits::max()); + else + options.set_option("unwind-min", 0); } // do incremental bmc @@ -273,7 +283,19 @@ void twols_parse_optionst::get_command_line_options(optionst &options) options.set_option("inline", true); options.set_option("havoc", true); if(!cmdline.isset("unwind")) - options.set_option("unwind", UINT_MAX); + options.set_option("unwind", std::numeric_limits::max()); + else + options.set_option("unwind-min", 0); + } + + // do bmc + if(cmdline.isset("bmc")) + { + options.set_option("bmc", true); + options.set_option("inline", true); + options.set_option("havoc", true); + if(!cmdline.isset("unwind")) + throw "--bmc only possible with --unwind"; } // check for spuriousness of assertion failures @@ -343,153 +365,156 @@ Function: twols_parse_optionst::doit int twols_parse_optionst::doit() { - if(cmdline.isset("version")) + try { - std::cout << TWOLS_VERSION << std::endl; - return 0; - } + if(cmdline.isset("version")) + { + std::cout << TWOLS_VERSION << std::endl; + return 0; + } - // - // command line options - // + // + // command line options + // - optionst options; - get_command_line_options(options); + optionst options; + get_command_line_options(options); - eval_verbosity(); + eval_verbosity(); - // - // Print a banner - // - status() << "2LS version " TWOLS_VERSION " (based on CBMC " CBMC_VERSION ")" - << eom; + // + // Print a banner + // + status() << "2LS version " TWOLS_VERSION " (based on CBMC " CBMC_VERSION ")" + << eom; - goto_modelt goto_model; + goto_modelt goto_model; - register_languages(); + register_languages(); - if(get_goto_program(options, goto_model)) - return 6; + if(get_goto_program(options, goto_model)) + return 6; - if(cmdline.isset("show-stats")) - { - show_stats(goto_model, std::cout); - return 7; - } + if(cmdline.isset("show-stats")) + { + show_stats(goto_model, std::cout); + return 7; + } - // options for various debug outputs + // options for various debug outputs - if(cmdline.isset("show-ssa")) - { - bool simplify=!cmdline.isset("no-simplify"); - irep_idt function=cmdline.get_value("function"); - show_ssa(goto_model, function, simplify, std::cout, ui_message_handler); - return 7; - } + if(cmdline.isset("show-ssa")) + { + bool simplify=!cmdline.isset("no-simplify"); + irep_idt function=cmdline.get_value("function"); + show_ssa(goto_model, function, simplify, std::cout, ui_message_handler); + return 7; + } - if(cmdline.isset("show-defs")) - { - irep_idt function=cmdline.get_value("function"); - show_defs(goto_model, function, std::cout, ui_message_handler); - return 7; - } + if(cmdline.isset("show-defs")) + { + irep_idt function=cmdline.get_value("function"); + show_defs(goto_model, function, std::cout, ui_message_handler); + return 7; + } - if(cmdline.isset("show-assignments")) - { - irep_idt function=cmdline.get_value("function"); - show_assignments(goto_model, function, std::cout, ui_message_handler); - return 7; - } + if(cmdline.isset("show-assignments")) + { + irep_idt function=cmdline.get_value("function"); + show_assignments(goto_model, function, std::cout, ui_message_handler); + return 7; + } - if(cmdline.isset("show-guards")) - { - irep_idt function=cmdline.get_value("function"); - show_guards(goto_model, function, std::cout, ui_message_handler); - return 7; - } + if(cmdline.isset("show-guards")) + { + irep_idt function=cmdline.get_value("function"); + show_guards(goto_model, function, std::cout, ui_message_handler); + return 7; + } - if(cmdline.isset("show-value-sets")) - { - irep_idt function=cmdline.get_value("function"); - show_value_sets(goto_model, function, std::cout, ui_message_handler); - return 7; - } + if(cmdline.isset("show-value-sets")) + { + irep_idt function=cmdline.get_value("function"); + show_value_sets(goto_model, function, std::cout, ui_message_handler); + return 7; + } - if(cmdline.isset("show-invariants")) - { - options.set_option("show-invariants", true); - } + if(cmdline.isset("show-invariants")) + { + options.set_option("show-invariants", true); + } #if IGNORE_RECURSION - if(recursion_detected) - { - status() << "Recursion not supported" << eom; - report_unknown(); - return 5; - } + if(recursion_detected) + { + status() << "Recursion not supported" << eom; + report_unknown(); + return 5; + } #endif #if IGNORE_THREADS - if(threads_detected) - { - status() << "Threads not supported" << eom; - report_unknown(); - return 5; - } + if(threads_detected) + { + status() << "Threads not supported" << eom; + report_unknown(); + return 5; + } #endif - if(cmdline.isset("context-sensitive")) - { - options.set_option("context-sensitive", true); - status() << "Context-sensitive analysis from " << - goto_model.goto_functions.entry_point() << eom; - } + if(cmdline.isset("context-sensitive")) + { + options.set_option("context-sensitive", true); + status() << "Context-sensitive analysis from " << + goto_model.goto_functions.entry_point() << eom; + } - if(cmdline.isset("arrays")) - { - options.set_option("arrays", true); - status() << "Do not ignore array contents" << eom; - } + if(cmdline.isset("arrays")) + { + options.set_option("arrays", true); + status() << "Do not ignore array contents" << eom; + } - // TODO: check option inconsistencies, ignored options etc - if(options.get_bool_option("havoc")) - status() << "Havocking loops and function calls" << eom; - else if(options.get_bool_option("equalities")) - status() << "Using (dis)equalities domain" << eom; - else - { - if(options.get_bool_option("intervals")) - status() << "Using intervals domain"; - else if(options.get_bool_option("zones")) - status() << "Using zones domain"; - else if(options.get_bool_option("octagons")) - status() << "Using octagons domain"; + // TODO: check option inconsistencies, ignored options etc + if(options.get_bool_option("havoc")) + status() << "Havocking loops and function calls" << eom; + else if(options.get_bool_option("equalities")) + status() << "Using (dis)equalities domain" << eom; else - assert(false); + { + if(options.get_bool_option("intervals")) + status() << "Using intervals domain"; + else if(options.get_bool_option("zones")) + status() << "Using zones domain"; + else if(options.get_bool_option("octagons")) + status() << "Using octagons domain"; + else + assert(false); - if(options.get_bool_option("enum-solver")) - status() << " with enumeration solver"; - else if(options.get_bool_option("binsearch-solver")) - status() << " with binary search solver"; - else - assert(false); + if(options.get_bool_option("enum-solver")) + status() << " with enumeration solver"; + else if(options.get_bool_option("binsearch-solver")) + status() << " with binary search solver"; + else + assert(false); - status() << eom; - } + status() << eom; + } - try - { std::unique_ptr checker; if(!options.get_bool_option("k-induction") && - !options.get_bool_option("incremental-bmc")) + !options.get_bool_option("incremental-bmc") && + !options.get_bool_option("bmc")) checker=std::unique_ptr( new summary_checker_ait(options)); if(options.get_bool_option("k-induction") && - !options.get_bool_option("incremental-bmc")) + !options.get_bool_option("incremental-bmc") && + !options.get_bool_option("bmc")) checker=std::unique_ptr( new summary_checker_kindt(options)); if(!options.get_bool_option("k-induction") && - options.get_bool_option("incremental-bmc")) + (options.get_bool_option("incremental-bmc") || + options.get_bool_option("bmc"))) checker=std::unique_ptr( new summary_checker_bmct(options)); diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index d564b1279..b332b216a 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -48,7 +48,7 @@ class optionst; "(show-locs)(show-vcc)(show-properties)(show-trace)(show-stats)" \ "(show-goto-functions)(show-guards)(show-defs)(show-ssa)(show-assignments)" \ "(show-invariants)(std-invariants)" \ - "(property):(all-properties)(k-induction)(incremental-bmc)" \ + "(property):(all-properties)(k-induction)(incremental-bmc)(bmc)" \ "(no-spurious-check)(all-functions)" \ "(no-simplify)(no-fixed-point)" \ "(graphml-witness):(json-cex):" \ diff --git a/src/2ls/cover_goals_ext.h b/src/2ls/cover_goals_ext.h index d777a8a66..a0e9fb3c1 100644 --- a/src/2ls/cover_goals_ext.h +++ b/src/2ls/cover_goals_ext.h @@ -52,7 +52,8 @@ class cover_goals_extt:public messaget incremental_solvert &_solver, const exprt::operandst& _loophead_selects, property_checkert::property_mapt &_property_map, - bool _spurious_check, bool _all_properties, + bool _spurious_check, + bool _all_properties, bool _build_error_trace): SSA(_SSA), solver(_solver), diff --git a/src/2ls/summary_checker_base.cpp b/src/2ls/summary_checker_base.cpp index c910b184c..4ff792162 100644 --- a/src/2ls/summary_checker_base.cpp +++ b/src/2ls/summary_checker_base.cpp @@ -243,10 +243,13 @@ void summary_checker_baset::check_properties( is_fully_unwound(loop_continues, loophead_selects, solver); status() << "Loops " << (fully_unwound ? "" : "not ") << "fully unwound" << eom; - + + bool require_spurious_check= + !fully_unwound && options.get_bool_option("spurious-check"); + cover_goals_extt cover_goals( SSA, solver, loophead_selects, property_map, - !fully_unwound && options.get_bool_option("spurious-check"), + require_spurious_check, all_properties, options.get_bool_option("show-trace") || options.get_option("graphml-witness")!="" || @@ -330,7 +333,10 @@ void summary_checker_baset::check_properties( // set all non-covered goals to PASS except if we do not try // to cover all goals and we have found a FAIL - if(all_properties || cover_goals.number_covered()==0) + if(all_properties && + (fully_unwound || + (!options.get_bool_option("bmc") && + !options.get_bool_option("incremental-bmc")))) { std::list::const_iterator g_it= cover_goals.goals.begin(); diff --git a/src/2ls/summary_checker_bmc.cpp b/src/2ls/summary_checker_bmc.cpp index 38e9e925e..afa1ffd0b 100644 --- a/src/2ls/summary_checker_bmc.cpp +++ b/src/2ls/summary_checker_bmc.cpp @@ -31,11 +31,12 @@ property_checkert::resultt summary_checker_bmct::operator()( ssa_unwinder.init(false, true); property_checkert::resultt result=property_checkert::UNKNOWN; + unsigned min_unwind=options.get_unsigned_int_option("unwind-min"); unsigned max_unwind=options.get_unsigned_int_option("unwind"); status() << "Max-unwind is " << max_unwind << eom; ssa_unwinder.init_localunwinders(); - for(unsigned unwind=0; unwind<=max_unwind; unwind++) + for(unsigned unwind=min_unwind; unwind<=max_unwind; unwind++) { status() << "Unwinding (k=" << unwind << ")" << messaget::eom; summary_db.mark_recompute_all(); @@ -43,13 +44,13 @@ property_checkert::resultt summary_checker_bmct::operator()( result=check_properties(); if(result==property_checkert::PASS) { - status() << "incremental BMC proof found after " + status() << "BMC proof found after " << unwind << " unwinding(s)" << messaget::eom; break; } else if(result==property_checkert::FAIL) { - status() << "incremental BMC counterexample found after " + status() << "BMC counterexample found after " << unwind << " unwinding(s)" << messaget::eom; break; } From aac26ff96b14c2963a4faeed874d447479101afd Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Tue, 25 Jul 2017 14:20:43 +0200 Subject: [PATCH 004/322] Rename --show-trace to --trace --- src/2ls/2ls_parse_options.cpp | 7 ++++--- src/2ls/2ls_parse_options.h | 2 +- src/2ls/summary_checker_base.cpp | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 3426fbd14..d6ca3731e 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -343,8 +343,8 @@ void twols_parse_optionst::get_command_line_options(optionst &options) } #endif - if(cmdline.isset("show-trace")) - options.set_option("show-trace", true); + if(cmdline.isset("trace")) + options.set_option("trace", true); if(cmdline.isset("graphml-witness")) options.set_option("graphml-witness", cmdline.get_value("graphml-witness")); if(cmdline.isset("json-cex")) @@ -1241,7 +1241,7 @@ void twols_parse_optionst::report_properties( << eom; } - if(cmdline.isset("show-trace") && + if(cmdline.isset("trace") && it->second.result==property_checkert::FAIL) show_counterexample(goto_model, it->second.error_trace); if(cmdline.isset("json-cex") && @@ -1604,6 +1604,7 @@ void twols_parse_optionst::help() "Backend options:\n" " --all-functions check each function as entry point\n" " --stop-on-fail stop on first failing assertion\n" + " --trace give a counterexample trace for failed properties\n" //NOLINT(*) " --context-sensitive context-sensitive analysis from entry point\n" // NOLINT(*) " --termination compute ranking functions to prove termination\n" // NOLINT(*) " --k-induction use k-induction\n" diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index b332b216a..80eae0b4e 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -45,7 +45,7 @@ class optionst; "(lexicographic-ranking-function):(monolithic-ranking-function)" \ "(max-inner-ranking-iterations):" \ "(preconditions)(sufficient)" \ - "(show-locs)(show-vcc)(show-properties)(show-trace)(show-stats)" \ + "(show-locs)(show-vcc)(show-properties)(trace)(show-stats)" \ "(show-goto-functions)(show-guards)(show-defs)(show-ssa)(show-assignments)" \ "(show-invariants)(std-invariants)" \ "(property):(all-properties)(k-induction)(incremental-bmc)(bmc)" \ diff --git a/src/2ls/summary_checker_base.cpp b/src/2ls/summary_checker_base.cpp index 4ff792162..4915111d4 100644 --- a/src/2ls/summary_checker_base.cpp +++ b/src/2ls/summary_checker_base.cpp @@ -251,7 +251,7 @@ void summary_checker_baset::check_properties( SSA, solver, loophead_selects, property_map, require_spurious_check, all_properties, - options.get_bool_option("show-trace") || + options.get_bool_option("trace") || options.get_option("graphml-witness")!="" || options.get_option("json-cex")!=""); From 905cde1836948edddd209773a17e78ee4ace93df Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sun, 29 Oct 2017 12:28:51 +0000 Subject: [PATCH 005/322] Remove --bmc option --- src/2ls/2ls_parse_options.cpp | 249 ++++++++++++++----------------- src/2ls/2ls_parse_options.h | 2 +- src/2ls/summary_checker_base.cpp | 12 +- src/2ls/summary_checker_bmc.cpp | 7 +- 4 files changed, 119 insertions(+), 151 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index d6ca3731e..8859ea604 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -141,15 +141,7 @@ void twols_parse_optionst::get_command_line_options(optionst &options) options.set_option("unwindset", cmdline.get_value("unwindset")); if(cmdline.isset("unwind")) - { options.set_option("unwind", cmdline.get_value("unwind")); - options.set_option("unwind-min", cmdline.get_value("unwind")); - } - else - { - options.set_option("unwind", 0); - options.set_option("unwind-min", 0); - } if(cmdline.isset("inline-partial")) options.set_option("inline-partial", cmdline.get_value("inline-partial")); @@ -271,9 +263,7 @@ void twols_parse_optionst::get_command_line_options(optionst &options) options.set_option("k-induction", true); options.set_option("inline", true); if(!cmdline.isset("unwind")) - options.set_option("unwind", std::numeric_limits::max()); - else - options.set_option("unwind-min", 0); + options.set_option("unwind", UINT_MAX); } // do incremental bmc @@ -283,19 +273,7 @@ void twols_parse_optionst::get_command_line_options(optionst &options) options.set_option("inline", true); options.set_option("havoc", true); if(!cmdline.isset("unwind")) - options.set_option("unwind", std::numeric_limits::max()); - else - options.set_option("unwind-min", 0); - } - - // do bmc - if(cmdline.isset("bmc")) - { - options.set_option("bmc", true); - options.set_option("inline", true); - options.set_option("havoc", true); - if(!cmdline.isset("unwind")) - throw "--bmc only possible with --unwind"; + options.set_option("unwind", UINT_MAX); } // check for spuriousness of assertion failures @@ -365,156 +343,153 @@ Function: twols_parse_optionst::doit int twols_parse_optionst::doit() { - try + if(cmdline.isset("version")) { - if(cmdline.isset("version")) - { - std::cout << TWOLS_VERSION << std::endl; - return 0; - } + std::cout << TWOLS_VERSION << std::endl; + return 0; + } - // - // command line options - // + // + // command line options + // - optionst options; - get_command_line_options(options); + optionst options; + get_command_line_options(options); - eval_verbosity(); + eval_verbosity(); - // - // Print a banner - // - status() << "2LS version " TWOLS_VERSION " (based on CBMC " CBMC_VERSION ")" - << eom; + // + // Print a banner + // + status() << "2LS version " TWOLS_VERSION " (based on CBMC " CBMC_VERSION ")" + << eom; - goto_modelt goto_model; + goto_modelt goto_model; - register_languages(); + register_languages(); - if(get_goto_program(options, goto_model)) - return 6; + if(get_goto_program(options, goto_model)) + return 6; - if(cmdline.isset("show-stats")) - { - show_stats(goto_model, std::cout); - return 7; - } + if(cmdline.isset("show-stats")) + { + show_stats(goto_model, std::cout); + return 7; + } - // options for various debug outputs + // options for various debug outputs - if(cmdline.isset("show-ssa")) - { - bool simplify=!cmdline.isset("no-simplify"); - irep_idt function=cmdline.get_value("function"); - show_ssa(goto_model, function, simplify, std::cout, ui_message_handler); - return 7; - } + if(cmdline.isset("show-ssa")) + { + bool simplify=!cmdline.isset("no-simplify"); + irep_idt function=cmdline.get_value("function"); + show_ssa(goto_model, function, simplify, std::cout, ui_message_handler); + return 7; + } - if(cmdline.isset("show-defs")) - { - irep_idt function=cmdline.get_value("function"); - show_defs(goto_model, function, std::cout, ui_message_handler); - return 7; - } + if(cmdline.isset("show-defs")) + { + irep_idt function=cmdline.get_value("function"); + show_defs(goto_model, function, std::cout, ui_message_handler); + return 7; + } - if(cmdline.isset("show-assignments")) - { - irep_idt function=cmdline.get_value("function"); - show_assignments(goto_model, function, std::cout, ui_message_handler); - return 7; - } + if(cmdline.isset("show-assignments")) + { + irep_idt function=cmdline.get_value("function"); + show_assignments(goto_model, function, std::cout, ui_message_handler); + return 7; + } - if(cmdline.isset("show-guards")) - { - irep_idt function=cmdline.get_value("function"); - show_guards(goto_model, function, std::cout, ui_message_handler); - return 7; - } + if(cmdline.isset("show-guards")) + { + irep_idt function=cmdline.get_value("function"); + show_guards(goto_model, function, std::cout, ui_message_handler); + return 7; + } - if(cmdline.isset("show-value-sets")) - { - irep_idt function=cmdline.get_value("function"); - show_value_sets(goto_model, function, std::cout, ui_message_handler); - return 7; - } + if(cmdline.isset("show-value-sets")) + { + irep_idt function=cmdline.get_value("function"); + show_value_sets(goto_model, function, std::cout, ui_message_handler); + return 7; + } - if(cmdline.isset("show-invariants")) - { - options.set_option("show-invariants", true); - } + if(cmdline.isset("show-invariants")) + { + options.set_option("show-invariants", true); + } #if IGNORE_RECURSION - if(recursion_detected) - { - status() << "Recursion not supported" << eom; - report_unknown(); - return 5; - } + if(recursion_detected) + { + status() << "Recursion not supported" << eom; + report_unknown(); + return 5; + } #endif #if IGNORE_THREADS - if(threads_detected) - { - status() << "Threads not supported" << eom; - report_unknown(); - return 5; - } + if(threads_detected) + { + status() << "Threads not supported" << eom; + report_unknown(); + return 5; + } #endif - if(cmdline.isset("context-sensitive")) - { - options.set_option("context-sensitive", true); - status() << "Context-sensitive analysis from " << - goto_model.goto_functions.entry_point() << eom; - } + if(cmdline.isset("context-sensitive")) + { + options.set_option("context-sensitive", true); + status() << "Context-sensitive analysis from " << + goto_model.goto_functions.entry_point() << eom; + } - if(cmdline.isset("arrays")) - { - options.set_option("arrays", true); - status() << "Do not ignore array contents" << eom; - } + if(cmdline.isset("arrays")) + { + options.set_option("arrays", true); + status() << "Do not ignore array contents" << eom; + } - // TODO: check option inconsistencies, ignored options etc - if(options.get_bool_option("havoc")) - status() << "Havocking loops and function calls" << eom; - else if(options.get_bool_option("equalities")) - status() << "Using (dis)equalities domain" << eom; + // TODO: check option inconsistencies, ignored options etc + if(options.get_bool_option("havoc")) + status() << "Havocking loops and function calls" << eom; + else if(options.get_bool_option("equalities")) + status() << "Using (dis)equalities domain" << eom; + else + { + if(options.get_bool_option("intervals")) + status() << "Using intervals domain"; + else if(options.get_bool_option("zones")) + status() << "Using zones domain"; + else if(options.get_bool_option("octagons")) + status() << "Using octagons domain"; else - { - if(options.get_bool_option("intervals")) - status() << "Using intervals domain"; - else if(options.get_bool_option("zones")) - status() << "Using zones domain"; - else if(options.get_bool_option("octagons")) - status() << "Using octagons domain"; - else - assert(false); + assert(false); - if(options.get_bool_option("enum-solver")) - status() << " with enumeration solver"; - else if(options.get_bool_option("binsearch-solver")) - status() << " with binary search solver"; - else - assert(false); + if(options.get_bool_option("enum-solver")) + status() << " with enumeration solver"; + else if(options.get_bool_option("binsearch-solver")) + status() << " with binary search solver"; + else + assert(false); - status() << eom; - } + status() << eom; + } + try + { std::unique_ptr checker; if(!options.get_bool_option("k-induction") && - !options.get_bool_option("incremental-bmc") && - !options.get_bool_option("bmc")) + !options.get_bool_option("incremental-bmc")) checker=std::unique_ptr( new summary_checker_ait(options)); if(options.get_bool_option("k-induction") && - !options.get_bool_option("incremental-bmc") && - !options.get_bool_option("bmc")) + !options.get_bool_option("incremental-bmc")) checker=std::unique_ptr( new summary_checker_kindt(options)); if(!options.get_bool_option("k-induction") && - (options.get_bool_option("incremental-bmc") || - options.get_bool_option("bmc"))) + options.get_bool_option("incremental-bmc")) checker=std::unique_ptr( new summary_checker_bmct(options)); diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index 80eae0b4e..0a42e12f9 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -48,7 +48,7 @@ class optionst; "(show-locs)(show-vcc)(show-properties)(trace)(show-stats)" \ "(show-goto-functions)(show-guards)(show-defs)(show-ssa)(show-assignments)" \ "(show-invariants)(std-invariants)" \ - "(property):(all-properties)(k-induction)(incremental-bmc)(bmc)" \ + "(property):(all-properties)(k-induction)(incremental-bmc)" \ "(no-spurious-check)(all-functions)" \ "(no-simplify)(no-fixed-point)" \ "(graphml-witness):(json-cex):" \ diff --git a/src/2ls/summary_checker_base.cpp b/src/2ls/summary_checker_base.cpp index 4915111d4..0274201e4 100644 --- a/src/2ls/summary_checker_base.cpp +++ b/src/2ls/summary_checker_base.cpp @@ -243,13 +243,10 @@ void summary_checker_baset::check_properties( is_fully_unwound(loop_continues, loophead_selects, solver); status() << "Loops " << (fully_unwound ? "" : "not ") << "fully unwound" << eom; - - bool require_spurious_check= - !fully_unwound && options.get_bool_option("spurious-check"); - + cover_goals_extt cover_goals( SSA, solver, loophead_selects, property_map, - require_spurious_check, + !fully_unwound && options.get_bool_option("spurious-check"), all_properties, options.get_bool_option("trace") || options.get_option("graphml-witness")!="" || @@ -333,10 +330,7 @@ void summary_checker_baset::check_properties( // set all non-covered goals to PASS except if we do not try // to cover all goals and we have found a FAIL - if(all_properties && - (fully_unwound || - (!options.get_bool_option("bmc") && - !options.get_bool_option("incremental-bmc")))) + if(all_properties || cover_goals.number_covered()==0) { std::list::const_iterator g_it= cover_goals.goals.begin(); diff --git a/src/2ls/summary_checker_bmc.cpp b/src/2ls/summary_checker_bmc.cpp index afa1ffd0b..38e9e925e 100644 --- a/src/2ls/summary_checker_bmc.cpp +++ b/src/2ls/summary_checker_bmc.cpp @@ -31,12 +31,11 @@ property_checkert::resultt summary_checker_bmct::operator()( ssa_unwinder.init(false, true); property_checkert::resultt result=property_checkert::UNKNOWN; - unsigned min_unwind=options.get_unsigned_int_option("unwind-min"); unsigned max_unwind=options.get_unsigned_int_option("unwind"); status() << "Max-unwind is " << max_unwind << eom; ssa_unwinder.init_localunwinders(); - for(unsigned unwind=min_unwind; unwind<=max_unwind; unwind++) + for(unsigned unwind=0; unwind<=max_unwind; unwind++) { status() << "Unwinding (k=" << unwind << ")" << messaget::eom; summary_db.mark_recompute_all(); @@ -44,13 +43,13 @@ property_checkert::resultt summary_checker_bmct::operator()( result=check_properties(); if(result==property_checkert::PASS) { - status() << "BMC proof found after " + status() << "incremental BMC proof found after " << unwind << " unwinding(s)" << messaget::eom; break; } else if(result==property_checkert::FAIL) { - status() << "BMC counterexample found after " + status() << "incremental BMC counterexample found after " << unwind << " unwinding(s)" << messaget::eom; break; } From 4edea2dd2cc32e27e1af3833dcad20ab44928572 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sat, 4 Nov 2017 17:10:04 +0000 Subject: [PATCH 006/322] Improve Readme file --- README.md | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index aa46ece57..5b9e4c352 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ About ===== -2LS is a verification tool for C programs. It is built upon the +2LS ("tools") is a verification tool for C programs. It is built upon the CPROVER framework ([cprover.org](http://www.cprover.org)), which supports C89, C99, most of C11 and most compiler extensions provided by gcc and Visual Studio. It allows verifying array bounds (buffer @@ -11,7 +11,6 @@ overflows), pointer safety, exceptions, user-specified assertions, and termination properties. The analysis is performed by template-based predicate synthesis and abstraction refinements techniques. -For more information see [cprover.org](http://www.cprover.org/2LS). License ======= @@ -19,3 +18,115 @@ License [build_img]: https://travis-ci.org/diffblue/2ls.svg?branch=master [travis]: https://travis-ci.org/diffblue/2ls + + +Overview +======== + + 2LS reduces program analysis problems expressed in second order logic + such as invariant or ranking function inference to synthesis problems + over templates. Hence, it reduces (an existential fragment of) 2nd + order Logic Solving to quantifier elimination in first order logic. + +The current tool has following capabilities: + +* function-modular interprocedural analysis of C code based on summaries +* summary and invariant inference using generic templates +* combined k-induction and invariant inference +* function-modular termination analysis + +Releases +======== + +Download using `git clone http://github.com/diffblue/2ls; cd 2ls; git checkout 2ls-x.y` + +* [2LS 0.5](http://github.com/diffblue/2ls/releases/tag/2ls-0.5) (01/2017) +* [2LS 0.4](http://github.com/diffblue/2ls/releases/tag/2ls-0.4) (08/2016) +* [2LS 0.3](http://svn.cprover.org/svn/deltacheck/releases/2ls-0.3) (08/2015) +* [2LS 0.2](http://svn.cprover.org/svn/deltacheck/releases/2ls-0.2) (06/2015) +* [2LS 0.1](http://svn.cprover.org/svn/deltacheck/releases/2ls-0.1) (11/2014) + +Software Verification Competition Contributions + +* [SV-COMP 2017](http://github.com/diffblue/2ls/releases/tag/2ls-0.5-sv-comp-2017) (01/2017) +* [SV-COMP 2016](http://svn.cprover.org/svn/deltacheck/releases/2ls-0.3-sv-comp-2016) (11/2015) [Follow these instructions](http://www.cprover.org/2LS/2ls-sv-comp-2016.pdf) + +Installation +============ + +`cd 2ls; ./install.h` + + Run `src/2ls/2ls` + +Command line options +==================== + +The default abstract domain are intervals. If no options are given a context-insensitive interprocedural analysis is performed. For context-sensitivity, add --context-sensitive. + +Other analyses include: + +* BMC: --inline --havoc --unwind n +* Incremental BMC: --incremental-bmc +* Incremental k-induction: --havoc --k-induction +* Incremental k-induction and k-invariants (kIkI): --k-induction +* Intraprocedural abstract interpretation with property checks: --inline +* Necessary preconditions: --preconditions +* Sufficient preconditions: --preconditions --sufficient + +Currently the following abstract domains are available: + +* Intervals (default): --intervals +* Zones: --zones +* Octagons --octagons +* Equalities/disequalities: --equalities +* The abstract domain consisting of the Top element: --havoc + +Interprocedural Termination Analysis +==================================== + +Is supported by release 0.1 and >=0.3. + +* Universal termination: --termination +* Context-sensitive universal termination: --termination --context-sensitive +* Sufficient preconditions for termination --termination --context-sensitive --preconditions + +Features in development +======================= + +* ACDL solver (ATVA'17 [Lifting CDCL to Template-Based Abstract Domains for Program Verification](https://doi.org/10.1007/978-3-319-68167-2_2)) +* abstract heap domain +* nontermination analysis +* custom template specifications +* modular refinement +* template refinement +* thread-modular analysis + +Publications +============ + +* TACAS'16 [2LS for Program Analysis](http://dl.acm.org/citation.cfm?id=2945506) +* SAS'15 [Safety Verification and Refutation by k-Invariants and k-Induction](http://link.springer.com/chapter/10.1007%2F978-3-662-48288-9_9) +* ASE'15 [Synthesising Interprocedural Bit-Precise Termination Proofs](http://dl.acm.org/citation.cfm?id=2916211) [Experimental log](http://www.cs.ox.ac.uk/people/peter.schrammel/2ls/ase15-experimental_results_log.txt) [Additional material](http://www.cs.ox.ac.uk/people/peter.schrammel/2ls/ase15-additional-material.tgz) [Website](http://www.cprover.org/termination/modular) + +Contributors +============ + +* Björn Wachter +* Cristina David +* Daniel Kroening +* Hongyi Chen +* Madhukar Kumar +* Martin Brain +* Peter Schrammel +* Rajdeep Mukherjee +* Samuel Bücheli +* Saurabh Joshi +* Stefan Marticek +* Viktor Malik + +Contact +======= + +[Peter Schrammel](http://www.schrammel.it) + + From c92a3c1ac6fdba4d33c86132f3dc9fba31c534ea Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Fri, 3 Nov 2017 23:23:08 +0000 Subject: [PATCH 007/322] Add ssa_var_collector Author: Stefan Marticek --- src/ssa/Makefile | 2 +- src/ssa/ssa_var_collector.cpp | 245 ++++++++++++++++++++++++++++++++++ src/ssa/ssa_var_collector.h | 79 +++++++++++ 3 files changed, 325 insertions(+), 1 deletion(-) create mode 100644 src/ssa/ssa_var_collector.cpp create mode 100644 src/ssa/ssa_var_collector.h diff --git a/src/ssa/Makefile b/src/ssa/Makefile index 0c4c0263f..f66679938 100644 --- a/src/ssa/Makefile +++ b/src/ssa/Makefile @@ -1,4 +1,4 @@ -SRC = local_ssa.cpp \ +SRC = local_ssa.cpp ssa_var_collector.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 \ diff --git a/src/ssa/ssa_var_collector.cpp b/src/ssa/ssa_var_collector.cpp new file mode 100644 index 000000000..7bf67d28a --- /dev/null +++ b/src/ssa/ssa_var_collector.cpp @@ -0,0 +1,245 @@ +/*******************************************************************\ + +Module: Template Generator for Summaries, Invariants and Preconditions + +Author: Peter Schrammel, Stefan Marticek + +\*******************************************************************/ + +#include "ssa_var_collector.h" + +/*******************************************************************\ + +Function: template_generator_baset::add_var + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void ssa_var_collectort::add_var( + const domaint::vart &var, + const domaint::guardt &pre_guard, + domaint::guardt post_guard, + const domaint::kindt &kind, + domaint::var_specst &var_specs) +{ + exprt aux_expr=true_exprt(); + if(std_invariants && pre_guard.id()==ID_and) + { + exprt init_guard=and_exprt(pre_guard.op0(), not_exprt(pre_guard.op1())); + exprt post_var=post_renaming_map[var]; + exprt aux_var=aux_renaming_map[var]; + exprt aux_equals_post=equal_exprt(aux_var, post_var); + exprt aux_equals_init=equal_exprt(aux_var, init_renaming_map[var]); + aux_expr= + and_exprt( + implies_exprt( + and_exprt(post_guard, not_exprt(init_guard)), + aux_equals_post), + implies_exprt( + init_guard, + aux_equals_init)); + post_guard=or_exprt(post_guard, init_guard); + } + if(var.type().id()!=ID_array) + { + var_specs.push_back(domaint::var_spect()); + domaint::var_spect &var_spec=var_specs.back(); + var_spec.pre_guard=pre_guard; + var_spec.post_guard=post_guard; + var_spec.aux_expr=aux_expr; + var_spec.kind=kind; + var_spec.var=var; + } + + // arrays + if(var.type().id()==ID_array && options.get_bool_option("arrays")) + { + const array_typet &array_type=to_array_type(var.type()); + mp_integer size; + to_integer(array_type.size(), size); + for(mp_integer i=0; ilocation->location_number << std::endl; + assert(n_it->loophead!=SSA.nodes.end()); + std::cout << "pre-location: " + << n_it->loophead->location->location_number << std::endl; +#endif + exprt lhguard=SSA.guard_symbol(n_it->loophead->location); + ssa_local_unwinder.unwinder_rename(to_symbol_expr(lhguard), *n_it, true); + exprt lsguard= + SSA.name(SSA.guard_symbol(), local_SSAt::LOOP_SELECT, n_it->location); + ssa_local_unwinder.unwinder_rename(to_symbol_expr(lsguard), *n_it, true); + pre_guard=and_exprt(lhguard, lsguard); + + exprt pguard=SSA.guard_symbol(n_it->location); + ssa_local_unwinder.unwinder_rename(to_symbol_expr(pguard), *n_it, false); + exprt pcond=SSA.cond_symbol(n_it->location); + ssa_local_unwinder.unwinder_rename(to_symbol_expr(pcond), *n_it, false); + post_guard=and_exprt(pguard, pcond); +} + +/*******************************************************************\ + +Function: template_generator_baset::get_pre_var + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void ssa_var_collectort::get_pre_var( + const local_SSAt &SSA, + local_SSAt::objectst::const_iterator o_it, + local_SSAt::nodest::const_iterator n_it, + symbol_exprt &pre_var) +{ + pre_var=SSA.name(*o_it, local_SSAt::LOOP_BACK, n_it->location); + ssa_local_unwinder.unwinder_rename(pre_var, *n_it, true); + + symbol_exprt post_var=SSA.read_rhs(*o_it, n_it->location); + ssa_local_unwinder.unwinder_rename(post_var, *n_it, false); + post_renaming_map[pre_var]=post_var; + + rename_aux_post(post_var); + aux_renaming_map[pre_var]=post_var; +} + +/*******************************************************************\ + +Function: template_generator_baset::get_init_expr + + Inputs: + + Outputs: + + Purpose: supposes that loop head PHIs are of the form + xphi=gls?xlb:x0 + +\*******************************************************************/ + +void ssa_var_collectort::get_init_expr( + const local_SSAt &SSA, + local_SSAt::objectst::const_iterator o_it, + local_SSAt::nodest::const_iterator n_it, + exprt &init_expr) +{ + symbol_exprt phi_var= + SSA.name(*o_it, local_SSAt::PHI, n_it->loophead->location); + ssa_local_unwinder.unwinder_rename(phi_var, *n_it->loophead, true); + for(local_SSAt::nodet::equalitiest::const_iterator e_it= + n_it->loophead->equalities.begin(); + e_it!=n_it->loophead->equalities.end(); e_it++) + { + if(e_it->rhs().id()==ID_if && + to_symbol_expr(e_it->lhs()).get_identifier()==phi_var.get_identifier()) + { + const if_exprt &if_expr=to_if_expr(e_it->rhs()); + init_expr=if_expr.false_case(); + // should already be renamed for inner loops + break; + } + } + + symbol_exprt pre_var=SSA.name(*o_it, local_SSAt::LOOP_BACK, n_it->location); + ssa_local_unwinder.unwinder_rename(pre_var, *n_it, true); + init_renaming_map[pre_var]=init_expr; +} + +/*******************************************************************\ + +Function: ssa_var_collectort::collect_variables_loop + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void ssa_var_collectort::collect_variables_loop( + const local_SSAt &SSA, + bool forward) +{ + // used for renaming map + var_listt pre_state_vars, post_state_vars; + + // add loop variables + 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()) // we've found a loop + { + exprt pre_guard, post_guard; + get_pre_post_guards(SSA, n_it, pre_guard, post_guard); + + const ssa_domaint::phi_nodest &phi_nodes= + SSA.ssa_analysis[n_it->loophead->location].phi_nodes; + + // Record the objects modified by the loop to get + // 'primed' (post-state) and 'unprimed' (pre-state) variables. + for(local_SSAt::objectst::const_iterator + 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()); + + if(p_it==phi_nodes.end()) + continue; // object not modified in this loop + + symbol_exprt pre_var; + get_pre_var(SSA, o_it, n_it, pre_var); + exprt init_expr; + get_init_expr(SSA, o_it, n_it, init_expr); + add_var(pre_var, pre_guard, post_guard, domaint::LOOP, var_specs); + +#ifdef DEBUG + std::cout << "Adding " << from_expr(ns, "", in) << " " + << from_expr(ns, "", out) << std::endl; +#endif + } + } + } +} diff --git a/src/ssa/ssa_var_collector.h b/src/ssa/ssa_var_collector.h new file mode 100644 index 000000000..1c69981aa --- /dev/null +++ b/src/ssa/ssa_var_collector.h @@ -0,0 +1,79 @@ +/*******************************************************************\ + +Module: SSA var collector class + +Author: Peter Schrammel, Stefan Marticek + +\*******************************************************************/ + +#ifndef CPROVER_2LS_SSA_SSA_VAR_COLLECTOR_H +#define CPROVER_2LS_SSA_SSA_VAR_COLLECTOR_H + +#include + +#include "local_ssa.h" +#include "ssa_unwinder.h" + +#include + +class ssa_var_collectort +{ +public: + typedef strategy_solver_baset::var_listt var_listt; + + explicit ssa_var_collectort( + optionst &_options, + ssa_local_unwindert &_ssa_local_unwinder): + options(_options), + ssa_local_unwinder(_ssa_local_unwinder) + { + std_invariants=options.get_bool_option("std-invariants"); + } + + domaint::var_specst var_specs; + replace_mapt post_renaming_map; + replace_mapt init_renaming_map; + replace_mapt aux_renaming_map; + + optionst options; // copy: we may override options + + void add_var( + const domaint::vart &var_to_add, + const domaint::guardt &pre_guard, + domaint::guardt post_guard, + const domaint::kindt &kind, + domaint::var_specst &var_specs); + + void get_pre_post_guards( + const local_SSAt &SSA, + local_SSAt::nodest::const_iterator n_it, + exprt &pre_guard, + exprt &post_guard); + + void get_pre_var( + const local_SSAt &SSA, + local_SSAt::objectst::const_iterator o_it, + local_SSAt::nodest::const_iterator n_it, + symbol_exprt &pre_var); + + void get_init_expr( + const local_SSAt &SSA, + local_SSAt::objectst::const_iterator o_it, + local_SSAt::nodest::const_iterator n_it, + exprt &init_expr); + + void rename_aux_post(symbol_exprt &expr) + { + expr.set_identifier(id2string(expr.get_identifier())+"'"); + } + + virtual void collect_variables_loop( + const local_SSAt &SSA, + bool forward); + +protected: + bool std_invariants; // include value at loop entry + const ssa_local_unwindert &ssa_local_unwinder; +}; + +#endif // CPROVER_2LS_SSA_SSA_VAR_COLLECTOR_H From 983b87546a6a2effdc78f378113074683a32b7dd Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sat, 4 Nov 2017 14:44:05 +0000 Subject: [PATCH 008/322] Nontermination checker Author: Stefan Marticek --- src/2ls/2ls_parse_options.cpp | 43 +- src/2ls/2ls_parse_options.h | 2 +- src/2ls/Makefile | 2 +- src/2ls/summary_checker_ai.cpp | 7 +- src/2ls/summary_checker_base.h | 10 +- src/2ls/summary_checker_nonterm.cpp | 628 ++++++++++++++++++++++++++++ src/2ls/summary_checker_nonterm.h | 34 ++ src/ssa/ssa_build_goto_trace.cpp | 9 +- 8 files changed, 720 insertions(+), 15 deletions(-) create mode 100644 src/2ls/summary_checker_nonterm.cpp create mode 100644 src/2ls/summary_checker_nonterm.h diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 8859ea604..95900d778 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -51,6 +51,7 @@ Author: Daniel Kroening, Peter Schrammel #include "summary_checker_ai.h" #include "summary_checker_bmc.h" #include "summary_checker_kind.h" +#include "summary_checker_nonterm.h" #include "show.h" #include "horn_encoding.h" @@ -263,7 +264,16 @@ void twols_parse_optionst::get_command_line_options(optionst &options) options.set_option("k-induction", true); options.set_option("inline", true); if(!cmdline.isset("unwind")) - options.set_option("unwind", UINT_MAX); + options.set_option("unwind", std::numeric_limits::max()); + } + + // compute singleton recurrence set - simple nontermination + if(cmdline.isset("nontermination")) + { + options.set_option("nontermination", true); + options.set_option("inline", true); + if(!cmdline.isset("unwind")) + options.set_option("unwind", std::numeric_limits::max()); } // do incremental bmc @@ -273,7 +283,7 @@ void twols_parse_optionst::get_command_line_options(optionst &options) options.set_option("inline", true); options.set_option("havoc", true); if(!cmdline.isset("unwind")) - options.set_option("unwind", UINT_MAX); + options.set_option("unwind", std::numeric_limits::max()); } // check for spuriousness of assertion failures @@ -420,6 +430,20 @@ int twols_parse_optionst::doit() options.set_option("show-invariants", true); } + if(cmdline.isset("nontermination")) + { + // turn assertions (from generic checks) into assumptions + Forall_goto_functions(f_it, goto_model.goto_functions) + { + goto_programt &body=f_it->second.body; + Forall_goto_program_instructions(i_it, body) + { + if(i_it->is_assert()) + i_it->type=goto_program_instruction_typet::ASSUME; + } + } + } + #if IGNORE_RECURSION if(recursion_detected) { @@ -492,6 +516,9 @@ int twols_parse_optionst::doit() options.get_bool_option("incremental-bmc")) checker=std::unique_ptr( new summary_checker_bmct(options)); + if(options.get_bool_option("nontermination")) + checker=std::unique_ptr( + new summary_checker_nontermt(options)); checker->set_message_handler(get_message_handler()); checker->simplify=!cmdline.isset("no-simplify"); @@ -840,7 +867,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"; } /*******************************************************************\ @@ -1014,8 +1041,7 @@ bool twols_parse_optionst::process_goto_program( try { status() << "Function Pointer Removal" << eom; - remove_function_pointers( - goto_model, cmdline.isset("pointer-check")); + remove_function_pointers(goto_model, cmdline.isset("pointer-check")); // do partial inlining if(options.get_bool_option("inline-partial")) @@ -1047,7 +1073,9 @@ bool twols_parse_optionst::process_goto_program( status() << "Performing full inlining" << eom; const namespacet ns(goto_model.symbol_table); goto_inlinet goto_inline( - goto_model.goto_functions, ns, ui_message_handler); + goto_model.goto_functions, + ns, + ui_message_handler); goto_inline(); #if IGNORE_RECURSION recursion_detected=goto_inline.recursion_detected(); @@ -1204,7 +1232,8 @@ void twols_parse_optionst::report_properties( xmlt xml_result("result"); xml_result.set_attribute("property", id2string(it->first)); xml_result.set_attribute( - "status", property_checkert::as_string(it->second.result)); + "status", + property_checkert::as_string(it->second.result)); std::cout << xml_result << "\n"; } else diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index 0a42e12f9..342b79c21 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -41,7 +41,7 @@ class optionst; "(string-abstraction)(no-arch)(arch):(floatbv)(fixedbv)" \ "(round-to-nearest)(round-to-plus-inf)(round-to-minus-inf)(round-to-zero)" \ "(inline)(inline-main)(inline-partial):" \ - "(context-sensitive)(termination)" \ + "(context-sensitive)(termination)(nontermination)" \ "(lexicographic-ranking-function):(monolithic-ranking-function)" \ "(max-inner-ranking-iterations):" \ "(preconditions)(sufficient)" \ diff --git a/src/2ls/Makefile b/src/2ls/Makefile index 06b9d4486..5b9362169 100644 --- a/src/2ls/Makefile +++ b/src/2ls/Makefile @@ -6,7 +6,7 @@ SRC = 2ls_main.cpp 2ls_parse_options.cpp \ 2ls_languages.cpp \ show.cpp summary_checker_base.cpp \ summary_checker_ai.cpp summary_checker_bmc.cpp \ - summary_checker_kind.cpp \ + summary_checker_kind.cpp summary_checker_nonterm.cpp \ cover_goals_ext.cpp horn_encoding.cpp \ preprocessing_util.cpp \ instrument_goto.cpp dynamic_cfg.cpp \ diff --git a/src/2ls/summary_checker_ai.cpp b/src/2ls/summary_checker_ai.cpp index 6cda09787..d11a9c6d7 100644 --- a/src/2ls/summary_checker_ai.cpp +++ b/src/2ls/summary_checker_ai.cpp @@ -9,7 +9,7 @@ Author: Peter Schrammel #include "summary_checker_ai.h" #include -#define TERM_CEX 1 +#define TERM_CEX 0 /*******************************************************************\ @@ -174,7 +174,12 @@ property_checkert::resultt summary_checker_ait::report_termination() } } #endif +#if 1 return property_checkert::FAIL; +#else + // rely on nontermination checker to find counterexample + return property_checkert::UNKNOWN; +#endif } return property_checkert::UNKNOWN; } diff --git a/src/2ls/summary_checker_base.h b/src/2ls/summary_checker_base.h index d4b1ad0e5..2dfd88bb2 100644 --- a/src/2ls/summary_checker_base.h +++ b/src/2ls/summary_checker_base.h @@ -81,16 +81,20 @@ class summary_checker_baset:public property_checkert bool termination=false); property_checkert::resultt check_properties(); - void check_properties( + virtual 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 &); + 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 &); + const irep_idt &function_name, + const local_SSAt &, + prop_convt &); bool is_fully_unwound( const exprt::operandst& loop_continues, const exprt::operandst& loophead_selects, diff --git a/src/2ls/summary_checker_nonterm.cpp b/src/2ls/summary_checker_nonterm.cpp new file mode 100644 index 000000000..c8166a828 --- /dev/null +++ b/src/2ls/summary_checker_nonterm.cpp @@ -0,0 +1,628 @@ +/*******************************************************************\ + +Module: Summarizer for Nontermination Bit-level analysis + +Author: Stefan Marticek + +\*******************************************************************/ + +#include "summary_checker_nonterm.h" + +#include +#include +#include + +#include +#include <2ls/show.h> + +#include + +/*******************************************************************\ + +Function: summary_checker_nontermt::operator() + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +property_checkert::resultt summary_checker_nontermt::operator()( + const goto_modelt &goto_model) +{ + const namespacet ns(goto_model.symbol_table); + + SSA_functions(goto_model, ns); + + ssa_unwinder.init(false, true); + + property_checkert::resultt result=property_checkert::UNKNOWN; + unsigned max_unwind=options.get_unsigned_int_option("unwind"); + status() << "Max-unwind is " << max_unwind << eom; + ssa_unwinder.init_localunwinders(); + + for(unsigned unwind=1; unwind<=max_unwind; unwind++) + { + status() << "Unwinding (k=" << unwind << ")" << messaget::eom; + ssa_unwinder.unwind_all(unwind); + if(unwind==51) // use a different nontermination technique + { + result=check_nonterm_linear(); + if(result==property_checkert::PASS) + { + status() << "Termination proved after " + << unwind << " unwinding(s)" << messaget::eom; + report_statistics(); + return result; + } + else if(result==property_checkert::FAIL) + { + status() << "Nonterminating program execution proved after " + << unwind << " unwinding(s)" << messaget::eom; + report_statistics(); + return result; + } + } + result=summary_checker_baset::check_properties(); + if(result==property_checkert::PASS) + { + status() << "Termination proved after " + << unwind << " unwinding(s)" << messaget::eom; + break; + } + else if(result==property_checkert::FAIL) + { + status() << "Nonterminating program execution proved after " + << unwind << " unwinding(s)" << messaget::eom; + break; + } + } + + report_statistics(); + return result; +} + +/*******************************************************************\ + +Function: summary_checker_baset::check_properties + + Inputs: + + Outputs: + + Purpose: checks the property loop instead of assertion + +\*******************************************************************/ + +void summary_checker_nontermt::check_properties( + const ssa_dbt::functionst::const_iterator f_it) +{ + unwindable_local_SSAt &SSA=*f_it->second; + + ssa_local_unwindert &ssa_local_unwinder=ssa_unwinder.get(f_it->first); + +#if 0 + SSA.output_verbose(std::cout); +#endif + + // solver + incremental_solvert &solver=ssa_db.get_solver(f_it->first); + solver.set_message_handler(get_message_handler()); + + // give SSA to solver + solver << SSA; + SSA.mark_nodes(); + + solver.new_context(); + + // freeze loop head selects + exprt::operandst loophead_selects= + get_loophead_selects(f_it->first, SSA, *solver.solver); + + exprt enabling_expr=SSA.get_enabling_exprs(); + solver << enabling_expr; + + cover_goals_extt cover_goals( + SSA, + solver, + loophead_selects, + property_map, + false, + false, + options.get_bool_option("show-trace") || + options.get_option("graphml-witness")!="" || + options.get_option("json-cex")!=""); + + property_map.clear(); + + exprt::operandst ls_guards; + + 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()) // we've found a loop + { + irep_idt property_id= + irep_idt(n_it->loophead->location->location_number, 0); + + exprt lsguard= + SSA.name(SSA.guard_symbol(), local_SSAt::LOOP_SELECT, n_it->location); + ssa_local_unwinder.unwinder_rename(to_symbol_expr(lsguard), *n_it, true); + + const ssa_domaint::phi_nodest &phi_nodes= + SSA.ssa_analysis[n_it->loophead->location].phi_nodes; + + long store_unwinding=SSA.current_unwinding; + exprt::operandst loop_check_operands; + + symbol_exprt lhguard=SSA.guard_symbol(n_it->loophead->location); + ssa_local_unwinder.unwinder_rename(lhguard, *n_it, false); + + for(SSA.current_unwinding=1; + SSA.current_unwinding<=store_unwinding; + SSA.current_unwinding++) + { + exprt::operandst loop_vars; + loop_vars.push_back(lhguard); + + for(local_SSAt::objectst::const_iterator + 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()); + if(p_it==phi_nodes.end()) + continue; // object not modified in this loop + + symbol_exprt post_var= + SSA.name(*o_it, local_SSAt::PHI, n_it->loophead->location); + ssa_local_unwinder.unwinder_rename(post_var, *n_it->loophead, false); + + symbol_exprt phi_var; + phi_var=SSA.name(*o_it, local_SSAt::PHI, n_it->loophead->location); + ssa_local_unwinder.unwinder_rename(phi_var, *n_it->loophead, true); + loop_vars.push_back(equal_exprt(post_var, phi_var)); + } + + loop_check_operands.push_back(conjunction(loop_vars)); + } + SSA.current_unwinding=store_unwinding; + + property_map[property_id].location=n_it->loophead->location; + property_map[property_id].result=UNKNOWN; + cover_goals.goal_map[property_id].conjuncts.push_back( + disjunction(loop_check_operands)); + ls_guards.push_back(not_exprt(lsguard)); + } + } + + solver << conjunction(ls_guards); + + for(cover_goals_extt::goal_mapt::const_iterator + it=cover_goals.goal_map.begin(); + it!=cover_goals.goal_map.end(); + it++) + { + literalt p=solver.convert(disjunction(it->second.conjuncts)); + cover_goals.add(p); + } + + status() << "Running " << solver.solver->decision_procedure_text() << eom; + + cover_goals(); + + solver.pop_context(); + + std::cout << "** " << cover_goals.number_covered() + << " of " << cover_goals.size() << " failed (" + << cover_goals.iterations() << " iterations)" << eom; +} + +/*******************************************************************\ + +Function: summary_checker_baset::check_properties_linear + + Inputs: + + Outputs: + + Purpose: searching for periodical recurrence set + +\*******************************************************************/ + +void summary_checker_nontermt::check_properties_linear( + const ssa_dbt::functionst::const_iterator f_it) +{ + unwindable_local_SSAt &SSA=*f_it->second; + + ssa_local_unwindert &ssa_local_unwinder=ssa_unwinder.get(f_it->first); + + // solver + incremental_solvert &solver=ssa_db.get_solver(f_it->first); + solver.set_message_handler(get_message_handler()); + + // give SSA to solver + solver << SSA; + SSA.mark_nodes(); + + solver.new_context(); + + // freeze loop head selects + exprt::operandst loophead_selects= + get_loophead_selects(f_it->first, SSA, *solver.solver); + + exprt enabling_expr=SSA.get_enabling_exprs(); + solver << enabling_expr; + + property_map.clear(); + + exprt::operandst ls_guards; + 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()) // we've found a loop + { + exprt lsguard= + SSA.name(SSA.guard_symbol(), local_SSAt::LOOP_SELECT, n_it->location); + ssa_local_unwinder.unwinder_rename(to_symbol_expr(lsguard), *n_it, true); + ls_guards.push_back(lsguard); + } + } + + unsigned loop_counter=std::numeric_limits::max(); + 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()) // we've found a loop + { + // we use continues further, therefore we put incrementation here + loop_counter++; + + irep_idt property_id= + irep_idt(n_it->loophead->location->location_number, 0); + + const ssa_domaint::phi_nodest &phi_nodes= + SSA.ssa_analysis[n_it->loophead->location].phi_nodes; + + SSA.current_unwinding-=1; + symbol_exprt lhguard_second=SSA.guard_symbol(n_it->loophead->location); + ssa_local_unwinder.unwinder_rename(lhguard_second, *n_it, true); + SSA.current_unwinding+=1; + + symbol_exprt lhguard=SSA.guard_symbol(n_it->loophead->location); + ssa_local_unwinder.unwinder_rename(lhguard, *n_it, true); + + exprt::operandst first_linearity_check; + exprt::operandst second_linearity_check; + exprt::operandst constants_computation; + exprt::operandst constants; + exprt::operandst loopback_vars; + exprt::operandst loop_exit_cond; + exprt::operandst neg_loop_exit_cond; + + property_map[property_id].location=n_it->loophead->location; + property_map[property_id].result=UNKNOWN; + + unsigned const_number=0; + for(local_SSAt::objectst::const_iterator + 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()); + if(p_it==phi_nodes.end()) + continue; // object not modified in this loop + + // first linearity check data preparation + + SSA.current_unwinding-=1; + symbol_exprt phi_var1; + phi_var1=SSA.name(*o_it, local_SSAt::PHI, n_it->loophead->location); + ssa_local_unwinder.unwinder_rename(phi_var1, *n_it->loophead, true); + SSA.current_unwinding+=1; + symbol_exprt phi_var2; + phi_var2=SSA.name(*o_it, local_SSAt::PHI, n_it->loophead->location); + ssa_local_unwinder.unwinder_rename(phi_var2, *n_it->loophead, true); + + // works only for bitvectors + + if((phi_var2.type().id()!=ID_unsignedbv) && + (phi_var2.type().id()!=ID_signedbv)) + { + first_linearity_check.clear(); + break; + } + + // x_k = x_0 + C*k, const$k - k, const$i - C + symbol_exprt constk("const$k", phi_var2.type()); + symbol_exprt const1( + "const$"+std::to_string(const_number++), phi_var2.type()); + + first_linearity_check.push_back( + equal_exprt( + phi_var1, + plus_exprt( + phi_var2, + const1))); + + // get constants data preparation + + constants_computation.push_back( + equal_exprt( + minus_exprt(phi_var1, phi_var2), + const1)); + constants.push_back(const1); + + // loopback vars data preparation + + exprt init_expr; + exprt lb_var; + for(local_SSAt::nodet::equalitiest::const_iterator e_it= + n_it->loophead->equalities.begin(); + e_it!=n_it->loophead->equalities.end(); e_it++) + { + if(e_it->rhs().id()==ID_if && + to_symbol_expr(e_it->lhs()).get_identifier()== + phi_var2.get_identifier()) + { + const if_exprt &if_expr=to_if_expr(e_it->rhs()); + init_expr=if_expr.false_case(); + lb_var=if_expr.true_case(); + // should already be renamed for inner loops + break; + } + } + + loopback_vars.push_back(lb_var); + loopback_vars.push_back(init_expr); + loopback_vars.push_back(constk); + } + + if(first_linearity_check.empty()) // nothing to be checked + continue; + + neg_loop_exit_cond.push_back(lhguard); + neg_loop_exit_cond.push_back(not_exprt(lhguard_second)); + loop_exit_cond.push_back(lhguard); + + solver.new_context(); + solver << conjunction(first_linearity_check); + switch(solver()) + { + case decision_proceduret::D_UNSATISFIABLE: + solver.pop_context(); + continue; + + case decision_proceduret::D_SATISFIABLE: + for(exprt::operandst::iterator it=first_linearity_check.begin(); + it!=first_linearity_check.end(); + ++it) + { + exprt ex=solver.get(it->op1().op1()); + second_linearity_check.push_back( + and_exprt( + *it, + not_exprt(equal_exprt(to_constant_expr(ex), it->op1().op1())))); + } + + solver.pop_context(); + break; + + default: + error() << "decision procedure has failed" << eom; + solver.pop_context(); + solver.pop_context(); + return; + } + + solver.new_context(); + solver << disjunction(second_linearity_check); + switch(solver()) + { + case decision_proceduret::D_UNSATISFIABLE: + solver.pop_context(); + break; + + case decision_proceduret::D_SATISFIABLE: + solver.pop_context(); + continue; + + default: + error() << "decision procedure has failed" << eom; + solver.pop_context(); + solver.pop_context(); + return; + } + + // constants extraction + exprt::operandst solver_consts; + + solver.new_context(); + solver << conjunction(constants_computation); + switch(solver()) + { + case decision_proceduret::D_UNSATISFIABLE: // should never happen + solver.pop_context(); + solver.pop_context(); + return; + + case decision_proceduret::D_SATISFIABLE: + for(auto constant : constants) + { + exprt ex=solver.solver->get(constant); + if(ex.type().id()==ID_unsignedbv) + { + // if (constant>UINT_MAX/2)?0-constant:constant + constant_exprt cex=to_constant_expr(ex); + constant_exprt zero=constant_exprt("0", ex.type()); + constant_exprt cex2= + to_constant_expr(simplify_expr(minus_exprt(zero, cex), SSA.ns)); + if_exprt ifex=if_exprt( + binary_relation_exprt(cex, ID_gt, cex2), + cex2, + cex, + ex.type()); + ex=simplify_expr(ifex, SSA.ns); + } + solver_consts.push_back(to_constant_expr((ex))); + } + solver.pop_context(); + break; + + default: + error() << "decision procedure has failed" << eom; + solver.pop_context(); + solver.pop_context(); + return; + } + + // loop exit conditions satisfiable check + + solver.new_context(); + + for(unsigned i=0; iget(*(lbv_it+1)); + + // TODO: make this in different way + if(!from_expr(SSA.ns, "", *slvc_it).compare("0")) + { + eq_expr=equal_exprt( + *(lbv_it+1), + to_constant_expr( + simplify_expr( + old_xinit, + SSA.ns))); + } + else + { + // Exists xinit % const != old_xinit % const + eq_expr=equal_exprt( + mod_exprt(*(lbv_it+1), *slvc_it), + mod_exprt( + to_constant_expr(simplify_expr(old_xinit, SSA.ns)), + *slvc_it)); + } + local_constraints.push_back(eq_expr); + ++slvc_it; + lbv_it+=3; + } + constraints.push_back(not_exprt(conjunction(local_constraints))); + solver << not_exprt(conjunction(local_constraints)); + break; + + default: + error() << "decision procedure has failed" << eom; + solver.pop_context(); + solver.pop_context(); + solver.pop_context(); + return; + } + } + while(result!=decision_proceduret::D_UNSATISFIABLE); + + solver.pop_context(); + + solver << conjunction(loop_exit_cond); + solver << conjunction(constraints); + + switch(solver()) + { + case decision_proceduret::D_UNSATISFIABLE: + solver.pop_context(); + break; + + case decision_proceduret::D_SATISFIABLE: + // found nontermination + property_map[property_id].result=FAIL; + solver.pop_context(); + solver.pop_context(); + return; + + default: + error() << "decision procedure has failed" << eom; + solver.pop_context(); + solver.pop_context(); + return; + } + } + } + solver.pop_context(); +} + +/*******************************************************************\ + +Function: summary_checker_nontermt::check_nonterm_linear + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +summary_checker_baset::resultt summary_checker_nontermt::check_nonterm_linear() +{ + // analyze 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; + + check_properties_linear(f_it); + } + + 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(p_it->second.result==FAIL) + return property_checkert::FAIL; + if(p_it->second.result==UNKNOWN) + result=property_checkert::UNKNOWN; + } + + return result; +} diff --git a/src/2ls/summary_checker_nonterm.h b/src/2ls/summary_checker_nonterm.h new file mode 100644 index 000000000..18992b169 --- /dev/null +++ b/src/2ls/summary_checker_nonterm.h @@ -0,0 +1,34 @@ +/*******************************************************************\ + +Module: Summarizer for Nontermination Bit-level analysis + +Author: Stefan Marticek + +\*******************************************************************/ + +#ifndef CPROVER_2LS_2LS_SUMMARY_CHECKER_NONTERM_H +#define CPROVER_2LS_2LS_SUMMARY_CHECKER_NONTERM_H + +#include "summary_checker_base.h" + +class summary_checker_nontermt:public summary_checker_baset +{ +public: + explicit summary_checker_nontermt(optionst &_options): + summary_checker_baset(_options) + { + } + + virtual resultt operator()(const goto_modelt &); + + void check_properties( + const ssa_dbt::functionst::const_iterator f_it); + + void check_properties_linear( + const ssa_dbt::functionst::const_iterator f_it); + +protected: + summary_checker_baset::resultt check_nonterm_linear(); +}; + +#endif // CPROVER_2LS_2LS_SUMMARY_CHECKER_NONTERM_H diff --git a/src/ssa/ssa_build_goto_trace.cpp b/src/ssa/ssa_build_goto_trace.cpp index 22891beff..2a24e33c6 100644 --- a/src/ssa/ssa_build_goto_trace.cpp +++ b/src/ssa/ssa_build_goto_trace.cpp @@ -336,7 +336,8 @@ void ssa_build_goto_tracet::operator()( std::cout << "loop-head : " << current_pc->location_number << std::endl; std::cout << "unwindings: " << unwindable_local_SSA.odometer_to_string( - unwindable_local_SSA.current_unwindings, 100) + unwindable_local_SSA.current_unwindings, + 100) << std::endl; #endif } @@ -365,13 +366,17 @@ void ssa_build_goto_tracet::operator()( #endif if(current_pc->is_backwards_goto()) { + if(unwindable_local_SSA.current_unwindings.back()==0) + break; + // we de-(!)-crement the unwinding counter unwindable_local_SSA.decrement_unwindings(0); #if 0 std::cout << "loop-end : " << current_pc->location_number << std::endl; std::cout << "unwindings: " << unwindable_local_SSA.odometer_to_string( - unwindable_local_SSA.current_unwindings, 100) + unwindable_local_SSA.current_unwindings, + 100) << std::endl; #endif #if TERM_CEX From e6ed0c4b7e60f094bd7005917f2e361f39c920f5 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sat, 4 Nov 2017 13:44:45 +0000 Subject: [PATCH 009/322] Regression tests for nontermination Author: Stefan Marticek --- regression/Makefile | 2 +- regression/nontermination/Makefile | 20 ++++ regression/nontermination/break_loop1/main.c | 11 ++ .../nontermination/break_loop1/test.desc | 6 + regression/nontermination/break_loop2/main.c | 11 ++ .../nontermination/break_loop2/test.desc | 6 + regression/nontermination/break_loop3/main.c | 105 ++++++++++++++++++ .../nontermination/break_loop3/test.desc | 6 + .../nontermination/continue_loop1/main.c | 12 ++ .../nontermination/continue_loop1/test.desc | 6 + regression/nontermination/loop1/main.c | 14 +++ regression/nontermination/loop1/test.desc | 6 + regression/nontermination/loop_seq1/main.c | 8 ++ regression/nontermination/loop_seq1/test.desc | 6 + regression/nontermination/loop_seq2/main.c | 10 ++ regression/nontermination/loop_seq2/test.desc | 6 + .../nontermination/loop_seq_break1/main.c | 9 ++ .../nontermination/loop_seq_break1/test.desc | 6 + regression/nontermination/malloc1/main.c | 6 + regression/nontermination/malloc1/test.desc | 6 + regression/nontermination/many_loops1/main.c | 15 +++ .../nontermination/many_loops1/test.desc | 6 + regression/nontermination/mem_alloc1/main.c | 14 +++ .../nontermination/mem_alloc1/test.desc | 6 + regression/nontermination/mto_loop1/main.c | 7 ++ regression/nontermination/mto_loop1/test.desc | 6 + .../nontermination/nested_loops1/main.c | 23 ++++ .../nontermination/nested_loops1/test.desc | 6 + .../nontermination/nested_loops2/main.c | 27 +++++ .../nontermination/nested_loops2/test.desc | 6 + .../nontermination/nested_loops3/main.c | 17 +++ .../nontermination/nested_loops3/test.desc | 6 + .../nontermination/nested_loops3b/main.c | 15 +++ .../nontermination/nested_loops3b/test.desc | 6 + .../nontermination/nested_loops4/main.c | 16 +++ .../nontermination/nested_loops4/test.desc | 6 + .../nontermination/nested_loops5/main.c | 17 +++ .../nontermination/nested_loops5/test.desc | 6 + .../nontermination/nested_loops6/main.c | 18 +++ .../nontermination/nested_loops6/test.desc | 6 + .../nontermination/nested_loops7/main.c | 18 +++ .../nontermination/nested_loops7/test.desc | 6 + .../nontermination/nested_loops8/main.c | 17 +++ .../nontermination/nested_loops8/test.desc | 6 + regression/nontermination/nonterm1/main.c | 21 ++++ regression/nontermination/nonterm1/test.desc | 6 + .../nontermination/nontermination1/main.c | 15 +++ .../nontermination/nontermination1/test.desc | 6 + .../nontermination/possible_bug1/main.c | 12 ++ .../nontermination/possible_bug1/test.desc | 6 + regression/nontermination/sloop2/main.c | 11 ++ regression/nontermination/sloop2/test.desc | 6 + regression/nontermination/sloop3/main.c | 8 ++ regression/nontermination/sloop3/test.desc | 6 + regression/nontermination/sloop4/main.c | 9 ++ regression/nontermination/sloop4/test.desc | 6 + regression/nontermination/sloop5/main.c | 13 +++ regression/nontermination/sloop5/test.desc | 6 + regression/nontermination/sloop6/main.c | 14 +++ regression/nontermination/sloop6/test.desc | 6 + regression/nontermination/sloop7/main.c | 13 +++ regression/nontermination/sloop7/test.desc | 6 + regression/nontermination/sloop8/main.c | 10 ++ regression/nontermination/sloop8/test.desc | 6 + regression/nontermination/sloop9/main.c | 10 ++ regression/nontermination/sloop9/test.desc | 6 + .../term_fail_break_loop1/main.c | 11 ++ .../term_fail_break_loop1/test.desc | 6 + .../precond_contextsensitive1/test.desc | 2 +- 69 files changed, 757 insertions(+), 2 deletions(-) create mode 100644 regression/nontermination/Makefile create mode 100644 regression/nontermination/break_loop1/main.c create mode 100644 regression/nontermination/break_loop1/test.desc create mode 100644 regression/nontermination/break_loop2/main.c create mode 100644 regression/nontermination/break_loop2/test.desc create mode 100644 regression/nontermination/break_loop3/main.c create mode 100644 regression/nontermination/break_loop3/test.desc create mode 100644 regression/nontermination/continue_loop1/main.c create mode 100644 regression/nontermination/continue_loop1/test.desc create mode 100644 regression/nontermination/loop1/main.c create mode 100644 regression/nontermination/loop1/test.desc create mode 100644 regression/nontermination/loop_seq1/main.c create mode 100644 regression/nontermination/loop_seq1/test.desc create mode 100644 regression/nontermination/loop_seq2/main.c create mode 100644 regression/nontermination/loop_seq2/test.desc create mode 100644 regression/nontermination/loop_seq_break1/main.c create mode 100644 regression/nontermination/loop_seq_break1/test.desc create mode 100644 regression/nontermination/malloc1/main.c create mode 100644 regression/nontermination/malloc1/test.desc create mode 100644 regression/nontermination/many_loops1/main.c create mode 100644 regression/nontermination/many_loops1/test.desc create mode 100644 regression/nontermination/mem_alloc1/main.c create mode 100644 regression/nontermination/mem_alloc1/test.desc create mode 100644 regression/nontermination/mto_loop1/main.c create mode 100644 regression/nontermination/mto_loop1/test.desc create mode 100644 regression/nontermination/nested_loops1/main.c create mode 100644 regression/nontermination/nested_loops1/test.desc create mode 100644 regression/nontermination/nested_loops2/main.c create mode 100644 regression/nontermination/nested_loops2/test.desc create mode 100644 regression/nontermination/nested_loops3/main.c create mode 100644 regression/nontermination/nested_loops3/test.desc create mode 100644 regression/nontermination/nested_loops3b/main.c create mode 100644 regression/nontermination/nested_loops3b/test.desc create mode 100644 regression/nontermination/nested_loops4/main.c create mode 100644 regression/nontermination/nested_loops4/test.desc create mode 100644 regression/nontermination/nested_loops5/main.c create mode 100644 regression/nontermination/nested_loops5/test.desc create mode 100644 regression/nontermination/nested_loops6/main.c create mode 100644 regression/nontermination/nested_loops6/test.desc create mode 100644 regression/nontermination/nested_loops7/main.c create mode 100644 regression/nontermination/nested_loops7/test.desc create mode 100644 regression/nontermination/nested_loops8/main.c create mode 100644 regression/nontermination/nested_loops8/test.desc create mode 100644 regression/nontermination/nonterm1/main.c create mode 100644 regression/nontermination/nonterm1/test.desc create mode 100644 regression/nontermination/nontermination1/main.c create mode 100644 regression/nontermination/nontermination1/test.desc create mode 100644 regression/nontermination/possible_bug1/main.c create mode 100644 regression/nontermination/possible_bug1/test.desc create mode 100644 regression/nontermination/sloop2/main.c create mode 100644 regression/nontermination/sloop2/test.desc create mode 100644 regression/nontermination/sloop3/main.c create mode 100644 regression/nontermination/sloop3/test.desc create mode 100644 regression/nontermination/sloop4/main.c create mode 100644 regression/nontermination/sloop4/test.desc create mode 100644 regression/nontermination/sloop5/main.c create mode 100644 regression/nontermination/sloop5/test.desc create mode 100644 regression/nontermination/sloop6/main.c create mode 100644 regression/nontermination/sloop6/test.desc create mode 100644 regression/nontermination/sloop7/main.c create mode 100644 regression/nontermination/sloop7/test.desc create mode 100644 regression/nontermination/sloop8/main.c create mode 100644 regression/nontermination/sloop8/test.desc create mode 100644 regression/nontermination/sloop9/main.c create mode 100644 regression/nontermination/sloop9/test.desc create mode 100644 regression/nontermination/term_fail_break_loop1/main.c create mode 100644 regression/nontermination/term_fail_break_loop1/test.desc diff --git a/regression/Makefile b/regression/Makefile index 22aec995c..b22a878c1 100644 --- a/regression/Makefile +++ b/regression/Makefile @@ -1,4 +1,4 @@ -DIRS = termination kiki preconditions interprocedural invariants +DIRS = nontermination termination kiki preconditions interprocedural invariants test: $(foreach var,$(DIRS), make -C $(var) test;) diff --git a/regression/nontermination/Makefile b/regression/nontermination/Makefile new file mode 100644 index 000000000..cbda9642d --- /dev/null +++ b/regression/nontermination/Makefile @@ -0,0 +1,20 @@ +default: tests.log + +FLAGS = --verbosity 10 --nontermination + +test: + @../test.pl -c "../../../src/2ls/2ls $(FLAGS)" + +tests.log: ../test.pl + @../test.pl -c "../../../src/2ls/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/nontermination/break_loop1/main.c b/regression/nontermination/break_loop1/main.c new file mode 100644 index 000000000..cfb20065d --- /dev/null +++ b/regression/nontermination/break_loop1/main.c @@ -0,0 +1,11 @@ +int main (void) +{ + int k = 0; + + while (k < 10) + { + if (k == 0) break; + } + + return 0; +} diff --git a/regression/nontermination/break_loop1/test.desc b/regression/nontermination/break_loop1/test.desc new file mode 100644 index 000000000..a99c31502 --- /dev/null +++ b/regression/nontermination/break_loop1/test.desc @@ -0,0 +1,6 @@ +KNOWNBUG +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/break_loop2/main.c b/regression/nontermination/break_loop2/main.c new file mode 100644 index 000000000..bf2fbb1da --- /dev/null +++ b/regression/nontermination/break_loop2/main.c @@ -0,0 +1,11 @@ +int main (void) +{ + int k = 0; + + while (k < 10) + { + if (k == 1) break; + } + + return 0; +} diff --git a/regression/nontermination/break_loop2/test.desc b/regression/nontermination/break_loop2/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/break_loop2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/break_loop3/main.c b/regression/nontermination/break_loop3/main.c new file mode 100644 index 000000000..9f51a8177 --- /dev/null +++ b/regression/nontermination/break_loop3/main.c @@ -0,0 +1,105 @@ +#include +int main(void) { + int i___0; + int d = 0; + int currentFloorID = 3; + int floorButtons_0; + int floorButtons_1; + int floorButtons_2; + int floorButtons_3; + int floorButtons_4 = 0; + int retValue_acc; + if (d == 0) { + i___0 = 0; + i___0 = currentFloorID - 1; + { + while (1) { + currentFloorID=currentFloorID; + floorButtons_4=floorButtons_4; + while_6_continue: /* CIL Label */ ; + if (i___0 >= 0) { + + } else { + goto while_6_break; + } + i___0 = currentFloorID + 1; + { + while (1) { + while_7_continue: /* CIL Label */ ; + if (i___0 < 5) { + + } else { + goto while_7_break; + } + if (i___0 == 0) { + if (floorButtons_0) { + retValue_acc = 1; + return (retValue_acc); + } else { + goto _L___6; + } + } else { + _L___6: /* CIL Label */ + if (i___0 == 1) { + if (floorButtons_1) { + retValue_acc = 1; + return (retValue_acc); + } else { + goto _L___5; + } + } else { + _L___5: /* CIL Label */ + if (i___0 == 2) { + if (floorButtons_2) { + retValue_acc = 1; + return (retValue_acc); + } else { + goto _L___4; + } + } else { + _L___4: /* CIL Label */ + if (i___0 == 3) { + if (floorButtons_3) { + retValue_acc = 1; + return (retValue_acc); + } else { + goto _L___3; + } + } else { + _L___3: /* CIL Label */ + if (i___0 == 4) { + if (floorButtons_4) { + retValue_acc = 1; + return (retValue_acc); + } else { + + } + } else { + + } + } + } + } + } + i___0 = i___0 + 1; + printf("%d %d %d %d %d %d %d %d %d\n", i___0, + d, + currentFloorID, + floorButtons_0, + floorButtons_1, + floorButtons_2, + floorButtons_3, + floorButtons_4, + retValue_acc); + } + while_7_break: /* CIL Label */ ; + } + i___0 = i___0 - 1; + } + while_6_break: /* CIL Label */ ; + } + } else { + + } + return 0; +} diff --git a/regression/nontermination/break_loop3/test.desc b/regression/nontermination/break_loop3/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/break_loop3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/continue_loop1/main.c b/regression/nontermination/continue_loop1/main.c new file mode 100644 index 000000000..993228df6 --- /dev/null +++ b/regression/nontermination/continue_loop1/main.c @@ -0,0 +1,12 @@ +int main (void) +{ + int k = 0; + + while (k < 10) + { + if (k == 0) continue; + k++; + } + + return 0; +} diff --git a/regression/nontermination/continue_loop1/test.desc b/regression/nontermination/continue_loop1/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/continue_loop1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/loop1/main.c b/regression/nontermination/loop1/main.c new file mode 100644 index 000000000..4db3a12ca --- /dev/null +++ b/regression/nontermination/loop1/main.c @@ -0,0 +1,14 @@ +int main(void) +{ + int i; + while(1) { + if (i++) break; + if (--i) break; + while(1) { + if (i) break; + if (i) break; + } + } + + return 0; +} diff --git a/regression/nontermination/loop1/test.desc b/regression/nontermination/loop1/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/loop1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/loop_seq1/main.c b/regression/nontermination/loop_seq1/main.c new file mode 100644 index 000000000..c37b25bfa --- /dev/null +++ b/regression/nontermination/loop_seq1/main.c @@ -0,0 +1,8 @@ +int main(void) +{ + int i = 0, j = 0, k = 0; + while (i < 10) i++; + while (j < 10) j++; + while (k < 10); + return 0; +} diff --git a/regression/nontermination/loop_seq1/test.desc b/regression/nontermination/loop_seq1/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/loop_seq1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/loop_seq2/main.c b/regression/nontermination/loop_seq2/main.c new file mode 100644 index 000000000..9d7a6f994 --- /dev/null +++ b/regression/nontermination/loop_seq2/main.c @@ -0,0 +1,10 @@ +int main(void) +{ + int k = 0; + while (k < 10) if (k < 10) break; + + do { + } while (k < 10); + + return 0; +} diff --git a/regression/nontermination/loop_seq2/test.desc b/regression/nontermination/loop_seq2/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/loop_seq2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/loop_seq_break1/main.c b/regression/nontermination/loop_seq_break1/main.c new file mode 100644 index 000000000..3d8eb9612 --- /dev/null +++ b/regression/nontermination/loop_seq_break1/main.c @@ -0,0 +1,9 @@ +int main(void) +{ + int i = 0, j = 0, k = 0; + while (i < 10) { i++; } + while (i < 15) { i++; } + while (k < 10) { if (k < 10) break; } + + return 0; +} diff --git a/regression/nontermination/loop_seq_break1/test.desc b/regression/nontermination/loop_seq_break1/test.desc new file mode 100644 index 000000000..a99c31502 --- /dev/null +++ b/regression/nontermination/loop_seq_break1/test.desc @@ -0,0 +1,6 @@ +KNOWNBUG +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/malloc1/main.c b/regression/nontermination/malloc1/main.c new file mode 100644 index 000000000..b968b3003 --- /dev/null +++ b/regression/nontermination/malloc1/main.c @@ -0,0 +1,6 @@ +int main (void) +{ + while (malloc(1)); + + return 0; +} diff --git a/regression/nontermination/malloc1/test.desc b/regression/nontermination/malloc1/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/malloc1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/many_loops1/main.c b/regression/nontermination/many_loops1/main.c new file mode 100644 index 000000000..26da22f15 --- /dev/null +++ b/regression/nontermination/many_loops1/main.c @@ -0,0 +1,15 @@ +int main(void) +{ + int i = 2; + int j = 2; + + for (int k = 0; k < 10; k++); + + while (i > 1) { + if (i > 2) + i--; + if (j > 2) + j--; + } + return i; +} diff --git a/regression/nontermination/many_loops1/test.desc b/regression/nontermination/many_loops1/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/many_loops1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/mem_alloc1/main.c b/regression/nontermination/mem_alloc1/main.c new file mode 100644 index 000000000..5b95dc851 --- /dev/null +++ b/regression/nontermination/mem_alloc1/main.c @@ -0,0 +1,14 @@ +int main(void) +{ + int i = 0; + while (1) { + i++; + int *a, *b; + if (malloc(110)) { + a = malloc(sizeof(malloc(10)))+1; + b = malloc(20); + } + } + + return 0; +} diff --git a/regression/nontermination/mem_alloc1/test.desc b/regression/nontermination/mem_alloc1/test.desc new file mode 100644 index 000000000..a99c31502 --- /dev/null +++ b/regression/nontermination/mem_alloc1/test.desc @@ -0,0 +1,6 @@ +KNOWNBUG +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/mto_loop1/main.c b/regression/nontermination/mto_loop1/main.c new file mode 100644 index 000000000..58e216f47 --- /dev/null +++ b/regression/nontermination/mto_loop1/main.c @@ -0,0 +1,7 @@ +int main(void) +{ + int i; + for ( int k = 0; k < 10; k++); + while ( i > 0); + return 0; +} diff --git a/regression/nontermination/mto_loop1/test.desc b/regression/nontermination/mto_loop1/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/mto_loop1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/nested_loops1/main.c b/regression/nontermination/nested_loops1/main.c new file mode 100644 index 000000000..5399c127d --- /dev/null +++ b/regression/nontermination/nested_loops1/main.c @@ -0,0 +1,23 @@ +int main(void) +{ + int i = 1, j = 2, k = 3; + while (i!=j && j!=k) + { + j = k - i; + k = j + i; + i = k - j; + while (i!=k && j!=k) + { + j = k - i; + k = j + i; + i = k - j; + while (i!=j && j!=k) + { + j = k - i; + k = j + i; + i = k - j; + } + + } + } +} diff --git a/regression/nontermination/nested_loops1/test.desc b/regression/nontermination/nested_loops1/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/nested_loops1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/nested_loops2/main.c b/regression/nontermination/nested_loops2/main.c new file mode 100644 index 000000000..97292a63d --- /dev/null +++ b/regression/nontermination/nested_loops2/main.c @@ -0,0 +1,27 @@ +#include + +int main(void) +{ //few permutations - 4th is the same 3 times unwind to prove nontermination + int i = 1, j = 2, k = 3; + int counter = 1; + while (1) + { + printf("%d %d %d\n", i, j, k); + if (counter % 2 ==0) + { + i = j + i; + j = i - j; + i = i - j; + counter--; + } + else + { + counter++; + } + //swap j and k + j = j + k; + k = j - k; + j = j - k; + //swap i and j + } +} diff --git a/regression/nontermination/nested_loops2/test.desc b/regression/nontermination/nested_loops2/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/nested_loops2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/nested_loops3/main.c b/regression/nontermination/nested_loops3/main.c new file mode 100644 index 000000000..24021b6b5 --- /dev/null +++ b/regression/nontermination/nested_loops3/main.c @@ -0,0 +1,17 @@ +int main (void) +{ + int i = 0, j = 0, k = 0; + while (i < 10) + { + while (j < 10) + { + while (k < 10) + { + i >>= 1; + j >>= 1; + } + } + } + + return 0; +} diff --git a/regression/nontermination/nested_loops3/test.desc b/regression/nontermination/nested_loops3/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/nested_loops3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/nested_loops3b/main.c b/regression/nontermination/nested_loops3b/main.c new file mode 100644 index 000000000..50476ae00 --- /dev/null +++ b/regression/nontermination/nested_loops3b/main.c @@ -0,0 +1,15 @@ +int main (void) +{ + int i = 4, j = 4, k = 4; + while (j < 10) + { + while (k < 10) + { + if (!i) break; + i >>= 1; + j >>= 1; + } + } + + return 0; +} diff --git a/regression/nontermination/nested_loops3b/test.desc b/regression/nontermination/nested_loops3b/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/nested_loops3b/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/nested_loops4/main.c b/regression/nontermination/nested_loops4/main.c new file mode 100644 index 000000000..9aec0b597 --- /dev/null +++ b/regression/nontermination/nested_loops4/main.c @@ -0,0 +1,16 @@ +int main (void) +{ + int i = 0, j = 0, k = 0; + while (i < 10) + { + while (j < 10) + { + while (k < 10) + { + for ( int x = 0; x < 100; x++); + } + } + } + + return 0; +} diff --git a/regression/nontermination/nested_loops4/test.desc b/regression/nontermination/nested_loops4/test.desc new file mode 100644 index 000000000..a99c31502 --- /dev/null +++ b/regression/nontermination/nested_loops4/test.desc @@ -0,0 +1,6 @@ +KNOWNBUG +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/nested_loops5/main.c b/regression/nontermination/nested_loops5/main.c new file mode 100644 index 000000000..473d5578a --- /dev/null +++ b/regression/nontermination/nested_loops5/main.c @@ -0,0 +1,17 @@ +int main (void) +{ + int i = 0, j = 0, k = 0; + while (i < 10) + { + while (j < 10) + { + while (k < 10) + { + if (k == 0) break; + } + if (j == 0) break; + } + } + + return 0; +} diff --git a/regression/nontermination/nested_loops5/test.desc b/regression/nontermination/nested_loops5/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/nested_loops5/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/nested_loops6/main.c b/regression/nontermination/nested_loops6/main.c new file mode 100644 index 000000000..a6c9486df --- /dev/null +++ b/regression/nontermination/nested_loops6/main.c @@ -0,0 +1,18 @@ +int main (void) +{ + int i = 0, j = 0, k = 0; + while (i < 10) + { + while (j < 10) + { + while (k < 10) + { + if (k == 0) break; + } + if (j == 0) break; + } + if (i == 0) break; + } + + return 0; +} diff --git a/regression/nontermination/nested_loops6/test.desc b/regression/nontermination/nested_loops6/test.desc new file mode 100644 index 000000000..a99c31502 --- /dev/null +++ b/regression/nontermination/nested_loops6/test.desc @@ -0,0 +1,6 @@ +KNOWNBUG +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/nested_loops7/main.c b/regression/nontermination/nested_loops7/main.c new file mode 100644 index 000000000..63bf53e75 --- /dev/null +++ b/regression/nontermination/nested_loops7/main.c @@ -0,0 +1,18 @@ +int main (void) +{ + int i = 0, j = 0, k = 0; + while (i < 10) + { + while (j < 10) + { + while (k < 10) + { + k = j - i; + } + j++; + } + i++; + } + + return 0; +} diff --git a/regression/nontermination/nested_loops7/test.desc b/regression/nontermination/nested_loops7/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/nested_loops7/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/nested_loops8/main.c b/regression/nontermination/nested_loops8/main.c new file mode 100644 index 000000000..57819ffa9 --- /dev/null +++ b/regression/nontermination/nested_loops8/main.c @@ -0,0 +1,17 @@ +int main (void) +{ + int i = 0, j = 0, k = 0; + while (i < 10) + { + while (j < 10) + { + while (k < 10) + { + k++; + } + } + i++; + } + + return 0; +} diff --git a/regression/nontermination/nested_loops8/test.desc b/regression/nontermination/nested_loops8/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/nested_loops8/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/nonterm1/main.c b/regression/nontermination/nonterm1/main.c new file mode 100644 index 000000000..6e47986c7 --- /dev/null +++ b/regression/nontermination/nonterm1/main.c @@ -0,0 +1,21 @@ +/* + * Date: 06/07/2015 + * Created by: Ton Chanh Le (chanhle@comp.nus.edu.sg) + * Adapted from Cairo_true-termination.c + */ + +typedef enum {false, true} bool; + +extern int __VERIFIER_nondet_int(void); + +int main() +{ + int x, y; + if (x > 0) { + while ((x != 0) && (y % 2 == 0)) { + x = x + 2; + y=y+2; + } + } + return 0; +} diff --git a/regression/nontermination/nonterm1/test.desc b/regression/nontermination/nonterm1/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/nonterm1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/nontermination1/main.c b/regression/nontermination/nontermination1/main.c new file mode 100644 index 000000000..c9e776b1b --- /dev/null +++ b/regression/nontermination/nontermination1/main.c @@ -0,0 +1,15 @@ +int main (void) +{ + int i = 4, j = 4, k; + __CPROVER_assume(3<=k && k<=4); + while (j < 10) + { + do + { + i >>= 1; + j >>= 1; + } while ((k < 10)); + } + + return 0; +} diff --git a/regression/nontermination/nontermination1/test.desc b/regression/nontermination/nontermination1/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/nontermination1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/possible_bug1/main.c b/regression/nontermination/possible_bug1/main.c new file mode 100644 index 000000000..f8eab91e9 --- /dev/null +++ b/regression/nontermination/possible_bug1/main.c @@ -0,0 +1,12 @@ +int main(void) +{ + int i, counter = 1; + for (i=1; i< 10;) + { + if (counter % 3 == 0) i++; + counter++; + } + while (i) i=i; + + return 0; +} diff --git a/regression/nontermination/possible_bug1/test.desc b/regression/nontermination/possible_bug1/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/possible_bug1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/sloop2/main.c b/regression/nontermination/sloop2/main.c new file mode 100644 index 000000000..3d252e48d --- /dev/null +++ b/regression/nontermination/sloop2/main.c @@ -0,0 +1,11 @@ +#include + +int main() +{ + int i = 4; + while (i > 1) { + if (i > 2) + i--; + } + return i; +} diff --git a/regression/nontermination/sloop2/test.desc b/regression/nontermination/sloop2/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/sloop2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/sloop3/main.c b/regression/nontermination/sloop3/main.c new file mode 100644 index 000000000..88f50133f --- /dev/null +++ b/regression/nontermination/sloop3/main.c @@ -0,0 +1,8 @@ +#include + +int main() +{ + int i = 2; + while (i > 1); + return i; +} diff --git a/regression/nontermination/sloop3/test.desc b/regression/nontermination/sloop3/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/sloop3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/sloop4/main.c b/regression/nontermination/sloop4/main.c new file mode 100644 index 000000000..2341e3391 --- /dev/null +++ b/regression/nontermination/sloop4/main.c @@ -0,0 +1,9 @@ +#include + +int main() +{ + int i = 2; + while (i > 1) i--; + assert(i==0); + return i; +} diff --git a/regression/nontermination/sloop4/test.desc b/regression/nontermination/sloop4/test.desc new file mode 100644 index 000000000..a99c31502 --- /dev/null +++ b/regression/nontermination/sloop4/test.desc @@ -0,0 +1,6 @@ +KNOWNBUG +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/sloop5/main.c b/regression/nontermination/sloop5/main.c new file mode 100644 index 000000000..ddcf95e49 --- /dev/null +++ b/regression/nontermination/sloop5/main.c @@ -0,0 +1,13 @@ +#include + +int main() +{ + int i = 4; + int j = 4; + while (i > 1) { + if (i > 2) + i--; + j--; + } + return i; +} diff --git a/regression/nontermination/sloop5/test.desc b/regression/nontermination/sloop5/test.desc new file mode 100644 index 000000000..a99c31502 --- /dev/null +++ b/regression/nontermination/sloop5/test.desc @@ -0,0 +1,6 @@ +KNOWNBUG +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/sloop6/main.c b/regression/nontermination/sloop6/main.c new file mode 100644 index 000000000..0e33516b0 --- /dev/null +++ b/regression/nontermination/sloop6/main.c @@ -0,0 +1,14 @@ +#include + +int main() +{ + int i = 5; + int j = 4; + while (i > 1) { + if (i > 2) + i--; + if (j > 2) + j--; + } + return i; +} diff --git a/regression/nontermination/sloop6/test.desc b/regression/nontermination/sloop6/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/sloop6/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/sloop7/main.c b/regression/nontermination/sloop7/main.c new file mode 100644 index 000000000..406a6469d --- /dev/null +++ b/regression/nontermination/sloop7/main.c @@ -0,0 +1,13 @@ +#include + +int main() +{ + int i = 4; + int j = 4; + while ( 1) { + if (i > 2) + i--; + j--; + } + return i; +} diff --git a/regression/nontermination/sloop7/test.desc b/regression/nontermination/sloop7/test.desc new file mode 100644 index 000000000..a99c31502 --- /dev/null +++ b/regression/nontermination/sloop7/test.desc @@ -0,0 +1,6 @@ +KNOWNBUG +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/sloop8/main.c b/regression/nontermination/sloop8/main.c new file mode 100644 index 000000000..a9b1d16ab --- /dev/null +++ b/regression/nontermination/sloop8/main.c @@ -0,0 +1,10 @@ +int main(void) +{ + int x=2; + int i=1; + while(x<10) { + if(i%2==0) x++; + i++; + } + return 0; +} diff --git a/regression/nontermination/sloop8/test.desc b/regression/nontermination/sloop8/test.desc new file mode 100644 index 000000000..a99c31502 --- /dev/null +++ b/regression/nontermination/sloop8/test.desc @@ -0,0 +1,6 @@ +KNOWNBUG +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/sloop9/main.c b/regression/nontermination/sloop9/main.c new file mode 100644 index 000000000..e9e5e36f5 --- /dev/null +++ b/regression/nontermination/sloop9/main.c @@ -0,0 +1,10 @@ +int main(void) +{ + int x=9; + int i=1; + while(x<10) { + if(i%2==0) x++; + i++; + } + return 0; +} diff --git a/regression/nontermination/sloop9/test.desc b/regression/nontermination/sloop9/test.desc new file mode 100644 index 000000000..a99c31502 --- /dev/null +++ b/regression/nontermination/sloop9/test.desc @@ -0,0 +1,6 @@ +KNOWNBUG +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/term_fail_break_loop1/main.c b/regression/nontermination/term_fail_break_loop1/main.c new file mode 100644 index 000000000..cfb20065d --- /dev/null +++ b/regression/nontermination/term_fail_break_loop1/main.c @@ -0,0 +1,11 @@ +int main (void) +{ + int k = 0; + + while (k < 10) + { + if (k == 0) break; + } + + return 0; +} diff --git a/regression/nontermination/term_fail_break_loop1/test.desc b/regression/nontermination/term_fail_break_loop1/test.desc new file mode 100644 index 000000000..a99c31502 --- /dev/null +++ b/regression/nontermination/term_fail_break_loop1/test.desc @@ -0,0 +1,6 @@ +KNOWNBUG +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/preconditions/precond_contextsensitive1/test.desc b/regression/preconditions/precond_contextsensitive1/test.desc index 76a98d95f..1da5cbf57 100644 --- a/regression/preconditions/precond_contextsensitive1/test.desc +++ b/regression/preconditions/precond_contextsensitive1/test.desc @@ -3,4 +3,4 @@ main.c --context-sensitive --preconditions ^EXIT=5$ ^SIGNAL=0$ -^\[sign\]: sign#return_value#phi19 <= 0 && -((signed __CPROVER_bitvector\[33\])sign#return_value#phi19) <= 0 ==> x <= 0 && -((signed __CPROVER_bitvector\[33\])x) <= 0$ +^\[sign\]: sign#return_value#phi17 <= 0 && -((signed __CPROVER_bitvector\[33\])sign#return_value#phi17) <= 0 ==> x <= 0 && -((signed __CPROVER_bitvector\[33\])x) <= 0$ From 6b7764b77b5044e5b967eaed0e10ef13fcf1856d Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sat, 4 Nov 2017 21:44:40 +0000 Subject: [PATCH 010/322] Version 0.5.2 --- src/2ls/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/2ls/version.h b/src/2ls/version.h index 132ef4309..ec3fd48d6 100644 --- a/src/2ls/version.h +++ b/src/2ls/version.h @@ -9,6 +9,6 @@ Author: Peter Schrammel #ifndef CPROVER_2LS_2LS_VERSION_H #define CPROVER_2LS_2LS_VERSION_H -#define TWOLS_VERSION "0.5.1" +#define TWOLS_VERSION "0.5.2" #endif From c42930e15f42a4046cb124b07f9246d33f8697da Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Wed, 10 Aug 2016 09:52:47 +0100 Subject: [PATCH 011/322] Handling pointer parameters of functions. Pointed object is passed as global. --- src/ssa/ssa_dereference.cpp | 6 ++++ src/ssa/ssa_inliner.cpp | 58 +++++++++++++++++++++++++++++++++++-- src/ssa/ssa_inliner.h | 10 +++++-- src/ssa/ssa_object.cpp | 1 + 4 files changed, 70 insertions(+), 5 deletions(-) diff --git a/src/ssa/ssa_dereference.cpp b/src/ssa/ssa_dereference.cpp index 0425e7d54..3bc60c5c8 100644 --- a/src/ssa/ssa_dereference.cpp +++ b/src/ssa/ssa_dereference.cpp @@ -341,6 +341,12 @@ exprt dereference_rec( result=if_exprt(guard, value, result); } + if (values.empty()) { + // We use the identifier of pointed object + irep_idt identifier = id2string(to_symbol_expr(pointer).get_identifier())+"'obj"; + result=symbol_exprt(identifier, src.type()); + } + return result; } else if(src.id()==ID_member) diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index 2f68901a0..18a34b042 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -10,6 +10,7 @@ Author: Peter Schrammel #include #include "ssa_inliner.h" +#include "ssa_dereference.h" /*******************************************************************\ @@ -63,7 +64,13 @@ void ssa_inlinert::get_summary( #endif // equalities for arguments - bindings.push_back(get_replace_params(summary.params, *f_it)); + bindings.push_back(get_replace_params( + summary.params, + *f_it, + summary.globals_in, + summary.globals_out, + SSA, + loc)); // equalities for globals_in if(forward) @@ -489,7 +496,11 @@ Function: ssa_inlinert::get_replace_params exprt ssa_inlinert::get_replace_params( const local_SSAt::var_listt ¶ms, - const function_application_exprt &funapp_expr) + const function_application_exprt &funapp_expr, + const local_SSAt::var_sett &globals_in, + const local_SSAt::var_sett &globals_out, + const local_SSAt &SSA, + const local_SSAt::locationt &loc) { // equalities for arguments exprt::operandst c; @@ -508,6 +519,49 @@ exprt ssa_inlinert::get_replace_params( exprt lhs=*p_it; // copy rename(lhs); c.push_back(equal_exprt(lhs, *it)); + + // For pointer parameters create equalities between pointed object passed as global and + // corresponding object in caller + if (p_it->type().id() == ID_pointer) { + // Find corresponding objects in caller's objects (separately for entry and exit) + exprt pointed_ssa_sym_in; + exprt pointed_ssa_sym_out; + for (equal_exprt equal : SSA.find_node(loc)->equalities) + { // search through equalities with argument value + if (equal.rhs().id() == ID_symbol && + to_symbol_expr(equal.rhs()).get_identifier() == to_symbol_expr(*it).get_identifier()) + { + exprt arg_pointed = dereference(equal.lhs(), SSA.ssa_value_ai[loc], "", SSA.ns); + if (arg_pointed.id() == ID_address_of) + { + arg_pointed = to_address_of_expr(arg_pointed).object(); + } + ssa_objectt pointed_ssa_obj(arg_pointed, SSA.ns); + // get correct SSA symbol for function call entry + pointed_ssa_sym_in = SSA.name(pointed_ssa_obj, local_SSAt::OUT, + SSA.get_def_loc(to_symbol_expr(arg_pointed), loc)); + // get correct SSA symbol for function call exit + pointed_ssa_sym_out = SSA.name(pointed_ssa_obj, local_SSAt::OUT, loc); + } + } + + // Find globals containing pointed object and create equalities + irep_idt global_id = id2string(to_symbol_expr(*p_it).get_identifier())+"'obj"; + symbol_exprt expr_to_find(global_id, p_it->type().subtype()); + + // Entry global + symbol_exprt global_in; + if(find_corresponding_symbol(expr_to_find,globals_in,global_in)) { + rename(global_in); + c.push_back(equal_exprt(global_in,pointed_ssa_sym_in)); + } + // Exit global + symbol_exprt global_out; + if(find_corresponding_symbol(expr_to_find,globals_out,global_out)) { + rename(global_out); + c.push_back(equal_exprt(global_out, pointed_ssa_sym_out)); + } + } } return conjunction(c); } diff --git a/src/ssa/ssa_inliner.h b/src/ssa/ssa_inliner.h index 7cf8d0730..d36ee5960 100644 --- a/src/ssa/ssa_inliner.h +++ b/src/ssa/ssa_inliner.h @@ -125,14 +125,18 @@ class ssa_inlinert:public messaget const local_SSAt::var_sett &cs_globals_out); exprt get_replace_globals_in( - const local_SSAt::var_sett &globals_in, + const local_SSAt::var_sett &globals_in, const local_SSAt::var_sett &globals); exprt get_replace_params( const local_SSAt::var_listt ¶ms, - const function_application_exprt &funapp_expr); + const function_application_exprt &funapp_expr, + const local_SSAt::var_sett &globals_in, + const local_SSAt::var_sett &globals_out, + const local_SSAt &SSA, + const local_SSAt::locationt &loc); exprt get_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_in, const local_SSAt::var_sett &cs_globals_out); void rename(exprt &expr); diff --git a/src/ssa/ssa_object.cpp b/src/ssa/ssa_object.cpp index d3aa56993..72440df3a 100644 --- a/src/ssa/ssa_object.cpp +++ b/src/ssa/ssa_object.cpp @@ -282,6 +282,7 @@ void ssa_objectst::categorize_objects( { if(is_ptr_object(root_object)) { + globals.insert(*o_it); } else { From eaa069501b04f56bdcda83dcadabe8e99c08d938 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 12 Aug 2016 17:12:50 +0100 Subject: [PATCH 012/322] Simple heap domain - can check if pointers are NULL. --- src/2ls/2ls_parse_options.cpp | 7 ++ src/2ls/2ls_parse_options.h | 2 +- src/domains/Makefile | 5 +- src/domains/heap_domain.cpp | 134 ++++++++++++++++++++++++ src/domains/heap_domain.h | 89 ++++++++++++++++ src/domains/ssa_analyzer.cpp | 7 ++ src/domains/strategy_solver_heap.cpp | 44 ++++++++ src/domains/strategy_solver_heap.h | 30 ++++++ src/domains/template_generator_base.cpp | 17 +++ src/domains/template_generator_base.h | 1 + 10 files changed, 333 insertions(+), 3 deletions(-) create mode 100644 src/domains/heap_domain.cpp create mode 100644 src/domains/heap_domain.h create mode 100644 src/domains/strategy_solver_heap.cpp create mode 100644 src/domains/strategy_solver_heap.h diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 95900d778..6551755c4 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -193,6 +193,10 @@ void twols_parse_optionst::get_command_line_options(optionst &options) options.set_option("equalities", true); options.set_option("std-invariants", true); } + else if (cmdline.isset("heap")) + { + options.set_option("heap", true); + } else { if(cmdline.isset("zones")) @@ -480,6 +484,8 @@ int twols_parse_optionst::doit() status() << "Havocking loops and function calls" << eom; else if(options.get_bool_option("equalities")) status() << "Using (dis)equalities domain" << eom; + else if (options.get_bool_option("heap")) + status() << "Using heap domain" << eom; else { if(options.get_bool_option("intervals")) @@ -1618,6 +1624,7 @@ void twols_parse_optionst::help() " --havoc havoc loops and function calls\n" " --intervals use interval domain\n" " --equalities use equalities and disequalities domain\n" + " --heap use heap domain\n" " --zones use zone domain\n" " --octagons use octagon domain\n" " --enum-solver use solver based on model enumeration\n" diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index 342b79c21..ddbc61c3e 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -36,7 +36,7 @@ class optionst; "(version)" \ "(i386-linux)(i386-macos)(i386-win32)(win32)(winx64)(gcc)" \ "(ppc-macos)(unsigned-char)" \ - "(havoc)(intervals)(zones)(octagons)(equalities)"\ + "(havoc)(intervals)(zones)(octagons)(equalities)(heap)"\ "(enum-solver)(binsearch-solver)(arrays)"\ "(string-abstraction)(no-arch)(arch):(floatbv)(fixedbv)" \ "(round-to-nearest)(round-to-plus-inf)(round-to-minus-inf)(round-to-zero)" \ diff --git a/src/domains/Makefile b/src/domains/Makefile index 82b6a23b8..d780aba0c 100644 --- a/src/domains/Makefile +++ b/src/domains/Makefile @@ -1,4 +1,5 @@ -SRC = tpolyhedra_domain.cpp equality_domain.cpp domain.cpp predabs_domain.cpp\ +SRC = tpolyhedra_domain.cpp equality_domain.cpp domain.cpp \ + predabs_domain.cpp heap_domain.cpp \ ssa_analyzer.cpp util.cpp incremental_solver.cpp \ strategy_solver_base.cpp strategy_solver_equality.cpp \ linrank_domain.cpp lexlinrank_domain.cpp\ @@ -7,7 +8,7 @@ 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 strategy_solver_heap.cpp #solver_enumeration.cpp include ../config.inc diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp new file mode 100644 index 000000000..39f29982c --- /dev/null +++ b/src/domains/heap_domain.cpp @@ -0,0 +1,134 @@ +/** + * Viktor Malik, 12.8.2016 (c). + */ + +#include "heap_domain.h" + +void heap_domaint::initialize(domaint::valuet &value) +{ + heap_valuet &val = static_cast(value); + val.paths.clear(); + val.nulls.clear(); +} + +void heap_domaint::make_template(const domaint::var_specst &var_specs, const namespacet &ns) +{ + unsigned long size = var_specs.size(); + templ.clear(); + templ.reserve(size); + + for (auto v1 = var_specs.begin(); v1 != var_specs.end(); ++v1) + { + // Template for variable - for NULL pointer and dangling checks + templ.push_back(template_rowt()); + template_rowt &templ_row = templ.back(); + templ_row.expr = v1->var; + templ_row.pre_guard = v1->pre_guard; + templ_row.post_guard = v1->post_guard; + templ_row.aux_expr = v1->post_guard; + templ_row.kind = v1->kind; + } +} + +exprt heap_domaint::get_pre_null_constraint(unsigned index) +{ + assert(index < templ.size()); + const template_rowt &templ_row = templ[index]; + if (templ_row.kind == OUT || templ_row.kind == OUTL) return true_exprt(); + const vart &var = templ_row.expr; + return implies_exprt(templ_row.pre_guard, + equal_exprt(var, null_pointer_exprt(to_pointer_type(var.type())))); +} + +exprt heap_domaint::get_post_not_null_constraint(unsigned index) +{ + assert(index < templ.size()); + const template_rowt &templ_row = templ[index]; + if (templ_row.kind == IN) return true_exprt(); + const vart &var = templ_row.expr; + exprt c = and_exprt(templ_row.aux_expr, + not_exprt(implies_exprt(templ_row.post_guard, + equal_exprt(var, null_pointer_exprt( + to_pointer_type(var.type())))))); + rename(c); + return c; +} + +void heap_domaint::set_null(unsigned index, heap_valuet &value) +{ + assert(index < templ.size()); + value.nulls.insert(index); +} + +void heap_domaint::get_index_set(std::set &indices) +{ + for (unsigned i = 0; i < templ.size(); i++) indices.insert(i); +} + +void heap_domaint::output_value(std::ostream &out, const domaint::valuet &value, + const namespacet &ns) const +{ + const heap_valuet &_val = static_cast(value); + heap_valuet val = _val; + + for (unsigned i = 0; i < templ.size(); ++i) + { + if (val.nulls.find(i) != val.nulls.end()) + { + out << from_expr(ns, "", templ[i].expr) << "== NULL" << std::endl; + } + } +} + +void heap_domaint::output_domain(std::ostream &out, const namespacet &ns) const +{ + for (unsigned i = 0; i < templ.size(); ++i) + { + const template_rowt &templ_row = templ[i]; + switch (templ_row.kind) + { + case LOOP: + out << "(LOOP) [ " << from_expr(ns, "", templ_row.pre_guard) << " | "; + out << from_expr(ns, "", templ_row.post_guard) << " | "; + out << from_expr(ns, "", templ_row.aux_expr) + << " ] ===> " << std::endl << " "; + break; + case IN: + out << "(IN) "; + out << from_expr(ns, "", templ_row.pre_guard) << " ===> " + << std::endl << " "; + break; + case OUT: + case OUTL: + out << "(OUT) "; + out << from_expr(ns, "", templ_row.post_guard) << " ===> " + << std::endl << " "; + break; + default: + assert(false); + } + const vart var = templ_row.expr; + out << from_expr(ns, "", var) << " =!= NULL" << std::endl; + } +} + +void heap_domaint::project_on_vars(domaint::valuet &value, + const domaint::var_sett &vars, exprt &result) +{ + heap_valuet &val = static_cast(value); + + exprt::operandst c; + for (auto it = val.nulls.begin(); it != val.nulls.end(); ++it) + { + const vart &var = templ[*it].expr; + + if (vars.find(var) == vars.end()) continue; + + if (templ[*it].kind == LOOP) + c.push_back(implies_exprt(templ[*it].pre_guard, + equal_exprt(var, null_pointer_exprt(to_pointer_type(var.type()))))); + else + c.push_back(equal_exprt(var, null_pointer_exprt(to_pointer_type(var.type())))); + } + result = conjunction(c); +} diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h new file mode 100644 index 000000000..adccdd70d --- /dev/null +++ b/src/domains/heap_domain.h @@ -0,0 +1,89 @@ +/** + * Viktor Malik, 12.8.2016 (c). + */ +#ifndef CPROVER_HEAP_DOMAIN_H +#define CPROVER_HEAP_DOMAIN_H + +#include "domain.h" + +class heap_domaint : public domaint +{ + public: + + class pathst + { + public: + inline void insert_path(vart _from, vart _to, member_exprt _field) + { + paths.push_back(patht()); + patht path = paths.back(); + path.from = _from; + path.to = _to; + path.field = _field; + } + + inline void clear() { paths.clear(); } + + struct patht + { + vart from; + vart to; + member_exprt field; + }; + protected: + std::list paths; + }; + + typedef std::set index_sett; + + heap_domaint(unsigned int _domain_number, replace_mapt &_renaming_map, + const var_specst &var_specs, + const namespacet &ns) + : domaint(_domain_number, _renaming_map) + { + make_template(var_specs, ns); + } + + class heap_valuet : public valuet + { + public: + pathst paths; + index_sett nulls; + }; + + struct template_rowt + { + guardt pre_guard; + guardt post_guard; + exprt expr; + exprt aux_expr; + kindt kind; + }; + + typedef std::vector templatet; + + virtual void initialize(valuet &value) override; + + exprt get_pre_null_constraint(unsigned index); + + exprt get_post_not_null_constraint(unsigned index); + + virtual void output_value(std::ostream &out, const valuet &value, + const namespacet &ns) const override; + + virtual void output_domain(std::ostream &out, const namespacet &ns) const override; + + virtual void project_on_vars(valuet &value, const var_sett &vars, exprt &result) override; + + void set_null(unsigned index, heap_valuet &value); + + void get_index_set(std::set &indices); + + protected: + templatet templ; + + void make_template(const var_specst &var_specs, const namespacet &ns); +}; + + +#endif //CPROVER_HEAP_DOMAIN_H diff --git a/src/domains/ssa_analyzer.cpp b/src/domains/ssa_analyzer.cpp index 993ba4eea..d01654888 100644 --- a/src/domains/ssa_analyzer.cpp +++ b/src/domains/ssa_analyzer.cpp @@ -31,6 +31,7 @@ Author: Peter Schrammel #include "template_generator_ranking.h" #include "strategy_solver_predabs.h" #include "ssa_analyzer.h" +#include "strategy_solver_heap.h" #define BINSEARCH_SOLVER strategy_solver_binsearcht(\ *static_cast(domain), solver, SSA.ns) @@ -103,6 +104,12 @@ void ssa_analyzert::operator()( *static_cast(domain), solver, SSA.ns); result=new equality_domaint::equ_valuet(); } + else if(template_generator.options.get_bool_option("heap")) + { + strategy_solver=new strategy_solver_heapt( + *static_cast(domain), solver, SSA.ns); + result=new heap_domaint::heap_valuet(); + } else { if(template_generator.options.get_bool_option("enum-solver")) diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp new file mode 100644 index 000000000..88a4b78f8 --- /dev/null +++ b/src/domains/strategy_solver_heap.cpp @@ -0,0 +1,44 @@ +/** + * Viktor Malik, 12.8.2016 (c). + */ + +#include "strategy_solver_heap.h" + +bool strategy_solver_heapt::iterate(invariantt &_inv) +{ + heap_domaint::heap_valuet &inv = static_cast(_inv); + + auto n_it = todo_nulls.begin(); + if (n_it != todo_nulls.end()) // check NULL pointers + { + solver.new_context(); + + exprt pre_expr = heap_domain.get_pre_null_constraint(*n_it); + + solver << pre_expr; + + exprt post_expr = heap_domain.get_post_not_null_constraint(*n_it); + literalt cond_literal = solver.convert(post_expr); + + solver << literal_exprt(cond_literal); + + if (solver() == decision_proceduret::D_SATISFIABLE) + { + } + else // equality holds + { + heap_domain.set_null(*n_it, inv); + + solver << pre_expr; // make permanent + } + + solver.pop_context(); + + todo_nulls.erase(n_it); + return true; + } + else + { + return false; + } +} diff --git a/src/domains/strategy_solver_heap.h b/src/domains/strategy_solver_heap.h new file mode 100644 index 000000000..38eccdd9e --- /dev/null +++ b/src/domains/strategy_solver_heap.h @@ -0,0 +1,30 @@ +/** + * Viktor Malik, 12.8.2016 (c). + */ +#ifndef CPROVER_STRATEGY_SOLVER_HEAP_H +#define CPROVER_STRATEGY_SOLVER_HEAP_H + +#include "strategy_solver_base.h" +#include "heap_domain.h" + +class strategy_solver_heapt : public strategy_solver_baset +{ + public: + explicit strategy_solver_heapt(heap_domaint &_heap_domain, incremental_solvert &_solver, + const namespacet &_ns) + : strategy_solver_baset(_solver, _ns), heap_domain(_heap_domain) + { + heap_domain.get_index_set(todo_nulls); + } + + virtual bool iterate(invariantt &_inv) override; + + protected: + heap_domaint &heap_domain; + + typedef std::set worklistt; + worklistt todo_nulls; +}; + + +#endif //CPROVER_STRATEGY_SOLVER_HEAP_H diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index e62fa1649..05326a71a 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -16,6 +16,7 @@ Author: Peter Schrammel #include "equality_domain.h" #include "tpolyhedra_domain.h" #include "predabs_domain.h" +#include "heap_domain.h" #ifdef DEBUG #include @@ -263,6 +264,17 @@ void template_generator_baset::filter_equality_domain() } } +void template_generator_baset::filter_heap_domain() +{ + domaint::var_specst new_var_specs(var_specs); + var_specs.clear(); + for (auto var=new_var_specs.begin(); var!=new_var_specs.end(); ++var) + { + if (var->var.type().id()==ID_pointer) + var_specs.push_back(*var); + } +} + /*******************************************************************\ Function: template_generator_baset::add_var @@ -678,6 +690,11 @@ void template_generator_baset::instantiate_standard_domains( domain_ptr= new equality_domaint(domain_number, renaming_map, var_specs, SSA.ns); } + else if(options.get_bool_option("heap")) + { + filter_heap_domain(); + domain_ptr = new heap_domaint(domain_number, renaming_map, var_specs, SSA.ns); + } else if(options.get_bool_option("intervals")) { domain_ptr= diff --git a/src/domains/template_generator_base.h b/src/domains/template_generator_base.h index 1c9428da2..757d342fc 100644 --- a/src/domains/template_generator_base.h +++ b/src/domains/template_generator_base.h @@ -73,6 +73,7 @@ class template_generator_baset:public messaget void filter_template_domain(); void filter_equality_domain(); + void filter_heap_domain(); void add_var( const domaint::vart &var_to_add, From 8ee1b4f9bfcca72c59afb02587163c59527a4375 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 12 Aug 2016 17:14:34 +0100 Subject: [PATCH 013/322] Basic regression tests for pointer properties (collected from other test directories). --- regression/heap/Makefile | 20 ++++++++++++++++++++ regression/heap/pointer1/main.c | 12 ++++++++++++ regression/heap/pointer1/test.desc | 6 ++++++ regression/heap/pointer2/main.c | 14 ++++++++++++++ regression/heap/pointer2/test.desc | 6 ++++++ regression/heap/pointer3/main.c | 12 ++++++++++++ regression/heap/pointer3/test.desc | 6 ++++++ regression/heap/pointer4/main.c | 15 +++++++++++++++ regression/heap/pointer4/test.desc | 6 ++++++ regression/heap/pointer5/main.c | 15 +++++++++++++++ regression/heap/pointer5/test.desc | 6 ++++++ regression/heap/pointer6/main.c | 16 ++++++++++++++++ regression/heap/pointer6/test.desc | 6 ++++++ regression/heap/pointer7/main.c | 10 ++++++++++ regression/heap/pointer7/test.desc | 6 ++++++ 15 files changed, 156 insertions(+) create mode 100644 regression/heap/Makefile create mode 100644 regression/heap/pointer1/main.c create mode 100644 regression/heap/pointer1/test.desc create mode 100644 regression/heap/pointer2/main.c create mode 100644 regression/heap/pointer2/test.desc create mode 100644 regression/heap/pointer3/main.c create mode 100644 regression/heap/pointer3/test.desc create mode 100644 regression/heap/pointer4/main.c create mode 100644 regression/heap/pointer4/test.desc create mode 100644 regression/heap/pointer5/main.c create mode 100644 regression/heap/pointer5/test.desc create mode 100644 regression/heap/pointer6/main.c create mode 100644 regression/heap/pointer6/test.desc create mode 100644 regression/heap/pointer7/main.c create mode 100644 regression/heap/pointer7/test.desc diff --git a/regression/heap/Makefile b/regression/heap/Makefile new file mode 100644 index 000000000..d2ff74910 --- /dev/null +++ b/regression/heap/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/heap/pointer1/main.c b/regression/heap/pointer1/main.c new file mode 100644 index 000000000..34c87bb31 --- /dev/null +++ b/regression/heap/pointer1/main.c @@ -0,0 +1,12 @@ +void foo(int *x) +{ + *x = 10; +} + +void main() +{ + int x; + foo(&x); + assert(x==10); +} + diff --git a/regression/heap/pointer1/test.desc b/regression/heap/pointer1/test.desc new file mode 100644 index 000000000..9ebb38e34 --- /dev/null +++ b/regression/heap/pointer1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/pointer2/main.c b/regression/heap/pointer2/main.c new file mode 100644 index 000000000..02f54b869 --- /dev/null +++ b/regression/heap/pointer2/main.c @@ -0,0 +1,14 @@ +void foo(int *x) +{ + x++; + *x = 10; +} + +void main() +{ + int x[2]; + foo(&x); + int y = x[1]; + assert(y==10); +} + diff --git a/regression/heap/pointer2/test.desc b/regression/heap/pointer2/test.desc new file mode 100644 index 000000000..c90269dfc --- /dev/null +++ b/regression/heap/pointer2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/pointer3/main.c b/regression/heap/pointer3/main.c new file mode 100644 index 000000000..098f61866 --- /dev/null +++ b/regression/heap/pointer3/main.c @@ -0,0 +1,12 @@ +#include + +void main() +{ + int x = 0; + int *p = &x; + int *y = p; + for(int i=0;i<10;i++) y = p; + assert(p!=NULL); + assert(y!=NULL); + *y = *p; +} diff --git a/regression/heap/pointer3/test.desc b/regression/heap/pointer3/test.desc new file mode 100644 index 000000000..c90269dfc --- /dev/null +++ b/regression/heap/pointer3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/pointer4/main.c b/regression/heap/pointer4/main.c new file mode 100644 index 000000000..0119e4601 --- /dev/null +++ b/regression/heap/pointer4/main.c @@ -0,0 +1,15 @@ +#include + +int *foo() +{ + return NULL; +} + +void main() +{ + int x = 0; + int *p = &x; + int *y = p; + for(int i=0;i<10;i++) y = foo(); + assert(y==NULL); +} diff --git a/regression/heap/pointer4/test.desc b/regression/heap/pointer4/test.desc new file mode 100644 index 000000000..c90269dfc --- /dev/null +++ b/regression/heap/pointer4/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/pointer5/main.c b/regression/heap/pointer5/main.c new file mode 100644 index 000000000..6dc5d56aa --- /dev/null +++ b/regression/heap/pointer5/main.c @@ -0,0 +1,15 @@ +#include + +void foo(int **x) +{ + x = NULL; +} + +void main() +{ + int x = 0; + int *p = &x; + int *y = p; + for(int i=0;i<10;i++) foo(y); + assert(y==NULL); +} diff --git a/regression/heap/pointer5/test.desc b/regression/heap/pointer5/test.desc new file mode 100644 index 000000000..c90269dfc --- /dev/null +++ b/regression/heap/pointer5/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/pointer6/main.c b/regression/heap/pointer6/main.c new file mode 100644 index 000000000..676c04b24 --- /dev/null +++ b/regression/heap/pointer6/main.c @@ -0,0 +1,16 @@ +#include + +int *foo(int *x) +{ + return x; +} + +void main() +{ + int x = 0; + int *y; + + y = foo(&x); + + assert(y!=NULL); +} diff --git a/regression/heap/pointer6/test.desc b/regression/heap/pointer6/test.desc new file mode 100644 index 000000000..c90269dfc --- /dev/null +++ b/regression/heap/pointer6/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/pointer7/main.c b/regression/heap/pointer7/main.c new file mode 100644 index 000000000..28c9e0ab5 --- /dev/null +++ b/regression/heap/pointer7/main.c @@ -0,0 +1,10 @@ +#include + +void main() +{ + int x[10]; + int *end = &x[9]; + int *p = x; + for(; p!=end; p++); + assert(p==end); +} diff --git a/regression/heap/pointer7/test.desc b/regression/heap/pointer7/test.desc new file mode 100644 index 000000000..38318bb3b --- /dev/null +++ b/regression/heap/pointer7/test.desc @@ -0,0 +1,6 @@ +KNOWNBUG +main.c +--heap +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ From c62fc0d1c69909b931f5e1597ab971f26a3165be Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Wed, 17 Aug 2016 17:50:27 +0100 Subject: [PATCH 014/322] Heap domain: completely redo the domain. Now, the domain can find invariants for paths between pointer variables. --- src/domains/heap_domain.cpp | 228 +++++++++++++++++++++------ src/domains/heap_domain.h | 104 +++++++----- src/domains/strategy_solver_heap.cpp | 57 ++++--- src/domains/strategy_solver_heap.h | 5 +- 4 files changed, 279 insertions(+), 115 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 39f29982c..65260f45e 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -3,14 +3,27 @@ */ #include "heap_domain.h" +#include "util.h" +/** + * Initialize value. + * Clears each pointer destinations. + * @param value + */ void heap_domaint::initialize(domaint::valuet &value) { heap_valuet &val = static_cast(value); - val.paths.clear(); - val.nulls.clear(); + val.resize(templ.size()); + for (unsigned row = 0; row < templ.size(); ++row) + val[row].dests.clear(); } +/** + * Create domain template for given set of variables. + * Template contains only pointers to structures containing field 'next'. + * @param var_specs Set of program variables. + * @param ns Namespace + */ void heap_domaint::make_template(const domaint::var_specst &var_specs, const namespacet &ns) { unsigned long size = var_specs.size(); @@ -19,64 +32,157 @@ void heap_domaint::make_template(const domaint::var_specst &var_specs, const nam for (auto v1 = var_specs.begin(); v1 != var_specs.end(); ++v1) { - // Template for variable - for NULL pointer and dangling checks - templ.push_back(template_rowt()); - template_rowt &templ_row = templ.back(); - templ_row.expr = v1->var; - templ_row.pre_guard = v1->pre_guard; - templ_row.post_guard = v1->post_guard; - templ_row.aux_expr = v1->post_guard; - templ_row.kind = v1->kind; + // Check if v1 is struct and has 'next' field + bool has_next = false; + const vart &var1 = v1->var; + if (var1.type().id() == ID_pointer) + { + const typet &pointed_type = ns.follow(var1.type().subtype()); + if (pointed_type.id() == ID_struct) + { + for (auto &component : to_struct_type(pointed_type).components()) + { + if (component.get_name() == "next") + has_next = true; + } + } + } + + if (has_next) + { // Create template + templ.push_back(template_rowt()); + template_rowt &templ_row = templ.back(); + templ_row.expr = v1->var; + templ_row.pre_guard = v1->pre_guard; + templ_row.post_guard = v1->post_guard; + templ_row.aux_expr = v1->post_guard; + templ_row.kind = v1->kind; + } } } -exprt heap_domaint::get_pre_null_constraint(unsigned index) +/** + * Create entry constraints expression for a value. + * @param value Value + * @return Conjuction of entry expressions for each template row + */ +exprt heap_domaint::to_pre_constraints(const heap_domaint::heap_valuet &value) const { - assert(index < templ.size()); - const template_rowt &templ_row = templ[index]; - if (templ_row.kind == OUT || templ_row.kind == OUTL) return true_exprt(); - const vart &var = templ_row.expr; - return implies_exprt(templ_row.pre_guard, - equal_exprt(var, null_pointer_exprt(to_pointer_type(var.type())))); + assert(value.size() == templ.size()); + exprt::operandst c; + for (rowt row = 0; row < templ.size(); ++row) + { + c.push_back(get_row_pre_constraint(row, value[row])); + } + return conjunction(c); } -exprt heap_domaint::get_post_not_null_constraint(unsigned index) +/** + * Create exit constraint expression for each row. + * Each expression is negation of row expression (for solving exists forall problem). + * @param value Value + * @param cond_exprs Constraint expressions + * @param value_exprs Template expressions (variables) + */ +void heap_domaint::make_not_post_constraints(const heap_domaint::heap_valuet &value, + exprt::operandst &cond_exprs, + exprt::operandst &value_exprs) { - assert(index < templ.size()); - const template_rowt &templ_row = templ[index]; - if (templ_row.kind == IN) return true_exprt(); - const vart &var = templ_row.expr; - exprt c = and_exprt(templ_row.aux_expr, - not_exprt(implies_exprt(templ_row.post_guard, - equal_exprt(var, null_pointer_exprt( - to_pointer_type(var.type())))))); - rename(c); - return c; + assert(value.size() == templ.size()); + cond_exprs.resize(templ.size()); + value_exprs.resize(templ.size()); + + for (rowt row = 0; row < templ.size(); ++row) + { + value_exprs[row] = templ[row].expr; + rename(value_exprs[row]); + cond_exprs[row] = and_exprt(templ[row].aux_expr, + not_exprt(get_row_post_constraint(row, value[row]))); + } +} + +/** + * Create entry constraint expression for a row. + * @param row Row number + * @param row_value Row value + * @return Entry constraint expression. + */ +exprt heap_domaint::get_row_pre_constraint(const rowt &row, const row_valuet &row_value) const +{ + assert(row < templ.size()); + const template_rowt &templ_row = templ[row]; + kindt k = templ_row.kind; + // For exit variables the result is true + if (k == OUT || k == OUTL) return true_exprt(); + if (row_value.dests.empty()) + // Bottom is false + return implies_exprt(templ_row.pre_guard, false_exprt()); + return implies_exprt(templ_row.pre_guard, row_value.get_row_expr(templ_row.expr, ns)); } -void heap_domaint::set_null(unsigned index, heap_valuet &value) +/** + * Create exit constraint expression for a row. + * @param row Row number + * @param row_value Row value + * @return Exit constraint expression. + */ +exprt heap_domaint::get_row_post_constraint(const rowt &row, const row_valuet &row_value) { - assert(index < templ.size()); - value.nulls.insert(index); + assert(row < templ.size()); + const template_rowt &templ_row = templ[row]; + // For entry variables the result is true + if (templ_row.kind == IN) return true_exprt(); + if (row_value.dests.empty()) + // Bottom is false + return implies_exprt(templ_row.post_guard, false_exprt()); + exprt c = implies_exprt(templ_row.post_guard, row_value.get_row_expr(templ_row.expr, ns)); + if (templ_row.kind == LOOP) rename(c); + return c; } -void heap_domaint::get_index_set(std::set &indices) +/** + * Add new destination for a row + * @param row Row number + * @param value Value + * @param dest New destination to add + * @return True if insertion took place (dest did not exist in the row value) + */ +bool heap_domaint::add_row_dest(const heap_domaint::rowt &row, + heap_domaint::heap_valuet &value, + const exprt &dest) { - for (unsigned i = 0; i < templ.size(); i++) indices.insert(i); + assert(row < value.size()); + assert(value.size() == templ.size()); + auto new_dest = value[row].dests.insert(dest); + return new_dest.second; } void heap_domaint::output_value(std::ostream &out, const domaint::valuet &value, const namespacet &ns) const { - const heap_valuet &_val = static_cast(value); - heap_valuet val = _val; - - for (unsigned i = 0; i < templ.size(); ++i) + const heap_valuet &val = static_cast(value); + for (rowt row = 0; row < templ.size(); ++row) { - if (val.nulls.find(i) != val.nulls.end()) + const template_rowt &templ_row = templ[row]; + switch (templ_row.kind) { - out << from_expr(ns, "", templ[i].expr) << "== NULL" << std::endl; + case LOOP: + out << "(LOOP) [ " << from_expr(ns, "", templ_row.pre_guard) << " | "; + out << from_expr(ns, "", templ_row.post_guard) << " | "; + out << from_expr(ns, "", templ_row.aux_expr) << " ] ===> " << std::endl << " "; + break; + case IN: + out << "(IN) "; + break; + case OUT: + case OUTL: + out << "(OUT) "; + break; + default: + assert(false); } + out << "( " << from_expr(ns, "", templ_row.expr) << " == " + << from_expr(ns, "", val[row].get_row_expr(templ_row.expr, ns)) << " )" << std::endl; } } @@ -107,28 +213,52 @@ void heap_domaint::output_domain(std::ostream &out, const namespacet &ns) const default: assert(false); } - const vart var = templ_row.expr; - out << from_expr(ns, "", var) << " =!= NULL" << std::endl; + const vart &var = templ_row.expr; + out << "?path(" << from_expr(ns, "", var) << ", DESTINATIONS)" << std::endl; } } void heap_domaint::project_on_vars(domaint::valuet &value, const domaint::var_sett &vars, exprt &result) { - heap_valuet &val = static_cast(value); + const heap_valuet &val = static_cast(value); + assert(val.size() == templ.size()); exprt::operandst c; - for (auto it = val.nulls.begin(); it != val.nulls.end(); ++it) + for (rowt row = 0; row < templ.size(); ++row) { - const vart &var = templ[*it].expr; + const template_rowt &templ_row = templ[row]; - if (vars.find(var) == vars.end()) continue; + if (vars.find(templ_row.expr) == vars.end()) continue; - if (templ[*it].kind == LOOP) - c.push_back(implies_exprt(templ[*it].pre_guard, - equal_exprt(var, null_pointer_exprt(to_pointer_type(var.type()))))); + const row_valuet &row_val = val[row]; + if (templ_row.kind == LOOP) + { + if (row_val.dests.empty()) + c.push_back(implies_exprt(templ_row.pre_guard, false_exprt())); + else + c.push_back(implies_exprt(templ_row.pre_guard, row_val.get_row_expr(templ_row.expr, ns))); + } else - c.push_back(equal_exprt(var, null_pointer_exprt(to_pointer_type(var.type())))); + { + if (row_val.dests.empty()) + c.push_back(false_exprt()); + else + c.push_back(row_val.get_row_expr(templ_row.expr, ns)); + } } result = conjunction(c); } + +/** + * Converts constant returned from solver to corresponding expression. + * @param expr Solver expression + * @return + */ +exprt heap_domaint::value_to_ptr_exprt(const exprt &expr) +{ + if (expr.id() == ID_constant) + return expr.op0(); + + return expr; +} diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index adccdd70d..098ec3509 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -1,86 +1,112 @@ /** + * Abstract domain for representing heap. + * * Viktor Malik, 12.8.2016 (c). */ #ifndef CPROVER_HEAP_DOMAIN_H #define CPROVER_HEAP_DOMAIN_H +#include #include "domain.h" class heap_domaint : public domaint { public: - - class pathst - { - public: - inline void insert_path(vart _from, vart _to, member_exprt _field) - { - paths.push_back(patht()); - patht path = paths.back(); - path.from = _from; - path.to = _to; - path.field = _field; - } - - inline void clear() { paths.clear(); } - - struct patht - { - vart from; - vart to; - member_exprt field; - }; - protected: - std::list paths; - }; - - typedef std::set index_sett; + typedef unsigned rowt; heap_domaint(unsigned int _domain_number, replace_mapt &_renaming_map, const var_specst &var_specs, - const namespacet &ns) - : domaint(_domain_number, _renaming_map) + const namespacet &ns_) + : domaint(_domain_number, _renaming_map), ns(ns_) { make_template(var_specs, ns); } - class heap_valuet : public valuet + /** + * Value of a row is set of addresses reachable from pointer (corresponding to template row) via + * field 'next'. + */ + struct row_valuet + { + std::set dests; + + /** + * Get expression for the row value. The expression has form of disjuncion of equalities. + * Equality can be: + * (templ_expr == NULL) when pointer is NULL + * (templ_expr->next == dest) when pointer points to dest via 'next' field + * @param templ_expr Pointer variable of the template row + * @param ns Namespace + * @return Expression corresponding to value - disjunction of equalities. + */ + exprt get_row_expr(const vart &templ_expr, const namespacet &ns) const + { + exprt::operandst dis; + for (auto dest : dests) + { + if (dest.id() == ID_constant && to_constant_expr(dest).get_value() == ID_NULL) + dis.push_back(equal_exprt(templ_expr, dest)); + else + { + assert(templ_expr.type().id() == ID_pointer); + const typet &struct_type = templ_expr.type().subtype(); + dis.push_back( + equal_exprt(member_exprt(dereference_exprt(templ_expr, struct_type), + "next", + dest.type()), + dest)); + } + } + return disjunction(dis); + } + }; + + class heap_valuet : public valuet, public std::vector { - public: - pathst paths; - index_sett nulls; }; struct template_rowt { guardt pre_guard; guardt post_guard; - exprt expr; + vart expr; exprt aux_expr; kindt kind; }; - typedef std::vector templatet; + // Initialize value virtual void initialize(valuet &value) override; - exprt get_pre_null_constraint(unsigned index); + // Value -> constraints + exprt to_pre_constraints(const heap_valuet &value) const; - exprt get_post_not_null_constraint(unsigned index); + void make_not_post_constraints(const heap_valuet &value, exprt::operandst &cond_exprs, + exprt::operandst &value_exprs); + // Row -> constraints + exprt get_row_pre_constraint(const rowt &row, const row_valuet &row_value) const; + + exprt get_row_post_constraint(const rowt &row, const row_valuet &row_value); + + // Add new destination to a row + bool add_row_dest(const rowt &row, heap_valuet &value, const exprt &dest); + + // Printing virtual void output_value(std::ostream &out, const valuet &value, const namespacet &ns) const override; virtual void output_domain(std::ostream &out, const namespacet &ns) const override; + // Projection virtual void project_on_vars(valuet &value, const var_sett &vars, exprt &result) override; - void set_null(unsigned index, heap_valuet &value); - - void get_index_set(std::set &indices); + // Conversion of solver value to expression + static exprt value_to_ptr_exprt(const exprt &expr); protected: templatet templ; + namespacet ns; void make_template(const var_specst &var_specs, const namespacet &ns); }; diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index 88a4b78f8..cac61907b 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -8,37 +8,48 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) { heap_domaint::heap_valuet &inv = static_cast(_inv); - auto n_it = todo_nulls.begin(); - if (n_it != todo_nulls.end()) // check NULL pointers - { - solver.new_context(); + bool improved = false; - exprt pre_expr = heap_domain.get_pre_null_constraint(*n_it); + solver.new_context(); - solver << pre_expr; + // Entry value constraints + exprt pre_expr = heap_domain.to_pre_constraints(inv); + solver << pre_expr; - exprt post_expr = heap_domain.get_post_not_null_constraint(*n_it); - literalt cond_literal = solver.convert(post_expr); + // Exit value constraints + exprt::operandst strategy_cond_exprs; + heap_domain.make_not_post_constraints(inv, strategy_cond_exprs, strategy_value_exprs); - solver << literal_exprt(cond_literal); + strategy_cond_literals.resize(strategy_cond_exprs.size()); - if (solver() == decision_proceduret::D_SATISFIABLE) - { - } - else // equality holds + for (unsigned i = 0; i < strategy_cond_exprs.size(); ++i) + { + strategy_cond_literals[i] = solver.convert(strategy_cond_exprs[i]); + strategy_cond_exprs[i] = literal_exprt(strategy_cond_literals[i]); + } + solver << disjunction(strategy_cond_exprs); + + if (solver() == decision_proceduret::D_SATISFIABLE) // improvement check + { + for (unsigned row = 0; row < strategy_cond_literals.size(); ++row) { - heap_domain.set_null(*n_it, inv); + if (solver.l_get(strategy_cond_literals[row]).is_true()) + { + debug() << "updating row: " << row << eom; - solver << pre_expr; // make permanent - } + exprt value = solver.get(strategy_value_exprs[row]); + // Value from solver must be converted into expression + exprt dest = heap_domain.value_to_ptr_exprt(value); - solver.pop_context(); + debug() << "destination: " << from_expr(ns, "", dest) << eom; - todo_nulls.erase(n_it); - return true; - } - else - { - return false; + if (heap_domain.add_row_dest(row, inv, dest)) + improved = true; + } + } } + solver.pop_context(); + + return improved; + } diff --git a/src/domains/strategy_solver_heap.h b/src/domains/strategy_solver_heap.h index 38eccdd9e..2de00e769 100644 --- a/src/domains/strategy_solver_heap.h +++ b/src/domains/strategy_solver_heap.h @@ -1,4 +1,5 @@ /** + * Strategy solver for heap verification. * Viktor Malik, 12.8.2016 (c). */ #ifndef CPROVER_STRATEGY_SOLVER_HEAP_H @@ -14,16 +15,12 @@ class strategy_solver_heapt : public strategy_solver_baset const namespacet &_ns) : strategy_solver_baset(_solver, _ns), heap_domain(_heap_domain) { - heap_domain.get_index_set(todo_nulls); } virtual bool iterate(invariantt &_inv) override; protected: heap_domaint &heap_domain; - - typedef std::set worklistt; - worklistt todo_nulls; }; From 4d56989dc9aa88be6f0ac020ba9559cd4f15bece Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Wed, 17 Aug 2016 17:53:15 +0100 Subject: [PATCH 015/322] Programs using malloc don't need to be fully inlined. Inlines only malloc and free functions. --- src/2ls/2ls_parse_options.cpp | 21 +++++++++++++++++++-- src/ssa/malloc_ssa.cpp | 4 +++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 6551755c4..5ef232136 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -1112,8 +1112,25 @@ bool twols_parse_optionst::process_goto_program( #endif #if 1 - // TODO: find a better place for that - replace_malloc(goto_model, ""); + // Find, inline and remove malloc function + //TODO: find a better place for that + Forall_goto_functions(it, goto_model.goto_functions) + { + if (it->first == "malloc" || it->first == "free") + it->second.type.set(ID_C_inlined, true); + } + goto_partial_inline(goto_model, ui_message_handler, 0); + Forall_goto_functions(it, goto_model.goto_functions) + { + if (it->first == "malloc" || it->first == "free") + it->second.body.clear(); + } + // Replace malloc + replace_malloc(goto_model,""); +#endif + +#if REMOVE_MULTIPLE_DEREFERENCES + remove_multiple_dereferences(goto_model); #endif // recalculate numbers, etc. diff --git a/src/ssa/malloc_ssa.cpp b/src/ssa/malloc_ssa.cpp index fd5246b4e..9e2263f9b 100644 --- a/src/ssa/malloc_ssa.cpp +++ b/src/ssa/malloc_ssa.cpp @@ -15,6 +15,8 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include +#include #include "malloc_ssa.h" @@ -222,7 +224,7 @@ void replace_malloc( exprt malloc_size=nil_exprt(); Forall_goto_program_instructions(i_it, f_it->second.body) { - if(i_it->is_assign()) + if (i_it->is_assign()) { code_assignt &code_assign=to_code_assign(i_it->code); if(code_assign.lhs().id()==ID_symbol) From 17fc7d48460fa1d8f09696f6deb49f302d42e680 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 18 Aug 2016 11:18:41 +0100 Subject: [PATCH 016/322] Heap domain: printing solver debug information --- src/domains/heap_domain.h | 2 + src/domains/strategy_solver_heap.cpp | 59 ++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index 098ec3509..47e4e8083 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -109,6 +109,8 @@ class heap_domaint : public domaint namespacet ns; void make_template(const var_specst &var_specs, const namespacet &ns); + + friend class strategy_solver_heapt; }; diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index cac61907b..030a7c92d 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -14,6 +14,9 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) // Entry value constraints exprt pre_expr = heap_domain.to_pre_constraints(inv); +#ifdef DEBUG_OUTPUT + debug() << "pre-inv: " << from_expr(ns,"",pre_expr) << eom; +#endif solver << pre_expr; // Exit value constraints @@ -22,15 +25,55 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) strategy_cond_literals.resize(strategy_cond_exprs.size()); +#ifdef DEBUG_OUTPUT + debug() << "post-inv: "; +#endif for (unsigned i = 0; i < strategy_cond_exprs.size(); ++i) { +#ifdef DEBUG_OUTPUT + debug() << (i>0 ? " || " : "") << from_expr(ns,"",strategy_cond_exprs[i]) ; +#endif strategy_cond_literals[i] = solver.convert(strategy_cond_exprs[i]); strategy_cond_exprs[i] = literal_exprt(strategy_cond_literals[i]); } +#ifdef DEBUG_OUTPUT + debug() << eom; +#endif solver << disjunction(strategy_cond_exprs); + #ifdef DEBUG_OUTPUT + debug() << "solve(): "; +#endif + if (solver() == decision_proceduret::D_SATISFIABLE) // improvement check { +#ifdef DEBUG_OUTPUT + debug() << "SAT" << eom; +#endif + +#ifdef DEBUG_OUTPUT + for(unsigned i=0; iis_in_conflict(solver.formula[i])) + debug() << "is_in_conflict: " << solver.formula[i] << eom; + else + debug() << "not_in_conflict: " << solver.formula[i] << eom; + } +#endif + } solver.pop_context(); return improved; From 500bd9d5610033964a8cddf86e35b95b22a68bb2 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 26 Aug 2016 12:35:58 +0100 Subject: [PATCH 017/322] Heap domain: improve inference of 'path' predicates. Not working for loops with nondeterministic number of iterations. --- src/domains/heap_domain.cpp | 148 ++++++++++++++++++++++----- src/domains/heap_domain.h | 115 ++++++++++++++++----- src/domains/strategy_solver_heap.cpp | 128 +++++++++++++++++++---- src/domains/strategy_solver_heap.h | 2 + 4 files changed, 321 insertions(+), 72 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 65260f45e..ee5eed64a 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -4,10 +4,12 @@ #include "heap_domain.h" #include "util.h" +#include +#include /** * Initialize value. - * Clears each pointer destinations. + * Clears each pointer paths and points_to predicates. * @param value */ void heap_domaint::initialize(domaint::valuet &value) @@ -15,7 +17,10 @@ void heap_domaint::initialize(domaint::valuet &value) heap_valuet &val = static_cast(value); val.resize(templ.size()); for (unsigned row = 0; row < templ.size(); ++row) - val[row].dests.clear(); + { + val[row].paths.clear(); + val[row].points_to.clear(); + } } /** @@ -57,6 +62,9 @@ void heap_domaint::make_template(const domaint::var_specst &var_specs, const nam templ_row.post_guard = v1->post_guard; templ_row.aux_expr = v1->post_guard; templ_row.kind = v1->kind; + // Check if the pointer itself is field of a dynamic object + const std::string identifier = id2string(to_symbol_expr(v1->var).get_identifier()); + templ_row.dynamic = identifier.find("dynamic_object$") != std::string::npos; } } } @@ -81,11 +89,10 @@ exprt heap_domaint::to_pre_constraints(const heap_domaint::heap_valuet &value) c * Create exit constraint expression for each row. * Each expression is negation of row expression (for solving exists forall problem). * @param value Value - * @param cond_exprs Constraint expressions - * @param value_exprs Template expressions (variables) + * @param cond_exprs Output - constraint expressions + * @param value_exprs Output - template expressions (row variables) */ -void heap_domaint::make_not_post_constraints(const heap_domaint::heap_valuet &value, - exprt::operandst &cond_exprs, +void heap_domaint::make_not_post_constraints(const heap_valuet &value, exprt::operandst &cond_exprs, exprt::operandst &value_exprs) { assert(value.size() == templ.size()); @@ -114,10 +121,8 @@ exprt heap_domaint::get_row_pre_constraint(const rowt &row, const row_valuet &ro kindt k = templ_row.kind; // For exit variables the result is true if (k == OUT || k == OUTL) return true_exprt(); - if (row_value.dests.empty()) - // Bottom is false - return implies_exprt(templ_row.pre_guard, false_exprt()); - return implies_exprt(templ_row.pre_guard, row_value.get_row_expr(templ_row.expr, ns)); + + return implies_exprt(templ_row.pre_guard, row_value.get_row_expr(templ_row.expr)); } /** @@ -132,10 +137,8 @@ exprt heap_domaint::get_row_post_constraint(const rowt &row, const row_valuet &r const template_rowt &templ_row = templ[row]; // For entry variables the result is true if (templ_row.kind == IN) return true_exprt(); - if (row_value.dests.empty()) - // Bottom is false - return implies_exprt(templ_row.post_guard, false_exprt()); - exprt c = implies_exprt(templ_row.post_guard, row_value.get_row_expr(templ_row.expr, ns)); + + exprt c = implies_exprt(templ_row.post_guard, row_value.get_row_expr(templ_row.expr)); if (templ_row.kind == LOOP) rename(c); return c; } @@ -145,16 +148,78 @@ exprt heap_domaint::get_row_post_constraint(const rowt &row, const row_valuet &r * @param row Row number * @param value Value * @param dest New destination to add + * @param dyn_obj Dynamic object for that the path passes through (is nil if path can have zero + * length). * @return True if insertion took place (dest did not exist in the row value) */ -bool heap_domaint::add_row_dest(const heap_domaint::rowt &row, - heap_domaint::heap_valuet &value, - const exprt &dest) +bool heap_domaint::add_row_path(const rowt &row, heap_valuet &value, const exprt &dest, + const dyn_objt &dyn_obj) { assert(row < value.size()); assert(value.size() == templ.size()); - auto new_dest = value[row].dests.insert(dest); - return new_dest.second; + + auto &path_set = value[row].paths; + + if (path_set.find(dest) == path_set.end()) + { + // Path does not exist yet + std::set dyn_obj_set; + bool zero_path = true; + if (dyn_obj.first.id() != ID_nil) + { // Path doesn't have zero length + dyn_obj_set.insert(dyn_obj); + zero_path = false; + } + path_set.emplace(dest, dyn_obj_set, zero_path); + return true; + } + else + { + // Path exists already + if (dyn_obj.first.id() == ID_nil) return false; + // Try to insert new dynamic object belonging to the path + return path_set.find(dest)->dyn_objects.insert(dyn_obj).second; + } +} + +/** + * Add all paths of one pointer as the destinations of another pointer. + * @param to Row to add new paths to + * @param from Row to add paths from + * @param value Heap value + * @param dyn_obj Dynamic object that all the paths pass through (it belongs to path segment from + * one pointer to another. + * @return True if any path was added or changed, otherwise false. + */ +bool heap_domaint::add_all_paths(const rowt &to, const rowt &from, heap_valuet &value, + const dyn_objt &dyn_obj) +{ + bool result = false; + for (auto &path : value[from].paths) + { + // Add the path with new dynamic object + if (add_row_path(to, value, path.destination, dyn_obj)) + result = true; + for (auto &o : path.dyn_objects) + { // Add all dynamic objects of the original path + if (add_row_path(to, value, path.destination, o)) + result = true; + } + } + return result; +} + +/** + * Add new points to address to a row. + * @param row Value row + * @param value Heap value + * @param dyn_obj New dynamic object that the row variable can point to. + * @return True if the object was really added. + */ +bool heap_domaint::add_points_to(const rowt &row, heap_valuet &value, const dyn_objt &dyn_obj) +{ + auto new_pt = value[row].points_to.insert(dyn_obj); + return new_pt.second; } void heap_domaint::output_value(std::ostream &out, const domaint::valuet &value, @@ -182,7 +247,8 @@ void heap_domaint::output_value(std::ostream &out, const domaint::valuet &value, assert(false); } out << "( " << from_expr(ns, "", templ_row.expr) << " == " - << from_expr(ns, "", val[row].get_row_expr(templ_row.expr, ns)) << " )" << std::endl; + << from_expr(ns, "", val[row].get_row_expr(templ_row.expr)) << " )" + << std::endl; } } @@ -234,17 +300,18 @@ void heap_domaint::project_on_vars(domaint::valuet &value, const row_valuet &row_val = val[row]; if (templ_row.kind == LOOP) { - if (row_val.dests.empty()) + if (row_val.paths.empty()) c.push_back(implies_exprt(templ_row.pre_guard, false_exprt())); else - c.push_back(implies_exprt(templ_row.pre_guard, row_val.get_row_expr(templ_row.expr, ns))); + c.push_back(implies_exprt(templ_row.pre_guard, + row_val.get_row_expr(templ_row.expr))); } else { - if (row_val.dests.empty()) + if (row_val.paths.empty()) c.push_back(false_exprt()); else - c.push_back(row_val.get_row_expr(templ_row.expr, ns)); + c.push_back(row_val.get_row_expr(templ_row.expr)); } } result = conjunction(c); @@ -262,3 +329,36 @@ exprt heap_domaint::value_to_ptr_exprt(const exprt &expr) return expr; } + +/** + * Join two abstract heap values. Join of each row is union of the two corresponding sets. + * @param value1 First value and result of join + * @param value2 Second value + */ +void heap_domaint::join(domaint::valuet &value1, const domaint::valuet &value2) +{ + heap_valuet &val1 = static_cast(value1); + const heap_valuet &val2 = static_cast(value2); + assert(val1.size() == templ.size()); + assert(val2.size() == val1.size()); + for (rowt row = 0; row < templ.size(); ++row) + { // Insert all elements of second set to first + val1[row].paths.insert(val2[row].paths.begin(), val2[row].paths.end()); + } +} + +/** + * Check whether expression is NULL pointer. + * @param expr Expression to check + * @return True if expr is NULL pointer + */ +bool heap_domaint::is_null_ptr(const exprt &expr) +{ + if (expr.id() == ID_constant && to_constant_expr(expr).get_value() == ID_NULL) + return true; + if (expr.id() == ID_plus) + return is_null_ptr(expr.op0()) || is_null_ptr(expr.op1()); + if (expr.id() == ID_typecast) + return is_null_ptr(to_typecast_expr(expr).op()); + return false; +} diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index 47e4e8083..55a08cd83 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -13,6 +13,8 @@ class heap_domaint : public domaint { public: typedef unsigned rowt; + typedef vart next_fieldt; + typedef std::pair dyn_objt; heap_domaint(unsigned int _domain_number, replace_mapt &_renaming_map, const var_specst &var_specs, @@ -23,41 +25,91 @@ class heap_domaint : public domaint } /** - * Value of a row is set of addresses reachable from pointer (corresponding to template row) via - * field 'next'. + * Value of a row is set of paths in the heap leading from row variable */ struct row_valuet { - std::set dests; + /** + * Path in a heap. Contains: + * - destination object + * - set of dynamic objects - this is the set of ssa objects that the path is composed of + * - boolean value expressing whether path can have zero length + * Paths are ordered by destination only as it is unique within a value row. + */ + struct patht + { + exprt destination; + mutable std::set dyn_objects; + mutable bool zero_length; + + patht(const exprt &dest_) : destination(dest_) {} + + patht(const exprt &dest_, const std::set &dyn_objs_, const bool zero_l_) + : destination(dest_), dyn_objects(dyn_objs_), zero_length(zero_l_) {} + + bool operator<(const patht &rhs) const + { + return destination < rhs.destination; + } + + bool operator==(const patht &rhs) const + { + return destination == rhs.destination; + } + }; + + std::set paths; /**< Set of paths leading from the row variable */ + std::set points_to; /**< Set of objects the row variable can point to */ /** - * Get expression for the row value. The expression has form of disjuncion of equalities. - * Equality can be: - * (templ_expr == NULL) when pointer is NULL - * (templ_expr->next == dest) when pointer points to dest via 'next' field + * Get expression for the row value. It is a conjunction of path expressions. + * Expression of path leading from variable 'p' to destination 'd' via set of objects 'O' + * has form: + * p = d || if path can have zero length + * p = &o && (o.next = d || o.next = o') where o,o' belong to O and p can point to &o * @param templ_expr Pointer variable of the template row - * @param ns Namespace - * @return Expression corresponding to value - disjunction of equalities. + * @return Row value expression in the described form */ - exprt get_row_expr(const vart &templ_expr, const namespacet &ns) const + exprt get_row_expr(const vart &templ_expr) const { - exprt::operandst dis; - for (auto dest : dests) - { - if (dest.id() == ID_constant && to_constant_expr(dest).get_value() == ID_NULL) - dis.push_back(equal_exprt(templ_expr, dest)); - else + if (paths.empty()) return false_exprt(); + exprt::operandst result; + + for (auto &path : paths) + { // path(p, d)[O] + const exprt &dest = path.destination; + exprt::operandst path_expr; + + if (path.zero_length) { - assert(templ_expr.type().id() == ID_pointer); - const typet &struct_type = templ_expr.type().subtype(); - dis.push_back( - equal_exprt(member_exprt(dereference_exprt(templ_expr, struct_type), - "next", - dest.type()), - dest)); + // p = d + path_expr.push_back(equal_exprt(templ_expr, dest)); } + for (const dyn_objt &obj1 : path.dyn_objects) + { + if (points_to.find(obj1) != points_to.end()) + { + // p = &o + exprt equ_exprt = equal_exprt(templ_expr, address_of_exprt(obj1.first)); + + exprt::operandst step_expr; + exprt next_expr = obj1.second; + // o.next = d + step_expr.push_back(equal_exprt(next_expr, dest)); + + for (auto &obj2 : path.dyn_objects) + { // o.next = o' + step_expr.push_back(equal_exprt(next_expr, address_of_exprt(obj2.first))); + } + + path_expr.push_back(and_exprt(equ_exprt, disjunction(step_expr))); + } + } + + result.push_back(disjunction(path_expr)); } - return disjunction(dis); + + return conjunction(result); } }; @@ -72,6 +124,7 @@ class heap_domaint : public domaint vart expr; exprt aux_expr; kindt kind; + bool dynamic; }; typedef std::vector templatet; @@ -89,8 +142,13 @@ class heap_domaint : public domaint exprt get_row_post_constraint(const rowt &row, const row_valuet &row_value); - // Add new destination to a row - bool add_row_dest(const rowt &row, heap_valuet &value, const exprt &dest); + // Add new predicates to a row value (path, or points_to) + bool add_row_path(const rowt &row, heap_valuet &value, const exprt &dest, + const dyn_objt &dyn_obj); + + bool add_all_paths(const rowt &to, const rowt &from, heap_valuet &value, const dyn_objt &dyn_obj); + + bool add_points_to(const rowt &row, heap_valuet &value, const dyn_objt &dyn_obj); // Printing virtual void output_value(std::ostream &out, const valuet &value, @@ -104,6 +162,11 @@ class heap_domaint : public domaint // Conversion of solver value to expression static exprt value_to_ptr_exprt(const exprt &expr); + // Join of values + virtual void join(valuet &value1, const valuet &value2) override; + + static bool is_null_ptr(const exprt &expr); + protected: templatet templ; namespacet ns; diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index 030a7c92d..ef3d6dba0 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -2,6 +2,8 @@ * Viktor Malik, 12.8.2016 (c). */ +//#define DEBUG_OUTPUT + #include "strategy_solver_heap.h" bool strategy_solver_heapt::iterate(invariantt &_inv) @@ -15,7 +17,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) // Entry value constraints exprt pre_expr = heap_domain.to_pre_constraints(inv); #ifdef DEBUG_OUTPUT - debug() << "pre-inv: " << from_expr(ns,"",pre_expr) << eom; + debug() << "pre-inv: " << from_expr(ns, "", pre_expr) << eom; #endif solver << pre_expr; @@ -31,7 +33,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) for (unsigned i = 0; i < strategy_cond_exprs.size(); ++i) { #ifdef DEBUG_OUTPUT - debug() << (i>0 ? " || " : "") << from_expr(ns,"",strategy_cond_exprs[i]) ; + debug() << (i > 0 ? " || " : "") << from_expr(ns, "", strategy_cond_exprs[i]); #endif strategy_cond_literals[i] = solver.convert(strategy_cond_exprs[i]); strategy_cond_exprs[i] = literal_exprt(strategy_cond_literals[i]); @@ -41,7 +43,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) #endif solver << disjunction(strategy_cond_exprs); - #ifdef DEBUG_OUTPUT +#ifdef DEBUG_OUTPUT debug() << "solve(): "; #endif @@ -52,25 +54,28 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) #endif #ifdef DEBUG_OUTPUT - for(unsigned i=0; i= 0); + exprt next_val_expr = heap_domain.templ[next_val_index].expr; + + // Add all paths from obj.next to p + if (heap_domain.add_all_paths(row, (unsigned) next_val_index, inv, + std::make_pair(obj, next_val_expr))) + improved = true; + debug() << "add all paths: " << from_expr(ns, "", next_val_expr) << ", through: " + << from_expr(ns, "", obj) << eom; + + if (obj.type().get_bool("#dynamic")) + { // Add points to information + assert(obj.id() == ID_symbol); + if (heap_domain.add_points_to(row, inv, std::make_pair(obj, next_val_expr))) + improved = true; + debug() << "add points to: " << from_expr(ns, "", obj) << eom; + } + } + + if (heap_domain.templ[row].dynamic) + { // Recursively check all expressions and update those that point to the dynamic object + // that this row variable belongs to. + for (unsigned j = 0; j < heap_domain.templ.size(); ++j) + { + for (auto &pt : inv[j].points_to) + { + exprt pre_pointer = heap_domain.templ[row].expr; + if (pre_pointer == pt.second) + { + if (heap_domain.add_all_paths(j, row, inv, pt)) + improved = true; + debug() << "recursively updating row: " << j << eom; + debug() << "add all paths: " << from_expr(ns, "", pre_pointer) << ", through: " + << from_expr(ns, "", pt.first) << eom; + } + } + } + } } } } + else { #ifdef DEBUG_OUTPUT @@ -98,17 +155,44 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) #endif #ifdef DEBUG_OUTPUT - for(unsigned i=0; iis_in_conflict(solver.formula[i])) + if (solver.solver->is_in_conflict(solver.formula[i])) debug() << "is_in_conflict: " << solver.formula[i] << eom; else debug() << "not_in_conflict: " << solver.formula[i] << eom; - } + } #endif } solver.pop_context(); return improved; +} + +/** + * Find the template row that contains next field of given object as row variable. + * @param obj + * @return Template row of obj.next + */ +int strategy_solver_heapt::next_field_row(const exprt &obj) const +{ + // Create "next" member expression + exprt next_expr = member_exprt(obj, "next", pointer_typet(obj.type())); + std::string next_expr_id = from_expr(ns, "", next_expr); + + int result = -1; + for (unsigned i = 0; i < strategy_value_exprs.size(); ++i) + { // Find the corresponding strategy value expression + exprt val_expr = strategy_value_exprs[i]; + assert(val_expr.id() == ID_symbol); + std::string val_expr_id = id2string(to_symbol_expr(val_expr).get_identifier()); + // Compare identifiers of row expression and "next" member expresssion + if (val_expr_id.find(next_expr_id) != std::string::npos) + { + result = i; + break; + } + } + return result; } diff --git a/src/domains/strategy_solver_heap.h b/src/domains/strategy_solver_heap.h index 2de00e769..09f000b98 100644 --- a/src/domains/strategy_solver_heap.h +++ b/src/domains/strategy_solver_heap.h @@ -21,6 +21,8 @@ class strategy_solver_heapt : public strategy_solver_baset protected: heap_domaint &heap_domain; + + int next_field_row(const exprt &obj) const; }; From d9976b1b33fb23acef0cc6084fa3c62b54281d47 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 26 Aug 2016 12:41:00 +0100 Subject: [PATCH 018/322] Regression tests for single linked lists. --- regression/heap/sll1_simple/main.c | 69 +++++++++++ regression/heap/sll1_simple/test.desc | 6 + regression/heap/sll2_nondet_loops/main.c | 66 ++++++++++ regression/heap/sll2_nondet_loops/test.desc | 6 + regression/heap/sll_to_dll1_reverse/main.c | 114 ++++++++++++++++++ regression/heap/sll_to_dll1_reverse/test.desc | 6 + 6 files changed, 267 insertions(+) create mode 100644 regression/heap/sll1_simple/main.c create mode 100644 regression/heap/sll1_simple/test.desc create mode 100644 regression/heap/sll2_nondet_loops/main.c create mode 100644 regression/heap/sll2_nondet_loops/test.desc create mode 100644 regression/heap/sll_to_dll1_reverse/main.c create mode 100644 regression/heap/sll_to_dll1_reverse/test.desc diff --git a/regression/heap/sll1_simple/main.c b/regression/heap/sll1_simple/main.c new file mode 100644 index 000000000..ef5784cb8 --- /dev/null +++ b/regression/heap/sll1_simple/main.c @@ -0,0 +1,69 @@ +#include + +extern int __VERIFIER_nondet_int(void); + +struct node { + struct node *next; +}; + +static struct node* alloc_node(void) +{ + struct node *ptr = malloc(sizeof *ptr); + if (!ptr) + abort(); + + ptr->next = NULL; + return ptr; +} + +static void chain_node(struct node **ppnode) +{ + struct node *node = alloc_node(); + node->next = *ppnode; + *ppnode = node; +} + +static struct node* create_sll(const struct node **pp1, const struct node **pp2) +{ + *pp2 = NULL; + + for (int i = 0; i < 2; ++i) + { + chain_node(pp2); + } + + *pp1 = *pp2; + + for (int i = 0; i < 2; ++i) + { + chain_node(pp1); + } + + struct node *list = *pp1; + + for (int i = 0; i < 2; ++i) + { + chain_node(&list); + } + + return list; +} + +void check_seq_next(const struct node *beg, const struct node *const end) { + assert(beg != NULL); + assert(end != NULL); + + for (beg = beg->next; end != beg; beg = beg->next) + assert(beg != NULL); +} + +void main() +{ + const struct node *p1, *p2; + + struct node *list = create_sll(&p1, &p2); + check_seq_next(list, p1); + check_seq_next(p1, p2); + +} + diff --git a/regression/heap/sll1_simple/test.desc b/regression/heap/sll1_simple/test.desc new file mode 100644 index 000000000..ed14b476a --- /dev/null +++ b/regression/heap/sll1_simple/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap --inline --no-propagation +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/sll2_nondet_loops/main.c b/regression/heap/sll2_nondet_loops/main.c new file mode 100644 index 000000000..5f44c5a68 --- /dev/null +++ b/regression/heap/sll2_nondet_loops/main.c @@ -0,0 +1,66 @@ +#include + +extern int __VERIFIER_nondet_int(void); + +struct node { + struct node *next; +}; + +static struct node* alloc_node(void) +{ + struct node *ptr = malloc(sizeof *ptr); + if (!ptr) + abort(); + + ptr->next = NULL; + return ptr; +} + +static void chain_node(struct node **ppnode) +{ + struct node *node = alloc_node(); + node->next = *ppnode; + *ppnode = node; +} + +static struct node* create_sll(const struct node **pp1, const struct node **pp2) +{ + *pp2 = NULL; + + do + chain_node(pp2); + while (__VERIFIER_nondet_int()); + + *pp1 = *pp2; + + do + chain_node(pp1); + while (__VERIFIER_nondet_int()); + + struct node *list = *pp1; + + do + chain_node(&list); + while (__VERIFIER_nondet_int()); + + return list; +} + +void check_seq_next(const struct node *beg, const struct node *const end) { + assert(beg != NULL); + assert(end != NULL); + + for (beg = beg->next; end != beg; beg = beg->next) + assert(beg != NULL); +} + +void main() +{ + const struct node *p1, *p2; + + struct node *list = create_sll(&p1, &p2); + check_seq_next(list, p1); + check_seq_next(p1, p2); + +} + diff --git a/regression/heap/sll2_nondet_loops/test.desc b/regression/heap/sll2_nondet_loops/test.desc new file mode 100644 index 000000000..ed14b476a --- /dev/null +++ b/regression/heap/sll2_nondet_loops/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap --inline --no-propagation +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/sll_to_dll1_reverse/main.c b/regression/heap/sll_to_dll1_reverse/main.c new file mode 100644 index 000000000..e8d0d1829 --- /dev/null +++ b/regression/heap/sll_to_dll1_reverse/main.c @@ -0,0 +1,114 @@ +#include + +extern int __VERIFIER_nondet_int(void); + +struct node { + struct node *next; + struct node *prev; +}; + +static struct node* alloc_node(void) +{ + struct node *ptr = malloc(sizeof *ptr); + if (!ptr) + abort(); + + ptr->next = NULL; + ptr->prev = NULL; + return ptr; +} + +static void chain_node(struct node **ppnode) +{ + struct node *node = alloc_node(); + node->next = *ppnode; + *ppnode = node; +} + +static struct node* create_sll(const struct node **pp1, const struct node **pp2) +{ + *pp2 = NULL; + + do + chain_node(pp2); + while (__VERIFIER_nondet_int()); + + *pp1 = *pp2; + + while (__VERIFIER_nondet_int()) + chain_node(pp1); + + struct node *list = *pp1; + + do + chain_node(&list); + while (__VERIFIER_nondet_int()); + + return list; +} + +void init_back_link(struct node *list) { + for (;;) { + struct node *next = list->next; + if (!next) + return; + + next->prev = list; + list = next; + } +} + +void reverse_dll(struct node *list) { + while (list) { + struct node *next = list->next; + list->next = list->prev; + list->prev = next; + list = next; + } +} + +void remove_fw_link(struct node *list) { + while (list) { + struct node *next = list->next; + list->next = NULL; + list = next; + } +} + +void check_seq_next(const struct node *beg, const struct node *const end) { + assert(beg != NULL); + assert(end != NULL); + + for (beg = beg->next; end != beg; beg = beg->next) + assert(beg != NULL); +} + +void check_seq_prev(const struct node *beg, const struct node *const end) { + assert(beg != NULL); + assert(end != NULL); + + for (beg = beg->prev; end != beg; beg = beg->prev) + assert(beg != NULL); +} + +void main() +{ + const struct node *p1, *p2; + + struct node *list = create_sll(&p1, &p2); + check_seq_next(p1, p2); + assert(p1->prev == NULL); + assert(p2->prev == NULL); + + init_back_link(list); + check_seq_next(p1, p2); + check_seq_prev(p2, p1); + + reverse_dll(list); + check_seq_prev(p1, p2); + check_seq_next(p2, p1); + + remove_fw_link(list); + check_seq_prev(p1, p2); +} + diff --git a/regression/heap/sll_to_dll1_reverse/test.desc b/regression/heap/sll_to_dll1_reverse/test.desc new file mode 100644 index 000000000..92784083a --- /dev/null +++ b/regression/heap/sll_to_dll1_reverse/test.desc @@ -0,0 +1,6 @@ +KNOWNBUG +main.c +--heap --inline --no-propagation +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ From 8ae53e5539541acca1a2925f22820b6156fdae15 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 26 Aug 2016 14:29:47 +0100 Subject: [PATCH 019/322] Heap domain: add points_to information to invariant. Now works also for loops with nondeterministic number of iterations. --- src/domains/heap_domain.h | 21 ++++++++++++++++++--- src/domains/strategy_solver_heap.cpp | 8 ++++++-- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index 55a08cd83..62d5901b0 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -59,10 +59,13 @@ class heap_domaint : public domaint }; std::set paths; /**< Set of paths leading from the row variable */ - std::set points_to; /**< Set of objects the row variable can point to */ + std::set points_to; /**< Set of objects (or NULL) the row variable can point to */ /** - * Get expression for the row value. It is a conjunction of path expressions. + * Get expression for the row value. It is a conjunction of points to expression and path + * expressions. + * Points to expression is disjunction of equalities: + * p = &o (NULL) for each object 'o' (or NULL) from points_to set * Expression of path leading from variable 'p' to destination 'd' via set of objects 'O' * has form: * p = d || if path can have zero length @@ -72,9 +75,21 @@ class heap_domaint : public domaint */ exprt get_row_expr(const vart &templ_expr) const { - if (paths.empty()) return false_exprt(); + if (paths.empty() && points_to.empty()) return false_exprt(); exprt::operandst result; + if (!points_to.empty()) + { // Points to expression + exprt::operandst pt_expr; + for (auto &pt : points_to) + { + pt_expr.push_back(equal_exprt(templ_expr, + is_null_ptr(pt.first) ? + pt.first : address_of_exprt(pt.first))); + } + result.push_back(disjunction(pt_expr)); + } + for (auto &path : paths) { // path(p, d)[O] const exprt &dest = path.destination; diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index ef3d6dba0..3263dcc27 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -92,11 +92,15 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) if (heap_domain.is_null_ptr(ptr_value)) { - if (heap_domain.add_row_path(row, inv, - null_pointer_exprt(to_pointer_type(ptr_value.type())), + exprt null_expr = null_pointer_exprt(to_pointer_type(ptr_value.type())); + if (heap_domain.add_row_path(row, inv, null_expr, std::make_pair(nil_exprt(), nil_exprt()))) improved = true; debug() << "add destination: " << from_expr(ns, "", ptr_value) << eom; + + if (heap_domain.add_points_to(row, inv, std::make_pair(null_expr, nil_exprt()))) + improved = true; + debug() << "add points to: " << from_expr(ns, "", ptr_value) << eom; } else { From a58b6ba15ff021f3ddcc7d5714410be892b9cfca Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 13 Sep 2016 16:55:37 +0100 Subject: [PATCH 020/322] Heap domain: handle simple doubly-linked list. See regression/heap/dll1_simple. --- regression/heap/dll1_simple/main.c | 107 +++++++++++++++++++++++ regression/heap/dll1_simple/test.desc | 6 ++ src/domains/heap_domain.cpp | 101 +++++++++++++++------- src/domains/heap_domain.h | 40 +++++---- src/domains/strategy_solver_heap.cpp | 110 +++++++++++++++--------- src/domains/strategy_solver_heap.h | 2 +- src/domains/template_generator_base.cpp | 2 +- 7 files changed, 279 insertions(+), 89 deletions(-) create mode 100644 regression/heap/dll1_simple/main.c create mode 100644 regression/heap/dll1_simple/test.desc diff --git a/regression/heap/dll1_simple/main.c b/regression/heap/dll1_simple/main.c new file mode 100644 index 000000000..0dae16a0d --- /dev/null +++ b/regression/heap/dll1_simple/main.c @@ -0,0 +1,107 @@ +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +extern int __VERIFIER_nondet_int(void); + +static void fail(void) { +ERROR: __VERIFIER_error(); +} + +#define ___SL_ASSERT(cond) do { \ + if (!(cond)) \ + fail(); \ + assert(cond); \ +} while (0) + +struct node { + struct node *next; + struct node *prev; +}; + +static struct node* alloc_node(void) +{ + struct node *ptr = malloc(sizeof *ptr); + + ptr->next = NULL; + ptr->prev = NULL; + return ptr; +} + +static void chain_node(struct node **ppnode) +{ + struct node *node = alloc_node(); + node->next = *ppnode; + *ppnode = node; +} + +static struct node* create_sll(const struct node **pp1, const struct node **pp2) +{ + struct node *list = NULL; + + do + chain_node(&list); + while (__VERIFIER_nondet_int()); + + return list; +} + +void init_back_link(struct node *list) { + while (list) { + struct node *next = list->next; + // if (!next) + // return; + + next->prev = list; + list = next; + } +} + +void reverse_dll(struct node *list) { + while (list) { + struct node *next = list->next; + list->next = list->prev; + list->prev = next; + list = next; + } +} + +void remove_fw_link(struct node *list) { + while (list) { + struct node *next = list->next; + list->next = NULL; + list = next; + } +} + +void check_seq_next(const struct node *beg, const struct node *const end) { + assert(beg != NULL); + assert(end != NULL); + + for (beg = beg->next; end != beg; beg = beg->next) + assert(beg != NULL); +} + +void check_seq_prev(const struct node *beg, const struct node *const end) { + assert(beg != NULL); + assert(end != NULL); + + for (beg = beg->prev; end != beg; beg = beg->prev) + assert(beg != NULL); +} + +void main() +{ + const struct node *p1, *p2; + + struct node *list = create_sll(&p1, &p2); + + init_back_link(list); + + // reverse_dll(list); + // check_seq_prev(p1, p2); + // check_seq_next(p2, p1); + + remove_fw_link(list); +} + diff --git a/regression/heap/dll1_simple/test.desc b/regression/heap/dll1_simple/test.desc new file mode 100644 index 000000000..ed14b476a --- /dev/null +++ b/regression/heap/dll1_simple/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap --inline --no-propagation +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index ee5eed64a..c4daa5062 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -25,7 +25,8 @@ void heap_domaint::initialize(domaint::valuet &value) /** * Create domain template for given set of variables. - * Template contains only pointers to structures containing field 'next'. + * Template contains row for each member of each variable being pointer to struct, + * and a row for each flattened member of a struct. * @param var_specs Set of program variables. * @param ns Namespace */ @@ -37,35 +38,46 @@ void heap_domaint::make_template(const domaint::var_specst &var_specs, const nam for (auto v1 = var_specs.begin(); v1 != var_specs.end(); ++v1) { - // Check if v1 is struct and has 'next' field - bool has_next = false; + // Create template for each pointer to struct const vart &var1 = v1->var; if (var1.type().id() == ID_pointer) { const typet &pointed_type = ns.follow(var1.type().subtype()); if (pointed_type.id() == ID_struct) { + // Check if var1 is member field of dynamic object + const std::string identifier = id2string(to_symbol_expr(v1->var).get_identifier()); + bool dynamic = identifier.find("dynamic_object$") != std::string::npos; + for (auto &component : to_struct_type(pointed_type).components()) { - if (component.get_name() == "next") - has_next = true; + if (!dynamic || + identifier.find("." + id2string(component.get_name())) != std::string::npos) + { + templ.push_back(template_rowt()); + template_rowt &templ_row = templ.back(); + templ_row.expr = v1->var; + templ_row.member = component.get_name(); + templ_row.pre_guard = v1->pre_guard; + templ_row.post_guard = v1->post_guard; + templ_row.aux_expr = v1->post_guard; + templ_row.kind = v1->kind; + templ_row.dynamic = dynamic; + if (dynamic) + { + int loc_num = get_symbol_loc(var1); + std::string var1_id = id2string(to_symbol_expr(var1).get_identifier()); + std::string do_base_id = var1_id.substr(0, var1_id.find_last_of('.')); + // TODO just add the whole suffix + irep_idt do_id = do_base_id + "#lb" + std::to_string(loc_num); + templ_row.dyn_obj = symbol_exprt(do_id, var1.type().subtype()); + } + else + templ_row.dyn_obj = nil_exprt(); + } } } } - - if (has_next) - { // Create template - templ.push_back(template_rowt()); - template_rowt &templ_row = templ.back(); - templ_row.expr = v1->var; - templ_row.pre_guard = v1->pre_guard; - templ_row.post_guard = v1->post_guard; - templ_row.aux_expr = v1->post_guard; - templ_row.kind = v1->kind; - // Check if the pointer itself is field of a dynamic object - const std::string identifier = id2string(to_symbol_expr(v1->var).get_identifier()); - templ_row.dynamic = identifier.find("dynamic_object$") != std::string::npos; - } } } @@ -176,7 +188,12 @@ bool heap_domaint::add_row_path(const rowt &row, heap_valuet &value, const exprt else { // Path exists already - if (dyn_obj.first.id() == ID_nil) return false; + if (dyn_obj.first.id() == ID_nil) + { + bool result = path_set.find(dest)->zero_length; + path_set.find(dest)->zero_length = true; + return !result; + } // Try to insert new dynamic object belonging to the path return path_set.find(dest)->dyn_objects.insert(dyn_obj).second; } @@ -280,7 +297,9 @@ void heap_domaint::output_domain(std::ostream &out, const namespacet &ns) const assert(false); } const vart &var = templ_row.expr; - out << "?path(" << from_expr(ns, "", var) << ", DESTINATIONS)" << std::endl; + const irep_idt &member = templ_row.member; + out << i << ": ?path(" << from_expr(ns, "", var) << ", " << member << ", DESTINATIONS)" + << std::endl; } } @@ -300,18 +319,12 @@ void heap_domaint::project_on_vars(domaint::valuet &value, const row_valuet &row_val = val[row]; if (templ_row.kind == LOOP) { - if (row_val.paths.empty()) - c.push_back(implies_exprt(templ_row.pre_guard, false_exprt())); - else - c.push_back(implies_exprt(templ_row.pre_guard, - row_val.get_row_expr(templ_row.expr))); + c.push_back(implies_exprt(templ_row.pre_guard, + row_val.get_row_expr(templ_row.expr))); } else { - if (row_val.paths.empty()) - c.push_back(false_exprt()); - else - c.push_back(row_val.get_row_expr(templ_row.expr)); + c.push_back(row_val.get_row_expr(templ_row.expr)); } } result = conjunction(c); @@ -362,3 +375,31 @@ bool heap_domaint::is_null_ptr(const exprt &expr) return is_null_ptr(to_typecast_expr(expr).op()); return false; } + +/** + * Get location number of a given symbol. + * @param expr Symbol expression. + * @return Number of location, or -1 if symbol is input. + */ +int heap_domaint::get_symbol_loc(const exprt &expr) +{ + assert(expr.id() == ID_symbol); + std::string expr_id = id2string(to_symbol_expr(expr).get_identifier()); + if (expr_id.find('#') == std::string::npos) return -1; + std::string loc_str = expr_id.substr(expr_id.find_last_not_of("0123456789") + 1); + assert(!loc_str.empty()); + return std::stoi(loc_str); +} + +/** + * Get base name of a symbol. + * @param expr Symbol expression. + * @return Base name of a symbol (without suffix with location number). + */ +std::string heap_domaint::get_base_name(const exprt &expr) +{ + assert(expr.id() == ID_symbol); + std::string result = id2string(to_symbol_expr(expr).get_identifier()); + result = result.substr(0, result.find_last_of('#')); + return result; +} diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index 62d5901b0..d602ee17a 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -13,8 +13,8 @@ class heap_domaint : public domaint { public: typedef unsigned rowt; - typedef vart next_fieldt; - typedef std::pair dyn_objt; + typedef vart member_fieldt; + typedef std::pair dyn_objt; heap_domaint(unsigned int _domain_number, replace_mapt &_renaming_map, const var_specst &var_specs, @@ -66,10 +66,10 @@ class heap_domaint : public domaint * expressions. * Points to expression is disjunction of equalities: * p = &o (NULL) for each object 'o' (or NULL) from points_to set - * Expression of path leading from variable 'p' to destination 'd' via set of objects 'O' - * has form: - * p = d || if path can have zero length - * p = &o && (o.next = d || o.next = o') where o,o' belong to O and p can point to &o + * Expression of path leading from variable 'p' to destination 'd' via field 'm' and + * passing through set of objects 'O' has form: + * p = d || if path can have zero length + * p = &o && (o.m = d || o.m = o') where o,o' belong to O and p can point to &o * @param templ_expr Pointer variable of the template row * @return Row value expression in the described form */ @@ -83,6 +83,7 @@ class heap_domaint : public domaint exprt::operandst pt_expr; for (auto &pt : points_to) { + exprt lhs = templ_expr; pt_expr.push_back(equal_exprt(templ_expr, is_null_ptr(pt.first) ? pt.first : address_of_exprt(pt.first))); @@ -91,7 +92,7 @@ class heap_domaint : public domaint } for (auto &path : paths) - { // path(p, d)[O] + { // path(p, m, d)[O] const exprt &dest = path.destination; exprt::operandst path_expr; @@ -102,23 +103,20 @@ class heap_domaint : public domaint } for (const dyn_objt &obj1 : path.dyn_objects) { - if (points_to.find(obj1) != points_to.end()) - { // p = &o exprt equ_exprt = equal_exprt(templ_expr, address_of_exprt(obj1.first)); exprt::operandst step_expr; - exprt next_expr = obj1.second; - // o.next = d - step_expr.push_back(equal_exprt(next_expr, dest)); + exprt member_expr = obj1.second; + // o.m = d + step_expr.push_back(equal_exprt(member_expr, dest)); for (auto &obj2 : path.dyn_objects) - { // o.next = o' - step_expr.push_back(equal_exprt(next_expr, address_of_exprt(obj2.first))); + { // o.m = o' + step_expr.push_back(equal_exprt(member_expr, address_of_exprt(obj2.first))); } path_expr.push_back(and_exprt(equ_exprt, disjunction(step_expr))); - } } result.push_back(disjunction(path_expr)); @@ -126,6 +124,11 @@ class heap_domaint : public domaint return conjunction(result); } + + inline bool empty() const + { + return paths.empty() && points_to.empty(); + } }; class heap_valuet : public valuet, public std::vector @@ -137,8 +140,10 @@ class heap_domaint : public domaint guardt pre_guard; guardt post_guard; vart expr; + irep_idt member; exprt aux_expr; kindt kind; + exprt dyn_obj; bool dynamic; }; typedef std::vector templatet; @@ -188,6 +193,11 @@ class heap_domaint : public domaint void make_template(const var_specst &var_specs, const namespacet &ns); + // Utility functions + static int get_symbol_loc(const exprt &expr); + + static std::string get_base_name(const exprt &expr); + friend class strategy_solver_heapt; }; diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index 3263dcc27..2051dbc95 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -66,7 +66,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) } for (unsigned i = 0; i < heap_domain.templ.size(); i++) { - exprt c = heap_domain.get_row_pre_constraint(i, inv[i]); + exprt c = heap_domain.get_row_pre_constraint(i, inv[i]).op1(); debug() << "cond: " << from_expr(ns, "", c) << " " << from_expr(ns, "", solver.get(c)) << eom; debug() << "guards: " << from_expr(ns, "", heap_domain.templ[i].pre_guard) << @@ -84,8 +84,10 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) if (solver.l_get(strategy_cond_literals[row]).is_true()) { debug() << "updating row: " << row << eom; - exprt pointer = strategy_value_exprs[row]; + int actual_loc = heap_domain.get_symbol_loc(heap_domain.templ[row].expr); + + exprt pointer = strategy_value_exprs[row]; exprt value = solver.get(pointer); // Value from solver must be converted into expression exprt ptr_value = heap_domain.value_to_ptr_exprt(value); @@ -105,25 +107,37 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) else { // pointer points to the heap (p = &obj) + debug() << from_expr(ns, "", ptr_value) << eom; assert(ptr_value.id() == ID_address_of); - exprt obj = to_address_of_expr(ptr_value).object(); - - // Find row with next field of pointed object (obj.next) - int next_val_index = next_field_row(obj); - assert(next_val_index >= 0); - exprt next_val_expr = heap_domain.templ[next_val_index].expr; - - // Add all paths from obj.next to p - if (heap_domain.add_all_paths(row, (unsigned) next_val_index, inv, - std::make_pair(obj, next_val_expr))) - improved = true; - debug() << "add all paths: " << from_expr(ns, "", next_val_expr) << ", through: " - << from_expr(ns, "", obj) << eom; + assert(to_address_of_expr(ptr_value).object().id() == ID_symbol); + symbol_exprt obj = to_symbol_expr(to_address_of_expr(ptr_value).object()); if (obj.type().get_bool("#dynamic")) - { // Add points to information - assert(obj.id() == ID_symbol); - if (heap_domain.add_points_to(row, inv, std::make_pair(obj, next_val_expr))) + { + // Find row with corresponding member field of pointed object (obj.member) + if (inv[row].empty() && heap_domain.templ[row].dyn_obj.id() != ID_nil && + heap_domain.get_base_name(obj) == + heap_domain.get_base_name(heap_domain.templ[row].dyn_obj)) + { + --actual_loc; + } + int member_val_index = find_member_row(obj, heap_domain.templ[row].member, + actual_loc); + assert(member_val_index >= 0); + exprt member_expr = heap_domain.templ[member_val_index].expr; + exprt do_expr = heap_domain.templ[member_val_index].dyn_obj; + + // Add all paths from obj.next to p + if (heap_domain.add_all_paths(row, (unsigned) member_val_index, inv, + std::make_pair(obj, member_expr))) + improved = true; + debug() << "add all paths: " << from_expr(ns, "", member_expr) << ", through: " + << from_expr(ns, "", obj) << eom; + + assert(do_expr.id() != ID_nil); + // Add points to information + assert(do_expr.id() == ID_symbol); + if (heap_domain.add_points_to(row, inv, std::make_pair(obj, member_expr))) improved = true; debug() << "add points to: " << from_expr(ns, "", obj) << eom; } @@ -134,16 +148,19 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) // that this row variable belongs to. for (unsigned j = 0; j < heap_domain.templ.size(); ++j) { - for (auto &pt : inv[j].points_to) + if (heap_domain.templ[row].member == heap_domain.templ[j].member) { - exprt pre_pointer = heap_domain.templ[row].expr; - if (pre_pointer == pt.second) + for (auto &pt : inv[j].points_to) { - if (heap_domain.add_all_paths(j, row, inv, pt)) - improved = true; - debug() << "recursively updating row: " << j << eom; - debug() << "add all paths: " << from_expr(ns, "", pre_pointer) << ", through: " - << from_expr(ns, "", pt.first) << eom; + exprt pre_pointer = heap_domain.templ[row].expr; + if (pre_pointer == pt.second) + { + if (heap_domain.add_all_paths(j, row, inv, pt)) + improved = true; + debug() << "recursively updating row: " << j << eom; + debug() << "add all paths: " << from_expr(ns, "", pre_pointer) << ", through: " + << from_expr(ns, "", pt.first) << eom; + } } } } @@ -154,9 +171,11 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) else { +#define DEBUG_OUTPUT #ifdef DEBUG_OUTPUT debug() << "UNSAT" << eom; #endif +#undef DEBUG_OUTPUT #ifdef DEBUG_OUTPUT for (unsigned i = 0; i < solver.formula.size(); i++) @@ -174,29 +193,36 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) } /** - * Find the template row that contains next field of given object as row variable. + * Find the template row that contains specified member field of a dynamic object at given location. + * Finds obj.member#loc with maximal loc less than actual_loc. * @param obj - * @return Template row of obj.next + * @param member Member field to find + * @param actual_loc Actual location number + * @return Template row of obj.member */ -int strategy_solver_heapt::next_field_row(const exprt &obj) const +int strategy_solver_heapt::find_member_row(const exprt &obj, const irep_idt &member, int actual_loc) { - // Create "next" member expression - exprt next_expr = member_exprt(obj, "next", pointer_typet(obj.type())); - std::string next_expr_id = from_expr(ns, "", next_expr); + assert(obj.id() == ID_symbol); + std::string obj_id = heap_domain.get_base_name(obj); int result = -1; - for (unsigned i = 0; i < strategy_value_exprs.size(); ++i) - { // Find the corresponding strategy value expression - exprt val_expr = strategy_value_exprs[i]; - assert(val_expr.id() == ID_symbol); - std::string val_expr_id = id2string(to_symbol_expr(val_expr).get_identifier()); - // Compare identifiers of row expression and "next" member expresssion - if (val_expr_id.find(next_expr_id) != std::string::npos) + int max_loc = -1; + for (unsigned i = 0; i < heap_domain.templ.size(); ++i) + { + heap_domaint::template_rowt &templ_row = heap_domain.templ[i]; + if (templ_row.member == member && templ_row.dyn_obj.id() != ID_nil) { - result = i; - break; + std::string id = id2string(to_symbol_expr(templ_row.expr).get_identifier()); + if (id.find(obj_id) != std::string::npos) + { + int loc = heap_domain.get_symbol_loc(templ_row.expr); + if (loc <= actual_loc && loc > max_loc) + { + max_loc = loc; + result = i; + } + } } } - return result; } diff --git a/src/domains/strategy_solver_heap.h b/src/domains/strategy_solver_heap.h index 09f000b98..edb63c9a4 100644 --- a/src/domains/strategy_solver_heap.h +++ b/src/domains/strategy_solver_heap.h @@ -22,7 +22,7 @@ class strategy_solver_heapt : public strategy_solver_baset protected: heap_domaint &heap_domain; - int next_field_row(const exprt &obj) const; + int find_member_row(const exprt &obj, const irep_idt &member, int actual_loc); }; diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index 05326a71a..8815d658a 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -270,7 +270,7 @@ void template_generator_baset::filter_heap_domain() var_specs.clear(); for (auto var=new_var_specs.begin(); var!=new_var_specs.end(); ++var) { - if (var->var.type().id()==ID_pointer) + if (var->var.type().id()==ID_pointer || var->var.type().get_bool("#dynamic")) var_specs.push_back(*var); } } From e6830681c4fc076931e49a334488a9c257ce3d32 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Wed, 21 Sep 2016 18:12:09 +0100 Subject: [PATCH 021/322] Heap domain: Fix bug with aux_expr. Small changes to path expression passed to solver. Now works for regression test heap/sll_to_dll1_reverse. --- regression/heap/path-format.py | 6 + regression/heap/sll1_simple/main.out.old | 1120 +++++++++++++++++ regression/heap/sll_to_dll1_reverse/main.c | 25 +- regression/heap/sll_to_dll1_reverse/test.desc | 2 +- src/domains/heap_domain.cpp | 3 +- src/domains/heap_domain.h | 13 +- src/domains/strategy_solver_heap.cpp | 22 +- 7 files changed, 1172 insertions(+), 19 deletions(-) create mode 100644 regression/heap/path-format.py create mode 100644 regression/heap/sll1_simple/main.out.old diff --git a/regression/heap/path-format.py b/regression/heap/path-format.py new file mode 100644 index 000000000..a18b0fe13 --- /dev/null +++ b/regression/heap/path-format.py @@ -0,0 +1,6 @@ +from lepl import Any, Delayed, Node, Space + +expr = Delayed() +expr += '{' / (Any() | expr[1:, Space()[:]]) / '}' > Node + +print expr.parse("{{a}{b}{{{c}}}}")[0] diff --git a/regression/heap/sll1_simple/main.out.old b/regression/heap/sll1_simple/main.out.old new file mode 100644 index 000000000..af5a78516 --- /dev/null +++ b/regression/heap/sll1_simple/main.out.old @@ -0,0 +1,1120 @@ +2LS version 0.3.4 (based on CBMC 5.4) +Parsing main.c +Converting +Type-checking main +file main.c line 53 function check_seq_next: function `assert' is not declared +Generating GOTO Program +Adding CPROVER library +Generic Property Instrumentation +Function Pointer Removal +Performing full inlining +Using heap domain +Computing SSA of _start +Simplifying +(E) $guard#0 == TRUE + +(E) __CPROVER_dead_object#2 == NULL + +(E) __CPROVER_deallocated#3 == NULL + +(E) __CPROVER_malloc_is_new_array#4 == FALSE + +(E) __CPROVER_malloc_object#5 == NULL + +(E) __CPROVER_malloc_size#6 == 0ul + +(E) __CPROVER_memory_leak#7 == NULL + +(E) __CPROVER_next_thread_id#8 == 0ul + +(E) __CPROVER_pipe_count#9 == 0u + +(E) __CPROVER_rounding_mode#10 == 0 + +(E) __CPROVER_thread_id#11 == 0ul + +(E) __CPROVER_threads_exited#12 == ARRAY_OF(FALSE) + +(E) p1#16 == nondet_symbol(ssa::nondet16.1) + +(E) p2#18 == nondet_symbol(ssa::nondet18.1) + +(E) list#20 == nondet_symbol(ssa::nondet20.1) + +(E) pp1#23 == nondet_symbol(ssa::nondet23.1) + +(E) pp1#24 == &p1 + +(E) pp2#26 == nondet_symbol(ssa::nondet26.1) + +(E) pp2#27 == &p2 + +(E) p2#28 == ((struct node *)NULL) + +(E) i#30 == nondet_symbol(ssa::nondet30.1) + +(E) i#31 == 0 + +(E) __CPROVER_deallocated#phi32 == ($guard#ls101 ? __CPROVER_deallocated#lb101 : __CPROVER_deallocated#3) +(E) __CPROVER_malloc_object#phi32 == ($guard#ls101 ? __CPROVER_malloc_object#lb101 : __CPROVER_malloc_object#5) +(E) __CPROVER_malloc_size#phi32 == ($guard#ls101 ? __CPROVER_malloc_size#lb101 : __CPROVER_malloc_size#6) +(E) __CPROVER_malloc_is_new_array#phi32 == ($guard#ls101 ? __CPROVER_malloc_is_new_array#lb101 : __CPROVER_malloc_is_new_array#4) +(E) __CPROVER_memory_leak#phi32 == ($guard#ls101 ? __CPROVER_memory_leak#lb101 : __CPROVER_memory_leak#7) +(E) i#phi32 == ($guard#ls101 ? i#lb101 : i#31) +(E) p2#phi32 == ($guard#ls101 ? p2#lb101 : p2#28) +(E) dynamic_object$0.next#phi32 == ($guard#ls101 ? dynamic_object$0.next#lb101 : dynamic_object$0.next) +(E) $cond#32 == i#phi32 >= 2 +(E) $guard#32 == $guard#0 + +(E) $guard#33 == (!$cond#32 && $guard#32) + +(E) ppnode#35 == nondet_symbol(ssa::nondet35.1) + +(E) ppnode#36 == pp2#27 + +(E) node#38 == nondet_symbol(ssa::nondet38.1) + +(E) ptr#41 == nondet_symbol(ssa::nondet41.1) + +(E) return_value_malloc$1#43 == nondet_symbol(ssa::nondet43.1) + +(E) malloc_size#46 == nondet_symbol(ssa::nondet46.1) + +(E) malloc_size#47 == sizeof(struct node) /*8ul*/ + +(E) malloc_res#50 == nondet_symbol(ssa::nondet50.1) + +(E) malloc_value$1#52 == nondet_symbol(ssa::nondet52.1) + +(E) malloc_value$1#53 == (void *)&dynamic_object$0 + +(E) malloc_res#54 == malloc_value$1#53 + +(E) __CPROVER_deallocated#56 == (malloc_res#54 == __CPROVER_deallocated#phi32 ? NULL : __CPROVER_deallocated#phi32) + +(E) record_malloc#58 == nondet_symbol(ssa::nondet58.1) + +(E) __CPROVER_malloc_object#59 == (record_malloc#58 ? malloc_res#54 : __CPROVER_malloc_object#phi32) + +(E) __CPROVER_malloc_size#60 == (record_malloc#58 ? malloc_size#47 : __CPROVER_malloc_size#phi32) + +(E) __CPROVER_malloc_is_new_array#61 == (!record_malloc#58 && __CPROVER_malloc_is_new_array#phi32) + +(E) record_may_leak#63 == nondet_symbol(ssa::nondet63.1) + +(E) __CPROVER_memory_leak#64 == (record_may_leak#63 ? malloc_res#54 : __CPROVER_memory_leak#phi32) + +(E) malloc#return_value#65 == malloc_res#54 + +(E) $cond#70 == TRUE + +(E) $guard#71 == FALSE + +(E) $guard#75 == ($cond#70 && $guard#33 || $guard#71) + +(E) return_value_malloc$1#77 == malloc#return_value#65 + +(E) ptr#79 == (struct node *)return_value_malloc$1#77 + +(E) $cond#81 == !(ptr#79 == ((struct node *)NULL)) + +(E) $guard#82 == (!$cond#81 && $guard#75) + +(E) $cond#83 == FALSE + +(E) $guard#84 == ($cond#83 && $guard#82) + +(E) dynamic_object$0.next#85 == ((struct node *)NULL) +(E) $guard#85 == ($cond#81 && $guard#75 || $guard#84) + +(E) alloc_node#return_value#86 == ptr#79 + +(E) $cond#89 == TRUE + +(E) $guard#90 == FALSE + +(E) $guard#92 == ($cond#89 && $guard#85 || $guard#90) + +(E) node#93 == alloc_node#return_value#86 + +(E) dynamic_object$0.next#95 == (ppnode#36 == &p2 ? p2#phi32 : deref#95) + +(E) p2#96 == node#93 + +(E) i#100 == 1 + i#phi32 + +(E) $cond#101 == TRUE + +(E) $guard#102 == ($cond#32 && $guard#32) + +(E) p1#103 == (pp2#27 == &p2 ? p2#phi32 : deref#103) + +(E) i#105 == nondet_symbol(ssa::nondet105.1) + +(E) i#106 == 0 + +(E) __CPROVER_deallocated#phi107 == ($guard#ls176 ? __CPROVER_deallocated#lb176 : __CPROVER_deallocated#phi32) +(E) __CPROVER_malloc_object#phi107 == ($guard#ls176 ? __CPROVER_malloc_object#lb176 : __CPROVER_malloc_object#phi32) +(E) __CPROVER_malloc_size#phi107 == ($guard#ls176 ? __CPROVER_malloc_size#lb176 : __CPROVER_malloc_size#phi32) +(E) __CPROVER_malloc_is_new_array#phi107 == ($guard#ls176 ? __CPROVER_malloc_is_new_array#lb176 : __CPROVER_malloc_is_new_array#phi32) +(E) __CPROVER_memory_leak#phi107 == ($guard#ls176 ? __CPROVER_memory_leak#lb176 : __CPROVER_memory_leak#phi32) +(E) i#phi107 == ($guard#ls176 ? i#lb176 : i#106) +(E) p1#phi107 == ($guard#ls176 ? p1#lb176 : p1#103) +(E) dynamic_object$1.next#phi107 == ($guard#ls176 ? dynamic_object$1.next#lb176 : dynamic_object$1.next) +(E) $cond#107 == i#phi107 >= 2 +(E) $guard#107 == $guard#102 + +(E) $guard#108 == (!$cond#107 && $guard#107) + +(E) ppnode#110 == nondet_symbol(ssa::nondet110.1) + +(E) ppnode#111 == pp1#24 + +(E) node#113 == nondet_symbol(ssa::nondet113.1) + +(E) ptr#116 == nondet_symbol(ssa::nondet116.1) + +(E) return_value_malloc$1#118 == nondet_symbol(ssa::nondet118.1) + +(E) malloc_size#121 == nondet_symbol(ssa::nondet121.1) + +(E) malloc_size#122 == sizeof(struct node) /*8ul*/ + +(E) malloc_res#125 == nondet_symbol(ssa::nondet125.1) + +(E) malloc_value$1#127 == nondet_symbol(ssa::nondet127.1) + +(E) malloc_value$1#128 == (void *)&dynamic_object$1 + +(E) malloc_res#129 == malloc_value$1#128 + +(E) __CPROVER_deallocated#131 == (malloc_res#129 == __CPROVER_deallocated#phi107 ? NULL : __CPROVER_deallocated#phi107) + +(E) record_malloc#133 == nondet_symbol(ssa::nondet133.1) + +(E) __CPROVER_malloc_object#134 == (record_malloc#133 ? malloc_res#129 : __CPROVER_malloc_object#phi107) + +(E) __CPROVER_malloc_size#135 == (record_malloc#133 ? malloc_size#122 : __CPROVER_malloc_size#phi107) + +(E) __CPROVER_malloc_is_new_array#136 == (!record_malloc#133 && __CPROVER_malloc_is_new_array#phi107) + +(E) record_may_leak#138 == nondet_symbol(ssa::nondet138.1) + +(E) __CPROVER_memory_leak#139 == (record_may_leak#138 ? malloc_res#129 : __CPROVER_memory_leak#phi107) + +(E) malloc#return_value#140 == malloc_res#129 + +(E) $cond#145 == TRUE + +(E) $guard#146 == FALSE + +(E) $guard#150 == ($cond#145 && $guard#108 || $guard#146) + +(E) return_value_malloc$1#152 == malloc#return_value#140 + +(E) ptr#154 == (struct node *)return_value_malloc$1#152 + +(E) $cond#156 == !(ptr#154 == ((struct node *)NULL)) + +(E) $guard#157 == (!$cond#156 && $guard#150) + +(E) $cond#158 == FALSE + +(E) $guard#159 == ($cond#158 && $guard#157) + +(E) dynamic_object$1.next#160 == ((struct node *)NULL) +(E) $guard#160 == ($cond#156 && $guard#150 || $guard#159) + +(E) alloc_node#return_value#161 == ptr#154 + +(E) $cond#164 == TRUE + +(E) $guard#165 == FALSE + +(E) $guard#167 == ($cond#164 && $guard#160 || $guard#165) + +(E) node#168 == alloc_node#return_value#161 + +(E) dynamic_object$1.next#170 == (ppnode#111 == &p1 ? p1#phi107 : deref#170) + +(E) p1#171 == node#168 + +(E) i#175 == 1 + i#phi107 + +(E) $cond#176 == TRUE + +(E) $guard#177 == ($cond#107 && $guard#107) + +(E) list#179 == nondet_symbol(ssa::nondet179.1) + +(E) list#180 == (pp1#24 == &p1 ? p1#phi107 : deref#180) + +(E) i#182 == nondet_symbol(ssa::nondet182.1) + +(E) i#183 == 0 + +(E) __CPROVER_deallocated#phi184 == ($guard#ls253 ? __CPROVER_deallocated#lb253 : __CPROVER_deallocated#phi107) +(E) __CPROVER_malloc_object#phi184 == ($guard#ls253 ? __CPROVER_malloc_object#lb253 : __CPROVER_malloc_object#phi107) +(E) __CPROVER_malloc_size#phi184 == ($guard#ls253 ? __CPROVER_malloc_size#lb253 : __CPROVER_malloc_size#phi107) +(E) __CPROVER_malloc_is_new_array#phi184 == ($guard#ls253 ? __CPROVER_malloc_is_new_array#lb253 : __CPROVER_malloc_is_new_array#phi107) +(E) __CPROVER_memory_leak#phi184 == ($guard#ls253 ? __CPROVER_memory_leak#lb253 : __CPROVER_memory_leak#phi107) +(E) list#phi184 == ($guard#ls253 ? list#lb253 : list#180) +(E) i#phi184 == ($guard#ls253 ? i#lb253 : i#183) +(E) dynamic_object$2.next#phi184 == ($guard#ls253 ? dynamic_object$2.next#lb253 : dynamic_object$2.next) +(E) $cond#184 == i#phi184 >= 2 +(E) $guard#184 == $guard#177 + +(E) $guard#185 == (!$cond#184 && $guard#184) + +(E) ppnode#187 == nondet_symbol(ssa::nondet187.1) + +(E) ppnode#188 == &list + +(E) node#190 == nondet_symbol(ssa::nondet190.1) + +(E) ptr#193 == nondet_symbol(ssa::nondet193.1) + +(E) return_value_malloc$1#195 == nondet_symbol(ssa::nondet195.1) + +(E) malloc_size#198 == nondet_symbol(ssa::nondet198.1) + +(E) malloc_size#199 == sizeof(struct node) /*8ul*/ + +(E) malloc_res#202 == nondet_symbol(ssa::nondet202.1) + +(E) malloc_value$1#204 == nondet_symbol(ssa::nondet204.1) + +(E) malloc_value$1#205 == (void *)&dynamic_object$2 + +(E) malloc_res#206 == malloc_value$1#205 + +(E) __CPROVER_deallocated#208 == (malloc_res#206 == __CPROVER_deallocated#phi184 ? NULL : __CPROVER_deallocated#phi184) + +(E) record_malloc#210 == nondet_symbol(ssa::nondet210.1) + +(E) __CPROVER_malloc_object#211 == (record_malloc#210 ? malloc_res#206 : __CPROVER_malloc_object#phi184) + +(E) __CPROVER_malloc_size#212 == (record_malloc#210 ? malloc_size#199 : __CPROVER_malloc_size#phi184) + +(E) __CPROVER_malloc_is_new_array#213 == (!record_malloc#210 && __CPROVER_malloc_is_new_array#phi184) + +(E) record_may_leak#215 == nondet_symbol(ssa::nondet215.1) + +(E) __CPROVER_memory_leak#216 == (record_may_leak#215 ? malloc_res#206 : __CPROVER_memory_leak#phi184) + +(E) malloc#return_value#217 == malloc_res#206 + +(E) $cond#222 == TRUE + +(E) $guard#223 == FALSE + +(E) $guard#227 == ($cond#222 && $guard#185 || $guard#223) + +(E) return_value_malloc$1#229 == malloc#return_value#217 + +(E) ptr#231 == (struct node *)return_value_malloc$1#229 + +(E) $cond#233 == !(ptr#231 == ((struct node *)NULL)) + +(E) $guard#234 == (!$cond#233 && $guard#227) + +(E) $cond#235 == FALSE + +(E) $guard#236 == ($cond#235 && $guard#234) + +(E) dynamic_object$2.next#237 == ((struct node *)NULL) +(E) $guard#237 == ($cond#233 && $guard#227 || $guard#236) + +(E) alloc_node#return_value#238 == ptr#231 + +(E) $cond#241 == TRUE + +(E) $guard#242 == FALSE + +(E) $guard#244 == ($cond#241 && $guard#237 || $guard#242) + +(E) node#245 == alloc_node#return_value#238 + +(E) dynamic_object$2.next#247 == (ppnode#188 == &list ? list#phi184 : deref#247) + +(E) list#248 == node#245 + +(E) i#252 == 1 + i#phi184 + +(E) $cond#253 == TRUE + +(E) $guard#254 == ($cond#184 && $guard#184) + +(E) create_sll#return_value#255 == list#phi184 + +(E) $cond#257 == TRUE + +(E) $guard#258 == FALSE + +(E) $guard#259 == ($cond#257 && $guard#254 || $guard#258) + +(E) list#262 == create_sll#return_value#255 + +(E) beg#266 == nondet_symbol(ssa::nondet266.1) + +(E) beg#267 == list#262 + +(E) end#269 == nondet_symbol(ssa::nondet269.1) + +(E) end#270 == p1#phi107 + +(A) !(beg#267 == ((struct node *)NULL)) || !$guard#259 + +(A) !(end#270 == ((struct node *)NULL)) || !$guard#259 + +(E) beg#273 == (beg#267 == &dynamic_object$2 ? dynamic_object$2.next#phi184 : (beg#267 == &dynamic_object$1 ? dynamic_object$1.next#phi107 : (beg#267 == &dynamic_object$0 ? dynamic_object$0.next#phi32 : deref#273.next))) + +(E) beg#phi274 == ($guard#ls277 ? beg#lb277 : beg#273) +(E) $cond#274 == (end#270 == beg#phi274) +(E) $guard#274 == $guard#259 + +(E) $guard#275 == (!$cond#274 && $guard#274) +(A) !(beg#phi274 == ((struct node *)NULL)) || !$guard#275 + +(E) beg#276 == (beg#phi274 == &dynamic_object$2 ? dynamic_object$2.next#phi184 : (beg#phi274 == &dynamic_object$1 ? dynamic_object$1.next#phi107 : (beg#phi274 == &dynamic_object$0 ? dynamic_object$0.next#phi32 : deref#276.next))) + +(E) $cond#277 == TRUE + +(E) $guard#278 == ($cond#274 && $guard#274) + +(E) beg#283 == nondet_symbol(ssa::nondet283.1) + +(E) beg#284 == p1#phi107 + +(E) end#286 == nondet_symbol(ssa::nondet286.1) + +(E) end#287 == p2#phi32 + +(A) !(beg#284 == ((struct node *)NULL)) || !$guard#278 + +(A) !(end#287 == ((struct node *)NULL)) || !$guard#278 + +(E) beg#290 == (beg#284 == &dynamic_object$1 ? dynamic_object$1.next#phi107 : (beg#284 == &dynamic_object$0 ? dynamic_object$0.next#phi32 : deref#290.next)) + +(E) beg#phi291 == ($guard#ls294 ? beg#lb294 : beg#290) +(E) $cond#291 == (end#287 == beg#phi291) +(E) $guard#291 == $guard#278 + +(E) $guard#292 == (!$cond#291 && $guard#291) +(A) !(beg#phi291 == ((struct node *)NULL)) || !$guard#292 + +(E) beg#293 == (beg#phi291 == &dynamic_object$1 ? dynamic_object$1.next#phi107 : (beg#phi291 == &dynamic_object$0 ? dynamic_object$0.next#phi32 : deref#293.next)) + +(E) $cond#294 == TRUE + +(E) $guard#295 == ($cond#291 && $guard#291) + + + +Summarizing function _start +Analyzing function _start +Computing summary +Template: +(LOOP) [ $guard#32 && $guard#ls101 | $guard#92 && $cond#101 | $guard#92 && $cond#101 ] ===> + ?path(p2#lb101, DESTINATIONS) +(LOOP) [ $guard#32 && $guard#ls101 | $guard#92 && $cond#101 | $guard#92 && $cond#101 ] ===> + ?path(dynamic_object$0.next#lb101, DESTINATIONS) +(LOOP) [ $guard#107 && $guard#ls176 | $guard#167 && $cond#176 | $guard#167 && $cond#176 ] ===> + ?path(p1#lb176, DESTINATIONS) +(LOOP) [ $guard#107 && $guard#ls176 | $guard#167 && $cond#176 | $guard#167 && $cond#176 ] ===> + ?path(dynamic_object$1.next#lb176, DESTINATIONS) +(LOOP) [ $guard#184 && $guard#ls253 | $guard#244 && $cond#253 | $guard#244 && $cond#253 ] ===> + ?path(list#lb253, DESTINATIONS) +(LOOP) [ $guard#184 && $guard#ls253 | $guard#244 && $cond#253 | $guard#244 && $cond#253 ] ===> + ?path(dynamic_object$2.next#lb253, DESTINATIONS) +(LOOP) [ $guard#274 && $guard#ls277 | $guard#275 && $cond#277 | $guard#275 && $cond#277 ] ===> + ?path(beg#lb277, DESTINATIONS) +(LOOP) [ $guard#291 && $guard#ls294 | $guard#292 && $cond#294 | $guard#292 && $cond#294 ] ===> + ?path(beg#lb294, DESTINATIONS) + +updating row: 0 +add all paths: dynamic_object$0.next#lb101, through: dynamic_object$0 +add points to: dynamic_object$0 +updating row: 1 +add destination: ((struct node *)NULL) +recursively updating row: 0 +add all paths: dynamic_object$0.next#lb101, through: dynamic_object$0 +updating row: 2 +add all paths: dynamic_object$1.next#lb176, through: dynamic_object$1 +add points to: dynamic_object$1 +updating row: 3 +add all paths: dynamic_object$0.next#lb101, through: dynamic_object$0 +add points to: dynamic_object$0 +recursively updating row: 2 +add all paths: dynamic_object$1.next#lb176, through: dynamic_object$1 +updating row: 3 +add all paths: dynamic_object$1.next#lb176, through: dynamic_object$1 +add points to: dynamic_object$1 +recursively updating row: 2 +add all paths: dynamic_object$1.next#lb176, through: dynamic_object$1 +recursively updating row: 3 +add all paths: dynamic_object$1.next#lb176, through: dynamic_object$1 +updating row: 4 +add all paths: dynamic_object$2.next#lb253, through: dynamic_object$2 +add points to: dynamic_object$2 +updating row: 5 +add all paths: dynamic_object$1.next#lb176, through: dynamic_object$1 +add points to: dynamic_object$1 +recursively updating row: 4 +add all paths: dynamic_object$2.next#lb253, through: dynamic_object$2 +updating row: 5 +add all paths: dynamic_object$2.next#lb253, through: dynamic_object$2 +add points to: dynamic_object$2 +recursively updating row: 4 +add all paths: dynamic_object$2.next#lb253, through: dynamic_object$2 +recursively updating row: 5 +add all paths: dynamic_object$2.next#lb253, through: dynamic_object$2 +updating row: 7 +add all paths: dynamic_object$1.next#lb176, through: dynamic_object$1 +add points to: dynamic_object$1 +updating row: 7 +add all paths: dynamic_object$0.next#lb101, through: dynamic_object$0 +add points to: dynamic_object$0 +updating row: 6 +add all paths: dynamic_object$2.next#lb253, through: dynamic_object$2 +add points to: dynamic_object$2 +updating row: 6 +add all paths: dynamic_object$1.next#lb176, through: dynamic_object$1 +add points to: dynamic_object$1 +updating row: 1 +add all paths: dynamic_object$0.next#lb101, through: dynamic_object$0 +add points to: dynamic_object$0 +recursively updating row: 0 +add all paths: dynamic_object$0.next#lb101, through: dynamic_object$0 +recursively updating row: 1 +add all paths: dynamic_object$0.next#lb101, through: dynamic_object$0 +recursively updating row: 3 +add all paths: dynamic_object$0.next#lb101, through: dynamic_object$0 +recursively updating row: 7 +add all paths: dynamic_object$0.next#lb101, through: dynamic_object$0 + +Summary for function _start +params: +globals_in: __CPROVER_threads_exited __CPROVER_malloc_is_new_array __CPROVER_dead_object __CPROVER_deallocated __CPROVER_malloc_object __CPROVER_memory_leak ppnode'obj beg'obj.next end'obj.next pp1'obj pp2'obj __CPROVER_rounding_mode __CPROVER_pipe_count __CPROVER_malloc_size __CPROVER_next_thread_id __CPROVER_thread_id +globals_out: __CPROVER_threads_exited#12 __CPROVER_malloc_is_new_array#phi184 __CPROVER_dead_object#2 __CPROVER_deallocated#phi184 __CPROVER_malloc_object#phi184 __CPROVER_memory_leak#phi184 ppnode'obj beg'obj.next end'obj.next pp1'obj pp2'obj __CPROVER_rounding_mode#10 __CPROVER_pipe_count#9 __CPROVER_malloc_size#phi184 __CPROVER_next_thread_id#8 __CPROVER_thread_id#11 +forward precondition: TRUE +forward transformer: TRUE +forward invariant: ($guard#32 && $guard#ls101 ==> p2#lb101 == &dynamic_object$0 && (dynamic_object$0.next#lb101 == ((struct node *)NULL) || dynamic_object$0.next#lb101 == &dynamic_object$0)) && ($guard#32 && $guard#ls101 ==> dynamic_object$0.next#lb101 == ((struct node *)NULL) || dynamic_object$0.next#lb101 == &dynamic_object$0 && (dynamic_object$0.next#lb101 == ((struct node *)NULL) || dynamic_object$0.next#lb101 == &dynamic_object$0)) && ($guard#107 && $guard#ls176 ==> p1#lb176 == &dynamic_object$1 && (dynamic_object$1.next#lb176 == ((struct node *)NULL) || dynamic_object$1.next#lb176 == &dynamic_object$0 || dynamic_object$1.next#lb176 == &dynamic_object$1)) && ($guard#107 && $guard#ls176 ==> dynamic_object$1.next#lb176 == &dynamic_object$0 && (dynamic_object$0.next#lb101 == ((struct node *)NULL) || dynamic_object$0.next#lb101 == &dynamic_object$0 || dynamic_object$0.next#lb101 == &dynamic_object$1) || dynamic_object$1.next#lb176 == &dynamic_object$1 && (dynamic_object$1.next#lb176 == ((struct node *)NULL) || dynamic_object$1.next#lb176 == &dynamic_object$0 || dynamic_object$1.next#lb176 == &dynamic_object$1)) && ($guard#184 && $guard#ls253 ==> list#lb253 == &dynamic_object$2 && (dynamic_object$2.next#lb253 == ((struct node *)NULL) || dynamic_object$2.next#lb253 == &dynamic_object$0 || dynamic_object$2.next#lb253 == &dynamic_object$1 || dynamic_object$2.next#lb253 == &dynamic_object$2)) && ($guard#184 && $guard#ls253 ==> dynamic_object$2.next#lb253 == &dynamic_object$1 && (dynamic_object$1.next#lb176 == ((struct node *)NULL) || dynamic_object$1.next#lb176 == &dynamic_object$0 || dynamic_object$1.next#lb176 == &dynamic_object$1 || dynamic_object$1.next#lb176 == &dynamic_object$2) || dynamic_object$2.next#lb253 == &dynamic_object$2 && (dynamic_object$2.next#lb253 == ((struct node *)NULL) || dynamic_object$2.next#lb253 == &dynamic_object$0 || dynamic_object$2.next#lb253 == &dynamic_object$1 || dynamic_object$2.next#lb253 == &dynamic_object$2)) && ($guard#274 && $guard#ls277 ==> beg#lb277 == &dynamic_object$1 && (dynamic_object$1.next#lb176 == ((struct node *)NULL) || dynamic_object$1.next#lb176 == &dynamic_object$0 || dynamic_object$1.next#lb176 == &dynamic_object$1 || dynamic_object$1.next#lb176 == &dynamic_object$2) || beg#lb277 == &dynamic_object$2 && (dynamic_object$2.next#lb253 == ((struct node *)NULL) || dynamic_object$2.next#lb253 == &dynamic_object$0 || dynamic_object$2.next#lb253 == &dynamic_object$1 || dynamic_object$2.next#lb253 == &dynamic_object$2)) && ($guard#291 && $guard#ls294 ==> beg#lb294 == &dynamic_object$0 && (dynamic_object$0.next#lb101 == ((struct node *)NULL) || dynamic_object$0.next#lb101 == &dynamic_object$0 || dynamic_object$0.next#lb101 == &dynamic_object$1) || beg#lb294 == &dynamic_object$1 && (dynamic_object$1.next#lb176 == ((struct node *)NULL) || dynamic_object$1.next#lb176 == &dynamic_object$0 || dynamic_object$1.next#lb176 == &dynamic_object$1)) +backward precondition: not computed +backward postcondition: not computed +backward transformer: not computed +backward invariant: not computed +termination argument: not computed +terminates: unknown + +Checking properties of _start +*** 0 +(E) $guard#0 == TRUE + +*** 2 file line 39 +(E) __CPROVER_dead_object#2 == NULL + +*** 3 file line 38 +(E) __CPROVER_deallocated#3 == NULL + +*** 4 file line 42 +(E) __CPROVER_malloc_is_new_array#4 == FALSE + +*** 5 file line 40 +(E) __CPROVER_malloc_object#5 == NULL + +*** 6 file line 41 +(E) __CPROVER_malloc_size#6 == 0ul + +*** 7 file line 43 +(E) __CPROVER_memory_leak#7 == NULL + +*** 8 file line 31 +(E) __CPROVER_next_thread_id#8 == 0ul + +*** 9 file line 87 +(E) __CPROVER_pipe_count#9 == 0u + +*** 10 file line 65 +(E) __CPROVER_rounding_mode#10 == 0 + +*** 11 file line 29 +(E) __CPROVER_thread_id#11 == 0ul + +*** 12 file line 30 +(E) __CPROVER_threads_exited#12 == ARRAY_OF(FALSE) + +*** 16 file main.c line 62 function main +(E) p1#16 == nondet_symbol(ssa::nondet16.1) + +*** 18 file main.c line 62 function main +(E) p2#18 == nondet_symbol(ssa::nondet18.1) + +*** 20 file main.c line 64 function main +(E) list#20 == nondet_symbol(ssa::nondet20.1) + +*** 23 file main.c line 64 function main +(E) pp1#23 == nondet_symbol(ssa::nondet23.1) + +*** 24 file main.c line 64 function main +(E) pp1#24 == &p1 + +*** 26 file main.c line 64 function main +(E) pp2#26 == nondet_symbol(ssa::nondet26.1) + +*** 27 file main.c line 64 function main +(E) pp2#27 == &p2 + +*** 28 file main.c line 28 function create_sll +(E) p2#28 == ((struct node *)NULL) + +*** 30 file main.c line 30 function create_sll +(E) i#30 == nondet_symbol(ssa::nondet30.1) + +*** 31 file main.c line 30 function create_sll +(E) i#31 == 0 + +*** 32 file main.c line 30 function create_sll +(E) __CPROVER_deallocated#phi32 == ($guard#ls101 ? __CPROVER_deallocated#lb101 : __CPROVER_deallocated#3) +(E) __CPROVER_malloc_object#phi32 == ($guard#ls101 ? __CPROVER_malloc_object#lb101 : __CPROVER_malloc_object#5) +(E) __CPROVER_malloc_size#phi32 == ($guard#ls101 ? __CPROVER_malloc_size#lb101 : __CPROVER_malloc_size#6) +(E) __CPROVER_malloc_is_new_array#phi32 == ($guard#ls101 ? __CPROVER_malloc_is_new_array#lb101 : __CPROVER_malloc_is_new_array#4) +(E) __CPROVER_memory_leak#phi32 == ($guard#ls101 ? __CPROVER_memory_leak#lb101 : __CPROVER_memory_leak#7) +(E) i#phi32 == ($guard#ls101 ? i#lb101 : i#31) +(E) p2#phi32 == ($guard#ls101 ? p2#lb101 : p2#28) +(E) dynamic_object$0.next#phi32 == ($guard#ls101 ? dynamic_object$0.next#lb101 : dynamic_object$0.next) +(E) $cond#32 == i#phi32 >= 2 +(E) $guard#32 == $guard#0 + +*** 33 file main.c line 32 function create_sll +(E) $guard#33 == (!$cond#32 && $guard#32) + +*** 35 file main.c line 32 function create_sll +(E) ppnode#35 == nondet_symbol(ssa::nondet35.1) + +*** 36 file main.c line 32 function create_sll +(E) ppnode#36 == pp2#27 + +*** 38 file main.c line 21 function chain_node +(E) node#38 == nondet_symbol(ssa::nondet38.1) + +*** 41 file main.c line 11 function alloc_node +(E) ptr#41 == nondet_symbol(ssa::nondet41.1) + +*** 43 file main.c line 11 function alloc_node +(E) return_value_malloc$1#43 == nondet_symbol(ssa::nondet43.1) + +*** 46 file main.c line 11 function alloc_node +(E) malloc_size#46 == nondet_symbol(ssa::nondet46.1) + +*** 47 file main.c line 11 function alloc_node +(E) malloc_size#47 == sizeof(struct node) /*8ul*/ + +*** 50 file main.c line 11 function alloc_node +(E) malloc_res#50 == nondet_symbol(ssa::nondet50.1) + +*** 52 file main.c line 11 function alloc_node +(E) malloc_value$1#52 == nondet_symbol(ssa::nondet52.1) + +*** 53 file main.c line 11 function alloc_node +(E) malloc_value$1#53 == (void *)&dynamic_object$0 + +*** 54 file main.c line 11 function alloc_node +(E) malloc_res#54 == malloc_value$1#53 + +*** 56 file main.c line 11 function alloc_node +(E) __CPROVER_deallocated#56 == (malloc_res#54 == __CPROVER_deallocated#phi32 ? NULL : __CPROVER_deallocated#phi32) + +*** 58 file main.c line 11 function alloc_node +(E) record_malloc#58 == nondet_symbol(ssa::nondet58.1) + +*** 59 file main.c line 11 function alloc_node +(E) __CPROVER_malloc_object#59 == (record_malloc#58 ? malloc_res#54 : __CPROVER_malloc_object#phi32) + +*** 60 file main.c line 11 function alloc_node +(E) __CPROVER_malloc_size#60 == (record_malloc#58 ? malloc_size#47 : __CPROVER_malloc_size#phi32) + +*** 61 file main.c line 11 function alloc_node +(E) __CPROVER_malloc_is_new_array#61 == (!record_malloc#58 && __CPROVER_malloc_is_new_array#phi32) + +*** 63 file main.c line 11 function alloc_node +(E) record_may_leak#63 == nondet_symbol(ssa::nondet63.1) + +*** 64 file main.c line 11 function alloc_node +(E) __CPROVER_memory_leak#64 == (record_may_leak#63 ? malloc_res#54 : __CPROVER_memory_leak#phi32) + +*** 65 file main.c line 11 function alloc_node +(E) malloc#return_value#65 == malloc_res#54 + +*** 70 file main.c line 11 function alloc_node +(E) $cond#70 == TRUE + +*** 71 file main.c line 11 function alloc_node +(E) $guard#71 == FALSE + +*** 75 file main.c line 11 function alloc_node +(E) $guard#75 == ($cond#70 && $guard#33 || $guard#71) + +*** 77 file main.c line 11 function alloc_node +(E) return_value_malloc$1#77 == malloc#return_value#65 + +*** 79 file main.c line 11 function alloc_node +(E) ptr#79 == (struct node *)return_value_malloc$1#77 + +*** 81 file main.c line 12 function alloc_node +(E) $cond#81 == !(ptr#79 == ((struct node *)NULL)) + +*** 82 file main.c line 13 function alloc_node +(E) $guard#82 == (!$cond#81 && $guard#75) + +*** 83 file line 6 function abort +(E) $cond#83 == FALSE + +*** 84 file line 7 function abort +(E) $guard#84 == ($cond#83 && $guard#82) + +*** 85 file main.c line 15 function alloc_node +(E) dynamic_object$0.next#85 == ((struct node *)NULL) +(E) $guard#85 == ($cond#81 && $guard#75 || $guard#84) + +*** 86 file main.c line 16 function alloc_node +(E) alloc_node#return_value#86 == ptr#79 + +*** 89 file main.c line 16 function alloc_node +(E) $cond#89 == TRUE + +*** 90 file main.c line 17 function alloc_node +(E) $guard#90 == FALSE + +*** 92 file main.c line 17 function alloc_node +(E) $guard#92 == ($cond#89 && $guard#85 || $guard#90) + +*** 93 file main.c line 21 function chain_node +(E) node#93 == alloc_node#return_value#86 + +*** 95 file main.c line 22 function chain_node +(E) dynamic_object$0.next#95 == (ppnode#36 == &p2 ? p2#phi32 : deref#95) + +*** 96 file main.c line 23 function chain_node +(E) p2#96 == node#93 + +*** 100 file main.c line 30 function create_sll +(E) i#100 == 1 + i#phi32 + +*** 101 file main.c line 30 function create_sll +(E) $cond#101 == TRUE +loop back to location 32 + +*** 102 file main.c line 33 function create_sll +(E) $guard#102 == ($cond#32 && $guard#32) + +*** 103 file main.c line 35 function create_sll +(E) p1#103 == (pp2#27 == &p2 ? p2#phi32 : deref#103) + +*** 105 file main.c line 37 function create_sll +(E) i#105 == nondet_symbol(ssa::nondet105.1) + +*** 106 file main.c line 37 function create_sll +(E) i#106 == 0 + +*** 107 file main.c line 37 function create_sll +(E) __CPROVER_deallocated#phi107 == ($guard#ls176 ? __CPROVER_deallocated#lb176 : __CPROVER_deallocated#phi32) +(E) __CPROVER_malloc_object#phi107 == ($guard#ls176 ? __CPROVER_malloc_object#lb176 : __CPROVER_malloc_object#phi32) +(E) __CPROVER_malloc_size#phi107 == ($guard#ls176 ? __CPROVER_malloc_size#lb176 : __CPROVER_malloc_size#phi32) +(E) __CPROVER_malloc_is_new_array#phi107 == ($guard#ls176 ? __CPROVER_malloc_is_new_array#lb176 : __CPROVER_malloc_is_new_array#phi32) +(E) __CPROVER_memory_leak#phi107 == ($guard#ls176 ? __CPROVER_memory_leak#lb176 : __CPROVER_memory_leak#phi32) +(E) i#phi107 == ($guard#ls176 ? i#lb176 : i#106) +(E) p1#phi107 == ($guard#ls176 ? p1#lb176 : p1#103) +(E) dynamic_object$1.next#phi107 == ($guard#ls176 ? dynamic_object$1.next#lb176 : dynamic_object$1.next) +(E) $cond#107 == i#phi107 >= 2 +(E) $guard#107 == $guard#102 + +*** 108 file main.c line 39 function create_sll +(E) $guard#108 == (!$cond#107 && $guard#107) + +*** 110 file main.c line 39 function create_sll +(E) ppnode#110 == nondet_symbol(ssa::nondet110.1) + +*** 111 file main.c line 39 function create_sll +(E) ppnode#111 == pp1#24 + +*** 113 file main.c line 21 function chain_node +(E) node#113 == nondet_symbol(ssa::nondet113.1) + +*** 116 file main.c line 11 function alloc_node +(E) ptr#116 == nondet_symbol(ssa::nondet116.1) + +*** 118 file main.c line 11 function alloc_node +(E) return_value_malloc$1#118 == nondet_symbol(ssa::nondet118.1) + +*** 121 file main.c line 11 function alloc_node +(E) malloc_size#121 == nondet_symbol(ssa::nondet121.1) + +*** 122 file main.c line 11 function alloc_node +(E) malloc_size#122 == sizeof(struct node) /*8ul*/ + +*** 125 file main.c line 11 function alloc_node +(E) malloc_res#125 == nondet_symbol(ssa::nondet125.1) + +*** 127 file main.c line 11 function alloc_node +(E) malloc_value$1#127 == nondet_symbol(ssa::nondet127.1) + +*** 128 file main.c line 11 function alloc_node +(E) malloc_value$1#128 == (void *)&dynamic_object$1 + +*** 129 file main.c line 11 function alloc_node +(E) malloc_res#129 == malloc_value$1#128 + +*** 131 file main.c line 11 function alloc_node +(E) __CPROVER_deallocated#131 == (malloc_res#129 == __CPROVER_deallocated#phi107 ? NULL : __CPROVER_deallocated#phi107) + +*** 133 file main.c line 11 function alloc_node +(E) record_malloc#133 == nondet_symbol(ssa::nondet133.1) + +*** 134 file main.c line 11 function alloc_node +(E) __CPROVER_malloc_object#134 == (record_malloc#133 ? malloc_res#129 : __CPROVER_malloc_object#phi107) + +*** 135 file main.c line 11 function alloc_node +(E) __CPROVER_malloc_size#135 == (record_malloc#133 ? malloc_size#122 : __CPROVER_malloc_size#phi107) + +*** 136 file main.c line 11 function alloc_node +(E) __CPROVER_malloc_is_new_array#136 == (!record_malloc#133 && __CPROVER_malloc_is_new_array#phi107) + +*** 138 file main.c line 11 function alloc_node +(E) record_may_leak#138 == nondet_symbol(ssa::nondet138.1) + +*** 139 file main.c line 11 function alloc_node +(E) __CPROVER_memory_leak#139 == (record_may_leak#138 ? malloc_res#129 : __CPROVER_memory_leak#phi107) + +*** 140 file main.c line 11 function alloc_node +(E) malloc#return_value#140 == malloc_res#129 + +*** 145 file main.c line 11 function alloc_node +(E) $cond#145 == TRUE + +*** 146 file main.c line 11 function alloc_node +(E) $guard#146 == FALSE + +*** 150 file main.c line 11 function alloc_node +(E) $guard#150 == ($cond#145 && $guard#108 || $guard#146) + +*** 152 file main.c line 11 function alloc_node +(E) return_value_malloc$1#152 == malloc#return_value#140 + +*** 154 file main.c line 11 function alloc_node +(E) ptr#154 == (struct node *)return_value_malloc$1#152 + +*** 156 file main.c line 12 function alloc_node +(E) $cond#156 == !(ptr#154 == ((struct node *)NULL)) + +*** 157 file main.c line 13 function alloc_node +(E) $guard#157 == (!$cond#156 && $guard#150) + +*** 158 file line 6 function abort +(E) $cond#158 == FALSE + +*** 159 file line 7 function abort +(E) $guard#159 == ($cond#158 && $guard#157) + +*** 160 file main.c line 15 function alloc_node +(E) dynamic_object$1.next#160 == ((struct node *)NULL) +(E) $guard#160 == ($cond#156 && $guard#150 || $guard#159) + +*** 161 file main.c line 16 function alloc_node +(E) alloc_node#return_value#161 == ptr#154 + +*** 164 file main.c line 16 function alloc_node +(E) $cond#164 == TRUE + +*** 165 file main.c line 17 function alloc_node +(E) $guard#165 == FALSE + +*** 167 file main.c line 17 function alloc_node +(E) $guard#167 == ($cond#164 && $guard#160 || $guard#165) + +*** 168 file main.c line 21 function chain_node +(E) node#168 == alloc_node#return_value#161 + +*** 170 file main.c line 22 function chain_node +(E) dynamic_object$1.next#170 == (ppnode#111 == &p1 ? p1#phi107 : deref#170) + +*** 171 file main.c line 23 function chain_node +(E) p1#171 == node#168 + +*** 175 file main.c line 37 function create_sll +(E) i#175 == 1 + i#phi107 + +*** 176 file main.c line 37 function create_sll +(E) $cond#176 == TRUE +loop back to location 107 + +*** 177 file main.c line 40 function create_sll +(E) $guard#177 == ($cond#107 && $guard#107) + +*** 179 file main.c line 42 function create_sll +(E) list#179 == nondet_symbol(ssa::nondet179.1) + +*** 180 file main.c line 42 function create_sll +(E) list#180 == (pp1#24 == &p1 ? p1#phi107 : deref#180) + +*** 182 file main.c line 44 function create_sll +(E) i#182 == nondet_symbol(ssa::nondet182.1) + +*** 183 file main.c line 44 function create_sll +(E) i#183 == 0 + +*** 184 file main.c line 44 function create_sll +(E) __CPROVER_deallocated#phi184 == ($guard#ls253 ? __CPROVER_deallocated#lb253 : __CPROVER_deallocated#phi107) +(E) __CPROVER_malloc_object#phi184 == ($guard#ls253 ? __CPROVER_malloc_object#lb253 : __CPROVER_malloc_object#phi107) +(E) __CPROVER_malloc_size#phi184 == ($guard#ls253 ? __CPROVER_malloc_size#lb253 : __CPROVER_malloc_size#phi107) +(E) __CPROVER_malloc_is_new_array#phi184 == ($guard#ls253 ? __CPROVER_malloc_is_new_array#lb253 : __CPROVER_malloc_is_new_array#phi107) +(E) __CPROVER_memory_leak#phi184 == ($guard#ls253 ? __CPROVER_memory_leak#lb253 : __CPROVER_memory_leak#phi107) +(E) list#phi184 == ($guard#ls253 ? list#lb253 : list#180) +(E) i#phi184 == ($guard#ls253 ? i#lb253 : i#183) +(E) dynamic_object$2.next#phi184 == ($guard#ls253 ? dynamic_object$2.next#lb253 : dynamic_object$2.next) +(E) $cond#184 == i#phi184 >= 2 +(E) $guard#184 == $guard#177 + +*** 185 file main.c line 46 function create_sll +(E) $guard#185 == (!$cond#184 && $guard#184) + +*** 187 file main.c line 46 function create_sll +(E) ppnode#187 == nondet_symbol(ssa::nondet187.1) + +*** 188 file main.c line 46 function create_sll +(E) ppnode#188 == &list + +*** 190 file main.c line 21 function chain_node +(E) node#190 == nondet_symbol(ssa::nondet190.1) + +*** 193 file main.c line 11 function alloc_node +(E) ptr#193 == nondet_symbol(ssa::nondet193.1) + +*** 195 file main.c line 11 function alloc_node +(E) return_value_malloc$1#195 == nondet_symbol(ssa::nondet195.1) + +*** 198 file main.c line 11 function alloc_node +(E) malloc_size#198 == nondet_symbol(ssa::nondet198.1) + +*** 199 file main.c line 11 function alloc_node +(E) malloc_size#199 == sizeof(struct node) /*8ul*/ + +*** 202 file main.c line 11 function alloc_node +(E) malloc_res#202 == nondet_symbol(ssa::nondet202.1) + +*** 204 file main.c line 11 function alloc_node +(E) malloc_value$1#204 == nondet_symbol(ssa::nondet204.1) + +*** 205 file main.c line 11 function alloc_node +(E) malloc_value$1#205 == (void *)&dynamic_object$2 + +*** 206 file main.c line 11 function alloc_node +(E) malloc_res#206 == malloc_value$1#205 + +*** 208 file main.c line 11 function alloc_node +(E) __CPROVER_deallocated#208 == (malloc_res#206 == __CPROVER_deallocated#phi184 ? NULL : __CPROVER_deallocated#phi184) + +*** 210 file main.c line 11 function alloc_node +(E) record_malloc#210 == nondet_symbol(ssa::nondet210.1) + +*** 211 file main.c line 11 function alloc_node +(E) __CPROVER_malloc_object#211 == (record_malloc#210 ? malloc_res#206 : __CPROVER_malloc_object#phi184) + +*** 212 file main.c line 11 function alloc_node +(E) __CPROVER_malloc_size#212 == (record_malloc#210 ? malloc_size#199 : __CPROVER_malloc_size#phi184) + +*** 213 file main.c line 11 function alloc_node +(E) __CPROVER_malloc_is_new_array#213 == (!record_malloc#210 && __CPROVER_malloc_is_new_array#phi184) + +*** 215 file main.c line 11 function alloc_node +(E) record_may_leak#215 == nondet_symbol(ssa::nondet215.1) + +*** 216 file main.c line 11 function alloc_node +(E) __CPROVER_memory_leak#216 == (record_may_leak#215 ? malloc_res#206 : __CPROVER_memory_leak#phi184) + +*** 217 file main.c line 11 function alloc_node +(E) malloc#return_value#217 == malloc_res#206 + +*** 222 file main.c line 11 function alloc_node +(E) $cond#222 == TRUE + +*** 223 file main.c line 11 function alloc_node +(E) $guard#223 == FALSE + +*** 227 file main.c line 11 function alloc_node +(E) $guard#227 == ($cond#222 && $guard#185 || $guard#223) + +*** 229 file main.c line 11 function alloc_node +(E) return_value_malloc$1#229 == malloc#return_value#217 + +*** 231 file main.c line 11 function alloc_node +(E) ptr#231 == (struct node *)return_value_malloc$1#229 + +*** 233 file main.c line 12 function alloc_node +(E) $cond#233 == !(ptr#231 == ((struct node *)NULL)) + +*** 234 file main.c line 13 function alloc_node +(E) $guard#234 == (!$cond#233 && $guard#227) + +*** 235 file line 6 function abort +(E) $cond#235 == FALSE + +*** 236 file line 7 function abort +(E) $guard#236 == ($cond#235 && $guard#234) + +*** 237 file main.c line 15 function alloc_node +(E) dynamic_object$2.next#237 == ((struct node *)NULL) +(E) $guard#237 == ($cond#233 && $guard#227 || $guard#236) + +*** 238 file main.c line 16 function alloc_node +(E) alloc_node#return_value#238 == ptr#231 + +*** 241 file main.c line 16 function alloc_node +(E) $cond#241 == TRUE + +*** 242 file main.c line 17 function alloc_node +(E) $guard#242 == FALSE + +*** 244 file main.c line 17 function alloc_node +(E) $guard#244 == ($cond#241 && $guard#237 || $guard#242) + +*** 245 file main.c line 21 function chain_node +(E) node#245 == alloc_node#return_value#238 + +*** 247 file main.c line 22 function chain_node +(E) dynamic_object$2.next#247 == (ppnode#188 == &list ? list#phi184 : deref#247) + +*** 248 file main.c line 23 function chain_node +(E) list#248 == node#245 + +*** 252 file main.c line 44 function create_sll +(E) i#252 == 1 + i#phi184 + +*** 253 file main.c line 44 function create_sll +(E) $cond#253 == TRUE +loop back to location 184 + +*** 254 file main.c line 47 function create_sll +(E) $guard#254 == ($cond#184 && $guard#184) + +*** 255 file main.c line 49 function create_sll +(E) create_sll#return_value#255 == list#phi184 + +*** 257 file main.c line 49 function create_sll +(E) $cond#257 == TRUE + +*** 258 file main.c line 50 function create_sll +(E) $guard#258 == FALSE + +*** 259 file main.c line 50 function create_sll +(E) $guard#259 == ($cond#257 && $guard#254 || $guard#258) + +*** 262 file main.c line 64 function main +(E) list#262 == create_sll#return_value#255 + +*** 266 file main.c line 65 function main +(E) beg#266 == nondet_symbol(ssa::nondet266.1) + +*** 267 file main.c line 65 function main +(E) beg#267 == list#262 + +*** 269 file main.c line 65 function main +(E) end#269 == nondet_symbol(ssa::nondet269.1) + +*** 270 file main.c line 65 function main +(E) end#270 == p1#phi107 + +*** 271 file main.c line 53 function check_seq_next +(A) !(beg#267 == ((struct node *)NULL)) || !$guard#259 + +*** 272 file main.c line 54 function check_seq_next +(A) !(end#270 == ((struct node *)NULL)) || !$guard#259 + +*** 273 file main.c line 56 function check_seq_next +(E) beg#273 == (beg#267 == &dynamic_object$2 ? dynamic_object$2.next#phi184 : (beg#267 == &dynamic_object$1 ? dynamic_object$1.next#phi107 : (beg#267 == &dynamic_object$0 ? dynamic_object$0.next#phi32 : deref#273.next))) + +*** 274 file main.c line 56 function check_seq_next +(E) beg#phi274 == ($guard#ls277 ? beg#lb277 : beg#273) +(E) $cond#274 == (end#270 == beg#phi274) +(E) $guard#274 == $guard#259 + +*** 275 file main.c line 57 function check_seq_next +(E) $guard#275 == (!$cond#274 && $guard#274) +(A) !(beg#phi274 == ((struct node *)NULL)) || !$guard#275 + +*** 276 file main.c line 56 function check_seq_next +(E) beg#276 == (beg#phi274 == &dynamic_object$2 ? dynamic_object$2.next#phi184 : (beg#phi274 == &dynamic_object$1 ? dynamic_object$1.next#phi107 : (beg#phi274 == &dynamic_object$0 ? dynamic_object$0.next#phi32 : deref#276.next))) + +*** 277 file main.c line 56 function check_seq_next +(E) $cond#277 == TRUE +loop back to location 274 + +*** 278 file main.c line 58 function check_seq_next +(E) $guard#278 == ($cond#274 && $guard#274) + +*** 283 file main.c line 66 function main +(E) beg#283 == nondet_symbol(ssa::nondet283.1) + +*** 284 file main.c line 66 function main +(E) beg#284 == p1#phi107 + +*** 286 file main.c line 66 function main +(E) end#286 == nondet_symbol(ssa::nondet286.1) + +*** 287 file main.c line 66 function main +(E) end#287 == p2#phi32 + +*** 288 file main.c line 53 function check_seq_next +(A) !(beg#284 == ((struct node *)NULL)) || !$guard#278 + +*** 289 file main.c line 54 function check_seq_next +(A) !(end#287 == ((struct node *)NULL)) || !$guard#278 + +*** 290 file main.c line 56 function check_seq_next +(E) beg#290 == (beg#284 == &dynamic_object$1 ? dynamic_object$1.next#phi107 : (beg#284 == &dynamic_object$0 ? dynamic_object$0.next#phi32 : deref#290.next)) + +*** 291 file main.c line 56 function check_seq_next +(E) beg#phi291 == ($guard#ls294 ? beg#lb294 : beg#290) +(E) $cond#291 == (end#287 == beg#phi291) +(E) $guard#291 == $guard#278 + +*** 292 file main.c line 57 function check_seq_next +(E) $guard#292 == (!$cond#291 && $guard#291) +(A) !(beg#phi291 == ((struct node *)NULL)) || !$guard#292 + +*** 293 file main.c line 56 function check_seq_next +(E) beg#293 == (beg#phi291 == &dynamic_object$1 ? dynamic_object$1.next#phi107 : (beg#phi291 == &dynamic_object$0 ? dynamic_object$0.next#phi32 : deref#293.next)) + +*** 294 file main.c line 56 function check_seq_next +(E) $cond#294 == TRUE +loop back to location 291 + +*** 295 file main.c line 58 function check_seq_next +(E) $guard#295 == ($cond#291 && $guard#291) + +(enable) TRUE + + +Callee summaries: +Callee bindings: + +Loops not fully unwound +Running refinement loop with MiniSAT 2.2.1 with simplifier +** 0 of 6 failed (1 iterations) +** statistics: + number of solver instances: 1 + number of solver calls: 14 + number of summaries used: 0 + +[check_seq_next.assertion.1] assertion beg != (struct node *)(void *)0: OK +[check_seq_next.assertion.2] assertion end != (struct node *)(void *)0: OK +[check_seq_next.assertion.3] assertion beg != (struct node *)(void *)0: OK +[check_seq_next.assertion.4] assertion beg != (struct node *)(void *)0: OK +[check_seq_next.assertion.5] assertion end != (struct node *)(void *)0: OK +[check_seq_next.assertion.6] assertion beg != (struct node *)(void *)0: OK + +** 0 of 6 unknown +** 0 of 6 failed +VERIFICATION SUCCESSFUL +EXIT=0 +SIGNAL=0 diff --git a/regression/heap/sll_to_dll1_reverse/main.c b/regression/heap/sll_to_dll1_reverse/main.c index e8d0d1829..f25d00f7e 100644 --- a/regression/heap/sll_to_dll1_reverse/main.c +++ b/regression/heap/sll_to_dll1_reverse/main.c @@ -1,3 +1,5 @@ +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + #include extern int __VERIFIER_nondet_int(void); @@ -10,8 +12,8 @@ struct node { static struct node* alloc_node(void) { struct node *ptr = malloc(sizeof *ptr); - if (!ptr) - abort(); + // if (!ptr) + // abort(); ptr->next = NULL; ptr->prev = NULL; @@ -35,8 +37,9 @@ static struct node* create_sll(const struct node **pp1, const struct node **pp2) *pp1 = *pp2; - while (__VERIFIER_nondet_int()) + do chain_node(pp1); + while (__VERIFIER_nondet_int()); struct node *list = *pp1; @@ -48,10 +51,10 @@ static struct node* create_sll(const struct node **pp1, const struct node **pp2) } void init_back_link(struct node *list) { - for (;;) { + while (list) { struct node *next = list->next; - if (!next) - return; + // if (!next) + // return; next->prev = list; list = next; @@ -96,19 +99,19 @@ void main() const struct node *p1, *p2; struct node *list = create_sll(&p1, &p2); - check_seq_next(p1, p2); assert(p1->prev == NULL); assert(p2->prev == NULL); + check_seq_next(p1, p2); init_back_link(list); check_seq_next(p1, p2); check_seq_prev(p2, p1); - reverse_dll(list); - check_seq_prev(p1, p2); - check_seq_next(p2, p1); + // reverse_dll(list); + // check_seq_prev(p1, p2); + // check_seq_next(p2, p1); remove_fw_link(list); - check_seq_prev(p1, p2); + check_seq_prev(p2, p1); } diff --git a/regression/heap/sll_to_dll1_reverse/test.desc b/regression/heap/sll_to_dll1_reverse/test.desc index 92784083a..ed14b476a 100644 --- a/regression/heap/sll_to_dll1_reverse/test.desc +++ b/regression/heap/sll_to_dll1_reverse/test.desc @@ -1,4 +1,4 @@ -KNOWNBUG +CORE main.c --heap --inline --no-propagation ^EXIT=0$ diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index c4daa5062..3af05b446 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -4,6 +4,7 @@ #include "heap_domain.h" #include "util.h" +#include "domain.h" #include #include @@ -60,7 +61,7 @@ void heap_domaint::make_template(const domaint::var_specst &var_specs, const nam templ_row.member = component.get_name(); templ_row.pre_guard = v1->pre_guard; templ_row.post_guard = v1->post_guard; - templ_row.aux_expr = v1->post_guard; + templ_row.aux_expr = v1->aux_expr; templ_row.kind = v1->kind; templ_row.dynamic = dynamic; if (dynamic) diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index d602ee17a..68a129f2f 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -101,8 +101,10 @@ class heap_domaint : public domaint // p = d path_expr.push_back(equal_exprt(templ_expr, dest)); } - for (const dyn_objt &obj1 : path.dyn_objects) + for (const dyn_objt &obj1 : points_to) { + if (path.dyn_objects.find(obj1) != path.dyn_objects.end()) + { // p = &o exprt equ_exprt = equal_exprt(templ_expr, address_of_exprt(obj1.first)); @@ -117,6 +119,13 @@ class heap_domaint : public domaint } path_expr.push_back(and_exprt(equ_exprt, disjunction(step_expr))); + } + else + { + path_expr.push_back(equal_exprt(templ_expr, + is_null_ptr(obj1.first) ? + obj1.first : address_of_exprt(obj1.first))); + } } result.push_back(disjunction(path_expr)); @@ -127,7 +136,7 @@ class heap_domaint : public domaint inline bool empty() const { - return paths.empty() && points_to.empty(); + return paths.empty(); } }; diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index 2051dbc95..0291f02fc 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -69,6 +69,10 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) exprt c = heap_domain.get_row_pre_constraint(i, inv[i]).op1(); debug() << "cond: " << from_expr(ns, "", c) << " " << from_expr(ns, "", solver.get(c)) << eom; + forall_operands(it, c) + { + debug() << from_expr(ns, "", *it) << " " << from_expr(ns, "", solver.get(*it)) << eom; + } debug() << "guards: " << from_expr(ns, "", heap_domain.templ[i].pre_guard) << " " << from_expr(ns, "", solver.get(heap_domain.templ[i].pre_guard)) << eom; debug() << "guards: " << from_expr(ns, "", heap_domain.templ[i].post_guard) << " " @@ -76,6 +80,10 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) exprt post = heap_domain.get_row_post_constraint(i, inv[i]).op1(); debug() << "post-cond: " << from_expr(ns, "", post) << " " << from_expr(ns, "", solver.get(post)) << eom; + forall_operands(it, post) + { + debug() << from_expr(ns, "", *it) << " " << from_expr(ns, "", solver.get(*it)) << eom; + } } #endif @@ -104,7 +112,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) improved = true; debug() << "add points to: " << from_expr(ns, "", ptr_value) << eom; } - else + else if (ptr_value.id() == ID_address_of) { // pointer points to the heap (p = &obj) debug() << from_expr(ns, "", ptr_value) << eom; @@ -115,14 +123,20 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) if (obj.type().get_bool("#dynamic")) { // Find row with corresponding member field of pointed object (obj.member) + int member_val_index; if (inv[row].empty() && heap_domain.templ[row].dyn_obj.id() != ID_nil && heap_domain.get_base_name(obj) == heap_domain.get_base_name(heap_domain.templ[row].dyn_obj)) { - --actual_loc; + member_val_index = find_member_row(obj, heap_domain.templ[row].member, --actual_loc); + if (member_val_index < 0) + member_val_index = find_member_row(obj, heap_domain.templ[row].member, + ++actual_loc); + } + else + { + member_val_index = find_member_row(obj, heap_domain.templ[row].member, actual_loc); } - int member_val_index = find_member_row(obj, heap_domain.templ[row].member, - actual_loc); assert(member_val_index >= 0); exprt member_expr = heap_domain.templ[member_val_index].expr; exprt do_expr = heap_domain.templ[member_val_index].dyn_obj; From 0a659066b69c80b9aaa0c324581593b53029a7c0 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 22 Sep 2016 14:26:51 +0100 Subject: [PATCH 022/322] Heap domain: recursive updating values of template rows when a dependent row is changed. --- src/domains/heap_domain.cpp | 17 ++++++-- src/domains/heap_domain.h | 7 +++- src/domains/strategy_solver_heap.cpp | 62 +++++++++++++++------------- src/domains/strategy_solver_heap.h | 3 ++ 4 files changed, 54 insertions(+), 35 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 3af05b446..84c04f9cc 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -21,6 +21,7 @@ void heap_domaint::initialize(domaint::valuet &value) { val[row].paths.clear(); val[row].points_to.clear(); + val[row].pointed_by.clear(); } } @@ -66,11 +67,8 @@ void heap_domaint::make_template(const domaint::var_specst &var_specs, const nam templ_row.dynamic = dynamic; if (dynamic) { - int loc_num = get_symbol_loc(var1); std::string var1_id = id2string(to_symbol_expr(var1).get_identifier()); - std::string do_base_id = var1_id.substr(0, var1_id.find_last_of('.')); - // TODO just add the whole suffix - irep_idt do_id = do_base_id + "#lb" + std::to_string(loc_num); + std::string do_id = var1_id.substr(0, var1_id.find_last_of('.')); templ_row.dyn_obj = symbol_exprt(do_id, var1.type().subtype()); } else @@ -240,6 +238,17 @@ bool heap_domaint::add_points_to(const rowt &row, heap_valuet &value, const dyn_ return new_pt.second; } +/** + * Add new dependent row (pb_row points to row) + * @param row Pointed row + * @param pb_row Pointer row + * @param value Hepa value + */ +void heap_domaint::add_pointed_by_row(const rowt &row, const rowt &pb_row, heap_valuet &value) +{ + value[row].pointed_by.insert(pb_row); +} + void heap_domaint::output_value(std::ostream &out, const domaint::valuet &value, const namespacet &ns) const { diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index 68a129f2f..e3bb1ca47 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -58,8 +58,9 @@ class heap_domaint : public domaint } }; - std::set paths; /**< Set of paths leading from the row variable */ - std::set points_to; /**< Set of objects (or NULL) the row variable can point to */ + std::set paths; /**< Set of paths leading from the row variable */ + std::set points_to; /**< Set of objects (or NULL) the row variable can point to */ + std::set pointed_by; /**< Set of rows whose variables point to this row */ /** * Get expression for the row value. It is a conjunction of points to expression and path @@ -179,6 +180,8 @@ class heap_domaint : public domaint bool add_points_to(const rowt &row, heap_valuet &value, const dyn_objt &dyn_obj); + void add_pointed_by_row(const rowt &row, const rowt &pb_row, heap_valuet &value); + // Printing virtual void output_value(std::ostream &out, const valuet &value, const namespacet &ns) const override; diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index 0291f02fc..b332c86d7 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -69,10 +69,6 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) exprt c = heap_domain.get_row_pre_constraint(i, inv[i]).op1(); debug() << "cond: " << from_expr(ns, "", c) << " " << from_expr(ns, "", solver.get(c)) << eom; - forall_operands(it, c) - { - debug() << from_expr(ns, "", *it) << " " << from_expr(ns, "", solver.get(*it)) << eom; - } debug() << "guards: " << from_expr(ns, "", heap_domain.templ[i].pre_guard) << " " << from_expr(ns, "", solver.get(heap_domain.templ[i].pre_guard)) << eom; debug() << "guards: " << from_expr(ns, "", heap_domain.templ[i].post_guard) << " " @@ -80,10 +76,6 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) exprt post = heap_domain.get_row_post_constraint(i, inv[i]).op1(); debug() << "post-cond: " << from_expr(ns, "", post) << " " << from_expr(ns, "", solver.get(post)) << eom; - forall_operands(it, post) - { - debug() << from_expr(ns, "", *it) << " " << from_expr(ns, "", solver.get(*it)) << eom; - } } #endif @@ -154,30 +146,15 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) if (heap_domain.add_points_to(row, inv, std::make_pair(obj, member_expr))) improved = true; debug() << "add points to: " << from_expr(ns, "", obj) << eom; + + heap_domain.add_pointed_by_row((unsigned) member_val_index, row, inv); } } if (heap_domain.templ[row].dynamic) - { // Recursively check all expressions and update those that point to the dynamic object - // that this row variable belongs to. - for (unsigned j = 0; j < heap_domain.templ.size(); ++j) - { - if (heap_domain.templ[row].member == heap_domain.templ[j].member) - { - for (auto &pt : inv[j].points_to) - { - exprt pre_pointer = heap_domain.templ[row].expr; - if (pre_pointer == pt.second) - { - if (heap_domain.add_all_paths(j, row, inv, pt)) - improved = true; - debug() << "recursively updating row: " << j << eom; - debug() << "add all paths: " << from_expr(ns, "", pre_pointer) << ", through: " - << from_expr(ns, "", pt.first) << eom; - } - } - } - } + { // Recursively update all rows that are dependent on this row + updated_rows.clear(); + update_rows_rec(row, inv); } } } @@ -224,7 +201,7 @@ int strategy_solver_heapt::find_member_row(const exprt &obj, const irep_idt &mem for (unsigned i = 0; i < heap_domain.templ.size(); ++i) { heap_domaint::template_rowt &templ_row = heap_domain.templ[i]; - if (templ_row.member == member && templ_row.dyn_obj.id() != ID_nil) + if (templ_row.member == member && templ_row.dynamic) { std::string id = id2string(to_symbol_expr(templ_row.expr).get_identifier()); if (id.find(obj_id) != std::string::npos) @@ -240,3 +217,30 @@ int strategy_solver_heapt::find_member_row(const exprt &obj, const irep_idt &mem } return result; } + +/** + * Recursively update rows that point to given row. + * @param row Pointed row + * @param value Heap value + * @return True if any change occured + */ +bool strategy_solver_heapt::update_rows_rec(const heap_domaint::rowt &row, + heap_domaint::heap_valuet &value) +{ + updated_rows.insert(row); + bool result = false; + heap_domaint::template_rowt &templ_row = heap_domain.templ[row]; + for (auto &ptr : value[row].pointed_by) + { + if (heap_domain.add_all_paths(ptr, row, value, + std::make_pair(templ_row.dyn_obj, templ_row.expr))) + result = true; + debug() << "recursively updating row: " << ptr << eom; + debug() << "add all paths: " << from_expr(ns, "", templ_row.expr) << ", through: " + << from_expr(ns, "", templ_row.dyn_obj) << eom; + // Recursive update is called for each row only once + if (updated_rows.find(ptr) == updated_rows.end()) + result = update_rows_rec(ptr, value) || result; + } + return result; +} diff --git a/src/domains/strategy_solver_heap.h b/src/domains/strategy_solver_heap.h index edb63c9a4..5b22acf4e 100644 --- a/src/domains/strategy_solver_heap.h +++ b/src/domains/strategy_solver_heap.h @@ -21,8 +21,11 @@ class strategy_solver_heapt : public strategy_solver_baset protected: heap_domaint &heap_domain; + std::set updated_rows; int find_member_row(const exprt &obj, const irep_idt &member, int actual_loc); + + bool update_rows_rec(const heap_domaint::rowt &row, heap_domaint::heap_valuet &value); }; From fd2290f73555acec567fab0c125606b08813647c Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 23 Sep 2016 17:32:20 +0100 Subject: [PATCH 023/322] Heap domain: remove zero_length field from path. --- src/domains/heap_domain.cpp | 14 ++++---------- src/domains/heap_domain.h | 10 ++-------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 84c04f9cc..9fca9faf5 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -175,24 +175,18 @@ bool heap_domaint::add_row_path(const rowt &row, heap_valuet &value, const exprt { // Path does not exist yet std::set dyn_obj_set; - bool zero_path = true; if (dyn_obj.first.id() != ID_nil) { // Path doesn't have zero length dyn_obj_set.insert(dyn_obj); - zero_path = false; } - path_set.emplace(dest, dyn_obj_set, zero_path); + path_set.emplace(dest, dyn_obj_set); return true; } else { // Path exists already - if (dyn_obj.first.id() == ID_nil) - { - bool result = path_set.find(dest)->zero_length; - path_set.find(dest)->zero_length = true; - return !result; - } + if (dyn_obj.first.id() == ID_nil) return false; + // Try to insert new dynamic object belonging to the path return path_set.find(dest)->dyn_objects.insert(dyn_obj).second; } @@ -242,7 +236,7 @@ bool heap_domaint::add_points_to(const rowt &row, heap_valuet &value, const dyn_ * Add new dependent row (pb_row points to row) * @param row Pointed row * @param pb_row Pointer row - * @param value Hepa value + * @param value Heap value */ void heap_domaint::add_pointed_by_row(const rowt &row, const rowt &pb_row, heap_valuet &value) { diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index e3bb1ca47..8f75a37dd 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -40,12 +40,11 @@ class heap_domaint : public domaint { exprt destination; mutable std::set dyn_objects; - mutable bool zero_length; patht(const exprt &dest_) : destination(dest_) {} - patht(const exprt &dest_, const std::set &dyn_objs_, const bool zero_l_) - : destination(dest_), dyn_objects(dyn_objs_), zero_length(zero_l_) {} + patht(const exprt &dest_, const std::set &dyn_objs_) + : destination(dest_), dyn_objects(dyn_objs_) {} bool operator<(const patht &rhs) const { @@ -97,11 +96,6 @@ class heap_domaint : public domaint const exprt &dest = path.destination; exprt::operandst path_expr; - if (path.zero_length) - { - // p = d - path_expr.push_back(equal_exprt(templ_expr, dest)); - } for (const dyn_objt &obj1 : points_to) { if (path.dyn_objects.find(obj1) != path.dyn_objects.end()) From 78032354574805722bde7592619a091fe0f56c0e Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 23 Sep 2016 17:56:26 +0100 Subject: [PATCH 024/322] SSA dereference: replace "deref" for pointers to objects by real "unknown" objects. --- src/domains/strategy_solver_heap.cpp | 68 ++++++++++++---------- src/ssa/assignments.cpp | 2 +- src/ssa/local_ssa.cpp | 84 +++++++++++++++++++++++++++- src/ssa/local_ssa.h | 11 +++- src/ssa/malloc_ssa.cpp | 2 + src/ssa/ssa_dereference.cpp | 16 +++++- src/ssa/ssa_object.h | 6 ++ 7 files changed, 155 insertions(+), 34 deletions(-) diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index b332c86d7..68ee5ace2 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -114,40 +114,50 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) if (obj.type().get_bool("#dynamic")) { - // Find row with corresponding member field of pointed object (obj.member) - int member_val_index; - if (inv[row].empty() && heap_domain.templ[row].dyn_obj.id() != ID_nil && - heap_domain.get_base_name(obj) == - heap_domain.get_base_name(heap_domain.templ[row].dyn_obj)) + if (id2string(obj.get_identifier()).find("$unknown") != std::string::npos) { - member_val_index = find_member_row(obj, heap_domain.templ[row].member, --actual_loc); - if (member_val_index < 0) - member_val_index = find_member_row(obj, heap_domain.templ[row].member, - ++actual_loc); + if (heap_domain.add_points_to(row, inv, std::make_pair(obj, nil_exprt()))) + improved = true; + debug() << "add points to: " << from_expr(ns, "", obj) << eom; } else { - member_val_index = find_member_row(obj, heap_domain.templ[row].member, actual_loc); + // Find row with corresponding member field of pointed object (obj.member) + int member_val_index; + if (inv[row].empty() && heap_domain.templ[row].dyn_obj.id() != ID_nil && + heap_domain.get_base_name(obj) == + heap_domain.get_base_name(heap_domain.templ[row].dyn_obj)) + { + member_val_index = find_member_row(obj, heap_domain.templ[row].member, + --actual_loc); + if (member_val_index < 0) + member_val_index = find_member_row(obj, heap_domain.templ[row].member, + ++actual_loc); + } + else + { + member_val_index = find_member_row(obj, heap_domain.templ[row].member, actual_loc); + } + assert(member_val_index >= 0); + exprt member_expr = heap_domain.templ[member_val_index].expr; + exprt do_expr = heap_domain.templ[member_val_index].dyn_obj; + + // Add all paths from obj.next to p + if (heap_domain.add_all_paths(row, (unsigned) member_val_index, inv, + std::make_pair(obj, member_expr))) + improved = true; + debug() << "add all paths: " << from_expr(ns, "", member_expr) << ", through: " + << from_expr(ns, "", obj) << eom; + + assert(do_expr.id() != ID_nil); + // Add points to information + assert(do_expr.id() == ID_symbol); + if (heap_domain.add_points_to(row, inv, std::make_pair(obj, member_expr))) + improved = true; + debug() << "add points to: " << from_expr(ns, "", obj) << eom; + + heap_domain.add_pointed_by_row((unsigned) member_val_index, row, inv); } - assert(member_val_index >= 0); - exprt member_expr = heap_domain.templ[member_val_index].expr; - exprt do_expr = heap_domain.templ[member_val_index].dyn_obj; - - // Add all paths from obj.next to p - if (heap_domain.add_all_paths(row, (unsigned) member_val_index, inv, - std::make_pair(obj, member_expr))) - improved = true; - debug() << "add all paths: " << from_expr(ns, "", member_expr) << ", through: " - << from_expr(ns, "", obj) << eom; - - assert(do_expr.id() != ID_nil); - // Add points to information - assert(do_expr.id() == ID_symbol); - if (heap_domain.add_points_to(row, inv, std::make_pair(obj, member_expr))) - improved = true; - debug() << "add points to: " << from_expr(ns, "", obj) << eom; - - heap_domain.add_pointed_by_row((unsigned) member_val_index, row, inv); } } diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index 2a5bc1c6b..5c977cb6b 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -121,7 +121,7 @@ void assignmentst::assign( // object? ssa_objectt ssa_object(lhs, ns); - if(ssa_object) + if(ssa_object && !ssa_object.is_unknown_obj()) // unknown objects are just placeholders { assign(ssa_object, loc, ns); } diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index f86fbb092..d9a941cc5 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -58,6 +58,7 @@ void local_SSAt::build_SSA() build_guard(i_it); build_assertions(i_it); build_function_call(i_it); + build_unknown_objs(i_it); } // collect custom templates in loop heads @@ -1344,7 +1345,10 @@ void local_SSAt::assign_rec( else if(lhs.id()==ID_if) { const if_exprt &if_expr=to_if_expr(lhs); - assign_rec(if_expr.true_case(), rhs, and_exprt(guard, if_expr.cond()), loc); + + exprt new_rhs = if_exprt(if_expr.cond(), rhs, if_expr.true_case()); + assign_rec(if_expr.true_case(), new_rhs, and_exprt(guard, if_expr.cond()), loc); + assign_rec( if_expr.false_case(), rhs, @@ -1559,6 +1563,18 @@ std::list &operator<<( { dest.push_back(*c_it); } + + for (auto &obj : src.unknown_objs) + { + const typet &obj_type = src.ns.follow(obj.type()); + if (obj_type.id() == ID_struct) + { + for (auto &component : to_struct_type(obj_type).components()) + { + dest.push_back(src.unknown_obj_eq(obj, component)); + } + } + } } #endif @@ -1609,6 +1625,18 @@ decision_proceduret &operator<<( dest << *c_it; } } + + for (auto &obj : src.unknown_objs) + { + const typet &obj_type = src.ns.follow(obj.type()); + if (obj_type.id() == ID_struct) + { + for (auto &component : to_struct_type(obj_type).components()) + { + dest << src.unknown_obj_eq(obj, component); + } + } + } #endif return dest; } @@ -1677,6 +1705,18 @@ incremental_solvert &operator<<( dest << *c_it; } } + + for (auto &obj : src.unknown_objs) + { + const typet &obj_type = src.ns.follow(obj.type()); + if (obj_type.id() == ID_struct) + { + for (auto &component : to_struct_type(obj_type).components()) + { + dest << src.unknown_obj_eq(obj, component); + } + } + } #endif return dest; } @@ -1736,3 +1776,45 @@ bool local_SSAt::has_function_calls() const return found; } +/** + * If a location is malloc call, create "unknown object" for return type. This is later used + * as a placeholder for invalid of unknown dereference of an object of that type. + * @param loc Location + */ +void local_SSAt::build_unknown_objs(locationt loc) +{ + if (loc->is_assign()) + { + const code_assignt &code_assign = to_code_assign(loc->code); + const exprt &rhs = code_assign.rhs(); + if (rhs.get_bool("#malloc_result")) + { + const exprt &addr_of_do = rhs.id() == ID_typecast ? to_typecast_expr(rhs).op() : rhs; + const exprt &dyn_obj = to_address_of_expr(addr_of_do).object(); + const typet &dyn_type = ns.follow(dyn_obj.type()); + + std::string dyn_type_name = dyn_type.id_string(); + if (dyn_type.id() == ID_struct) + dyn_type_name += "_" + id2string(to_struct_type(dyn_type).get_tag()); + irep_idt identifier = "ssa::" + dyn_type_name + "_obj$unknown"; + + symbol_exprt unknown_obj(identifier, dyn_obj.type()); + unknown_objs.insert(unknown_obj); + } + } +} + +/** + * Create equality obj.component = &obj, which creates self-loop on "unknown" objects. + * @param obj "Unknown" object + * @param component Object's component + * @return Equality obj.component = &obj + */ +exprt local_SSAt::unknown_obj_eq(const symbol_exprt &obj, + const struct_typet::componentt &component) const +{ + const irep_idt identifier = + id2string(obj.get_identifier()) + "." + id2string(component.get_name()); + const symbol_exprt member(identifier, component.type()); + return equal_exprt(member, address_of_exprt(obj)); +} diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 0f8fcc477..38914d95a 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" @@ -123,9 +124,12 @@ class local_SSAt // function entry and exit variables typedef std::list var_listt; typedef std::set var_sett; - var_listt params; + var_listt params; var_sett globals_in, globals_out; + // unknown heap objects + var_sett unknown_objs; + bool has_function_calls() const; const namespacet &ns; @@ -162,6 +166,8 @@ class local_SSAt void assign_rec( const exprt &lhs, const exprt &rhs, const exprt &guard, locationt loc); + exprt unknown_obj_eq(const symbol_exprt &obj, const struct_typet::componentt &component) const; + void get_entry_exit_vars(); bool has_static_lifetime(const ssa_objectt &) const; @@ -212,6 +218,7 @@ class local_SSAt void build_guard(locationt loc); void build_function_call(locationt loc); void build_assertions(locationt loc); + void build_unknown_objs(locationt loc); // custom templates void collect_custom_templates(); diff --git a/src/ssa/malloc_ssa.cpp b/src/ssa/malloc_ssa.cpp index 9e2263f9b..9a51ba3f9 100644 --- a/src/ssa/malloc_ssa.cpp +++ b/src/ssa/malloc_ssa.cpp @@ -165,6 +165,8 @@ exprt malloc_ssa( if(result.type()!=code.type()) result=typecast_exprt(result, code.type()); + result.set("#malloc_result", true); + return result; } diff --git a/src/ssa/ssa_dereference.cpp b/src/ssa/ssa_dereference.cpp index 3bc60c5c8..f6be56299 100644 --- a/src/ssa/ssa_dereference.cpp +++ b/src/ssa/ssa_dereference.cpp @@ -325,7 +325,21 @@ exprt dereference_rec( // We use the identifier produced by // local_SSAt::replace_side_effects_rec - exprt result=symbol_exprt(nondet_prefix, src.type()); + exprt result; + const typet &pointed_type = pointer.type().subtype(); + if (pointed_type.id() == ID_pointer) + result = symbol_exprt(nondet_prefix, src.type()); + else + { + const typet &obj_type = ns.follow(pointed_type); + std::string dyn_type_name = obj_type.id_string(); + if (obj_type.id() == ID_struct) + dyn_type_name += "_" + id2string(to_struct_type(obj_type).get_tag()); + irep_idt identifier = "ssa::" + dyn_type_name + "_obj$unknown"; + + result = symbol_exprt(identifier, src.type()); + } + // query the value sets const ssa_value_domaint::valuest values= diff --git a/src/ssa/ssa_object.h b/src/ssa/ssa_object.h index 37f4b8c8e..1cb21ec1d 100644 --- a/src/ssa/ssa_object.h +++ b/src/ssa/ssa_object.h @@ -84,6 +84,12 @@ class ssa_objectt return get_root_object_rec(expr); } + inline bool is_unknown_obj() + { + std::string id_str = id2string(identifier); + return id_str.find("$unknown") != std::string::npos; + } + protected: exprt expr; identifiert identifier; From 8d6eba70d978136024d2a31a6ceefa34c809977f Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 30 Sep 2016 10:31:28 +0100 Subject: [PATCH 025/322] SSA: add pointed object into globals only if it is assigned in the function, or the original pointer is parameter. --- src/ssa/local_ssa.cpp | 29 +++++++++++++++-------------- src/ssa/ssa_object.cpp | 6 ++---- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index d9a941cc5..43031bad9 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -150,6 +150,21 @@ void local_SSAt::get_globals( id2string(returns_for_function)+"#return_value")==std::string::npos) continue; + const exprt &root_obj=it->get_root_object(); + if(is_ptr_object(root_obj)) + { + const symbolt *symbol; + if(ns.lookup(root_obj.get(ID_ptr_object), symbol)) continue; + if(!symbol->is_parameter) + { + const ssa_domaint &ssa_domain=ssa_analysis[loc]; + // Filter out non-assigned symbols + const auto &def=ssa_domain.def_map.find(it->get_identifier()); + if(def->second.def.is_input()) + continue; + } + } + if(rhs_value) { const exprt &expr=read_rhs(it->get_expr(), loc); @@ -1678,20 +1693,6 @@ incremental_solvert &operator<<( 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 diff --git a/src/ssa/ssa_object.cpp b/src/ssa/ssa_object.cpp index 72440df3a..55f3e185f 100644 --- a/src/ssa/ssa_object.cpp +++ b/src/ssa/ssa_object.cpp @@ -231,9 +231,7 @@ void ssa_objectst::add_ptr_objects( { if(o_it->type().id()==ID_pointer) { - const symbolt &symbol=ns.lookup(root_object); - if(symbol.is_parameter) - tmp.insert(*o_it); + tmp.insert(*o_it); } } } @@ -280,7 +278,7 @@ void ssa_objectst::categorize_objects( if(root_object.id()==ID_symbol) { - if(is_ptr_object(root_object)) + if(is_ptr_object(root_object) || root_object.type().get_bool("#dynamic")) { globals.insert(*o_it); } From 20d3745894df3b3ae397e812a7faf26dcb7aa3c1 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 13 Oct 2016 14:35:19 +0100 Subject: [PATCH 026/322] Improve heap objects passing between functions. Objects pointed by parameters are passed to function as global. Handle heap objects pointed by return value of called function. --- src/ssa/assignments.cpp | 8 +++++- src/ssa/local_ssa.cpp | 56 ++++++++++++++++++++++++++++--------- src/ssa/ssa_dereference.cpp | 2 +- src/ssa/ssa_object.cpp | 19 +++++++++---- src/ssa/ssa_value_set.cpp | 13 +++++++++ 5 files changed, 77 insertions(+), 21 deletions(-) diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index 5c977cb6b..7c4d99e46 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -61,7 +61,13 @@ void assignmentst::build_assignment_map( for(objectst::const_iterator o_it=ssa_objects.globals.begin(); o_it!=ssa_objects.globals.end(); o_it++) - assign(*o_it, it, ns); + { + const exprt &function = code_function_call.function(); + if (function.id() == ID_symbol && + id2string(o_it->get_identifier()).find( + id2string(to_symbol_expr(function).get_identifier())) != std::string::npos) + assign(*o_it, it, ns); + } // the call might come with an assignment if(code_function_call.lhs().is_not_nil()) diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 43031bad9..dbf9bb8d0 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -95,13 +95,32 @@ void local_SSAt::get_entry_exit_vars() if(ns.lookup(identifier, symbol)) continue; - params.push_back(symbol->symbol_expr()); + const symbol_exprt ¶m=symbol->symbol_expr(); + params.push_back(param); + + if(param.type().id()==ID_pointer) + { + const typet &pointed_type=ns.follow(param.type().subtype()); + const symbol_exprt pointed_obj(id2string(param.get_identifier()) + "'obj", pointed_type); + nodes.begin()->equalities.push_back(equal_exprt(param, address_of_exprt(pointed_obj))); + } } // get globals in goto_programt::const_targett first=goto_function.body.instructions.begin(); get_globals(first, globals_in, true, false); // filters out #return_value + for(auto &global_in : globals_in) + { + if(global_in.type().id()==ID_pointer && + id2string(global_in.get_identifier()).find('.') == std::string::npos) + { + const typet &pointed_type=ns.follow(global_in.type().subtype()); + const symbol_exprt pointed_obj(id2string(global_in.get_identifier()) + "'obj", pointed_type); + nodes.begin()->equalities.push_back(equal_exprt(global_in, address_of_exprt(pointed_obj))); + } + } + // get globals out (includes return value) goto_programt::const_targett last=goto_function.body.instructions.end(); last--; @@ -142,21 +161,26 @@ void local_SSAt::get_globals( "#return_value")!=std::string::npos) continue; - // filter out return values of other functions + //filter out return values of other functions if(with_returns && returns_for_function!="" && - id2string(it->get_identifier()).find( - "#return_value")!=std::string::npos && + id2string(it->get_identifier()).find("#return_value")== + id2string(it->get_identifier()).size()-std::string("#return_value").size() && id2string(it->get_identifier()).find( id2string(returns_for_function)+"#return_value")==std::string::npos) continue; const exprt &root_obj=it->get_root_object(); + if(root_obj.type().get_bool("#dynamic") && !with_returns) + continue; if(is_ptr_object(root_obj)) { const symbolt *symbol; if(ns.lookup(root_obj.get(ID_ptr_object), symbol)) continue; if(!symbol->is_parameter) { + if(!with_returns || + id2string(it->get_identifier()).find("'obj")==std::string::npos) + continue; const ssa_domaint &ssa_domain=ssa_analysis[loc]; // Filter out non-assigned symbols const auto &def=ssa_domain.def_map.find(it->get_identifier()); @@ -1361,8 +1385,13 @@ void local_SSAt::assign_rec( { const if_exprt &if_expr=to_if_expr(lhs); - exprt new_rhs = if_exprt(if_expr.cond(), rhs, if_expr.true_case()); - assign_rec(if_expr.true_case(), new_rhs, and_exprt(guard, if_expr.cond()), loc); + if (if_expr.false_case().id() == ID_if) + { + exprt new_rhs = if_exprt(if_expr.cond(), rhs, if_expr.true_case()); + assign_rec(if_expr.true_case(), new_rhs, and_exprt(guard, if_expr.cond()), loc); + } + else + assign_rec(if_expr.true_case(), rhs, and_exprt(guard, if_expr.cond()), loc); assign_rec( if_expr.false_case(), @@ -1579,15 +1608,16 @@ std::list &operator<<( dest.push_back(*c_it); } - for (auto &obj : src.unknown_objs) + } + + for (auto &obj : src.unknown_objs) + { + const typet &obj_type = src.ns.follow(obj.type()); + if (obj_type.id() == ID_struct) { - const typet &obj_type = src.ns.follow(obj.type()); - if (obj_type.id() == ID_struct) + for (auto &component : to_struct_type(obj_type).components()) { - for (auto &component : to_struct_type(obj_type).components()) - { - dest.push_back(src.unknown_obj_eq(obj, component)); - } + dest.push_back(src.unknown_obj_eq(obj, component)); } } } diff --git a/src/ssa/ssa_dereference.cpp b/src/ssa/ssa_dereference.cpp index f6be56299..08c33e166 100644 --- a/src/ssa/ssa_dereference.cpp +++ b/src/ssa/ssa_dereference.cpp @@ -358,7 +358,7 @@ exprt dereference_rec( if (values.empty()) { // We use the identifier of pointed object irep_idt identifier = id2string(to_symbol_expr(pointer).get_identifier())+"'obj"; - result=symbol_exprt(identifier, src.type()); + result = symbol_exprt(identifier, ns.follow(pointed_type)); } return result; diff --git a/src/ssa/ssa_object.cpp b/src/ssa/ssa_object.cpp index 55f3e185f..cf5e047c9 100644 --- a/src/ssa/ssa_object.cpp +++ b/src/ssa/ssa_object.cpp @@ -229,7 +229,9 @@ void ssa_objectst::add_ptr_objects( exprt root_object=o_it->get_root_object(); if(root_object.id()==ID_symbol) { - if(o_it->type().id()==ID_pointer) + const symbolt &symbol = ns.lookup(root_object); + if(o_it->type().id()==ID_pointer && + (symbol.is_parameter || !symbol.is_procedure_local())) { tmp.insert(*o_it); } @@ -240,11 +242,16 @@ void ssa_objectst::add_ptr_objects( o_it!=tmp.end(); o_it++) { - typet type=o_it->type().subtype(); - irep_idt identifier=id2string(o_it->get_identifier())+"'obj"; - symbol_exprt ptr_object(identifier, type); - ptr_object.set(ID_ptr_object, o_it->get_identifier()); - collect_objects_rec(ptr_object, ns, objects, literals); + typet type = o_it->type(); + irep_idt identifier = o_it->get_identifier(); + do + { + type = type.subtype(); + identifier = id2string(identifier) + "'obj"; + symbol_exprt ptr_object(identifier, type); + ptr_object.set(ID_ptr_object, o_it->get_identifier()); + collect_objects_rec(ptr_object, ns, objects, literals); + } while (ns.follow(type).id() == ID_pointer); } } diff --git a/src/ssa/ssa_value_set.cpp b/src/ssa/ssa_value_set.cpp index aa362160e..e9b73940c 100644 --- a/src/ssa/ssa_value_set.cpp +++ b/src/ssa/ssa_value_set.cpp @@ -294,6 +294,19 @@ void ssa_value_domaint::assign_rhs_rec( tmp_values.alignment=merge_alignment(tmp_values.alignment, alignment); dest.merge(tmp_values); } + else if(ssa_object.type().id()==ID_pointer && + id2string(ssa_object.get_identifier()) + .find("#return_value")!=std::string::npos && + id2string(ssa_object.get_identifier())!="malloc#return_value") + { + // Pointer typed return value of some function points to some dynamic object + const typet &pointed_type=ns.follow(ssa_object.type().subtype()); + const symbol_exprt &pointed_obj=symbol_exprt( + id2string(ssa_object.get_identifier())+"'obj", pointed_type); + dest.value_set.insert(ssa_objectt(pointed_obj, ns)); + if(offset) + dest.offset=true; + } } else { From 6d861c17487db254acabf8db840baa10e7e58954 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sat, 4 Nov 2017 22:51:15 +0000 Subject: [PATCH 027/322] Fixes to heap domain --- src/domains/heap_domain.h | 22 +++---- src/solver/summary.h | 5 +- src/ssa/ssa_inliner.cpp | 135 +++++++++++++++++++++++++++++++++----- src/ssa/ssa_inliner.h | 14 +++- 4 files changed, 144 insertions(+), 32 deletions(-) diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index 8f75a37dd..748805c66 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -3,25 +3,26 @@ * * Viktor Malik, 12.8.2016 (c). */ -#ifndef CPROVER_HEAP_DOMAIN_H -#define CPROVER_HEAP_DOMAIN_H +#ifndef CPROVER_2LS_DOMAINS_HEAP_DOMAIN_H +#define CPROVER_2LS_DOMAINS_HEAP_DOMAIN_H -#include #include "domain.h" -class heap_domaint : public domaint +class heap_domaint:public domaint { public: typedef unsigned rowt; typedef vart member_fieldt; typedef std::pair dyn_objt; - heap_domaint(unsigned int _domain_number, replace_mapt &_renaming_map, - const var_specst &var_specs, - const namespacet &ns_) - : domaint(_domain_number, _renaming_map), ns(ns_) + heap_domaint( + unsigned int _domain_number, + replace_mapt &_renaming_map, + const var_specst &var_specs, + const namespacet &ns_): + domaint(_domain_number, _renaming_map, ns_) { - make_template(var_specs, ns); + make_template(var_specs, ns_); } /** @@ -195,7 +196,6 @@ class heap_domaint : public domaint protected: templatet templ; - namespacet ns; void make_template(const var_specst &var_specs, const namespacet &ns); @@ -208,4 +208,4 @@ class heap_domaint : public domaint }; -#endif //CPROVER_HEAP_DOMAIN_H +#endif // CPROVER_2LS_DOMAINS_HEAP_DOMAIN_H diff --git a/src/solver/summary.h b/src/solver/summary.h index 840a42230..0141d4bd4 100644 --- a/src/solver/summary.h +++ b/src/solver/summary.h @@ -13,6 +13,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include typedef enum {YES, NO, UNKNOWN} threevalt; @@ -38,7 +39,7 @@ class summaryt var_listt params; var_sett globals_in, globals_out; - + ssa_value_domaint value_domain; 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) @@ -58,6 +59,8 @@ class summaryt void join(const summaryt &new_summary); + void set_value_domain(const local_SSAt &SSA); + protected: void combine_or(exprt &olde, const exprt &newe); void combine_and(exprt &olde, const exprt &newe); diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index 18a34b042..3a72fbfa4 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -96,17 +96,11 @@ void ssa_inlinert::get_summary( // 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)); + bindings.push_back(get_replace_globals_out( + cs_globals_in, cs_globals_out, summary, SSA.ns)); else - bindings.push_back( - get_replace_globals_out( - summary.globals_in, - cs_globals_out, - cs_globals_in)); + bindings.push_back(get_replace_globals_out( + cs_globals_out, cs_globals_in, summary, SSA.ns)); } /*******************************************************************\ @@ -614,22 +608,76 @@ Function: ssa_inlinert::get_replace_globals_out \*******************************************************************/ exprt ssa_inlinert::get_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, + const summaryt &summary, + const namespacet &ns) { // 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); + exprt rhs; + + if(id2string(it->get_identifier()).find("'obj")!=std::string::npos && + it->get_identifier()!=get_original_identifier(*it)) + { + // variable is heap object (contains 'obj) and is assigned by the call + const irep_idt &id=get_original_identifier(*it); + if(is_struct_member(id)) + { + // variable is member of dynamic struct + const std::string member=id2string(id).substr(id2string(id).find_last_of(".")); + const irep_idt &root_id=id2string(id).substr(0, id2string(id).find_last_of(".")); + // find root object (must be in global variables) + symbol_exprt root_object; + for(auto &global : cs_globals_out) + { + if(get_original_identifier(global)==root_id) + root_object=global; + } + + // find corresponding dynamic object in called function + symbol_exprt dynamic_object; + assert(find_corresponding_dyn_obj(root_object, summary, ns, dynamic_object)); + + // restore member expression + dynamic_object.set_identifier(id2string(dynamic_object.get_identifier()) + member); + dynamic_object.type()=it->type(); + + assert(find_corresponding_symbol(dynamic_object, summary.globals_out, lhs)); + rename(lhs); + + rhs=*it; // copy + } + else + { // variable is dynamic object + // find corresponding dynamic object in called function + symbol_exprt dynamic_object; + assert(find_corresponding_dyn_obj(*it, summary, ns, dynamic_object)); + + // equality is between addresses of corresponding dynamic objects + exprt addr=address_of_exprt(dynamic_object); + rename(addr); + assert(addr.id()==ID_symbol); + + lhs=to_symbol_expr(addr); + + symbol_exprt orig_obj(id, dynamic_object.type()); + rhs=address_of_exprt(orig_obj); + } + } else - assert(find_corresponding_symbol(*it, cs_globals_in, lhs)); - c.push_back(equal_exprt(lhs, rhs)); + { + rhs=*it; // copy + if (find_corresponding_symbol(*it, summary.globals_out, lhs)) + rename(lhs); + else + assert(find_corresponding_symbol(*it, cs_globals_in, lhs)); + } + c.push_back(equal_exprt(lhs,rhs)); } return conjunction (c); } @@ -705,6 +753,17 @@ void ssa_inlinert::rename(exprt &expr) irep_idt id=id2string(sexpr.get_identifier())+"@"+i2string(counter); sexpr.set_identifier(id); } + else if (expr.id() == ID_address_of) + { + irep_idt id; + const exprt &obj = to_address_of_expr(expr).object(); + if (obj.id() == ID_symbol) + { + id = id2string(to_symbol_expr(obj).get_identifier()) + "'addr" + "@" + i2string(counter); + } + symbol_exprt addr_symbol(id, expr.type()); + expr = addr_symbol; + } Forall_operands(op, expr) rename(*op); } @@ -965,6 +1024,7 @@ irep_idt ssa_inlinert::get_original_identifier(const symbol_exprt &s) { if(!(c=='#' || c=='@' || c=='%' || c=='!' || c=='$') && !(c=='p' || c=='h' || c=='i') && + !(c=='l' || c=='b') && !('0'<=c && c<='9')) pos=std::string::npos; } @@ -974,3 +1034,44 @@ irep_idt ssa_inlinert::get_original_identifier(const symbol_exprt &s) return id; } +/** + * Test if variable is member of struct. + * @param identifier Id of variable + * @return + */ +bool ssa_inlinert::is_struct_member(const irep_idt &identifier) +{ + const std::string id = id2string(identifier); + return id.find(".") != std::string::npos && + id.find_first_of("#$@'%!", id.find_last_of(".")) == std::string::npos; +} + +/** + * Find corresponding dynamic object in called function. + * Takes pointer to s (by stripping away 'obj suffix) and querys called function value set (stored + * in summary of that function). + * @param s Call site dynamic object + * @param summary Called function summary + * @param ns Namespace + * @param found Found symbol + * @return True if an object was found, otherwise false. + */ +bool ssa_inlinert::find_corresponding_dyn_obj(const symbol_exprt &s, + const summaryt &summary, + const namespacet &ns, + symbol_exprt &found) +{ + irep_idt id = get_original_identifier(s); + const std::string &id_str = id2string(s.get_identifier()); + id = id_str.substr(0, id_str.rfind("'obj")); + + auto &values = summary.value_domain(symbol_exprt(id, pointer_typet(s.type())), ns); + if (values.value_set.size() == 1) + { + found = values.value_set.begin()->symbol_expr(); + return true; + } + + return false; +} + diff --git a/src/ssa/ssa_inliner.h b/src/ssa/ssa_inliner.h index d36ee5960..dea9c7f9b 100644 --- a/src/ssa/ssa_inliner.h +++ b/src/ssa/ssa_inliner.h @@ -103,8 +103,15 @@ class ssa_inlinert:public messaget const local_SSAt::var_sett &globals, symbol_exprt &s_found); + static bool find_corresponding_dyn_obj(const symbol_exprt &s, + const summaryt &summary, + const namespacet &ns, + symbol_exprt &found); + static irep_idt get_original_identifier(const symbol_exprt &s); + static bool is_struct_member(const irep_idt &identifier); + protected: unsigned counter; summary_dbt &summary_db; @@ -135,9 +142,10 @@ class ssa_inlinert:public messaget const local_SSAt &SSA, const local_SSAt::locationt &loc); exprt get_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_in, + const local_SSAt::var_sett &cs_globals_out, + const summaryt &summary, + const namespacet &ns); void rename(exprt &expr); void rename(local_SSAt::nodet &node); From 221a0fc5d358e9648ac2debbdf4ef6789c2588e4 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 13 Oct 2016 14:41:09 +0100 Subject: [PATCH 028/322] Heap domain: create summaries (transformers) for functions. Does not work for passing heap objects by pointer parameters between functions. --- src/domains/heap_domain.cpp | 21 +++++++++++--- src/domains/heap_domain.h | 5 ++-- src/domains/strategy_solver_heap.cpp | 38 +++++++++++++++++++------ src/domains/template_generator_base.cpp | 12 ++++++-- src/ssa/address_canonizer.cpp | 30 +++++++++++-------- 5 files changed, 76 insertions(+), 30 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 9fca9faf5..1e5425822 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -40,6 +40,8 @@ void heap_domaint::make_template(const domaint::var_specst &var_specs, const nam for (auto v1 = var_specs.begin(); v1 != var_specs.end(); ++v1) { + if (v1->kind == IN) continue; + // Create template for each pointer to struct const vart &var1 = v1->var; if (var1.type().id() == ID_pointer) @@ -49,7 +51,12 @@ void heap_domaint::make_template(const domaint::var_specst &var_specs, const nam { // Check if var1 is member field of dynamic object const std::string identifier = id2string(to_symbol_expr(v1->var).get_identifier()); - bool dynamic = identifier.find("dynamic_object$") != std::string::npos; + bool dynamic = false; + for (auto &component : to_struct_type(pointed_type).components()) + { + if (identifier.find("." + id2string(component.get_name())) != std::string::npos) + dynamic = true; + } for (auto &component : to_struct_type(pointed_type).components()) { @@ -175,18 +182,24 @@ bool heap_domaint::add_row_path(const rowt &row, heap_valuet &value, const exprt { // Path does not exist yet std::set dyn_obj_set; + bool zero_path = true; if (dyn_obj.first.id() != ID_nil) { // Path doesn't have zero length dyn_obj_set.insert(dyn_obj); + zero_path = false; } - path_set.emplace(dest, dyn_obj_set); + path_set.emplace(dest, dyn_obj_set, zero_path); return true; } else { // Path exists already - if (dyn_obj.first.id() == ID_nil) return false; - + if (dyn_obj.first.id() == ID_nil) + { + bool result = path_set.find(dest)->zero_length; + path_set.find(dest)->zero_length = true; + return !result; + } // Try to insert new dynamic object belonging to the path return path_set.find(dest)->dyn_objects.insert(dyn_obj).second; } diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index 748805c66..efe023b86 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -41,11 +41,12 @@ class heap_domaint:public domaint { exprt destination; mutable std::set dyn_objects; + mutable bool zero_length; patht(const exprt &dest_) : destination(dest_) {} - patht(const exprt &dest_, const std::set &dyn_objs_) - : destination(dest_), dyn_objects(dyn_objs_) {} + patht(const exprt &dest_, const std::set &dyn_objs_, const bool zero_l_) + : destination(dest_), dyn_objects(dyn_objs_), zero_length(zero_l_) {} bool operator<(const patht &rhs) const { diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index 68ee5ace2..b6ad92e6a 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -5,6 +5,7 @@ //#define DEBUG_OUTPUT #include "strategy_solver_heap.h" +#include "../ssa/address_canonizer.h" bool strategy_solver_heapt::iterate(invariantt &_inv) { @@ -66,14 +67,14 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) } for (unsigned i = 0; i < heap_domain.templ.size(); i++) { - exprt c = heap_domain.get_row_pre_constraint(i, inv[i]).op1(); + exprt c = heap_domain.get_row_pre_constraint(i, inv[i]); debug() << "cond: " << from_expr(ns, "", c) << " " << from_expr(ns, "", solver.get(c)) << eom; debug() << "guards: " << from_expr(ns, "", heap_domain.templ[i].pre_guard) << " " << from_expr(ns, "", solver.get(heap_domain.templ[i].pre_guard)) << eom; debug() << "guards: " << from_expr(ns, "", heap_domain.templ[i].post_guard) << " " << from_expr(ns, "", solver.get(heap_domain.templ[i].post_guard)) << eom; - exprt post = heap_domain.get_row_post_constraint(i, inv[i]).op1(); + exprt post = heap_domain.get_row_post_constraint(i, inv[i]); debug() << "post-cond: " << from_expr(ns, "", post) << " " << from_expr(ns, "", solver.get(post)) << eom; } @@ -95,11 +96,14 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) if (heap_domain.is_null_ptr(ptr_value)) { exprt null_expr = null_pointer_exprt(to_pointer_type(ptr_value.type())); + + // Add path to NULL if (heap_domain.add_row_path(row, inv, null_expr, std::make_pair(nil_exprt(), nil_exprt()))) improved = true; debug() << "add destination: " << from_expr(ns, "", ptr_value) << eom; + // Add points to information if (heap_domain.add_points_to(row, inv, std::make_pair(null_expr, nil_exprt()))) improved = true; debug() << "add points to: " << from_expr(ns, "", ptr_value) << eom; @@ -109,13 +113,18 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) // pointer points to the heap (p = &obj) debug() << from_expr(ns, "", ptr_value) << eom; assert(ptr_value.id() == ID_address_of); - assert(to_address_of_expr(ptr_value).object().id() == ID_symbol); - symbol_exprt obj = to_symbol_expr(to_address_of_expr(ptr_value).object()); + // Canonize address + const exprt address = address_canonizer(ptr_value, ns); + assert(to_address_of_expr(address).object().id() == ID_symbol); + + symbol_exprt obj = to_symbol_expr(to_address_of_expr(address).object()); if (obj.type().get_bool("#dynamic")) { + // obj is dynamic object accessed inside the function + if (id2string(obj.get_identifier()).find("$unknown") != std::string::npos) - { + { // handle unknown object if (heap_domain.add_points_to(row, inv, std::make_pair(obj, nil_exprt()))) improved = true; debug() << "add points to: " << from_expr(ns, "", obj) << eom; @@ -127,7 +136,8 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) if (inv[row].empty() && heap_domain.templ[row].dyn_obj.id() != ID_nil && heap_domain.get_base_name(obj) == heap_domain.get_base_name(heap_domain.templ[row].dyn_obj)) - { + { // for the same object find previous instance + // (used for multiple loops in one function) member_val_index = find_member_row(obj, heap_domain.templ[row].member, --actual_loc); if (member_val_index < 0) @@ -140,7 +150,6 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) } assert(member_val_index >= 0); exprt member_expr = heap_domain.templ[member_val_index].expr; - exprt do_expr = heap_domain.templ[member_val_index].dyn_obj; // Add all paths from obj.next to p if (heap_domain.add_all_paths(row, (unsigned) member_val_index, inv, @@ -149,9 +158,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) debug() << "add all paths: " << from_expr(ns, "", member_expr) << ", through: " << from_expr(ns, "", obj) << eom; - assert(do_expr.id() != ID_nil); // Add points to information - assert(do_expr.id() == ID_symbol); if (heap_domain.add_points_to(row, inv, std::make_pair(obj, member_expr))) improved = true; debug() << "add points to: " << from_expr(ns, "", obj) << eom; @@ -159,6 +166,19 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) heap_domain.add_pointed_by_row((unsigned) member_val_index, row, inv); } } + else + { + // Add points to information + if (heap_domain.add_points_to(row, inv, std::make_pair(obj, nil_exprt()))) + improved = true; + debug() << "add points to: " << from_expr(ns, "", obj) << eom; + + // Add path to &(obj) + if (heap_domain.add_row_path(row, inv, address_of_exprt(obj), + std::make_pair(nil_exprt(), nil_exprt()))) + improved = true; + debug() << "add destination: " << from_expr(ns, "", ptr_value) << eom; + } } if (heap_domain.templ[row].dynamic) diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index 8815d658a..7aa2e1ed9 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -17,6 +17,7 @@ Author: Peter Schrammel #include "tpolyhedra_domain.h" #include "predabs_domain.h" #include "heap_domain.h" +#include #ifdef DEBUG #include @@ -268,10 +269,15 @@ void template_generator_baset::filter_heap_domain() { domaint::var_specst new_var_specs(var_specs); var_specs.clear(); - for (auto var=new_var_specs.begin(); var!=new_var_specs.end(); ++var) + for(auto var=new_var_specs.begin(); var!=new_var_specs.end(); ++var) { - if (var->var.type().id()==ID_pointer || var->var.type().get_bool("#dynamic")) - var_specs.push_back(*var); + if(var->var.id()==ID_symbol && var->var.type().id()==ID_pointer) + { + // Filter out non-assigned variables + if(ssa_inlinert::get_original_identifier(to_symbol_expr(var->var)) != + to_symbol_expr(var->var).get_identifier()) + var_specs.push_back(*var); + } } } diff --git a/src/ssa/address_canonizer.cpp b/src/ssa/address_canonizer.cpp index 2ffab3ff1..f6e6b9cb2 100644 --- a/src/ssa/address_canonizer.cpp +++ b/src/ssa/address_canonizer.cpp @@ -47,18 +47,24 @@ exprt address_canonizer( // get offset exprt offset=member_offset_expr(to_member_expr(object), ns); - // &x.m ---> (&x)+offset - - address_of_exprt address_of_expr(to_member_expr(object).struct_op()); - exprt rec_result=address_canonizer(address_of_expr, ns); // rec. call - - pointer_typet byte_pointer(unsigned_char_type()); - typecast_exprt typecast_expr(rec_result, byte_pointer); - plus_exprt sum(typecast_expr, offset); - if(sum.type()!=address.type()) - sum.make_typecast(address.type()); - - return sum; + if (offset.id()==ID_constant && to_constant_expr(offset).is_zero()) + { + return address_of_exprt(to_member_expr(object).struct_op()); + } + else + { + // &x.m ---> (&x)+offset + + address_of_exprt address_of_expr(to_member_expr(object).struct_op()); + exprt rec_result=address_canonizer(address_of_expr, ns); // rec. call + + pointer_typet byte_pointer(unsigned_char_type()); + typecast_exprt typecast_expr(rec_result, byte_pointer); + plus_exprt sum(typecast_expr, offset); + if (sum.type()!=address.type()) sum.make_typecast(address.type()); + + return sum; + } } else if(object.id()==ID_index) { From 22d6decae5332982a7a90be097231d927b6a378d Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 13 Oct 2016 18:33:18 +0100 Subject: [PATCH 029/322] Better collection of pointed objects. Only objects pointed by parameters and any called function returns, or arguments are collected. --- src/ssa/local_ssa.cpp | 17 +++------- src/ssa/ssa_object.cpp | 76 +++++++++++++++++++++++++++++++++++------- src/ssa/ssa_object.h | 4 +-- 3 files changed, 71 insertions(+), 26 deletions(-) diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index dbf9bb8d0..eb9d17aa7 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -175,18 +175,11 @@ void local_SSAt::get_globals( if(is_ptr_object(root_obj)) { const symbolt *symbol; - if(ns.lookup(root_obj.get(ID_ptr_object), symbol)) continue; - if(!symbol->is_parameter) - { - if(!with_returns || - id2string(it->get_identifier()).find("'obj")==std::string::npos) - continue; - const ssa_domaint &ssa_domain=ssa_analysis[loc]; - // Filter out non-assigned symbols - const auto &def=ssa_domain.def_map.find(it->get_identifier()); - if(def->second.def.is_input()) - continue; - } + irep_idt ptr_obj_id=root_obj.get(ID_ptr_object); + if(ns.lookup(ptr_obj_id, symbol)) + continue; + if(!symbol->is_parameter && !with_returns) + continue; } if(rhs_value) diff --git a/src/ssa/ssa_object.cpp b/src/ssa/ssa_object.cpp index cf5e047c9..0996c9b3c 100644 --- a/src/ssa/ssa_object.cpp +++ b/src/ssa/ssa_object.cpp @@ -37,15 +37,9 @@ bool is_ptr_object(const exprt &src) src.get(ID_ptr_object)!=irep_idt(); } -void collect_objects_rec( - const exprt &src, - const namespacet &ns, - std::set &objects, - std::set &literals); - /*******************************************************************\ -Function: collect_objects_address_of_rec +Function: collect_objects_rec Inputs: @@ -55,6 +49,44 @@ Function: collect_objects_address_of_rec \*******************************************************************/ +void collect_objects_rec( + const exprt &src, + const namespacet &ns, + std::set &objects, + std::set &literals); + +void collect_ptr_objects( + const exprt &expr, + const namespacet &ns, + std::set &objects, + std::set &literals) +{ + if(expr.id()==ID_symbol) + { + const symbol_exprt &src=to_symbol_expr(expr); + const typet &type=ns.follow(src.type()); + if(type.id()==ID_pointer) + { + const irep_idt &identifier=id2string(src.get_identifier()) + "'obj"; + const typet &pointed_type=src.type().subtype(); + symbol_exprt ptr_object(identifier, pointed_type); + + if(is_ptr_object(src)) + ptr_object.set(ID_ptr_object, src.get(ID_ptr_object)); + else + ptr_object.set(ID_ptr_object, src.get_identifier()); + + collect_objects_rec(ptr_object, ns, objects, literals); + collect_ptr_objects(ptr_object, ns, objects, literals); + } + } + else + { + forall_operands(it, expr) + collect_ptr_objects(*it, ns, objects, literals); + } +} + void collect_objects_address_of_rec( const exprt &src, const namespacet &ns, @@ -120,6 +152,15 @@ void collect_objects_rec( { forall_operands(it, src) collect_objects_rec(*it, ns, objects, literals); + + const codet &code=to_code(src); + if (code.get_statement()==ID_function_call) + { + const code_function_callt &function_call=to_code_function_call(code); + for (auto &arg : function_call.arguments()) + collect_ptr_objects(arg, ns, objects, literals); + } + return; } else if(src.id()==ID_address_of) @@ -141,6 +182,10 @@ void collect_objects_rec( { if(type.id()==ID_struct) { + std::string id=id2string(ssa_object.get_identifier()); + if (src.type().get_bool("#dynamic") || id.find("'obj")==id.size()-4) + objects.insert(ssa_object); + // need to split up const struct_typet &struct_type=to_struct_type(type); @@ -162,6 +207,14 @@ void collect_objects_rec( #endif objects.insert(ssa_object); + + const exprt &root_object=ssa_object.get_root_object(); + const symbolt *symbol; + if(ssa_object.type().get_bool("#dynamic") || + (root_object.id()==ID_symbol && + !ns.lookup(to_symbol_expr(root_object).get_identifier(), symbol) && + (symbol->is_parameter || !symbol->is_procedure_local()))) + collect_ptr_objects(ssa_object.symbol_expr(), ns, objects, literals); } } else @@ -195,6 +248,7 @@ void ssa_objectst::collect_objects( { symbol_exprt symbol=ns.lookup(*it).symbol_expr(); collect_objects_rec(symbol, ns, objects, literals); + collect_ptr_objects(symbol, ns, objects, literals); } // Rummage through body. @@ -218,6 +272,7 @@ Function: ssa_objectst::add_ptr_objects \*******************************************************************/ void ssa_objectst::add_ptr_objects( + const goto_functionst::goto_functiont &goto_function, const namespacet &ns) { objectst tmp; @@ -230,8 +285,9 @@ void ssa_objectst::add_ptr_objects( if(root_object.id()==ID_symbol) { const symbolt &symbol = ns.lookup(root_object); + dirtyt dirty(goto_function); if(o_it->type().id()==ID_pointer && - (symbol.is_parameter || !symbol.is_procedure_local())) + (symbol.is_parameter || !symbol.is_procedure_local() || dirty(symbol.name))) { tmp.insert(*o_it); } @@ -385,10 +441,6 @@ ssa_objectt::identifiert ssa_objectt::object_id_rec( { return identifiert(); } - else if(src.id()==ID_ptr_object) - { - return identifiert(id2string(src.get(ID_identifier))+"'obj"); - } else return identifiert(); } diff --git a/src/ssa/ssa_object.h b/src/ssa/ssa_object.h index 1cb21ec1d..5a16bcd6b 100644 --- a/src/ssa/ssa_object.h +++ b/src/ssa/ssa_object.h @@ -114,7 +114,6 @@ class ssa_objectst const namespacet &ns) { collect_objects(goto_function, ns); - add_ptr_objects(ns); categorize_objects(goto_function, ns); } @@ -128,7 +127,8 @@ class ssa_objectst const namespacet &); void add_ptr_objects( - const namespacet &); + const goto_functionst::goto_functiont &, + const namespacet &); }; bool is_ptr_object(const exprt &); From 7468625ff11977cf27e844fe09c4717daf87ba2c Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 18 Oct 2016 11:15:28 +0100 Subject: [PATCH 030/322] Assignments and value domain for objects pointed by function call arguments. --- src/ssa/assignments.cpp | 32 ++++++++++++++++++++--- src/ssa/ssa_value_set.cpp | 54 +++++++++++++++++++++++++++++---------- 2 files changed, 69 insertions(+), 17 deletions(-) diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index 7c4d99e46..4b5703444 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -62,10 +62,34 @@ void assignmentst::build_assignment_map( o_it=ssa_objects.globals.begin(); o_it!=ssa_objects.globals.end(); o_it++) { - const exprt &function = code_function_call.function(); - if (function.id() == ID_symbol && - id2string(o_it->get_identifier()).find( - id2string(to_symbol_expr(function).get_identifier())) != std::string::npos) + bool assigned = false; + const exprt &root_obj = o_it->get_root_object(); + if (is_ptr_object(root_obj)) + { // assign objects pointed by arguments and return value of the function + const exprt &function = code_function_call.function(); + if (function.id() == ID_symbol && + id2string(o_it->get_identifier()).find( + id2string(to_symbol_expr(function).get_identifier())) != + std::string::npos) + assigned = true; + + for (auto &arg : code_function_call.arguments()) + { + exprt arg_symbol = arg; + if (arg.id() == ID_address_of) + arg_symbol = to_address_of_expr(arg_symbol).object(); + if (arg_symbol.id() == ID_symbol && id2string(o_it->get_identifier()).find( + id2string(to_symbol_expr(arg_symbol).get_identifier())) != std::string::npos) + assigned = true; + } + } + else + { // assign return value of the function + if (id2string(o_it->get_identifier()).find("#return_value") == std::string::npos) + assigned = true; + } + + if (assigned) assign(*o_it, it, ns); } diff --git a/src/ssa/ssa_value_set.cpp b/src/ssa/ssa_value_set.cpp index e9b73940c..c57ea8023 100644 --- a/src/ssa/ssa_value_set.cpp +++ b/src/ssa/ssa_value_set.cpp @@ -74,6 +74,30 @@ void ssa_value_domaint::transform( assign(*o_it, it, ns); #endif + for (auto &argument : code_function_call.arguments()) + { + exprt arg = argument; + while (arg.type().id() == ID_pointer) + { + if (arg.id() == ID_symbol) + { + const typet &pointed_type = ns.follow(arg.type().subtype()); + symbol_exprt pointed_obj = symbol_exprt( + id2string(to_symbol_expr(arg).get_identifier()) + "'obj", + pointed_type); + pointed_obj.type().set("#dynamic", true); + + assign_lhs_rec(arg, address_of_exprt(pointed_obj), ns); + + arg = pointed_obj; + } + else if (arg.id() == ID_address_of) + { + arg = to_address_of_expr(arg).object(); + } + } + } + // the call might come with an assignment if(code_function_call.lhs().is_not_nil()) { @@ -137,6 +161,23 @@ void ssa_value_domaint::assign_lhs_rec( return; // done } + // if rhs is a return value of pointer type, it points to a dynamic object + if(rhs.id()==ID_symbol && + rhs.type().id()==ID_pointer && + id2string(to_symbol_expr(rhs).get_identifier()).find("#return_value")!= + std::string::npos && + id2string(to_symbol_expr(rhs).get_identifier())!="malloc#return_value") + { + // Pointer typed return value of some function points to some dynamic object + const typet &pointed_type=ns.follow(rhs.type().subtype()); + symbol_exprt pointed_obj=symbol_exprt( + id2string(to_symbol_expr(rhs).get_identifier())+"'obj", + pointed_type); + pointed_obj.type().set("#dynamic", true); + + assign_lhs_rec(rhs, address_of_exprt(pointed_obj), ns); + } + // object? ssa_objectt ssa_object(lhs, ns); @@ -294,19 +335,6 @@ void ssa_value_domaint::assign_rhs_rec( tmp_values.alignment=merge_alignment(tmp_values.alignment, alignment); dest.merge(tmp_values); } - else if(ssa_object.type().id()==ID_pointer && - id2string(ssa_object.get_identifier()) - .find("#return_value")!=std::string::npos && - id2string(ssa_object.get_identifier())!="malloc#return_value") - { - // Pointer typed return value of some function points to some dynamic object - const typet &pointed_type=ns.follow(ssa_object.type().subtype()); - const symbol_exprt &pointed_obj=symbol_exprt( - id2string(ssa_object.get_identifier())+"'obj", pointed_type); - dest.value_set.insert(ssa_objectt(pointed_obj, ns)); - if(offset) - dest.offset=true; - } } else { From 0c1377cf915d2820f3e1d591359a13b2afce462a Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 18 Oct 2016 11:16:47 +0100 Subject: [PATCH 031/322] Bindings for objects pointed by arguments when inlining called function summaries. --- src/ssa/ssa_inliner.cpp | 102 +++++++++++++++++++++++++++++++++++----- src/ssa/ssa_inliner.h | 12 +++-- 2 files changed, 99 insertions(+), 15 deletions(-) diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index 3a72fbfa4..3c47ab741 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -97,10 +97,10 @@ void ssa_inlinert::get_summary( // equalities for globals out (including unmodified globals) if(forward) bindings.push_back(get_replace_globals_out( - cs_globals_in, cs_globals_out, summary, SSA.ns)); + cs_globals_in, cs_globals_out, summary, *f_it, *n_it, SSA.ns)); else bindings.push_back(get_replace_globals_out( - cs_globals_out, cs_globals_in, summary, SSA.ns)); + cs_globals_out, cs_globals_in, summary, *f_it, *n_it, SSA.ns)); } /*******************************************************************\ @@ -532,8 +532,7 @@ exprt ssa_inlinert::get_replace_params( } ssa_objectt pointed_ssa_obj(arg_pointed, SSA.ns); // get correct SSA symbol for function call entry - pointed_ssa_sym_in = SSA.name(pointed_ssa_obj, local_SSAt::OUT, - SSA.get_def_loc(to_symbol_expr(arg_pointed), loc)); + pointed_ssa_sym_in = SSA.read_rhs(pointed_ssa_obj, loc); // get correct SSA symbol for function call exit pointed_ssa_sym_out = SSA.name(pointed_ssa_obj, local_SSAt::OUT, loc); } @@ -611,6 +610,8 @@ exprt ssa_inlinert::get_replace_globals_out( const local_SSAt::var_sett &cs_globals_in, const local_SSAt::var_sett &cs_globals_out, const summaryt &summary, + const function_application_exprt &funapp_expr, + const local_SSAt::nodet &ssa_node, const namespacet &ns) { // equalities for globals_out @@ -641,7 +642,14 @@ exprt ssa_inlinert::get_replace_globals_out( // find corresponding dynamic object in called function symbol_exprt dynamic_object; - assert(find_corresponding_dyn_obj(root_object, summary, ns, dynamic_object)); + if (!find_corresponding_dyn_obj(root_object, summary, funapp_expr, ssa_node, ns, + dynamic_object)) + { // if corresponding dynamic object does not exist, the global is not changed + rhs = *it; // copy + assert(find_corresponding_symbol(*it, cs_globals_in, lhs)); + c.push_back(equal_exprt(lhs, rhs)); + continue; + } // restore member expression dynamic_object.set_identifier(id2string(dynamic_object.get_identifier()) + member); @@ -656,7 +664,13 @@ exprt ssa_inlinert::get_replace_globals_out( { // variable is dynamic object // find corresponding dynamic object in called function symbol_exprt dynamic_object; - assert(find_corresponding_dyn_obj(*it, summary, ns, dynamic_object)); + if (!find_corresponding_dyn_obj(*it, summary, funapp_expr, ssa_node, ns, dynamic_object)) + { // if corresponding dynamic object does not exist, the global is not changed + rhs = *it; // copy + assert(find_corresponding_symbol(*it, cs_globals_in, lhs)); + c.push_back(equal_exprt(lhs, rhs)); + continue; + } // equality is between addresses of corresponding dynamic objects exprt addr=address_of_exprt(dynamic_object); @@ -665,7 +679,9 @@ exprt ssa_inlinert::get_replace_globals_out( lhs=to_symbol_expr(addr); - symbol_exprt orig_obj(id, dynamic_object.type()); + typet orig_type = it->type(); + orig_type.set("#dynamic", dynamic_object.type().get_bool("#dynamic")); + symbol_exprt orig_obj(id, orig_type); rhs=address_of_exprt(orig_obj); } } @@ -759,7 +775,13 @@ void ssa_inlinert::rename(exprt &expr) const exprt &obj = to_address_of_expr(expr).object(); if (obj.id() == ID_symbol) { - id = id2string(to_symbol_expr(obj).get_identifier()) + "'addr" + "@" + i2string(counter); + const std::string &obj_id = id2string(to_symbol_expr(obj).get_identifier()); + if (obj_id.compare(obj_id.length() - 4, 4, "'obj") == 0) + id = obj_id.substr(0, obj_id.find_last_of("'")); + else + id = id2string(obj_id) + "'addr"; + + id = id2string(id) + "@" + i2string(counter); } symbol_exprt addr_symbol(id, expr.type()); expr = addr_symbol; @@ -1053,22 +1075,80 @@ bool ssa_inlinert::is_struct_member(const irep_idt &identifier) * @param s Call site dynamic object * @param summary Called function summary * @param ns Namespace - * @param found Found symbol + * @param found_sym Found symbol * @return True if an object was found, otherwise false. */ bool ssa_inlinert::find_corresponding_dyn_obj(const symbol_exprt &s, const summaryt &summary, + const function_application_exprt &funapp_expr, + const local_SSAt::nodet &ssa_node, const namespacet &ns, - symbol_exprt &found) + symbol_exprt &found_sym) { irep_idt id = get_original_identifier(s); const std::string &id_str = id2string(s.get_identifier()); id = id_str.substr(0, id_str.rfind("'obj")); + if (id2string(id).find("#return_value") == std::string::npos) + { + auto p_it = summary.params.begin(); + bool found = false; + for (auto arg_it = funapp_expr.arguments().begin(); arg_it != funapp_expr.arguments().end(); + ++arg_it, ++p_it) + { + exprt arg = nil_exprt(); + for (auto &eq : ssa_node.equalities) + { + if (eq.rhs() == *arg_it) + arg = eq.lhs(); + } + assert(arg.is_not_nil()); + + symbol_exprt param = *p_it; + while (arg.type().id() == ID_pointer) + { + if (arg.id() == ID_symbol) + { + if (to_symbol_expr(arg).get_identifier() == id) + { + found = true; + break; + } + else + { + // arg --> arg'obj + symbol_exprt &arg_sym = to_symbol_expr(arg); + arg_sym.set_identifier(id2string(arg_sym.get_identifier()) + "'obj"); + arg_sym.type() = arg_sym.type().subtype(); + + // param --> param'obj + assert(param.type().id() == ID_pointer); + param.set_identifier(id2string(param.get_identifier()) + "'obj"); + param.type() = param.type().subtype(); + + } + } + else if (arg.id() == ID_address_of) + { + // &arg --> arg + arg = to_address_of_expr(arg).object(); + + // param --> param'obj + assert(param.type().id() == ID_pointer); + param.set_identifier(id2string(param.get_identifier()) + "'obj"); + param.type() = param.type().subtype(); + } + } + if (found) + id = param.get_identifier(); + } + assert(found); + } + auto &values = summary.value_domain(symbol_exprt(id, pointer_typet(s.type())), ns); if (values.value_set.size() == 1) { - found = values.value_set.begin()->symbol_expr(); + found_sym = values.value_set.begin()->symbol_expr(); return true; } diff --git a/src/ssa/ssa_inliner.h b/src/ssa/ssa_inliner.h index dea9c7f9b..9a2a9d4f9 100644 --- a/src/ssa/ssa_inliner.h +++ b/src/ssa/ssa_inliner.h @@ -103,10 +103,12 @@ class ssa_inlinert:public messaget const local_SSAt::var_sett &globals, symbol_exprt &s_found); - static bool find_corresponding_dyn_obj(const symbol_exprt &s, - const summaryt &summary, - const namespacet &ns, - symbol_exprt &found); + static bool find_corresponding_dyn_obj(const symbol_exprt &s, + const summaryt &summary, + const function_application_exprt &funapp_expr, + const local_SSAt::nodet &ssa_node, + const namespacet &ns, + symbol_exprt &found_sym); static irep_idt get_original_identifier(const symbol_exprt &s); @@ -145,6 +147,8 @@ class ssa_inlinert:public messaget const local_SSAt::var_sett &cs_globals_in, const local_SSAt::var_sett &cs_globals_out, const summaryt &summary, + const function_application_exprt &funapp_expr, + const local_SSAt::nodet &ssa_node, const namespacet &ns); void rename(exprt &expr); From d0db87252687c11d58f373f7a3c36c72f8a0f1e6 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 20 Oct 2016 10:11:16 +0100 Subject: [PATCH 032/322] Improve dereferencing. --- src/ssa/local_ssa.cpp | 9 ++---- src/ssa/ssa_dereference.cpp | 62 ++++++++++++++++++------------------- 2 files changed, 32 insertions(+), 39 deletions(-) diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index eb9d17aa7..964abb41c 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -1378,13 +1378,8 @@ void local_SSAt::assign_rec( { const if_exprt &if_expr=to_if_expr(lhs); - if (if_expr.false_case().id() == ID_if) - { - exprt new_rhs = if_exprt(if_expr.cond(), rhs, if_expr.true_case()); - assign_rec(if_expr.true_case(), new_rhs, and_exprt(guard, if_expr.cond()), loc); - } - else - assign_rec(if_expr.true_case(), rhs, and_exprt(guard, if_expr.cond()), loc); + exprt new_rhs = if_exprt(if_expr.cond(), rhs, if_expr.true_case()); + assign_rec(if_expr.true_case(), new_rhs, and_exprt(guard, if_expr.cond()), loc); assign_rec( if_expr.false_case(), diff --git a/src/ssa/ssa_dereference.cpp b/src/ssa/ssa_dereference.cpp index 08c33e166..95ae0f425 100644 --- a/src/ssa/ssa_dereference.cpp +++ b/src/ssa/ssa_dereference.cpp @@ -323,42 +323,40 @@ exprt dereference_rec( exprt pointer_deref= dereference(pointer, ssa_value_domain, nondet_prefix, ns); - // We use the identifier produced by - // local_SSAt::replace_side_effects_rec - exprt result; - const typet &pointed_type = pointer.type().subtype(); - if (pointed_type.id() == ID_pointer) - result = symbol_exprt(nondet_prefix, src.type()); - else - { - const typet &obj_type = ns.follow(pointed_type); - std::string dyn_type_name = obj_type.id_string(); - if (obj_type.id() == ID_struct) - dyn_type_name += "_" + id2string(to_struct_type(obj_type).get_tag()); - irep_idt identifier = "ssa::" + dyn_type_name + "_obj$unknown"; - - result = symbol_exprt(identifier, src.type()); - } + const typet &pointed_type=ns.follow(pointer.type().subtype()); + const ssa_value_domaint::valuest values=ssa_value_domain(pointer, ns); - // query the value sets - const ssa_value_domaint::valuest values= - ssa_value_domain(pointer, ns); - - for(ssa_value_domaint::valuest::value_sett::const_iterator - it=values.value_set.begin(); - it!=values.value_set.end(); - it++) + exprt result; + if (values.value_set.empty()) { - exprt guard=ssa_alias_guard(src, it->get_expr(), ns); - exprt value=ssa_alias_value(src, it->get_expr(), ns); - result=if_exprt(guard, value, result); + irep_idt identifier=id2string(to_symbol_expr(pointer).get_identifier())+"'obj"; + result=symbol_exprt(identifier, pointed_type); } - - if (values.empty()) { - // We use the identifier of pointed object - irep_idt identifier = id2string(to_symbol_expr(pointer).get_identifier())+"'obj"; - result = symbol_exprt(identifier, ns.follow(pointed_type)); + else + { + auto it=values.value_set.begin(); + + if(values.null || values.unknown) + { + std::string dyn_type_name=pointed_type.id_string(); + if(pointed_type.id()==ID_struct) + dyn_type_name+= "_"+id2string(to_struct_type(pointed_type).get_tag()); + irep_idt identifier="ssa::"+dyn_type_name+"_obj$unknown"; + + result=symbol_exprt(identifier, src.type()); + } + else + { + result=ssa_alias_value(src, (it++)->get_expr(), ns); + } + + for (; it!=values.value_set.end(); ++it) + { + exprt guard=ssa_alias_guard(src, it->get_expr(), ns); + exprt value=ssa_alias_value(src, it->get_expr(), ns); + result=if_exprt(guard, value, result); + } } return result; From fca0f0e0148f56ebd2be1dd1c818d1710d543128 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 9 Dec 2016 10:55:05 +0100 Subject: [PATCH 033/322] Repair collection of dynamic objects --- src/ssa/ssa_object.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ssa/ssa_object.cpp b/src/ssa/ssa_object.cpp index 0996c9b3c..0db5acd5d 100644 --- a/src/ssa/ssa_object.cpp +++ b/src/ssa/ssa_object.cpp @@ -183,7 +183,7 @@ void collect_objects_rec( if(type.id()==ID_struct) { std::string id=id2string(ssa_object.get_identifier()); - if (src.type().get_bool("#dynamic") || id.find("'obj")==id.size()-4) + if (src.type().get_bool("#dynamic") || id.rfind("'obj")==id.size()-4) objects.insert(ssa_object); // need to split up From 35a163f56018c72d689694ec7b2b63b88e8ee87a Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 9 Dec 2016 11:23:41 +0100 Subject: [PATCH 034/322] Remove replacement of arguments by symbols. Now actual arguments are used in function call. Also remove equalities between parameter and its pointed object (will be solved in next commits). --- src/ssa/assignments.cpp | 28 +++++++++++-------- src/ssa/local_ssa.cpp | 60 ++++++++++++++++++----------------------- 2 files changed, 43 insertions(+), 45 deletions(-) diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index 4b5703444..7ff61824f 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -65,23 +65,13 @@ void assignmentst::build_assignment_map( bool assigned = false; const exprt &root_obj = o_it->get_root_object(); if (is_ptr_object(root_obj)) - { // assign objects pointed by arguments and return value of the function + { // assign objects pointed by return value of the function const exprt &function = code_function_call.function(); if (function.id() == ID_symbol && id2string(o_it->get_identifier()).find( id2string(to_symbol_expr(function).get_identifier())) != std::string::npos) assigned = true; - - for (auto &arg : code_function_call.arguments()) - { - exprt arg_symbol = arg; - if (arg.id() == ID_address_of) - arg_symbol = to_address_of_expr(arg_symbol).object(); - if (arg_symbol.id() == ID_symbol && id2string(o_it->get_identifier()).find( - id2string(to_symbol_expr(arg_symbol).get_identifier())) != std::string::npos) - assigned = true; - } } else { // assign return value of the function @@ -93,6 +83,22 @@ void assignmentst::build_assignment_map( assign(*o_it, it, ns); } + // assign objects pointed by arguments of the function + for (auto &arg : code_function_call.arguments()) + { + if (arg.type().id() == ID_pointer) + { + exprt arg_ptr = arg; + do + { + arg_ptr = dereference(dereference_exprt(arg_ptr, arg_ptr.type().subtype()), + ssa_value_ai[it], "", ns); + assign(arg_ptr, it, ns); + } + while (arg_ptr.type().id() == ID_pointer); + } + } + // the call might come with an assignment if(code_function_call.lhs().is_not_nil()) { diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 964abb41c..45af83a02 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -97,34 +97,16 @@ void local_SSAt::get_entry_exit_vars() const symbol_exprt ¶m=symbol->symbol_expr(); params.push_back(param); - - if(param.type().id()==ID_pointer) - { - const typet &pointed_type=ns.follow(param.type().subtype()); - const symbol_exprt pointed_obj(id2string(param.get_identifier()) + "'obj", pointed_type); - nodes.begin()->equalities.push_back(equal_exprt(param, address_of_exprt(pointed_obj))); - } } // get globals in goto_programt::const_targett first=goto_function.body.instructions.begin(); get_globals(first, globals_in, true, false); // filters out #return_value - for(auto &global_in : globals_in) - { - if(global_in.type().id()==ID_pointer && - id2string(global_in.get_identifier()).find('.') == std::string::npos) - { - const typet &pointed_type=ns.follow(global_in.type().subtype()); - const symbol_exprt pointed_obj(id2string(global_in.get_identifier()) + "'obj", pointed_type); - nodes.begin()->equalities.push_back(equal_exprt(global_in, address_of_exprt(pointed_obj))); - } - } - - // get globals out (includes return value) - goto_programt::const_targett + //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_globals(last,globals_out,true,true,last->function); } /*******************************************************************\ @@ -561,20 +543,9 @@ void local_SSAt::build_function_call(locationt loc) return; } - f=to_function_application_expr(read_rhs(f, loc)); - assert(f.function().id()==ID_symbol); // no function pointers - irep_idt fname=to_symbol_expr(f.function()).get_identifier(); - // add equalities for arguments - unsigned i=0; - 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)); - *it=arg; - } + assert(f.function().id()==ID_symbol); //no function pointers + f = to_function_application_expr(read_rhs(f, loc)); n_it->function_calls.push_back( to_function_application_expr(f)); } @@ -1417,6 +1388,27 @@ Function: local_SSAt::output void local_SSAt::output(std::ostream &out) const { + out << "params:"; + for (auto ¶m : params) + { + out << " " << from_expr(param); + } + out << '\n'; + + out << "globals in:"; + for (auto &glob : globals_in) + { + out << " " << from_expr(glob); + } + out << '\n'; + + out << "globals out:"; + for (auto &glob : globals_out) + { + out << " " << from_expr(glob); + } + out << "\n\n"; + for(nodest::const_iterator n_it=nodes.begin(); n_it!=nodes.end(); n_it++) From a26bd5800b058b3aa869109a04612e166d701d1f Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 9 Dec 2016 11:27:01 +0100 Subject: [PATCH 035/322] New preprocessings of GOTO program. Remove loop heads in the entry of a function. Add symbols for objects pointed by function parameters into symbol table. --- src/2ls/2ls_parse_options.cpp | 6 ++ src/2ls/2ls_parse_options.h | 3 + src/2ls/preprocessing_util.cpp | 107 ++++++++++++++++++++++++++++++++- 3 files changed, 115 insertions(+), 1 deletion(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 5ef232136..cd8e78fa6 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -1129,6 +1129,9 @@ bool twols_parse_optionst::process_goto_program( replace_malloc(goto_model,""); #endif + // create symbols for objects pointed by parameters + create_dynamic_objects(goto_model); + #if REMOVE_MULTIPLE_DEREFERENCES remove_multiple_dereferences(goto_model); #endif @@ -1139,6 +1142,9 @@ bool twols_parse_optionst::process_goto_program( // add loop ids goto_model.goto_functions.compute_loop_numbers(); + // remove loop heads from function entries + remove_loops_in_entry(goto_model); + // inline __CPROVER_initialize and main if(cmdline.isset("inline-main")) { diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index ddbc61c3e..68dea5b5b 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -174,6 +174,9 @@ class twols_parse_optionst: void add_assumptions_after_assertions(goto_modelt &goto_model); void filter_assertions(goto_modelt &goto_model); void split_loopheads(goto_modelt &goto_model); + void remove_loops_in_entry(goto_modelt &goto_model); + void create_dynamic_objects(goto_modelt &goto_model); + void add_dynamic_object_rec(exprt &expr, symbol_tablet &symbol_table); }; #endif diff --git a/src/2ls/preprocessing_util.cpp b/src/2ls/preprocessing_util.cpp index 590827693..dff5120e9 100644 --- a/src/2ls/preprocessing_util.cpp +++ b/src/2ls/preprocessing_util.cpp @@ -15,7 +15,6 @@ Author: Peter Schrammel #include "2ls_parse_options.h" - /*******************************************************************\ Function: twols_parse_optionst::inline_main @@ -466,3 +465,109 @@ void twols_parse_optionst::split_loopheads(goto_modelt &goto_model) } } } + +/*******************************************************************\ + +Function: twols_parse_optionst::remove_loops_in_entry + + Inputs: + + Outputs: + + Purpose: Remove loop head from entry instruction of a function - + causes problems with input variables naming. If first + instruction is target of back-jump, insert SKIP instruction + before. + +\*******************************************************************/ + +void twols_parse_optionst::remove_loops_in_entry(goto_modelt &goto_model) +{ + Forall_goto_functions(f_it, goto_model.goto_functions) + { + if (f_it->second.body_available() && + f_it->second.body.instructions.begin()->is_target()) + { + auto new_entry= + f_it->second.body.insert_before(f_it->second.body.instructions.begin()); + new_entry->make_skip(); + } + } +} + +/*******************************************************************\ + +Function: twols_parse_optionst::create_dynamic_objects + + Inputs: + + Outputs: + + Purpose: Create symbols for objects pointed by parameters of a function. + +\*******************************************************************/ + +void twols_parse_optionst::create_dynamic_objects(goto_modelt &goto_model) +{ + Forall_goto_functions(f_it, goto_model.goto_functions) + { + Forall_goto_program_instructions(i_it, f_it->second.body) + { + if (i_it->is_assign()) + { + code_assignt &code_assign = to_code_assign(i_it->code); + add_dynamic_object_rec(code_assign.lhs(), goto_model.symbol_table); + add_dynamic_object_rec(code_assign.rhs(), goto_model.symbol_table); + } + } + } +} + +/*******************************************************************\ + +Function: twols_parse_optionst::add_dynamic_object_rec + + Inputs: + + Outputs: + + Purpose: For each pointer-typed symbol in an expression which is a parameter, + create symbol for pointed object in the symbol table. + +\*******************************************************************/ + +void twols_parse_optionst::add_dynamic_object_rec( + exprt &expr, symbol_tablet &symbol_table) +{ + if (expr.id() == ID_symbol) + { + const symbolt &symbol= + symbol_table.lookup(to_symbol_expr(expr).get_identifier()); + if (symbol.is_parameter && symbol.type.id() == ID_pointer) + { + // New symbol + symbolt object_symbol; + + object_symbol.base_name = id2string(symbol.base_name) + "'obj"; + object_symbol.name = id2string(symbol.name) + "'obj"; + const typet &pointed_type = symbol.type.subtype(); + // Follow pointed type + if (pointed_type.id() == ID_symbol) + { + const symbolt type_symbol = symbol_table.lookup( + to_symbol_type(pointed_type).get_identifier()); + object_symbol.type = type_symbol.type; + } + else + object_symbol.type = pointed_type; + object_symbol.mode = ID_C; + + symbol_table.add(object_symbol); + } + } + else + { + Forall_operands(it, expr) + add_dynamic_object_rec(*it, symbol_table); + } +} From d982c708248df7bf1dba2970597d07bbda958f89 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 9 Dec 2016 12:45:53 +0100 Subject: [PATCH 036/322] Heap domain changes - solve problem with calling context for functions called in loop. Introduce nondet value for template row - expression is TRUE. Initialize heap strategy solver - create precondition for pointer-typed parameters that don't have it. --- src/domains/heap_domain.cpp | 77 +++++++- src/domains/heap_domain.h | 69 +------ src/domains/ssa_analyzer.cpp | 2 +- src/domains/strategy_solver_heap.cpp | 228 +++++++++++++++++------- src/domains/strategy_solver_heap.h | 15 +- src/domains/template_generator_base.cpp | 5 +- src/ssa/address_canonizer.cpp | 2 +- 7 files changed, 263 insertions(+), 135 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 1e5425822..20fc9cb14 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -27,7 +27,7 @@ void heap_domaint::initialize(domaint::valuet &value) /** * Create domain template for given set of variables. - * Template contains row for each member of each variable being pointer to struct, + * Template contains a row for each member of each variable being pointer to struct, * and a row for each flattened member of a struct. * @param var_specs Set of program variables. * @param ns Namespace @@ -420,3 +420,78 @@ std::string heap_domaint::get_base_name(const exprt &expr) result = result.substr(0, result.find_last_of('#')); return result; } + +/** + * Get expression for the row value. It is a conjunction of points to expression and path + * expressions. + * Points to expression is disjunction of equalities: + * p = &o (NULL) for each object 'o' (or NULL) from points_to set + * Expression of path leading from variable 'p' to destination 'd' via field 'm' and + * passing through set of objects 'O' has form: + * p = d || if path can have zero length + * p = &o && (o.m = d || o.m = o') where o,o' belong to O and p can point to &o + * @param templ_expr Pointer variable of the template row + * @return Row value expression in the described form + */ +exprt heap_domaint::row_valuet::get_row_expr(const vart &templ_expr) const +{ + if (nondet) return true_exprt(); + + if (paths.empty() && points_to.empty()) return false_exprt(); + + exprt::operandst result; + + exprt::operandst pt_expr; + if (!points_to.empty()) + { // Points to expression + for (auto &pt : points_to) + { + pt_expr.push_back(equal_exprt(templ_expr, + templ_expr.type() == pt.first.type() ? + pt.first : address_of_exprt(pt.first))); + } + result.push_back(disjunction(pt_expr)); + } + + exprt::operandst paths_expr; + if (!paths.empty()) + { + for (auto &path : paths) + { // path(p, m, d)[O] + const exprt &dest = path.destination; + exprt::operandst path_expr; + + for (const dyn_objt &obj1 : points_to) + { + if (path.dyn_objects.find(obj1) != path.dyn_objects.end()) + { + // p = &o + exprt equ_exprt = equal_exprt(templ_expr, address_of_exprt(obj1.first)); + + exprt::operandst step_expr; + exprt member_expr = obj1.second; + // o.m = d + step_expr.push_back(equal_exprt(member_expr, dest)); + + for (auto &obj2 : path.dyn_objects) + { // o.m = o' + step_expr.push_back(equal_exprt(member_expr, address_of_exprt(obj2.first))); + } + + path_expr.push_back(and_exprt(equ_exprt, disjunction(step_expr))); + } + else + { + path_expr.push_back(equal_exprt(templ_expr, + templ_expr.type() == obj1.first.type() ? + obj1.first : address_of_exprt(obj1.first))); + } + } + + paths_expr.push_back(disjunction(path_expr)); + } + result.push_back(disjunction(paths_expr)); + } + + return conjunction(result); +} diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index efe023b86..2f0b51dd1 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -62,74 +62,9 @@ class heap_domaint:public domaint std::set paths; /**< Set of paths leading from the row variable */ std::set points_to; /**< Set of objects (or NULL) the row variable can point to */ std::set pointed_by; /**< Set of rows whose variables point to this row */ + bool nondet = false; /**< Row is nondeterministic - expression is TRUE */ - /** - * Get expression for the row value. It is a conjunction of points to expression and path - * expressions. - * Points to expression is disjunction of equalities: - * p = &o (NULL) for each object 'o' (or NULL) from points_to set - * Expression of path leading from variable 'p' to destination 'd' via field 'm' and - * passing through set of objects 'O' has form: - * p = d || if path can have zero length - * p = &o && (o.m = d || o.m = o') where o,o' belong to O and p can point to &o - * @param templ_expr Pointer variable of the template row - * @return Row value expression in the described form - */ - exprt get_row_expr(const vart &templ_expr) const - { - if (paths.empty() && points_to.empty()) return false_exprt(); - exprt::operandst result; - - if (!points_to.empty()) - { // Points to expression - exprt::operandst pt_expr; - for (auto &pt : points_to) - { - exprt lhs = templ_expr; - pt_expr.push_back(equal_exprt(templ_expr, - is_null_ptr(pt.first) ? - pt.first : address_of_exprt(pt.first))); - } - result.push_back(disjunction(pt_expr)); - } - - for (auto &path : paths) - { // path(p, m, d)[O] - const exprt &dest = path.destination; - exprt::operandst path_expr; - - for (const dyn_objt &obj1 : points_to) - { - if (path.dyn_objects.find(obj1) != path.dyn_objects.end()) - { - // p = &o - exprt equ_exprt = equal_exprt(templ_expr, address_of_exprt(obj1.first)); - - exprt::operandst step_expr; - exprt member_expr = obj1.second; - // o.m = d - step_expr.push_back(equal_exprt(member_expr, dest)); - - for (auto &obj2 : path.dyn_objects) - { // o.m = o' - step_expr.push_back(equal_exprt(member_expr, address_of_exprt(obj2.first))); - } - - path_expr.push_back(and_exprt(equ_exprt, disjunction(step_expr))); - } - else - { - path_expr.push_back(equal_exprt(templ_expr, - is_null_ptr(obj1.first) ? - obj1.first : address_of_exprt(obj1.first))); - } - } - - result.push_back(disjunction(path_expr)); - } - - return conjunction(result); - } + exprt get_row_expr(const vart &templ_expr) const; inline bool empty() const { diff --git a/src/domains/ssa_analyzer.cpp b/src/domains/ssa_analyzer.cpp index d01654888..68d178e62 100644 --- a/src/domains/ssa_analyzer.cpp +++ b/src/domains/ssa_analyzer.cpp @@ -107,7 +107,7 @@ void ssa_analyzert::operator()( else if(template_generator.options.get_bool_option("heap")) { strategy_solver=new strategy_solver_heapt( - *static_cast(domain), solver, SSA.ns); + *static_cast(domain), solver, SSA, precondition); result=new heap_domaint::heap_valuet(); } else diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index b6ad92e6a..fc171428f 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -77,6 +77,8 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) exprt post = heap_domain.get_row_post_constraint(i, inv[i]); debug() << "post-cond: " << from_expr(ns, "", post) << " " << from_expr(ns, "", solver.get(post)) << eom; + print_solver_expr(c); + print_solver_expr(post); } #endif @@ -86,25 +88,25 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) { debug() << "updating row: " << row << eom; - int actual_loc = heap_domain.get_symbol_loc(heap_domain.templ[row].expr); + const heap_domaint::template_rowt &templ_row = heap_domain.templ[row]; + + int actual_loc = heap_domain.get_symbol_loc(templ_row.expr); exprt pointer = strategy_value_exprs[row]; exprt value = solver.get(pointer); // Value from solver must be converted into expression exprt ptr_value = heap_domain.value_to_ptr_exprt(value); - if (heap_domain.is_null_ptr(ptr_value)) + if (ptr_value.id() == ID_constant && to_constant_expr(ptr_value).get_value() == ID_NULL) { - exprt null_expr = null_pointer_exprt(to_pointer_type(ptr_value.type())); - - // Add path to NULL - if (heap_domain.add_row_path(row, inv, null_expr, + // Add path to constant + if (heap_domain.add_row_path(row, inv, ptr_value, std::make_pair(nil_exprt(), nil_exprt()))) improved = true; debug() << "add destination: " << from_expr(ns, "", ptr_value) << eom; // Add points to information - if (heap_domain.add_points_to(row, inv, std::make_pair(null_expr, nil_exprt()))) + if (heap_domain.add_points_to(row, inv, std::make_pair(ptr_value, nil_exprt()))) improved = true; debug() << "add points to: " << from_expr(ns, "", ptr_value) << eom; } @@ -119,69 +121,100 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) symbol_exprt obj = to_symbol_expr(to_address_of_expr(address).object()); - if (obj.type().get_bool("#dynamic")) + if (obj.type() == pointer.type()) { - // obj is dynamic object accessed inside the function + if (heap_domain.add_points_to(row, inv, std::make_pair(obj, nil_exprt()))) + improved = true; + debug() << "add points to: " << from_expr(ns, "", obj) << eom; - if (id2string(obj.get_identifier()).find("$unknown") != std::string::npos) - { // handle unknown object - if (heap_domain.add_points_to(row, inv, std::make_pair(obj, nil_exprt()))) - improved = true; - debug() << "add points to: " << from_expr(ns, "", obj) << eom; - } - else + if (heap_domain.add_row_path(row, inv, obj, + std::make_pair(nil_exprt(), nil_exprt()))); + } + else + { + + if (obj.type().get_bool("#dynamic")) { - // Find row with corresponding member field of pointed object (obj.member) - int member_val_index; - if (inv[row].empty() && heap_domain.templ[row].dyn_obj.id() != ID_nil && - heap_domain.get_base_name(obj) == - heap_domain.get_base_name(heap_domain.templ[row].dyn_obj)) - { // for the same object find previous instance - // (used for multiple loops in one function) - member_val_index = find_member_row(obj, heap_domain.templ[row].member, - --actual_loc); - if (member_val_index < 0) - member_val_index = find_member_row(obj, heap_domain.templ[row].member, - ++actual_loc); + // obj is dynamic object accessed inside the function + + if (id2string(obj.get_identifier()).find("$unknown") != std::string::npos) + { // handle unknown object + if (heap_domain.add_points_to(row, inv, std::make_pair(obj, nil_exprt()))) + improved = true; + debug() << "add points to: " << from_expr(ns, "", obj) << eom; } else { - member_val_index = find_member_row(obj, heap_domain.templ[row].member, actual_loc); + // Find row with corresponding member field of pointed object (obj.member) + int member_val_index; + if (inv[row].empty() && templ_row.dyn_obj.id() != ID_nil && + heap_domain.get_base_name(obj) == + heap_domain.get_base_name(templ_row.dyn_obj)) + { // for the same object find previous instance + // (used for multiple loops in one function) + member_val_index = find_member_row(obj, templ_row.member, --actual_loc, + templ_row.kind); + if (member_val_index < 0) + member_val_index = find_member_row(obj, templ_row.member, ++actual_loc, + templ_row.kind); + } + else + { + member_val_index = find_member_row(obj, templ_row.member, actual_loc, + templ_row.kind); + } + assert(member_val_index >= 0); + exprt member_expr = heap_domain.templ[member_val_index].expr; + + // Add all paths from obj.next to p + if (heap_domain.add_all_paths(row, (unsigned) member_val_index, inv, + std::make_pair(obj, member_expr))) + improved = true; + debug() << "add all paths: " << from_expr(ns, "", member_expr) << ", through: " + << from_expr(ns, "", obj) << eom; + + // Add points to information + if (heap_domain.add_points_to(row, inv, std::make_pair(obj, member_expr))) + improved = true; + debug() << "add points to: " << from_expr(ns, "", obj) << eom; + + heap_domain.add_pointed_by_row((unsigned) member_val_index, row, inv); } - assert(member_val_index >= 0); - exprt member_expr = heap_domain.templ[member_val_index].expr; - - // Add all paths from obj.next to p - if (heap_domain.add_all_paths(row, (unsigned) member_val_index, inv, - std::make_pair(obj, member_expr))) - improved = true; - debug() << "add all paths: " << from_expr(ns, "", member_expr) << ", through: " - << from_expr(ns, "", obj) << eom; - + } + else + { // Add points to information - if (heap_domain.add_points_to(row, inv, std::make_pair(obj, member_expr))) + if (heap_domain.add_points_to(row, inv, std::make_pair(obj, nil_exprt()))) improved = true; debug() << "add points to: " << from_expr(ns, "", obj) << eom; - heap_domain.add_pointed_by_row((unsigned) member_val_index, row, inv); + // Add path to &(obj) + if (heap_domain.add_row_path(row, inv, address_of_exprt(obj), + std::make_pair(nil_exprt(), nil_exprt()))) + improved = true; + debug() << "add destination: " << from_expr(ns, "", ptr_value) << eom; } } - else - { - // Add points to information - if (heap_domain.add_points_to(row, inv, std::make_pair(obj, nil_exprt()))) - improved = true; - debug() << "add points to: " << from_expr(ns, "", obj) << eom; + } + else if (ptr_value.id() == ID_symbol) + { + if (heap_domain.add_points_to(row, inv, std::make_pair(ptr_value, nil_exprt()))) + improved = true; + debug() << "add points to: " << from_expr(ns, "", ptr_value) << eom; - // Add path to &(obj) - if (heap_domain.add_row_path(row, inv, address_of_exprt(obj), - std::make_pair(nil_exprt(), nil_exprt()))) - improved = true; - debug() << "add destination: " << from_expr(ns, "", ptr_value) << eom; - } + if (heap_domain.add_row_path(row, inv, ptr_value, + std::make_pair(nil_exprt(), nil_exprt()))) + improved = true; + debug() << "add destination: " << from_expr(ns, "", ptr_value) << eom; + } + else + { + improved = !inv[row].nondet; + inv[row].nondet = true; + debug() << "set nondet" << eom; } - if (heap_domain.templ[row].dynamic) + if (templ_row.dynamic) { // Recursively update all rows that are dependent on this row updated_rows.clear(); update_rows_rec(row, inv); @@ -192,11 +225,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) else { -#define DEBUG_OUTPUT -#ifdef DEBUG_OUTPUT debug() << "UNSAT" << eom; -#endif -#undef DEBUG_OUTPUT #ifdef DEBUG_OUTPUT for (unsigned i = 0; i < solver.formula.size(); i++) @@ -206,6 +235,20 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) else debug() << "not_in_conflict: " << solver.formula[i] << eom; } + + for (unsigned i = 0; i < heap_domain.templ.size(); i++) + { + exprt c = heap_domain.get_row_pre_constraint(i, inv[i]); + debug() << "cond: " << from_expr(ns, "", c) << " " << + from_expr(ns, "", solver.get(c)) << eom; + debug() << "guards: " << from_expr(ns, "", heap_domain.templ[i].pre_guard) << + " " << from_expr(ns, "", solver.get(heap_domain.templ[i].pre_guard)) << eom; + debug() << "guards: " << from_expr(ns, "", heap_domain.templ[i].post_guard) << " " + << from_expr(ns, "", solver.get(heap_domain.templ[i].post_guard)) << eom; + exprt post = heap_domain.get_row_post_constraint(i, inv[i]); + debug() << "post-cond: " << from_expr(ns, "", post) << " " + << from_expr(ns, "", solver.get(post)) << eom; + } #endif } solver.pop_context(); @@ -221,7 +264,8 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) * @param actual_loc Actual location number * @return Template row of obj.member */ -int strategy_solver_heapt::find_member_row(const exprt &obj, const irep_idt &member, int actual_loc) +int strategy_solver_heapt::find_member_row(const exprt &obj, const irep_idt &member, int actual_loc, + const domaint::kindt &kind) { assert(obj.id() == ID_symbol); std::string obj_id = heap_domain.get_base_name(obj); @@ -231,7 +275,7 @@ int strategy_solver_heapt::find_member_row(const exprt &obj, const irep_idt &mem for (unsigned i = 0; i < heap_domain.templ.size(); ++i) { heap_domaint::template_rowt &templ_row = heap_domain.templ[i]; - if (templ_row.member == member && templ_row.dynamic) + if (templ_row.kind == kind && templ_row.member == member && templ_row.dynamic) { std::string id = id2string(to_symbol_expr(templ_row.expr).get_identifier()); if (id.find(obj_id) != std::string::npos) @@ -274,3 +318,67 @@ bool strategy_solver_heapt::update_rows_rec(const heap_domaint::rowt &row, } return result; } + +void strategy_solver_heapt::print_solver_expr(const exprt &expr) +{ + debug() << from_expr(ns, "", expr) << ": " << from_expr(ns, "", solver.get(expr)) << eom; + forall_operands(it, expr) + print_solver_expr(*it); +} + +void strategy_solver_heapt::initialize(const local_SSAt &SSA, const exprt &precondition) +{ + exprt::operandst equs; + for (auto ¶m : SSA.params) + { + if (param.type().id() == ID_pointer && + id2string(param.get_identifier()).find('.') == std::string::npos) + { + if (!has_precondition_rec(param, precondition)) + { + debug() << "Creating precondition for pointer parameters" << eom; + const symbolt *symbol; + if (ns.lookup(id2string(param.get_identifier()), symbol)) continue; + + address_of_exprt init_value(symbol->symbol_expr()); + init_value.type() = symbol->type; + equs.push_back(equal_exprt(param, init_value)); + } + } + } + for (auto &global_in : SSA.globals_in) + { + if (global_in.type().id() == ID_pointer && + id2string(global_in.get_identifier()).find('.') == std::string::npos) + { + if (!has_precondition_rec(global_in, precondition)) + { + debug() << "Creating precondition for pointer parameters" << eom; + const symbolt *symbol; + if (ns.lookup(id2string(global_in.get_identifier()), symbol)) continue; + + address_of_exprt init_value(symbol->symbol_expr()); + init_value.type() = symbol->type; + equs.push_back(equal_exprt(global_in, init_value)); + } + } + } + + solver << conjunction(equs); +} + +bool strategy_solver_heapt::has_precondition_rec(const exprt &expr, const exprt &precondition) +{ + if (precondition.id() == ID_equal) + { + const equal_exprt &eq = to_equal_expr(precondition); + return (eq.lhs() == expr && eq.rhs() != expr); + } + else + { + bool result = false; + forall_operands(it, precondition) + result = result || has_precondition_rec(expr, *it); + return result; + } +} diff --git a/src/domains/strategy_solver_heap.h b/src/domains/strategy_solver_heap.h index 5b22acf4e..0d80fc10f 100644 --- a/src/domains/strategy_solver_heap.h +++ b/src/domains/strategy_solver_heap.h @@ -5,6 +5,7 @@ #ifndef CPROVER_STRATEGY_SOLVER_HEAP_H #define CPROVER_STRATEGY_SOLVER_HEAP_H +#include "../ssa/local_ssa.h" #include "strategy_solver_base.h" #include "heap_domain.h" @@ -12,20 +13,28 @@ class strategy_solver_heapt : public strategy_solver_baset { public: explicit strategy_solver_heapt(heap_domaint &_heap_domain, incremental_solvert &_solver, - const namespacet &_ns) - : strategy_solver_baset(_solver, _ns), heap_domain(_heap_domain) + const local_SSAt &SSA, const exprt &precondition) + : strategy_solver_baset(_solver, SSA.ns), heap_domain(_heap_domain) { + initialize(SSA, precondition); } virtual bool iterate(invariantt &_inv) override; + void initialize(const local_SSAt &SSA, const exprt &precondition); + protected: heap_domaint &heap_domain; std::set updated_rows; - int find_member_row(const exprt &obj, const irep_idt &member, int actual_loc); + int find_member_row(const exprt &obj, const irep_idt &member, int actual_loc, + const domaint::kindt &kind); bool update_rows_rec(const heap_domaint::rowt &row, heap_domaint::heap_valuet &value); + + void print_solver_expr(const exprt &expr); + + bool has_precondition_rec(const exprt &expr, const exprt &precondition); }; diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index 7aa2e1ed9..45249b0e5 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -273,8 +273,9 @@ void template_generator_baset::filter_heap_domain() { if(var->var.id()==ID_symbol && var->var.type().id()==ID_pointer) { - // Filter out non-assigned variables - if(ssa_inlinert::get_original_identifier(to_symbol_expr(var->var)) != + // Filter out non-assigned OUT variables + if(var->kind!=domaint::OUT || + ssa_inlinert::get_original_identifier(to_symbol_expr(var->var))!= to_symbol_expr(var->var).get_identifier()) var_specs.push_back(*var); } diff --git a/src/ssa/address_canonizer.cpp b/src/ssa/address_canonizer.cpp index f6e6b9cb2..466139299 100644 --- a/src/ssa/address_canonizer.cpp +++ b/src/ssa/address_canonizer.cpp @@ -49,7 +49,7 @@ exprt address_canonizer( if (offset.id()==ID_constant && to_constant_expr(offset).is_zero()) { - return address_of_exprt(to_member_expr(object).struct_op()); + return address_of_exprt(to_member_expr(object).compound()); } else { From 1cb1881021e297be4c613451ef459555f90658b8 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 17 Jan 2017 10:55:07 +0100 Subject: [PATCH 037/322] Strategy solver heap: move creating precondition to separate function --- src/domains/strategy_solver_heap.cpp | 56 ++++++++++++---------------- src/domains/strategy_solver_heap.h | 3 ++ 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index fc171428f..6b9bc6c91 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -328,41 +328,12 @@ void strategy_solver_heapt::print_solver_expr(const exprt &expr) void strategy_solver_heapt::initialize(const local_SSAt &SSA, const exprt &precondition) { + // Create preconditions for input variables if not exist exprt::operandst equs; for (auto ¶m : SSA.params) - { - if (param.type().id() == ID_pointer && - id2string(param.get_identifier()).find('.') == std::string::npos) - { - if (!has_precondition_rec(param, precondition)) - { - debug() << "Creating precondition for pointer parameters" << eom; - const symbolt *symbol; - if (ns.lookup(id2string(param.get_identifier()), symbol)) continue; - - address_of_exprt init_value(symbol->symbol_expr()); - init_value.type() = symbol->type; - equs.push_back(equal_exprt(param, init_value)); - } - } - } + create_precondition(param, precondition, equs); for (auto &global_in : SSA.globals_in) - { - if (global_in.type().id() == ID_pointer && - id2string(global_in.get_identifier()).find('.') == std::string::npos) - { - if (!has_precondition_rec(global_in, precondition)) - { - debug() << "Creating precondition for pointer parameters" << eom; - const symbolt *symbol; - if (ns.lookup(id2string(global_in.get_identifier()), symbol)) continue; - - address_of_exprt init_value(symbol->symbol_expr()); - init_value.type() = symbol->type; - equs.push_back(equal_exprt(global_in, init_value)); - } - } - } + create_precondition(global_in, precondition, equs); solver << conjunction(equs); } @@ -378,7 +349,26 @@ bool strategy_solver_heapt::has_precondition_rec(const exprt &expr, const exprt { bool result = false; forall_operands(it, precondition) - result = result || has_precondition_rec(expr, *it); + result = result || has_precondition_rec(expr, *it); return result; } } + +void strategy_solver_heapt::create_precondition(const symbol_exprt &var, const exprt &precondition, + exprt::operandst &equs) +{ + if (var.type().id() == ID_pointer && + id2string(var.get_identifier()).find('.') == std::string::npos) + { + if (!has_precondition_rec(var, precondition)) + { + debug() << "Creating precondition for pointer parameters" << eom; + const symbolt *symbol; + if (ns.lookup(id2string(var.get_identifier()), symbol)) return; + + address_of_exprt init_value(symbol->symbol_expr()); + init_value.type() = symbol->type; + equs.push_back(equal_exprt(var, init_value)); + } + } +} diff --git a/src/domains/strategy_solver_heap.h b/src/domains/strategy_solver_heap.h index 0d80fc10f..c048dda04 100644 --- a/src/domains/strategy_solver_heap.h +++ b/src/domains/strategy_solver_heap.h @@ -34,6 +34,9 @@ class strategy_solver_heapt : public strategy_solver_baset void print_solver_expr(const exprt &expr); + void create_precondition(const symbol_exprt &var, const exprt &precondition, + exprt::operandst &equs); + bool has_precondition_rec(const exprt &expr, const exprt &precondition); }; From 0b8a3c835aa2e5160c99a31494989f699f8c29f0 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 17 Jan 2017 11:02:30 +0100 Subject: [PATCH 038/322] Heap domain: split template into STACK and HEAP part. Stack part contains rows for pointers and a value is set of pointed objects. Heap part contains rows for struct objects and a value is set of access paths. --- src/domains/heap_domain.cpp | 360 +++++++++++++-------------- src/domains/heap_domain.h | 79 ++++-- src/domains/strategy_solver_heap.cpp | 232 +++++++++-------- 3 files changed, 339 insertions(+), 332 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 20fc9cb14..6431059cb 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -16,12 +16,15 @@ void heap_domaint::initialize(domaint::valuet &value) { heap_valuet &val = static_cast(value); - val.resize(templ.size()); - for (unsigned row = 0; row < templ.size(); ++row) + + for (auto &templ_row : templ) { - val[row].paths.clear(); - val[row].points_to.clear(); - val[row].pointed_by.clear(); + if (templ_row.mem_kind == STACK) + val.emplace_back(new stack_row_valuet()); + else if (templ_row.mem_kind == HEAP) + val.emplace_back(new heap_row_valuet()); + else + assert(false); } } @@ -38,55 +41,52 @@ void heap_domaint::make_template(const domaint::var_specst &var_specs, const nam templ.clear(); templ.reserve(size); - for (auto v1 = var_specs.begin(); v1 != var_specs.end(); ++v1) + for (auto v = var_specs.begin(); v != var_specs.end(); ++v) { - if (v1->kind == IN) continue; + if (v->kind == IN) continue; // Create template for each pointer to struct - const vart &var1 = v1->var; - if (var1.type().id() == ID_pointer) + const vart &var = v->var; + if (var.type().id() == ID_pointer) { - const typet &pointed_type = ns.follow(var1.type().subtype()); + const typet &pointed_type = ns.follow(var.type().subtype()); if (pointed_type.id() == ID_struct) { - // Check if var1 is member field of dynamic object - const std::string identifier = id2string(to_symbol_expr(v1->var).get_identifier()); - bool dynamic = false; - for (auto &component : to_struct_type(pointed_type).components()) - { - if (identifier.find("." + id2string(component.get_name())) != std::string::npos) - dynamic = true; - } - - for (auto &component : to_struct_type(pointed_type).components()) - { - if (!dynamic || - identifier.find("." + id2string(component.get_name())) != std::string::npos) - { - templ.push_back(template_rowt()); - template_rowt &templ_row = templ.back(); - templ_row.expr = v1->var; - templ_row.member = component.get_name(); - templ_row.pre_guard = v1->pre_guard; - templ_row.post_guard = v1->post_guard; - templ_row.aux_expr = v1->aux_expr; - templ_row.kind = v1->kind; - templ_row.dynamic = dynamic; - if (dynamic) - { - std::string var1_id = id2string(to_symbol_expr(var1).get_identifier()); - std::string do_id = var1_id.substr(0, var1_id.find_last_of('.')); - templ_row.dyn_obj = symbol_exprt(do_id, var1.type().subtype()); - } - else - templ_row.dyn_obj = nil_exprt(); - } - } + add_template_row(*v, pointed_type); } } } } +void heap_domaint::add_template_row(const var_spect &var_spec, const typet &pointed_type) +{ + const vart &var = var_spec.var; + + templ.push_back(template_rowt()); + template_rowt &templ_row = templ.back(); + templ_row.expr = var; + templ_row.pre_guard = var_spec.pre_guard; + templ_row.post_guard = var_spec.post_guard; + templ_row.aux_expr = var_spec.aux_expr; + templ_row.kind = var_spec.kind; + + templ_row.mem_kind = STACK; + // Check if var is member field of heap object + const std::string identifier = id2string(to_symbol_expr(var_spec.var).get_identifier()); + for (auto &component : to_struct_type(pointed_type).components()) + { + if (identifier.find("." + id2string(component.get_name())) != std::string::npos) + { + templ_row.mem_kind = HEAP; + templ_row.member = component.get_name(); + + std::string var_id = id2string(to_symbol_expr(var).get_identifier()); + std::string do_id = var_id.substr(0, var_id.find_last_of('.')); + templ_row.dyn_obj = symbol_exprt(do_id, var.type().subtype()); + } + } +} + /** * Create entry constraints expression for a value. * @param value Value @@ -161,50 +161,6 @@ exprt heap_domaint::get_row_post_constraint(const rowt &row, const row_valuet &r return c; } -/** - * Add new destination for a row - * @param row Row number - * @param value Value - * @param dest New destination to add - * @param dyn_obj Dynamic object for that the path passes through (is nil if path can have zero - * length). - * @return True if insertion took place (dest did not exist in the row value) - */ -bool heap_domaint::add_row_path(const rowt &row, heap_valuet &value, const exprt &dest, - const dyn_objt &dyn_obj) -{ - assert(row < value.size()); - assert(value.size() == templ.size()); - - auto &path_set = value[row].paths; - - if (path_set.find(dest) == path_set.end()) - { - // Path does not exist yet - std::set dyn_obj_set; - bool zero_path = true; - if (dyn_obj.first.id() != ID_nil) - { // Path doesn't have zero length - dyn_obj_set.insert(dyn_obj); - zero_path = false; - } - path_set.emplace(dest, dyn_obj_set, zero_path); - return true; - } - else - { - // Path exists already - if (dyn_obj.first.id() == ID_nil) - { - bool result = path_set.find(dest)->zero_length; - path_set.find(dest)->zero_length = true; - return !result; - } - // Try to insert new dynamic object belonging to the path - return path_set.find(dest)->dyn_objects.insert(dyn_obj).second; - } -} - /** * Add all paths of one pointer as the destinations of another pointer. * @param to Row to add new paths to @@ -214,46 +170,43 @@ bool heap_domaint::add_row_path(const rowt &row, heap_valuet &value, const exprt * one pointer to another. * @return True if any path was added or changed, otherwise false. */ -bool heap_domaint::add_all_paths(const rowt &to, const rowt &from, heap_valuet &value, - const dyn_objt &dyn_obj) +bool heap_domaint::add_transitivity(const rowt &from, const rowt &to, heap_valuet &value) { + assert(from < value.size() && to < value.size()); + assert(templ[to].mem_kind == HEAP && templ[from].mem_kind == HEAP); + + heap_row_valuet &heap_val_from = static_cast(value[from]); + heap_row_valuet &heap_val_to = static_cast(value[to]); + bool result = false; - for (auto &path : value[from].paths) + if (heap_val_from.add_all_paths(heap_val_to, std::make_pair(templ[to].dyn_obj, templ[to].expr))) + result = true; + if (from != to) { - // Add the path with new dynamic object - if (add_row_path(to, value, path.destination, dyn_obj)) + if (heap_val_to.add_pointed_by(from)) result = true; - for (auto &o : path.dyn_objects) - { // Add all dynamic objects of the original path - if (add_row_path(to, value, path.destination, o)) - result = true; - } } + return result; } -/** - * Add new points to address to a row. - * @param row Value row - * @param value Heap value - * @param dyn_obj New dynamic object that the row variable can point to. - * @return True if the object was really added. - */ -bool heap_domaint::add_points_to(const rowt &row, heap_valuet &value, const dyn_objt &dyn_obj) +bool heap_domaint::add_points_to(const heap_domaint::rowt &row, heap_domaint::heap_valuet &value, + const exprt &dest) { - auto new_pt = value[row].points_to.insert(dyn_obj); - return new_pt.second; + assert(row < value.size()); + + if (templ[row].dyn_obj == dest) return false; + + return value[row].add_points_to(dest); } -/** - * Add new dependent row (pb_row points to row) - * @param row Pointed row - * @param pb_row Pointer row - * @param value Heap value - */ -void heap_domaint::add_pointed_by_row(const rowt &row, const rowt &pb_row, heap_valuet &value) +bool heap_domaint::set_nondet(const rowt &row, heap_valuet &value) { - value[row].pointed_by.insert(pb_row); + assert(row < value.size()); + + bool result = !value[row].nondet; + value[row].nondet = true; + return result; } void heap_domaint::output_value(std::ostream &out, const domaint::valuet &value, @@ -314,8 +267,10 @@ void heap_domaint::output_domain(std::ostream &out, const namespacet &ns) const assert(false); } const vart &var = templ_row.expr; - const irep_idt &member = templ_row.member; - out << i << ": ?path(" << from_expr(ns, "", var) << ", " << member << ", DESTINATIONS)" + + out << i << ": " << from_expr(ns, "", var) + << (templ_row.mem_kind == STACK ? " --points_to--> Locations" + : " --paths--> Destinations") << std::endl; } } @@ -371,26 +326,6 @@ void heap_domaint::join(domaint::valuet &value1, const domaint::valuet &value2) const heap_valuet &val2 = static_cast(value2); assert(val1.size() == templ.size()); assert(val2.size() == val1.size()); - for (rowt row = 0; row < templ.size(); ++row) - { // Insert all elements of second set to first - val1[row].paths.insert(val2[row].paths.begin(), val2[row].paths.end()); - } -} - -/** - * Check whether expression is NULL pointer. - * @param expr Expression to check - * @return True if expr is NULL pointer - */ -bool heap_domaint::is_null_ptr(const exprt &expr) -{ - if (expr.id() == ID_constant && to_constant_expr(expr).get_value() == ID_NULL) - return true; - if (expr.id() == ID_plus) - return is_null_ptr(expr.op0()) || is_null_ptr(expr.op1()); - if (expr.id() == ID_typecast) - return is_null_ptr(to_typecast_expr(expr).op()); - return false; } /** @@ -421,77 +356,122 @@ std::string heap_domaint::get_base_name(const exprt &expr) return result; } -/** - * Get expression for the row value. It is a conjunction of points to expression and path - * expressions. - * Points to expression is disjunction of equalities: - * p = &o (NULL) for each object 'o' (or NULL) from points_to set - * Expression of path leading from variable 'p' to destination 'd' via field 'm' and - * passing through set of objects 'O' has form: - * p = d || if path can have zero length - * p = &o && (o.m = d || o.m = o') where o,o' belong to O and p can point to &o - * @param templ_expr Pointer variable of the template row - * @return Row value expression in the described form - */ -exprt heap_domaint::row_valuet::get_row_expr(const vart &templ_expr) const +exprt heap_domaint::stack_row_valuet::get_row_expr(const domaint::vart &templ_expr) const { if (nondet) return true_exprt(); - if (paths.empty() && points_to.empty()) return false_exprt(); - - exprt::operandst result; - - exprt::operandst pt_expr; - if (!points_to.empty()) + if (empty()) + return false_exprt(); + else { // Points to expression + exprt::operandst result; for (auto &pt : points_to) { - pt_expr.push_back(equal_exprt(templ_expr, - templ_expr.type() == pt.first.type() ? - pt.first : address_of_exprt(pt.first))); + result.push_back(equal_exprt(templ_expr, templ_expr.type() == pt.type() ? + pt : address_of_exprt(pt))); } - result.push_back(disjunction(pt_expr)); + return disjunction(result); } +} - exprt::operandst paths_expr; - if (!paths.empty()) +bool heap_domaint::stack_row_valuet::add_points_to(const exprt &expr) +{ + auto new_pt = points_to.insert(expr); + return new_pt.second; +} + +exprt heap_domaint::heap_row_valuet::get_row_expr(const domaint::vart &templ_expr) const +{ + if (nondet) return true_exprt(); + + if (empty()) + return false_exprt(); + else { + exprt::operandst result; for (auto &path : paths) - { // path(p, m, d)[O] - const exprt &dest = path.destination; + { // path(o.m, d)[O] + const exprt &dest = templ_expr.type() == path.destination.type() ? + path.destination : address_of_exprt(path.destination); exprt::operandst path_expr; - for (const dyn_objt &obj1 : points_to) + // o.m = d + path_expr.push_back(equal_exprt(templ_expr, dest)); + + for (const dyn_objt &obj1 : path.dyn_objects) { - if (path.dyn_objects.find(obj1) != path.dyn_objects.end()) - { - // p = &o - exprt equ_exprt = equal_exprt(templ_expr, address_of_exprt(obj1.first)); - - exprt::operandst step_expr; - exprt member_expr = obj1.second; - // o.m = d - step_expr.push_back(equal_exprt(member_expr, dest)); - - for (auto &obj2 : path.dyn_objects) - { // o.m = o' - step_expr.push_back(equal_exprt(member_expr, address_of_exprt(obj2.first))); - } - - path_expr.push_back(and_exprt(equ_exprt, disjunction(step_expr))); - } - else - { - path_expr.push_back(equal_exprt(templ_expr, - templ_expr.type() == obj1.first.type() ? - obj1.first : address_of_exprt(obj1.first))); + // o.m = &o' + exprt equ_exprt = equal_exprt(templ_expr, address_of_exprt(obj1.first)); + + exprt::operandst steps_expr; + exprt member_expr = obj1.second; + // o'.m = d + steps_expr.push_back(equal_exprt(member_expr, dest)); + + for (auto &obj2 : path.dyn_objects) + { // o'.m = o'' + steps_expr.push_back(equal_exprt(member_expr, address_of_exprt(obj2.first))); } + + path_expr.push_back(and_exprt(equ_exprt, disjunction(steps_expr))); } - paths_expr.push_back(disjunction(path_expr)); + result.push_back(disjunction(path_expr)); + } + return conjunction(result); + } +} + +bool heap_domaint::heap_row_valuet::add_points_to(const exprt &dest) +{ + return add_path(dest, std::make_pair(nil_exprt(), nil_exprt())); +} + +bool heap_domaint::heap_row_valuet::add_path(const exprt &dest, + const heap_domaint::dyn_objt &dyn_obj) +{ + if (paths.find(dest) == paths.end()) + { + // Path does not exist yet + std::set dyn_obj_set; + if (dyn_obj.first.id() != ID_nil) + { // Path doesn't have zero length + dyn_obj_set.insert(dyn_obj); } - result.push_back(disjunction(paths_expr)); + paths.emplace(dest, dyn_obj_set); + return true; + } + else + { + // Path exists already + if (dyn_obj.first.id() != ID_nil) + // Try to insert new dynamic object on the path + return paths.find(dest)->dyn_objects.insert(dyn_obj).second; + else + return false; } +} - return conjunction(result); +bool heap_domaint::heap_row_valuet::add_all_paths(const heap_domaint::heap_row_valuet &other_val, + const heap_domaint::dyn_objt &dyn_obj) +{ + bool result = false; + for (auto &path : other_val.paths) + { + // Add the path with new dynamic object + if (add_path(path.destination, dyn_obj)) + result = true; + for (auto &o : path.dyn_objects) + { // Add all dynamic objects of the original path + if (add_path(path.destination, o)) + result = true; + } + } + return result; +} + +bool heap_domaint::heap_row_valuet::add_pointed_by(const rowt &row) +{ + auto new_pb = pointed_by.insert(row); + return new_pb.second; } diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index 2f0b51dd1..ca6474ca0 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -6,6 +6,8 @@ #ifndef CPROVER_2LS_DOMAINS_HEAP_DOMAIN_H #define CPROVER_2LS_DOMAINS_HEAP_DOMAIN_H +#include +#include #include "domain.h" class heap_domaint:public domaint @@ -15,6 +17,8 @@ class heap_domaint:public domaint typedef vart member_fieldt; typedef std::pair dyn_objt; + typedef enum { STACK, HEAP } mem_kindt; + heap_domaint( unsigned int _domain_number, replace_mapt &_renaming_map, @@ -29,6 +33,31 @@ class heap_domaint:public domaint * Value of a row is set of paths in the heap leading from row variable */ struct row_valuet + { + bool nondet = false; /**< Row is nondeterministic - expression is TRUE */ + + virtual exprt get_row_expr(const vart &templ_expr) const = 0; + + virtual bool empty() const = 0; + + virtual bool add_points_to(const exprt &dest) = 0; + }; + + struct stack_row_valuet : public row_valuet + { + std::set points_to; /**< Set of objects (or NULL) the row variable can point to */ + + virtual exprt get_row_expr(const vart &templ_expr) const override; + + virtual bool add_points_to(const exprt &expr) override; + + virtual bool empty() const override + { + return points_to.empty(); + } + }; + + struct heap_row_valuet : public row_valuet { /** * Path in a heap. Contains: @@ -41,12 +70,11 @@ class heap_domaint:public domaint { exprt destination; mutable std::set dyn_objects; - mutable bool zero_length; patht(const exprt &dest_) : destination(dest_) {} - patht(const exprt &dest_, const std::set &dyn_objs_, const bool zero_l_) - : destination(dest_), dyn_objects(dyn_objs_), zero_length(zero_l_) {} + patht(const exprt &dest_, const std::set &dyn_objs_) + : destination(dest_), dyn_objects(dyn_objs_) {} bool operator<(const patht &rhs) const { @@ -59,33 +87,44 @@ class heap_domaint:public domaint } }; - std::set paths; /**< Set of paths leading from the row variable */ - std::set points_to; /**< Set of objects (or NULL) the row variable can point to */ - std::set pointed_by; /**< Set of rows whose variables point to this row */ - bool nondet = false; /**< Row is nondeterministic - expression is TRUE */ + std::set paths; /**< Set o paths leading from the row variable */ + std::set pointed_by; /**< Set of rows whose variables point to this row */ - exprt get_row_expr(const vart &templ_expr) const; + virtual exprt get_row_expr(const vart &templ_expr) const override; - inline bool empty() const + virtual bool add_points_to(const exprt &dest) override; + + virtual bool empty() const override { return paths.empty(); } + + bool add_path(const exprt &dest, const dyn_objt &dyn_obj); + + bool add_all_paths(const heap_row_valuet &other_val, const dyn_objt &dyn_obj); + + bool add_pointed_by(const rowt &row); }; - class heap_valuet : public valuet, public std::vector + class heap_valuet : public valuet, public std::vector> { + public: + row_valuet &operator[](const rowt &row) const + { + return *(this->at(row).get()); + } }; struct template_rowt { + vart expr; guardt pre_guard; guardt post_guard; - vart expr; - irep_idt member; exprt aux_expr; kindt kind; + mem_kindt mem_kind; exprt dyn_obj; - bool dynamic; + irep_idt member; }; typedef std::vector templatet; @@ -103,15 +142,11 @@ class heap_domaint:public domaint exprt get_row_post_constraint(const rowt &row, const row_valuet &row_value); - // Add new predicates to a row value (path, or points_to) - bool add_row_path(const rowt &row, heap_valuet &value, const exprt &dest, - const dyn_objt &dyn_obj); + bool add_transitivity(const rowt &from, const rowt &to, heap_valuet &value); - bool add_all_paths(const rowt &to, const rowt &from, heap_valuet &value, const dyn_objt &dyn_obj); + bool add_points_to(const rowt &row, heap_valuet &value, const exprt &dest); - bool add_points_to(const rowt &row, heap_valuet &value, const dyn_objt &dyn_obj); - - void add_pointed_by_row(const rowt &row, const rowt &pb_row, heap_valuet &value); + bool set_nondet(const rowt &row, heap_valuet &value); // Printing virtual void output_value(std::ostream &out, const valuet &value, @@ -128,13 +163,13 @@ class heap_domaint:public domaint // Join of values virtual void join(valuet &value1, const valuet &value2) override; - static bool is_null_ptr(const exprt &expr); - protected: templatet templ; void make_template(const var_specst &var_specs, const namespacet &ns); + void add_template_row(const var_spect &var_spec, const typet &pointed_type); + // Utility functions static int get_symbol_loc(const exprt &expr); diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index 6b9bc6c91..dad13badc 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -9,7 +9,8 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) { - heap_domaint::heap_valuet &inv = static_cast(_inv); + heap_domaint::heap_valuet &inv= + static_cast(_inv); bool improved = false; @@ -24,7 +25,8 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) // Exit value constraints exprt::operandst strategy_cond_exprs; - heap_domain.make_not_post_constraints(inv, strategy_cond_exprs, strategy_value_exprs); + heap_domain.make_not_post_constraints( + inv, strategy_cond_exprs, strategy_value_exprs); strategy_cond_literals.resize(strategy_cond_exprs.size()); @@ -34,7 +36,8 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) for (unsigned i = 0; i < strategy_cond_exprs.size(); ++i) { #ifdef DEBUG_OUTPUT - debug() << (i > 0 ? " || " : "") << from_expr(ns, "", strategy_cond_exprs[i]); + debug() << (i > 0 ? " || " : "") + << from_expr(ns, "", strategy_cond_exprs[i]); #endif strategy_cond_literals[i] = solver.convert(strategy_cond_exprs[i]); strategy_cond_exprs[i] = literal_exprt(strategy_cond_literals[i]); @@ -70,10 +73,15 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) exprt c = heap_domain.get_row_pre_constraint(i, inv[i]); debug() << "cond: " << from_expr(ns, "", c) << " " << from_expr(ns, "", solver.get(c)) << eom; - debug() << "guards: " << from_expr(ns, "", heap_domain.templ[i].pre_guard) << - " " << from_expr(ns, "", solver.get(heap_domain.templ[i].pre_guard)) << eom; - debug() << "guards: " << from_expr(ns, "", heap_domain.templ[i].post_guard) << " " - << from_expr(ns, "", solver.get(heap_domain.templ[i].post_guard)) << eom; + debug() << "guards: " + << from_expr(ns, "", heap_domain.templ[i].pre_guard) + << " " + << from_expr(ns, "", solver.get(heap_domain.templ[i].pre_guard)) + << eom; + debug() << "guards: " + << from_expr(ns, "", heap_domain.templ[i].post_guard) << " " + << from_expr(ns, "", solver.get(heap_domain.templ[i].post_guard)) + << eom; exprt post = heap_domain.get_row_post_constraint(i, inv[i]); debug() << "post-cond: " << from_expr(ns, "", post) << " " << from_expr(ns, "", solver.get(post)) << eom; @@ -97,18 +105,19 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) // Value from solver must be converted into expression exprt ptr_value = heap_domain.value_to_ptr_exprt(value); - if (ptr_value.id() == ID_constant && to_constant_expr(ptr_value).get_value() == ID_NULL) + if ((ptr_value.id() == ID_constant && + to_constant_expr(ptr_value).get_value() == ID_NULL) || + ptr_value.id() == ID_symbol) { - // Add path to constant - if (heap_domain.add_row_path(row, inv, ptr_value, - std::make_pair(nil_exprt(), nil_exprt()))) - improved = true; - debug() << "add destination: " << from_expr(ns, "", ptr_value) << eom; - - // Add points to information - if (heap_domain.add_points_to(row, inv, std::make_pair(ptr_value, nil_exprt()))) + // Add equality p == NULL or p == symbol + if (heap_domain.add_points_to(row, inv, ptr_value)) + { improved = true; - debug() << "add points to: " << from_expr(ns, "", ptr_value) << eom; + debug() << "Add " + << (templ_row.mem_kind == heap_domaint::STACK ? + "points to " : "path to ") + << from_expr(ns, "", ptr_value) << eom; + } } else if (ptr_value.id() == ID_address_of) { @@ -119,102 +128,66 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) const exprt address = address_canonizer(ptr_value, ns); assert(to_address_of_expr(address).object().id() == ID_symbol); - symbol_exprt obj = to_symbol_expr(to_address_of_expr(address).object()); + symbol_exprt obj=to_symbol_expr(to_address_of_expr(address).object()); - if (obj.type() == pointer.type()) + // Add equality p == &obj + if (heap_domain.add_points_to(row, inv, obj)) { - if (heap_domain.add_points_to(row, inv, std::make_pair(obj, nil_exprt()))) - improved = true; - debug() << "add points to: " << from_expr(ns, "", obj) << eom; - - if (heap_domain.add_row_path(row, inv, obj, - std::make_pair(nil_exprt(), nil_exprt()))); + improved = true; + debug() << "Add " + << (templ_row.mem_kind == heap_domaint::STACK ? + "points to " : "path to ") + << from_expr(ns, "", obj) << eom; } - else - { - if (obj.type().get_bool("#dynamic")) - { - // obj is dynamic object accessed inside the function - - if (id2string(obj.get_identifier()).find("$unknown") != std::string::npos) - { // handle unknown object - if (heap_domain.add_points_to(row, inv, std::make_pair(obj, nil_exprt()))) - improved = true; - debug() << "add points to: " << from_expr(ns, "", obj) << eom; - } - else - { - // Find row with corresponding member field of pointed object (obj.member) - int member_val_index; - if (inv[row].empty() && templ_row.dyn_obj.id() != ID_nil && - heap_domain.get_base_name(obj) == - heap_domain.get_base_name(templ_row.dyn_obj)) - { // for the same object find previous instance - // (used for multiple loops in one function) - member_val_index = find_member_row(obj, templ_row.member, --actual_loc, - templ_row.kind); - if (member_val_index < 0) - member_val_index = find_member_row(obj, templ_row.member, ++actual_loc, - templ_row.kind); - } - else - { - member_val_index = find_member_row(obj, templ_row.member, actual_loc, - templ_row.kind); - } - assert(member_val_index >= 0); - exprt member_expr = heap_domain.templ[member_val_index].expr; - - // Add all paths from obj.next to p - if (heap_domain.add_all_paths(row, (unsigned) member_val_index, inv, - std::make_pair(obj, member_expr))) - improved = true; - debug() << "add all paths: " << from_expr(ns, "", member_expr) << ", through: " - << from_expr(ns, "", obj) << eom; - - // Add points to information - if (heap_domain.add_points_to(row, inv, std::make_pair(obj, member_expr))) - improved = true; - debug() << "add points to: " << from_expr(ns, "", obj) << eom; - - heap_domain.add_pointed_by_row((unsigned) member_val_index, row, inv); - } + if(templ_row.mem_kind==heap_domaint::HEAP && + obj.type().get_bool("#dynamic") && + id2string(obj.get_identifier()).find("$unknown")== + std::string::npos) + { + // Find row with corresponding member field + // of pointed object (obj.member) + int member_val_index; + if (inv[row].empty() && templ_row.dyn_obj.id() != ID_nil && + heap_domain.get_base_name(obj) == + heap_domain.get_base_name(templ_row.dyn_obj)) + { // for the same object find previous instance + // (used for multiple loops in one function) + member_val_index=find_member_row( + obj, templ_row.member, --actual_loc, templ_row.kind); + if (member_val_index < 0) + member_val_index = find_member_row( + obj, templ_row.member, ++actual_loc, templ_row.kind); } else { - // Add points to information - if (heap_domain.add_points_to(row, inv, std::make_pair(obj, nil_exprt()))) - improved = true; - debug() << "add points to: " << from_expr(ns, "", obj) << eom; - - // Add path to &(obj) - if (heap_domain.add_row_path(row, inv, address_of_exprt(obj), - std::make_pair(nil_exprt(), nil_exprt()))) - improved = true; - debug() << "add destination: " << from_expr(ns, "", ptr_value) << eom; + member_val_index=find_member_row( + obj, templ_row.member, actual_loc, templ_row.kind); } - } - } - else if (ptr_value.id() == ID_symbol) - { - if (heap_domain.add_points_to(row, inv, std::make_pair(ptr_value, nil_exprt()))) - improved = true; - debug() << "add points to: " << from_expr(ns, "", ptr_value) << eom; + assert(member_val_index >= 0); - if (heap_domain.add_row_path(row, inv, ptr_value, - std::make_pair(nil_exprt(), nil_exprt()))) - improved = true; - debug() << "add destination: " << from_expr(ns, "", ptr_value) << eom; + // Add all paths from obj.next to p + if(heap_domain.add_transitivity( + row, (unsigned) member_val_index, inv)) + { + improved = true; + debug() + << "Add all paths: " + << from_expr(ns, "", heap_domain.templ[member_val_index].expr) + << ", through: " << from_expr(ns, "", obj) << eom; + } + } } else { - improved = !inv[row].nondet; - inv[row].nondet = true; - debug() << "set nondet" << eom; + if (heap_domain.set_nondet(row, inv)) + { + improved = true; + debug() << "Set nondet" << eom; + } } - if (templ_row.dynamic) + if (templ_row.mem_kind == heap_domaint::HEAP) { // Recursively update all rows that are dependent on this row updated_rows.clear(); update_rows_rec(row, inv); @@ -241,10 +214,15 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) exprt c = heap_domain.get_row_pre_constraint(i, inv[i]); debug() << "cond: " << from_expr(ns, "", c) << " " << from_expr(ns, "", solver.get(c)) << eom; - debug() << "guards: " << from_expr(ns, "", heap_domain.templ[i].pre_guard) << - " " << from_expr(ns, "", solver.get(heap_domain.templ[i].pre_guard)) << eom; - debug() << "guards: " << from_expr(ns, "", heap_domain.templ[i].post_guard) << " " - << from_expr(ns, "", solver.get(heap_domain.templ[i].post_guard)) << eom; + debug() << "guards: " + << from_expr(ns, "", heap_domain.templ[i].pre_guard) + << " " + << from_expr(ns, "", solver.get(heap_domain.templ[i].pre_guard)) + << eom; + debug() << "guards: " + << from_expr(ns, "", heap_domain.templ[i].post_guard) << " " + << from_expr(ns, "", solver.get(heap_domain.templ[i].post_guard)) + << eom; exprt post = heap_domain.get_row_post_constraint(i, inv[i]); debug() << "post-cond: " << from_expr(ns, "", post) << " " << from_expr(ns, "", solver.get(post)) << eom; @@ -257,15 +235,19 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) } /** - * Find the template row that contains specified member field of a dynamic object at given location. + * Find the template row that contains specified member field + * of a dynamic object at given location. * Finds obj.member#loc with maximal loc less than actual_loc. * @param obj * @param member Member field to find * @param actual_loc Actual location number * @return Template row of obj.member */ -int strategy_solver_heapt::find_member_row(const exprt &obj, const irep_idt &member, int actual_loc, - const domaint::kindt &kind) +int strategy_solver_heapt::find_member_row( + const exprt &obj, + const irep_idt &member, + int actual_loc, + const domaint::kindt &kind) { assert(obj.id() == ID_symbol); std::string obj_id = heap_domain.get_base_name(obj); @@ -275,9 +257,10 @@ int strategy_solver_heapt::find_member_row(const exprt &obj, const irep_idt &mem for (unsigned i = 0; i < heap_domain.templ.size(); ++i) { heap_domaint::template_rowt &templ_row = heap_domain.templ[i]; - if (templ_row.kind == kind && templ_row.member == member && templ_row.dynamic) + if (templ_row.kind == kind && templ_row.member == member && + templ_row.mem_kind == heap_domaint::HEAP) { - std::string id = id2string(to_symbol_expr(templ_row.expr).get_identifier()); + std::string id=id2string(to_symbol_expr(templ_row.expr).get_identifier()); if (id.find(obj_id) != std::string::npos) { int loc = heap_domain.get_symbol_loc(templ_row.expr); @@ -298,19 +281,23 @@ int strategy_solver_heapt::find_member_row(const exprt &obj, const irep_idt &mem * @param value Heap value * @return True if any change occured */ -bool strategy_solver_heapt::update_rows_rec(const heap_domaint::rowt &row, - heap_domaint::heap_valuet &value) +bool strategy_solver_heapt::update_rows_rec( + const heap_domaint::rowt &row, + heap_domaint::heap_valuet &value) { + heap_domaint::heap_row_valuet &row_value = + static_cast(value[row]); + const heap_domaint::template_rowt &templ_row = heap_domain.templ[row]; + updated_rows.insert(row); bool result = false; - heap_domaint::template_rowt &templ_row = heap_domain.templ[row]; - for (auto &ptr : value[row].pointed_by) + for (auto &ptr : row_value.pointed_by) { - if (heap_domain.add_all_paths(ptr, row, value, - std::make_pair(templ_row.dyn_obj, templ_row.expr))) + if (heap_domain.add_transitivity(ptr, row, value)) result = true; debug() << "recursively updating row: " << ptr << eom; - debug() << "add all paths: " << from_expr(ns, "", templ_row.expr) << ", through: " + debug() << "add all paths: " << from_expr(ns, "", templ_row.expr) + << ", through: " << from_expr(ns, "", templ_row.dyn_obj) << eom; // Recursive update is called for each row only once if (updated_rows.find(ptr) == updated_rows.end()) @@ -321,12 +308,14 @@ bool strategy_solver_heapt::update_rows_rec(const heap_domaint::rowt &row, void strategy_solver_heapt::print_solver_expr(const exprt &expr) { - debug() << from_expr(ns, "", expr) << ": " << from_expr(ns, "", solver.get(expr)) << eom; + debug() << from_expr(ns, "", expr) << ": " + << from_expr(ns, "", solver.get(expr)) << eom; forall_operands(it, expr) print_solver_expr(*it); } -void strategy_solver_heapt::initialize(const local_SSAt &SSA, const exprt &precondition) +void strategy_solver_heapt::initialize( + const local_SSAt &SSA, const exprt &precondition) { // Create preconditions for input variables if not exist exprt::operandst equs; @@ -338,7 +327,8 @@ void strategy_solver_heapt::initialize(const local_SSAt &SSA, const exprt &preco solver << conjunction(equs); } -bool strategy_solver_heapt::has_precondition_rec(const exprt &expr, const exprt &precondition) +bool strategy_solver_heapt::has_precondition_rec( + const exprt &expr, const exprt &precondition) { if (precondition.id() == ID_equal) { @@ -354,8 +344,10 @@ bool strategy_solver_heapt::has_precondition_rec(const exprt &expr, const exprt } } -void strategy_solver_heapt::create_precondition(const symbol_exprt &var, const exprt &precondition, - exprt::operandst &equs) +void strategy_solver_heapt::create_precondition( + const symbol_exprt &var, + const exprt &precondition, + exprt::operandst &equs) { if (var.type().id() == ID_pointer && id2string(var.get_identifier()).find('.') == std::string::npos) From 59294494cbb6168ef7f3bc184a2fa05701983ea7 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 30 Jan 2017 16:11:11 +0100 Subject: [PATCH 039/322] assignments: function call assigns objects pointed by arguments --- src/ssa/assignments.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index 7ff61824f..ff508e032 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -91,8 +91,11 @@ void assignmentst::build_assignment_map( exprt arg_ptr = arg; do { + // Dereference argument in next location (to include potential new objects after + // the function call) + auto n_it = it; ++n_it; arg_ptr = dereference(dereference_exprt(arg_ptr, arg_ptr.type().subtype()), - ssa_value_ai[it], "", ns); + ssa_value_ai[n_it], "", ns); assign(arg_ptr, it, ns); } while (arg_ptr.type().id() == ID_pointer); From 7d197320a59f6c7c34b50d6ddec1cfbb05f425b6 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 30 Jan 2017 16:16:23 +0100 Subject: [PATCH 040/322] Value analysis: improve handling function calls. Potential new objects pointed by argument are added to previous value set. Objects pointed by return value are handled in function call (even if the assignment of the return value is in the next location). --- src/ssa/ssa_value_set.cpp | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/ssa/ssa_value_set.cpp b/src/ssa/ssa_value_set.cpp index c57ea8023..28f4ab86a 100644 --- a/src/ssa/ssa_value_set.cpp +++ b/src/ssa/ssa_value_set.cpp @@ -87,7 +87,7 @@ void ssa_value_domaint::transform( pointed_type); pointed_obj.type().set("#dynamic", true); - assign_lhs_rec(arg, address_of_exprt(pointed_obj), ns); + assign_lhs_rec(arg, address_of_exprt(pointed_obj), ns, true); arg = pointed_obj; } @@ -104,6 +104,25 @@ void ssa_value_domaint::transform( exprt lhs_deref=dereference(code_function_call.lhs(), *this, "", ns); assign_lhs_rec(lhs_deref, nil_exprt(), ns); } + + // the assignment of return value might be in next instruction + if (to->is_assign() && to_code_assign(to->code).rhs().id() == ID_symbol) + { + const symbol_exprt &return_value = to_symbol_expr(to_code_assign(to->code).rhs()); + if (return_value.type().id() == ID_pointer && + return_value.get_identifier() == + id2string(to_symbol_expr(code_function_call.function()).get_identifier()) + + "#return_value") + { + const typet &pointed_type = ns.follow(return_value.type().subtype()); + symbol_exprt pointed_obj = symbol_exprt( + id2string(return_value.get_identifier()) + "'obj", + pointed_type); + pointed_obj.type().set("#dynamic", true); + + assign_lhs_rec(return_value, address_of_exprt(pointed_obj), ns); + } + } } else if(from->is_dead()) { @@ -161,23 +180,6 @@ void ssa_value_domaint::assign_lhs_rec( return; // done } - // if rhs is a return value of pointer type, it points to a dynamic object - if(rhs.id()==ID_symbol && - rhs.type().id()==ID_pointer && - id2string(to_symbol_expr(rhs).get_identifier()).find("#return_value")!= - std::string::npos && - id2string(to_symbol_expr(rhs).get_identifier())!="malloc#return_value") - { - // Pointer typed return value of some function points to some dynamic object - const typet &pointed_type=ns.follow(rhs.type().subtype()); - symbol_exprt pointed_obj=symbol_exprt( - id2string(to_symbol_expr(rhs).get_identifier())+"'obj", - pointed_type); - pointed_obj.type().set("#dynamic", true); - - assign_lhs_rec(rhs, address_of_exprt(pointed_obj), ns); - } - // object? ssa_objectt ssa_object(lhs, ns); From 30c450e630863df417fb9fb6f42ce25dc46c5368 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 30 Jan 2017 16:20:38 +0100 Subject: [PATCH 041/322] Collect objects pointed by function call arguments for calling context template. --- .../template_generator_callingcontext.cpp | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/domains/template_generator_callingcontext.cpp b/src/domains/template_generator_callingcontext.cpp index 310ea4303..966beff3f 100644 --- a/src/domains/template_generator_callingcontext.cpp +++ b/src/domains/template_generator_callingcontext.cpp @@ -112,7 +112,49 @@ void template_generator_callingcontextt::collect_variables_callingcontext( a_it!=f_it->arguments().end(); a_it++) { std::set args; - find_symbols(*a_it, args); + find_symbols(*a_it,args); + + exprt arg=*a_it; + + // add objects pointed by arguments + while(arg.type().id()==ID_pointer) + { + if(arg.id()==ID_symbol) + { // remove SSA suffix (for querying value analysis) + const std::string id=id2string(to_symbol_expr(arg).get_identifier()); + to_symbol_expr(arg).set_identifier(id.substr(0, id.find_last_of('#'))); + } + // query value analysis + exprt deref_arg=SSA.dereference( + dereference_exprt(arg, arg.type().subtype()), n_it->location); + debug() << "Argument " << from_expr(SSA.ns, "", arg) << " deref: " + << from_expr(SSA.ns, "", deref_arg) << eom; + + // Find all symbols in dereferenced expression and add them to var_specs + std::set vars; + find_symbols(deref_arg, vars); + + for(auto &var : vars) + { + if(var.type().id()==ID_struct) + { + // need to split the struct into members + for (auto &component : to_struct_type(var.type()).components()) + { + const symbol_exprt member( + id2string(var.get_identifier())+"."+id2string(component.get_name()), + component.type()); + + args.insert(to_symbol_expr(SSA.read_rhs(member, n_it->location))); + } + } + else + args.insert(to_symbol_expr(SSA.read_rhs(var, n_it->location))); + } + + arg=deref_arg; + } + add_vars(args, guard, guard, domaint::OUT, var_specs); } } From f9ce64d25c6b8ef2219f13c833f7692203f6c520 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 30 Jan 2017 16:24:57 +0100 Subject: [PATCH 042/322] SSA inliner: rename to callee -- rename objects not present in globals in to non-suffixed versions. --- src/ssa/ssa_inliner.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index 3c47ab741..a2304d0ab 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -919,9 +919,11 @@ void ssa_inlinert::rename_to_callee( warning() << "'" << it->get_identifier() << "' not bound in caller" << eom; #endif - replace_map[*it]= - symbol_exprt( - id2string(it->get_identifier())+"@"+i2string(++counter), it->type()); + // rename objects not present in globals in to non-suffix version + symbol_exprt to_replace(get_original_identifier(*it), it->type()); + replace_map[*it]=to_replace; + // to propagate #dynamic flag on type + replace_map[to_replace]=to_replace; } } From 26e0cea0b7e95434123fdcd708672d2200c441d8 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 30 Jan 2017 16:48:49 +0100 Subject: [PATCH 043/322] Heap analysis: introduce list advancers into SSA. Initialization of value analysis -- insert advancers. Modify adding to value sets -- advancers require special treatment. Address of advancer is replaced by a symbol. Distinguish situation when advancer abstracts all list elements and all elements but the first one. --- src/ssa/address_canonizer.cpp | 9 ++ src/ssa/local_ssa.cpp | 15 +++ src/ssa/ssa_object.cpp | 6 +- src/ssa/ssa_object.h | 5 + src/ssa/ssa_value_set.cpp | 189 ++++++++++++++++++++++++++++++++-- src/ssa/ssa_value_set.h | 14 ++- 6 files changed, 229 insertions(+), 9 deletions(-) diff --git a/src/ssa/address_canonizer.cpp b/src/ssa/address_canonizer.cpp index 466139299..a17585679 100644 --- a/src/ssa/address_canonizer.cpp +++ b/src/ssa/address_canonizer.cpp @@ -81,6 +81,15 @@ exprt address_canonizer( return sum; } + else if (object.id() == ID_symbol && + id2string(to_symbol_expr(object).get_identifier()).find("'adv") != std::string::npos) + { + // address of advancer is dereferenced to a corresponding symbol - will be bound to real + // address during analysis + symbol_exprt advancer_addr(id2string(to_symbol_expr(object).get_identifier()) + "'addr", + address.type()); + return advancer_addr; + } else return address; } diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 45af83a02..f65d70e34 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -1284,6 +1284,21 @@ void local_SSAt::assign_rec( return; } + if (lhs.id() == ID_member && to_member_expr(lhs).compound().get_bool("#advancer") && + to_member_expr(lhs).compound().get_bool("#except_first")) + { // if an advancer instance is assigned and it does not cover first element, create + // non-deterministic case split since not all list elements are assigned here + exprt lhs_copy = lhs; + to_member_expr(lhs_copy).compound().set("#except_first", false); + if_exprt advancer_split(name(guard_symbol(), LOOP_SELECT, loc), lhs_copy, + symbol_exprt("", lhs_copy.type()) + + ); + assign_rec(advancer_split, rhs, guard, loc); + + return; + } + ssa_objectt lhs_object(lhs, ns); const std::set &assigned= diff --git a/src/ssa/ssa_object.cpp b/src/ssa/ssa_object.cpp index 0db5acd5d..1f7bf3a62 100644 --- a/src/ssa/ssa_object.cpp +++ b/src/ssa/ssa_object.cpp @@ -71,6 +71,10 @@ void collect_ptr_objects( const typet &pointed_type=src.type().subtype(); symbol_exprt ptr_object(identifier, pointed_type); + const symbolt *symbol; + if (!ns.lookup(src.get_identifier(), symbol) && !symbol->is_procedure_local()) + ptr_object.type().set("#dynamic", true); + if(is_ptr_object(src)) ptr_object.set(ID_ptr_object, src.get(ID_ptr_object)); else @@ -183,7 +187,7 @@ void collect_objects_rec( if(type.id()==ID_struct) { std::string id=id2string(ssa_object.get_identifier()); - if (src.type().get_bool("#dynamic") || id.rfind("'obj")==id.size()-4) + if (src.type().get_bool("#dynamic") || is_ptr_object(src)) objects.insert(ssa_object); // need to split up diff --git a/src/ssa/ssa_object.h b/src/ssa/ssa_object.h index 5a16bcd6b..990b67641 100644 --- a/src/ssa/ssa_object.h +++ b/src/ssa/ssa_object.h @@ -90,6 +90,11 @@ class ssa_objectt return id_str.find("$unknown") != std::string::npos; } + inline void set_flag(const irep_idt flag, bool value) + { + expr.set(flag, value); + } + protected: exprt expr; identifiert identifier; diff --git a/src/ssa/ssa_value_set.cpp b/src/ssa/ssa_value_set.cpp index 28f4ab86a..773d4aba1 100644 --- a/src/ssa/ssa_value_set.cpp +++ b/src/ssa/ssa_value_set.cpp @@ -13,6 +13,7 @@ Author: Daniel Kroening, kroening@kroening.com #endif #include +#include #include "ssa_value_set.h" #include "ssa_dereference.h" @@ -183,7 +184,8 @@ void ssa_value_domaint::assign_lhs_rec( // object? ssa_objectt ssa_object(lhs, ns); - if(ssa_object) + if(ssa_object && + !(lhs.id()==ID_member && to_member_expr(lhs).compound().get_bool("#advancer"))) { valuest tmp_values; assign_rhs_rec(tmp_values, rhs, ns, false, 0); @@ -369,7 +371,7 @@ void ssa_value_domaint::assign_rhs_rec_address_of( if(ssa_object) { - dest.value_set.insert(ssa_object); + dest.add_to_value_set(ssa_object); if(offset) dest.offset=true; } @@ -500,10 +502,10 @@ bool ssa_value_domaint::valuest::merge(const valuest &src) } // value set - unsigned old_size=value_set.size(); - value_set.insert(src.value_set.begin(), src.value_set.end()); - if(old_size!=value_set.size()) - result=true; + for (const ssa_objectt &v : src.value_set) + { + result = add_to_value_set(v) || result; + } // alignment alignment=merge_alignment(alignment, src.alignment); @@ -561,3 +563,178 @@ bool ssa_value_domaint::merge( return result; } + +/*******************************************************************\ + +Function: ssa_value_domaint::valuest::add_to_value_set + + Inputs: SSA object to be added + + Outputs: True if 'this' has changed + + Purpose: Add given object to value set of this. + If value set contains both advancer (abstracts all elements + of the list except the first one) and object pointed by + advancer pointer (abstracts the first element of the list), + only advancer is preserved and #except_first is set to false. + +\*******************************************************************/ + +bool ssa_value_domaint::valuest::add_to_value_set(ssa_objectt object) +{ + if (value_set.find(object) == value_set.end()) + { + bool result = false; + if (object.get_expr().get_bool("#advancer")) + { // advancer is to be inserted - check if set already contains first object of corresponding + // list + const irep_idt corresp_object_id = object.get_expr().get("#object_id"); + + auto it = std::find_if(value_set.begin(), value_set.end(), + [&corresp_object_id](const ssa_objectt &o) + { + return o.get_identifier() == corresp_object_id; + }); + + if (it != value_set.end()) + { + value_set.erase(it); + object.set_flag("#except_first", false); + result = true; + } + } + else if (id2string(object.get_identifier()).find("'obj") != std::string::npos) + { // pointed object is to be inserted - check if set already contains corresponding advancer + const irep_idt object_id = object.get_identifier(); + + auto it = std::find_if(value_set.begin(), value_set.end(), + [&object_id](const ssa_objectt &o) + { + return id2string(o.get_identifier()).find(id2string(object_id)) != + std::string::npos && + id2string(o.get_identifier()).find("'adv") != + std::string::npos; + }); + + if (it != value_set.end()) + { + ssa_objectt new_advancer(*it); + new_advancer.set_flag("#except_first", false); + value_set.erase(it); + value_set.insert(new_advancer); + return false; + } + } + + auto inserted = value_set.insert(object); + return result || inserted.second; + } + return false; +} + +/*******************************************************************\ + +Function: ssa_value_ait::initialize + + Inputs: GOTO function + + Outputs: + + Purpose: Initialize value sets for pointer parameters and pointer-typed + fields of objects pointed by parameters. + +\*******************************************************************/ + +void ssa_value_ait::initialize(const goto_functionst::goto_functiont &goto_function) +{ + ait::initialize(goto_function); + + // Initialize value sets for pointer parameters + + if (!goto_function.type.parameters().empty()) + { + locationt e = goto_function.body.instructions.begin(); + ssa_value_domaint &entry = operator[](e); + + for (auto ¶m : goto_function.type.parameters()) + { + const symbol_exprt param_expr(param.get_identifier(), param.type()); + assign_ptr_param_rec(param_expr, entry); + } + + } +} + +/*******************************************************************\ + +Function: ssa_value_ait::assign_ptr_param_rec + + Inputs: Expression to be initialized and entry record of value set analysis + + Outputs: + + Purpose: Initialize value set for the given expression and recursively for all + structure members and all pointed objects. + Pointer-typed variable p initially points to abstract object p'obj. + Pointer-typed field of structure initially points to advancer. + +\*******************************************************************/ + +void ssa_value_ait::assign_ptr_param_rec(const exprt &expr, ssa_value_domaint &entry) +{ + const typet &type = ns.follow(expr.type()); + if (type.id() == ID_pointer) + { + if (expr.id() == ID_symbol) + { // pointer variable + const symbol_exprt pointed_expr(id2string(to_symbol_expr(expr).get_identifier()) + "'obj", + type.subtype()); + assign(expr, pointed_expr, entry); + assign_ptr_param_rec(pointed_expr, entry); + } + else if (expr.id() == ID_member) + { // pointer member of a structure + const member_exprt &member = to_member_expr(expr); + ssa_objectt member_obj(member, ns); + symbol_exprt member_dest(id2string(member_obj.get_identifier()) + "'adv", + type.subtype()); + member_dest.set("#advancer", true); + // intially advancer abstracts all list members except first + member_dest.set("#except_first", true); + assert(member.compound().id() == ID_symbol); + // set advancer object + member_dest.set("#object_id", to_symbol_expr(member.compound()).get_identifier()); + assign(expr, member_dest, entry); + } + } + else if (type.id() == ID_struct) + { // split structure into fields + for (auto &component : to_struct_type(type).components()) + { + const member_exprt member(expr, component.get_name(), component.type()); + assign_ptr_param_rec(member, entry); + } + } +} + +/*******************************************************************\ + +Function: ssa_value_ait::assign + + Inputs: Pointer variable src, pointed object dest and analysis entry. + + Outputs: + + Purpose: Insert object to value set of another object in the given entry. + +\*******************************************************************/ + +void ssa_value_ait::assign(const exprt &src, const exprt &dest, ssa_value_domaint &entry) +{ + ssa_objectt src_obj(src, ns); + ssa_objectt dest_obj(dest, ns); + if (src_obj && dest_obj) + { + entry.value_map[src_obj].value_set.insert(dest_obj); + } +} diff --git a/src/ssa/ssa_value_set.h b/src/ssa/ssa_value_set.h index 4e1f8afc1..c948ddeb8 100644 --- a/src/ssa/ssa_value_set.h +++ b/src/ssa/ssa_value_set.h @@ -42,6 +42,8 @@ class ssa_value_domaint:public ai_domain_baset bool merge(const valuest &src); + bool add_to_value_set(ssa_objectt object); + inline void clear() { *this=valuest(); @@ -100,12 +102,20 @@ class ssa_value_ait:public ait public: ssa_value_ait( const goto_functionst::goto_functiont &goto_function, - const namespacet &ns) + const namespacet &ns_) : ns(ns_) { - operator()(goto_function, ns); + operator()(goto_function, ns_); } protected: + virtual void initialize(const goto_functionst::goto_functiont &goto_function) override; + + void assign_ptr_param_rec(const exprt &expr, ssa_value_domaint &entry); + + void assign(const exprt &src, const exprt &dest, ssa_value_domaint &entry); + + const namespacet &ns; + friend class ssa_value_domaint; }; From 37aff500a4e4b8f378d4145b7dc56acec8c3bd06 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 30 Jan 2017 16:54:32 +0100 Subject: [PATCH 044/322] Heap domain: introduce self-linkage flag on heap template rows. Self linkage determines whether the heap object might contain self-loop. --- src/domains/heap_domain.cpp | 26 ++++++++++++++++++++------ src/domains/heap_domain.h | 4 ++++ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 6431059cb..4fbe28490 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -22,7 +22,7 @@ void heap_domaint::initialize(domaint::valuet &value) if (templ_row.mem_kind == STACK) val.emplace_back(new stack_row_valuet()); else if (templ_row.mem_kind == HEAP) - val.emplace_back(new heap_row_valuet()); + val.emplace_back(new heap_row_valuet(std::make_pair(templ_row.dyn_obj, templ_row.expr))); else assert(false); } @@ -194,9 +194,6 @@ bool heap_domaint::add_points_to(const heap_domaint::rowt &row, heap_domaint::he const exprt &dest) { assert(row < value.size()); - - if (templ[row].dyn_obj == dest) return false; - return value[row].add_points_to(dest); } @@ -385,7 +382,14 @@ exprt heap_domaint::heap_row_valuet::get_row_expr(const domaint::vart &templ_exp if (nondet) return true_exprt(); if (empty()) - return false_exprt(); + { + if (self_linkage) + { + return equal_exprt(templ_expr, address_of_exprt(dyn_obj.first)); + } + else + return false_exprt(); + } else { exprt::operandst result; @@ -424,7 +428,17 @@ exprt heap_domaint::heap_row_valuet::get_row_expr(const domaint::vart &templ_exp bool heap_domaint::heap_row_valuet::add_points_to(const exprt &dest) { - return add_path(dest, std::make_pair(nil_exprt(), nil_exprt())); + if (dest == dyn_obj.first) + { + bool changed = !self_linkage; + self_linkage = true; + return changed; + } + else + { + const dyn_objt through = self_linkage ? dyn_obj : std::make_pair(nil_exprt(), nil_exprt()); + return add_path(dest, through); + } } bool heap_domaint::heap_row_valuet::add_path(const exprt &dest, diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index ca6474ca0..7a47a7a3c 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -89,6 +89,10 @@ class heap_domaint:public domaint std::set paths; /**< Set o paths leading from the row variable */ std::set pointed_by; /**< Set of rows whose variables point to this row */ + dyn_objt dyn_obj; + bool self_linkage = false; + + heap_row_valuet(const dyn_objt &dyn_obj_) : dyn_obj(dyn_obj_) {} virtual exprt get_row_expr(const vart &templ_expr) const override; From 40e255124a86664f378eebc2f483218b6e5621ec Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 30 Jan 2017 17:22:52 +0100 Subject: [PATCH 045/322] Heap analysis: bind list advancers to actual heap objects. Advancers are determined from SSA, actual objects are determined from calling context. New template rows are inserted for objects whose corresponding advancer is written withing the function. --- src/domains/heap_domain.cpp | 5 + src/domains/heap_domain.h | 4 + src/domains/ssa_analyzer.cpp | 3 +- src/domains/strategy_solver_heap.cpp | 317 ++++++++++++++++++++++++++- src/domains/strategy_solver_heap.h | 86 +++++++- src/ssa/local_ssa.cpp | 15 ++ src/ssa/local_ssa.h | 2 + 7 files changed, 416 insertions(+), 16 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 4fbe28490..541d6440b 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -489,3 +489,8 @@ bool heap_domaint::heap_row_valuet::add_pointed_by(const rowt &row) auto new_pb = pointed_by.insert(row); return new_pb.second; } + +const std::list &heap_domaint::get_new_heap_vars() const +{ + return new_heap_row_vars; +} diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index 7a47a7a3c..d2f8fc940 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -167,9 +167,13 @@ class heap_domaint:public domaint // Join of values virtual void join(valuet &value1, const valuet &value2) override; + const std::list &get_new_heap_vars() const; + protected: templatet templ; + std::list new_heap_row_vars; + void make_template(const var_specst &var_specs, const namespacet &ns); void add_template_row(const var_spect &var_spec, const typet &pointed_type); diff --git a/src/domains/ssa_analyzer.cpp b/src/domains/ssa_analyzer.cpp index 68d178e62..74b75e736 100644 --- a/src/domains/ssa_analyzer.cpp +++ b/src/domains/ssa_analyzer.cpp @@ -107,7 +107,8 @@ void ssa_analyzert::operator()( else if(template_generator.options.get_bool_option("heap")) { strategy_solver=new strategy_solver_heapt( - *static_cast(domain), solver, SSA, precondition); + *static_cast(domain), + solver, SSA, precondition, get_message_handler(), template_generator); result=new heap_domaint::heap_valuet(); } else diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index dad13badc..1eab5615b 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -315,35 +315,76 @@ void strategy_solver_heapt::print_solver_expr(const exprt &expr) } void strategy_solver_heapt::initialize( - const local_SSAt &SSA, const exprt &precondition) + const local_SSAt &SSA, + const exprt &precondition, + template_generator_baset &template_generator) { + // Bind list advancers + bind_advancers(SSA, precondition, template_generator); + // Create preconditions for input variables if not exist exprt::operandst equs; for (auto ¶m : SSA.params) create_precondition(param, precondition, equs); for (auto &global_in : SSA.globals_in) create_precondition(global_in, precondition, equs); - - solver << conjunction(equs); + if (!equs.empty()) + solver << conjunction(equs); } -bool strategy_solver_heapt::has_precondition_rec( - const exprt &expr, const exprt &precondition) +/*******************************************************************\ + +Function: strategy_solver_heapt::collect_preconditions_rec + + Inputs: Expression and calling context (precondition) + + Outputs: Set of preconditions corresponding to given expression. + + Purpose: Recursively find all preconditions for the given expression + in the calling context. + Returns right-hand sides of equalities where expr is left-hand + side. + +\*******************************************************************/ + +std::set strategy_solver_heapt::collect_preconditions_rec( + const exprt &expr, + const exprt &precondition) { + std::set result; if (precondition.id() == ID_equal) { const equal_exprt &eq = to_equal_expr(precondition); - return (eq.lhs() == expr && eq.rhs() != expr); + if (eq.lhs() == expr && eq.rhs() != expr) + { + result.insert(eq.rhs()); + } } else { - bool result = false; forall_operands(it, precondition) - result = result || has_precondition_rec(expr, *it); - return result; + { + std::set op_result = collect_preconditions_rec(expr, *it); + result.insert(op_result.begin(), op_result.end()); + } } + return result; } +/*******************************************************************\ + +Function: strategy_solver_heapt::create_precondition + + Inputs: Variable, calling context (precondition) and reference to + bindings list. + + Outputs: + + Purpose: Create precondition for given variable at the input of the + function if it does not exist in given calling context. + +\*******************************************************************/ + void strategy_solver_heapt::create_precondition( const symbol_exprt &var, const exprt &precondition, @@ -352,7 +393,8 @@ void strategy_solver_heapt::create_precondition( if (var.type().id() == ID_pointer && id2string(var.get_identifier()).find('.') == std::string::npos) { - if (!has_precondition_rec(var, precondition)) + auto pre = collect_preconditions_rec(var, precondition); + if (pre.empty()) { debug() << "Creating precondition for pointer parameters" << eom; const symbolt *symbol; @@ -364,3 +406,258 @@ void strategy_solver_heapt::create_precondition( } } } + +/*******************************************************************\ + +Function: strategy_solver_heapt::collect_advancers + + Inputs: SSA + + Outputs: + + Purpose: Collect all advancers and their instances in the given SSA + +\*******************************************************************/ + +void strategy_solver_heapt::collect_advancers(const local_SSAt &SSA) +{ + for (const symbol_exprt &global : SSA.globals_in) + { + if (global.type().id() == ID_pointer && + id2string(global.get_identifier()).find('.') != std::string::npos) + { // Get all pointer-typed fields of input structure objects + const typet &pointed_type = ns.follow(global.type().subtype()); + if (pointed_type.id() == ID_struct) + { + // Split pointer'obj.member into pointer and member + const std::string id = id2string(global.get_identifier()); + const irep_idt member = id.substr(id.find_last_of('.') + 1); + const irep_idt pointer_id = id.substr(0, id.rfind("'obj." + id2string(member))); + // Find the corresponding pointer (must be in global objects or parameters) + symbol_exprt pointer(""); + for (const symbol_exprt ¶m : SSA.params) + { + if (param.get_identifier() == pointer_id) + { + pointer = param; + break; + } + } + if (pointer.get_identifier() == "") + { + for (const symbol_exprt &global_other : SSA.globals_in) + { + if (global_other.get_identifier() == pointer_id) + { + pointer = global_other; + break; + } + } + } + assert(pointer.get_identifier() != ""); + + // Create advancer + advancers.emplace_back(pointer, member); + advancert &advancer = advancers.back(); + + // Collect advancer instances + for (auto &component : to_struct_type(pointed_type).components()) + { + const irep_idt &component_name = component.get_name(); + // Read-access advancer instance + advancer.add_instance(component_name, IN_LOC); + + // Find all write-accesses and create corresponding advancer instances + ssa_objectt instance_obj(advancer.instance_symbol_expr(component_name, IN_LOC), SSA.ns); + std::list written_locs = SSA.all_assignment_locs(instance_obj); + for (unsigned loc : written_locs) + { + advancer.add_instance(component_name, loc); + } + } + } + } + } +} + +/*******************************************************************\ + +Function: strategy_solver_heapt::reachable_objects + + Inputs: List advancer, function call calling context represented by + precondition. + + Outputs: Set of reachable objects + + Purpose: Find all objects reachable from advancer pointer via advancer + field in the given precondition. + +\*******************************************************************/ + +std::set strategy_solver_heapt::reachable_objects( + const advancert &advancer, + const exprt &precondition) +{ + std::set result; + + // Collect all addresses pointed by advancer pointer (from stack template rows of the + // calling context) + std::set pointed_objs = collect_preconditions_rec(advancer.pointer, precondition); + for (const exprt &pointed : pointed_objs) + { + if (pointed.id() == ID_address_of) + { + const exprt &pointed_obj = to_address_of_expr(pointed).object(); + assert(pointed_obj.id() == ID_symbol); + + // Create obj.member + symbol_exprt obj_member = recursive_member_symbol(to_symbol_expr(pointed_obj), + advancer.member, IN_LOC); + obj_member.type() = advancer.pointer.type(); + + // Collect all reachable objects (from heap rows of the calling context) + std::set reachable_objs = collect_preconditions_rec(obj_member, precondition); + for (const exprt &reachable : reachable_objs) + { + if (reachable.id() == ID_address_of) + { + const exprt &reachable_obj = to_address_of_expr(reachable).object(); + assert(reachable_obj.id() == ID_symbol); + + result.insert(to_symbol_expr(reachable_obj)); + } + } + } + } + + return result; +} + +/*******************************************************************\ + +Function: strategy_solver_heapt::bind_advancers + + Inputs: SSA, calling context represented by precondition and reference + to template generator + + Outputs: + + Purpose: Bind advancers from SSA to actual heap objects from the + calling context. + +\*******************************************************************/ + +void strategy_solver_heapt::bind_advancers( + const local_SSAt &SSA, const exprt &precondition, + template_generator_baset &template_generator) +{ + collect_advancers(SSA); + + for (const advancert &advancer : advancers) + { + exprt::operandst reachable_bindings; + + std::set reachable_objs = reachable_objects(advancer, precondition); + + exprt::operandst adv_bindings; + for (const symbol_exprt &reachable : reachable_objs) + { + // Bind address of advancer (represented by symbol) with &(reachable) + address_of_exprt reachable_addr = address_of_exprt(reachable); + reachable_addr.object().type().set("#dynamic", true); + adv_bindings.push_back(equal_exprt( + symbol_exprt(id2string(advancer.symbol_expr().get_identifier()) + "'addr", + advancer.pointer.type()), + reachable_addr)); + + // Bind reachable.m with advancer instance + for (auto &instance: advancer.instances) + { + for (const int &instance_loc : instance.second) + { + adv_bindings.push_back(equal_exprt( + recursive_member_symbol(reachable, instance.first, instance_loc), + advancer.instance_symbol_expr(instance.first, instance_loc) + )); + } + } + reachable_bindings.push_back(conjunction(adv_bindings)); + + // Create new template rows for output write instances + for (const std::pair &instance : advancer.output_instances()) + { + new_output_template_row(SSA, + recursive_member_symbol(reachable, instance.first, instance.second), + template_generator); + } + } + + if (!reachable_bindings.empty()) + { + advancer_bindings = disjunction(reachable_bindings); + debug() << "Advancers bindings:" << eom; + debug() << from_expr(SSA.ns, "", advancer_bindings) << eom; + solver << advancer_bindings; + + debug() << "Template after advancer binding:" << eom; + heap_domain.output_domain(debug(), SSA.ns); + } + } +} + +/*******************************************************************\ + +Function: strategy_solver_heapt::recursive_member_symbol + + Inputs: Structure-typed object, name of its member and a location number. + + Outputs: Corresponding symbol: + object.member#loc, or object.memer if loc is input + + Purpose: + +\*******************************************************************/ + +const symbol_exprt strategy_solver_heapt::recursive_member_symbol( + const symbol_exprt &object, + const irep_idt &member, + const int loc_num) +{ + std::string suffix = loc_num != IN_LOC ? ("#" + std::to_string(loc_num)) : ""; + return symbol_exprt(id2string(object.get_identifier()) + "." + id2string(member) + suffix, + pointer_typet(object.type())); +} + +/*******************************************************************\ + +Function: strategy_solver_heapt::new_output_template_row + + Inputs: SSA, new row variable and the template generator + + Outputs: + + Purpose: Insert new output template row into the template. + +\*******************************************************************/ + +void strategy_solver_heapt::new_output_template_row( + const local_SSAt &SSA, + const symbol_exprt &var, + template_generator_baset &template_generator) +{ + exprt guard = SSA.guard_symbol(--SSA.goto_function.body.instructions.end()); + + template_generator.var_specs.push_back(domaint::var_spect()); + domaint::var_spect &var_spec = template_generator.var_specs.back(); + + var_spec.var = var; + var_spec.pre_guard = guard; + var_spec.post_guard = guard; + var_spec.aux_expr = true_exprt(); + var_spec.kind = domaint::OUT; + + assert(var.type().id() == ID_pointer); + const typet &pointed_type = ns.follow(var.type().subtype()); + heap_domain.add_template_row(var_spec, pointed_type); + heap_domain.new_heap_row_vars.push_back(var); +} diff --git a/src/domains/strategy_solver_heap.h b/src/domains/strategy_solver_heap.h index c048dda04..72871c7ea 100644 --- a/src/domains/strategy_solver_heap.h +++ b/src/domains/strategy_solver_heap.h @@ -8,25 +8,85 @@ #include "../ssa/local_ssa.h" #include "strategy_solver_base.h" #include "heap_domain.h" +#include "template_generator_base.h" class strategy_solver_heapt : public strategy_solver_baset { public: explicit strategy_solver_heapt(heap_domaint &_heap_domain, incremental_solvert &_solver, - const local_SSAt &SSA, const exprt &precondition) + const local_SSAt &SSA, const exprt &precondition, + message_handlert &message_handler, + template_generator_baset &template_generator) : strategy_solver_baset(_solver, SSA.ns), heap_domain(_heap_domain) { - initialize(SSA, precondition); + set_message_handler(message_handler); + initialize(SSA, precondition, template_generator); } virtual bool iterate(invariantt &_inv) override; - void initialize(const local_SSAt &SSA, const exprt &precondition); + void initialize(const local_SSAt &SSA, const exprt &precondition, + template_generator_baset &template_generator); protected: + + class advancert + { + public: + symbol_exprt pointer; + irep_idt member; + + std::map > instances; + + advancert(const symbol_exprt &pointer_, const irep_idt &member_) + : pointer(pointer_), member(member_) {} + + bool operator<(const advancert &rhs) const + { + return std::tie(pointer, member) < std::tie(rhs.pointer, rhs.member); + } + + void add_instance(const irep_idt &member, const int location_number) + { + instances[member].insert(location_number); + } + + const symbol_exprt symbol_expr() const + { + return symbol_exprt( + id2string(pointer.get_identifier()) + "'obj." + id2string(member) + "'adv", + pointer.type().subtype()); + } + + const symbol_exprt instance_symbol_expr(const irep_idt &member, const int location_number) const + { + return recursive_member_symbol(symbol_expr(), member, location_number); + } + + const std::list> output_instances() const + { + std::list> result; + + // Find instance with maximal location number + for (auto &instance : instances) + { + int max_loc = *(--(instance.second.end())); + if (max_loc >= 0) + result.emplace_back(instance.first, max_loc); + } + + return result; + } + }; + + static const int IN_LOC = -1; + heap_domaint &heap_domain; std::set updated_rows; + std::list advancers; + exprt advancer_bindings; + int find_member_row(const exprt &obj, const irep_idt &member, int actual_loc, const domaint::kindt &kind); @@ -34,10 +94,26 @@ class strategy_solver_heapt : public strategy_solver_baset void print_solver_expr(const exprt &expr); - void create_precondition(const symbol_exprt &var, const exprt &precondition, + void create_precondition(const symbol_exprt &var, + const exprt &precondition, exprt::operandst &equs); - bool has_precondition_rec(const exprt &expr, const exprt &precondition); + void bind_advancers(const local_SSAt &SSA, const exprt &precondition, + template_generator_baset &template_generator); + + void collect_advancers(const local_SSAt &SSA); + + void new_output_template_row(const local_SSAt &SSA, const symbol_exprt &var, + template_generator_baset &template_generator); + + static std::set reachable_objects(const advancert &advancer, + const exprt &precondition); + + static std::set collect_preconditions_rec(const exprt &expr, const exprt &precondition); + + static const symbol_exprt recursive_member_symbol(const symbol_exprt &object, + const irep_idt &member, + const int loc_num); }; diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index f65d70e34..fc07209a5 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -1844,3 +1844,18 @@ exprt local_SSAt::unknown_obj_eq(const symbol_exprt &obj, const symbol_exprt member(identifier, component.type()); return equal_exprt(member, address_of_exprt(obj)); } + +std::list local_SSAt::all_assignment_locs(const ssa_objectt &object) const +{ + std::list result; + + forall_goto_program_instructions(it, goto_function.body) + { + if (assignments.assigns(it, object)) + { + result.push_back(it->location_number); + } + } + + return result; +} diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 38914d95a..e26032cec 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -166,6 +166,8 @@ class local_SSAt void assign_rec( const exprt &lhs, const exprt &rhs, const exprt &guard, locationt loc); + std::list all_assignment_locs(const ssa_objectt &object) const; + exprt unknown_obj_eq(const symbol_exprt &obj, const struct_typet::componentt &component) const; void get_entry_exit_vars(); From 5e3a1547a40df49d351e6ea0970b44ed98426bd6 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 30 Jan 2017 17:26:26 +0100 Subject: [PATCH 046/322] Heap analysis: update output heap objects based on new template rows created during analysis. --- src/domains/ssa_analyzer.cpp | 7 +++++++ src/domains/ssa_analyzer.h | 3 +++ src/solver/summarizer_fw.cpp | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/src/domains/ssa_analyzer.cpp b/src/domains/ssa_analyzer.cpp index 74b75e736..a3668b692 100644 --- a/src/domains/ssa_analyzer.cpp +++ b/src/domains/ssa_analyzer.cpp @@ -168,3 +168,10 @@ void ssa_analyzert::get_result(exprt &_result, const domaint::var_sett &vars) { domain->project_on_vars(*result, vars, _result); } + +void ssa_analyzert::update_heap_out(summaryt::var_sett &out) +{ + heap_domaint &heap_domain = static_cast(*domain); + + out.insert(heap_domain.get_new_heap_vars().begin(), heap_domain.get_new_heap_vars().end()); +} diff --git a/src/domains/ssa_analyzer.h b/src/domains/ssa_analyzer.h index 1758f4711..1792b9682 100644 --- a/src/domains/ssa_analyzer.h +++ b/src/domains/ssa_analyzer.h @@ -11,6 +11,7 @@ Author: Peter Schrammel #include +#include #include #include "strategy_solver_base.h" @@ -43,6 +44,8 @@ class ssa_analyzert:public messaget void get_result(exprt &result, const domaint::var_sett &vars); + void update_heap_out(summaryt::var_sett &out); + inline unsigned get_number_of_solver_instances() { return solver_instances; } inline unsigned get_number_of_solver_calls() { return solver_calls; } diff --git a/src/solver/summarizer_fw.cpp b/src/solver/summarizer_fw.cpp index 1048a2b0f..c0b1d4883 100644 --- a/src/solver/summarizer_fw.cpp +++ b/src/solver/summarizer_fw.cpp @@ -179,6 +179,11 @@ void summarizer_fwt::do_summary( implies_exprt(summary.fw_precondition, summary.fw_invariant); } + if (options.get_bool_option("heap")) + { + analyzer.update_heap_out(summary.globals_out); + } + solver_instances+=analyzer.get_number_of_solver_instances(); solver_calls+=analyzer.get_number_of_solver_calls(); } From 1632bbec5209514908920a3e59f06e004e56c972 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 30 Jan 2017 17:51:41 +0100 Subject: [PATCH 047/322] Heap analysis: improve binding objects pointed by arguments and return value between caller and callee. Handle binding when callee works with advancers. Algorithms require value analysis of the called function - store in summary. --- src/solver/summarizer_fw.cpp | 1 + src/solver/summary.cpp | 20 ++ src/solver/summary.h | 4 +- src/ssa/ssa_inliner.cpp | 661 ++++++++++++++++++++++++----------- src/ssa/ssa_inliner.h | 65 +++- 5 files changed, 537 insertions(+), 214 deletions(-) diff --git a/src/solver/summarizer_fw.cpp b/src/solver/summarizer_fw.cpp index c0b1d4883..397b3d2b4 100644 --- a/src/solver/summarizer_fw.cpp +++ b/src/solver/summarizer_fw.cpp @@ -71,6 +71,7 @@ void summarizer_fwt::compute_summary_rec( summary.params=SSA.params; summary.globals_in=SSA.globals_in; summary.globals_out=SSA.globals_out; + summary.set_value_domains(SSA); summary.fw_precondition=precondition; if(!options.get_bool_option("havoc")) diff --git a/src/solver/summary.cpp b/src/solver/summary.cpp index 3a74ba628..ffa76f7ae 100644 --- a/src/solver/summary.cpp +++ b/src/solver/summary.cpp @@ -173,6 +173,26 @@ void summaryt::join(const summaryt &new_summary) /*******************************************************************\ +Function: summaryt::set_value_domains + + Inputs: + + Outputs: + + Purpose: Get value domain for last location from SSA. + +\*******************************************************************/ + +void summaryt::set_value_domains(const local_SSAt &SSA) +{ + const local_SSAt::locationt &entry_loc=SSA.nodes.begin()->location; + const local_SSAt::locationt &exit_loc=(--SSA.nodes.end())->location; + value_domain_in=SSA.ssa_value_ai[entry_loc]; + value_domain_out=SSA.ssa_value_ai[exit_loc]; +} + +/*******************************************************************\ + Function: threeval2string Inputs: diff --git a/src/solver/summary.h b/src/solver/summary.h index 0141d4bd4..3ee24a666 100644 --- a/src/solver/summary.h +++ b/src/solver/summary.h @@ -39,7 +39,7 @@ class summaryt var_listt params; var_sett globals_in, globals_out; - ssa_value_domaint value_domain; + ssa_value_domaint value_domain_in, value_domain_out; 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) @@ -59,7 +59,7 @@ class summaryt void join(const summaryt &new_summary); - void set_value_domain(const local_SSAt &SSA); + void set_value_domains(const local_SSAt &SSA); protected: void combine_or(exprt &olde, const exprt &newe); diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index a2304d0ab..e7d649ecf 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -63,13 +63,14 @@ void ssa_inlinert::get_summary( std::cout << std::endl; #endif - // equalities for arguments + //equalities for arguments bindings.push_back(get_replace_params( summary.params, *f_it, - summary.globals_in, - summary.globals_out, + cs_globals_in, + cs_globals_out, SSA, + summary, loc)); // equalities for globals_in @@ -91,16 +92,16 @@ void ssa_inlinert::get_summary( summary.bw_transformer; } rename(transformer); - summaries.push_back( - implies_exprt(SSA.guard_symbol(n_it->location), 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( - cs_globals_in, cs_globals_out, summary, *f_it, *n_it, SSA.ns)); + cs_globals_in, cs_globals_out, summary, *f_it, SSA, loc)); else bindings.push_back(get_replace_globals_out( - cs_globals_out, cs_globals_in, summary, *f_it, *n_it, SSA.ns)); + cs_globals_out, cs_globals_in, summary, *f_it, SSA, loc)); } /*******************************************************************\ @@ -421,20 +422,24 @@ exprt ssa_inlinert::get_replace_globals_in( for(summaryt::var_sett::const_iterator it=globals_in.begin(); it!=globals_in.end(); it++) { - symbol_exprt lhs=*it; // copy - rename(lhs); - symbol_exprt rhs; - if(find_corresponding_symbol(*it, globals, rhs)) + // bind only real globals - filter out heap objects + if(id2string(it->get_identifier()).find("'obj")==std::string::npos) { - debug() << "binding: " << lhs.get_identifier() << "==" - << rhs.get_identifier() << eom; - c.push_back(equal_exprt(lhs, rhs)); - } + symbol_exprt lhs=*it; // copy + rename(lhs); + symbol_exprt rhs; + if(find_corresponding_symbol(*it, globals, rhs)) + { + debug() << "binding: " << lhs.get_identifier() << " == " + << rhs.get_identifier() << eom; + c.push_back(equal_exprt(lhs, rhs)); + } #if 0 - else - warning() << "'" << it->get_identifier() - << "' not bound in caller" << eom; + else + warning() << "'" << it->get_identifier() + << "' not bound in caller" << eom; #endif + } } return conjunction(c); } @@ -491,9 +496,10 @@ Function: ssa_inlinert::get_replace_params exprt ssa_inlinert::get_replace_params( const local_SSAt::var_listt ¶ms, const function_application_exprt &funapp_expr, - const local_SSAt::var_sett &globals_in, - 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 &SSA, + const summaryt &summary, const local_SSAt::locationt &loc) { // equalities for arguments @@ -503,57 +509,165 @@ exprt ssa_inlinert::get_replace_params( it!=funapp_expr.arguments().end(); it++, p_it++) { 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 + if (funapp_expr.arguments().size()!=params.size() && + ++next_p_it==params.end()) // TODO: handle ellipsis { warning() << "ignoring excess function arguments" << eom; break; } - exprt lhs=*p_it; // copy + exprt param=*p_it; // copy + exprt arg=*it; // copy + + exprt lhs=param; rename(lhs); - c.push_back(equal_exprt(lhs, *it)); - - // For pointer parameters create equalities between pointed object passed as global and - // corresponding object in caller - if (p_it->type().id() == ID_pointer) { - // Find corresponding objects in caller's objects (separately for entry and exit) - exprt pointed_ssa_sym_in; - exprt pointed_ssa_sym_out; - for (equal_exprt equal : SSA.find_node(loc)->equalities) - { // search through equalities with argument value - if (equal.rhs().id() == ID_symbol && - to_symbol_expr(equal.rhs()).get_identifier() == to_symbol_expr(*it).get_identifier()) + // bind parameter <-> argument + c.push_back(equal_exprt(lhs, arg)); + + typet arg_type=SSA.ns.follow(arg.type()); + + // Bind objects pointed by parameter/argument pair + std::list args_in={arg}; + std::list args_out={arg}; + std::list params_in={param}; + std::list params_out={param}; + while(arg_type.id()==ID_pointer) + { + std::list args_deref_in=apply_dereference(args_in, SSA.ssa_value_ai[loc], SSA.ns); + std::list params_deref_in=apply_dereference(params_in, summary.value_domain_in, SSA.ns); + + local_SSAt::locationt next_loc=loc; ++next_loc; + std::list args_deref_out=apply_dereference(args_out, SSA.ssa_value_ai[next_loc], SSA.ns); + std::list params_deref_out=apply_dereference(params_out, summary.value_domain_out, SSA.ns); + + if(contains_advancer(params_deref_out)) + { + // If the caller contains advancers, bindings are different since objects from caller will + // appear in the callee summary + assert(!args_deref_in.empty() && !args_deref_out.empty()); + arg_type=SSA.ns.follow(args_deref_in.begin()->type()); + + assert(arg_type.id()==ID_struct); + + for (const exprt &a : args_deref_in) { - exprt arg_pointed = dereference(equal.lhs(), SSA.ssa_value_ai[loc], "", SSA.ns); - if (arg_pointed.id() == ID_address_of) + // Bind argument address + address_of_exprt lhs_addr=address_of_exprt(a); + rename(lhs_addr); + + address_of_exprt rhs_addr=address_of_exprt(a); + typet symbol_type=args_out.begin()->type().subtype(); + symbol_type.set("#dynamic", params_deref_out.begin()->type().get_bool("#dynamic")); + rhs_addr.object().type()=symbol_type; + + c.push_back(equal_exprt(lhs_addr, rhs_addr)); + + for (auto &component : to_struct_type(arg_type).components()) { - arg_pointed = to_address_of_expr(arg_pointed).object(); + // Bind argument members at the input + symbol_exprt arg_member( + id2string(to_symbol_expr(a).get_identifier())+"."+ + id2string(component.get_name()), component.type()); + + symbol_exprt member_lhs_in=arg_member; + rename(member_lhs_in); + + c.push_back(equal_exprt(member_lhs_in, SSA.read_rhs(arg_member, loc))); + + // Bind argument members at the output + symbol_exprt member_lhs_out; + if(find_corresponding_symbol(arg_member, summary.globals_out, member_lhs_out)) + { + rename(member_lhs_out); + } + else + { + // If the argument member is not in globals out, it was not assigned by the function + // and is not changed by the call + assert(find_corresponding_symbol(arg_member, cs_globals_in, member_lhs_out)); + } + + c.push_back(equal_exprt( + member_lhs_out, + SSA.name(ssa_objectt(arg_member, SSA.ns), local_SSAt::OUT, loc))); + } + } + + for (const exprt &a : args_deref_out) + { + for (auto &component : to_struct_type(arg_type).components()) + { + // Bind argument members at the output (args_deref_out might contain different objects + // than args_deref_in since function call may create new objects). + symbol_exprt arg_member(id2string(to_symbol_expr(a).get_identifier()) + "." + + id2string(component.get_name()), component.type()); + + symbol_exprt member_lhs_out; + if (find_corresponding_symbol(arg_member, summary.globals_out, member_lhs_out)) + { + rename(member_lhs_out); + } + else + { + assert(find_corresponding_symbol(arg_member, cs_globals_in, member_lhs_out)); + } + + c.push_back(equal_exprt(member_lhs_out, + SSA.name(ssa_objectt(arg_member, SSA.ns), + local_SSAt::OUT, + loc))); } - ssa_objectt pointed_ssa_obj(arg_pointed, SSA.ns); - // get correct SSA symbol for function call entry - pointed_ssa_sym_in = SSA.read_rhs(pointed_ssa_obj, loc); - // get correct SSA symbol for function call exit - pointed_ssa_sym_out = SSA.name(pointed_ssa_obj, local_SSAt::OUT, loc); } } + else + { // Bind objects pointed by argument and parameter when advancer is not present + if (!args_deref_in.empty()) + { + arg_type = SSA.ns.follow(args_deref_in.begin()->type()); - // Find globals containing pointed object and create equalities - irep_idt global_id = id2string(to_symbol_expr(*p_it).get_identifier())+"'obj"; - symbol_exprt expr_to_find(global_id, p_it->type().subtype()); + bind(transform_pointed_params_in(params_deref_in), + transform_pointed_args_in(args_deref_in, SSA, loc), + c); - // Entry global - symbol_exprt global_in; - if(find_corresponding_symbol(expr_to_find,globals_in,global_in)) { - rename(global_in); - c.push_back(equal_exprt(global_in,pointed_ssa_sym_in)); - } - // Exit global - symbol_exprt global_out; - if(find_corresponding_symbol(expr_to_find,globals_out,global_out)) { - rename(global_out); - c.push_back(equal_exprt(global_out, pointed_ssa_sym_out)); + if (arg_type.id() == ID_struct) + { + for (auto &component : to_struct_type(arg_type).components()) + { + bind(transform_pointed_member_params_in(params_deref_in, component), + transform_pointed_member_args_in(args_deref_in, component, SSA, loc), + c); + } + } + } + + if (!args_deref_out.empty()) + { + arg_type = SSA.ns.follow(args_deref_out.begin()->type()); + + bind(transform_pointed_params_out(params_deref_out, summary.globals_out, arg_type), + transform_pointed_args_out(args_deref_out, args_out.begin()->type().subtype(), + params_deref_out.begin()->type(), SSA, loc), + c); + + if (arg_type.id() == ID_struct) + { + for (auto &component : to_struct_type(arg_type).components()) + { + bind(transform_pointed_member_params_out(params_deref_out, component, + summary.globals_out), + transform_pointed_member_args_out(args_deref_out, component, SSA, loc), + c); + } + } + } } + + args_in = args_deref_in; + args_out = args_deref_out; + params_in = params_deref_in; + params_out = params_deref_out; + + if (args_in.empty() && args_out.empty()) break; } } return conjunction(c); @@ -611,91 +725,90 @@ exprt ssa_inlinert::get_replace_globals_out( const local_SSAt::var_sett &cs_globals_out, const summaryt &summary, const function_application_exprt &funapp_expr, - const local_SSAt::nodet &ssa_node, - const namespacet &ns) + const local_SSAt &SSA, + const local_SSAt::locationt &loc) { // equalities for globals_out exprt::operandst c; - for(summaryt::var_sett::const_iterator it=cs_globals_out.begin(); - it!=cs_globals_out.end(); it++) + const irep_idt &ret_val_id= + id2string(to_symbol_expr(funapp_expr.function()).get_identifier()) + "#return_value"; + for (summaryt::var_sett::const_iterator it=cs_globals_out.begin(); + it!=cs_globals_out.end(); it++) { symbol_exprt lhs; exprt rhs; - if(id2string(it->get_identifier()).find("'obj")!=std::string::npos && - it->get_identifier()!=get_original_identifier(*it)) - { - // variable is heap object (contains 'obj) and is assigned by the call - const irep_idt &id=get_original_identifier(*it); - if(is_struct_member(id)) - { - // variable is member of dynamic struct - const std::string member=id2string(id).substr(id2string(id).find_last_of(".")); - const irep_idt &root_id=id2string(id).substr(0, id2string(id).find_last_of(".")); - // find root object (must be in global variables) - symbol_exprt root_object; - for(auto &global : cs_globals_out) - { - if(get_original_identifier(global)==root_id) - root_object=global; - } - // find corresponding dynamic object in called function - symbol_exprt dynamic_object; - if (!find_corresponding_dyn_obj(root_object, summary, funapp_expr, ssa_node, ns, - dynamic_object)) - { // if corresponding dynamic object does not exist, the global is not changed - rhs = *it; // copy - assert(find_corresponding_symbol(*it, cs_globals_in, lhs)); - c.push_back(equal_exprt(lhs, rhs)); - continue; - } + if(get_original_identifier(*it)==ret_val_id) + { + // Bind function return value + rhs=*it; // copy + assert(find_corresponding_symbol(*it, summary.globals_out, lhs)); + rename(lhs); + c.push_back(equal_exprt(lhs, rhs)); - // restore member expression - dynamic_object.set_identifier(id2string(dynamic_object.get_identifier()) + member); - dynamic_object.type()=it->type(); + typet type=SSA.ns.follow(rhs.type()); - assert(find_corresponding_symbol(dynamic_object, summary.globals_out, lhs)); - rename(lhs); + std::list callee_rv={*it}; + std::list caller_rv={*it}; - rhs=*it; // copy - } - else - { // variable is dynamic object - // find corresponding dynamic object in called function - symbol_exprt dynamic_object; - if (!find_corresponding_dyn_obj(*it, summary, funapp_expr, ssa_node, ns, dynamic_object)) - { // if corresponding dynamic object does not exist, the global is not changed - rhs = *it; // copy - assert(find_corresponding_symbol(*it, cs_globals_in, lhs)); - c.push_back(equal_exprt(lhs, rhs)); - continue; - } + // Bind all objects pointed by return value + while(type.id()==ID_pointer) + { + local_SSAt::locationt next_loc=loc; ++next_loc; + std::list caller_rv_deref= + apply_dereference(caller_rv, SSA.ssa_value_ai[next_loc], SSA.ns); + std::list callee_rv_deref= + apply_dereference(callee_rv, summary.value_domain_out, SSA.ns); - // equality is between addresses of corresponding dynamic objects - exprt addr=address_of_exprt(dynamic_object); - rename(addr); - assert(addr.id()==ID_symbol); + if(!callee_rv_deref.empty()) + { + type=SSA.ns.follow(callee_rv_deref.begin()->type()); + bind(transform_pointed_params_out( + callee_rv_deref, summary.globals_out, type), + transform_pointed_args_out( + caller_rv_deref, + caller_rv.begin()->type().subtype(), + callee_rv_deref.begin()->type(), + SSA, + loc), + c); + + if(type.id()==ID_struct) + { + for(auto &component : to_struct_type(type).components()) + { + bind(transform_pointed_member_params_out( + callee_rv_deref, component, summary.globals_out), + transform_pointed_member_args_out( + caller_rv_deref, component, SSA, loc), + c); + } + } + } - lhs=to_symbol_expr(addr); + callee_rv=callee_rv_deref; + caller_rv=caller_rv_deref; - typet orig_type = it->type(); - orig_type.set("#dynamic", dynamic_object.type().get_bool("#dynamic")); - symbol_exprt orig_obj(id, orig_type); - rhs=address_of_exprt(orig_obj); + if(caller_rv.empty()) + break; } } else { - rhs=*it; // copy - if (find_corresponding_symbol(*it, summary.globals_out, lhs)) - rename(lhs); - else - assert(find_corresponding_symbol(*it, cs_globals_in, lhs)); + if(id2string(it->get_identifier()).find("dynamic_object$")==std::string::npos && + id2string(it->get_identifier()).find("'obj")==std::string::npos) + { + rhs=*it; // copy + if(find_corresponding_symbol(*it, summary.globals_out, lhs)) + rename(lhs); + else + assert(find_corresponding_symbol(*it, cs_globals_in, lhs)); + c.push_back(equal_exprt(lhs, rhs)); + } } - c.push_back(equal_exprt(lhs,rhs)); } - return conjunction (c); + return conjunction(c); } /*******************************************************************\ @@ -1058,102 +1171,250 @@ irep_idt ssa_inlinert::get_original_identifier(const symbol_exprt &s) return id; } -/** - * Test if variable is member of struct. - * @param identifier Id of variable - * @return - */ -bool ssa_inlinert::is_struct_member(const irep_idt &identifier) +/*******************************************************************\ + +Function: ssa_inlinert::apply_dereference + + Inputs: Set of pointers and value analysis + + Outputs: Set of all objects that can be pointed by one of pointers + from the input set. + + Purpose: + +\*******************************************************************/ + +std::list ssa_inlinert::apply_dereference( + const std::list &exprs, + const ssa_value_domaint &value_domain, + const namespacet &ns) { - const std::string id = id2string(identifier); - return id.find(".") != std::string::npos && - id.find_first_of("#$@'%!", id.find_last_of(".")) == std::string::npos; + std::list result; + for(const exprt &expr : exprs) + { + if(expr.id()==ID_symbol || expr.id()==ID_address_of) + { + exprt to_query=expr; // copy + if(expr.id()==ID_symbol) + { + to_symbol_expr(to_query).set_identifier(get_original_identifier(to_symbol_expr(expr))); + } + ssa_value_domaint::valuest values=value_domain(to_query, ns); + for(auto &v : values.value_set) + { + result.push_back(v.symbol_expr()); + } + } + else + { + assert(false); + } + } + return result; } -/** - * Find corresponding dynamic object in called function. - * Takes pointer to s (by stripping away 'obj suffix) and querys called function value set (stored - * in summary of that function). - * @param s Call site dynamic object - * @param summary Called function summary - * @param ns Namespace - * @param found_sym Found symbol - * @return True if an object was found, otherwise false. - */ -bool ssa_inlinert::find_corresponding_dyn_obj(const symbol_exprt &s, - const summaryt &summary, - const function_application_exprt &funapp_expr, - const local_SSAt::nodet &ssa_node, - const namespacet &ns, - symbol_exprt &found_sym) +/*******************************************************************\ + +Function: ssa_inlinert::bind + + Inputs: Two sets of objects + + Outputs: + + Purpose: Create bindings between pairs of objects from given sets. + +\*******************************************************************/ + +void ssa_inlinert::bind( + const std::list &lhs, + const std::list &rhs, + exprt::operandst &bindings) { - irep_idt id = get_original_identifier(s); - const std::string &id_str = id2string(s.get_identifier()); - id = id_str.substr(0, id_str.rfind("'obj")); + exprt::operandst new_bind; + for(const exprt &l : lhs) + { + for(const exprt &r : rhs) + { + new_bind.push_back(equal_exprt(l, r)); + } + } + if(!new_bind.empty()) + bindings.push_back(disjunction(new_bind)); +} + +std::list ssa_inlinert::transform_pointed_params_in(const std::list ¶ms_in) +{ + std::list result; + for(const exprt &p : params_in) + { + symbol_exprt param_in=to_symbol_expr(p); + rename(param_in); + result.push_back(param_in); + } + return result; +} + +std::list ssa_inlinert::transform_pointed_args_in( + const std::list &args_in, + const local_SSAt &SSA, + local_SSAt::locationt loc) +{ + std::list result; + for(const exprt &a : args_in) + { + result.push_back(SSA.read_rhs(a, loc)); + } + return result; +} - if (id2string(id).find("#return_value") == std::string::npos) +std::list ssa_inlinert::transform_pointed_member_params_in( + const std::list ¶ms_in, + const struct_union_typet::componentt &component) +{ + std::list result; + for(const exprt &p : params_in) + { + symbol_exprt param_member( + id2string(to_symbol_expr(p).get_identifier())+"."+ + id2string(component.get_name()), component.type()); + rename(param_member); + result.push_back(param_member); + } + return result; +} + +std::list ssa_inlinert::transform_pointed_member_args_in( + const std::list &args_in, + const struct_union_typet::componentt &component, + const local_SSAt &SSA, + local_SSAt::locationt loc) +{ + std::list result; + for(const exprt &a : args_in) + { + symbol_exprt arg_member( + id2string(to_symbol_expr(a).get_identifier())+"."+ + id2string(component.get_name()), component.type()); + result.push_back(SSA.read_rhs(arg_member, loc)); + } + return result; +} + +std::list ssa_inlinert::transform_pointed_params_out( + const std::list ¶ms_out, + const local_SSAt::var_sett &globals_out, + const typet ¶m_type) +{ + std::list result; + for(const exprt &p : params_out) { - auto p_it = summary.params.begin(); - bool found = false; - for (auto arg_it = funapp_expr.arguments().begin(); arg_it != funapp_expr.arguments().end(); - ++arg_it, ++p_it) + symbol_exprt param_out; + if (find_corresponding_symbol(to_symbol_expr(p), globals_out, param_out)) { - exprt arg = nil_exprt(); - for (auto &eq : ssa_node.equalities) + if (param_type.id()==ID_struct) { - if (eq.rhs() == *arg_it) - arg = eq.lhs(); + address_of_exprt param_addr=address_of_exprt(p); + rename(param_addr); + result.push_back(param_addr); } - assert(arg.is_not_nil()); - - symbol_exprt param = *p_it; - while (arg.type().id() == ID_pointer) + else { - if (arg.id() == ID_symbol) - { - if (to_symbol_expr(arg).get_identifier() == id) - { - found = true; - break; - } - else - { - // arg --> arg'obj - symbol_exprt &arg_sym = to_symbol_expr(arg); - arg_sym.set_identifier(id2string(arg_sym.get_identifier()) + "'obj"); - arg_sym.type() = arg_sym.type().subtype(); + rename(param_out); + result.push_back(param_out); + } + } + } + return result; +} - // param --> param'obj - assert(param.type().id() == ID_pointer); - param.set_identifier(id2string(param.get_identifier()) + "'obj"); - param.type() = param.type().subtype(); +std::list ssa_inlinert::transform_pointed_args_out( + const std::list &args_out, + const typet &arg_symbol_type, + const typet ¶m_type, + const local_SSAt &SSA, + local_SSAt::locationt loc) +{ + std::list result; - } - } - else if (arg.id() == ID_address_of) - { - // &arg --> arg - arg = to_address_of_expr(arg).object(); + const typet &arg_type=SSA.ns.follow(arg_symbol_type); + for(const exprt &a : args_out) + { + if(arg_type.id()==ID_struct) + { + address_of_exprt arg_addr=address_of_exprt(a); + typet symbol_type=arg_symbol_type; + symbol_type.set("#dynamic", param_type.get_bool("#dynamic")); + arg_addr.object().type()=symbol_type; + result.push_back(arg_addr); + } + else + { + result.push_back(SSA.name(ssa_objectt(a, SSA.ns), local_SSAt::OUT, loc)); + } + } + return result; +} - // param --> param'obj - assert(param.type().id() == ID_pointer); - param.set_identifier(id2string(param.get_identifier()) + "'obj"); - param.type() = param.type().subtype(); - } - } - if (found) - id = param.get_identifier(); +std::list ssa_inlinert::transform_pointed_member_params_out( + const std::list ¶ms_out, + const struct_union_typet::componentt &component, + const local_SSAt::var_sett &globals_out) +{ + std::list result; + for(const exprt &p : params_out) + { + symbol_exprt param_member( + id2string(to_symbol_expr(p).get_identifier())+"."+ + id2string(component.get_name()), component.type()); + symbol_exprt param_out; + if(find_corresponding_symbol(param_member, globals_out, param_out)) + { + rename(param_out); + result.push_back(param_out); } - assert(found); } + return result; +} - auto &values = summary.value_domain(symbol_exprt(id, pointer_typet(s.type())), ns); - if (values.value_set.size() == 1) +std::list ssa_inlinert::transform_pointed_member_args_out( + const std::list &args_out, + const struct_union_typet::componentt &component, + const local_SSAt &SSA, + local_SSAt::locationt loc) +{ + std::list result; + for(const exprt &a : args_out) { - found_sym = values.value_set.begin()->symbol_expr(); - return true; + symbol_exprt arg_member( + id2string(to_symbol_expr(a).get_identifier()) + "." + + id2string(component.get_name()), component.type()); + result.push_back(SSA.name(ssa_objectt(arg_member, SSA.ns), local_SSAt::OUT, loc)); } + return result; +} + +/*******************************************************************\ + +Function: ssa_inlinert::contains_advancer + Inputs: List of expressions + + Outputs: True if the list contains an advancer + + Purpose: + +\*******************************************************************/ + +bool ssa_inlinert::contains_advancer(const std::list ¶ms) +{ + for(const exprt &p : params) + { + if(p.id()==ID_symbol && + id2string(to_symbol_expr(p).get_identifier()).find("'adv") != std::string::npos) + { + return true; + } + } return false; } diff --git a/src/ssa/ssa_inliner.h b/src/ssa/ssa_inliner.h index 9a2a9d4f9..4b098084b 100644 --- a/src/ssa/ssa_inliner.h +++ b/src/ssa/ssa_inliner.h @@ -103,16 +103,11 @@ class ssa_inlinert:public messaget const local_SSAt::var_sett &globals, symbol_exprt &s_found); - static bool find_corresponding_dyn_obj(const symbol_exprt &s, - const summaryt &summary, - const function_application_exprt &funapp_expr, - const local_SSAt::nodet &ssa_node, - const namespacet &ns, - symbol_exprt &found_sym); - static irep_idt get_original_identifier(const symbol_exprt &s); - static bool is_struct_member(const irep_idt &identifier); + static std::list apply_dereference(const std::list &exprs, + const ssa_value_domaint &value_domain, + const namespacet &ns); protected: unsigned counter; @@ -139,20 +134,66 @@ class ssa_inlinert:public messaget exprt get_replace_params( const local_SSAt::var_listt ¶ms, const function_application_exprt &funapp_expr, - const local_SSAt::var_sett &globals_in, - 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 &SSA, + const summaryt &summary, const local_SSAt::locationt &loc); exprt get_replace_globals_out( const local_SSAt::var_sett &cs_globals_in, const local_SSAt::var_sett &cs_globals_out, const summaryt &summary, const function_application_exprt &funapp_expr, - const local_SSAt::nodet &ssa_node, - const namespacet &ns); + const local_SSAt &SSA, + const local_SSAt::locationt &loc); void rename(exprt &expr); void rename(local_SSAt::nodet &node); + static void bind( + const std::list &lhs, + const std::list &rhs, + exprt::operandst &bindings); + + // Transformation functions for lists of input/output arguments/pointers (or their members) + // for binding purposes + + std::list transform_pointed_params_in( + const std::list ¶ms_in); + std::list transform_pointed_args_in( + const std::list &args_in, + const local_SSAt &SSA, + local_SSAt::locationt loc); + + std::list transform_pointed_member_params_in( + const std::list ¶ms_in, + const struct_union_typet::componentt &component); + + std::list transform_pointed_member_args_in( + const std::list &args_in, + const struct_union_typet::componentt &component, + const local_SSAt &SSA, + local_SSAt::locationt loc); + std::list transform_pointed_params_out( + const std::list ¶ms_out, + const local_SSAt::var_sett &globals_out, + const typet ¶m_type); + std::list transform_pointed_args_out( + const std::list &args_out, + const typet &arg_symbol_type, + const typet ¶m_type, + const local_SSAt &SSA, + local_SSAt::locationt loc); + std::list transform_pointed_member_params_out( + const std::list ¶ms_out, + const struct_union_typet::componentt &component, + const local_SSAt::var_sett &globals_out); + std::list transform_pointed_member_args_out( + const std::list &args_out, + const struct_union_typet::componentt &component, + const local_SSAt &SSA, + local_SSAt::locationt loc); + + static bool contains_advancer(const std::list ¶ms); }; #endif From 3b3572ab0c2532aa9464296a133dff9f1f21a6f8 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 30 Jan 2017 17:54:35 +0100 Subject: [PATCH 048/322] Remove canonizing addresses of first member of a structure. Problem was resolved by correct typing -- address_of_exprt is always typed as pointed to symbol type (instead of pointer to actual type). --- src/domains/strategy_solver_heap.cpp | 6 ++---- src/ssa/address_canonizer.cpp | 30 +++++++++++----------------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index 1eab5615b..c2fc325cd 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -5,7 +5,6 @@ //#define DEBUG_OUTPUT #include "strategy_solver_heap.h" -#include "../ssa/address_canonizer.h" bool strategy_solver_heapt::iterate(invariantt &_inv) { @@ -125,10 +124,9 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) debug() << from_expr(ns, "", ptr_value) << eom; assert(ptr_value.id() == ID_address_of); // Canonize address - const exprt address = address_canonizer(ptr_value, ns); - assert(to_address_of_expr(address).object().id() == ID_symbol); + assert(to_address_of_expr(ptr_value).object().id() == ID_symbol); - symbol_exprt obj=to_symbol_expr(to_address_of_expr(address).object()); + symbol_exprt obj=to_symbol_expr(to_address_of_expr(ptr_value).object()); // Add equality p == &obj if (heap_domain.add_points_to(row, inv, obj)) diff --git a/src/ssa/address_canonizer.cpp b/src/ssa/address_canonizer.cpp index a17585679..29bcea9bb 100644 --- a/src/ssa/address_canonizer.cpp +++ b/src/ssa/address_canonizer.cpp @@ -47,24 +47,18 @@ exprt address_canonizer( // get offset exprt offset=member_offset_expr(to_member_expr(object), ns); - if (offset.id()==ID_constant && to_constant_expr(offset).is_zero()) - { - return address_of_exprt(to_member_expr(object).compound()); - } - else - { - // &x.m ---> (&x)+offset - - address_of_exprt address_of_expr(to_member_expr(object).struct_op()); - exprt rec_result=address_canonizer(address_of_expr, ns); // rec. call - - pointer_typet byte_pointer(unsigned_char_type()); - typecast_exprt typecast_expr(rec_result, byte_pointer); - plus_exprt sum(typecast_expr, offset); - if (sum.type()!=address.type()) sum.make_typecast(address.type()); - - return sum; - } + // &x.m ---> (&x)+offset + + address_of_exprt address_of_expr(to_member_expr(object).struct_op()); + exprt rec_result=address_canonizer(address_of_expr, ns); // rec. call + + pointer_typet byte_pointer(unsigned_char_type()); + typecast_exprt typecast_expr(rec_result, byte_pointer); + plus_exprt sum(typecast_expr, offset); + if(sum.type()!=address.type()) + sum.make_typecast(address.type()); + + return sum; } else if(object.id()==ID_index) { From 57def4013f52284703e69ac49781f251db940d98 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 31 Jan 2017 10:29:10 +0100 Subject: [PATCH 049/322] Heap analysis inlininig: remove duplicity from advancer binding. --- src/ssa/ssa_inliner.cpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index e7d649ecf..b04ed4b7d 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -573,23 +573,6 @@ exprt ssa_inlinert::get_replace_params( rename(member_lhs_in); c.push_back(equal_exprt(member_lhs_in, SSA.read_rhs(arg_member, loc))); - - // Bind argument members at the output - symbol_exprt member_lhs_out; - if(find_corresponding_symbol(arg_member, summary.globals_out, member_lhs_out)) - { - rename(member_lhs_out); - } - else - { - // If the argument member is not in globals out, it was not assigned by the function - // and is not changed by the call - assert(find_corresponding_symbol(arg_member, cs_globals_in, member_lhs_out)); - } - - c.push_back(equal_exprt( - member_lhs_out, - SSA.name(ssa_objectt(arg_member, SSA.ns), local_SSAt::OUT, loc))); } } From 57e1d11f7248c83415745a8c5217a58bea8914af Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 31 Jan 2017 12:17:54 +0100 Subject: [PATCH 050/322] SSA assignments: function only assigns those dirty locals that have been declared before. --- src/ssa/assignments.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index ff508e032..ecb0bc684 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -56,7 +56,16 @@ void assignmentst::build_assignment_map( for(objectst::const_iterator o_it=ssa_objects.dirty_locals.begin(); o_it!=ssa_objects.dirty_locals.end(); o_it++) - assign(*o_it, it, ns); + { + bool declared = false; + forall_goto_program_instructions(other_it, goto_program) + { + if (it == other_it) break; + if (assigns(other_it, *o_it)) declared = true; + } + if (declared) + assign(*o_it, it, ns); + } for(objectst::const_iterator o_it=ssa_objects.globals.begin(); From cea4d39d8a54a28634d40f9032f946b1a5664fb6 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 2 Feb 2017 10:39:18 +0100 Subject: [PATCH 051/322] Heap domain: add self linkage to actual and any new path. --- src/domains/heap_domain.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 541d6440b..46a074ecc 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -432,6 +432,11 @@ bool heap_domaint::heap_row_valuet::add_points_to(const exprt &dest) { bool changed = !self_linkage; self_linkage = true; + for (auto &path : paths) + { + if (add_path(path.destination, dyn_obj)) + changed = true; + } return changed; } else @@ -452,6 +457,10 @@ bool heap_domaint::heap_row_valuet::add_path(const exprt &dest, { // Path doesn't have zero length dyn_obj_set.insert(dyn_obj); } + if (self_linkage) + { + dyn_obj_set.insert(this->dyn_obj); + } paths.emplace(dest, dyn_obj_set); return true; } From b18ae6d7feeb2092c5143a2859e649249aa8eb11 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 9 Feb 2017 10:35:13 +0100 Subject: [PATCH 052/322] Heap analysis: improve finding row corresponding to dynamic object in strategy solver. --- src/domains/strategy_solver_heap.cpp | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index c2fc325cd..df7c3cb1c 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -146,23 +146,9 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) // Find row with corresponding member field // of pointed object (obj.member) int member_val_index; - if (inv[row].empty() && templ_row.dyn_obj.id() != ID_nil && - heap_domain.get_base_name(obj) == - heap_domain.get_base_name(templ_row.dyn_obj)) - { // for the same object find previous instance - // (used for multiple loops in one function) - member_val_index=find_member_row( - obj, templ_row.member, --actual_loc, templ_row.kind); - if (member_val_index < 0) - member_val_index = find_member_row( - obj, templ_row.member, ++actual_loc, templ_row.kind); - } - else - { - member_val_index=find_member_row( - obj, templ_row.member, actual_loc, templ_row.kind); - } - assert(member_val_index >= 0); + member_val_index=find_member_row( + obj, templ_row.member, actual_loc, templ_row.kind); + assert(member_val_index>=0); // Add all paths from obj.next to p if(heap_domain.add_transitivity( @@ -262,7 +248,7 @@ int strategy_solver_heapt::find_member_row( if (id.find(obj_id) != std::string::npos) { int loc = heap_domain.get_symbol_loc(templ_row.expr); - if (loc <= actual_loc && loc > max_loc) + if (loc > max_loc && (kind == domaint::OUT || loc <= actual_loc)) { max_loc = loc; result = i; From e27c030973e8e15ca72208b3784da7a12ec8b9af Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 9 Feb 2017 10:36:22 +0100 Subject: [PATCH 053/322] SSA inliner: better inlining of pointed objects and advancers. Add dependency between input and output argument/parameter pairs. --- src/ssa/ssa_inliner.cpp | 410 ++++++++++++++++++---------------------- src/ssa/ssa_inliner.h | 53 +++--- 2 files changed, 213 insertions(+), 250 deletions(-) diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index b04ed4b7d..08f0b0309 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -6,6 +6,8 @@ Author: Peter Schrammel \*******************************************************************/ +#include + #include #include @@ -531,6 +533,8 @@ exprt ssa_inlinert::get_replace_params( std::list args_out={arg}; std::list params_in={param}; std::list params_out={param}; + + exprt new_arg_out=arg; while(arg_type.id()==ID_pointer) { std::list args_deref_in=apply_dereference(args_in, SSA.ssa_value_ai[loc], SSA.ns); @@ -540,6 +544,11 @@ exprt ssa_inlinert::get_replace_params( std::list args_deref_out=apply_dereference(args_out, SSA.ssa_value_ai[next_loc], SSA.ns); std::list params_deref_out=apply_dereference(params_out, summary.value_domain_out, SSA.ns); + const typet arg_symbol_type = arg_type.subtype(); + arg_type = SSA.ns.follow(arg_symbol_type); + + new_arg_out = new_pointed_arg(new_arg_out, arg_type, args_deref_out); + if(contains_advancer(params_deref_out)) { // If the caller contains advancers, bindings are different since objects from caller will @@ -552,27 +561,17 @@ exprt ssa_inlinert::get_replace_params( for (const exprt &a : args_deref_in) { // Bind argument address - address_of_exprt lhs_addr=address_of_exprt(a); - rename(lhs_addr); - - address_of_exprt rhs_addr=address_of_exprt(a); - typet symbol_type=args_out.begin()->type().subtype(); - symbol_type.set("#dynamic", params_deref_out.begin()->type().get_bool("#dynamic")); - rhs_addr.object().type()=symbol_type; - - c.push_back(equal_exprt(lhs_addr, rhs_addr)); + c.push_back(equal_exprt( + param_out_transformer(a, arg_type, summary.globals_out), + arg_out_transformer(a, arg_symbol_type, params_deref_out.begin()->type(), SSA, loc))); for (auto &component : to_struct_type(arg_type).components()) { // Bind argument members at the input - symbol_exprt arg_member( - id2string(to_symbol_expr(a).get_identifier())+"."+ - id2string(component.get_name()), component.type()); - - symbol_exprt member_lhs_in=arg_member; - rename(member_lhs_in); - - c.push_back(equal_exprt(member_lhs_in, SSA.read_rhs(arg_member, loc))); + c.push_back(equal_exprt( + param_in_member_transformer(a, component), + arg_in_member_transformer(a, component, SSA, loc) + )); } } @@ -596,53 +595,75 @@ exprt ssa_inlinert::get_replace_params( } c.push_back(equal_exprt(member_lhs_out, - SSA.name(ssa_objectt(arg_member, SSA.ns), - local_SSAt::OUT, - loc))); + arg_out_member_transformer(a, component, SSA, loc))); } } } else { // Bind objects pointed by argument and parameter when advancer is not present - if (!args_deref_in.empty()) - { - arg_type = SSA.ns.follow(args_deref_in.begin()->type()); + assert(params_deref_in.size() == 1); + const exprt &p_in = params_deref_in.front(); - bind(transform_pointed_params_in(params_deref_in), - transform_pointed_args_in(args_deref_in, SSA, loc), - c); - - if (arg_type.id() == ID_struct) + exprt::operandst d; + for (const exprt &p_out : params_deref_out) + { + for (const exprt &a_out : args_deref_out) { - for (auto &component : to_struct_type(arg_type).components()) + exprt::operandst binding; + if (std::find(args_deref_in.begin(), args_deref_in.end(), a_out) != args_deref_in.end()) { - bind(transform_pointed_member_params_in(params_deref_in, component), - transform_pointed_member_args_in(args_deref_in, component, SSA, loc), - c); + binding.push_back(equal_exprt( + param_in_transformer(p_in), + arg_in_transformer(a_out, SSA, loc))); } - } - } - if (!args_deref_out.empty()) - { - arg_type = SSA.ns.follow(args_deref_out.begin()->type()); + const exprt &arg_out = p_out == p_in ? a_out : new_arg_out; + binding.push_back(equal_exprt( + param_out_transformer(p_out, arg_type, summary.globals_out), + arg_out_transformer(arg_out, arg_symbol_type, p_out.type(), SSA, loc))); - bind(transform_pointed_params_out(params_deref_out, summary.globals_out, arg_type), - transform_pointed_args_out(args_deref_out, args_out.begin()->type().subtype(), - params_deref_out.begin()->type(), SSA, loc), - c); + if (arg_type.id() == ID_struct) + { + for (auto &component : to_struct_type(arg_type).components()) + { + if (std::find(args_deref_in.begin(), args_deref_in.end(), a_out) != args_deref_in.end()) + { + binding.push_back(equal_exprt( + param_in_member_transformer(p_in, component), + arg_in_member_transformer(a_out, component, SSA, loc))); + } + + binding.push_back(equal_exprt( + param_out_member_transformer(p_out, component, summary.globals_out), + arg_out_member_transformer(arg_out, component, SSA, loc))); + } + } - if (arg_type.id() == ID_struct) - { - for (auto &component : to_struct_type(arg_type).components()) + for (const exprt &a_out_other : args_deref_out) { - bind(transform_pointed_member_params_out(params_deref_out, component, - summary.globals_out), - transform_pointed_member_args_out(args_deref_out, component, SSA, loc), - c); + if (a_out_other != arg_out) + { + if (arg_type.id() == ID_struct) + { + for (auto &component : to_struct_type(arg_type).components()) + { + binding.push_back(equal_exprt( + arg_out_member_transformer(a_out_other, component, SSA, loc), + arg_in_member_transformer(a_out_other, component, SSA, loc))); + } + } + else + { + binding.push_back(equal_exprt( + arg_out_transformer(a_out_other, arg_symbol_type, arg_type, SSA, loc), + arg_in_transformer(a_out_other, SSA, loc))); + } + } } + d.push_back(conjunction(binding)); } } + c.push_back(disjunction(d)); } args_in = args_deref_in; @@ -746,28 +767,34 @@ exprt ssa_inlinert::get_replace_globals_out( if(!callee_rv_deref.empty()) { - type=SSA.ns.follow(callee_rv_deref.begin()->type()); - bind(transform_pointed_params_out( - callee_rv_deref, summary.globals_out, type), - transform_pointed_args_out( - caller_rv_deref, - caller_rv.begin()->type().subtype(), - callee_rv_deref.begin()->type(), - SSA, - loc), - c); - - if(type.id()==ID_struct) + const typet symbol_type=type.subtype(); + type=SSA.ns.follow(symbol_type); + + exprt::operandst d; + for(const exprt &callee : callee_rv_deref) { - for(auto &component : to_struct_type(type).components()) + for(const exprt &caller : caller_rv_deref) { - bind(transform_pointed_member_params_out( - callee_rv_deref, component, summary.globals_out), - transform_pointed_member_args_out( - caller_rv_deref, component, SSA, loc), - c); + exprt::operandst binding; + binding.push_back(equal_exprt( + param_out_transformer(callee, type, summary.globals_out), + arg_out_transformer(caller, symbol_type, callee.type(), SSA, loc))); + + if(type.id()==ID_struct) + { + for(auto &component : to_struct_type(type).components()) + { + binding.push_back(equal_exprt( + param_out_member_transformer(callee, component, summary.globals_out), + arg_out_member_transformer(caller, component, SSA, loc))); + } + } + + d.push_back(conjunction(binding)); } } + + c.push_back(disjunction(d)); } callee_rv=callee_rv_deref; @@ -1198,206 +1225,145 @@ std::list ssa_inlinert::apply_dereference( /*******************************************************************\ -Function: ssa_inlinert::bind +Function: ssa_inlinert::contains_advancer - Inputs: Two sets of objects + Inputs: List of expressions - Outputs: + Outputs: True if the list contains an advancer - Purpose: Create bindings between pairs of objects from given sets. + Purpose: \*******************************************************************/ -void ssa_inlinert::bind( - const std::list &lhs, - const std::list &rhs, - exprt::operandst &bindings) +bool ssa_inlinert::contains_advancer(const std::list ¶ms) { - exprt::operandst new_bind; - for(const exprt &l : lhs) + for (const exprt &p : params) { - for(const exprt &r : rhs) + if (p.id() == ID_symbol && + id2string(to_symbol_expr(p).get_identifier()).find("'adv") != std::string::npos) { - new_bind.push_back(equal_exprt(l, r)); + return true; } } - if(!new_bind.empty()) - bindings.push_back(disjunction(new_bind)); + return false; } -std::list ssa_inlinert::transform_pointed_params_in(const std::list ¶ms_in) +exprt ssa_inlinert::param_in_transformer(const exprt ¶m) { - std::list result; - for(const exprt &p : params_in) - { - symbol_exprt param_in=to_symbol_expr(p); - rename(param_in); - result.push_back(param_in); - } - return result; + assert(param.id() == ID_symbol); + symbol_exprt param_in = to_symbol_expr(param); + rename(param_in); + return param_in; } -std::list ssa_inlinert::transform_pointed_args_in( - const std::list &args_in, - const local_SSAt &SSA, - local_SSAt::locationt loc) +exprt ssa_inlinert::arg_in_transformer(const exprt &arg, const local_SSAt &SSA, + local_SSAt::locationt loc) { - std::list result; - for(const exprt &a : args_in) - { - result.push_back(SSA.read_rhs(a, loc)); - } - return result; + return SSA.read_rhs(arg, loc); } -std::list ssa_inlinert::transform_pointed_member_params_in( - const std::list ¶ms_in, - const struct_union_typet::componentt &component) +exprt ssa_inlinert::param_in_member_transformer(const exprt ¶m, + const struct_union_typet::componentt &component) { - std::list result; - for(const exprt &p : params_in) - { - symbol_exprt param_member( - id2string(to_symbol_expr(p).get_identifier())+"."+ - id2string(component.get_name()), component.type()); - rename(param_member); - result.push_back(param_member); - } - return result; + assert(param.id() == ID_symbol); + symbol_exprt param_member(id2string(to_symbol_expr(param).get_identifier()) + "." + + id2string(component.get_name()), component.type()); + rename(param_member); + return param_member; } -std::list ssa_inlinert::transform_pointed_member_args_in( - const std::list &args_in, - const struct_union_typet::componentt &component, - const local_SSAt &SSA, - local_SSAt::locationt loc) +exprt ssa_inlinert::arg_in_member_transformer(const exprt &arg, + const struct_union_typet::componentt &component, + const local_SSAt &SSA, local_SSAt::locationt loc) { - std::list result; - for(const exprt &a : args_in) - { - symbol_exprt arg_member( - id2string(to_symbol_expr(a).get_identifier())+"."+ - id2string(component.get_name()), component.type()); - result.push_back(SSA.read_rhs(arg_member, loc)); - } - return result; + symbol_exprt arg_member(id2string(to_symbol_expr(arg).get_identifier()) + "." + + id2string(component.get_name()), component.type()); + return SSA.read_rhs(arg_member, loc); } -std::list ssa_inlinert::transform_pointed_params_out( - const std::list ¶ms_out, - const local_SSAt::var_sett &globals_out, - const typet ¶m_type) +exprt ssa_inlinert::param_out_transformer(const exprt ¶m, const typet &type, + const local_SSAt::var_sett &globals_out) { - std::list result; - for(const exprt &p : params_out) + assert(param.id() == ID_symbol); + + if (type.id() == ID_struct) + { + address_of_exprt param_addr = address_of_exprt(param); + rename(param_addr); + return param_addr; + } + else { symbol_exprt param_out; - if (find_corresponding_symbol(to_symbol_expr(p), globals_out, param_out)) - { - if (param_type.id()==ID_struct) - { - address_of_exprt param_addr=address_of_exprt(p); - rename(param_addr); - result.push_back(param_addr); - } - else - { - rename(param_out); - result.push_back(param_out); - } - } + assert(find_corresponding_symbol(to_symbol_expr(param), globals_out, param_out)); + rename(param_out); + return param_out; } - return result; } -std::list ssa_inlinert::transform_pointed_args_out( - const std::list &args_out, - const typet &arg_symbol_type, - const typet ¶m_type, - const local_SSAt &SSA, - local_SSAt::locationt loc) +exprt ssa_inlinert::arg_out_transformer(const exprt &arg, const typet &arg_symbol_type, + const typet ¶m_type, const local_SSAt &SSA, + local_SSAt::locationt loc) { - std::list result; - - const typet &arg_type=SSA.ns.follow(arg_symbol_type); - for(const exprt &a : args_out) + const typet &arg_type = SSA.ns.follow(arg_symbol_type); + if (arg_type.id() == ID_struct) { - if(arg_type.id()==ID_struct) - { - address_of_exprt arg_addr=address_of_exprt(a); - typet symbol_type=arg_symbol_type; - symbol_type.set("#dynamic", param_type.get_bool("#dynamic")); - arg_addr.object().type()=symbol_type; - result.push_back(arg_addr); - } - else - { - result.push_back(SSA.name(ssa_objectt(a, SSA.ns), local_SSAt::OUT, loc)); - } + address_of_exprt arg_addr = address_of_exprt(arg); + typet object_type = arg_symbol_type; + object_type.set("#dynamic", param_type.get_bool("#dynamic")); + arg_addr.object().type() = object_type; + return arg_addr; } - return result; -} - -std::list ssa_inlinert::transform_pointed_member_params_out( - const std::list ¶ms_out, - const struct_union_typet::componentt &component, - const local_SSAt::var_sett &globals_out) -{ - std::list result; - for(const exprt &p : params_out) + else { - symbol_exprt param_member( - id2string(to_symbol_expr(p).get_identifier())+"."+ - id2string(component.get_name()), component.type()); - symbol_exprt param_out; - if(find_corresponding_symbol(param_member, globals_out, param_out)) - { - rename(param_out); - result.push_back(param_out); - } + return SSA.name(ssa_objectt(arg, SSA.ns), local_SSAt::OUT, loc); } - return result; } -std::list ssa_inlinert::transform_pointed_member_args_out( - const std::list &args_out, - const struct_union_typet::componentt &component, - const local_SSAt &SSA, - local_SSAt::locationt loc) +exprt ssa_inlinert::param_out_member_transformer(const exprt ¶m, + const struct_union_typet::componentt &component, + const local_SSAt::var_sett &globals_out) { - std::list result; - for(const exprt &a : args_out) - { - symbol_exprt arg_member( - id2string(to_symbol_expr(a).get_identifier()) + "." + - id2string(component.get_name()), component.type()); - result.push_back(SSA.name(ssa_objectt(arg_member, SSA.ns), local_SSAt::OUT, loc)); - } - return result; + assert(param.id() == ID_symbol); + + symbol_exprt param_member(id2string(to_symbol_expr(param).get_identifier()) + "." + + id2string(component.get_name()), component.type()); + symbol_exprt param_out; + assert(find_corresponding_symbol(param_member, globals_out, param_out)); + rename(param_out); + return param_out; } -/*******************************************************************\ - -Function: ssa_inlinert::contains_advancer - - Inputs: List of expressions - - Outputs: True if the list contains an advancer - - Purpose: - -\*******************************************************************/ +exprt ssa_inlinert::arg_out_member_transformer(const exprt &arg, + const struct_union_typet::componentt &component, + const local_SSAt &SSA, local_SSAt::locationt loc) +{ + symbol_exprt arg_member(id2string(to_symbol_expr(arg).get_identifier()) + "." + + id2string(component.get_name()), component.type()); + return SSA.name(ssa_objectt(arg_member, SSA.ns), local_SSAt::OUT, loc); +} -bool ssa_inlinert::contains_advancer(const std::list ¶ms) +const exprt ssa_inlinert::new_pointed_arg(const exprt &arg, const typet &pointed_type, + const std::list &args_out) { - for(const exprt &p : params) + symbol_exprt to_find; + if (arg.id() == ID_symbol) { - if(p.id()==ID_symbol && - id2string(to_symbol_expr(p).get_identifier()).find("'adv") != std::string::npos) - { - return true; - } + to_find = symbol_exprt(id2string(to_symbol_expr(arg).get_identifier()) + "'obj", pointed_type); } - return false; + else if (arg.id() == ID_address_of && to_address_of_expr(arg).object().id() == ID_symbol) + { + to_find = to_symbol_expr(to_address_of_expr(arg).object()); + } + else + return nil_exprt(); + + for (const exprt &a : args_out) + { + if (a == to_find) + return a; + } + + return nil_exprt(); } diff --git a/src/ssa/ssa_inliner.h b/src/ssa/ssa_inliner.h index 4b098084b..dca7eecad 100644 --- a/src/ssa/ssa_inliner.h +++ b/src/ssa/ssa_inliner.h @@ -149,50 +149,47 @@ class ssa_inlinert:public messaget void rename(exprt &expr); void rename(local_SSAt::nodet &node); - static void bind( - const std::list &lhs, - const std::list &rhs, - exprt::operandst &bindings); - // Transformation functions for lists of input/output arguments/pointers (or their members) - // for binding purposes +// Transformation functions for lists of input/output arguments/pointers (or their members) +// for binding purposes - std::list transform_pointed_params_in( - const std::list ¶ms_in); - std::list transform_pointed_args_in( - const std::list &args_in, - const local_SSAt &SSA, - local_SSAt::locationt loc); - - std::list transform_pointed_member_params_in( - const std::list ¶ms_in, + exprt param_in_transformer(const exprt ¶m); + exprt arg_in_transformer(const exprt &arg, const local_SSAt &SSA, local_SSAt::locationt loc); + exprt param_in_member_transformer( + const exprt ¶m, const struct_union_typet::componentt &component); - - std::list transform_pointed_member_args_in( - const std::list &args_in, + exprt arg_in_member_transformer( + const exprt &arg, const struct_union_typet::componentt &component, const local_SSAt &SSA, local_SSAt::locationt loc); - std::list transform_pointed_params_out( - const std::list ¶ms_out, - const local_SSAt::var_sett &globals_out, - const typet ¶m_type); - std::list transform_pointed_args_out( - const std::list &args_out, + + exprt param_out_transformer( + const exprt ¶m, + const typet &type, + const local_SSAt::var_sett &globals_out); + + exprt arg_out_transformer( + const exprt &arg, const typet &arg_symbol_type, const typet ¶m_type, const local_SSAt &SSA, local_SSAt::locationt loc); - std::list transform_pointed_member_params_out( - const std::list ¶ms_out, + exprt param_out_member_transformer( + const exprt ¶m, const struct_union_typet::componentt &component, const local_SSAt::var_sett &globals_out); - std::list transform_pointed_member_args_out( - const std::list &args_out, + exprt arg_out_member_transformer( + const exprt &arg, const struct_union_typet::componentt &component, const local_SSAt &SSA, local_SSAt::locationt loc); + const exprt new_pointed_arg( + const exprt &arg, + const typet &pointed_type, + const std::list &args_out); + static bool contains_advancer(const std::list ¶ms); }; From fa357ce8dd5d387972123e9627b8b0b967c00f67 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 9 Feb 2017 10:39:13 +0100 Subject: [PATCH 054/322] Heap analysis: value of heap row is now disjunction of conjunctions of paths. --- src/domains/heap_domain.cpp | 159 ++++++++++++++++++++++++++---------- src/domains/heap_domain.h | 12 ++- 2 files changed, 125 insertions(+), 46 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 46a074ecc..e5a8a2521 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -393,36 +393,41 @@ exprt heap_domaint::heap_row_valuet::get_row_expr(const domaint::vart &templ_exp else { exprt::operandst result; - for (auto &path : paths) - { // path(o.m, d)[O] - const exprt &dest = templ_expr.type() == path.destination.type() ? - path.destination : address_of_exprt(path.destination); - exprt::operandst path_expr; - - // o.m = d - path_expr.push_back(equal_exprt(templ_expr, dest)); - - for (const dyn_objt &obj1 : path.dyn_objects) - { - // o.m = &o' - exprt equ_exprt = equal_exprt(templ_expr, address_of_exprt(obj1.first)); - - exprt::operandst steps_expr; - exprt member_expr = obj1.second; - // o'.m = d - steps_expr.push_back(equal_exprt(member_expr, dest)); - - for (auto &obj2 : path.dyn_objects) - { // o'.m = o'' - steps_expr.push_back(equal_exprt(member_expr, address_of_exprt(obj2.first))); + for (auto &path_set : paths) + { + exprt::operandst path_set_expr; + for (auto &path : path_set) + { // path(o.m, d)[O] + const exprt &dest = templ_expr.type() == path.destination.type() ? + path.destination : address_of_exprt(path.destination); + exprt::operandst path_expr; + + // o.m = d + path_expr.push_back(equal_exprt(templ_expr, dest)); + + for (const dyn_objt &obj1 : path.dyn_objects) + { + // o.m = &o' + exprt equ_exprt = equal_exprt(templ_expr, address_of_exprt(obj1.first)); + + exprt::operandst steps_expr; + exprt member_expr = obj1.second; + // o'.m = d + steps_expr.push_back(equal_exprt(member_expr, dest)); + + for (auto &obj2 : path.dyn_objects) + { // o'.m = o'' + steps_expr.push_back(equal_exprt(member_expr, address_of_exprt(obj2.first))); + } + + path_expr.push_back(and_exprt(equ_exprt, disjunction(steps_expr))); } - path_expr.push_back(and_exprt(equ_exprt, disjunction(steps_expr))); + path_set_expr.push_back(disjunction(path_expr)); } - - result.push_back(disjunction(path_expr)); + result.push_back(conjunction(path_set_expr)); } - return conjunction(result); + return disjunction(result); } } @@ -430,14 +435,7 @@ bool heap_domaint::heap_row_valuet::add_points_to(const exprt &dest) { if (dest == dyn_obj.first) { - bool changed = !self_linkage; - self_linkage = true; - for (auto &path : paths) - { - if (add_path(path.destination, dyn_obj)) - changed = true; - } - return changed; + return add_self_linkage(); } else { @@ -446,10 +444,28 @@ bool heap_domaint::heap_row_valuet::add_points_to(const exprt &dest) } } -bool heap_domaint::heap_row_valuet::add_path(const exprt &dest, - const heap_domaint::dyn_objt &dyn_obj) +bool heap_domaint::heap_row_valuet::add_path(const exprt &dest, const dyn_objt &dyn_obj) +{ + pathsett new_path_set; + std::set dyn_obj_set; + if (dyn_obj.first.id() != ID_nil) + { + dyn_obj_set.insert(dyn_obj); + } + if (self_linkage) + { + dyn_obj_set.insert(this->dyn_obj); + } + new_path_set.emplace(dest, dyn_obj_set); + paths.push_back(new_path_set); + return true; +} + +bool +heap_domaint::heap_row_valuet::add_path(const exprt &dest, const heap_domaint::dyn_objt &dyn_obj, + pathsett &path_set) { - if (paths.find(dest) == paths.end()) + if (path_set.find(dest) == path_set.end()) { // Path does not exist yet std::set dyn_obj_set; @@ -461,7 +477,7 @@ bool heap_domaint::heap_row_valuet::add_path(const exprt &dest, { dyn_obj_set.insert(this->dyn_obj); } - paths.emplace(dest, dyn_obj_set); + path_set.emplace(dest, dyn_obj_set); return true; } else @@ -469,36 +485,89 @@ bool heap_domaint::heap_row_valuet::add_path(const exprt &dest, // Path exists already if (dyn_obj.first.id() != ID_nil) // Try to insert new dynamic object on the path - return paths.find(dest)->dyn_objects.insert(dyn_obj).second; + return path_set.find(dest)->dyn_objects.insert(dyn_obj).second; else return false; } } -bool heap_domaint::heap_row_valuet::add_all_paths(const heap_domaint::heap_row_valuet &other_val, - const heap_domaint::dyn_objt &dyn_obj) +bool heap_domaint::heap_row_valuet::join_path_sets(heap_domaint::heap_row_valuet::pathsett &dest, + const heap_domaint::heap_row_valuet::pathsett &src, + const dyn_objt &through) { bool result = false; - for (auto &path : other_val.paths) + for (auto &path : src) { - // Add the path with new dynamic object - if (add_path(path.destination, dyn_obj)) + if (add_path(path.destination, through, dest)) result = true; for (auto &o : path.dyn_objects) { // Add all dynamic objects of the original path - if (add_path(path.destination, o)) + if (add_path(path.destination, o, dest)) result = true; } } return result; } +bool heap_domaint::heap_row_valuet::add_all_paths(const heap_domaint::heap_row_valuet &other_val, + const heap_domaint::dyn_objt &dyn_obj) +{ + bool result = false; + + auto other_it = other_val.paths.begin(); + if (other_it != other_val.paths.end()) + { + for (auto it = paths.begin(); it != paths.end(); ++it) + { + if (it->find(other_val.dyn_obj.first) != it->end()) + { + auto next_it = other_it; + ++next_it; + if (next_it != other_val.paths.end()) + { // Duplicate element pointed by it + ++it; + it = paths.insert(it, *it); + --it; + } + + // Add all paths to *it + + if (join_path_sets(*it, *other_it, dyn_obj)) + result = true; + + // Move other_it to next, or to first if next doesn't exist + other_it = next_it == other_val.paths.end() ? other_val.paths.begin() : next_it; + } + } +// join_all_path_sets(); + } + return result; +} + bool heap_domaint::heap_row_valuet::add_pointed_by(const rowt &row) { auto new_pb = pointed_by.insert(row); return new_pb.second; } +bool heap_domaint::heap_row_valuet::add_self_linkage() +{ + bool result; + result = !self_linkage; + self_linkage = true; + if (result) + { + for (auto &path_set : paths) + { + for (auto &path : path_set) + { + path.dyn_objects.insert(dyn_obj); + } + } + } + return result; +} + const std::list &heap_domaint::get_new_heap_vars() const { return new_heap_row_vars; diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index d2f8fc940..e53a2a15b 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -87,7 +87,9 @@ class heap_domaint:public domaint } }; - std::set paths; /**< Set o paths leading from the row variable */ + typedef std::set pathsett; + + std::list paths; std::set pointed_by; /**< Set of rows whose variables point to this row */ dyn_objt dyn_obj; bool self_linkage = false; @@ -105,9 +107,17 @@ class heap_domaint:public domaint bool add_path(const exprt &dest, const dyn_objt &dyn_obj); + bool add_path(const exprt &dest, const heap_domaint::dyn_objt &dyn_obj, pathsett &path_set); + + bool join_path_sets(heap_domaint::heap_row_valuet::pathsett &dest, + const heap_domaint::heap_row_valuet::pathsett &src, + const dyn_objt &through); + bool add_all_paths(const heap_row_valuet &other_val, const dyn_objt &dyn_obj); bool add_pointed_by(const rowt &row); + + bool add_self_linkage(); }; class heap_valuet : public valuet, public std::vector> From 9e716007747bbbb4e01e53c1354635ec72aec440 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 9 Feb 2017 10:40:02 +0100 Subject: [PATCH 055/322] Always collect pointed objects for function arguments. --- src/ssa/ssa_object.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/ssa/ssa_object.cpp b/src/ssa/ssa_object.cpp index 1f7bf3a62..76c3994cd 100644 --- a/src/ssa/ssa_object.cpp +++ b/src/ssa/ssa_object.cpp @@ -59,7 +59,8 @@ void collect_ptr_objects( const exprt &expr, const namespacet &ns, std::set &objects, - std::set &literals) + std::set &literals, + bool dynamic) { if(expr.id()==ID_symbol) { @@ -72,7 +73,7 @@ void collect_ptr_objects( symbol_exprt ptr_object(identifier, pointed_type); const symbolt *symbol; - if (!ns.lookup(src.get_identifier(), symbol) && !symbol->is_procedure_local()) + if (dynamic || !ns.lookup(src.get_identifier(), symbol) && !symbol->is_procedure_local()) ptr_object.type().set("#dynamic", true); if(is_ptr_object(src)) @@ -81,13 +82,13 @@ void collect_ptr_objects( ptr_object.set(ID_ptr_object, src.get_identifier()); collect_objects_rec(ptr_object, ns, objects, literals); - collect_ptr_objects(ptr_object, ns, objects, literals); + collect_ptr_objects(ptr_object, ns, objects, literals, dynamic); } } else { forall_operands(it, expr) - collect_ptr_objects(*it, ns, objects, literals); + collect_ptr_objects(*it, ns, objects, literals, dynamic); } } @@ -162,7 +163,7 @@ void collect_objects_rec( { const code_function_callt &function_call=to_code_function_call(code); for (auto &arg : function_call.arguments()) - collect_ptr_objects(arg, ns, objects, literals); + collect_ptr_objects(arg, ns, objects, literals, true); } return; @@ -218,7 +219,7 @@ void collect_objects_rec( (root_object.id()==ID_symbol && !ns.lookup(to_symbol_expr(root_object).get_identifier(), symbol) && (symbol->is_parameter || !symbol->is_procedure_local()))) - collect_ptr_objects(ssa_object.symbol_expr(), ns, objects, literals); + collect_ptr_objects(ssa_object.symbol_expr(), ns, objects, literals, false); } } else @@ -252,7 +253,7 @@ void ssa_objectst::collect_objects( { symbol_exprt symbol=ns.lookup(*it).symbol_expr(); collect_objects_rec(symbol, ns, objects, literals); - collect_ptr_objects(symbol, ns, objects, literals); + collect_ptr_objects(symbol, ns, objects, literals, false); } // Rummage through body. From 4713f001e685d1bca3532eee94ad82e8a78b4dc5 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 9 Feb 2017 10:41:46 +0100 Subject: [PATCH 056/322] Heap analysis: improve collection and binding of advancers. Move advancer class to separate file. Move advancer collection to SSA (in order to collect SSA version of the advancer pointer). Move creating initial bindings from precondition into heap domain. Improve binding of advancers -- bind with value of advancer pointer. --- src/domains/Makefile | 2 +- src/domains/advancer.cpp | 52 ++++ src/domains/advancer.h | 52 ++++ src/domains/heap_domain.cpp | 281 ++++++++++++++++++++++ src/domains/heap_domain.h | 25 ++ src/domains/strategy_solver_heap.cpp | 344 +-------------------------- src/domains/strategy_solver_heap.h | 75 ------ src/ssa/local_ssa.cpp | 44 +++- src/ssa/local_ssa.h | 7 +- src/ssa/ssa_object.cpp | 4 +- src/ssa/ssa_value_set.cpp | 1 + 11 files changed, 464 insertions(+), 423 deletions(-) create mode 100644 src/domains/advancer.cpp create mode 100644 src/domains/advancer.h diff --git a/src/domains/Makefile b/src/domains/Makefile index d780aba0c..f69cc367e 100644 --- a/src/domains/Makefile +++ b/src/domains/Makefile @@ -1,5 +1,5 @@ SRC = tpolyhedra_domain.cpp equality_domain.cpp domain.cpp \ - predabs_domain.cpp heap_domain.cpp \ + predabs_domain.cpp heap_domain.cpp advancer.cpp \ ssa_analyzer.cpp util.cpp incremental_solver.cpp \ strategy_solver_base.cpp strategy_solver_equality.cpp \ linrank_domain.cpp lexlinrank_domain.cpp\ diff --git a/src/domains/advancer.cpp b/src/domains/advancer.cpp new file mode 100644 index 000000000..25607ae2a --- /dev/null +++ b/src/domains/advancer.cpp @@ -0,0 +1,52 @@ +/** + * Viktor Malik, 2/6/17 (c). + */ + +#include "advancer.h" + +const symbol_exprt advancert::symbol_expr() const +{ + return symbol_exprt(id2string(input_pointer_id()) + "'obj." + id2string(member) + "'adv", + pointer.type().subtype()); +} + +const symbol_exprt advancert::instance_symbol_expr(const irep_idt &member, + const int location_number) const +{ + return recursive_member_symbol(symbol_expr(), member, location_number); +} + +const std::list> advancert::output_instances() const +{ + std::list> result; + + // Find instance with maximal location number + for (auto &instance : instances) + { + int max_loc = *(--(instance.second.end())); + if (max_loc >= 0) + result.emplace_back(instance.first, max_loc); + } + + return result; +} + +const symbol_exprt advancert::input_pointer() const +{ + return symbol_exprt(input_pointer_id(), pointer.type()); +} + +const irep_idt advancert::input_pointer_id() const +{ + const irep_idt id = pointer.get_identifier(); + return id2string(id).substr(0, id2string(id).rfind("#")); +} + +const symbol_exprt recursive_member_symbol(const symbol_exprt &object, + const irep_idt &member, + const int loc_num) +{ + std::string suffix = loc_num != advancert::IN_LOC ? ("#" + std::to_string(loc_num)) : ""; + return symbol_exprt(id2string(object.get_identifier()) + "." + id2string(member) + suffix, + pointer_typet(object.type())); +} diff --git a/src/domains/advancer.h b/src/domains/advancer.h new file mode 100644 index 000000000..09bf4f68e --- /dev/null +++ b/src/domains/advancer.h @@ -0,0 +1,52 @@ +/** + * Viktor Malik, 2/6/17 (c). + */ +#ifndef INC_2LS_ADVANCERT_H +#define INC_2LS_ADVANCERT_H + + +#include +#include + +class advancert +{ + public: + static const int IN_LOC = -1; + + symbol_exprt pointer; + irep_idt member; + + mutable std::map > instances; + + advancert(const symbol_exprt &pointer_, const irep_idt &member_) + : pointer(pointer_), member(member_) {} + + bool operator<(const advancert &rhs) const + { + return std::tie(pointer, member) < std::tie(rhs.pointer, rhs.member); + } + + void add_instance(const irep_idt &member, const int location_number) const + { + instances[member].insert(location_number); + } + + const symbol_exprt input_pointer() const; + + const symbol_exprt symbol_expr() const; + + const symbol_exprt instance_symbol_expr(const irep_idt &member, const int location_number) const; + + const std::list> output_instances() const; + + protected: + const irep_idt input_pointer_id() const; +}; + + +const symbol_exprt recursive_member_symbol(const symbol_exprt &object, + const irep_idt &member, + const int loc_num); + + +#endif //INC_2LS_ADVANCERT_H diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index e5a8a2521..7eeff9a29 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -572,3 +572,284 @@ const std::list &heap_domaint::get_new_heap_vars() const { return new_heap_row_vars; } + +void heap_domaint::initialize_domain(const local_SSAt &SSA, const exprt &precondition, + template_generator_baset &template_generator) +{ + // Bind list advancers + bind_advancers(SSA, precondition, template_generator); + + // Create preconditions for input variables if not exist + exprt::operandst equs; + for (auto ¶m : SSA.params) + create_precondition(param, precondition); + for (auto &global_in : SSA.globals_in) + create_precondition(global_in, precondition); +} + +/*******************************************************************\ + +Function: strategy_solver_heapt::bind_advancers + + Inputs: SSA, calling context represented by precondition and reference + to template generator + + Outputs: + + Purpose: Bind advancers from SSA to actual heap objects from the + calling context. + +\*******************************************************************/ +void heap_domaint::bind_advancers(const local_SSAt &SSA, const exprt &precondition, + template_generator_baset &template_generator) +{ + for (const advancert &advancer : SSA.advancers) + { + exprt::operandst read_bindings; + exprt::operandst write_bindings; + + std::set reachable_objs = reachable_objects(advancer, precondition); + + for (const symbol_exprt &reachable : reachable_objs) + { + exprt::operandst reachable_read_binding; + exprt::operandst reachable_write_binding; + + if (reachable_objs.size() > 1) + reachable_read_binding.push_back( + equal_exprt(advancer.pointer, address_of_exprt(reachable))); + + // Bind reachable.m with advancer instance + for (auto &instance: advancer.instances) + { + for (const int &instance_loc : instance.second) + { + const equal_exprt instance_eq( + advancer.instance_symbol_expr(instance.first, instance_loc), + recursive_member_symbol(reachable, instance.first, instance_loc) + ); + if (instance_loc == advancert::IN_LOC) + reachable_read_binding.push_back(instance_eq); + else + reachable_write_binding.push_back(instance_eq); + } + } + read_bindings.push_back(conjunction(reachable_read_binding)); + write_bindings.push_back(conjunction(reachable_write_binding)); + + // Create new template rows for output write instances + for (const std::pair &instance : advancer.output_instances()) + { + new_output_template_row(SSA, + recursive_member_symbol(reachable, instance.first, instance.second), + template_generator); + } + } + + if (!read_bindings.empty()) + { + advancer_bindings.push_back(disjunction(read_bindings)); + } + if (!write_bindings.empty()) + { + advancer_bindings.push_back(disjunction(write_bindings)); + } + } +} + +/*******************************************************************\ + +Function: strategy_solver_heapt::new_output_template_row + + Inputs: SSA, new row variable and the template generator + + Outputs: + + Purpose: Insert new output template row into the template. + +\*******************************************************************/ +void heap_domaint::new_output_template_row(const local_SSAt &SSA, const symbol_exprt &var, + template_generator_baset &template_generator) +{ + exprt guard = SSA.guard_symbol(--SSA.goto_function.body.instructions.end()); + + template_generator.var_specs.push_back(domaint::var_spect()); + domaint::var_spect &var_spec = template_generator.var_specs.back(); + + var_spec.var = var; + var_spec.pre_guard = guard; + var_spec.post_guard = guard; + var_spec.aux_expr = true_exprt(); + var_spec.kind = domaint::OUT; + + assert(var.type().id() == ID_pointer); + const typet &pointed_type = ns.follow(var.type().subtype()); + add_template_row(var_spec, pointed_type); + new_heap_row_vars.push_back(var); +} + +/*******************************************************************\ + +Function: strategy_solver_heapt::reachable_objects + + Inputs: List advancer, function call calling context represented by + precondition. + + Outputs: Set of reachable objects + + Purpose: Find all objects reachable from advancer pointer via advancer + field in the given precondition. + +\*******************************************************************/ +std::set heap_domaint::reachable_objects(const advancert &advancer, + const exprt &precondition) +{ + std::set result; + + // Collect all addresses pointed by advancer pointer (from stack template rows of the + // calling context) + std::set pointed_objs = collect_preconditions_rec(advancer.input_pointer(), precondition); + for (const exprt &pointed : pointed_objs) + { + if (pointed.id() == ID_address_of) + { + const exprt &pointed_obj = to_address_of_expr(pointed).object(); + assert(pointed_obj.id() == ID_symbol); + + // Create obj.member + symbol_exprt obj_member = recursive_member_symbol(to_symbol_expr(pointed_obj), + advancer.member, advancert::IN_LOC); + obj_member.type() = advancer.pointer.type(); + + // Collect all reachable objects (from heap rows of the calling context) + std::set reachable_objs = collect_preconditions_rec(obj_member, precondition); + for (const exprt &reachable : reachable_objs) + { + if (reachable.id() == ID_address_of) + { + const exprt &reachable_obj = to_address_of_expr(reachable).object(); + assert(reachable_obj.id() == ID_symbol); + + result.insert(to_symbol_expr(reachable_obj)); + } + } + } + } + + return result; +} + +/*******************************************************************\ + +Function: strategy_solver_heapt::collect_preconditions_rec + + Inputs: Expression and calling context (precondition) + + Outputs: Set of preconditions corresponding to given expression. + + Purpose: Recursively find all preconditions for the given expression + in the calling context. + Returns right-hand sides of equalities where expr is left-hand + side. + +\*******************************************************************/ +std::set heap_domaint::collect_preconditions_rec(const exprt &expr, + const exprt &precondition) +{ + std::set result; + if (precondition.id() == ID_equal) + { + const equal_exprt &eq = to_equal_expr(precondition); + if (eq.lhs() == expr && eq.rhs() != expr) + { + result.insert(eq.rhs()); + } + } + else + { + forall_operands(it, precondition) + { + std::set op_result = collect_preconditions_rec(expr, *it); + result.insert(op_result.begin(), op_result.end()); + } + } + return result; +} + +/*******************************************************************\ + +Function: strategy_solver_heapt::create_precondition + + Inputs: Variable, calling context (precondition) and reference to + bindings list. + + Outputs: + + Purpose: Create precondition for given variable at the input of the + function if it does not exist in given calling context. + +\*******************************************************************/ +void heap_domaint::create_precondition(const symbol_exprt &var, const exprt &precondition) +{ + if (var.type().id() == ID_pointer) + { + auto pre = collect_preconditions_rec(var, precondition); + if (pre.empty()) + { + if (id2string(var.get_identifier()).find('.') == std::string::npos) + { + const symbolt *symbol; + if (ns.lookup(id2string(var.get_identifier()), symbol)) return; + + address_of_exprt init_value(symbol->symbol_expr()); + init_value.type() = symbol->type; + aux_bindings.push_back(equal_exprt(var, init_value)); + } + else + { + if (ns.follow(var.type().subtype()).id() == ID_struct) + { + std::string var_id_str = id2string(var.get_identifier()); + const symbol_exprt pointer(var_id_str.substr(0, var_id_str.rfind("'obj")), var.type()); + const irep_idt member = var_id_str.substr(var_id_str.rfind(".")); + + exprt::operandst d; + std::set pointed_objs = collect_preconditions_rec(pointer, precondition); + for (auto pointed : pointed_objs) + { + if (pointed.id() == ID_address_of) + { + const exprt pointed_object = to_address_of_expr(pointed).object(); + if (pointed_object.id() == ID_symbol) + { + symbol_exprt pointed_member( + id2string(to_symbol_expr(pointed_object).get_identifier()) + id2string(member), + var.type()); + d.push_back(equal_exprt(var, pointed_member)); + } + } + } + if (!d.empty()) + { + advancer_bindings.push_back(disjunction(d)); + } + } + } + } + } +} + +const exprt heap_domaint::get_advancer_bindings() const +{ + return conjunction(advancer_bindings); +} + +const exprt heap_domaint::get_aux_bindings() const +{ + return conjunction(aux_bindings); +} + +const exprt heap_domaint::get_input_bindings() const +{ + return and_exprt(get_advancer_bindings(), get_aux_bindings()); +} diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index e53a2a15b..9d377cd78 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -8,7 +8,9 @@ #include #include +#include "../ssa/local_ssa.h" #include "domain.h" +#include "template_generator_base.h" class heap_domaint:public domaint { @@ -145,6 +147,9 @@ class heap_domaint:public domaint // Initialize value virtual void initialize(valuet &value) override; + void initialize_domain(const local_SSAt &SSA, const exprt &precondition, + template_generator_baset &template_generator); + // Value -> constraints exprt to_pre_constraints(const heap_valuet &value) const; @@ -179,15 +184,35 @@ class heap_domaint:public domaint const std::list &get_new_heap_vars() const; + const exprt get_advancer_bindings() const; + const exprt get_aux_bindings() const; + const exprt get_input_bindings() const; + protected: templatet templ; + exprt::operandst advancer_bindings; + exprt::operandst aux_bindings; std::list new_heap_row_vars; void make_template(const var_specst &var_specs, const namespacet &ns); void add_template_row(const var_spect &var_spec, const typet &pointed_type); + // Initializing functions + void bind_advancers(const local_SSAt &SSA, const exprt &precondition, + template_generator_baset &template_generator); + + void create_precondition(const symbol_exprt &var, const exprt &precondition); + + void new_output_template_row(const local_SSAt &SSA, const symbol_exprt &var, + template_generator_baset &template_generator); + + static std::set reachable_objects(const advancert &advancer, + const exprt &precondition); + + static std::set collect_preconditions_rec(const exprt &expr, const exprt &precondition); + // Utility functions static int get_symbol_loc(const exprt &expr); diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index df7c3cb1c..27dc7ad2d 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -303,345 +303,13 @@ void strategy_solver_heapt::initialize( const exprt &precondition, template_generator_baset &template_generator) { - // Bind list advancers - bind_advancers(SSA, precondition, template_generator); - - // Create preconditions for input variables if not exist - exprt::operandst equs; - for (auto ¶m : SSA.params) - create_precondition(param, precondition, equs); - for (auto &global_in : SSA.globals_in) - create_precondition(global_in, precondition, equs); - if (!equs.empty()) - solver << conjunction(equs); -} - -/*******************************************************************\ - -Function: strategy_solver_heapt::collect_preconditions_rec - - Inputs: Expression and calling context (precondition) - - Outputs: Set of preconditions corresponding to given expression. - - Purpose: Recursively find all preconditions for the given expression - in the calling context. - Returns right-hand sides of equalities where expr is left-hand - side. - -\*******************************************************************/ - -std::set strategy_solver_heapt::collect_preconditions_rec( - const exprt &expr, - const exprt &precondition) -{ - std::set result; - if (precondition.id() == ID_equal) - { - const equal_exprt &eq = to_equal_expr(precondition); - if (eq.lhs() == expr && eq.rhs() != expr) - { - result.insert(eq.rhs()); - } - } - else - { - forall_operands(it, precondition) - { - std::set op_result = collect_preconditions_rec(expr, *it); - result.insert(op_result.begin(), op_result.end()); - } - } - return result; -} - -/*******************************************************************\ - -Function: strategy_solver_heapt::create_precondition - - Inputs: Variable, calling context (precondition) and reference to - bindings list. - - Outputs: - - Purpose: Create precondition for given variable at the input of the - function if it does not exist in given calling context. - -\*******************************************************************/ - -void strategy_solver_heapt::create_precondition( - const symbol_exprt &var, - const exprt &precondition, - exprt::operandst &equs) -{ - if (var.type().id() == ID_pointer && - id2string(var.get_identifier()).find('.') == std::string::npos) - { - auto pre = collect_preconditions_rec(var, precondition); - if (pre.empty()) - { - debug() << "Creating precondition for pointer parameters" << eom; - const symbolt *symbol; - if (ns.lookup(id2string(var.get_identifier()), symbol)) return; - - address_of_exprt init_value(symbol->symbol_expr()); - init_value.type() = symbol->type; - equs.push_back(equal_exprt(var, init_value)); - } - } -} - -/*******************************************************************\ - -Function: strategy_solver_heapt::collect_advancers - - Inputs: SSA - - Outputs: - - Purpose: Collect all advancers and their instances in the given SSA - -\*******************************************************************/ - -void strategy_solver_heapt::collect_advancers(const local_SSAt &SSA) -{ - for (const symbol_exprt &global : SSA.globals_in) - { - if (global.type().id() == ID_pointer && - id2string(global.get_identifier()).find('.') != std::string::npos) - { // Get all pointer-typed fields of input structure objects - const typet &pointed_type = ns.follow(global.type().subtype()); - if (pointed_type.id() == ID_struct) - { - // Split pointer'obj.member into pointer and member - const std::string id = id2string(global.get_identifier()); - const irep_idt member = id.substr(id.find_last_of('.') + 1); - const irep_idt pointer_id = id.substr(0, id.rfind("'obj." + id2string(member))); - // Find the corresponding pointer (must be in global objects or parameters) - symbol_exprt pointer(""); - for (const symbol_exprt ¶m : SSA.params) - { - if (param.get_identifier() == pointer_id) - { - pointer = param; - break; - } - } - if (pointer.get_identifier() == "") - { - for (const symbol_exprt &global_other : SSA.globals_in) - { - if (global_other.get_identifier() == pointer_id) - { - pointer = global_other; - break; - } - } - } - assert(pointer.get_identifier() != ""); - - // Create advancer - advancers.emplace_back(pointer, member); - advancert &advancer = advancers.back(); - - // Collect advancer instances - for (auto &component : to_struct_type(pointed_type).components()) - { - const irep_idt &component_name = component.get_name(); - // Read-access advancer instance - advancer.add_instance(component_name, IN_LOC); - - // Find all write-accesses and create corresponding advancer instances - ssa_objectt instance_obj(advancer.instance_symbol_expr(component_name, IN_LOC), SSA.ns); - std::list written_locs = SSA.all_assignment_locs(instance_obj); - for (unsigned loc : written_locs) - { - advancer.add_instance(component_name, loc); - } - } - } - } - } -} - -/*******************************************************************\ - -Function: strategy_solver_heapt::reachable_objects - - Inputs: List advancer, function call calling context represented by - precondition. + heap_domain.initialize_domain(SSA, precondition, template_generator); - Outputs: Set of reachable objects - - Purpose: Find all objects reachable from advancer pointer via advancer - field in the given precondition. - -\*******************************************************************/ - -std::set strategy_solver_heapt::reachable_objects( - const advancert &advancer, - const exprt &precondition) -{ - std::set result; - - // Collect all addresses pointed by advancer pointer (from stack template rows of the - // calling context) - std::set pointed_objs = collect_preconditions_rec(advancer.pointer, precondition); - for (const exprt &pointed : pointed_objs) - { - if (pointed.id() == ID_address_of) - { - const exprt &pointed_obj = to_address_of_expr(pointed).object(); - assert(pointed_obj.id() == ID_symbol); - - // Create obj.member - symbol_exprt obj_member = recursive_member_symbol(to_symbol_expr(pointed_obj), - advancer.member, IN_LOC); - obj_member.type() = advancer.pointer.type(); - - // Collect all reachable objects (from heap rows of the calling context) - std::set reachable_objs = collect_preconditions_rec(obj_member, precondition); - for (const exprt &reachable : reachable_objs) - { - if (reachable.id() == ID_address_of) - { - const exprt &reachable_obj = to_address_of_expr(reachable).object(); - assert(reachable_obj.id() == ID_symbol); - - result.insert(to_symbol_expr(reachable_obj)); - } - } - } - } - - return result; -} - -/*******************************************************************\ - -Function: strategy_solver_heapt::bind_advancers - - Inputs: SSA, calling context represented by precondition and reference - to template generator - - Outputs: - - Purpose: Bind advancers from SSA to actual heap objects from the - calling context. - -\*******************************************************************/ - -void strategy_solver_heapt::bind_advancers( - const local_SSAt &SSA, const exprt &precondition, - template_generator_baset &template_generator) -{ - collect_advancers(SSA); - - for (const advancert &advancer : advancers) + const exprt input_bindings=heap_domain.get_input_bindings(); + if (!input_bindings.is_true()) { - exprt::operandst reachable_bindings; - - std::set reachable_objs = reachable_objects(advancer, precondition); - - exprt::operandst adv_bindings; - for (const symbol_exprt &reachable : reachable_objs) - { - // Bind address of advancer (represented by symbol) with &(reachable) - address_of_exprt reachable_addr = address_of_exprt(reachable); - reachable_addr.object().type().set("#dynamic", true); - adv_bindings.push_back(equal_exprt( - symbol_exprt(id2string(advancer.symbol_expr().get_identifier()) + "'addr", - advancer.pointer.type()), - reachable_addr)); - - // Bind reachable.m with advancer instance - for (auto &instance: advancer.instances) - { - for (const int &instance_loc : instance.second) - { - adv_bindings.push_back(equal_exprt( - recursive_member_symbol(reachable, instance.first, instance_loc), - advancer.instance_symbol_expr(instance.first, instance_loc) - )); - } - } - reachable_bindings.push_back(conjunction(adv_bindings)); - - // Create new template rows for output write instances - for (const std::pair &instance : advancer.output_instances()) - { - new_output_template_row(SSA, - recursive_member_symbol(reachable, instance.first, instance.second), - template_generator); - } - } - - if (!reachable_bindings.empty()) - { - advancer_bindings = disjunction(reachable_bindings); - debug() << "Advancers bindings:" << eom; - debug() << from_expr(SSA.ns, "", advancer_bindings) << eom; - solver << advancer_bindings; - - debug() << "Template after advancer binding:" << eom; - heap_domain.output_domain(debug(), SSA.ns); - } + solver << input_bindings; + debug() << "Input bindings:" << eom; + debug() << from_expr(ns, "", input_bindings) << eom; } } - -/*******************************************************************\ - -Function: strategy_solver_heapt::recursive_member_symbol - - Inputs: Structure-typed object, name of its member and a location number. - - Outputs: Corresponding symbol: - object.member#loc, or object.memer if loc is input - - Purpose: - -\*******************************************************************/ - -const symbol_exprt strategy_solver_heapt::recursive_member_symbol( - const symbol_exprt &object, - const irep_idt &member, - const int loc_num) -{ - std::string suffix = loc_num != IN_LOC ? ("#" + std::to_string(loc_num)) : ""; - return symbol_exprt(id2string(object.get_identifier()) + "." + id2string(member) + suffix, - pointer_typet(object.type())); -} - -/*******************************************************************\ - -Function: strategy_solver_heapt::new_output_template_row - - Inputs: SSA, new row variable and the template generator - - Outputs: - - Purpose: Insert new output template row into the template. - -\*******************************************************************/ - -void strategy_solver_heapt::new_output_template_row( - const local_SSAt &SSA, - const symbol_exprt &var, - template_generator_baset &template_generator) -{ - exprt guard = SSA.guard_symbol(--SSA.goto_function.body.instructions.end()); - - template_generator.var_specs.push_back(domaint::var_spect()); - domaint::var_spect &var_spec = template_generator.var_specs.back(); - - var_spec.var = var; - var_spec.pre_guard = guard; - var_spec.post_guard = guard; - var_spec.aux_expr = true_exprt(); - var_spec.kind = domaint::OUT; - - assert(var.type().id() == ID_pointer); - const typet &pointed_type = ns.follow(var.type().subtype()); - heap_domain.add_template_row(var_spec, pointed_type); - heap_domain.new_heap_row_vars.push_back(var); -} diff --git a/src/domains/strategy_solver_heap.h b/src/domains/strategy_solver_heap.h index 72871c7ea..a2c0df33e 100644 --- a/src/domains/strategy_solver_heap.h +++ b/src/domains/strategy_solver_heap.h @@ -30,90 +30,15 @@ class strategy_solver_heapt : public strategy_solver_baset protected: - class advancert - { - public: - symbol_exprt pointer; - irep_idt member; - - std::map > instances; - - advancert(const symbol_exprt &pointer_, const irep_idt &member_) - : pointer(pointer_), member(member_) {} - - bool operator<(const advancert &rhs) const - { - return std::tie(pointer, member) < std::tie(rhs.pointer, rhs.member); - } - - void add_instance(const irep_idt &member, const int location_number) - { - instances[member].insert(location_number); - } - - const symbol_exprt symbol_expr() const - { - return symbol_exprt( - id2string(pointer.get_identifier()) + "'obj." + id2string(member) + "'adv", - pointer.type().subtype()); - } - - const symbol_exprt instance_symbol_expr(const irep_idt &member, const int location_number) const - { - return recursive_member_symbol(symbol_expr(), member, location_number); - } - - const std::list> output_instances() const - { - std::list> result; - - // Find instance with maximal location number - for (auto &instance : instances) - { - int max_loc = *(--(instance.second.end())); - if (max_loc >= 0) - result.emplace_back(instance.first, max_loc); - } - - return result; - } - }; - - static const int IN_LOC = -1; - heap_domaint &heap_domain; std::set updated_rows; - std::list advancers; - exprt advancer_bindings; - int find_member_row(const exprt &obj, const irep_idt &member, int actual_loc, const domaint::kindt &kind); bool update_rows_rec(const heap_domaint::rowt &row, heap_domaint::heap_valuet &value); void print_solver_expr(const exprt &expr); - - void create_precondition(const symbol_exprt &var, - const exprt &precondition, - exprt::operandst &equs); - - void bind_advancers(const local_SSAt &SSA, const exprt &precondition, - template_generator_baset &template_generator); - - void collect_advancers(const local_SSAt &SSA); - - void new_output_template_row(const local_SSAt &SSA, const symbol_exprt &var, - template_generator_baset &template_generator); - - static std::set reachable_objects(const advancert &advancer, - const exprt &precondition); - - static std::set collect_preconditions_rec(const exprt &expr, const exprt &precondition); - - static const symbol_exprt recursive_member_symbol(const symbol_exprt &object, - const irep_idt &member, - const int loc_num); }; diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index fc07209a5..36e925326 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -1306,6 +1306,9 @@ void local_SSAt::assign_rec( if(assigned.find(lhs_object)!=assigned.end()) { + collect_advancers_lhs(lhs_object, loc); + collect_advancers_rhs(rhs, loc); + exprt ssa_rhs=read_rhs(rhs, loc); const symbol_exprt ssa_symbol=name(lhs_object, OUT, loc); @@ -1845,17 +1848,44 @@ exprt local_SSAt::unknown_obj_eq(const symbol_exprt &obj, return equal_exprt(member, address_of_exprt(obj)); } -std::list local_SSAt::all_assignment_locs(const ssa_objectt &object) const +void local_SSAt::collect_advancers_rhs(const exprt &expr, locationt loc) { - std::list result; - - forall_goto_program_instructions(it, goto_function.body) + if (expr.id() == ID_member) { - if (assignments.assigns(it, object)) + const member_exprt &advancer_ins = to_member_expr(expr); + if (advancer_ins.compound().get_bool("#advancer") && advancer_ins.compound().id() == ID_symbol) { - result.push_back(it->location_number); + new_advancer_instance(to_member_expr(expr), loc, advancert::IN_LOC); } } + else + { + forall_operands(it, expr) + collect_advancers_rhs(*it, loc); + } +} - return result; +void local_SSAt::collect_advancers_lhs(const ssa_objectt &object, local_SSAt::locationt loc) +{ + if (object.get_root_object().get_bool("#advancer") && object.get_root_object().id() == ID_symbol) + { + assert(object.get_expr().id() == ID_member); + new_advancer_instance(to_member_expr(object.get_expr()), loc, loc->location_number); + } +} + +void local_SSAt::new_advancer_instance(const member_exprt &expr, local_SSAt::locationt loc, + int inst_loc_number) +{ + assert(expr.compound().id() == ID_symbol); + const symbol_exprt &advancer_sym = to_symbol_expr(expr.compound()); + const irep_idt &object_id = advancer_sym.get("#object_id"); + const irep_idt pointer_id = id2string(object_id).substr(0, object_id.size() - 4); + + exprt pointer = read_rhs(symbol_exprt(pointer_id, expr.type()), loc); + assert(pointer.id() == ID_symbol); + advancert advancer(to_symbol_expr(pointer), advancer_sym.get("#member")); + + auto adv_it = advancers.insert(advancer); + adv_it.first->add_instance(expr.get_component_name(), inst_loc_number); } diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index e26032cec..3478c7468 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -13,6 +13,7 @@ Author: Daniel Kroening, kroening@kroening.com #include +#include #include #include "ssa_domain.h" @@ -127,6 +128,8 @@ class local_SSAt var_listt params; var_sett globals_in, globals_out; + std::set advancers; + // unknown heap objects var_sett unknown_objs; @@ -166,7 +169,9 @@ class local_SSAt void assign_rec( const exprt &lhs, const exprt &rhs, const exprt &guard, locationt loc); - std::list all_assignment_locs(const ssa_objectt &object) const; + void collect_advancers_rhs(const exprt &expr, locationt loc); + void collect_advancers_lhs(const ssa_objectt &object, locationt loc); + void new_advancer_instance(const member_exprt &expr, locationt loc, int inst_loc_number); exprt unknown_obj_eq(const symbol_exprt &obj, const struct_typet::componentt &component) const; diff --git a/src/ssa/ssa_object.cpp b/src/ssa/ssa_object.cpp index 76c3994cd..e2d00be24 100644 --- a/src/ssa/ssa_object.cpp +++ b/src/ssa/ssa_object.cpp @@ -73,7 +73,9 @@ void collect_ptr_objects( symbol_exprt ptr_object(identifier, pointed_type); const symbolt *symbol; - if (dynamic || !ns.lookup(src.get_identifier(), symbol) && !symbol->is_procedure_local()) + if(dynamic || + (!ns.lookup(src.get_identifier(), symbol) && + !symbol->is_procedure_local())) ptr_object.type().set("#dynamic", true); if(is_ptr_object(src)) diff --git a/src/ssa/ssa_value_set.cpp b/src/ssa/ssa_value_set.cpp index 773d4aba1..9e232b8f5 100644 --- a/src/ssa/ssa_value_set.cpp +++ b/src/ssa/ssa_value_set.cpp @@ -704,6 +704,7 @@ void ssa_value_ait::assign_ptr_param_rec(const exprt &expr, ssa_value_domaint &e assert(member.compound().id() == ID_symbol); // set advancer object member_dest.set("#object_id", to_symbol_expr(member.compound()).get_identifier()); + member_dest.set("#member", member.get_component_name()); assign(expr, member_dest, entry); } } From 31ffe6c6561817c6cb7abd52fc60b42b52e14118 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 9 Feb 2017 10:46:35 +0100 Subject: [PATCH 057/322] Add auxiliary precondition to summary and use it when checking properties. For heap analysis, this stores advancer bindings. --- src/2ls/summary_checker_base.cpp | 6 ++++++ src/domains/ssa_analyzer.cpp | 5 +++++ src/domains/ssa_analyzer.h | 1 + src/solver/summarizer_fw.cpp | 15 ++++++++++----- src/solver/summary.h | 3 +++ 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/2ls/summary_checker_base.cpp b/src/2ls/summary_checker_base.cpp index 0274201e4..9caddfe84 100644 --- a/src/2ls/summary_checker_base.cpp +++ b/src/2ls/summary_checker_base.cpp @@ -228,6 +228,12 @@ void summary_checker_baset::check_properties( { solver << summary_db.get(f_it->first).fw_invariant; solver << summary_db.get(f_it->first).fw_precondition; + + if (options.get_bool_option("heap") && + summary_db.get(f_it->first).aux_precondition.is_not_nil()) + { + solver << summary_db.get(f_it->first).aux_precondition; + } } // callee summaries diff --git a/src/domains/ssa_analyzer.cpp b/src/domains/ssa_analyzer.cpp index a3668b692..0a165a15f 100644 --- a/src/domains/ssa_analyzer.cpp +++ b/src/domains/ssa_analyzer.cpp @@ -175,3 +175,8 @@ void ssa_analyzert::update_heap_out(summaryt::var_sett &out) out.insert(heap_domain.get_new_heap_vars().begin(), heap_domain.get_new_heap_vars().end()); } + +const exprt ssa_analyzert::input_heap_bindings() +{ + return static_cast(*domain).get_advancer_bindings(); +} diff --git a/src/domains/ssa_analyzer.h b/src/domains/ssa_analyzer.h index 1792b9682..5398e883d 100644 --- a/src/domains/ssa_analyzer.h +++ b/src/domains/ssa_analyzer.h @@ -45,6 +45,7 @@ class ssa_analyzert:public messaget void get_result(exprt &result, const domaint::var_sett &vars); void update_heap_out(summaryt::var_sett &out); + const exprt input_heap_bindings(); inline unsigned get_number_of_solver_instances() { return solver_instances; } inline unsigned get_number_of_solver_calls() { return solver_calls; } diff --git a/src/solver/summarizer_fw.cpp b/src/solver/summarizer_fw.cpp index 397b3d2b4..9d7aded5b 100644 --- a/src/solver/summarizer_fw.cpp +++ b/src/solver/summarizer_fw.cpp @@ -172,6 +172,16 @@ void summarizer_fwt::do_summary( debug() << "whole result: " << from_expr(SSA.ns, "", whole_result) << eom; #endif + if(options.get_bool_option("heap")) + { + analyzer.update_heap_out(summary.globals_out); + const exprt advancer_bindings=analyzer.input_heap_bindings(); + if(!advancer_bindings.is_true()) + { + summary.aux_precondition=advancer_bindings; + } + } + if(context_sensitive && !summary.fw_precondition.is_true()) { summary.fw_transformer= @@ -180,11 +190,6 @@ void summarizer_fwt::do_summary( implies_exprt(summary.fw_precondition, summary.fw_invariant); } - if (options.get_bool_option("heap")) - { - analyzer.update_heap_out(summary.globals_out); - } - solver_instances+=analyzer.get_number_of_solver_instances(); solver_calls+=analyzer.get_number_of_solver_calls(); } diff --git a/src/solver/summary.h b/src/solver/summary.h index 3ee24a666..f4cd32205 100644 --- a/src/solver/summary.h +++ b/src/solver/summary.h @@ -33,6 +33,7 @@ class summaryt bw_postcondition(nil_exprt()), bw_transformer(nil_exprt()), bw_invariant(nil_exprt()), + aux_precondition(nil_exprt()), termination_argument(nil_exprt()), terminates(UNKNOWN), mark_recompute(false) {} @@ -49,6 +50,8 @@ class summaryt predicatet bw_transformer; // backward summary (over- or under-approx) predicatet bw_invariant; // backward invariant (over- or under-approx) + predicatet aux_precondition; + predicatet termination_argument; threevalt terminates; From f3d49ed545c61239200df14d7e0f46ca9af015f1 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 6 Apr 2017 12:41:40 +0200 Subject: [PATCH 058/322] Heap analysis: introduce OUTHEAP kind for template rows. This row kind is used for fields of dynamic objects that are bound to iterators in the analysed function. The value of a row is updated only if iterator points to the corresponding object. This is ensured by a guard in post condition. --- src/domains/domain.h | 2 +- src/domains/heap_domain.cpp | 64 +++++++++++++++++++--- src/domains/heap_domain.h | 9 ++- src/domains/strategy_solver_heap.cpp | 9 ++- src/domains/template_generator_summary.cpp | 5 +- 5 files changed, 74 insertions(+), 15 deletions(-) diff --git a/src/domains/domain.h b/src/domains/domain.h index cdc10fa83..5f8fde816 100644 --- a/src/domains/domain.h +++ b/src/domains/domain.h @@ -39,7 +39,7 @@ class domaint typedef std::vector var_listt; typedef std::set var_sett; - typedef enum {LOOP, IN, OUT, OUTL} kindt; + typedef enum {LOOP, IN, OUT, OUTL, OUTHEAP} kindt; typedef exprt guardt; diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 7eeff9a29..21ef36756 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -140,7 +140,9 @@ exprt heap_domaint::get_row_pre_constraint(const rowt &row, const row_valuet &ro // For exit variables the result is true if (k == OUT || k == OUTL) return true_exprt(); - return implies_exprt(templ_row.pre_guard, row_value.get_row_expr(templ_row.expr)); + if (k == OUTHEAP && row_value.empty()) return true_exprt(); + + return implies_exprt(templ_row.pre_guard, row_value.get_row_expr(templ_row.expr, false)); } /** @@ -156,7 +158,8 @@ exprt heap_domaint::get_row_post_constraint(const rowt &row, const row_valuet &r // For entry variables the result is true if (templ_row.kind == IN) return true_exprt(); - exprt c = implies_exprt(templ_row.post_guard, row_value.get_row_expr(templ_row.expr)); + exprt c = implies_exprt(templ_row.post_guard, + row_value.get_row_expr(templ_row.expr, templ_row.kind == OUTHEAP)); if (templ_row.kind == LOOP) rename(c); return c; } @@ -227,11 +230,14 @@ void heap_domaint::output_value(std::ostream &out, const domaint::valuet &value, case OUTL: out << "(OUT) "; break; + case OUTHEAP: + out << "(HEAP) "; + break; default: assert(false); } out << "( " << from_expr(ns, "", templ_row.expr) << " == " - << from_expr(ns, "", val[row].get_row_expr(templ_row.expr)) << " )" + << from_expr(ns, "", val[row].get_row_expr(templ_row.expr, false)) << " )" << std::endl; } } @@ -260,6 +266,11 @@ void heap_domaint::output_domain(std::ostream &out, const namespacet &ns) const out << from_expr(ns, "", templ_row.post_guard) << " ===> " << std::endl << " "; break; + case OUTHEAP: + out << "(HEAP) [ " << from_expr(ns, "", templ_row.pre_guard) << " | "; + out << from_expr(ns, "", templ_row.post_guard) + << " ] ===> " << std::endl << " "; + break; default: assert(false); } @@ -288,12 +299,14 @@ void heap_domaint::project_on_vars(domaint::valuet &value, const row_valuet &row_val = val[row]; if (templ_row.kind == LOOP) { - c.push_back(implies_exprt(templ_row.pre_guard, - row_val.get_row_expr(templ_row.expr))); + c.push_back(implies_exprt(templ_row.pre_guard, row_val.get_row_expr(templ_row.expr, false))); } else { - c.push_back(row_val.get_row_expr(templ_row.expr)); + exprt row_expr = row_val.get_row_expr(templ_row.expr, false); + if (templ_row.kind == OUTHEAP) + rename(row_expr); + c.push_back(row_expr); } } result = conjunction(c); @@ -353,7 +366,20 @@ std::string heap_domaint::get_base_name(const exprt &expr) return result; } -exprt heap_domaint::stack_row_valuet::get_row_expr(const domaint::vart &templ_expr) const +/*******************************************************************\ + +Function: heap_domaint::stack_row_valuet::get_row_expr + + Inputs: templ_expr Template expression + + Outputs: Formula corresponding to the template row + + Purpose: Stack row is a disjuction of equalities between templ_expr and addresses of + dynamic objects from points_to set. + +\*******************************************************************/ +exprt heap_domaint::stack_row_valuet::get_row_expr(const vart &templ_expr, + bool rename_templ_expr) const { if (nondet) return true_exprt(); @@ -377,11 +403,31 @@ bool heap_domaint::stack_row_valuet::add_points_to(const exprt &expr) return new_pt.second; } -exprt heap_domaint::heap_row_valuet::get_row_expr(const domaint::vart &templ_expr) const +/*******************************************************************\ + +Function: heap_domaint::heap_row_valuet::get_row_expr + + Inputs: templ_expr Template expression + rename_templ_expr True if templ_expr should be renamed (the corresponding template row + is of outheap type) + + Outputs: Formula corresponding to the template row + + Purpose: Heap row is disjunction of path sets, where each path set is a conjunction of paths. + nondet is TRUE + empty is FALSE + +\*******************************************************************/ +exprt heap_domaint::heap_row_valuet::get_row_expr(const vart &templ_expr_, + bool rename_templ_expr) const { if (nondet) return true_exprt(); - if (empty()) + exprt templ_expr = templ_expr_; + if (rename_templ_expr) + templ_expr = rename_outheap(to_symbol_expr(templ_expr_)); + + if (paths.empty()) { if (self_linkage) { diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index 9d377cd78..aae26e04e 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -38,7 +38,7 @@ class heap_domaint:public domaint { bool nondet = false; /**< Row is nondeterministic - expression is TRUE */ - virtual exprt get_row_expr(const vart &templ_expr) const = 0; + virtual exprt get_row_expr(const vart &templ_expr, bool rename_templ_expr) const = 0; virtual bool empty() const = 0; @@ -49,7 +49,7 @@ class heap_domaint:public domaint { std::set points_to; /**< Set of objects (or NULL) the row variable can point to */ - virtual exprt get_row_expr(const vart &templ_expr) const override; + virtual exprt get_row_expr(const vart &templ_expr, bool rename_templ_expr) const override; virtual bool add_points_to(const exprt &expr) override; @@ -98,7 +98,7 @@ class heap_domaint:public domaint heap_row_valuet(const dyn_objt &dyn_obj_) : dyn_obj(dyn_obj_) {} - virtual exprt get_row_expr(const vart &templ_expr) const override; + virtual exprt get_row_expr(const vart &templ_expr_, bool rename_templ_expr) const override; virtual bool add_points_to(const exprt &dest) override; @@ -120,6 +120,9 @@ class heap_domaint:public domaint bool add_pointed_by(const rowt &row); bool add_self_linkage(); + + protected: + static exprt rename_outheap(const symbol_exprt &expr); }; class heap_valuet : public valuet, public std::vector> diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index 27dc7ad2d..d0cd54aeb 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -248,7 +248,8 @@ int strategy_solver_heapt::find_member_row( if (id.find(obj_id) != std::string::npos) { int loc = heap_domain.get_symbol_loc(templ_row.expr); - if (loc > max_loc && (kind == domaint::OUT || loc <= actual_loc)) + if (loc > max_loc && + (kind == domaint::OUT || kind == domaint::OUTHEAP || loc <= actual_loc)) { max_loc = loc; result = i; @@ -312,4 +313,10 @@ void strategy_solver_heapt::initialize( debug() << "Input bindings:" << eom; debug() << from_expr(ns, "", input_bindings) << eom; } + + if (!heap_domain.new_heap_row_specs.empty()) + { + debug() << "New template:" << eom; + heap_domain.output_domain(debug(), ns); + } } diff --git a/src/domains/template_generator_summary.cpp b/src/domains/template_generator_summary.cpp index becceba5f..4b83c2d01 100644 --- a/src/domains/template_generator_summary.cpp +++ b/src/domains/template_generator_summary.cpp @@ -11,6 +11,7 @@ Author: Peter Schrammel #include "template_generator_summary.h" #include "equality_domain.h" #include "tpolyhedra_domain.h" +#include "domain.h" #include #include @@ -123,7 +124,9 @@ domaint::var_sett template_generator_summaryt::inout_vars() for(domaint::var_specst::const_iterator v=var_specs.begin(); v!=var_specs.end(); v++) { - if(v->kind==domaint::IN || v->kind==domaint::OUT) + if(v->kind==domaint::IN || + v->kind==domaint::OUT || + v->kind==domaint::OUTHEAP) vars.insert(v->var); } return vars; From ed32a924cd668ad801e61778debfb4912fee509f Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 6 Apr 2017 12:59:11 +0200 Subject: [PATCH 059/322] Heap analysis: functions for adding new template rows during heap analysis. Added row is of OUTHEAP type, functions will be called from iterator binding. --- src/domains/heap_domain.cpp | 70 ++++++++++++++++++++++++++++++------- src/domains/heap_domain.h | 37 ++++++++++++++++++-- 2 files changed, 92 insertions(+), 15 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 21ef36756..ed5ee439b 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -614,9 +614,48 @@ bool heap_domaint::heap_row_valuet::add_self_linkage() return result; } -const std::list &heap_domaint::get_new_heap_vars() const +/*******************************************************************\ + +Function: heap_domaint::heap_row_valuet::rename_outheap + + Inputs: expr Expression to be renamed + + Outputs: Renamed expression + + Purpose: Rename OUTHEAP row expression (used for post-expr). Simply remove 'lb' from suffix. + +\*******************************************************************/ +exprt heap_domaint::heap_row_valuet::rename_outheap(const symbol_exprt &expr) { - return new_heap_row_vars; + const std::string id = id2string(expr.get_identifier()); + return symbol_exprt(id.substr(0, id.rfind("lb")) + id.substr(id.rfind("lb") + 2), expr.type()); +} + +/*******************************************************************\ + +Function: heap_domaint::get_new_heap_vars + + Inputs: + + Outputs: List of variables (symbols) that were added to template during analysis + + Purpose: + +\*******************************************************************/ +const std::list heap_domaint::get_new_heap_vars() +{ + std::list result; + for (auto &row : templ) + { + if (row.kind == OUTHEAP) + { + assert(row.expr.id() == ID_symbol); + symbol_exprt expr = to_symbol_expr(row.expr); + rename(expr); + result.push_back(expr); + } + } + return result; } void heap_domaint::initialize_domain(const local_SSAt &SSA, const exprt &precondition, @@ -705,33 +744,40 @@ void heap_domaint::bind_advancers(const local_SSAt &SSA, const exprt &preconditi /*******************************************************************\ -Function: strategy_solver_heapt::new_output_template_row +Function: heap_domaint::new_output_template_row - Inputs: SSA, new row variable and the template generator + Inputs: Outputs: Purpose: Insert new output template row into the template. \*******************************************************************/ -void heap_domaint::new_output_template_row(const local_SSAt &SSA, const symbol_exprt &var, +void heap_domaint::new_output_template_row(const symbol_exprt &var, const unsigned location_number, + const exprt &post_guard, const local_SSAt &SSA, template_generator_baset &template_generator) { - exprt guard = SSA.guard_symbol(--SSA.goto_function.body.instructions.end()); - template_generator.var_specs.push_back(domaint::var_spect()); domaint::var_spect &var_spec = template_generator.var_specs.back(); - var_spec.var = var; - var_spec.pre_guard = guard; - var_spec.post_guard = guard; + local_SSAt::locationt loc = SSA.get_location(location_number); + + const exprt pre_guard = SSA.guard_symbol(loc); + + const symbol_exprt pre_var = SSA.name(ssa_objectt(var, SSA.ns), local_SSAt::LOOP_BACK, loc); + const symbol_exprt post_var = SSA.name(ssa_objectt(var, SSA.ns), local_SSAt::OUT, loc); + + var_spec.var = pre_var; + var_spec.pre_guard = pre_guard; + var_spec.post_guard = post_guard; var_spec.aux_expr = true_exprt(); - var_spec.kind = domaint::OUT; + var_spec.kind = OUTHEAP; + + renaming_map[pre_var] = post_var; assert(var.type().id() == ID_pointer); const typet &pointed_type = ns.follow(var.type().subtype()); add_template_row(var_spec, pointed_type); - new_heap_row_vars.push_back(var); } /*******************************************************************\ diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index aae26e04e..2c845bc6e 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -185,7 +185,8 @@ class heap_domaint:public domaint // Join of values virtual void join(valuet &value1, const valuet &value2) override; - const std::list &get_new_heap_vars() const; + // Getters for protected fields + const std::list get_new_heap_vars(); const exprt get_advancer_bindings() const; const exprt get_aux_bindings() const; @@ -196,7 +197,34 @@ class heap_domaint:public domaint exprt::operandst advancer_bindings; exprt::operandst aux_bindings; - std::list new_heap_row_vars; + + /** + * Specification of a new heap row. The row is added dynamically at the beginning of the analysis + * after binding of iterators to actual dynamic objects from calling context. + */ + class heap_row_spect + { + public: + symbol_exprt expr; /**< Row expression */ + unsigned location_number; /**< Location where the corresponding iterator occured */ + + mutable exprt post_guard; + + heap_row_spect(const symbol_exprt &expr, unsigned int location_number, const exprt &post_guard) + : expr(expr), location_number(location_number), post_guard(post_guard) {} + + bool operator<(const heap_row_spect &rhs) const + { + return std::tie(expr, location_number) < std::tie(rhs.expr, rhs.location_number); + } + + bool operator==(const heap_row_spect &rhs) const + { + return std::tie(expr, location_number) == std::tie(rhs.expr, rhs.location_number); + } + }; + + std::set new_heap_row_specs; void make_template(const var_specst &var_specs, const namespacet &ns); @@ -208,7 +236,8 @@ class heap_domaint:public domaint void create_precondition(const symbol_exprt &var, const exprt &precondition); - void new_output_template_row(const local_SSAt &SSA, const symbol_exprt &var, + void new_output_template_row(const symbol_exprt &var, const unsigned location_number, + const exprt &post_guard, const local_SSAt &SSA, template_generator_baset &template_generator); static std::set reachable_objects(const advancert &advancer, @@ -216,6 +245,8 @@ class heap_domaint:public domaint static std::set collect_preconditions_rec(const exprt &expr, const exprt &precondition); + void add_new_heap_row_spec(const symbol_exprt &expr, const unsigned location_number, + const exprt &post_guard); // Utility functions static int get_symbol_loc(const exprt &expr); From 1cfca1afdf618749835ab064bcff6c0c9f757818 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 6 Apr 2017 13:10:19 +0200 Subject: [PATCH 060/322] Collection of helper function for working with pointed objects. Functions simplify working with objects that are abstractions of objects pointed by a pointer. --- src/ssa/Makefile | 2 +- src/ssa/ssa_pointed_objects.cpp | 258 ++++++++++++++++++++++++++++++++ src/ssa/ssa_pointed_objects.h | 51 +++++++ 3 files changed, 310 insertions(+), 1 deletion(-) create mode 100644 src/ssa/ssa_pointed_objects.cpp create mode 100644 src/ssa/ssa_pointed_objects.h diff --git a/src/ssa/Makefile b/src/ssa/Makefile index f66679938..ecb631819 100644 --- a/src/ssa/Makefile +++ b/src/ssa/Makefile @@ -1,5 +1,5 @@ SRC = local_ssa.cpp ssa_var_collector.cpp \ - ssa_domain.cpp translate_union_member.cpp malloc_ssa.cpp \ + ssa_domain.cpp translate_union_member.cpp malloc_ssa.cpp ssa_pointed_objects.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 \ diff --git a/src/ssa/ssa_pointed_objects.cpp b/src/ssa/ssa_pointed_objects.cpp new file mode 100644 index 000000000..70904114c --- /dev/null +++ b/src/ssa/ssa_pointed_objects.cpp @@ -0,0 +1,258 @@ +/** + * Viktor Malik, 2/15/17 (c). + */ + +#include "ssa_pointed_objects.h" +#include "ssa_object.h" + +const irep_idt level_str(const unsigned level, const irep_idt &suffix) +{ + return "#lvl_" + std::to_string(level) + "_" + id2string(suffix); +} + +const irep_idt it_field_str(const unsigned level) +{ + return id2string(ID_it_field) + "_" + std::to_string(level); +} + +void copy_iterator(exprt &dest, const exprt &src) +{ + if (src.get_bool(ID_iterator)) + { + dest.set(ID_iterator, true); + dest.set(ID_it_pointer, src.get(ID_it_pointer)); + dest.set(ID_it_init_value, src.get(ID_it_init_value)); + dest.set(ID_it_init_value_level, src.get(ID_it_init_value_level)); + + unsigned field_cnt = src.get_unsigned_int(ID_it_field_cnt); + dest.set(ID_it_field_cnt, field_cnt); + for (unsigned i = 0; i < field_cnt; ++i) + { + const irep_idt field = src.get(it_field_str(i)); + dest.set(it_field_str(i), field); + } + } +} + +void copy_pointed_info(exprt &dest, const exprt &src, const unsigned max_level) +{ + if(max_level < pointed_level(src)) + { + dest.set(ID_pointed, true); + dest.set(ID_pointed_level, max_level + 1); + for (unsigned l = 0; l <= max_level; ++l) + { + const irep_idt lvl_pointed_id = src.get(level_str(l, ID_pointer_id)); + dest.set(level_str(l, ID_pointer_id), lvl_pointed_id); + dest.set(level_str(l, ID_pointer_subtype), src.get(level_str(l, ID_pointer_subtype))); + if (lvl_pointed_id == ID_symbol) + { + dest.set(level_str(l, ID_pointer_sym), src.get(level_str(l, ID_pointer_sym))); + } + else + { + dest.set(level_str(l, ID_pointer_compound), src.get(level_str(l, ID_pointer_compound))); + dest.set(level_str(l, ID_pointer_field), src.get(level_str(l, ID_pointer_field))); + } + } + } +} + +symbol_exprt pointed_object(const exprt &expr, const namespacet &ns) +{ + assert(expr.type().id() == ID_pointer); + + ssa_objectt ssa_object(expr, ns); + if (ssa_object) + { + const typet &pointed_type = ssa_object.type().subtype(); + symbol_exprt pointed(id2string(ssa_object.get_identifier()) + "'obj", ns.follow(pointed_type)); + pointed.set(ID_pointed, true); + + unsigned level = 0; + const exprt root_obj = ssa_object.get_root_object(); + if (root_obj.get_bool(ID_pointed)) + { + level = pointed_level(root_obj); + copy_pointed_info(pointed, root_obj, level - 1); + } + + pointed.set(ID_pointed_level, level + 1); + + assert(root_obj.id() == ID_symbol); + + pointed.set(level_str(level, ID_pointer_id), ssa_object.get_expr().id()); + if (ssa_object.get_expr().id() == ID_symbol) + { + pointed.set(level_str(level, ID_pointer_sym), ssa_object.get_identifier()); + } + else + { + assert(ssa_object.get_expr().id() == ID_member); + const member_exprt member = to_member_expr(ssa_object.get_expr()); + assert(member.compound().id() == ID_symbol); + pointed.set(level_str(level, ID_pointer_compound), + to_symbol_expr(member.compound()).get_identifier()); + pointed.set(level_str(level, ID_pointer_field), member.get_component_name()); + } + + if (pointed_type.id() == ID_symbol) + { + pointed.set(level_str(level, ID_pointer_subtype), + to_symbol_type(pointed_type).get_identifier()); + } + + copy_iterator(pointed, root_obj); + + return pointed; + } + else + return symbol_exprt(""); +} + +const irep_idt pointer_root_id(const exprt &expr) +{ + assert(expr.get_bool(ID_pointed)); + unsigned max_level_index = expr.get_unsigned_int(ID_pointed_level) - 1; + if (expr.get(level_str(max_level_index, ID_pointer_id)) == ID_symbol) + return expr.get(level_str(max_level_index, ID_pointer_sym)); + else + return expr.get(level_str(max_level_index, ID_pointer_compound)); +} + +unsigned pointed_level(const exprt &expr) +{ + if (is_pointed(expr)) + return expr.get_unsigned_int(ID_pointed_level); + else + return 0; +} + +const irep_idt pointer_level_field(const exprt &expr, const unsigned level) +{ + assert(expr.get(level_str(level, ID_pointer_id)) == ID_member); + return expr.get(level_str(level, ID_pointer_field)); +} + +const exprt get_pointer(const exprt &expr, unsigned level) +{ + exprt pointer; + + const typet &pointed_type = symbol_typet(expr.get(level_str(level, ID_pointer_subtype))); + + if (expr.get(level_str(level, ID_pointer_id)) == ID_symbol) + { + pointer = symbol_exprt(expr.get(level_str(level, ID_pointer_sym)), pointer_typet(pointed_type)); + copy_pointed_info(pointer, expr, level - 1); + } + else + { + assert(expr.get(level_str(level, ID_pointer_id)) == ID_member); + symbol_exprt compound(expr.get(level_str(level, ID_pointer_compound)), expr.type()); + copy_pointed_info(compound, expr, level - 1); + pointer = member_exprt(compound, pointer_level_field(expr, level), pointer_typet(pointed_type)); + } + return pointer; +} + +unsigned it_value_level(const exprt &expr) +{ + assert(expr.get_bool(ID_pointed)); + return expr.get_unsigned_int(ID_it_init_value_level); +} + +bool is_pointed(const exprt &expr) +{ + return expr.get_bool(ID_pointed); +} + +bool is_iterator(const exprt &expr) +{ + return expr.get_bool(ID_iterator); +} + +void copy_pointed_info(exprt &dest, const exprt &src) +{ + copy_pointed_info(dest, src, pointed_level(src) - 1); +} + +const exprt symbolic_dereference(const exprt &expr, const namespacet &ns) +{ + if (expr.id() == ID_dereference) + { + const exprt &pointer = symbolic_dereference(to_dereference_expr(expr).pointer(), ns); + const ssa_objectt pointer_object(pointer, ns); + assert(pointer_object); + + return pointed_object(pointer_object.symbol_expr(), ns); + } + else if (expr.id() == ID_member) + { + member_exprt member = to_member_expr(expr); + member.compound() = symbolic_dereference(member.compound(), ns); + + return member; + } + else + { + exprt tmp = expr; + Forall_operands(it, tmp) + *it = symbolic_dereference(*it, ns); + return tmp; + } +} + +void set_iterator_fields(exprt &dest, const std::vector fields) +{ + dest.set(ID_it_field_cnt, (unsigned) fields.size()); + for (unsigned i = 0; i < fields.size(); ++i) + { + dest.set(it_field_str(i), fields.at(i)); + } +} + +const std::vector get_iterator_fields(const exprt &expr) +{ + assert(is_iterator(expr)); + unsigned cnt = expr.get_unsigned_int(ID_it_field_cnt); + std::vector result; + for (unsigned i = 0; i < cnt; ++i) + { + result.push_back(expr.get(it_field_str(i))); + } + return result; +} + +const std::vector pointer_fields(const exprt &expr, const unsigned from_level) +{ + std::vector result; + unsigned max_level = pointed_level(expr); + assert(from_level < max_level); + for (unsigned l = from_level; l < max_level; ++l) + { + result.push_back(pointer_level_field(expr, l)); + } + return result; +} + +const exprt get_pointer_root(const exprt &expr, unsigned level) +{ + exprt pointer = get_pointer(expr, level); + if (pointer.id() == ID_member) + pointer = to_member_expr(pointer).compound(); + assert(pointer.id() == ID_symbol); + return pointer; +} + +const irep_idt iterator_to_initial_id(const exprt &expr, const irep_idt &expr_id) +{ + assert(is_iterator(expr)); + std::string id_str = id2string(expr_id); + const std::string init_value_id_str = id2string(expr.get(ID_it_init_value)); + const std::string iterator_id_str = id2string(expr.get(ID_it_pointer)) + "'it"; + + assert(id_str.find(iterator_id_str) != std::string::npos); + return id_str.replace(id_str.find(iterator_id_str), + iterator_id_str.length(), + init_value_id_str); +} diff --git a/src/ssa/ssa_pointed_objects.h b/src/ssa/ssa_pointed_objects.h new file mode 100644 index 000000000..8d6195b75 --- /dev/null +++ b/src/ssa/ssa_pointed_objects.h @@ -0,0 +1,51 @@ +/** + * Viktor Malik, 2/15/17 (c). + */ +#ifndef CPROVER_SSA_POINTED_OBJECTS_H +#define CPROVER_SSA_POINTED_OBJECTS_H + +#include +#include +#include + +#define ID_pointed "#pointed" +#define ID_pointed_level "#level" +#define ID_pointer_id "id" +#define ID_pointer_subtype "subtype" +#define ID_pointer_sym "sym" +#define ID_pointer_compound "compound" +#define ID_pointer_field "field" +#define ID_iterator "#iterator" +#define ID_it_pointer "#it_pointer" +#define ID_it_field "#it_field" +#define ID_it_field_cnt "#it_field_cnt" +#define ID_it_init_value "#it_init_value" +#define ID_it_init_value_level "#it_init_value_level" + +symbol_exprt pointed_object(const exprt &expr, const namespacet &ns); + +bool is_pointed(const exprt &expr); +bool is_iterator(const exprt &expr); + +unsigned pointed_level(const exprt &expr); +unsigned it_value_level(const exprt &expr); + +const irep_idt pointer_root_id(const exprt &expr); +const irep_idt pointer_level_field(const exprt &expr, const unsigned level); +const std::vector pointer_fields(const exprt &expr, const unsigned from_level); + +const exprt get_pointer(const exprt &expr, unsigned level); +const exprt get_pointer_root(const exprt &expr, unsigned level); + +void copy_pointed_info(exprt &dest, const exprt &src, const unsigned max_level); +void copy_pointed_info(exprt &dest, const exprt &src); +void copy_iterator(exprt &dest, const exprt &src); + +const exprt symbolic_dereference(const exprt &expr, const namespacet &ns); + +void set_iterator_fields(exprt &dest, const std::vector fields); +const std::vector get_iterator_fields(const exprt &expr); + +const irep_idt iterator_to_initial_id(const exprt &expr, const irep_idt &expr_id); + +#endif //CPROVER_SSA_POINTED_OBJECTS_H From f57791b9cea15d89d603f2ae9f2ab4d6acf44443 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 6 Apr 2017 13:35:54 +0200 Subject: [PATCH 061/322] Change advancers to list iterators. Iterators abstract a situation when a linked list given as input to a function is traversed node by node and each node is altered. Iterators are created in ssa_value_analysis in merge on the loop-back edge. They are bound to actual objects from the calling context at the beginning of analysis of a function. --- src/domains/Makefile | 2 +- src/domains/advancer.cpp | 52 ----- src/domains/advancer.h | 52 ----- src/domains/heap_domain.cpp | 426 ++++++++++++++++++++++------------ src/domains/heap_domain.h | 22 +- src/domains/list_iterator.cpp | 78 +++++++ src/domains/list_iterator.h | 51 ++++ src/domains/ssa_analyzer.cpp | 5 +- src/ssa/address_canonizer.cpp | 10 +- src/ssa/local_ssa.cpp | 68 +++--- src/ssa/local_ssa.h | 10 +- src/ssa/ssa_dereference.cpp | 1 + src/ssa/ssa_inliner.cpp | 19 +- src/ssa/ssa_inliner.h | 2 +- src/ssa/ssa_object.h | 14 ++ src/ssa/ssa_value_set.cpp | 204 ++++++++-------- src/ssa/ssa_value_set.h | 10 +- 17 files changed, 602 insertions(+), 424 deletions(-) delete mode 100644 src/domains/advancer.cpp delete mode 100644 src/domains/advancer.h create mode 100644 src/domains/list_iterator.cpp create mode 100644 src/domains/list_iterator.h diff --git a/src/domains/Makefile b/src/domains/Makefile index f69cc367e..38e8f9f60 100644 --- a/src/domains/Makefile +++ b/src/domains/Makefile @@ -1,5 +1,5 @@ SRC = tpolyhedra_domain.cpp equality_domain.cpp domain.cpp \ - predabs_domain.cpp heap_domain.cpp advancer.cpp \ + predabs_domain.cpp heap_domain.cpp list_iterator.cpp \ ssa_analyzer.cpp util.cpp incremental_solver.cpp \ strategy_solver_base.cpp strategy_solver_equality.cpp \ linrank_domain.cpp lexlinrank_domain.cpp\ diff --git a/src/domains/advancer.cpp b/src/domains/advancer.cpp deleted file mode 100644 index 25607ae2a..000000000 --- a/src/domains/advancer.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Viktor Malik, 2/6/17 (c). - */ - -#include "advancer.h" - -const symbol_exprt advancert::symbol_expr() const -{ - return symbol_exprt(id2string(input_pointer_id()) + "'obj." + id2string(member) + "'adv", - pointer.type().subtype()); -} - -const symbol_exprt advancert::instance_symbol_expr(const irep_idt &member, - const int location_number) const -{ - return recursive_member_symbol(symbol_expr(), member, location_number); -} - -const std::list> advancert::output_instances() const -{ - std::list> result; - - // Find instance with maximal location number - for (auto &instance : instances) - { - int max_loc = *(--(instance.second.end())); - if (max_loc >= 0) - result.emplace_back(instance.first, max_loc); - } - - return result; -} - -const symbol_exprt advancert::input_pointer() const -{ - return symbol_exprt(input_pointer_id(), pointer.type()); -} - -const irep_idt advancert::input_pointer_id() const -{ - const irep_idt id = pointer.get_identifier(); - return id2string(id).substr(0, id2string(id).rfind("#")); -} - -const symbol_exprt recursive_member_symbol(const symbol_exprt &object, - const irep_idt &member, - const int loc_num) -{ - std::string suffix = loc_num != advancert::IN_LOC ? ("#" + std::to_string(loc_num)) : ""; - return symbol_exprt(id2string(object.get_identifier()) + "." + id2string(member) + suffix, - pointer_typet(object.type())); -} diff --git a/src/domains/advancer.h b/src/domains/advancer.h deleted file mode 100644 index 09bf4f68e..000000000 --- a/src/domains/advancer.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Viktor Malik, 2/6/17 (c). - */ -#ifndef INC_2LS_ADVANCERT_H -#define INC_2LS_ADVANCERT_H - - -#include -#include - -class advancert -{ - public: - static const int IN_LOC = -1; - - symbol_exprt pointer; - irep_idt member; - - mutable std::map > instances; - - advancert(const symbol_exprt &pointer_, const irep_idt &member_) - : pointer(pointer_), member(member_) {} - - bool operator<(const advancert &rhs) const - { - return std::tie(pointer, member) < std::tie(rhs.pointer, rhs.member); - } - - void add_instance(const irep_idt &member, const int location_number) const - { - instances[member].insert(location_number); - } - - const symbol_exprt input_pointer() const; - - const symbol_exprt symbol_expr() const; - - const symbol_exprt instance_symbol_expr(const irep_idt &member, const int location_number) const; - - const std::list> output_instances() const; - - protected: - const irep_idt input_pointer_id() const; -}; - - -const symbol_exprt recursive_member_symbol(const symbol_exprt &object, - const irep_idt &member, - const int loc_num); - - -#endif //INC_2LS_ADVANCERT_H diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index ed5ee439b..dab32beaa 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -7,6 +7,8 @@ #include "domain.h" #include #include +#include "../ssa/ssa_inliner.h" +#include "../ssa/address_canonizer.h" /** * Initialize value. @@ -661,8 +663,8 @@ const std::list heap_domaint::get_new_heap_vars() void heap_domaint::initialize_domain(const local_SSAt &SSA, const exprt &precondition, template_generator_baset &template_generator) { - // Bind list advancers - bind_advancers(SSA, precondition, template_generator); + // Bind list iterators + bind_iterators(SSA, precondition, template_generator); // Create preconditions for input variables if not exist exprt::operandst equs; @@ -674,71 +676,63 @@ void heap_domaint::initialize_domain(const local_SSAt &SSA, const exprt &precond /*******************************************************************\ -Function: strategy_solver_heapt::bind_advancers +Function: heap_domaint::bind_iterators Inputs: SSA, calling context represented by precondition and reference to template generator Outputs: - Purpose: Bind advancers from SSA to actual heap objects from the + Purpose: Bind iterators from SSA to actual heap objects from the calling context. \*******************************************************************/ -void heap_domaint::bind_advancers(const local_SSAt &SSA, const exprt &precondition, +void heap_domaint::bind_iterators(const local_SSAt &SSA, const exprt &precondition, template_generator_baset &template_generator) { - for (const advancert &advancer : SSA.advancers) + new_heap_row_specs.clear(); + for (const list_iteratort &iterator : SSA.iterators) { - exprt::operandst read_bindings; - exprt::operandst write_bindings; - - std::set reachable_objs = reachable_objects(advancer, precondition); - - for (const symbol_exprt &reachable : reachable_objs) + for (const list_iteratort::accesst &access : iterator.accesses) { - exprt::operandst reachable_read_binding; - exprt::operandst reachable_write_binding; - - if (reachable_objs.size() > 1) - reachable_read_binding.push_back( - equal_exprt(advancer.pointer, address_of_exprt(reachable))); - - // Bind reachable.m with advancer instance - for (auto &instance: advancer.instances) + exprt access_binding = iterator_access_bindings(iterator.pointer, iterator.init_pointer, + iterator.iterator_symbol(), iterator.fields, + access, 0, exprt::operandst(), precondition, + SSA); + + // Special treatment for first element in the list + // @TODO this should be handled better + if (access.fields.size() > 1 && access.location != list_iteratort::IN_LOC) { - for (const int &instance_loc : instance.second) + const std::set first = collect_preconditions_rec(iterator.init_pointer, + precondition); + for (const exprt &value : first) { - const equal_exprt instance_eq( - advancer.instance_symbol_expr(instance.first, instance_loc), - recursive_member_symbol(reachable, instance.first, instance_loc) - ); - if (instance_loc == advancert::IN_LOC) - reachable_read_binding.push_back(instance_eq); - else - reachable_write_binding.push_back(instance_eq); + if (value.id() == ID_address_of) + { + assert(to_address_of_expr(value).object().id() == ID_symbol); + const symbol_exprt &first_obj = to_symbol_expr(to_address_of_expr(value).object()); + const symbol_exprt new_value = recursive_member_symbol(first_obj, access.fields.back(), + access.location, ns); + const symbol_exprt old_value = recursive_member_symbol(first_obj, access.fields.back(), + list_iteratort::IN_LOC, ns); + const exprt binding = equal_exprt(new_value, old_value); + access_binding = or_exprt(access_binding, binding); + + add_new_heap_row_spec(old_value, (unsigned) access.location, binding); + } } } - read_bindings.push_back(conjunction(reachable_read_binding)); - write_bindings.push_back(conjunction(reachable_write_binding)); - // Create new template rows for output write instances - for (const std::pair &instance : advancer.output_instances()) - { - new_output_template_row(SSA, - recursive_member_symbol(reachable, instance.first, instance.second), - template_generator); - } + iterator_bindings.push_back(access_binding); } + } - if (!read_bindings.empty()) - { - advancer_bindings.push_back(disjunction(read_bindings)); - } - if (!write_bindings.empty()) - { - advancer_bindings.push_back(disjunction(write_bindings)); - } + // Add template rows for bound heap objects + for (auto &row_spec : new_heap_row_specs) + { + new_output_template_row(row_spec.expr, row_spec.location_number, row_spec.post_guard, SSA, + template_generator); } } @@ -782,166 +776,298 @@ void heap_domaint::new_output_template_row(const symbol_exprt &var, const unsign /*******************************************************************\ -Function: strategy_solver_heapt::reachable_objects +Function: heap_domaint::create_precondition - Inputs: List advancer, function call calling context represented by - precondition. + Inputs: Variable and a calling context (precondition) - Outputs: Set of reachable objects + Outputs: - Purpose: Find all objects reachable from advancer pointer via advancer - field in the given precondition. + Purpose: Create precondition for given variable at the input of the + function if it does not exist in given calling context. \*******************************************************************/ -std::set heap_domaint::reachable_objects(const advancert &advancer, - const exprt &precondition) -{ - std::set result; - // Collect all addresses pointed by advancer pointer (from stack template rows of the - // calling context) - std::set pointed_objs = collect_preconditions_rec(advancer.input_pointer(), precondition); - for (const exprt &pointed : pointed_objs) +void heap_domaint::create_precondition( + const symbol_exprt &var, const exprt &precondition) +{ + if(var.type().id()==ID_pointer) { - if (pointed.id() == ID_address_of) + auto pre=collect_preconditions_rec(var, precondition); + if(pre.empty() || (pre.size()==1 && *(pre.begin())==var)) { - const exprt &pointed_obj = to_address_of_expr(pointed).object(); - assert(pointed_obj.id() == ID_symbol); - - // Create obj.member - symbol_exprt obj_member = recursive_member_symbol(to_symbol_expr(pointed_obj), - advancer.member, advancert::IN_LOC); - obj_member.type() = advancer.pointer.type(); + if(id2string(var.get_identifier()).find('.')==std::string::npos) + { + // For variables, create abstract address + const symbolt *symbol; + if(ns.lookup(id2string(var.get_identifier()), symbol)) + return; - // Collect all reachable objects (from heap rows of the calling context) - std::set reachable_objs = collect_preconditions_rec(obj_member, precondition); - for (const exprt &reachable : reachable_objs) + address_of_exprt init_value(symbol->symbol_expr()); + init_value.type()=symbol->type; + aux_bindings.push_back(equal_exprt(var, init_value)); + } + else { - if (reachable.id() == ID_address_of) + // For members of structs, find corresponding object + // in calling context and return its member + std::string var_id_str=id2string(var.get_identifier()); + const symbol_exprt pointer( + var_id_str.substr(0, var_id_str.rfind("'obj")), + var.type()); + const irep_idt member=var_id_str.substr(var_id_str.rfind(".")); + + exprt::operandst d; + std::set pointed_objs= + collect_preconditions_rec(pointer, precondition); + for(auto pointed : pointed_objs) { - const exprt &reachable_obj = to_address_of_expr(reachable).object(); - assert(reachable_obj.id() == ID_symbol); - - result.insert(to_symbol_expr(reachable_obj)); + if(pointed.id()== ID_address_of) + { + const exprt pointed_object=to_address_of_expr(pointed).object(); + if(pointed_object.id()==ID_symbol) + { + symbol_exprt pointed_member( + id2string(to_symbol_expr(pointed_object).get_identifier())+ + id2string(member), + var.type()); + d.push_back(equal_exprt(var, pointed_member)); + } + } + } + if(!d.empty()) + { + iterator_bindings.push_back(disjunction(d)); } } } } +} - return result; +const exprt heap_domaint::get_iterator_bindings() const +{ + return conjunction(iterator_bindings); +} + +const exprt heap_domaint::get_aux_bindings() const +{ + return conjunction(aux_bindings); +} + +const exprt heap_domaint::get_input_bindings() const +{ + return and_exprt(get_iterator_bindings(), get_aux_bindings()); } /*******************************************************************\ -Function: strategy_solver_heapt::collect_preconditions_rec +Function: heap_domaint::iterator_access_bindings - Inputs: Expression and calling context (precondition) + Inputs: src Source pointer (symbolic value) + init_pointed Actual value of the source pointer + iterator_sym Corresponding iterator symbol + fields Set of fields to follow + access Iterator access to be bound + level Current access level + guards + precondition Calling context + SSA - Outputs: Set of preconditions corresponding to given expression. + Outputs: Formula corresponding to bindings - Purpose: Recursively find all preconditions for the given expression - in the calling context. - Returns right-hand sides of equalities where expr is left-hand - side. + Purpose: Create bindings of iterator with corresponding dynamic objects. Function is called + recursively, if there is access with multiple fields. \*******************************************************************/ -std::set heap_domaint::collect_preconditions_rec(const exprt &expr, - const exprt &precondition) +const exprt heap_domaint::iterator_access_bindings(const symbol_exprt &src, + const exprt &init_pointer, + const symbol_exprt &iterator_sym, + const std::vector &fields, + const list_iteratort::accesst &access, + const unsigned level, + exprt::operandst guards, + const exprt &precondition, + const local_SSAt &SSA) { - std::set result; - if (precondition.id() == ID_equal) + const std::set reachable = reachable_objects(init_pointer, fields, precondition); + + exprt::operandst d; + for (auto &r : reachable) { - const equal_exprt &eq = to_equal_expr(precondition); - if (eq.lhs() == expr && eq.rhs() != expr) + exprt::operandst c; + + equal_exprt points_to_eq(src, address_of_exprt(r)); + c.push_back(points_to_eq); + + if (level == 0) { - result.insert(eq.rhs()); + equal_exprt address_eq(address_canonizer(address_of_exprt(iterator_sym), ns), + address_of_exprt(r)); + c.push_back(address_eq); } + + equal_exprt access_eq = access.binding(iterator_sym, r, level, ns); + c.push_back(access_eq); + + guards.push_back(conjunction(c)); + + if (level < access.fields.size() - 1) + { + assert(access_eq.lhs().id() == ID_symbol); + assert(access_eq.rhs().id() == ID_symbol); + const symbol_exprt new_src = to_symbol_expr(access_eq.rhs()); + const symbol_exprt new_iterator_sym = pointed_object(to_symbol_expr(access_eq.lhs()), ns); + c.push_back( + iterator_access_bindings(new_src, r, new_iterator_sym, {access.fields.at(level)}, + access, level + 1, guards, precondition, SSA)); + } + else if (access.location != list_iteratort::IN_LOC) + { + add_new_heap_row_spec( + recursive_member_symbol(r, access.fields.back(), list_iteratort::IN_LOC, ns), + (unsigned) access.location, conjunction(guards)); + } + + guards.pop_back(); + + d.push_back(conjunction(c)); } + + if (!d.empty()) + return disjunction(d); else - { - forall_operands(it, precondition) - { - std::set op_result = collect_preconditions_rec(expr, *it); - result.insert(op_result.begin(), op_result.end()); - } - } - return result; + return true_exprt(); } /*******************************************************************\ -Function: strategy_solver_heapt::create_precondition +Function: heap_domaint::reachable_objects - Inputs: Variable, calling context (precondition) and reference to - bindings list. + Inputs: src Source expression + fields Set of fields to follow + precondition Calling context - Outputs: + Outputs: Set of reachable objects - Purpose: Create precondition for given variable at the input of the - function if it does not exist in given calling context. + Purpose: Find all objects reachable from source via the vector of fields \*******************************************************************/ -void heap_domaint::create_precondition(const symbol_exprt &var, const exprt &precondition) +const std::set heap_domaint::reachable_objects(const exprt &src, + const std::vector &fields, + const exprt &precondition) const { - if (var.type().id() == ID_pointer) + std::set result; + + if (!(src.id() == ID_symbol || src.id() == ID_member)) return result; + + std::set pointed_objs; + if (src.id() == ID_member && to_member_expr(src).compound().get_bool(ID_pointed)) { - auto pre = collect_preconditions_rec(var, precondition); - if (pre.empty()) + const member_exprt &member = to_member_expr(src); + const exprt pointer = get_pointer(member.compound(), pointed_level(member.compound()) - 1); + + std::set r = reachable_objects(pointer, {member.get_component_name()}, + precondition); + pointed_objs.insert(r.begin(), r.end()); + } + else + { + if (src.type().id() == ID_pointer) { - if (id2string(var.get_identifier()).find('.') == std::string::npos) + std::set values = collect_preconditions_rec(src, precondition); + for (auto &v : values) { - const symbolt *symbol; - if (ns.lookup(id2string(var.get_identifier()), symbol)) return; - - address_of_exprt init_value(symbol->symbol_expr()); - init_value.type() = symbol->type; - aux_bindings.push_back(equal_exprt(var, init_value)); + if (v.id() == ID_address_of) + { + assert(to_address_of_expr(v).object().id() == ID_symbol); + pointed_objs.insert(to_symbol_expr(to_address_of_expr(v).object())); + } } - else + } + else + { + assert(src.type().get_bool("#dynamic")); + pointed_objs.insert(to_symbol_expr(src)); + } + } + + for (unsigned i = 0; i < fields.size(); ++i) + { + for (const symbol_exprt &pointed_obj : pointed_objs) + { + // Create obj.member + symbol_exprt obj_member = recursive_member_symbol(pointed_obj, fields.at(i), + list_iteratort::IN_LOC, ns); + + // Collect all reachable objects (from heap rows of the calling context) + std::set reachable_objs = collect_preconditions_rec(obj_member, precondition); + for (const exprt &reachable : reachable_objs) { - if (ns.follow(var.type().subtype()).id() == ID_struct) + if (reachable.id() == ID_address_of) { - std::string var_id_str = id2string(var.get_identifier()); - const symbol_exprt pointer(var_id_str.substr(0, var_id_str.rfind("'obj")), var.type()); - const irep_idt member = var_id_str.substr(var_id_str.rfind(".")); + const exprt &reachable_obj = to_address_of_expr(reachable).object(); + assert(reachable_obj.id() == ID_symbol); - exprt::operandst d; - std::set pointed_objs = collect_preconditions_rec(pointer, precondition); - for (auto pointed : pointed_objs) - { - if (pointed.id() == ID_address_of) - { - const exprt pointed_object = to_address_of_expr(pointed).object(); - if (pointed_object.id() == ID_symbol) - { - symbol_exprt pointed_member( - id2string(to_symbol_expr(pointed_object).get_identifier()) + id2string(member), - var.type()); - d.push_back(equal_exprt(var, pointed_member)); - } - } - } - if (!d.empty()) - { - advancer_bindings.push_back(disjunction(d)); - } + result.insert(to_symbol_expr(reachable_obj)); } } } + if (i != fields.size() - 1) + pointed_objs = result; } -} -const exprt heap_domaint::get_advancer_bindings() const -{ - return conjunction(advancer_bindings); + return result; } -const exprt heap_domaint::get_aux_bindings() const +void heap_domaint::add_new_heap_row_spec(const symbol_exprt &expr, const unsigned location_number, + const exprt &post_guard) { - return conjunction(aux_bindings); + auto it = new_heap_row_specs.emplace(expr, location_number, post_guard); + if (!it.second) + { + if (it.first->post_guard != post_guard) + it.first->post_guard = or_exprt(it.first->post_guard, post_guard); + } } -const exprt heap_domaint::get_input_bindings() const +/*******************************************************************\ + +Function: heap_domaint::collect_preconditions_rec + + Inputs: Expression and calling context (precondition) + + Outputs: Set of preconditions corresponding to given expression. + + Purpose: Recursively find all preconditions for the given expression + in the calling context. + Returns right-hand sides of equalities where expr is left-hand + side. + +\*******************************************************************/ + +const std::set heap_domaint::collect_preconditions_rec( + const exprt &expr, + const exprt &precondition) { - return and_exprt(get_advancer_bindings(), get_aux_bindings()); + std::set result; + if(precondition.id()==ID_equal) + { + const equal_exprt &eq=to_equal_expr(precondition); + if((eq.lhs()==expr && eq.rhs()!=expr) || + (eq.lhs().id()==ID_symbol && + expr.id()==ID_symbol && + to_symbol_expr(eq.lhs()).get_identifier()== + to_symbol_expr(expr).get_identifier())) + { + result.insert(eq.rhs()); + } + } + else + { + forall_operands(it, precondition) + { + std::set op_result=collect_preconditions_rec(expr, *it); + result.insert(op_result.begin(), op_result.end()); + } + } + return result; } diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index 2c845bc6e..111cdec79 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -188,14 +188,14 @@ class heap_domaint:public domaint // Getters for protected fields const std::list get_new_heap_vars(); - const exprt get_advancer_bindings() const; + const exprt get_iterator_bindings() const; const exprt get_aux_bindings() const; const exprt get_input_bindings() const; protected: templatet templ; - exprt::operandst advancer_bindings; + exprt::operandst iterator_bindings; exprt::operandst aux_bindings; /** @@ -231,7 +231,7 @@ class heap_domaint:public domaint void add_template_row(const var_spect &var_spec, const typet &pointed_type); // Initializing functions - void bind_advancers(const local_SSAt &SSA, const exprt &precondition, + void bind_iterators(const local_SSAt &SSA, const exprt &precondition, template_generator_baset &template_generator); void create_precondition(const symbol_exprt &var, const exprt &precondition); @@ -240,10 +240,20 @@ class heap_domaint:public domaint const exprt &post_guard, const local_SSAt &SSA, template_generator_baset &template_generator); - static std::set reachable_objects(const advancert &advancer, - const exprt &precondition); + const exprt iterator_access_bindings(const symbol_exprt &src, const exprt &init_pointer, + const symbol_exprt &iterator_sym, + const std::vector &fields, + const list_iteratort::accesst &access, const unsigned level, + exprt::operandst guards, const exprt &precondition, + const local_SSAt &SSA); + + const std::set reachable_objects(const exprt &src, + const std::vector &fields, + const exprt &precondition) const; + + static const std::set collect_preconditions_rec(const exprt &expr, + const exprt &precondition); - static std::set collect_preconditions_rec(const exprt &expr, const exprt &precondition); void add_new_heap_row_spec(const symbol_exprt &expr, const unsigned location_number, const exprt &post_guard); diff --git a/src/domains/list_iterator.cpp b/src/domains/list_iterator.cpp new file mode 100644 index 000000000..6d6b96bbe --- /dev/null +++ b/src/domains/list_iterator.cpp @@ -0,0 +1,78 @@ +/** + * Viktor Malik, 2/6/17 (c). + */ + +#include +#include "../ssa/ssa_pointed_objects.h" +#include "../ssa/address_canonizer.h" +#include "list_iterator.h" + +void list_iteratort::add_access(const member_exprt &expr, int location_number) const +{ + assert(expr.compound().get_bool(ID_iterator) && expr.compound().get_bool(ID_pointed)); + + accesst access; + access.location = location_number; + + unsigned level = pointed_level(expr.compound()); + unsigned iterator_level = it_value_level(expr.compound()); + for (unsigned l = iterator_level; l < level; ++l) + { + access.fields.push_back(pointer_level_field(expr.compound(), l)); + } + access.fields.push_back(expr.get_component_name()); + + accesses.push_back(access); +} + +const symbol_exprt list_iteratort::access_symbol_expr(const accesst &access, unsigned level, const namespacet &ns) const +{ + int location = level == access.fields.size() - 1 ? access.location : IN_LOC; + if (level == 0) + { + return recursive_member_symbol(iterator_symbol(), access.fields.at(level), location, ns); + } + else + { + return recursive_member_symbol(access_symbol_expr(access, level - 1, ns), + access.fields.at(level), location, ns); + } +} + +const symbol_exprt list_iteratort::iterator_symbol() const +{ + symbol_exprt iterator(id2string(pointer.get_identifier()).substr(0, id2string( + pointer.get_identifier()).find_last_of('#')) + "'it", pointer.type().subtype()); + iterator.set(ID_iterator, true); + + return iterator; +} + +const symbol_exprt recursive_member_symbol(const symbol_exprt &object, const irep_idt &member, + const int loc_num, const namespacet &ns) +{ + typet type = nil_typet(); + const typet &object_type = ns.follow(object.type()); + assert(object_type.id() == ID_struct); + for (auto &component : to_struct_type(object_type).components()) + { + if (component.get_name() == member) + type = component.type(); + } + assert(type.is_not_nil()); + + std::string suffix = loc_num != list_iteratort::IN_LOC ? ("#" + std::to_string(loc_num)) : ""; + symbol_exprt symbol(id2string(object.get_identifier()) + "." + id2string(member) + suffix, type); + copy_pointed_info(symbol, object); + copy_iterator(symbol, object); + + return symbol; +} + +equal_exprt list_iteratort::accesst::binding(const symbol_exprt &lhs, const symbol_exprt &rhs, + const unsigned level, const namespacet &ns) const +{ + int loc = level == fields.size() - 1 ? location : IN_LOC; + return equal_exprt(recursive_member_symbol(lhs, fields.at(level), loc, ns), + recursive_member_symbol(rhs, fields.at(level), loc, ns)); +} diff --git a/src/domains/list_iterator.h b/src/domains/list_iterator.h new file mode 100644 index 000000000..51574bc37 --- /dev/null +++ b/src/domains/list_iterator.h @@ -0,0 +1,51 @@ +/** + * Viktor Malik, 2/6/17 (c). + */ +#ifndef CPROVER_LIST_ITERATOR_H +#define CPROVER_LIST_ITERATOR_H + + +#include +#include + +class list_iteratort +{ + public: + static const int IN_LOC = -1; + + class accesst + { + public: + std::vector fields; + int location; + + equal_exprt binding(const symbol_exprt &lhs, const symbol_exprt &rhs, + const unsigned level, const namespacet &ns) const; + }; + + symbol_exprt pointer; + exprt init_pointer; + std::vector fields; + mutable std::list accesses; + + list_iteratort(const symbol_exprt &pointer, const exprt &init_pointer, + const std::vector &fields) + : pointer(pointer), init_pointer(init_pointer), fields(fields) {} + + bool operator<(const list_iteratort &rhs) const + { + return std::tie(pointer, fields) < std::tie(rhs.pointer, rhs.fields); + } + + void add_access(const member_exprt &expr, int location_number) const; + + const symbol_exprt + access_symbol_expr(const accesst &access, unsigned level, const namespacet &ns) const; + + const symbol_exprt iterator_symbol() const; +}; + +const symbol_exprt recursive_member_symbol(const symbol_exprt &object, const irep_idt &member, const int loc_num, + const namespacet &ns); + +#endif //CPROVER_LIST_ITERATOR_H diff --git a/src/domains/ssa_analyzer.cpp b/src/domains/ssa_analyzer.cpp index 0a165a15f..5584c3bc2 100644 --- a/src/domains/ssa_analyzer.cpp +++ b/src/domains/ssa_analyzer.cpp @@ -173,10 +173,11 @@ void ssa_analyzert::update_heap_out(summaryt::var_sett &out) { heap_domaint &heap_domain = static_cast(*domain); - out.insert(heap_domain.get_new_heap_vars().begin(), heap_domain.get_new_heap_vars().end()); + auto new_heap_vars = heap_domain.get_new_heap_vars(); + out.insert(new_heap_vars.begin(), new_heap_vars.end()); } const exprt ssa_analyzert::input_heap_bindings() { - return static_cast(*domain).get_advancer_bindings(); + return static_cast(*domain).get_iterator_bindings(); } diff --git a/src/ssa/address_canonizer.cpp b/src/ssa/address_canonizer.cpp index 29bcea9bb..08a2a1781 100644 --- a/src/ssa/address_canonizer.cpp +++ b/src/ssa/address_canonizer.cpp @@ -12,6 +12,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include "address_canonizer.h" +#include "ssa_pointed_objects.h" /*******************************************************************\ @@ -75,14 +76,13 @@ exprt address_canonizer( return sum; } - else if (object.id() == ID_symbol && - id2string(to_symbol_expr(object).get_identifier()).find("'adv") != std::string::npos) + else if (object.id() == ID_symbol && is_iterator(object)) { - // address of advancer is dereferenced to a corresponding symbol - will be bound to real + // address of iterator is dereferenced to a corresponding symbol - will be bound to real // address during analysis - symbol_exprt advancer_addr(id2string(to_symbol_expr(object).get_identifier()) + "'addr", + symbol_exprt iterator_addr(id2string(to_symbol_expr(object).get_identifier()) + "'addr", address.type()); - return advancer_addr; + return iterator_addr; } else return address; diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 36e925326..f21516843 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -21,6 +21,9 @@ Author: Daniel Kroening, kroening@kroening.com #include +#include +#include + #include "local_ssa.h" #include "malloc_ssa.h" #include "ssa_dereference.h" @@ -675,6 +678,9 @@ void local_SSAt::build_assertions(locationt loc) { if(loc->is_assert()) { + const exprt deref_rhs = dereference(loc->guard, loc); + collect_iterators_rhs(deref_rhs, loc); + exprt c=read_rhs(loc->guard, loc); exprt g=guard_symbol(loc); (--nodes.end())->assertions.push_back(implies_exprt(g, c)); @@ -1284,21 +1290,6 @@ void local_SSAt::assign_rec( return; } - if (lhs.id() == ID_member && to_member_expr(lhs).compound().get_bool("#advancer") && - to_member_expr(lhs).compound().get_bool("#except_first")) - { // if an advancer instance is assigned and it does not cover first element, create - // non-deterministic case split since not all list elements are assigned here - exprt lhs_copy = lhs; - to_member_expr(lhs_copy).compound().set("#except_first", false); - if_exprt advancer_split(name(guard_symbol(), LOOP_SELECT, loc), lhs_copy, - symbol_exprt("", lhs_copy.type()) - - ); - assign_rec(advancer_split, rhs, guard, loc); - - return; - } - ssa_objectt lhs_object(lhs, ns); const std::set &assigned= @@ -1306,8 +1297,8 @@ void local_SSAt::assign_rec( if(assigned.find(lhs_object)!=assigned.end()) { - collect_advancers_lhs(lhs_object, loc); - collect_advancers_rhs(rhs, loc); + collect_iterators_lhs(lhs_object, loc); + collect_iterators_rhs(rhs, loc); exprt ssa_rhs=read_rhs(rhs, loc); @@ -1848,44 +1839,49 @@ exprt local_SSAt::unknown_obj_eq(const symbol_exprt &obj, return equal_exprt(member, address_of_exprt(obj)); } -void local_SSAt::collect_advancers_rhs(const exprt &expr, locationt loc) +void local_SSAt::collect_iterators_rhs(const exprt &expr, locationt loc) { if (expr.id() == ID_member) { - const member_exprt &advancer_ins = to_member_expr(expr); - if (advancer_ins.compound().get_bool("#advancer") && advancer_ins.compound().id() == ID_symbol) + const member_exprt &member = to_member_expr(expr); + if (member.compound().get_bool(ID_iterator) && member.compound().id() == ID_symbol) { - new_advancer_instance(to_member_expr(expr), loc, advancert::IN_LOC); + new_iterator_access(to_member_expr(expr), loc, list_iteratort::IN_LOC); } } else { forall_operands(it, expr) - collect_advancers_rhs(*it, loc); + collect_iterators_rhs(*it, loc); } } -void local_SSAt::collect_advancers_lhs(const ssa_objectt &object, local_SSAt::locationt loc) +void local_SSAt::collect_iterators_lhs(const ssa_objectt &object, local_SSAt::locationt loc) { - if (object.get_root_object().get_bool("#advancer") && object.get_root_object().id() == ID_symbol) + if (is_iterator(object.get_root_object()) && object.get_root_object().id() == ID_symbol) { assert(object.get_expr().id() == ID_member); - new_advancer_instance(to_member_expr(object.get_expr()), loc, loc->location_number); + new_iterator_access(to_member_expr(object.get_expr()), loc, loc->location_number); } } -void local_SSAt::new_advancer_instance(const member_exprt &expr, local_SSAt::locationt loc, - int inst_loc_number) +void local_SSAt::new_iterator_access(const member_exprt &expr, local_SSAt::locationt loc, + int inst_loc_number) { - assert(expr.compound().id() == ID_symbol); - const symbol_exprt &advancer_sym = to_symbol_expr(expr.compound()); - const irep_idt &object_id = advancer_sym.get("#object_id"); - const irep_idt pointer_id = id2string(object_id).substr(0, object_id.size() - 4); + assert(is_iterator(expr.compound())); + + const irep_idt pointer_id = expr.compound().get(ID_it_pointer); + const symbolt &pointer_symbol = ns.lookup(pointer_id); + exprt pointer_rhs = read_rhs(pointer_symbol.symbol_expr(), loc); + assert(pointer_rhs.id() == ID_symbol); - exprt pointer = read_rhs(symbol_exprt(pointer_id, expr.type()), loc); - assert(pointer.id() == ID_symbol); - advancert advancer(to_symbol_expr(pointer), advancer_sym.get("#member")); + unsigned init_value_level = expr.compound().get_unsigned_int(ID_it_init_value_level); + const exprt init_pointer = get_pointer(expr.compound(), init_value_level - 1); - auto adv_it = advancers.insert(advancer); - adv_it.first->add_instance(expr.get_component_name(), inst_loc_number); + list_iteratort iterator(to_symbol_expr(pointer_rhs), init_pointer, + get_iterator_fields(expr.compound())); + + auto it = iterators.insert(iterator); + it.first->add_access(expr, inst_loc_number); } + diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 3478c7468..20db8add5 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -13,7 +13,7 @@ Author: Daniel Kroening, kroening@kroening.com #include -#include +#include #include #include "ssa_domain.h" @@ -128,7 +128,7 @@ class local_SSAt var_listt params; var_sett globals_in, globals_out; - std::set advancers; + std::set iterators; // unknown heap objects var_sett unknown_objs; @@ -169,9 +169,9 @@ class local_SSAt void assign_rec( const exprt &lhs, const exprt &rhs, const exprt &guard, locationt loc); - void collect_advancers_rhs(const exprt &expr, locationt loc); - void collect_advancers_lhs(const ssa_objectt &object, locationt loc); - void new_advancer_instance(const member_exprt &expr, locationt loc, int inst_loc_number); + void collect_iterators_rhs(const exprt &expr, locationt loc); + void collect_iterators_lhs(const ssa_objectt &object, locationt loc); + void new_iterator_access(const member_exprt &expr, locationt loc, int inst_loc_number); exprt unknown_obj_eq(const symbol_exprt &obj, const struct_typet::componentt &component) const; diff --git a/src/ssa/ssa_dereference.cpp b/src/ssa/ssa_dereference.cpp index 95ae0f425..0c8286d38 100644 --- a/src/ssa/ssa_dereference.cpp +++ b/src/ssa/ssa_dereference.cpp @@ -345,6 +345,7 @@ exprt dereference_rec( irep_idt identifier="ssa::"+dyn_type_name+"_obj$unknown"; result=symbol_exprt(identifier, src.type()); + result.set("#unknown_obj", true); } else { diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index 08f0b0309..0c8e52ad3 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -549,9 +549,9 @@ exprt ssa_inlinert::get_replace_params( new_arg_out = new_pointed_arg(new_arg_out, arg_type, args_deref_out); - if(contains_advancer(params_deref_out)) + if(contains_iterator(params_deref_out)) { - // If the caller contains advancers, bindings are different since objects from caller will + // If the caller contains iterators, bindings are different since objects from caller will // appear in the callee summary assert(!args_deref_in.empty() && !args_deref_out.empty()); arg_type=SSA.ns.follow(args_deref_in.begin()->type()); @@ -1235,17 +1235,11 @@ Function: ssa_inlinert::contains_advancer \*******************************************************************/ -bool ssa_inlinert::contains_advancer(const std::list ¶ms) +bool ssa_inlinert::contains_iterator(const std::list ¶ms) { - for (const exprt &p : params) - { - if (p.id() == ID_symbol && - id2string(to_symbol_expr(p).get_identifier()).find("'adv") != std::string::npos) - { - return true; - } - } - return false; + auto it = std::find_if(params.begin(), params.end(), + [](const exprt &p) { return is_iterator(p); }); + return (it != params.end()); } exprt ssa_inlinert::param_in_transformer(const exprt ¶m) @@ -1366,4 +1360,3 @@ const exprt ssa_inlinert::new_pointed_arg(const exprt &arg, const typet &pointed return nil_exprt(); } - diff --git a/src/ssa/ssa_inliner.h b/src/ssa/ssa_inliner.h index dca7eecad..8abc6b24b 100644 --- a/src/ssa/ssa_inliner.h +++ b/src/ssa/ssa_inliner.h @@ -190,7 +190,7 @@ class ssa_inlinert:public messaget const typet &pointed_type, const std::list &args_out); - static bool contains_advancer(const std::list ¶ms); + static bool contains_iterator(const std::list ¶ms); }; #endif diff --git a/src/ssa/ssa_object.h b/src/ssa/ssa_object.h index 990b67641..9eed48f15 100644 --- a/src/ssa/ssa_object.h +++ b/src/ssa/ssa_object.h @@ -9,6 +9,7 @@ Author: Daniel Kroening, kroening@kroening.com #ifndef CPROVER_2LS_SSA_SSA_OBJECT_H #define CPROVER_2LS_SSA_SSA_OBJECT_H +#include "ssa_pointed_objects.h" #include class ssa_objectt @@ -95,6 +96,19 @@ class ssa_objectt expr.set(flag, value); } + inline void set_iterator(const irep_idt &pointer_id, const std::vector &fields) + { + assert(expr.id() == ID_symbol && expr.get_bool(ID_pointed)); + expr.set(ID_iterator, true); + expr.set(ID_it_pointer, pointer_id); + set_iterator_fields(expr, fields); + expr.set(ID_it_init_value, to_symbol_expr(expr).get_identifier()); + expr.set(ID_it_init_value_level, expr.get(ID_pointed_level)); + const irep_idt new_id = id2string(pointer_id) + id2string("'it"); + to_symbol_expr(expr).set_identifier(new_id); + identifier = identifiert(new_id); + } + protected: exprt expr; identifiert identifier; diff --git a/src/ssa/ssa_value_set.cpp b/src/ssa/ssa_value_set.cpp index 9e232b8f5..105e65f10 100644 --- a/src/ssa/ssa_value_set.cpp +++ b/src/ssa/ssa_value_set.cpp @@ -12,11 +12,13 @@ Author: Daniel Kroening, kroening@kroening.com #include #endif -#include #include +#include + #include "ssa_value_set.h" #include "ssa_dereference.h" +#include "ssa_pointed_objects.h" /*******************************************************************\ @@ -184,9 +186,9 @@ void ssa_value_domaint::assign_lhs_rec( // object? ssa_objectt ssa_object(lhs, ns); - if(ssa_object && - !(lhs.id()==ID_member && to_member_expr(lhs).compound().get_bool("#advancer"))) + if (ssa_object) { + assign_pointed_rhs_rec(rhs, ns); valuest tmp_values; assign_rhs_rec(tmp_values, rhs, ns, false, 0); @@ -371,7 +373,7 @@ void ssa_value_domaint::assign_rhs_rec_address_of( if(ssa_object) { - dest.add_to_value_set(ssa_object); + dest.value_set.insert(ssa_object); if(offset) dest.offset=true; } @@ -475,7 +477,8 @@ Function: ssa_value_domaint::valuest::merge \*******************************************************************/ -bool ssa_value_domaint::valuest::merge(const valuest &src) +bool ssa_value_domaint::valuest::merge(const valuest &src, bool is_loop_back, + const irep_idt &object_id) { bool result=false; @@ -502,10 +505,74 @@ bool ssa_value_domaint::valuest::merge(const valuest &src) } // value set - for (const ssa_objectt &v : src.value_set) + unsigned long old_size = value_set.size(); + for (auto &v : src.value_set) { - result = add_to_value_set(v) || result; + if (is_loop_back) + { + if (is_pointed(v.get_expr())) + { + unsigned level = pointed_level(v.get_expr()) - 1; + exprt expr = v.get_expr(); + + auto it = value_set.end(); + + while (level > 0) + { + const irep_idt ptr_root_id = pointer_root_id(expr); + it = std::find_if(value_set.begin(), value_set.end(), + [&ptr_root_id](const ssa_objectt &o) + { + return o.get_identifier() == ptr_root_id; + }); + if (it != value_set.end()) + break; + else + { + expr = get_pointer_root(expr, level--); + } + } + + if (it != value_set.end()) + { + if (!it->get_expr().get_bool(ID_iterator)) + { + assert(it->get_expr().get_bool(ID_pointed)); + ssa_objectt object_copy(*it); + object_copy.set_iterator(object_id, pointer_fields(v.get_expr(), level)); + value_set.erase(it); + value_set.insert(object_copy); + result = true; + } + continue; + } + } + if (is_iterator(v.get_expr())) continue; + } + else + { + if (v.get_expr().get_bool(ID_iterator)) + { + const irep_idt &corresponding_id = iterator_to_initial_id(v.get_expr(), v.get_identifier()); + + auto it = std::find_if(value_set.begin(), value_set.end(), + [&corresponding_id](const ssa_objectt &o) + { + return o.get_expr().get_bool(ID_pointed) && + (o.get_identifier() == corresponding_id); + }); + if (it != value_set.end()) + { + if (v != *it) + result = true; + value_set.erase(it); + } + } + } + value_set.insert(v); } + if (value_set.size() != old_size) + result = true; // alignment alignment=merge_alignment(alignment, src.alignment); @@ -541,7 +608,8 @@ bool ssa_value_domaint::merge( { if(v_it==value_map.end() || it->firstfirst) { - value_map.insert(v_it, *it); + if (!from->is_backwards_goto() || !is_iterator(it->first.get_root_object())) + value_map.insert(v_it, *it); result=true; it++; continue; @@ -554,7 +622,7 @@ bool ssa_value_domaint::merge( assert(v_it->first==it->first); - if(v_it->second.merge(it->second)) + if(v_it->second.merge(it->second, from->is_backwards_goto(), it->first.get_identifier())) result=true; v_it++; @@ -564,72 +632,29 @@ bool ssa_value_domaint::merge( return result; } -/*******************************************************************\ - -Function: ssa_value_domaint::valuest::add_to_value_set - - Inputs: SSA object to be added - - Outputs: True if 'this' has changed - - Purpose: Add given object to value set of this. - If value set contains both advancer (abstracts all elements - of the list except the first one) and object pointed by - advancer pointer (abstracts the first element of the list), - only advancer is preserved and #except_first is set to false. - -\*******************************************************************/ - -bool ssa_value_domaint::valuest::add_to_value_set(ssa_objectt object) +void ssa_value_domaint::assign_pointed_rhs_rec(const exprt &rhs, const namespacet &ns) { - if (value_set.find(object) == value_set.end()) + ssa_objectt ssa_object(rhs, ns); + + if(ssa_object && ssa_object.type().id()==ID_pointer) { - bool result = false; - if (object.get_expr().get_bool("#advancer")) - { // advancer is to be inserted - check if set already contains first object of corresponding - // list - const irep_idt corresp_object_id = object.get_expr().get("#object_id"); + if(ssa_object.get_root_object().get_bool("#unknown_obj")) + return; - auto it = std::find_if(value_set.begin(), value_set.end(), - [&corresp_object_id](const ssa_objectt &o) - { - return o.get_identifier() == corresp_object_id; - }); + value_mapt::const_iterator m_it=value_map.find(ssa_object); - if (it != value_set.end()) - { - value_set.erase(it); - object.set_flag("#except_first", false); - result = true; - } - } - else if (id2string(object.get_identifier()).find("'obj") != std::string::npos) - { // pointed object is to be inserted - check if set already contains corresponding advancer - const irep_idt object_id = object.get_identifier(); - - auto it = std::find_if(value_set.begin(), value_set.end(), - [&object_id](const ssa_objectt &o) - { - return id2string(o.get_identifier()).find(id2string(object_id)) != - std::string::npos && - id2string(o.get_identifier()).find("'adv") != - std::string::npos; - }); - - if (it != value_set.end()) - { - ssa_objectt new_advancer(*it); - new_advancer.set_flag("#except_first", false); - value_set.erase(it); - value_set.insert(new_advancer); - return false; - } + if(m_it==value_map.end()) + { + const symbol_exprt pointed = pointed_object(rhs, ns); + ssa_objectt pointed_obj(pointed, ns); + value_map[ssa_object].value_set.insert(pointed_obj); } - - auto inserted = value_set.insert(object); - return result || inserted.second; } - return false; + else + { + forall_operands(it, rhs) + assign_pointed_rhs_rec(*it, ns); + } } /*******************************************************************\ @@ -659,7 +684,7 @@ void ssa_value_ait::initialize(const goto_functionst::goto_functiont &goto_funct for (auto ¶m : goto_function.type.parameters()) { const symbol_exprt param_expr(param.get_identifier(), param.type()); - assign_ptr_param_rec(param_expr, entry); + assign_ptr_param(param_expr, entry); } } @@ -680,40 +705,25 @@ Function: ssa_value_ait::assign_ptr_param_rec \*******************************************************************/ -void ssa_value_ait::assign_ptr_param_rec(const exprt &expr, ssa_value_domaint &entry) +void ssa_value_ait::assign_ptr_param(const exprt &expr, ssa_value_domaint &entry) { - const typet &type = ns.follow(expr.type()); - if (type.id() == ID_pointer) + const typet &type=ns.follow(expr.type()); + if(type.id()==ID_pointer) { - if (expr.id() == ID_symbol) + if(expr.id()==ID_symbol) { // pointer variable - const symbol_exprt pointed_expr(id2string(to_symbol_expr(expr).get_identifier()) + "'obj", - type.subtype()); + symbol_exprt pointed_expr=pointed_object(expr, ns); assign(expr, pointed_expr, entry); - assign_ptr_param_rec(pointed_expr, entry); - } - else if (expr.id() == ID_member) - { // pointer member of a structure - const member_exprt &member = to_member_expr(expr); - ssa_objectt member_obj(member, ns); - symbol_exprt member_dest(id2string(member_obj.get_identifier()) + "'adv", - type.subtype()); - member_dest.set("#advancer", true); - // intially advancer abstracts all list members except first - member_dest.set("#except_first", true); - assert(member.compound().id() == ID_symbol); - // set advancer object - member_dest.set("#object_id", to_symbol_expr(member.compound()).get_identifier()); - member_dest.set("#member", member.get_component_name()); - assign(expr, member_dest, entry); + assign_ptr_param(pointed_expr, entry); } } - else if (type.id() == ID_struct) - { // split structure into fields - for (auto &component : to_struct_type(type).components()) + else if(type.id()==ID_struct) + { + // split structure into fields + for(auto &component : to_struct_type(type).components()) { const member_exprt member(expr, component.get_name(), component.type()); - assign_ptr_param_rec(member, entry); + assign_ptr_param(member, entry); } } } @@ -734,7 +744,7 @@ void ssa_value_ait::assign(const exprt &src, const exprt &dest, ssa_value_domain { ssa_objectt src_obj(src, ns); ssa_objectt dest_obj(dest, ns); - if (src_obj && dest_obj) + if(src_obj && dest_obj) { entry.value_map[src_obj].value_set.insert(dest_obj); } diff --git a/src/ssa/ssa_value_set.h b/src/ssa/ssa_value_set.h index c948ddeb8..3560083f9 100644 --- a/src/ssa/ssa_value_set.h +++ b/src/ssa/ssa_value_set.h @@ -40,10 +40,10 @@ class ssa_value_domaint:public ai_domain_baset void output(std::ostream &, const namespacet &) const; - bool merge(const valuest &src); + bool merge(const valuest &src, + bool is_loop_back=false, + const irep_idt &object_id=irep_idt()); - bool add_to_value_set(ssa_objectt object); - inline void clear() { *this=valuest(); @@ -84,6 +84,8 @@ class ssa_value_domaint:public ai_domain_baset bool offset, unsigned alignment) const; + void assign_pointed_rhs_rec(const exprt &rhs, const namespacet &ns); + static unsigned merge_alignment(unsigned a, unsigned b) { // could use lcm here @@ -110,7 +112,7 @@ class ssa_value_ait:public ait protected: virtual void initialize(const goto_functionst::goto_functiont &goto_function) override; - void assign_ptr_param_rec(const exprt &expr, ssa_value_domaint &entry); + void assign_ptr_param(const exprt &expr, ssa_value_domaint &entry); void assign(const exprt &src, const exprt &dest, ssa_value_domaint &entry); From ef2e8591011d8751d2103e03de1cc7e57e583e59 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 6 Apr 2017 15:48:23 +0200 Subject: [PATCH 062/322] Use functions from ssa_pointed_objects and propagate information about pointed objects. --- src/ssa/local_ssa.cpp | 4 ++++ src/ssa/ssa_dereference.cpp | 3 +-- src/ssa/ssa_inliner.cpp | 2 +- src/ssa/ssa_object.cpp | 8 ++++---- src/ssa/ssa_value_set.cpp | 5 +---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index f21516843..3957d135a 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -1169,6 +1169,8 @@ symbol_exprt local_SSAt::name( if(object.get_expr().source_location().is_not_nil()) new_symbol_expr.add_source_location()=object.get_expr().source_location(); + copy_pointed_info(new_symbol_expr, object.get_expr()); + return new_symbol_expr; } @@ -1218,6 +1220,8 @@ symbol_exprt local_SSAt::name_input(const ssa_objectt &object) const if(object.get_expr().source_location().is_not_nil()) new_symbol_expr.add_source_location()=object.get_expr().source_location(); + copy_pointed_info(new_symbol_expr, object.get_expr()); + return new_symbol_expr; } diff --git a/src/ssa/ssa_dereference.cpp b/src/ssa/ssa_dereference.cpp index 0c8286d38..0f487fe0f 100644 --- a/src/ssa/ssa_dereference.cpp +++ b/src/ssa/ssa_dereference.cpp @@ -330,8 +330,7 @@ exprt dereference_rec( exprt result; if (values.value_set.empty()) { - irep_idt identifier=id2string(to_symbol_expr(pointer).get_identifier())+"'obj"; - result=symbol_exprt(identifier, pointed_type); + result=pointed_object(pointer, ns); } else { diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index 0c8e52ad3..ac312e85d 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -425,7 +425,7 @@ exprt ssa_inlinert::get_replace_globals_in( it!=globals_in.end(); it++) { // bind only real globals - filter out heap objects - if(id2string(it->get_identifier()).find("'obj")==std::string::npos) + if(!is_pointed(*it)) { symbol_exprt lhs=*it; // copy rename(lhs); diff --git a/src/ssa/ssa_object.cpp b/src/ssa/ssa_object.cpp index e2d00be24..effde72f4 100644 --- a/src/ssa/ssa_object.cpp +++ b/src/ssa/ssa_object.cpp @@ -68,9 +68,7 @@ void collect_ptr_objects( const typet &type=ns.follow(src.type()); if(type.id()==ID_pointer) { - const irep_idt &identifier=id2string(src.get_identifier()) + "'obj"; - const typet &pointed_type=src.type().subtype(); - symbol_exprt ptr_object(identifier, pointed_type); + symbol_exprt ptr_object=pointed_object(src, ns); const symbolt *symbol; if(dynamic || @@ -190,7 +188,7 @@ void collect_objects_rec( if(type.id()==ID_struct) { std::string id=id2string(ssa_object.get_identifier()); - if (src.type().get_bool("#dynamic") || is_ptr_object(src)) + if (src.type().get_bool("#dynamic") || is_pointed(src)) objects.insert(ssa_object); // need to split up @@ -204,6 +202,8 @@ void collect_objects_rec( it++) { member_exprt new_src(src, it->get_name(), it->type()); + copy_pointed_info(new_src, src); + collect_objects_rec(new_src, ns, objects, literals); // recursive call } } diff --git a/src/ssa/ssa_value_set.cpp b/src/ssa/ssa_value_set.cpp index 105e65f10..bdd558857 100644 --- a/src/ssa/ssa_value_set.cpp +++ b/src/ssa/ssa_value_set.cpp @@ -84,10 +84,7 @@ void ssa_value_domaint::transform( { if (arg.id() == ID_symbol) { - const typet &pointed_type = ns.follow(arg.type().subtype()); - symbol_exprt pointed_obj = symbol_exprt( - id2string(to_symbol_expr(arg).get_identifier()) + "'obj", - pointed_type); + symbol_exprt pointed_obj = pointed_object(arg, ns); pointed_obj.type().set("#dynamic", true); assign_lhs_rec(arg, address_of_exprt(pointed_obj), ns, true); From 226cf805321caeed6029016cf7fb7d22cc8a5b85 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 6 Apr 2017 17:23:55 +0200 Subject: [PATCH 063/322] SSA heap analysis: new interprocedural analysis. Interprocedural analysis that determines which dynamic objects are created and modified within a function. TODO: switch from static_analysist to ait. --- src/ssa/ssa_heap_domain.cpp | 430 ++++++++++++++++++++++++++++++++++++ src/ssa/ssa_heap_domain.h | 74 +++++++ 2 files changed, 504 insertions(+) create mode 100644 src/ssa/ssa_heap_domain.cpp create mode 100644 src/ssa/ssa_heap_domain.h diff --git a/src/ssa/ssa_heap_domain.cpp b/src/ssa/ssa_heap_domain.cpp new file mode 100644 index 000000000..287bb398c --- /dev/null +++ b/src/ssa/ssa_heap_domain.cpp @@ -0,0 +1,430 @@ +/** + * Viktor Malik, 2/28/17 (c). + */ + +#include +#include "ssa_heap_domain.h" + +void ssa_heap_domaint::transform(const namespacet &ns, domain_baset::locationt from, + domain_baset::locationt to) +{ + if (from->is_assign()) + { + const code_assignt &assign = to_code_assign(from->code); + assign_lhs_rec(assign.lhs(), assign.rhs(), ns); + } + else if (from->is_function_call() && from->function == to->function) + { + const code_function_callt &fun_call = to_code_function_call(from->code); + assert(fun_call.function().id() == ID_symbol); + const irep_idt &fun_id = to_symbol_expr(fun_call.function()).get_identifier(); + + if (function_map.find(fun_id) != function_map.end()) + { + unsigned counter = 0; + for (auto &obj : function_map.at(fun_id).new_objects) + { + symbol_exprt new_obj = obj.first; + rename_to_caller(new_obj, from, counter); + + const symbolt *symbol; + if (!ns.lookup(new_obj.get_identifier(), symbol)) + new_obj = symbol->symbol_expr(); + + if (function_map[function].new_objects.find(new_obj) == + function_map[function].new_objects.end()) + { + function_map[function].new_objects.insert(std::make_pair(new_obj, std::set())); + } + + for (auto &expr : obj.second) + { + const exprt pointer = function_map.at(fun_id).corresponding_expr(expr, + fun_call.arguments(), 0); + + objectst old_objects = value_map[pointer]; + value_map[pointer] = {new_obj}; + + if (is_function_output(pointer, function, ns, false)) + { + function_map[function].new_objects.at(new_obj).insert(pointer); + } + + for (auto &o : old_objects) + { + if (o.id() == ID_symbol && o.type().get_bool("#dynamic") && + new_obj != o) + function_map[function].new_objects.at(to_symbol_expr(o)).erase(pointer); + } + } + } + + for (auto &obj : function_map.at(fun_id).modified_objects) + { + const exprt caller_obj = function_map.at(fun_id).corresponding_expr(obj, + fun_call.arguments(), + 0); + if (is_function_output(caller_obj, function, ns, false)) + function_map[function].modified_objects.insert(caller_obj); + } + } + } +} + +bool ssa_heap_domaint::merge(const ssa_heap_domaint &other, domain_baset::locationt to) +{ + bool result = false; + + if (to->function == "" || to->function == other.function) + { + function = other.function; + + // Merge value maps - union + for (auto &other_value : other.value_map) + { + if (value_map.find(other_value.first) == value_map.end()) + { + value_map[other_value.first] = other_value.second; + result = true; + } + else + { + unsigned long old_size = value_map[other_value.first].size(); + value_map[other_value.first].insert(other_value.second.begin(), other_value.second.end()); + result = old_size != value_map[other_value.first].size(); + } + } + } + else + { + function = to->function; + } + + for (auto &f : other.function_map) + { + auto &objects = function_map[f.first].new_objects; + const auto &other_objects = f.second.new_objects; + + if (f.first == function && function == other.function) + { + for (auto &other_object : other_objects) + { + if (objects.find(other_object.first) == objects.end()) + { + objects[other_object.first] = other_object.second; + result = true; + } + else if (!other_object.second.empty()) + { + unsigned long old_size = objects[other_object.first].size(); + std::set intersection; + std::set_intersection(objects[other_object.first].begin(), + objects[other_object.first].end(), + other_object.second.begin(), + other_object.second.end(), + std::inserter(intersection, intersection.begin())); + if (!intersection.empty()) + objects[other_object.first] = intersection; + else + objects.erase(other_object.first); + + if (old_size != objects[other_object.first].size()) + result = true; + } + } + } + else + { + for (auto &o : other_objects) + { + unsigned long old_size = objects[o.first].size(); + objects[o.first] = o.second; + if (old_size != objects[o.first].size()) + result = true; + } + } + + function_map[f.first].params = f.second.params; + + unsigned long old_size = function_map[f.first].modified_objects.size(); + function_map[f.first].modified_objects.insert(f.second.modified_objects.begin(), + f.second.modified_objects.end()); + if (old_size != function_map[f.first].modified_objects.size()) + result = true; + } + + return result; +} + +void ssa_heap_domaint::assign_rhs(const exprt &rhs, const irep_idt &function, objectst &objects, + const namespacet &ns) +{ + if (rhs.get_bool("#malloc_result")) + { + exprt malloc_result = rhs; + if (malloc_result.id() == ID_typecast) + malloc_result = to_typecast_expr(malloc_result).op(); + assert(malloc_result.id() == ID_address_of); + + const symbol_exprt new_object = to_symbol_expr(to_address_of_expr(malloc_result).object()); + + function_infot &function_info = function_map[function]; + if (function_info.new_objects.find(new_object) == function_info.new_objects.end()) + { + function_info.new_objects.insert(std::make_pair(new_object, std::set())); + } + + objects = {new_object}; + } + else if (rhs.id() == ID_typecast) + { + assign_rhs(to_typecast_expr(rhs).op(), function, objects, ns); + } + else + { + auto values = value_map.find(rhs); + if (values != value_map.end()) + { + objects = values->second; + } + } +} + +bool ssa_heap_domaint::is_function_output(const exprt &expr, const irep_idt &function, + const namespacet &ns, bool in_deref) +{ + if (expr.id() == ID_dereference) + { + return is_function_output(to_dereference_expr(expr).pointer(), function, ns, true); + } + else if (expr.id() == ID_member) + { + return is_function_output(to_member_expr(expr).compound(), function, ns, in_deref); + } + else if (expr.id() == ID_symbol) + { + const symbol_exprt &symbol_expr = to_symbol_expr(expr); + if (id2string(symbol_expr.get_identifier()).find("#return_value") != std::string::npos) + { + return symbol_expr.get_identifier() == id2string(function) + "#return_value"; + } + + const symbolt *symbol; + if (!ns.lookup(symbol_expr.get_identifier(), symbol) && + (in_deref && symbol->is_parameter || !symbol->is_procedure_local())) + return true; + } + return false; +} + +const std::set ssa_heap_domaint::value(const exprt &expr) const +{ + std::set result; + if (value_map.find(expr) != value_map.end()) + { + for (auto &value : value_map.at(expr)) + { + if (value.id() == ID_symbol) + result.insert(to_symbol_expr(value)); + } + } + return result; +} + +const std::list ssa_heap_domaint::new_objects() const +{ + return new_objects(function); +} + +const std::list ssa_heap_domaint::new_objects(const irep_idt &fname) const +{ + std::list result; + if (function_map.find(fname) != function_map.end()) + { + for (auto &obj : function_map.at(fname).new_objects) + result.push_back(obj.first); + } + return result; +} + +void ssa_heap_domaint::rename_to_caller(symbol_exprt &object, domain_baset::locationt loc, + unsigned &index) const +{ + object.set_identifier("ssa::dynamic_object$" + std::to_string(loc->location_number) + "$" + + std::to_string(index++)); +} + +const std::list ssa_heap_domaint::new_caller_objects(const irep_idt &fname, + domain_baset::locationt loc) const +{ + std::list result = new_objects(fname); + unsigned counter = 0; + for (symbol_exprt &o : result) + { + rename_to_caller(o, loc, counter); + } + return result; +} + +const std::set ssa_heap_domaint::modified_objects(const irep_idt &fname) const +{ + std::set result; + if (function_map.find(fname) != function_map.end()) + { + result = function_map.at(fname).modified_objects; + } + return result; +} + +void ssa_heap_domaint::assign_lhs_rec(const exprt &lhs, const exprt &rhs, const namespacet &ns) +{ + objectst rhs_objects; + assign_rhs(rhs, function, rhs_objects, ns); + + if (!rhs_objects.empty()) + value_map[lhs] = rhs_objects; + else + value_map.erase(lhs); + + if (is_function_output(lhs, function, ns, false)) + { + auto &objects = function_map[function].new_objects; + for (auto &o : rhs_objects) + { + if (o.id() == ID_symbol && o.type().get_bool("#dynamic")) + { + const symbol_exprt new_o = to_symbol_expr(o); + if (objects.find(new_o) != objects.end()) + { + objects[new_o].insert(lhs); + } + } + } + } + + update_modified(lhs, ns); +} + +void ssa_heap_domaint::update_modified(const exprt &expr, const namespacet &ns) +{ + if (expr.id() == ID_member) + { + update_modified(to_member_expr(expr).compound(), ns); + } + else if (expr.id() == ID_dereference) + { + for (const exprt &v : value_map[to_dereference_expr(expr).pointer()]) + { + if (is_function_output(v, function, ns, false)) + function_map[function].modified_objects.insert(v); + } + } + else + if (is_function_output(expr, function, ns, false)) + function_map[function].modified_objects.insert(expr); +} + +void ssa_heap_analysist::initialize(const goto_functionst &goto_functions) +{ + static_analysis_baset::initialize(goto_functions); + + if (goto_functions.function_map.at("main").body_available()) + { + locationt e = goto_functions.function_map.at("main").body.instructions.begin(); + ssa_heap_domaint &entry = operator[](e); + + entry.function = e->function; + + forall_goto_functions(f_it, goto_functions) + { + if (f_it->second.body_available()) + { + locationt f_e = f_it->second.body.instructions.begin(); + ssa_heap_domaint &f_entry = operator[](f_e); + for (auto ¶m : f_it->second.type.parameters()) + { + entry.function_map[f_it->first].params.push_back(param.get_identifier()); + const symbol_exprt param_expr(param.get_identifier(), param.type()); + init_ptr_param(param_expr, f_entry); + } + } + } + } +} + +void ssa_heap_analysist::init_ptr_param(const exprt &expr, ssa_heap_domaint &f_entry) +{ + const typet &type = ns.follow(expr.type()); + if (type.id() == ID_pointer) + { + const dereference_exprt dereference(expr, type.subtype()); + f_entry.value_map[expr].insert(dereference); + init_ptr_param(dereference, f_entry); + } + else if (type.id() == ID_struct) + { + assert(expr.id() == ID_dereference); + for (auto &component : to_struct_type(type).components()) + { + if (component.type().id() == ID_pointer && ns.follow(component.type().subtype()) == type) + { + const member_exprt member(expr, component.get_name(), component.type()); + f_entry.value_map[member].insert(expr); + } + } + } +} + +const exprt ssa_heap_domaint::function_infot::corresponding_expr(const exprt &expr, + const code_function_callt::argumentst &arguments, + unsigned deref_level) const +{ + if (expr.id() == ID_symbol) + { + const irep_idt expr_id = to_symbol_expr(expr).get_identifier(); + exprt result = expr; + for (unsigned i = 0; i < params.size(); ++i) + { + if (expr_id == params.at(i)) + { + result = apply_deref(arguments.at(i), deref_level); + break; + } + } + return result; + } + else if (expr.id() == ID_dereference) + { + return corresponding_expr(to_dereference_expr(expr).pointer(), arguments, deref_level + 1); + } + else if (expr.id() == ID_member) + { + return corresponding_expr(to_member_expr(expr).compound(), arguments, deref_level); + } + + assert(false); + return nil_exprt(); +} + +const exprt ssa_heap_domaint::function_infot::apply_deref(const exprt &expr, unsigned level) const +{ + if (level == 0) return expr; + + exprt deref; + if (expr.id() == ID_address_of) + { + deref = to_address_of_expr(expr).object(); + } + else if (expr.id() == ID_symbol || expr.id() == ID_dereference) + { + deref = dereference_exprt(expr, expr.type().subtype()); + } + else if (expr.id() == ID_member && to_member_expr(expr).compound().id() == ID_dereference) + { + deref = to_member_expr(expr).compound(); + } + else + assert(false); + + return apply_deref(deref, level - 1); +} diff --git a/src/ssa/ssa_heap_domain.h b/src/ssa/ssa_heap_domain.h new file mode 100644 index 000000000..2404e927c --- /dev/null +++ b/src/ssa/ssa_heap_domain.h @@ -0,0 +1,74 @@ +/** + * Viktor Malik, 2/28/17 (c). + */ +#ifndef INC_2LS_SSA_HEAP_DOMAIN_H +#define INC_2LS_SSA_HEAP_DOMAIN_H + + +#include + +class ssa_heap_domaint : public domain_baset +{ + public: + virtual void transform(const namespacet &ns, locationt from, locationt to) override; + bool merge(const ssa_heap_domaint &, locationt); + + irep_idt function; + + typedef std::set objectst; + std::map value_map; + + const std::set value(const exprt &expr) const; + + class function_infot + { + public: + std::map > new_objects; + std::set modified_objects; + std::vector params; + + const exprt corresponding_expr(const exprt &expr, + const code_function_callt::argumentst &arguments, + unsigned deref_level) const; + + + protected: + const exprt apply_deref(const exprt &expr, unsigned level) const; + }; + + std::map function_map; + + const std::list new_objects() const; + const std::list new_objects(const irep_idt &fname) const; + const std::list new_caller_objects(const irep_idt &fname, locationt loc) const; + + const std::set modified_objects(const irep_idt &fname) const; + protected: + + void assign_lhs_rec(const exprt &lhs, const exprt &rhs, const namespacet &ns); + + void assign_rhs(const exprt &rhs, const irep_idt &function, objectst &objects, + const namespacet &ns); + + bool is_function_output(const exprt &expr, const irep_idt &function, + const namespacet &ns, bool in_deref); + + void rename_to_caller(symbol_exprt &object, locationt loc, unsigned &index) const; + + void update_modified(const exprt &expr, const namespacet &ns); +}; + +class ssa_heap_analysist : public static_analysist +{ + public: + explicit ssa_heap_analysist(const namespacet &_ns) + : static_analysist(_ns) {} + + virtual void initialize(const goto_functionst &goto_functions) override; + + protected: + void init_ptr_param(const exprt &expr, ssa_heap_domaint &f_entry); +}; + + +#endif //INC_2LS_SSA_HEAP_DOMAIN_H From ae4917c4fb1f0e1fb51cd4995ab0d370b21a8608 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 6 Apr 2017 17:41:11 +0200 Subject: [PATCH 064/322] Use ssa heap analysis for SSA generation. assignments: assignments in function calls ssa_object: collect new objects created by function ssa_value_set: changes to points-to relation after function call malloc_ssa: identify dynamic object by its location --- src/2ls/2ls_parse_options.cpp | 20 +++++--- src/2ls/horn_encoding.cpp | 3 +- src/2ls/show.cpp | 67 +++++++++++++----------- src/2ls/summary_checker_ai.cpp | 2 +- src/2ls/summary_checker_ai.h | 5 +- src/2ls/summary_checker_base.cpp | 7 +-- src/2ls/summary_checker_base.h | 9 +++- src/2ls/summary_checker_bmc.cpp | 2 +- src/2ls/summary_checker_bmc.h | 4 +- src/2ls/summary_checker_kind.cpp | 2 +- src/2ls/summary_checker_kind.h | 5 +- src/2ls/summary_checker_nonterm.cpp | 2 +- src/2ls/summary_checker_nonterm.h | 5 +- src/ssa/Makefile | 3 +- src/ssa/assignments.cpp | 77 ++++++++++++---------------- src/ssa/assignments.h | 16 +++--- src/ssa/local_ssa.h | 13 +++-- src/ssa/malloc_ssa.cpp | 14 +++-- src/ssa/ssa_db.h | 7 ++- src/ssa/ssa_heap_domain.cpp | 4 +- src/ssa/ssa_heap_domain.h | 1 + src/ssa/ssa_object.cpp | 70 +++++-------------------- src/ssa/ssa_object.h | 14 ++--- src/ssa/ssa_value_set.cpp | 79 ++++++++++++++++++++++++----- src/ssa/ssa_value_set.h | 10 ++-- src/ssa/unwindable_local_ssa.h | 4 +- 26 files changed, 242 insertions(+), 203 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index cd8e78fa6..c9710a994 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -507,24 +507,31 @@ int twols_parse_optionst::doit() status() << eom; } + const namespacet ns(goto_model.symbol_table); + ssa_heap_analysist heap_analysis(ns); + if(!options.get_bool_option("inline")) + { + heap_analysis(goto_model.goto_functions); + } + try { std::unique_ptr checker; if(!options.get_bool_option("k-induction") && !options.get_bool_option("incremental-bmc")) checker=std::unique_ptr( - new summary_checker_ait(options)); + new summary_checker_ait(options, heap_analysis)); if(options.get_bool_option("k-induction") && !options.get_bool_option("incremental-bmc")) checker=std::unique_ptr( - new summary_checker_kindt(options)); + new summary_checker_kindt(options, heap_analysis)); if(!options.get_bool_option("k-induction") && options.get_bool_option("incremental-bmc")) checker=std::unique_ptr( - new summary_checker_bmct(options)); + new summary_checker_bmct(options, heap_analysis)); if(options.get_bool_option("nontermination")) checker=std::unique_ptr( - new summary_checker_nontermt(options)); + new summary_checker_nontermt(options, heap_analysis)); checker->set_message_handler(get_message_handler()); checker->simplify=!cmdline.isset("no-simplify"); @@ -1125,8 +1132,6 @@ bool twols_parse_optionst::process_goto_program( if (it->first == "malloc" || it->first == "free") it->second.body.clear(); } - // Replace malloc - replace_malloc(goto_model,""); #endif // create symbols for objects pointed by parameters @@ -1142,6 +1147,9 @@ bool twols_parse_optionst::process_goto_program( // add loop ids goto_model.goto_functions.compute_loop_numbers(); + // Replace malloc + replace_malloc(goto_model,""); + // remove loop heads from function entries remove_loops_in_entry(goto_model); diff --git a/src/2ls/horn_encoding.cpp b/src/2ls/horn_encoding.cpp index fb986a691..cacffe305 100644 --- a/src/2ls/horn_encoding.cpp +++ b/src/2ls/horn_encoding.cpp @@ -81,7 +81,8 @@ void horn_encodingt::translate( ";\n"; // compute SSA - local_SSAt local_SSA(f_it->second, ns, ""); + ssa_heap_analysist heap_analysis(ns); + local_SSAt local_SSA(f_it->second, ns, heap_analysis, ""); const goto_programt &body=f_it->second.body; diff --git a/src/2ls/show.cpp b/src/2ls/show.cpp index c81d0db95..07f1e979c 100644 --- a/src/2ls/show.cpp +++ b/src/2ls/show.cpp @@ -38,14 +38,14 @@ Function: show_assignments \*******************************************************************/ -void show_assignments( - const goto_functionst::goto_functiont &goto_function, - const namespacet &ns, - std::ostream &out) +void show_assignments(const goto_functionst::goto_functiont &goto_function, + const namespacet &ns, + std::ostream &out, + const ssa_heap_analysist &heap_analysis) { - ssa_objectst ssa_objects(goto_function, ns); - ssa_value_ait ssa_value_ai(goto_function, ns); - assignmentst assignments(goto_function.body, ns, ssa_objects, ssa_value_ai); + ssa_objectst ssa_objects(goto_function, ns, heap_analysis); + ssa_value_ait ssa_value_ai(goto_function, ns, heap_analysis); + assignmentst assignments(goto_function.body, ns, ssa_objects, ssa_value_ai, heap_analysis); assignments.output(ns, goto_function.body, out); } @@ -69,6 +69,8 @@ void show_assignments( { const namespacet ns(goto_model.symbol_table); + ssa_heap_analysist heap_analysis(ns); + if(!function.empty()) { goto_functionst::function_mapt::const_iterator @@ -76,7 +78,7 @@ void show_assignments( if(f_it==goto_model.goto_functions.function_map.end()) out << "function " << function << " not found\n"; else - show_assignments(f_it->second, ns, out); + show_assignments(f_it->second, ns, out, heap_analysis); } else { @@ -84,8 +86,8 @@ void show_assignments( { out << ">>>> Function " << f_it->first << "\n"; - show_assignments(f_it->second, ns, out); - + show_assignments(f_it->second, ns, out, heap_analysis); + out << "\n"; } } @@ -103,14 +105,14 @@ Function: show_defs \*******************************************************************/ -void show_defs( - const goto_functionst::goto_functiont &goto_function, - const namespacet &ns, - std::ostream &out) +void show_defs(const goto_functionst::goto_functiont &goto_function, + const namespacet &ns, + std::ostream &out, + const ssa_heap_analysist &heap_analysis) { - ssa_objectst ssa_objects(goto_function, ns); - ssa_value_ait ssa_value_ai(goto_function, ns); - assignmentst assignments(goto_function.body, ns, ssa_objects, ssa_value_ai); + ssa_objectst ssa_objects(goto_function, ns, heap_analysis); + ssa_value_ait ssa_value_ai(goto_function, ns, heap_analysis); + assignmentst assignments(goto_function.body, ns, ssa_objects, ssa_value_ai, heap_analysis); ssa_ait ssa_analysis(assignments); ssa_analysis(goto_function, ns); ssa_analysis.output(ns, goto_function.body, out); @@ -136,6 +138,8 @@ void show_defs( { const namespacet ns(goto_model.symbol_table); + ssa_heap_analysist heap_analysis(ns); + if(!function.empty()) { goto_functionst::function_mapt::const_iterator @@ -143,7 +147,7 @@ void show_defs( if(f_it==goto_model.goto_functions.function_map.end()) out << "function " << function << " not found\n"; else - show_defs(f_it->second, ns, out); + show_defs(f_it->second, ns, out, heap_analysis); } else { @@ -151,8 +155,8 @@ void show_defs( { out << ">>>> Function " << f_it->first << "\n"; - show_defs(f_it->second, ns, out); - + show_defs(f_it->second, ns, out, heap_analysis); + out << "\n"; } } @@ -239,7 +243,8 @@ void show_ssa( const namespacet &ns, std::ostream &out) { - local_SSAt local_SSA(goto_function, ns); + ssa_heap_analysist heap_analysis(ns); + local_SSAt local_SSA(goto_function, ns, heap_analysis); if(simplify) ::simplify(local_SSA, ns); local_SSA.output_verbose(out); @@ -555,13 +560,13 @@ Function: show_value_set \*******************************************************************/ -void show_value_set( - const goto_functionst::goto_functiont &goto_function, - const namespacet &ns, - std::ostream &out) +void show_value_set(const goto_functionst::goto_functiont &goto_function, + const namespacet &ns, + std::ostream &out, + const ssa_heap_analysist &heap_analysis) { - ssa_objectst ssa_objects(goto_function, ns); - ssa_value_ait ssa_value_ai(goto_function, ns); + ssa_objectst ssa_objects(goto_function, ns, heap_analysis); + ssa_value_ait ssa_value_ai(goto_function, ns, heap_analysis); ssa_value_ai.output(ns, goto_function, out); } @@ -585,6 +590,8 @@ void show_value_sets( { const namespacet ns(goto_model.symbol_table); + ssa_heap_analysist heap_analysis(ns); + if(!function.empty()) { goto_functionst::function_mapt::const_iterator @@ -592,7 +599,7 @@ void show_value_sets( if(f_it==goto_model.goto_functions.function_map.end()) out << "function " << function << " not found\n"; else - show_value_set(f_it->second, ns, out); + show_value_set(f_it->second, ns, out, heap_analysis); } else { @@ -600,8 +607,8 @@ void show_value_sets( { out << ">>>> Function " << f_it->first << "\n"; - show_value_set(f_it->second, ns, out); - + show_value_set(f_it->second, ns, out, heap_analysis); + out << "\n"; } } diff --git a/src/2ls/summary_checker_ai.cpp b/src/2ls/summary_checker_ai.cpp index d11a9c6d7..765090016 100644 --- a/src/2ls/summary_checker_ai.cpp +++ b/src/2ls/summary_checker_ai.cpp @@ -28,7 +28,7 @@ property_checkert::resultt summary_checker_ait::operator()( { const namespacet ns(goto_model.symbol_table); - SSA_functions(goto_model, ns); + SSA_functions(goto_model, ns, heap_analysis); ssa_unwinder.init(false, false); diff --git a/src/2ls/summary_checker_ai.h b/src/2ls/summary_checker_ai.h index 84eab2bf0..600c1fce6 100644 --- a/src/2ls/summary_checker_ai.h +++ b/src/2ls/summary_checker_ai.h @@ -14,8 +14,9 @@ Author: Peter Schrammel class summary_checker_ait:public summary_checker_baset { public: - explicit summary_checker_ait(optionst &_options): - summary_checker_baset(_options) + inline summary_checker_ait( + optionst &_options, const ssa_heap_analysist &heap_analysis): + summary_checker_baset(_options, heap_analysis) { } diff --git a/src/2ls/summary_checker_base.cpp b/src/2ls/summary_checker_base.cpp index 9caddfe84..6f740ad17 100644 --- a/src/2ls/summary_checker_base.cpp +++ b/src/2ls/summary_checker_base.cpp @@ -53,7 +53,8 @@ Function: summary_checker_baset::SSA_functions void summary_checker_baset::SSA_functions( const goto_modelt &goto_model, - const namespacet &ns) + const namespacet &ns, + const ssa_heap_analysist &heap_analysis) { // compute SSA for all the functions forall_goto_functions(f_it, goto_model.goto_functions) @@ -64,9 +65,9 @@ void summary_checker_baset::SSA_functions( continue; status() << "Computing SSA of " << f_it->first << messaget::eom; - ssa_db.create(f_it->first, f_it->second, ns); + ssa_db.create(f_it->first, f_it->second, ns, heap_analysis); local_SSAt &SSA=ssa_db.get(f_it->first); - + // simplify, if requested if(simplify) { diff --git a/src/2ls/summary_checker_base.h b/src/2ls/summary_checker_base.h index 2dfd88bb2..653bd9881 100644 --- a/src/2ls/summary_checker_base.h +++ b/src/2ls/summary_checker_base.h @@ -14,6 +14,7 @@ Author: Peter Schrammel #include #include +#include #include #include #include @@ -27,7 +28,7 @@ class graphml_witness_extt; class summary_checker_baset:public property_checkert { public: - explicit summary_checker_baset(optionst &_options): + inline summary_checker_baset(optionst &_options, const ssa_heap_analysist &_heap_analysis) : show_vcc(false), simplify(false), fixed_point(false), @@ -35,6 +36,7 @@ class summary_checker_baset:public property_checkert ssa_db(_options), summary_db(), ssa_unwinder(ssa_db), ssa_inliner(summary_db), + heap_analysis(_heap_analysis), solver_instances(0), solver_calls(0), summaries_used(0), @@ -62,6 +64,8 @@ class summary_checker_baset:public property_checkert ssa_unwindert ssa_unwinder; ssa_inlinert ssa_inliner; + const ssa_heap_analysist &heap_analysis; + unsigned solver_instances; unsigned solver_calls; unsigned summaries_used; @@ -73,7 +77,8 @@ class summary_checker_baset:public property_checkert const goto_programt::const_targett, const local_SSAt::nodet::assertionst::const_iterator &); - void SSA_functions(const goto_modelt &, const namespacet &ns); + void SSA_functions(const goto_modelt &, const namespacet &ns, + const ssa_heap_analysist &heap_analysis); void summarize( const goto_modelt &, diff --git a/src/2ls/summary_checker_bmc.cpp b/src/2ls/summary_checker_bmc.cpp index 38e9e925e..4682e2cf8 100644 --- a/src/2ls/summary_checker_bmc.cpp +++ b/src/2ls/summary_checker_bmc.cpp @@ -26,7 +26,7 @@ property_checkert::resultt summary_checker_bmct::operator()( { const namespacet ns(goto_model.symbol_table); - SSA_functions(goto_model, ns); + SSA_functions(goto_model, ns, heap_analysis); ssa_unwinder.init(false, true); diff --git a/src/2ls/summary_checker_bmc.h b/src/2ls/summary_checker_bmc.h index 5885f6b36..ecb6c71c2 100644 --- a/src/2ls/summary_checker_bmc.h +++ b/src/2ls/summary_checker_bmc.h @@ -14,8 +14,8 @@ Author: Peter Schrammel class summary_checker_bmct:public summary_checker_baset { public: - explicit summary_checker_bmct(optionst &_options): - summary_checker_baset(_options) + inline summary_checker_bmct(optionst &_options, const ssa_heap_analysist &heap_analysis) : + summary_checker_baset(_options, heap_analysis) { } diff --git a/src/2ls/summary_checker_kind.cpp b/src/2ls/summary_checker_kind.cpp index 5c13a3a92..330fe62b6 100644 --- a/src/2ls/summary_checker_kind.cpp +++ b/src/2ls/summary_checker_kind.cpp @@ -27,7 +27,7 @@ property_checkert::resultt summary_checker_kindt::operator()( { const namespacet ns(goto_model.symbol_table); - SSA_functions(goto_model, ns); + SSA_functions(goto_model, ns, heap_analysis); ssa_unwinder.init(true, false); diff --git a/src/2ls/summary_checker_kind.h b/src/2ls/summary_checker_kind.h index 930c593f1..77e8885d8 100644 --- a/src/2ls/summary_checker_kind.h +++ b/src/2ls/summary_checker_kind.h @@ -14,8 +14,9 @@ Author: Peter Schrammel class summary_checker_kindt:public summary_checker_baset { public: - explicit summary_checker_kindt(optionst &_options): - summary_checker_baset(_options) + inline summary_checker_kindt( + optionst &_options, const ssa_heap_analysist &heap_analysis): + summary_checker_baset(_options, heap_analysis) { } diff --git a/src/2ls/summary_checker_nonterm.cpp b/src/2ls/summary_checker_nonterm.cpp index c8166a828..9c5bd6705 100644 --- a/src/2ls/summary_checker_nonterm.cpp +++ b/src/2ls/summary_checker_nonterm.cpp @@ -34,7 +34,7 @@ property_checkert::resultt summary_checker_nontermt::operator()( { const namespacet ns(goto_model.symbol_table); - SSA_functions(goto_model, ns); + SSA_functions(goto_model, ns, heap_analysis); ssa_unwinder.init(false, true); diff --git a/src/2ls/summary_checker_nonterm.h b/src/2ls/summary_checker_nonterm.h index 18992b169..48245e20e 100644 --- a/src/2ls/summary_checker_nonterm.h +++ b/src/2ls/summary_checker_nonterm.h @@ -14,8 +14,9 @@ Author: Stefan Marticek class summary_checker_nontermt:public summary_checker_baset { public: - explicit summary_checker_nontermt(optionst &_options): - summary_checker_baset(_options) + explicit summary_checker_nontermt( + optionst &_options, const ssa_heap_analysist &heap_analysis): + summary_checker_baset(_options, heap_analysis) { } diff --git a/src/ssa/Makefile b/src/ssa/Makefile index ecb631819..788963786 100644 --- a/src/ssa/Makefile +++ b/src/ssa/Makefile @@ -1,5 +1,6 @@ SRC = local_ssa.cpp ssa_var_collector.cpp \ - ssa_domain.cpp translate_union_member.cpp malloc_ssa.cpp ssa_pointed_objects.cpp \ + ssa_domain.cpp translate_union_member.cpp \ + malloc_ssa.cpp ssa_pointed_objects.cpp ssa_heap_domain.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 \ diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index ecb0bc684..382af3427 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -7,9 +7,11 @@ Author: Daniel Kroening, kroening@kroening.com \*******************************************************************/ #include +#include #include "assignments.h" #include "ssa_dereference.h" +#include "local_ssa.h" /*******************************************************************\ @@ -49,65 +51,52 @@ void assignmentst::build_assignment_map( const code_function_callt &code_function_call= to_code_function_call(it->code); - // functions may alter state almost arbitrarily: - // * any global-scoped variables - // * any dirty locals + // Get information from ssa_heap_analysis + auto n_it=it; ++n_it; + const irep_idt fname=to_symbol_expr(code_function_call.function()).get_identifier(); + std::list new_objects; + std::set modified_objects; + new_objects=ssa_heap_analysis[n_it].new_caller_objects(fname, it); + modified_objects=ssa_heap_analysis[n_it].modified_objects(fname); - for(objectst::const_iterator - o_it=ssa_objects.dirty_locals.begin(); - o_it!=ssa_objects.dirty_locals.end(); o_it++) + // Assign new objects + for(auto &o : new_objects) { - bool declared = false; - forall_goto_program_instructions(other_it, goto_program) - { - if (it == other_it) break; - if (assigns(other_it, *o_it)) declared = true; - } - if (declared) - assign(*o_it, it, ns); + assign(o, it, ns); } for(objectst::const_iterator o_it=ssa_objects.globals.begin(); o_it!=ssa_objects.globals.end(); o_it++) { - bool assigned = false; - const exprt &root_obj = o_it->get_root_object(); - if (is_ptr_object(root_obj)) - { // assign objects pointed by return value of the function - const exprt &function = code_function_call.function(); - if (function.id() == ID_symbol && - id2string(o_it->get_identifier()).find( - id2string(to_symbol_expr(function).get_identifier())) != - std::string::npos) - assigned = true; - } - else - { // assign return value of the function - if (id2string(o_it->get_identifier()).find("#return_value") == std::string::npos) - assigned = true; - } - - if (assigned) + if (id2string(o_it->get_identifier()) == id2string(fname) + "#return_value") assign(*o_it, it, ns); } - // assign objects pointed by arguments of the function - for (auto &arg : code_function_call.arguments()) + // Assign all modified objects + for (auto &modified : modified_objects) { - if (arg.type().id() == ID_pointer) + const exprt arg = ssa_heap_analysis[n_it].function_map.at(fname).corresponding_expr( + modified, code_function_call.arguments(), 0); + + if (arg != modified) { - exprt arg_ptr = arg; - do + const exprt arg_deref = dereference(arg, ssa_value_ai[it], "", ns); + assign(arg_deref, it, ns); + + std::set symbols; + find_symbols(arg_deref, symbols); + for (auto &symbol : symbols) { - // Dereference argument in next location (to include potential new objects after - // the function call) - auto n_it = it; ++n_it; - arg_ptr = dereference(dereference_exprt(arg_ptr, arg_ptr.type().subtype()), - ssa_value_ai[n_it], "", ns); - assign(arg_ptr, it, ns); + if (symbol.type() == arg_deref.type()) + { + auto &aliases = ssa_value_ai[n_it](symbol, ns).value_set; + for (auto &alias : aliases) + { + assign(alias.get_expr(), it, ns); + } + } } - while (arg_ptr.type().id() == ID_pointer); } } diff --git a/src/ssa/assignments.h b/src/ssa/assignments.h index 28b36d608..4d19f681e 100644 --- a/src/ssa/assignments.h +++ b/src/ssa/assignments.h @@ -21,6 +21,7 @@ class assignmentst const ssa_objectst &ssa_objects; const ssa_value_ait &ssa_value_ai; + const ssa_heap_analysist &ssa_heap_analysis; typedef ssa_objectst::objectst objectst; @@ -42,13 +43,14 @@ class assignmentst return it->second; } - explicit assignmentst( - const goto_programt &_goto_program, - const namespacet &_ns, - const ssa_objectst &_ssa_objects, - const ssa_value_ait &_ssa_value_ai): - ssa_objects(_ssa_objects), - ssa_value_ai(_ssa_value_ai) + explicit assignmentst(const goto_programt &_goto_program, + const namespacet &_ns, + const ssa_objectst &_ssa_objects, + const ssa_value_ait &_ssa_value_ai, + const ssa_heap_analysist &_ssa_heap_analysis) : + ssa_objects(_ssa_objects), + ssa_value_ai(_ssa_value_ai), + ssa_heap_analysis(_ssa_heap_analysis) { build_assignment_map(_goto_program, _ns); } diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 20db8add5..2c54b3c0f 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -19,6 +19,7 @@ Author: Daniel Kroening, kroening@kroening.com #include "ssa_domain.h" #include "guard_map.h" #include "ssa_object.h" +#include "ssa_heap_domain.h" #define TEMPLATE_PREFIX "__CPROVER_template" #define TEMPLATE_DECL TEMPLATE_PREFIX @@ -34,11 +35,13 @@ class local_SSAt inline local_SSAt( const goto_functiont &_goto_function, const namespacet &_ns, - const std::string &_suffix=""): + const ssa_heap_analysist &_heap_analysis, + const std::string &_suffix = "") : ns(_ns), goto_function(_goto_function), - ssa_objects(_goto_function, ns), - ssa_value_ai(_goto_function, ns), - assignments(_goto_function.body, ns, ssa_objects, ssa_value_ai), + heap_analysis(_heap_analysis), + ssa_objects(_goto_function, ns, _heap_analysis), + ssa_value_ai(_goto_function, ns, _heap_analysis), + assignments(_goto_function.body, ns, ssa_objects, ssa_value_ai, heap_analysis), guard_map(_goto_function.body), ssa_analysis(assignments), suffix(_suffix) @@ -182,6 +185,8 @@ class local_SSAt exprt dereference(const exprt &expr, locationt loc) const; + const ssa_heap_analysist &heap_analysis; + ssa_objectst ssa_objects; typedef ssa_objectst::objectst objectst; ssa_value_ait ssa_value_ai; diff --git a/src/ssa/malloc_ssa.cpp b/src/ssa/malloc_ssa.cpp index 9a51ba3f9..2c11f358f 100644 --- a/src/ssa/malloc_ssa.cpp +++ b/src/ssa/malloc_ssa.cpp @@ -188,20 +188,19 @@ static void replace_malloc_rec( const std::string &suffix, symbol_tablet &symbol_table, const exprt &malloc_size, - unsigned &counter) + unsigned loc_number) { if(expr.id()==ID_side_effect && to_side_effect_expr(expr).get_statement()==ID_malloc) { assert(!malloc_size.is_nil()); expr.op0()=malloc_size; - - expr=malloc_ssa(to_side_effect_expr(expr), - "$"+i2string(counter++)+suffix, symbol_table); + + expr=malloc_ssa(to_side_effect_expr(expr),"$"+std::to_string(loc_number)+suffix,symbol_table); } else - Forall_operands(it, expr) - replace_malloc_rec(*it, suffix, symbol_table, malloc_size, counter); + Forall_operands(it,expr) + replace_malloc_rec(*it,suffix,symbol_table,malloc_size,loc_number); } /*******************************************************************\ @@ -220,7 +219,6 @@ void replace_malloc( goto_modelt &goto_model, const std::string &suffix) { - unsigned counter=0; Forall_goto_functions(f_it, goto_model.goto_functions) { exprt malloc_size=nil_exprt(); @@ -242,7 +240,7 @@ void replace_malloc( malloc_size=code_assign.rhs(); } replace_malloc_rec(code_assign.rhs(), suffix, - goto_model.symbol_table, malloc_size, counter); + goto_model.symbol_table, malloc_size, i_it->location_number); } } } diff --git a/src/ssa/ssa_db.h b/src/ssa/ssa_db.h index c7c92ed91..958c969b5 100644 --- a/src/ssa/ssa_db.h +++ b/src/ssa/ssa_db.h @@ -12,6 +12,7 @@ Author: Peter Schrammel #include #include +#include #include #include @@ -64,9 +65,11 @@ class ssa_dbt inline void create( const function_namet &function_name, const goto_functionst::goto_functiont &goto_function, - const namespacet &ns) + const namespacet &ns, + const ssa_heap_analysist &heap_analysis) { - store[function_name]=new unwindable_local_SSAt(goto_function, ns); + store[function_name]= + new unwindable_local_SSAt(goto_function, ns, heap_analysis); } protected: diff --git a/src/ssa/ssa_heap_domain.cpp b/src/ssa/ssa_heap_domain.cpp index 287bb398c..d5c7a8fdb 100644 --- a/src/ssa/ssa_heap_domain.cpp +++ b/src/ssa/ssa_heap_domain.cpp @@ -210,8 +210,8 @@ bool ssa_heap_domaint::is_function_output(const exprt &expr, const irep_idt &fun } const symbolt *symbol; - if (!ns.lookup(symbol_expr.get_identifier(), symbol) && - (in_deref && symbol->is_parameter || !symbol->is_procedure_local())) + if(!ns.lookup(symbol_expr.get_identifier(), symbol) && + ((in_deref && symbol->is_parameter) || !symbol->is_procedure_local())) return true; } return false; diff --git a/src/ssa/ssa_heap_domain.h b/src/ssa/ssa_heap_domain.h index 2404e927c..a0e874071 100644 --- a/src/ssa/ssa_heap_domain.h +++ b/src/ssa/ssa_heap_domain.h @@ -4,6 +4,7 @@ #ifndef INC_2LS_SSA_HEAP_DOMAIN_H #define INC_2LS_SSA_HEAP_DOMAIN_H +#define USE_DEPRECATED_STATIC_ANALYSIS_H #include diff --git a/src/ssa/ssa_object.cpp b/src/ssa/ssa_object.cpp index effde72f4..31763b878 100644 --- a/src/ssa/ssa_object.cpp +++ b/src/ssa/ssa_object.cpp @@ -18,6 +18,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include "ssa_object.h" +#include "local_ssa.h" /*******************************************************************\ @@ -157,15 +158,6 @@ void collect_objects_rec( { forall_operands(it, src) collect_objects_rec(*it, ns, objects, literals); - - const codet &code=to_code(src); - if (code.get_statement()==ID_function_call) - { - const code_function_callt &function_call=to_code_function_call(code); - for (auto &arg : function_call.arguments()) - collect_ptr_objects(arg, ns, objects, literals, true); - } - return; } else if(src.id()==ID_address_of) @@ -219,9 +211,13 @@ void collect_objects_rec( const symbolt *symbol; if(ssa_object.type().get_bool("#dynamic") || (root_object.id()==ID_symbol && + id2string(to_symbol_expr(root_object).get_identifier()).find("#return_value") == + std::string::npos && !ns.lookup(to_symbol_expr(root_object).get_identifier(), symbol) && (symbol->is_parameter || !symbol->is_procedure_local()))) + { collect_ptr_objects(ssa_object.symbol_expr(), ns, objects, literals, false); + } } } else @@ -243,9 +239,7 @@ Function: ssa_objectst::collect_objects \*******************************************************************/ -void ssa_objectst::collect_objects( - const goto_functionst::goto_functiont &src, - const namespacet &ns) +void ssa_objectst::collect_objects(const goto_functionst::goto_functiont &src, const namespacet &ns) { // Add objects for parameters. for(goto_functionst::goto_functiont::parameter_identifierst:: @@ -264,58 +258,18 @@ void ssa_objectst::collect_objects( collect_objects_rec(it->guard, ns, objects, literals); collect_objects_rec(it->code, ns, objects, literals); } -} - -/*******************************************************************\ - -Function: ssa_objectst::add_ptr_objects - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -void ssa_objectst::add_ptr_objects( - const goto_functionst::goto_functiont &goto_function, - const namespacet &ns) -{ - objectst tmp; - - for(objectst::const_iterator o_it=objects.begin(); - o_it!=objects.end(); - o_it++) + // Add new objects created within the function + local_SSAt::locationt exit=--(src.body.instructions.end()); + if (heap_analysis.has_location(exit)) { - exprt root_object=o_it->get_root_object(); - if(root_object.id()==ID_symbol) + const std::list &new_objects=heap_analysis[exit].new_objects(); + for(const symbol_exprt &o : new_objects) { - const symbolt &symbol = ns.lookup(root_object); - dirtyt dirty(goto_function); - if(o_it->type().id()==ID_pointer && - (symbol.is_parameter || !symbol.is_procedure_local() || dirty(symbol.name))) - { - tmp.insert(*o_it); - } + collect_objects_rec(o, ns, objects, literals); } } - for(objectst::const_iterator o_it=tmp.begin(); - o_it!=tmp.end(); - o_it++) - { - typet type = o_it->type(); - irep_idt identifier = o_it->get_identifier(); - do - { - type = type.subtype(); - identifier = id2string(identifier) + "'obj"; - symbol_exprt ptr_object(identifier, type); - ptr_object.set(ID_ptr_object, o_it->get_identifier()); - collect_objects_rec(ptr_object, ns, objects, literals); - } while (ns.follow(type).id() == ID_pointer); - } } /*******************************************************************\ diff --git a/src/ssa/ssa_object.h b/src/ssa/ssa_object.h index 9eed48f15..80384a03a 100644 --- a/src/ssa/ssa_object.h +++ b/src/ssa/ssa_object.h @@ -11,6 +11,7 @@ Author: Daniel Kroening, kroening@kroening.com #include "ssa_pointed_objects.h" #include +#include "ssa_heap_domain.h" class ssa_objectt { @@ -128,9 +129,12 @@ class ssa_objectst typedef std::set literalst; literalst literals; - ssa_objectst( - const goto_functionst::goto_functiont &goto_function, - const namespacet &ns) + const ssa_heap_analysist &heap_analysis; + + ssa_objectst(const goto_functionst::goto_functiont &goto_function, + const namespacet &ns, + const ssa_heap_analysist &_heap_analysis) + : heap_analysis(_heap_analysis) { collect_objects(goto_function, ns); categorize_objects(goto_function, ns); @@ -144,10 +148,6 @@ class ssa_objectst void categorize_objects( const goto_functionst::goto_functiont &, const namespacet &); - - void add_ptr_objects( - const goto_functionst::goto_functiont &, - const namespacet &); }; bool is_ptr_object(const exprt &); diff --git a/src/ssa/ssa_value_set.cpp b/src/ssa/ssa_value_set.cpp index bdd558857..d6803682a 100644 --- a/src/ssa/ssa_value_set.cpp +++ b/src/ssa/ssa_value_set.cpp @@ -60,6 +60,9 @@ void ssa_value_domaint::transform( { const code_function_callt &code_function_call= to_code_function_call(from->code); + const irep_idt &fname = to_symbol_expr(code_function_call.function()).get_identifier(); + + const ssa_heap_domaint &heap_domain = static_cast(ai).heap_analysis[to]; // functions may alter state almost arbitrarily: // * any global-scoped variables @@ -77,9 +80,12 @@ void ssa_value_domaint::transform( assign(*o_it, it, ns); #endif + std::list objects; + for (auto &argument : code_function_call.arguments()) { exprt arg = argument; + exprt arg_expr = argument; while (arg.type().id() == ID_pointer) { if (arg.id() == ID_symbol) @@ -87,13 +93,33 @@ void ssa_value_domaint::transform( symbol_exprt pointed_obj = pointed_object(arg, ns); pointed_obj.type().set("#dynamic", true); - assign_lhs_rec(arg, address_of_exprt(pointed_obj), ns, true); + std::set new_objects = heap_domain.value(arg_expr); + if (new_objects.empty()) + { + new_objects.insert(pointed_obj); + } + + auto it = new_objects.begin(); + assign_lhs_rec(arg, address_of_exprt(*it), ns); + objects.push_back(*it); + + for (++it; it != new_objects.end(); ++it) + { + assign_lhs_rec(arg, address_of_exprt(*it), ns, true); + objects.push_back(*it); + } + arg_expr = dereference_exprt(arg_expr, arg.type().subtype()); arg = pointed_obj; } else if (arg.id() == ID_address_of) { - arg = to_address_of_expr(arg).object(); + arg = arg_expr = to_address_of_expr(arg).object(); + } + else if (arg.id() == ID_typecast) + { + assert(arg_expr.id() == ID_typecast); + arg = arg_expr = to_typecast_expr(arg).op(); } } } @@ -110,17 +136,39 @@ void ssa_value_domaint::transform( { const symbol_exprt &return_value = to_symbol_expr(to_code_assign(to->code).rhs()); if (return_value.type().id() == ID_pointer && - return_value.get_identifier() == - id2string(to_symbol_expr(code_function_call.function()).get_identifier()) + - "#return_value") + return_value.get_identifier() == id2string(fname) + "#return_value") { - const typet &pointed_type = ns.follow(return_value.type().subtype()); - symbol_exprt pointed_obj = symbol_exprt( - id2string(return_value.get_identifier()) + "'obj", - pointed_type); - pointed_obj.type().set("#dynamic", true); + std::set new_objects = heap_domain.value(return_value); + if (new_objects.empty()) + { + symbol_exprt pointed_obj = pointed_object(return_value, ns); + pointed_obj.type().set("#dynamic", true); + new_objects.insert(pointed_obj); + } + + auto it = new_objects.begin(); + assign_lhs_rec(return_value, address_of_exprt(*it), ns); + objects.push_back(*it); + + for (++it; it != new_objects.end(); ++it) + { + assign_lhs_rec(return_value, address_of_exprt(*it), ns, true); + objects.push_back(*it); + } + + for (auto &new_o : heap_domain.new_caller_objects(fname, from)) + { + objects.push_back(new_o); + } + } + } - assign_lhs_rec(return_value, address_of_exprt(pointed_obj), ns); + for (const symbol_exprt &o1 : objects) + { + for (const symbol_exprt &o2 : objects) + { + if (o1 != o2 && o1.type() == o2.type()) + value_map[ssa_objectt(o1, ns)].value_set.insert(ssa_objectt(o2, ns)); } } } @@ -167,13 +215,20 @@ void ssa_value_domaint::assign_lhs_rec( const struct_typet &struct_type=to_struct_type(lhs_type); const struct_typet::componentst &components=struct_type.components(); + auto rhs_it= + rhs.id()==ID_struct ? rhs.operands().begin() : rhs.operands().end(); + for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { member_exprt new_lhs(lhs, it->get_name(), it->type()); - member_exprt new_rhs(rhs, it->get_name(), it->type()); + exprt new_rhs; + if (rhs_it != rhs.operands().end()) + new_rhs = *(rhs_it++); + else + new_rhs = member_exprt(rhs, it->get_name(), it->type()); assign_lhs_rec(new_lhs, new_rhs, ns, add); // recursive call } diff --git a/src/ssa/ssa_value_set.h b/src/ssa/ssa_value_set.h index 3560083f9..a2f0d5fbe 100644 --- a/src/ssa/ssa_value_set.h +++ b/src/ssa/ssa_value_set.h @@ -12,6 +12,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include "ssa_object.h" +#include "ssa_heap_domain.h" class ssa_value_domaint:public ai_domain_baset { @@ -102,9 +103,10 @@ class ssa_value_domaint:public ai_domain_baset class ssa_value_ait:public ait { public: - ssa_value_ait( - const goto_functionst::goto_functiont &goto_function, - const namespacet &ns_) : ns(ns_) + ssa_value_ait(const goto_functionst::goto_functiont &goto_function, + const namespacet &ns_, + const ssa_heap_analysist &_heap_analysis) + : ns(ns_), heap_analysis(_heap_analysis) { operator()(goto_function, ns_); } @@ -118,6 +120,8 @@ class ssa_value_ait:public ait const namespacet &ns; + const ssa_heap_analysist &heap_analysis; + friend class ssa_value_domaint; }; diff --git a/src/ssa/unwindable_local_ssa.h b/src/ssa/unwindable_local_ssa.h index 462e89169..3e7cf337b 100644 --- a/src/ssa/unwindable_local_ssa.h +++ b/src/ssa/unwindable_local_ssa.h @@ -12,6 +12,7 @@ Author: Peter Schrammel, Saurabh Joshi #include #include "local_ssa.h" +#include "ssa_heap_domain.h" class unwindable_local_SSAt:public local_SSAt { @@ -19,8 +20,9 @@ class unwindable_local_SSAt:public local_SSAt unwindable_local_SSAt( const goto_functiont &_goto_function, const namespacet &_ns, + const ssa_heap_analysist &heap_analysis, const std::string &_suffix=""): - local_SSAt(_goto_function, _ns, _suffix), + local_SSAt(_goto_function, _ns, heap_analysis, _suffix), current_unwinding(-1) { compute_loop_hierarchy(); From 2a22a79aebd130a988b7c596b172ac697768fd0b Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 6 Apr 2017 17:53:25 +0200 Subject: [PATCH 065/322] Add all dynamic objects to symbol table (after running SSA heap analysis). --- src/2ls/2ls_parse_options.cpp | 1 + src/2ls/2ls_parse_options.h | 1 + src/2ls/preprocessing_util.cpp | 48 ++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index c9710a994..0e64e87b3 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -512,6 +512,7 @@ int twols_parse_optionst::doit() if(!options.get_bool_option("inline")) { heap_analysis(goto_model.goto_functions); + add_dynamic_object_symbols(heap_analysis, goto_model); } try diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index 68dea5b5b..f93bae489 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -177,6 +177,7 @@ class twols_parse_optionst: void remove_loops_in_entry(goto_modelt &goto_model); void create_dynamic_objects(goto_modelt &goto_model); void add_dynamic_object_rec(exprt &expr, symbol_tablet &symbol_table); + void add_dynamic_object_symbols(const ssa_heap_analysist &heap_analysis, goto_modelt &goto_model); }; #endif diff --git a/src/2ls/preprocessing_util.cpp b/src/2ls/preprocessing_util.cpp index dff5120e9..6e5a03565 100644 --- a/src/2ls/preprocessing_util.cpp +++ b/src/2ls/preprocessing_util.cpp @@ -490,6 +490,7 @@ void twols_parse_optionst::remove_loops_in_entry(goto_modelt &goto_model) { auto new_entry= f_it->second.body.insert_before(f_it->second.body.instructions.begin()); + new_entry->function=f_it->first; new_entry->make_skip(); } } @@ -571,3 +572,50 @@ void twols_parse_optionst::add_dynamic_object_rec( add_dynamic_object_rec(*it, symbol_table); } } + +/*******************************************************************\ + +Function: twols_parse_optionst::add_dynamic_object_symbols + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void twols_parse_optionst::add_dynamic_object_symbols( + const ssa_heap_analysist &heap_analysis, + goto_modelt &goto_model) +{ + forall_goto_functions(f_it, goto_model.goto_functions) + { + forall_goto_program_instructions(i_it, f_it->second.body) + { + if(i_it->is_function_call()) + { + auto &fun_call=to_code_function_call(i_it->code); + const irep_idt fname= + to_symbol_expr(fun_call.function()).get_identifier(); + auto n_it=i_it; ++n_it; + for(auto &o : heap_analysis[n_it].new_caller_objects(fname, i_it)) + { + // New symbol + symbolt object_symbol; + + object_symbol.name=o.get_identifier(); + object_symbol.base_name=id2string(object_symbol.name).substr(5); + object_symbol.is_lvalue=true; + + object_symbol.type=o.type(); + object_symbol.type.set("#dynamic", true); + + object_symbol.mode=ID_C; + + goto_model.symbol_table.add(object_symbol); + } + } + } + } +} From 2a1454ca3045e96dcc8ef7a4e8557c7a93f6751b Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 7 Apr 2017 08:09:04 +0200 Subject: [PATCH 066/322] Change collection of variables for calling context. Collect arguments and all dynamic objects only. --- .../template_generator_callingcontext.cpp | 46 ++----------------- 1 file changed, 4 insertions(+), 42 deletions(-) diff --git a/src/domains/template_generator_callingcontext.cpp b/src/domains/template_generator_callingcontext.cpp index 966beff3f..437415cdf 100644 --- a/src/domains/template_generator_callingcontext.cpp +++ b/src/domains/template_generator_callingcontext.cpp @@ -93,7 +93,8 @@ void template_generator_callingcontextt::collect_variables_callingcontext( v_it!=cs_globals_in.end(); v_it++) { symbol_exprt dummy; - if(ssa_inlinert::find_corresponding_symbol(*v_it, globals_in, dummy)) + if (ssa_inlinert::find_corresponding_symbol(*v_it, globals_in, dummy) || + id2string(v_it->get_identifier()).find("dynamic_object$") != std::string::npos) add_var( *v_it, guard, @@ -107,56 +108,17 @@ void template_generator_callingcontextt::collect_variables_callingcontext( if(!forward) return; + std::set args; // add function arguments for(exprt::operandst::const_iterator a_it=f_it->arguments().begin(); a_it!=f_it->arguments().end(); a_it++) { - std::set args; find_symbols(*a_it,args); exprt arg=*a_it; - // add objects pointed by arguments - while(arg.type().id()==ID_pointer) - { - if(arg.id()==ID_symbol) - { // remove SSA suffix (for querying value analysis) - const std::string id=id2string(to_symbol_expr(arg).get_identifier()); - to_symbol_expr(arg).set_identifier(id.substr(0, id.find_last_of('#'))); - } - // query value analysis - exprt deref_arg=SSA.dereference( - dereference_exprt(arg, arg.type().subtype()), n_it->location); - debug() << "Argument " << from_expr(SSA.ns, "", arg) << " deref: " - << from_expr(SSA.ns, "", deref_arg) << eom; - - // Find all symbols in dereferenced expression and add them to var_specs - std::set vars; - find_symbols(deref_arg, vars); - - for(auto &var : vars) - { - if(var.type().id()==ID_struct) - { - // need to split the struct into members - for (auto &component : to_struct_type(var.type()).components()) - { - const symbol_exprt member( - id2string(var.get_identifier())+"."+id2string(component.get_name()), - component.type()); - - args.insert(to_symbol_expr(SSA.read_rhs(member, n_it->location))); - } - } - else - args.insert(to_symbol_expr(SSA.read_rhs(var, n_it->location))); - } - - arg=deref_arg; - } - - add_vars(args, guard, guard, domaint::OUT, var_specs); } + add_vars(args, guard, guard, domaint::OUT, var_specs); } /*******************************************************************\ From 4aa43f419b51b9ffbd097e5028721e6da2069b7e Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 7 Apr 2017 08:19:15 +0200 Subject: [PATCH 067/322] SSA inliner: collect all heap objects that are covered by a binding. The information will be used to avoid duplicit bindings and to bind objects that are not changed within the function. --- src/ssa/ssa_inliner.cpp | 32 ++++++++++++++++++++++++++------ src/ssa/ssa_inliner.h | 4 ++++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index ac312e85d..093596006 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -37,6 +37,8 @@ void ssa_inlinert::get_summary( { counter++; + covered_cs_heap_out.clear(); + // getting globals at call site local_SSAt::var_sett cs_globals_in, cs_globals_out; goto_programt::const_targett loc=n_it->location; @@ -1302,15 +1304,24 @@ exprt ssa_inlinert::arg_out_transformer(const exprt &arg, const typet &arg_symbo const typet &arg_type = SSA.ns.follow(arg_symbol_type); if (arg_type.id() == ID_struct) { - address_of_exprt arg_addr = address_of_exprt(arg); - typet object_type = arg_symbol_type; - object_type.set("#dynamic", param_type.get_bool("#dynamic")); - arg_addr.object().type() = object_type; + assert(arg.id() == ID_symbol); + symbol_exprt arg_symbol = to_symbol_expr(arg); + address_of_exprt arg_addr = address_of_exprt(arg_symbol); + + const symbolt *symbol; + if (!SSA.ns.lookup(arg_symbol.get_identifier(), symbol)) + { + arg_addr = address_of_exprt(symbol->symbol_expr()); + } + + covered_cs_heap_out.insert(arg_symbol); return arg_addr; } else { - return SSA.name(ssa_objectt(arg, SSA.ns), local_SSAt::OUT, loc); + const symbol_exprt &arg_out = SSA.name(ssa_objectt(arg, SSA.ns), local_SSAt::OUT, loc); + covered_cs_heap_out.insert(arg_out); + return arg_out; } } @@ -1334,7 +1345,16 @@ exprt ssa_inlinert::arg_out_member_transformer(const exprt &arg, { symbol_exprt arg_member(id2string(to_symbol_expr(arg).get_identifier()) + "." + id2string(component.get_name()), component.type()); - return SSA.name(ssa_objectt(arg_member, SSA.ns), local_SSAt::OUT, loc); + const symbol_exprt &arg_member_out = SSA.name(ssa_objectt(arg_member, SSA.ns), local_SSAt::OUT, + loc); + covered_cs_heap_out.insert(arg_member_out); + return arg_member_out; +} + +bool ssa_inlinert::cs_heap_covered(const exprt &expr) +{ + return expr.id() == ID_symbol && + covered_cs_heap_out.find(to_symbol_expr(expr)) != covered_cs_heap_out.end(); } const exprt ssa_inlinert::new_pointed_arg(const exprt &arg, const typet &pointed_type, diff --git a/src/ssa/ssa_inliner.h b/src/ssa/ssa_inliner.h index 8abc6b24b..de78a9304 100644 --- a/src/ssa/ssa_inliner.h +++ b/src/ssa/ssa_inliner.h @@ -117,6 +117,8 @@ class ssa_inlinert:public messaget local_SSAt::nodet::equalitiest new_equs; std::set rm_function_calls; + std::set covered_cs_heap_out; + void replace_globals_in( const local_SSAt::var_sett &globals_in, const local_SSAt::var_sett &globals); @@ -150,6 +152,8 @@ class ssa_inlinert:public messaget void rename(exprt &expr); void rename(local_SSAt::nodet &node); + bool cs_heap_covered(const exprt &expr); + // Transformation functions for lists of input/output arguments/pointers (or their members) // for binding purposes From 85fd5825f5534fe4917b8c59dc2b9e2672ff95fb Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 7 Apr 2017 08:22:56 +0200 Subject: [PATCH 068/322] SSA inliner: improve binding parameters and global objects. Bind new objects separately. Use information about covered heap objects to avoid duplicities and to bind unchanged globals. --- src/ssa/ssa_inliner.cpp | 237 +++++++++++++++++++++++----------------- src/ssa/ssa_inliner.h | 5 + 2 files changed, 144 insertions(+), 98 deletions(-) diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index 093596006..cfb8eb56e 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -67,6 +67,8 @@ void ssa_inlinert::get_summary( std::cout << std::endl; #endif + bindings.push_back(get_replace_new_objects(SSA, *f_it, loc, summary)); + //equalities for arguments bindings.push_back(get_replace_params( summary.params, @@ -607,65 +609,55 @@ exprt ssa_inlinert::get_replace_params( const exprt &p_in = params_deref_in.front(); exprt::operandst d; - for (const exprt &p_out : params_deref_out) + for(const exprt &a_in : args_deref_in) { - for (const exprt &a_out : args_deref_out) + exprt::operandst binding; + binding.push_back(equal_exprt( + param_in_transformer(p_in), + arg_in_transformer(a_in, SSA, loc))); + + if(arg_type.id()==ID_struct) { - exprt::operandst binding; - if (std::find(args_deref_in.begin(), args_deref_in.end(), a_out) != args_deref_in.end()) + for(auto &component : to_struct_type(arg_type).components()) { binding.push_back(equal_exprt( - param_in_transformer(p_in), - arg_in_transformer(a_out, SSA, loc))); + param_in_member_transformer(p_in, component), + arg_in_member_transformer(a_in, component, SSA, loc))); } + } + d.push_back(conjunction(binding)); + } + if (!d.empty()) + c.push_back(disjunction(d)); - const exprt &arg_out = p_out == p_in ? a_out : new_arg_out; - binding.push_back(equal_exprt( - param_out_transformer(p_out, arg_type, summary.globals_out), - arg_out_transformer(arg_out, arg_symbol_type, p_out.type(), SSA, loc))); - - if (arg_type.id() == ID_struct) + d.clear(); + for(const exprt &p_out : params_deref_out) + { + for(const exprt &a_out : args_deref_out) + { + if(!cs_heap_covered(a_out)) { - for (auto &component : to_struct_type(arg_type).components()) - { - if (std::find(args_deref_in.begin(), args_deref_in.end(), a_out) != args_deref_in.end()) - { - binding.push_back(equal_exprt( - param_in_member_transformer(p_in, component), - arg_in_member_transformer(a_out, component, SSA, loc))); - } + exprt::operandst binding; - binding.push_back(equal_exprt( - param_out_member_transformer(p_out, component, summary.globals_out), - arg_out_member_transformer(arg_out, component, SSA, loc))); - } - } + binding.push_back(equal_exprt( + param_out_transformer(p_out, arg_type, summary.globals_out), + arg_out_transformer(a_out, arg_symbol_type, p_out.type(), SSA, loc))); - for (const exprt &a_out_other : args_deref_out) - { - if (a_out_other != arg_out) + if(arg_type.id()==ID_struct) { - if (arg_type.id() == ID_struct) - { - for (auto &component : to_struct_type(arg_type).components()) - { - binding.push_back(equal_exprt( - arg_out_member_transformer(a_out_other, component, SSA, loc), - arg_in_member_transformer(a_out_other, component, SSA, loc))); - } - } - else + for(auto &component : to_struct_type(arg_type).components()) { binding.push_back(equal_exprt( - arg_out_transformer(a_out_other, arg_symbol_type, arg_type, SSA, loc), - arg_in_transformer(a_out_other, SSA, loc))); + param_out_member_transformer(p_out, component, summary.globals_out), + arg_out_member_transformer(a_out, component, SSA, loc))); } } + d.push_back(conjunction(binding)); } - d.push_back(conjunction(binding)); } } - c.push_back(disjunction(d)); + if(!d.empty()) + c.push_back(disjunction(d)); } args_in = args_deref_in; @@ -736,82 +728,91 @@ exprt ssa_inlinert::get_replace_globals_out( { // equalities for globals_out exprt::operandst c; - const irep_idt &ret_val_id= - id2string(to_symbol_expr(funapp_expr.function()).get_identifier()) + "#return_value"; - for (summaryt::var_sett::const_iterator it=cs_globals_out.begin(); + for(summaryt::var_sett::const_iterator it=cs_globals_out.begin(); it!=cs_globals_out.end(); it++) { symbol_exprt lhs; - exprt rhs; + const exprt rhs=*it; - if(get_original_identifier(*it)==ret_val_id) + if(is_pointed(*it) || + id2string(it->get_identifier()).find("dynamic_object$") != std::string::npos) { - // Bind function return value - rhs=*it; // copy - assert(find_corresponding_symbol(*it, summary.globals_out, lhs)); - rename(lhs); - c.push_back(equal_exprt(lhs, rhs)); + if(!cs_heap_covered(*it) && + !find_corresponding_symbol(*it, summary.globals_out, lhs)) + { + assert(find_corresponding_symbol(*it, cs_globals_in, lhs)); + c.push_back(equal_exprt(lhs, rhs)); + } + } + else + { + if(find_corresponding_symbol(*it, summary.globals_out, lhs)) + { + // Bind function return value + rename(lhs); + c.push_back(equal_exprt(lhs, rhs)); - typet type=SSA.ns.follow(rhs.type()); + typet type=SSA.ns.follow(rhs.type()); - std::list callee_rv={*it}; - std::list caller_rv={*it}; + std::list callee_global={*it}; + std::list caller_global={*it}; - // Bind all objects pointed by return value - while(type.id()==ID_pointer) - { - local_SSAt::locationt next_loc=loc; ++next_loc; - std::list caller_rv_deref= - apply_dereference(caller_rv, SSA.ssa_value_ai[next_loc], SSA.ns); - std::list callee_rv_deref= - apply_dereference(callee_rv, summary.value_domain_out, SSA.ns); - - if(!callee_rv_deref.empty()) + // Bind all objects pointed by return value + while(type.id()==ID_pointer) { - const typet symbol_type=type.subtype(); - type=SSA.ns.follow(symbol_type); - - exprt::operandst d; - for(const exprt &callee : callee_rv_deref) + local_SSAt::locationt next_loc=loc; + ++next_loc; + std::list caller_deref=apply_dereference(caller_global, + SSA.ssa_value_ai[next_loc], SSA.ns); + std::list callee_deref=apply_dereference(callee_global, summary.value_domain_out, + SSA.ns); + + if(!callee_deref.empty()) { - for(const exprt &caller : caller_rv_deref) - { - exprt::operandst binding; - binding.push_back(equal_exprt( - param_out_transformer(callee, type, summary.globals_out), - arg_out_transformer(caller, symbol_type, callee.type(), SSA, loc))); + const typet symbol_type=type.subtype(); + type=SSA.ns.follow(symbol_type); - if(type.id()==ID_struct) + exprt::operandst d; + for(const exprt &callee : callee_deref) + { + for(const exprt &caller : caller_deref) { - for(auto &component : to_struct_type(type).components()) + if(!cs_heap_covered(caller)) { + exprt::operandst binding; binding.push_back(equal_exprt( - param_out_member_transformer(callee, component, summary.globals_out), - arg_out_member_transformer(caller, component, SSA, loc))); + param_out_transformer(callee, type, summary.globals_out), + arg_out_transformer(caller, symbol_type, callee.type(), SSA, loc))); + + if(type.id()==ID_struct) + { + for(auto &component : to_struct_type(type).components()) + { + binding.push_back(equal_exprt( + param_out_member_transformer(callee, component, summary.globals_out), + arg_out_member_transformer(caller, component, SSA, loc))); + } + } + + d.push_back(conjunction(binding)); } } - - d.push_back(conjunction(binding)); } - } - c.push_back(disjunction(d)); - } + if(!d.empty()) + c.push_back(disjunction(d)); + } - callee_rv=callee_rv_deref; - caller_rv=caller_rv_deref; + callee_global=callee_deref; + caller_global=caller_deref; - if(caller_rv.empty()) - break; + if(caller_global.empty()) + break; + } } - } - else - { - if(id2string(it->get_identifier()).find("dynamic_object$")==std::string::npos && - id2string(it->get_identifier()).find("'obj")==std::string::npos) + else { - rhs=*it; // copy if(find_corresponding_symbol(*it, summary.globals_out, lhs)) rename(lhs); else @@ -1290,9 +1291,9 @@ exprt ssa_inlinert::param_out_transformer(const exprt ¶m, const typet &type, } else { - symbol_exprt param_out; - assert(find_corresponding_symbol(to_symbol_expr(param), globals_out, param_out)); - rename(param_out); + symbol_exprt param_out = to_symbol_expr(param); + if (find_corresponding_symbol(to_symbol_expr(param), globals_out, param_out)) + rename(param_out); return param_out; } } @@ -1380,3 +1381,43 @@ const exprt ssa_inlinert::new_pointed_arg(const exprt &arg, const typet &pointed return nil_exprt(); } + +exprt ssa_inlinert::get_replace_new_objects( + const local_SSAt &SSA, + const function_application_exprt funapp_expr, + local_SSAt::locationt loc, + const summaryt &summary) +{ + const irep_idt &fname=to_symbol_expr(funapp_expr.function()).get_identifier(); + + auto next_loc=loc; ++next_loc; + const ssa_heap_domaint &heap_domain=SSA.heap_analysis[next_loc]; + + const std::list callee_objects=heap_domain.new_objects(fname); + const std::list caller_objects=heap_domain.new_caller_objects(fname, loc); + + exprt::operandst binding; + auto callee_it=callee_objects.begin(); + for(auto caller_it=caller_objects.begin(); caller_it != caller_objects.end(); + ++caller_it, ++callee_it) + { + const typet symbol_type=caller_it->type(); + const typet type=SSA.ns.follow(symbol_type); + + binding.push_back(equal_exprt( + param_out_transformer(*callee_it, type, summary.globals_out), + arg_out_transformer(*caller_it, symbol_type, type, SSA, loc))); + + if(type.id()==ID_struct) + { + for(auto &component : to_struct_type(type).components()) + { + binding.push_back(equal_exprt( + param_out_member_transformer(*callee_it, component, summary.globals_out), + arg_out_member_transformer(*caller_it, component, SSA, loc))); + } + } + } + + return conjunction(binding); +} diff --git a/src/ssa/ssa_inliner.h b/src/ssa/ssa_inliner.h index de78a9304..7a7bbd5e7 100644 --- a/src/ssa/ssa_inliner.h +++ b/src/ssa/ssa_inliner.h @@ -133,6 +133,11 @@ class ssa_inlinert:public messaget exprt get_replace_globals_in( const local_SSAt::var_sett &globals_in, const local_SSAt::var_sett &globals); + exprt get_replace_new_objects( + const local_SSAt &SSA, + const function_application_exprt funapp_expr, + local_SSAt::locationt loc, + const summaryt &summary); exprt get_replace_params( const local_SSAt::var_listt ¶ms, const function_application_exprt &funapp_expr, From b6c53f15ed18760b05911cd48a07ae5da86be315 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 7 Apr 2017 08:28:40 +0200 Subject: [PATCH 069/322] SSA inliner: improve binding list iterators. Bind all aliased objects together (aliasing is determined in value analysis). --- src/ssa/ssa_inliner.cpp | 61 +++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index cfb8eb56e..7ea015854 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -558,48 +558,57 @@ exprt ssa_inlinert::get_replace_params( // If the caller contains iterators, bindings are different since objects from caller will // appear in the callee summary assert(!args_deref_in.empty() && !args_deref_out.empty()); - arg_type=SSA.ns.follow(args_deref_in.begin()->type()); + arg_type=SSA.ns.follow(args_deref_in.begin()->type()); assert(arg_type.id()==ID_struct); for (const exprt &a : args_deref_in) { - // Bind argument address - c.push_back(equal_exprt( - param_out_transformer(a, arg_type, summary.globals_out), - arg_out_transformer(a, arg_symbol_type, params_deref_out.begin()->type(), SSA, loc))); + std::list aliases = apply_dereference({a}, SSA.ssa_value_ai[next_loc], SSA.ns); + aliases.push_front(a); - for (auto &component : to_struct_type(arg_type).components()) + for (auto &alias : aliases) { - // Bind argument members at the input + // Bind argument address c.push_back(equal_exprt( - param_in_member_transformer(a, component), - arg_in_member_transformer(a, component, SSA, loc) - )); + param_out_transformer(alias, arg_type, summary.globals_out), + arg_out_transformer(alias, arg_symbol_type, params_deref_out.begin()->type(), SSA, + loc))); + + for (auto &component : to_struct_type(arg_type).components()) + { + // Bind argument members at the input + c.push_back(equal_exprt( + param_in_member_transformer(alias, component), + arg_in_member_transformer(alias, component, SSA, loc) + )); + } } } for (const exprt &a : args_deref_out) { - for (auto &component : to_struct_type(arg_type).components()) + std::list aliases = apply_dereference({a}, SSA.ssa_value_ai[next_loc], SSA.ns); + aliases.push_front(a); + for (auto &alias : aliases) { - // Bind argument members at the output (args_deref_out might contain different objects - // than args_deref_in since function call may create new objects). - symbol_exprt arg_member(id2string(to_symbol_expr(a).get_identifier()) + "." + - id2string(component.get_name()), component.type()); - - symbol_exprt member_lhs_out; - if (find_corresponding_symbol(arg_member, summary.globals_out, member_lhs_out)) + const typet &alias_type = SSA.ns.follow(alias.type()); + assert(alias_type.id() == ID_struct); + for (auto &component : to_struct_type(alias_type).components()) { - rename(member_lhs_out); - } - else - { - assert(find_corresponding_symbol(arg_member, cs_globals_in, member_lhs_out)); - } + // Bind argument members at the output (args_deref_out might contain different objects + // than args_deref_in since function call may create new objects). + symbol_exprt arg_member(id2string(to_symbol_expr(alias).get_identifier()) + "." + + id2string(component.get_name()), component.type()); - c.push_back(equal_exprt(member_lhs_out, - arg_out_member_transformer(a, component, SSA, loc))); + symbol_exprt member_lhs_out; + if (find_corresponding_symbol(arg_member, summary.globals_out, member_lhs_out)) + { + rename(member_lhs_out); + c.push_back(equal_exprt(member_lhs_out, + arg_out_member_transformer(alias, component, SSA, loc))); + } + } } } } From b592fa16e47d6c20af60713b35ae5d3b233cb668 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 7 Apr 2017 08:32:47 +0200 Subject: [PATCH 070/322] SSA inliner: remove new_arg_out function. We don't need it anymore since output heap objects are determined from SSA heap analysis. --- src/ssa/ssa_inliner.cpp | 27 --------------------------- src/ssa/ssa_inliner.h | 5 ----- 2 files changed, 32 deletions(-) diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index 7ea015854..a61af58d4 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -538,7 +538,6 @@ exprt ssa_inlinert::get_replace_params( std::list params_in={param}; std::list params_out={param}; - exprt new_arg_out=arg; while(arg_type.id()==ID_pointer) { std::list args_deref_in=apply_dereference(args_in, SSA.ssa_value_ai[loc], SSA.ns); @@ -551,8 +550,6 @@ exprt ssa_inlinert::get_replace_params( const typet arg_symbol_type = arg_type.subtype(); arg_type = SSA.ns.follow(arg_symbol_type); - new_arg_out = new_pointed_arg(new_arg_out, arg_type, args_deref_out); - if(contains_iterator(params_deref_out)) { // If the caller contains iterators, bindings are different since objects from caller will @@ -1367,30 +1364,6 @@ bool ssa_inlinert::cs_heap_covered(const exprt &expr) covered_cs_heap_out.find(to_symbol_expr(expr)) != covered_cs_heap_out.end(); } -const exprt ssa_inlinert::new_pointed_arg(const exprt &arg, const typet &pointed_type, - const std::list &args_out) -{ - symbol_exprt to_find; - if (arg.id() == ID_symbol) - { - to_find = symbol_exprt(id2string(to_symbol_expr(arg).get_identifier()) + "'obj", pointed_type); - } - else if (arg.id() == ID_address_of && to_address_of_expr(arg).object().id() == ID_symbol) - { - to_find = to_symbol_expr(to_address_of_expr(arg).object()); - } - else - return nil_exprt(); - - for (const exprt &a : args_out) - { - if (a == to_find) - return a; - } - - return nil_exprt(); -} - exprt ssa_inlinert::get_replace_new_objects( const local_SSAt &SSA, const function_application_exprt funapp_expr, diff --git a/src/ssa/ssa_inliner.h b/src/ssa/ssa_inliner.h index 7a7bbd5e7..94d0fa0c8 100644 --- a/src/ssa/ssa_inliner.h +++ b/src/ssa/ssa_inliner.h @@ -194,11 +194,6 @@ class ssa_inlinert:public messaget const local_SSAt &SSA, local_SSAt::locationt loc); - const exprt new_pointed_arg( - const exprt &arg, - const typet &pointed_type, - const std::list &args_out); - static bool contains_iterator(const std::list ¶ms); }; From c46373604d0223a3795e9fadd4f0a403678d96df Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 7 Apr 2017 08:36:18 +0200 Subject: [PATCH 071/322] Allow inlining summaries to certain location only. This is used when computing calling context - only summaries before the call site are inlined. --- src/solver/summarizer_base.cpp | 2 +- src/ssa/ssa_inliner.cpp | 14 +++++++++++++- src/ssa/ssa_inliner.h | 5 ++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/solver/summarizer_base.cpp b/src/solver/summarizer_base.cpp index 9a951bda9..553b0bd3f 100644 --- a/src/solver/summarizer_base.cpp +++ b/src/solver/summarizer_base.cpp @@ -194,7 +194,7 @@ exprt summarizer_baset::compute_calling_context( solver.new_context(); solver << SSA.get_enabling_exprs(); - solver << ssa_inliner.get_summaries(SSA); + solver << ssa_inliner.get_summaries_to_loc(SSA, n_it->location); ssa_analyzert analyzer; analyzer.set_message_handler(get_message_handler()); diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index a61af58d4..6079caf9a 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -129,6 +129,14 @@ exprt ssa_inlinert::get_summaries(const local_SSAt &SSA) return and_exprt(conjunction(bindings), conjunction(summaries)); } +exprt ssa_inlinert::get_summaries_to_loc( + const local_SSAt &SSA, local_SSAt::locationt loc) +{ + exprt::operandst summaries,bindings; + get_summaries(SSA,true,summaries,bindings, loc); + return and_exprt(conjunction(bindings),conjunction(summaries)); +} + /*******************************************************************\ Function: ssa_inlinert::get_summaries @@ -145,11 +153,15 @@ void ssa_inlinert::get_summaries( const local_SSAt &SSA, bool forward, exprt::operandst &summaries, - exprt::operandst &bindings) + exprt::operandst &bindings, + local_SSAt::locationt loc) { for(local_SSAt::nodest::const_iterator n_it=SSA.nodes.begin(); n_it!=SSA.nodes.end(); n_it++) { + if(loc!=local_SSAt::locationt() && + n_it->location->location_number>=loc->location_number) + return; for(local_SSAt::nodet::function_callst::const_iterator f_it= n_it->function_calls.begin(); f_it!=n_it->function_calls.end(); f_it++) diff --git a/src/ssa/ssa_inliner.h b/src/ssa/ssa_inliner.h index 94d0fa0c8..e5e58542a 100644 --- a/src/ssa/ssa_inliner.h +++ b/src/ssa/ssa_inliner.h @@ -38,9 +38,12 @@ class ssa_inlinert:public messaget const local_SSAt &SSA, bool forward, exprt::operandst &summaries, - exprt::operandst &bindings); + exprt::operandst &bindings, + local_SSAt::locationt loc=local_SSAt::locationt()); exprt get_summaries(const local_SSAt &SSA); + exprt get_summaries_to_loc(const local_SSAt &SSA, local_SSAt::locationt loc); + void replace( local_SSAt &SSA, local_SSAt::nodest::iterator node, From fff489e8edfb0147f11c00d9e70ebd810062140c Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 7 Apr 2017 08:39:23 +0200 Subject: [PATCH 072/322] SSA inliner: some minor changes. get_original_identifier: '$' is not removed - it is a part of the variable name. apply_dereference: support typecast. --- src/ssa/ssa_inliner.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index 6079caf9a..6c8c670af 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -1185,12 +1185,12 @@ irep_idt ssa_inlinert::get_original_identifier(const symbol_exprt &s) char c=id.at(i); if(pos==std::string::npos) { - if(c=='#' || c=='@' || c=='%' || c=='!' || c=='$') + if(c=='#' || c=='@' || c=='%' || c=='!') pos=i; } else { - if(!(c=='#' || c=='@' || c=='%' || c=='!' || c=='$') && + if(!(c=='#' || c=='@' || c=='%' || c=='!') && !(c=='p' || c=='h' || c=='i') && !(c=='l' || c=='b') && !('0'<=c && c<='9')) @@ -1233,10 +1233,17 @@ std::list ssa_inlinert::apply_dereference( ssa_value_domaint::valuest values=value_domain(to_query, ns); for(auto &v : values.value_set) { - result.push_back(v.symbol_expr()); + assert(v.get_expr().id() == ID_symbol); + result.push_back(v.get_expr()); } } - else + else if (expr.id() == ID_typecast) + { + std::list tmp = apply_dereference({to_typecast_expr(expr).op()}, value_domain, ns); + for (auto &e : tmp) + result.push_back(e); + } + else if (expr.id() != ID_constant) { assert(false); } From e8e3270893ad38c09805728749ee52ca499d1e77 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 7 Apr 2017 08:44:36 +0200 Subject: [PATCH 073/322] SSA: better collection of global objects. --- src/ssa/local_ssa.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 3957d135a..7a5744171 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -141,9 +141,8 @@ 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) + if(!with_returns && !is_pointed(it->get_expr()) && + id2string(it->get_identifier()).find("#return_value") != std::string::npos) continue; //filter out return values of other functions @@ -155,16 +154,12 @@ void local_SSAt::get_globals( continue; const exprt &root_obj=it->get_root_object(); - if(root_obj.type().get_bool("#dynamic") && !with_returns) - continue; if(is_ptr_object(root_obj)) { const symbolt *symbol; irep_idt ptr_obj_id=root_obj.get(ID_ptr_object); if(ns.lookup(ptr_obj_id, symbol)) continue; - if(!symbol->is_parameter && !with_returns) - continue; } if(rhs_value) From aaaa1321f54104420ba8e387f8f37e6b4e51a030 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 7 Apr 2017 08:45:47 +0200 Subject: [PATCH 074/322] SSA: replace constant arguments by a symbol. --- src/ssa/local_ssa.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 7a5744171..e21b89665 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -544,6 +544,22 @@ void local_SSAt::build_function_call(locationt loc) assert(f.function().id()==ID_symbol); //no function pointers f = to_function_application_expr(read_rhs(f, loc)); + + irep_idt fname = to_symbol_expr(f.function()).get_identifier(); + //add equalities for arguments + unsigned i = 0; + for (auto &a : f.arguments()) + { + if (a.is_constant() || a.id() == ID_typecast && to_typecast_expr(a).op().is_constant()) + { + symbol_exprt arg(id2string(fname) + "#arg" + i2string(i) + + "#" + i2string(loc->location_number) , a.type()); + n_it->equalities.push_back(equal_exprt(a, arg)); + a = arg; + } + ++i; + } + n_it->function_calls.push_back( to_function_application_expr(f)); } From 537a5ea115ec04264509c0276eaf0c621669a111 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 7 Apr 2017 08:49:18 +0200 Subject: [PATCH 075/322] Heap analysis: set nondet if type of returned address doesn't match. --- src/domains/strategy_solver_heap.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index d0cd54aeb..bc0def35d 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -128,6 +128,17 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) symbol_exprt obj=to_symbol_expr(to_address_of_expr(ptr_value).object()); + if (obj.type() != templ_row.expr.type() && + ns.follow(templ_row.expr.type().subtype()) != ns.follow(obj.type())) + { + if (heap_domain.set_nondet(row, inv)) + { + improved = true; + debug() << "Set nondet" << eom; + } + continue; + } + // Add equality p == &obj if (heap_domain.add_points_to(row, inv, obj)) { From 0c96775afafb46b7c0092d1f5cd4f64d5650679f Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 7 Apr 2017 08:50:51 +0200 Subject: [PATCH 076/322] Heap analysis: improve updating paths of other rows. Do not update paths if one of the rows is nondet. Check for equality of memory type and field between the rows. --- src/domains/strategy_solver_heap.cpp | 58 +++++++++++++++------------- src/ssa/local_ssa.cpp | 19 +++++---- 2 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index bc0def35d..483b6f4f1 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -159,33 +159,33 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) int member_val_index; member_val_index=find_member_row( obj, templ_row.member, actual_loc, templ_row.kind); - assert(member_val_index>=0); - - // Add all paths from obj.next to p - if(heap_domain.add_transitivity( - row, (unsigned) member_val_index, inv)) + if (member_val_index>=0 && !inv[member_val_index].nondet) { - improved = true; - debug() - << "Add all paths: " - << from_expr(ns, "", heap_domain.templ[member_val_index].expr) - << ", through: " << from_expr(ns, "", obj) << eom; + // Add all paths from obj.next to p + if(heap_domain.add_transitivity(row, (unsigned) member_val_index, inv)) + { + improved=true; + debug() << "Add all paths: " + << from_expr(ns, "", heap_domain.templ[member_val_index].expr) + << ", through: " << from_expr(ns, "", obj) << eom; + } } } } else { - if (heap_domain.set_nondet(row, inv)) + if(heap_domain.set_nondet(row, inv)) { improved = true; debug() << "Set nondet" << eom; } } - if (templ_row.mem_kind == heap_domaint::HEAP) + if (templ_row.mem_kind==heap_domaint::HEAP) { // Recursively update all rows that are dependent on this row updated_rows.clear(); - update_rows_rec(row, inv); + if(!inv[row].nondet) + update_rows_rec(row, inv); } } } @@ -196,17 +196,17 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) debug() << "UNSAT" << eom; #ifdef DEBUG_OUTPUT - for (unsigned i = 0; i < solver.formula.size(); i++) + for(unsigned i=0; iis_in_conflict(solver.formula[i])) + if(solver.solver->is_in_conflict(solver.formula[i])) debug() << "is_in_conflict: " << solver.formula[i] << eom; else debug() << "not_in_conflict: " << solver.formula[i] << eom; } - for (unsigned i = 0; i < heap_domain.templ.size(); i++) + for(unsigned i=0; ilocation_number) , a.type()); + symbol_exprt arg( + id2string(fname)+"#arg"+i2string(i)+ + "#"+i2string(loc->location_number), + a.type()); n_it->equalities.push_back(equal_exprt(a, arg)); - a = arg; + a=arg; } ++i; } From bed0cd5039005fc345b1fd994754a6362a6ac7d1 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 7 Apr 2017 08:54:45 +0200 Subject: [PATCH 077/322] Heap domain: improve adding paths. Do not add new path if this is already contained in some paths set. Correct an error in add_all_paths. --- src/domains/heap_domain.cpp | 55 +++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index dab32beaa..782d06174 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -492,25 +492,51 @@ bool heap_domaint::heap_row_valuet::add_points_to(const exprt &dest) } } +/*******************************************************************\ + +Function: heap_domaint::heap_row_valuet::add_path + + Inputs: dest Path destination + dyn_obj Dynamic object that the path goes through + + Outputs: True if the value was changed (a path was added) + + Purpose: Add new path set if any path set does not contain the given destination. + If any path set already contains dest, do nothing since the pathset will be updated from + other rows. + +\*******************************************************************/ bool heap_domaint::heap_row_valuet::add_path(const exprt &dest, const dyn_objt &dyn_obj) { - pathsett new_path_set; - std::set dyn_obj_set; - if (dyn_obj.first.id() != ID_nil) + bool new_path = true; + for (auto &path_set : paths) { - dyn_obj_set.insert(dyn_obj); + auto p_it = path_set.find(dest); + if (p_it != path_set.end() && p_it->dyn_objects.empty()) + { + new_path = false; + break; + } } - if (self_linkage) + if (new_path) { - dyn_obj_set.insert(this->dyn_obj); + pathsett new_path_set; + std::set dyn_obj_set; + if (dyn_obj.first.id() != ID_nil) + { + dyn_obj_set.insert(dyn_obj); + } + if (self_linkage) + { + dyn_obj_set.insert(this->dyn_obj); + } + new_path_set.emplace(dest, dyn_obj_set); + paths.push_back(new_path_set); } - new_path_set.emplace(dest, dyn_obj_set); - paths.push_back(new_path_set); - return true; + return new_path; } -bool -heap_domaint::heap_row_valuet::add_path(const exprt &dest, const heap_domaint::dyn_objt &dyn_obj, +bool heap_domaint::heap_row_valuet::add_path(const exprt &dest, const heap_domaint::dyn_objt &dyn_obj, pathsett &path_set) { if (path_set.find(dest) == path_set.end()) @@ -573,9 +599,9 @@ bool heap_domaint::heap_row_valuet::add_all_paths(const heap_domaint::heap_row_v ++next_it; if (next_it != other_val.paths.end()) { // Duplicate element pointed by it - ++it; - it = paths.insert(it, *it); - --it; + auto n_it = it; + ++n_it; + paths.insert(n_it, *it); } // Add all paths to *it @@ -587,7 +613,6 @@ bool heap_domaint::heap_row_valuet::add_all_paths(const heap_domaint::heap_row_v other_it = next_it == other_val.paths.end() ? other_val.paths.begin() : next_it; } } -// join_all_path_sets(); } return result; } From de5cd99be098a9ce006bd339892057b97e93955d Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 7 Apr 2017 08:55:47 +0200 Subject: [PATCH 078/322] Heap domain: check for address offset when converting the value from the solver. --- src/domains/heap_domain.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 782d06174..652fffa89 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -322,7 +322,13 @@ void heap_domaint::project_on_vars(domaint::valuet &value, exprt heap_domaint::value_to_ptr_exprt(const exprt &expr) { if (expr.id() == ID_constant) - return expr.op0(); + { + const std::string value = id2string(to_constant_expr(expr).get_value()); + if (value.substr(value.size() / 2).find_first_not_of('0') != std::string::npos) + return plus_exprt(expr.op0(), constant_exprt::integer_constant(0)); + else + return expr.op0(); + } return expr; } From 608e8c49fe340b6fd9437340c51fd2b5623fe152 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 7 Apr 2017 08:57:08 +0200 Subject: [PATCH 079/322] Heap domain: minor changes. Move template to top. empty checks for self_linkage. --- src/domains/heap_domain.h | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index 111cdec79..9795bcea9 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -31,6 +31,19 @@ class heap_domaint:public domaint make_template(var_specs, ns_); } + struct template_rowt + { + vart expr; + guardt pre_guard; + guardt post_guard; + exprt aux_expr; + kindt kind; + mem_kindt mem_kind; + exprt dyn_obj; + irep_idt member; + }; + typedef std::vector templatet; + /** * Value of a row is set of paths in the heap leading from row variable */ @@ -104,7 +117,7 @@ class heap_domaint:public domaint virtual bool empty() const override { - return paths.empty(); + return paths.empty() && !self_linkage; } bool add_path(const exprt &dest, const dyn_objt &dyn_obj); @@ -134,19 +147,6 @@ class heap_domaint:public domaint } }; - struct template_rowt - { - vart expr; - guardt pre_guard; - guardt post_guard; - exprt aux_expr; - kindt kind; - mem_kindt mem_kind; - exprt dyn_obj; - irep_idt member; - }; - typedef std::vector templatet; - // Initialize value virtual void initialize(valuet &value) override; @@ -164,6 +164,7 @@ class heap_domaint:public domaint exprt get_row_post_constraint(const rowt &row, const row_valuet &row_value); + // Row modifications bool add_transitivity(const rowt &from, const rowt &to, heap_valuet &value); bool add_points_to(const rowt &row, heap_valuet &value, const exprt &dest); From d9c8a8bf81084ae58f81f322bd4353323d7f0370 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 28 Apr 2017 09:29:15 +0200 Subject: [PATCH 080/322] Comment unknown objects equalities - causing problems --- src/ssa/local_ssa.cpp | 66 +++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index e129fa90b..08cf19d48 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -1617,17 +1617,17 @@ std::list &operator<<( } - for (auto &obj : src.unknown_objs) - { - const typet &obj_type = src.ns.follow(obj.type()); - if (obj_type.id() == ID_struct) - { - for (auto &component : to_struct_type(obj_type).components()) - { - dest.push_back(src.unknown_obj_eq(obj, component)); - } - } - } +// for (auto &obj : src.unknown_objs) +// { +// const typet &obj_type = src.ns.follow(obj.type()); +// if (obj_type.id() == ID_struct) +// { +// for (auto &component : to_struct_type(obj_type).components()) +// { +// dest.push_back(src.unknown_obj_eq(obj, component)); +// } +// } +// } #endif return dest; @@ -1678,17 +1678,17 @@ decision_proceduret &operator<<( } } - for (auto &obj : src.unknown_objs) - { - const typet &obj_type = src.ns.follow(obj.type()); - if (obj_type.id() == ID_struct) - { - for (auto &component : to_struct_type(obj_type).components()) - { - dest << src.unknown_obj_eq(obj, component); - } - } - } +// for (auto &obj : src.unknown_objs) +// { +// const typet &obj_type = src.ns.follow(obj.type()); +// if (obj_type.id() == ID_struct) +// { +// for (auto &component : to_struct_type(obj_type).components()) +// { +// dest << src.unknown_obj_eq(obj, component); +// } +// } +// } #endif return dest; } @@ -1744,17 +1744,17 @@ incremental_solvert &operator<<( } } - for (auto &obj : src.unknown_objs) - { - const typet &obj_type = src.ns.follow(obj.type()); - if (obj_type.id() == ID_struct) - { - for (auto &component : to_struct_type(obj_type).components()) - { - dest << src.unknown_obj_eq(obj, component); - } - } - } +// for (auto &obj : src.unknown_objs) +// { +// const typet &obj_type = src.ns.follow(obj.type()); +// if (obj_type.id() == ID_struct) +// { +// for (auto &component : to_struct_type(obj_type).components()) +// { +// dest << src.unknown_obj_eq(obj, component); +// } +// } +// } #endif return dest; } From fc32b8e18334371d081c8cbf0ceec997bdd76c86 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 28 Apr 2017 08:58:42 +0200 Subject: [PATCH 081/322] Heap-interval domain: combination of domains. Simple combination of heap and interval domains. New domain is created that contains both domains together. Heap domain is used for pointer variables and interval domain is used for numerical variables. --- src/2ls/2ls_parse_options.cpp | 6 +++ src/2ls/2ls_parse_options.h | 2 +- src/domains/Makefile | 4 +- src/domains/heap_interval_domain.cpp | 43 +++++++++++++++ src/domains/heap_interval_domain.h | 53 +++++++++++++++++++ src/domains/ssa_analyzer.cpp | 8 +++ src/domains/strategy_solver_heap_interval.cpp | 22 ++++++++ src/domains/strategy_solver_heap_interval.h | 38 +++++++++++++ src/domains/template_generator_base.cpp | 41 +++++++++++++- src/domains/template_generator_base.h | 1 + src/domains/tpolyhedra_domain.cpp | 2 + 11 files changed, 217 insertions(+), 3 deletions(-) create mode 100644 src/domains/heap_interval_domain.cpp create mode 100644 src/domains/heap_interval_domain.h create mode 100644 src/domains/strategy_solver_heap_interval.cpp create mode 100644 src/domains/strategy_solver_heap_interval.h diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 0e64e87b3..d51bd3528 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -197,6 +197,10 @@ void twols_parse_optionst::get_command_line_options(optionst &options) { options.set_option("heap", true); } + else if (cmdline.isset("heap-interval")) + { + options.set_option("heap-interval", true); + } else { if(cmdline.isset("zones")) @@ -486,6 +490,8 @@ int twols_parse_optionst::doit() status() << "Using (dis)equalities domain" << eom; else if (options.get_bool_option("heap")) status() << "Using heap domain" << eom; + else if (options.get_bool_option("heap-interval")) + status() << "Using heap domain with interval domain for values" << eom; else { if(options.get_bool_option("intervals")) diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index f93bae489..a992325af 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -36,7 +36,7 @@ class optionst; "(version)" \ "(i386-linux)(i386-macos)(i386-win32)(win32)(winx64)(gcc)" \ "(ppc-macos)(unsigned-char)" \ - "(havoc)(intervals)(zones)(octagons)(equalities)(heap)"\ + "(havoc)(intervals)(zones)(octagons)(equalities)(heap)(heap-interval)"\ "(enum-solver)(binsearch-solver)(arrays)"\ "(string-abstraction)(no-arch)(arch):(floatbv)(fixedbv)" \ "(round-to-nearest)(round-to-plus-inf)(round-to-minus-inf)(round-to-zero)" \ diff --git a/src/domains/Makefile b/src/domains/Makefile index 38e8f9f60..d7a9d1540 100644 --- a/src/domains/Makefile +++ b/src/domains/Makefile @@ -1,5 +1,6 @@ SRC = tpolyhedra_domain.cpp equality_domain.cpp domain.cpp \ predabs_domain.cpp heap_domain.cpp list_iterator.cpp \ + heap_interval_domain.cpp \ ssa_analyzer.cpp util.cpp incremental_solver.cpp \ strategy_solver_base.cpp strategy_solver_equality.cpp \ linrank_domain.cpp lexlinrank_domain.cpp\ @@ -8,7 +9,8 @@ SRC = tpolyhedra_domain.cpp equality_domain.cpp 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_heap.cpp + strategy_solver_predabs.cpp strategy_solver_heap.cpp \ + strategy_solver_heap_interval.cpp #solver_enumeration.cpp include ../config.inc diff --git a/src/domains/heap_interval_domain.cpp b/src/domains/heap_interval_domain.cpp new file mode 100644 index 000000000..0b6f06775 --- /dev/null +++ b/src/domains/heap_interval_domain.cpp @@ -0,0 +1,43 @@ +/** + * Viktor Malik, 3/30/17 (c). + */ + +#include "heap_interval_domain.h" + +void heap_interval_domaint::initialize(domaint::valuet &value) +{ + heap_interval_valuet &v = static_cast(value); + + heap_domain.initialize(v.heap_value); + interval_domain.initialize(v.interval_value); +} + +void heap_interval_domaint::output_value(std::ostream &out, const domaint::valuet &value, + const namespacet &ns) const +{ + const heap_interval_valuet &v = static_cast(value); + + heap_domain.output_value(out, v.heap_value, ns); + interval_domain.output_value(out, v.interval_value, ns); +} + +void heap_interval_domaint::output_domain(std::ostream &out, const namespacet &ns) const +{ + heap_domain.output_domain(out, ns); + interval_domain.output_domain(out, ns); +} + +void heap_interval_domaint::project_on_vars(domaint::valuet &value, const domaint::var_sett &vars, + exprt &result) +{ + heap_interval_valuet &v = static_cast(value); + + exprt heap_result; + heap_domain.project_on_vars(v.heap_value, vars, heap_result); + exprt interval_result; + interval_domain.project_on_vars(v.interval_value, vars, interval_result); + + result = and_exprt(heap_result, interval_result); +} + + diff --git a/src/domains/heap_interval_domain.h b/src/domains/heap_interval_domain.h new file mode 100644 index 000000000..51fc3dfba --- /dev/null +++ b/src/domains/heap_interval_domain.h @@ -0,0 +1,53 @@ +/** + * Viktor Malik, 3/30/17 (c). + */ +#ifndef INC_2LS_HEAP_INTERVAL_DOMAINT_H +#define INC_2LS_HEAP_INTERVAL_DOMAINT_H + + +#include "domain.h" +#include "tpolyhedra_domain.h" +#include "heap_domain.h" + +class heap_interval_domaint : public domaint +{ + public: + heap_domaint heap_domain; + tpolyhedra_domaint interval_domain; + + heap_domaint::heap_valuet heap_value; + + heap_interval_domaint( + unsigned int _domain_number, + replace_mapt &_renaming_map, + const var_specst &var_specs, + const namespacet &ns): + domaint(_domain_number, _renaming_map, ns), + heap_domain(_domain_number, _renaming_map, var_specs, ns), + interval_domain(_domain_number, _renaming_map, ns) + { + interval_domain.add_interval_template(var_specs, ns); + } + + class heap_interval_valuet:public valuet + { + public: + heap_domaint::heap_valuet heap_value; + tpolyhedra_domaint::templ_valuet interval_value; + }; + + virtual void initialize(valuet &value) override; + + virtual void output_value( + std::ostream &out, + const valuet &value, + const namespacet &ns) const override; + + virtual void output_domain( + std::ostream &out, const namespacet &ns) const override; + + virtual void project_on_vars(valuet &value, const var_sett &vars, exprt &result) override; +}; + + +#endif //INC_2LS_HEAP_INTERVAL_DOMAINT_H diff --git a/src/domains/ssa_analyzer.cpp b/src/domains/ssa_analyzer.cpp index 5584c3bc2..92cb85c7a 100644 --- a/src/domains/ssa_analyzer.cpp +++ b/src/domains/ssa_analyzer.cpp @@ -32,6 +32,7 @@ Author: Peter Schrammel #include "strategy_solver_predabs.h" #include "ssa_analyzer.h" #include "strategy_solver_heap.h" +#include "strategy_solver_heap_interval.h" #define BINSEARCH_SOLVER strategy_solver_binsearcht(\ *static_cast(domain), solver, SSA.ns) @@ -111,6 +112,13 @@ void ssa_analyzert::operator()( solver, SSA, precondition, get_message_handler(), template_generator); result=new heap_domaint::heap_valuet(); } + else if (template_generator.options.get_bool_option("heap-interval")) + { + strategy_solver = new strategy_solver_heap_intervalt( + *static_cast(domain), solver, SSA, precondition, + get_message_handler(), template_generator); + result = new heap_interval_domaint::heap_interval_valuet(); + } else { if(template_generator.options.get_bool_option("enum-solver")) diff --git a/src/domains/strategy_solver_heap_interval.cpp b/src/domains/strategy_solver_heap_interval.cpp new file mode 100644 index 000000000..4ce5a0a4a --- /dev/null +++ b/src/domains/strategy_solver_heap_interval.cpp @@ -0,0 +1,22 @@ +/** + * Viktor Malik, 3/30/17 (c). + */ + +#include "strategy_solver_heap_interval.h" + +bool strategy_solver_heap_intervalt::iterate(strategy_solver_baset::invariantt &_inv) +{ + heap_interval_domaint::heap_interval_valuet &inv = + static_cast(_inv); + + bool heap_improved = heap_solver.iterate(inv.heap_value); + bool interval_improved = interval_solver.iterate(inv.interval_value); + + return heap_improved || interval_improved; +} + +void strategy_solver_heap_intervalt::set_message_handler(message_handlert &_message_handler) +{ + heap_solver.set_message_handler(_message_handler); + interval_solver.set_message_handler(_message_handler); +} diff --git a/src/domains/strategy_solver_heap_interval.h b/src/domains/strategy_solver_heap_interval.h new file mode 100644 index 000000000..771ecb5ad --- /dev/null +++ b/src/domains/strategy_solver_heap_interval.h @@ -0,0 +1,38 @@ +/** + * Viktor Malik, 3/30/17 (c). + */ +#ifndef INC_2LS_STRATEGY_SOLVER_HEAP_INTERVALT_H +#define INC_2LS_STRATEGY_SOLVER_HEAP_INTERVALT_H + + +#include "strategy_solver_base.h" +#include "heap_interval_domain.h" +#include "strategy_solver_heap.h" +#include "strategy_solver_binsearch.h" + +class strategy_solver_heap_intervalt : public strategy_solver_baset +{ + public: + strategy_solver_heap_intervalt(heap_interval_domaint &_heap_interval_domain, + incremental_solvert &_solver, const local_SSAt &SSA, + const exprt &precondition, message_handlert &message_handler, + template_generator_baset &template_generator) + : strategy_solver_baset(_solver, SSA.ns), + heap_interval_domain(_heap_interval_domain), + heap_solver(heap_interval_domain.heap_domain, _solver, SSA, precondition, message_handler, + template_generator), + interval_solver(heap_interval_domain.interval_domain, _solver, SSA.ns) {} + + virtual bool iterate(invariantt &_inv) override; + + virtual void set_message_handler(message_handlert &_message_handler) override; + + protected: + heap_interval_domaint &heap_interval_domain; + + strategy_solver_heapt heap_solver; + strategy_solver_binsearcht interval_solver; +}; + + +#endif //INC_2LS_STRATEGY_SOLVER_HEAP_INTERVALT_H diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index 45249b0e5..f07372a27 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -12,12 +12,14 @@ Author: Peter Schrammel #include #include +#include + #include "template_generator_base.h" #include "equality_domain.h" #include "tpolyhedra_domain.h" #include "predabs_domain.h" #include "heap_domain.h" -#include +#include "heap_interval_domain.h" #ifdef DEBUG #include @@ -742,4 +744,41 @@ void template_generator_baset::instantiate_standard_domains( static_cast(domain_ptr)->add_quadratic_template( var_specs, SSA.ns); } + else if (options.get_bool_option("heap-interval")) + { + filter_heap_interval_domain(); + domain_ptr = new heap_interval_domaint(domain_number, renaming_map, var_specs, SSA.ns); + } +} + +void template_generator_baset::filter_heap_interval_domain() +{ + domaint::var_specst new_var_specs(var_specs); + var_specs.clear(); + for(domaint::var_specst::const_iterator v = new_var_specs.begin(); + v!=new_var_specs.end(); v++) + { + const domaint::vart &s = v->var; + + if (s.type().id()==ID_unsignedbv || + s.type().id()==ID_signedbv || + s.type().id()==ID_floatbv) + { + var_specs.push_back(*v); + continue; + } + + if (s.id() == ID_symbol && s.type().id() == ID_pointer && + id2string(to_symbol_expr(s).get_identifier()).find("__CPROVER") == std::string::npos) + { + // Filter out non-assigned OUT variables + if (v->kind != domaint::OUT || + ssa_inlinert::get_original_identifier(to_symbol_expr(s)) != + to_symbol_expr(s).get_identifier()) + { + var_specs.push_back(*v); + continue; + } + } + } } diff --git a/src/domains/template_generator_base.h b/src/domains/template_generator_base.h index 757d342fc..aec758b7c 100644 --- a/src/domains/template_generator_base.h +++ b/src/domains/template_generator_base.h @@ -74,6 +74,7 @@ class template_generator_baset:public messaget void filter_template_domain(); void filter_equality_domain(); void filter_heap_domain(); + void filter_heap_interval_domain(); void add_var( const domaint::vart &var_to_add, diff --git a/src/domains/tpolyhedra_domain.cpp b/src/domains/tpolyhedra_domain.cpp index 470931c05..55f8e5447 100644 --- a/src/domains/tpolyhedra_domain.cpp +++ b/src/domains/tpolyhedra_domain.cpp @@ -1008,6 +1008,8 @@ void tpolyhedra_domaint::add_interval_template( { if(v.kind==IN) continue; + if(v.var.type().id()==ID_pointer) + continue; // x add_template_row( From 7ae7415652986c29128f74472d2a4198cfc8dd99 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 3 Jul 2017 08:08:27 +0200 Subject: [PATCH 082/322] Heap-interval domain: remove abstract value from the domain (it is not used). --- src/domains/heap_interval_domain.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/domains/heap_interval_domain.h b/src/domains/heap_interval_domain.h index 51fc3dfba..b3142fb79 100644 --- a/src/domains/heap_interval_domain.h +++ b/src/domains/heap_interval_domain.h @@ -15,8 +15,6 @@ class heap_interval_domaint : public domaint heap_domaint heap_domain; tpolyhedra_domaint interval_domain; - heap_domaint::heap_valuet heap_value; - heap_interval_domaint( unsigned int _domain_number, replace_mapt &_renaming_map, From 834dcc91315424131a398984141d63d5614f11e4 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 3 Jul 2017 08:09:33 +0200 Subject: [PATCH 083/322] Heap domain: include all pointers into the pointer part of the template. Only pointers to structures were considered so far. --- src/domains/heap_domain.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 652fffa89..b461645a2 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -47,15 +47,12 @@ void heap_domaint::make_template(const domaint::var_specst &var_specs, const nam { if (v->kind == IN) continue; - // Create template for each pointer to struct + // Create template for each pointer const vart &var = v->var; if (var.type().id() == ID_pointer) { const typet &pointed_type = ns.follow(var.type().subtype()); - if (pointed_type.id() == ID_struct) - { add_template_row(*v, pointed_type); - } } } } @@ -73,18 +70,21 @@ void heap_domaint::add_template_row(const var_spect &var_spec, const typet &poin templ_row.kind = var_spec.kind; templ_row.mem_kind = STACK; - // Check if var is member field of heap object - const std::string identifier = id2string(to_symbol_expr(var_spec.var).get_identifier()); - for (auto &component : to_struct_type(pointed_type).components()) + if (pointed_type.id() == ID_struct) { - if (identifier.find("." + id2string(component.get_name())) != std::string::npos) + // Check if var is member field of heap object + const std::string identifier = id2string(to_symbol_expr(var_spec.var).get_identifier()); + for (auto &component : to_struct_type(pointed_type).components()) { - templ_row.mem_kind = HEAP; - templ_row.member = component.get_name(); + if (identifier.find("." + id2string(component.get_name())) != std::string::npos) + { + templ_row.mem_kind = HEAP; + templ_row.member = component.get_name(); - std::string var_id = id2string(to_symbol_expr(var).get_identifier()); - std::string do_id = var_id.substr(0, var_id.find_last_of('.')); - templ_row.dyn_obj = symbol_exprt(do_id, var.type().subtype()); + std::string var_id = id2string(to_symbol_expr(var).get_identifier()); + std::string do_id = var_id.substr(0, var_id.find_last_of('.')); + templ_row.dyn_obj = symbol_exprt(do_id, var.type().subtype()); + } } } } From c9e52848a5debd8941a77b7be562652b268b412f Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 3 Jul 2017 08:12:32 +0200 Subject: [PATCH 084/322] SSA heap analysis: use only with interprocedural heap analysis. Also add some missing checks for existing location in the SSA heap analysis. --- src/2ls/2ls_parse_options.cpp | 4 +- src/ssa/assignments.cpp | 8 ++- src/ssa/ssa_inliner.cpp | 99 +++++++++++++++++++---------------- src/ssa/ssa_value_set.cpp | 24 +++++++-- 4 files changed, 81 insertions(+), 54 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index d51bd3528..063eb40a5 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -515,7 +515,9 @@ int twols_parse_optionst::doit() const namespacet ns(goto_model.symbol_table); ssa_heap_analysist heap_analysis(ns); - if(!options.get_bool_option("inline")) + if((options.get_bool_option("heap") || + options.get_bool_option("heap-interval")) && + !options.get_bool_option("inline")) { heap_analysis(goto_model.goto_functions); add_dynamic_object_symbols(heap_analysis, goto_model); diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index 382af3427..6c3d2b9d6 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -56,8 +56,12 @@ void assignmentst::build_assignment_map( const irep_idt fname=to_symbol_expr(code_function_call.function()).get_identifier(); std::list new_objects; std::set modified_objects; - new_objects=ssa_heap_analysis[n_it].new_caller_objects(fname, it); - modified_objects=ssa_heap_analysis[n_it].modified_objects(fname); + + if(ssa_heap_analysis.has_location(n_it)) + { + new_objects=ssa_heap_analysis[n_it].new_caller_objects(fname, it); + modified_objects=ssa_heap_analysis[n_it].modified_objects(fname); + } // Assign new objects for(auto &o : new_objects) diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index 6c8c670af..eb178673c 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -622,60 +622,63 @@ exprt ssa_inlinert::get_replace_params( } } else - { // Bind objects pointed by argument and parameter when advancer is not present - assert(params_deref_in.size() == 1); - const exprt &p_in = params_deref_in.front(); - - exprt::operandst d; - for(const exprt &a_in : args_deref_in) + { + // Bind objects pointed by argument and parameter when advancer is not present + if(params_deref_in.size()==1) { - exprt::operandst binding; - binding.push_back(equal_exprt( - param_in_transformer(p_in), - arg_in_transformer(a_in, SSA, loc))); + const exprt &p_in = params_deref_in.front(); - if(arg_type.id()==ID_struct) + exprt::operandst d; + for(const exprt &a_in : args_deref_in) { - for(auto &component : to_struct_type(arg_type).components()) + exprt::operandst binding; + binding.push_back(equal_exprt( + param_in_transformer(p_in), + arg_in_transformer(a_in, SSA, loc))); + + if(arg_type.id() == ID_struct) { - binding.push_back(equal_exprt( - param_in_member_transformer(p_in, component), - arg_in_member_transformer(a_in, component, SSA, loc))); + for(auto &component : to_struct_type(arg_type).components()) + { + binding.push_back(equal_exprt( + param_in_member_transformer(p_in, component), + arg_in_member_transformer(a_in, component, SSA, loc))); + } } + d.push_back(conjunction(binding)); } - d.push_back(conjunction(binding)); - } - if (!d.empty()) - c.push_back(disjunction(d)); + if(!d.empty()) + c.push_back(disjunction(d)); - d.clear(); - for(const exprt &p_out : params_deref_out) - { - for(const exprt &a_out : args_deref_out) + d.clear(); + for(const exprt &p_out : params_deref_out) { - if(!cs_heap_covered(a_out)) + for(const exprt &a_out : args_deref_out) { - exprt::operandst binding; + if(!cs_heap_covered(a_out)) + { + exprt::operandst binding; - binding.push_back(equal_exprt( - param_out_transformer(p_out, arg_type, summary.globals_out), - arg_out_transformer(a_out, arg_symbol_type, p_out.type(), SSA, loc))); + binding.push_back(equal_exprt( + param_out_transformer(p_out, arg_type, summary.globals_out), + arg_out_transformer(a_out, arg_symbol_type, p_out.type(), SSA, loc))); - if(arg_type.id()==ID_struct) - { - for(auto &component : to_struct_type(arg_type).components()) + if(arg_type.id()==ID_struct) { - binding.push_back(equal_exprt( - param_out_member_transformer(p_out, component, summary.globals_out), - arg_out_member_transformer(a_out, component, SSA, loc))); + for (auto &component : to_struct_type(arg_type).components()) + { + binding.push_back(equal_exprt( + param_out_member_transformer(p_out, component, summary.globals_out), + arg_out_member_transformer(a_out, component, SSA, loc))); + } } + d.push_back(conjunction(binding)); } - d.push_back(conjunction(binding)); } } + if(!d.empty()) + c.push_back(disjunction(d)); } - if(!d.empty()) - c.push_back(disjunction(d)); } args_in = args_deref_in; @@ -1051,6 +1054,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++) { @@ -1243,21 +1251,17 @@ std::list ssa_inlinert::apply_dereference( for (auto &e : tmp) result.push_back(e); } - else if (expr.id() != ID_constant) - { - assert(false); - } } return result; } /*******************************************************************\ -Function: ssa_inlinert::contains_advancer +Function: ssa_inlinert::contains_iterator Inputs: List of expressions - Outputs: True if the list contains an advancer + Outputs: True if the list contains an iterator Purpose: @@ -1395,7 +1399,8 @@ exprt ssa_inlinert::get_replace_new_objects( const ssa_heap_domaint &heap_domain=SSA.heap_analysis[next_loc]; const std::list callee_objects=heap_domain.new_objects(fname); - const std::list caller_objects=heap_domain.new_caller_objects(fname, loc); + const std::list caller_objects= + heap_domain.new_caller_objects(fname, loc); exprt::operandst binding; auto callee_it=callee_objects.begin(); @@ -1414,8 +1419,10 @@ exprt ssa_inlinert::get_replace_new_objects( for(auto &component : to_struct_type(type).components()) { binding.push_back(equal_exprt( - param_out_member_transformer(*callee_it, component, summary.globals_out), - arg_out_member_transformer(*caller_it, component, SSA, loc))); + param_out_member_transformer( + *callee_it, component, summary.globals_out), + arg_out_member_transformer( + *caller_it, component, SSA, loc))); } } } diff --git a/src/ssa/ssa_value_set.cpp b/src/ssa/ssa_value_set.cpp index d6803682a..de776e74b 100644 --- a/src/ssa/ssa_value_set.cpp +++ b/src/ssa/ssa_value_set.cpp @@ -62,7 +62,12 @@ void ssa_value_domaint::transform( to_code_function_call(from->code); const irep_idt &fname = to_symbol_expr(code_function_call.function()).get_identifier(); - const ssa_heap_domaint &heap_domain = static_cast(ai).heap_analysis[to]; + const ssa_value_ait & value_analysis = static_cast(ai); + + const ssa_heap_domaint *heap_domain = NULL; + if (value_analysis.heap_analysis.has_location(to)) + heap_domain = &value_analysis.heap_analysis[to]; + // functions may alter state almost arbitrarily: // * any global-scoped variables @@ -93,7 +98,9 @@ void ssa_value_domaint::transform( symbol_exprt pointed_obj = pointed_object(arg, ns); pointed_obj.type().set("#dynamic", true); - std::set new_objects = heap_domain.value(arg_expr); + std::set new_objects; + if (heap_domain) + new_objects = heap_domain->value(arg_expr); if (new_objects.empty()) { new_objects.insert(pointed_obj); @@ -121,6 +128,8 @@ void ssa_value_domaint::transform( assert(arg_expr.id() == ID_typecast); arg = arg_expr = to_typecast_expr(arg).op(); } + else + break; } } @@ -138,7 +147,9 @@ void ssa_value_domaint::transform( if (return_value.type().id() == ID_pointer && return_value.get_identifier() == id2string(fname) + "#return_value") { - std::set new_objects = heap_domain.value(return_value); + std::set new_objects; + if (heap_domain) + new_objects = heap_domain->value(return_value); if (new_objects.empty()) { symbol_exprt pointed_obj = pointed_object(return_value, ns); @@ -156,9 +167,12 @@ void ssa_value_domaint::transform( objects.push_back(*it); } - for (auto &new_o : heap_domain.new_caller_objects(fname, from)) + if (heap_domain) { - objects.push_back(new_o); + for (auto &new_o : heap_domain->new_caller_objects(fname, from)) + { + objects.push_back(new_o); + } } } } From 10b170f8c528cb63c788d9d0de0b8f296dba53b8 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 21 Jul 2017 07:54:09 +0200 Subject: [PATCH 085/322] Change heap regression tests. Add working tests for SLL to DLL transformation. --- .../main.c | 43 +- .../{pointer3 => dll2_segments}/test.desc | 2 +- regression/heap/pointer1/main.c | 12 - regression/heap/pointer1/test.desc | 6 - regression/heap/pointer2/main.c | 14 - regression/heap/pointer2/test.desc | 6 - regression/heap/pointer3/main.c | 12 - regression/heap/pointer4/main.c | 15 - regression/heap/pointer4/test.desc | 6 - regression/heap/pointer5/main.c | 15 - regression/heap/pointer5/test.desc | 6 - regression/heap/pointer6/main.c | 16 - regression/heap/pointer6/test.desc | 6 - regression/heap/pointer7/main.c | 10 - regression/heap/pointer7/test.desc | 6 - regression/heap/sll1_simple/main.c | 69 - regression/heap/sll1_simple/main.out.old | 1120 ----------------- regression/heap/sll1_simple/test.desc | 6 - regression/heap/sll2_nondet_loops/main.c | 66 - regression/heap/sll2_nondet_loops/test.desc | 6 - regression/heap/sll_to_dll1_reverse/test.desc | 6 - 21 files changed, 25 insertions(+), 1423 deletions(-) rename regression/heap/{sll_to_dll1_reverse => dll2_segments}/main.c (79%) rename regression/heap/{pointer3 => dll2_segments}/test.desc (56%) delete mode 100644 regression/heap/pointer1/main.c delete mode 100644 regression/heap/pointer1/test.desc delete mode 100644 regression/heap/pointer2/main.c delete mode 100644 regression/heap/pointer2/test.desc delete mode 100644 regression/heap/pointer3/main.c delete mode 100644 regression/heap/pointer4/main.c delete mode 100644 regression/heap/pointer4/test.desc delete mode 100644 regression/heap/pointer5/main.c delete mode 100644 regression/heap/pointer5/test.desc delete mode 100644 regression/heap/pointer6/main.c delete mode 100644 regression/heap/pointer6/test.desc delete mode 100644 regression/heap/pointer7/main.c delete mode 100644 regression/heap/pointer7/test.desc delete mode 100644 regression/heap/sll1_simple/main.c delete mode 100644 regression/heap/sll1_simple/main.out.old delete mode 100644 regression/heap/sll1_simple/test.desc delete mode 100644 regression/heap/sll2_nondet_loops/main.c delete mode 100644 regression/heap/sll2_nondet_loops/test.desc delete mode 100644 regression/heap/sll_to_dll1_reverse/test.desc diff --git a/regression/heap/sll_to_dll1_reverse/main.c b/regression/heap/dll2_segments/main.c similarity index 79% rename from regression/heap/sll_to_dll1_reverse/main.c rename to regression/heap/dll2_segments/main.c index f25d00f7e..e9c81d319 100644 --- a/regression/heap/sll_to_dll1_reverse/main.c +++ b/regression/heap/dll2_segments/main.c @@ -4,6 +4,16 @@ extern void __VERIFIER_error() __attribute__ ((__noreturn__)); extern int __VERIFIER_nondet_int(void); +static void fail(void) { +ERROR: __VERIFIER_error(); +} + +#define ___SL_ASSERT(cond) do { \ + if (!(cond)) \ + fail(); \ + assert(cond); \ +} while (0) + struct node { struct node *next; struct node *prev; @@ -12,8 +22,6 @@ struct node { static struct node* alloc_node(void) { struct node *ptr = malloc(sizeof *ptr); - // if (!ptr) - // abort(); ptr->next = NULL; ptr->prev = NULL; @@ -51,24 +59,24 @@ static struct node* create_sll(const struct node **pp1, const struct node **pp2) } void init_back_link(struct node *list) { - while (list) { + for (;;) { struct node *next = list->next; - // if (!next) - // return; + if (!next) + return; next->prev = list; list = next; } } -void reverse_dll(struct node *list) { - while (list) { - struct node *next = list->next; - list->next = list->prev; - list->prev = next; - list = next; - } -} +// void reverse_dll(struct node *list) { +// while (list) { +// struct node *next = list->next; +// list->next = list->prev; +// list->prev = next; +// list = next; +// } +// } void remove_fw_link(struct node *list) { while (list) { @@ -99,19 +107,16 @@ void main() const struct node *p1, *p2; struct node *list = create_sll(&p1, &p2); - assert(p1->prev == NULL); - assert(p2->prev == NULL); + check_seq_next(p1, p2); init_back_link(list); + check_seq_next(p1, p2); check_seq_prev(p2, p1); - // reverse_dll(list); - // check_seq_prev(p1, p2); - // check_seq_next(p2, p1); - remove_fw_link(list); + check_seq_prev(p2, p1); } diff --git a/regression/heap/pointer3/test.desc b/regression/heap/dll2_segments/test.desc similarity index 56% rename from regression/heap/pointer3/test.desc rename to regression/heap/dll2_segments/test.desc index c90269dfc..f4875431c 100644 --- a/regression/heap/pointer3/test.desc +++ b/regression/heap/dll2_segments/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap +--heap --context-sensitive --no-propagation ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/pointer1/main.c b/regression/heap/pointer1/main.c deleted file mode 100644 index 34c87bb31..000000000 --- a/regression/heap/pointer1/main.c +++ /dev/null @@ -1,12 +0,0 @@ -void foo(int *x) -{ - *x = 10; -} - -void main() -{ - int x; - foo(&x); - assert(x==10); -} - diff --git a/regression/heap/pointer1/test.desc b/regression/heap/pointer1/test.desc deleted file mode 100644 index 9ebb38e34..000000000 --- a/regression/heap/pointer1/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c - -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/pointer2/main.c b/regression/heap/pointer2/main.c deleted file mode 100644 index 02f54b869..000000000 --- a/regression/heap/pointer2/main.c +++ /dev/null @@ -1,14 +0,0 @@ -void foo(int *x) -{ - x++; - *x = 10; -} - -void main() -{ - int x[2]; - foo(&x); - int y = x[1]; - assert(y==10); -} - diff --git a/regression/heap/pointer2/test.desc b/regression/heap/pointer2/test.desc deleted file mode 100644 index c90269dfc..000000000 --- a/regression/heap/pointer2/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/pointer3/main.c b/regression/heap/pointer3/main.c deleted file mode 100644 index 098f61866..000000000 --- a/regression/heap/pointer3/main.c +++ /dev/null @@ -1,12 +0,0 @@ -#include - -void main() -{ - int x = 0; - int *p = &x; - int *y = p; - for(int i=0;i<10;i++) y = p; - assert(p!=NULL); - assert(y!=NULL); - *y = *p; -} diff --git a/regression/heap/pointer4/main.c b/regression/heap/pointer4/main.c deleted file mode 100644 index 0119e4601..000000000 --- a/regression/heap/pointer4/main.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -int *foo() -{ - return NULL; -} - -void main() -{ - int x = 0; - int *p = &x; - int *y = p; - for(int i=0;i<10;i++) y = foo(); - assert(y==NULL); -} diff --git a/regression/heap/pointer4/test.desc b/regression/heap/pointer4/test.desc deleted file mode 100644 index c90269dfc..000000000 --- a/regression/heap/pointer4/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/pointer5/main.c b/regression/heap/pointer5/main.c deleted file mode 100644 index 6dc5d56aa..000000000 --- a/regression/heap/pointer5/main.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -void foo(int **x) -{ - x = NULL; -} - -void main() -{ - int x = 0; - int *p = &x; - int *y = p; - for(int i=0;i<10;i++) foo(y); - assert(y==NULL); -} diff --git a/regression/heap/pointer5/test.desc b/regression/heap/pointer5/test.desc deleted file mode 100644 index c90269dfc..000000000 --- a/regression/heap/pointer5/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/pointer6/main.c b/regression/heap/pointer6/main.c deleted file mode 100644 index 676c04b24..000000000 --- a/regression/heap/pointer6/main.c +++ /dev/null @@ -1,16 +0,0 @@ -#include - -int *foo(int *x) -{ - return x; -} - -void main() -{ - int x = 0; - int *y; - - y = foo(&x); - - assert(y!=NULL); -} diff --git a/regression/heap/pointer6/test.desc b/regression/heap/pointer6/test.desc deleted file mode 100644 index c90269dfc..000000000 --- a/regression/heap/pointer6/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/pointer7/main.c b/regression/heap/pointer7/main.c deleted file mode 100644 index 28c9e0ab5..000000000 --- a/regression/heap/pointer7/main.c +++ /dev/null @@ -1,10 +0,0 @@ -#include - -void main() -{ - int x[10]; - int *end = &x[9]; - int *p = x; - for(; p!=end; p++); - assert(p==end); -} diff --git a/regression/heap/pointer7/test.desc b/regression/heap/pointer7/test.desc deleted file mode 100644 index 38318bb3b..000000000 --- a/regression/heap/pointer7/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -KNOWNBUG -main.c ---heap -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/sll1_simple/main.c b/regression/heap/sll1_simple/main.c deleted file mode 100644 index ef5784cb8..000000000 --- a/regression/heap/sll1_simple/main.c +++ /dev/null @@ -1,69 +0,0 @@ -#include - -extern int __VERIFIER_nondet_int(void); - -struct node { - struct node *next; -}; - -static struct node* alloc_node(void) -{ - struct node *ptr = malloc(sizeof *ptr); - if (!ptr) - abort(); - - ptr->next = NULL; - return ptr; -} - -static void chain_node(struct node **ppnode) -{ - struct node *node = alloc_node(); - node->next = *ppnode; - *ppnode = node; -} - -static struct node* create_sll(const struct node **pp1, const struct node **pp2) -{ - *pp2 = NULL; - - for (int i = 0; i < 2; ++i) - { - chain_node(pp2); - } - - *pp1 = *pp2; - - for (int i = 0; i < 2; ++i) - { - chain_node(pp1); - } - - struct node *list = *pp1; - - for (int i = 0; i < 2; ++i) - { - chain_node(&list); - } - - return list; -} - -void check_seq_next(const struct node *beg, const struct node *const end) { - assert(beg != NULL); - assert(end != NULL); - - for (beg = beg->next; end != beg; beg = beg->next) - assert(beg != NULL); -} - -void main() -{ - const struct node *p1, *p2; - - struct node *list = create_sll(&p1, &p2); - check_seq_next(list, p1); - check_seq_next(p1, p2); - -} - diff --git a/regression/heap/sll1_simple/main.out.old b/regression/heap/sll1_simple/main.out.old deleted file mode 100644 index af5a78516..000000000 --- a/regression/heap/sll1_simple/main.out.old +++ /dev/null @@ -1,1120 +0,0 @@ -2LS version 0.3.4 (based on CBMC 5.4) -Parsing main.c -Converting -Type-checking main -file main.c line 53 function check_seq_next: function `assert' is not declared -Generating GOTO Program -Adding CPROVER library -Generic Property Instrumentation -Function Pointer Removal -Performing full inlining -Using heap domain -Computing SSA of _start -Simplifying -(E) $guard#0 == TRUE - -(E) __CPROVER_dead_object#2 == NULL - -(E) __CPROVER_deallocated#3 == NULL - -(E) __CPROVER_malloc_is_new_array#4 == FALSE - -(E) __CPROVER_malloc_object#5 == NULL - -(E) __CPROVER_malloc_size#6 == 0ul - -(E) __CPROVER_memory_leak#7 == NULL - -(E) __CPROVER_next_thread_id#8 == 0ul - -(E) __CPROVER_pipe_count#9 == 0u - -(E) __CPROVER_rounding_mode#10 == 0 - -(E) __CPROVER_thread_id#11 == 0ul - -(E) __CPROVER_threads_exited#12 == ARRAY_OF(FALSE) - -(E) p1#16 == nondet_symbol(ssa::nondet16.1) - -(E) p2#18 == nondet_symbol(ssa::nondet18.1) - -(E) list#20 == nondet_symbol(ssa::nondet20.1) - -(E) pp1#23 == nondet_symbol(ssa::nondet23.1) - -(E) pp1#24 == &p1 - -(E) pp2#26 == nondet_symbol(ssa::nondet26.1) - -(E) pp2#27 == &p2 - -(E) p2#28 == ((struct node *)NULL) - -(E) i#30 == nondet_symbol(ssa::nondet30.1) - -(E) i#31 == 0 - -(E) __CPROVER_deallocated#phi32 == ($guard#ls101 ? __CPROVER_deallocated#lb101 : __CPROVER_deallocated#3) -(E) __CPROVER_malloc_object#phi32 == ($guard#ls101 ? __CPROVER_malloc_object#lb101 : __CPROVER_malloc_object#5) -(E) __CPROVER_malloc_size#phi32 == ($guard#ls101 ? __CPROVER_malloc_size#lb101 : __CPROVER_malloc_size#6) -(E) __CPROVER_malloc_is_new_array#phi32 == ($guard#ls101 ? __CPROVER_malloc_is_new_array#lb101 : __CPROVER_malloc_is_new_array#4) -(E) __CPROVER_memory_leak#phi32 == ($guard#ls101 ? __CPROVER_memory_leak#lb101 : __CPROVER_memory_leak#7) -(E) i#phi32 == ($guard#ls101 ? i#lb101 : i#31) -(E) p2#phi32 == ($guard#ls101 ? p2#lb101 : p2#28) -(E) dynamic_object$0.next#phi32 == ($guard#ls101 ? dynamic_object$0.next#lb101 : dynamic_object$0.next) -(E) $cond#32 == i#phi32 >= 2 -(E) $guard#32 == $guard#0 - -(E) $guard#33 == (!$cond#32 && $guard#32) - -(E) ppnode#35 == nondet_symbol(ssa::nondet35.1) - -(E) ppnode#36 == pp2#27 - -(E) node#38 == nondet_symbol(ssa::nondet38.1) - -(E) ptr#41 == nondet_symbol(ssa::nondet41.1) - -(E) return_value_malloc$1#43 == nondet_symbol(ssa::nondet43.1) - -(E) malloc_size#46 == nondet_symbol(ssa::nondet46.1) - -(E) malloc_size#47 == sizeof(struct node) /*8ul*/ - -(E) malloc_res#50 == nondet_symbol(ssa::nondet50.1) - -(E) malloc_value$1#52 == nondet_symbol(ssa::nondet52.1) - -(E) malloc_value$1#53 == (void *)&dynamic_object$0 - -(E) malloc_res#54 == malloc_value$1#53 - -(E) __CPROVER_deallocated#56 == (malloc_res#54 == __CPROVER_deallocated#phi32 ? NULL : __CPROVER_deallocated#phi32) - -(E) record_malloc#58 == nondet_symbol(ssa::nondet58.1) - -(E) __CPROVER_malloc_object#59 == (record_malloc#58 ? malloc_res#54 : __CPROVER_malloc_object#phi32) - -(E) __CPROVER_malloc_size#60 == (record_malloc#58 ? malloc_size#47 : __CPROVER_malloc_size#phi32) - -(E) __CPROVER_malloc_is_new_array#61 == (!record_malloc#58 && __CPROVER_malloc_is_new_array#phi32) - -(E) record_may_leak#63 == nondet_symbol(ssa::nondet63.1) - -(E) __CPROVER_memory_leak#64 == (record_may_leak#63 ? malloc_res#54 : __CPROVER_memory_leak#phi32) - -(E) malloc#return_value#65 == malloc_res#54 - -(E) $cond#70 == TRUE - -(E) $guard#71 == FALSE - -(E) $guard#75 == ($cond#70 && $guard#33 || $guard#71) - -(E) return_value_malloc$1#77 == malloc#return_value#65 - -(E) ptr#79 == (struct node *)return_value_malloc$1#77 - -(E) $cond#81 == !(ptr#79 == ((struct node *)NULL)) - -(E) $guard#82 == (!$cond#81 && $guard#75) - -(E) $cond#83 == FALSE - -(E) $guard#84 == ($cond#83 && $guard#82) - -(E) dynamic_object$0.next#85 == ((struct node *)NULL) -(E) $guard#85 == ($cond#81 && $guard#75 || $guard#84) - -(E) alloc_node#return_value#86 == ptr#79 - -(E) $cond#89 == TRUE - -(E) $guard#90 == FALSE - -(E) $guard#92 == ($cond#89 && $guard#85 || $guard#90) - -(E) node#93 == alloc_node#return_value#86 - -(E) dynamic_object$0.next#95 == (ppnode#36 == &p2 ? p2#phi32 : deref#95) - -(E) p2#96 == node#93 - -(E) i#100 == 1 + i#phi32 - -(E) $cond#101 == TRUE - -(E) $guard#102 == ($cond#32 && $guard#32) - -(E) p1#103 == (pp2#27 == &p2 ? p2#phi32 : deref#103) - -(E) i#105 == nondet_symbol(ssa::nondet105.1) - -(E) i#106 == 0 - -(E) __CPROVER_deallocated#phi107 == ($guard#ls176 ? __CPROVER_deallocated#lb176 : __CPROVER_deallocated#phi32) -(E) __CPROVER_malloc_object#phi107 == ($guard#ls176 ? __CPROVER_malloc_object#lb176 : __CPROVER_malloc_object#phi32) -(E) __CPROVER_malloc_size#phi107 == ($guard#ls176 ? __CPROVER_malloc_size#lb176 : __CPROVER_malloc_size#phi32) -(E) __CPROVER_malloc_is_new_array#phi107 == ($guard#ls176 ? __CPROVER_malloc_is_new_array#lb176 : __CPROVER_malloc_is_new_array#phi32) -(E) __CPROVER_memory_leak#phi107 == ($guard#ls176 ? __CPROVER_memory_leak#lb176 : __CPROVER_memory_leak#phi32) -(E) i#phi107 == ($guard#ls176 ? i#lb176 : i#106) -(E) p1#phi107 == ($guard#ls176 ? p1#lb176 : p1#103) -(E) dynamic_object$1.next#phi107 == ($guard#ls176 ? dynamic_object$1.next#lb176 : dynamic_object$1.next) -(E) $cond#107 == i#phi107 >= 2 -(E) $guard#107 == $guard#102 - -(E) $guard#108 == (!$cond#107 && $guard#107) - -(E) ppnode#110 == nondet_symbol(ssa::nondet110.1) - -(E) ppnode#111 == pp1#24 - -(E) node#113 == nondet_symbol(ssa::nondet113.1) - -(E) ptr#116 == nondet_symbol(ssa::nondet116.1) - -(E) return_value_malloc$1#118 == nondet_symbol(ssa::nondet118.1) - -(E) malloc_size#121 == nondet_symbol(ssa::nondet121.1) - -(E) malloc_size#122 == sizeof(struct node) /*8ul*/ - -(E) malloc_res#125 == nondet_symbol(ssa::nondet125.1) - -(E) malloc_value$1#127 == nondet_symbol(ssa::nondet127.1) - -(E) malloc_value$1#128 == (void *)&dynamic_object$1 - -(E) malloc_res#129 == malloc_value$1#128 - -(E) __CPROVER_deallocated#131 == (malloc_res#129 == __CPROVER_deallocated#phi107 ? NULL : __CPROVER_deallocated#phi107) - -(E) record_malloc#133 == nondet_symbol(ssa::nondet133.1) - -(E) __CPROVER_malloc_object#134 == (record_malloc#133 ? malloc_res#129 : __CPROVER_malloc_object#phi107) - -(E) __CPROVER_malloc_size#135 == (record_malloc#133 ? malloc_size#122 : __CPROVER_malloc_size#phi107) - -(E) __CPROVER_malloc_is_new_array#136 == (!record_malloc#133 && __CPROVER_malloc_is_new_array#phi107) - -(E) record_may_leak#138 == nondet_symbol(ssa::nondet138.1) - -(E) __CPROVER_memory_leak#139 == (record_may_leak#138 ? malloc_res#129 : __CPROVER_memory_leak#phi107) - -(E) malloc#return_value#140 == malloc_res#129 - -(E) $cond#145 == TRUE - -(E) $guard#146 == FALSE - -(E) $guard#150 == ($cond#145 && $guard#108 || $guard#146) - -(E) return_value_malloc$1#152 == malloc#return_value#140 - -(E) ptr#154 == (struct node *)return_value_malloc$1#152 - -(E) $cond#156 == !(ptr#154 == ((struct node *)NULL)) - -(E) $guard#157 == (!$cond#156 && $guard#150) - -(E) $cond#158 == FALSE - -(E) $guard#159 == ($cond#158 && $guard#157) - -(E) dynamic_object$1.next#160 == ((struct node *)NULL) -(E) $guard#160 == ($cond#156 && $guard#150 || $guard#159) - -(E) alloc_node#return_value#161 == ptr#154 - -(E) $cond#164 == TRUE - -(E) $guard#165 == FALSE - -(E) $guard#167 == ($cond#164 && $guard#160 || $guard#165) - -(E) node#168 == alloc_node#return_value#161 - -(E) dynamic_object$1.next#170 == (ppnode#111 == &p1 ? p1#phi107 : deref#170) - -(E) p1#171 == node#168 - -(E) i#175 == 1 + i#phi107 - -(E) $cond#176 == TRUE - -(E) $guard#177 == ($cond#107 && $guard#107) - -(E) list#179 == nondet_symbol(ssa::nondet179.1) - -(E) list#180 == (pp1#24 == &p1 ? p1#phi107 : deref#180) - -(E) i#182 == nondet_symbol(ssa::nondet182.1) - -(E) i#183 == 0 - -(E) __CPROVER_deallocated#phi184 == ($guard#ls253 ? __CPROVER_deallocated#lb253 : __CPROVER_deallocated#phi107) -(E) __CPROVER_malloc_object#phi184 == ($guard#ls253 ? __CPROVER_malloc_object#lb253 : __CPROVER_malloc_object#phi107) -(E) __CPROVER_malloc_size#phi184 == ($guard#ls253 ? __CPROVER_malloc_size#lb253 : __CPROVER_malloc_size#phi107) -(E) __CPROVER_malloc_is_new_array#phi184 == ($guard#ls253 ? __CPROVER_malloc_is_new_array#lb253 : __CPROVER_malloc_is_new_array#phi107) -(E) __CPROVER_memory_leak#phi184 == ($guard#ls253 ? __CPROVER_memory_leak#lb253 : __CPROVER_memory_leak#phi107) -(E) list#phi184 == ($guard#ls253 ? list#lb253 : list#180) -(E) i#phi184 == ($guard#ls253 ? i#lb253 : i#183) -(E) dynamic_object$2.next#phi184 == ($guard#ls253 ? dynamic_object$2.next#lb253 : dynamic_object$2.next) -(E) $cond#184 == i#phi184 >= 2 -(E) $guard#184 == $guard#177 - -(E) $guard#185 == (!$cond#184 && $guard#184) - -(E) ppnode#187 == nondet_symbol(ssa::nondet187.1) - -(E) ppnode#188 == &list - -(E) node#190 == nondet_symbol(ssa::nondet190.1) - -(E) ptr#193 == nondet_symbol(ssa::nondet193.1) - -(E) return_value_malloc$1#195 == nondet_symbol(ssa::nondet195.1) - -(E) malloc_size#198 == nondet_symbol(ssa::nondet198.1) - -(E) malloc_size#199 == sizeof(struct node) /*8ul*/ - -(E) malloc_res#202 == nondet_symbol(ssa::nondet202.1) - -(E) malloc_value$1#204 == nondet_symbol(ssa::nondet204.1) - -(E) malloc_value$1#205 == (void *)&dynamic_object$2 - -(E) malloc_res#206 == malloc_value$1#205 - -(E) __CPROVER_deallocated#208 == (malloc_res#206 == __CPROVER_deallocated#phi184 ? NULL : __CPROVER_deallocated#phi184) - -(E) record_malloc#210 == nondet_symbol(ssa::nondet210.1) - -(E) __CPROVER_malloc_object#211 == (record_malloc#210 ? malloc_res#206 : __CPROVER_malloc_object#phi184) - -(E) __CPROVER_malloc_size#212 == (record_malloc#210 ? malloc_size#199 : __CPROVER_malloc_size#phi184) - -(E) __CPROVER_malloc_is_new_array#213 == (!record_malloc#210 && __CPROVER_malloc_is_new_array#phi184) - -(E) record_may_leak#215 == nondet_symbol(ssa::nondet215.1) - -(E) __CPROVER_memory_leak#216 == (record_may_leak#215 ? malloc_res#206 : __CPROVER_memory_leak#phi184) - -(E) malloc#return_value#217 == malloc_res#206 - -(E) $cond#222 == TRUE - -(E) $guard#223 == FALSE - -(E) $guard#227 == ($cond#222 && $guard#185 || $guard#223) - -(E) return_value_malloc$1#229 == malloc#return_value#217 - -(E) ptr#231 == (struct node *)return_value_malloc$1#229 - -(E) $cond#233 == !(ptr#231 == ((struct node *)NULL)) - -(E) $guard#234 == (!$cond#233 && $guard#227) - -(E) $cond#235 == FALSE - -(E) $guard#236 == ($cond#235 && $guard#234) - -(E) dynamic_object$2.next#237 == ((struct node *)NULL) -(E) $guard#237 == ($cond#233 && $guard#227 || $guard#236) - -(E) alloc_node#return_value#238 == ptr#231 - -(E) $cond#241 == TRUE - -(E) $guard#242 == FALSE - -(E) $guard#244 == ($cond#241 && $guard#237 || $guard#242) - -(E) node#245 == alloc_node#return_value#238 - -(E) dynamic_object$2.next#247 == (ppnode#188 == &list ? list#phi184 : deref#247) - -(E) list#248 == node#245 - -(E) i#252 == 1 + i#phi184 - -(E) $cond#253 == TRUE - -(E) $guard#254 == ($cond#184 && $guard#184) - -(E) create_sll#return_value#255 == list#phi184 - -(E) $cond#257 == TRUE - -(E) $guard#258 == FALSE - -(E) $guard#259 == ($cond#257 && $guard#254 || $guard#258) - -(E) list#262 == create_sll#return_value#255 - -(E) beg#266 == nondet_symbol(ssa::nondet266.1) - -(E) beg#267 == list#262 - -(E) end#269 == nondet_symbol(ssa::nondet269.1) - -(E) end#270 == p1#phi107 - -(A) !(beg#267 == ((struct node *)NULL)) || !$guard#259 - -(A) !(end#270 == ((struct node *)NULL)) || !$guard#259 - -(E) beg#273 == (beg#267 == &dynamic_object$2 ? dynamic_object$2.next#phi184 : (beg#267 == &dynamic_object$1 ? dynamic_object$1.next#phi107 : (beg#267 == &dynamic_object$0 ? dynamic_object$0.next#phi32 : deref#273.next))) - -(E) beg#phi274 == ($guard#ls277 ? beg#lb277 : beg#273) -(E) $cond#274 == (end#270 == beg#phi274) -(E) $guard#274 == $guard#259 - -(E) $guard#275 == (!$cond#274 && $guard#274) -(A) !(beg#phi274 == ((struct node *)NULL)) || !$guard#275 - -(E) beg#276 == (beg#phi274 == &dynamic_object$2 ? dynamic_object$2.next#phi184 : (beg#phi274 == &dynamic_object$1 ? dynamic_object$1.next#phi107 : (beg#phi274 == &dynamic_object$0 ? dynamic_object$0.next#phi32 : deref#276.next))) - -(E) $cond#277 == TRUE - -(E) $guard#278 == ($cond#274 && $guard#274) - -(E) beg#283 == nondet_symbol(ssa::nondet283.1) - -(E) beg#284 == p1#phi107 - -(E) end#286 == nondet_symbol(ssa::nondet286.1) - -(E) end#287 == p2#phi32 - -(A) !(beg#284 == ((struct node *)NULL)) || !$guard#278 - -(A) !(end#287 == ((struct node *)NULL)) || !$guard#278 - -(E) beg#290 == (beg#284 == &dynamic_object$1 ? dynamic_object$1.next#phi107 : (beg#284 == &dynamic_object$0 ? dynamic_object$0.next#phi32 : deref#290.next)) - -(E) beg#phi291 == ($guard#ls294 ? beg#lb294 : beg#290) -(E) $cond#291 == (end#287 == beg#phi291) -(E) $guard#291 == $guard#278 - -(E) $guard#292 == (!$cond#291 && $guard#291) -(A) !(beg#phi291 == ((struct node *)NULL)) || !$guard#292 - -(E) beg#293 == (beg#phi291 == &dynamic_object$1 ? dynamic_object$1.next#phi107 : (beg#phi291 == &dynamic_object$0 ? dynamic_object$0.next#phi32 : deref#293.next)) - -(E) $cond#294 == TRUE - -(E) $guard#295 == ($cond#291 && $guard#291) - - - -Summarizing function _start -Analyzing function _start -Computing summary -Template: -(LOOP) [ $guard#32 && $guard#ls101 | $guard#92 && $cond#101 | $guard#92 && $cond#101 ] ===> - ?path(p2#lb101, DESTINATIONS) -(LOOP) [ $guard#32 && $guard#ls101 | $guard#92 && $cond#101 | $guard#92 && $cond#101 ] ===> - ?path(dynamic_object$0.next#lb101, DESTINATIONS) -(LOOP) [ $guard#107 && $guard#ls176 | $guard#167 && $cond#176 | $guard#167 && $cond#176 ] ===> - ?path(p1#lb176, DESTINATIONS) -(LOOP) [ $guard#107 && $guard#ls176 | $guard#167 && $cond#176 | $guard#167 && $cond#176 ] ===> - ?path(dynamic_object$1.next#lb176, DESTINATIONS) -(LOOP) [ $guard#184 && $guard#ls253 | $guard#244 && $cond#253 | $guard#244 && $cond#253 ] ===> - ?path(list#lb253, DESTINATIONS) -(LOOP) [ $guard#184 && $guard#ls253 | $guard#244 && $cond#253 | $guard#244 && $cond#253 ] ===> - ?path(dynamic_object$2.next#lb253, DESTINATIONS) -(LOOP) [ $guard#274 && $guard#ls277 | $guard#275 && $cond#277 | $guard#275 && $cond#277 ] ===> - ?path(beg#lb277, DESTINATIONS) -(LOOP) [ $guard#291 && $guard#ls294 | $guard#292 && $cond#294 | $guard#292 && $cond#294 ] ===> - ?path(beg#lb294, DESTINATIONS) - -updating row: 0 -add all paths: dynamic_object$0.next#lb101, through: dynamic_object$0 -add points to: dynamic_object$0 -updating row: 1 -add destination: ((struct node *)NULL) -recursively updating row: 0 -add all paths: dynamic_object$0.next#lb101, through: dynamic_object$0 -updating row: 2 -add all paths: dynamic_object$1.next#lb176, through: dynamic_object$1 -add points to: dynamic_object$1 -updating row: 3 -add all paths: dynamic_object$0.next#lb101, through: dynamic_object$0 -add points to: dynamic_object$0 -recursively updating row: 2 -add all paths: dynamic_object$1.next#lb176, through: dynamic_object$1 -updating row: 3 -add all paths: dynamic_object$1.next#lb176, through: dynamic_object$1 -add points to: dynamic_object$1 -recursively updating row: 2 -add all paths: dynamic_object$1.next#lb176, through: dynamic_object$1 -recursively updating row: 3 -add all paths: dynamic_object$1.next#lb176, through: dynamic_object$1 -updating row: 4 -add all paths: dynamic_object$2.next#lb253, through: dynamic_object$2 -add points to: dynamic_object$2 -updating row: 5 -add all paths: dynamic_object$1.next#lb176, through: dynamic_object$1 -add points to: dynamic_object$1 -recursively updating row: 4 -add all paths: dynamic_object$2.next#lb253, through: dynamic_object$2 -updating row: 5 -add all paths: dynamic_object$2.next#lb253, through: dynamic_object$2 -add points to: dynamic_object$2 -recursively updating row: 4 -add all paths: dynamic_object$2.next#lb253, through: dynamic_object$2 -recursively updating row: 5 -add all paths: dynamic_object$2.next#lb253, through: dynamic_object$2 -updating row: 7 -add all paths: dynamic_object$1.next#lb176, through: dynamic_object$1 -add points to: dynamic_object$1 -updating row: 7 -add all paths: dynamic_object$0.next#lb101, through: dynamic_object$0 -add points to: dynamic_object$0 -updating row: 6 -add all paths: dynamic_object$2.next#lb253, through: dynamic_object$2 -add points to: dynamic_object$2 -updating row: 6 -add all paths: dynamic_object$1.next#lb176, through: dynamic_object$1 -add points to: dynamic_object$1 -updating row: 1 -add all paths: dynamic_object$0.next#lb101, through: dynamic_object$0 -add points to: dynamic_object$0 -recursively updating row: 0 -add all paths: dynamic_object$0.next#lb101, through: dynamic_object$0 -recursively updating row: 1 -add all paths: dynamic_object$0.next#lb101, through: dynamic_object$0 -recursively updating row: 3 -add all paths: dynamic_object$0.next#lb101, through: dynamic_object$0 -recursively updating row: 7 -add all paths: dynamic_object$0.next#lb101, through: dynamic_object$0 - -Summary for function _start -params: -globals_in: __CPROVER_threads_exited __CPROVER_malloc_is_new_array __CPROVER_dead_object __CPROVER_deallocated __CPROVER_malloc_object __CPROVER_memory_leak ppnode'obj beg'obj.next end'obj.next pp1'obj pp2'obj __CPROVER_rounding_mode __CPROVER_pipe_count __CPROVER_malloc_size __CPROVER_next_thread_id __CPROVER_thread_id -globals_out: __CPROVER_threads_exited#12 __CPROVER_malloc_is_new_array#phi184 __CPROVER_dead_object#2 __CPROVER_deallocated#phi184 __CPROVER_malloc_object#phi184 __CPROVER_memory_leak#phi184 ppnode'obj beg'obj.next end'obj.next pp1'obj pp2'obj __CPROVER_rounding_mode#10 __CPROVER_pipe_count#9 __CPROVER_malloc_size#phi184 __CPROVER_next_thread_id#8 __CPROVER_thread_id#11 -forward precondition: TRUE -forward transformer: TRUE -forward invariant: ($guard#32 && $guard#ls101 ==> p2#lb101 == &dynamic_object$0 && (dynamic_object$0.next#lb101 == ((struct node *)NULL) || dynamic_object$0.next#lb101 == &dynamic_object$0)) && ($guard#32 && $guard#ls101 ==> dynamic_object$0.next#lb101 == ((struct node *)NULL) || dynamic_object$0.next#lb101 == &dynamic_object$0 && (dynamic_object$0.next#lb101 == ((struct node *)NULL) || dynamic_object$0.next#lb101 == &dynamic_object$0)) && ($guard#107 && $guard#ls176 ==> p1#lb176 == &dynamic_object$1 && (dynamic_object$1.next#lb176 == ((struct node *)NULL) || dynamic_object$1.next#lb176 == &dynamic_object$0 || dynamic_object$1.next#lb176 == &dynamic_object$1)) && ($guard#107 && $guard#ls176 ==> dynamic_object$1.next#lb176 == &dynamic_object$0 && (dynamic_object$0.next#lb101 == ((struct node *)NULL) || dynamic_object$0.next#lb101 == &dynamic_object$0 || dynamic_object$0.next#lb101 == &dynamic_object$1) || dynamic_object$1.next#lb176 == &dynamic_object$1 && (dynamic_object$1.next#lb176 == ((struct node *)NULL) || dynamic_object$1.next#lb176 == &dynamic_object$0 || dynamic_object$1.next#lb176 == &dynamic_object$1)) && ($guard#184 && $guard#ls253 ==> list#lb253 == &dynamic_object$2 && (dynamic_object$2.next#lb253 == ((struct node *)NULL) || dynamic_object$2.next#lb253 == &dynamic_object$0 || dynamic_object$2.next#lb253 == &dynamic_object$1 || dynamic_object$2.next#lb253 == &dynamic_object$2)) && ($guard#184 && $guard#ls253 ==> dynamic_object$2.next#lb253 == &dynamic_object$1 && (dynamic_object$1.next#lb176 == ((struct node *)NULL) || dynamic_object$1.next#lb176 == &dynamic_object$0 || dynamic_object$1.next#lb176 == &dynamic_object$1 || dynamic_object$1.next#lb176 == &dynamic_object$2) || dynamic_object$2.next#lb253 == &dynamic_object$2 && (dynamic_object$2.next#lb253 == ((struct node *)NULL) || dynamic_object$2.next#lb253 == &dynamic_object$0 || dynamic_object$2.next#lb253 == &dynamic_object$1 || dynamic_object$2.next#lb253 == &dynamic_object$2)) && ($guard#274 && $guard#ls277 ==> beg#lb277 == &dynamic_object$1 && (dynamic_object$1.next#lb176 == ((struct node *)NULL) || dynamic_object$1.next#lb176 == &dynamic_object$0 || dynamic_object$1.next#lb176 == &dynamic_object$1 || dynamic_object$1.next#lb176 == &dynamic_object$2) || beg#lb277 == &dynamic_object$2 && (dynamic_object$2.next#lb253 == ((struct node *)NULL) || dynamic_object$2.next#lb253 == &dynamic_object$0 || dynamic_object$2.next#lb253 == &dynamic_object$1 || dynamic_object$2.next#lb253 == &dynamic_object$2)) && ($guard#291 && $guard#ls294 ==> beg#lb294 == &dynamic_object$0 && (dynamic_object$0.next#lb101 == ((struct node *)NULL) || dynamic_object$0.next#lb101 == &dynamic_object$0 || dynamic_object$0.next#lb101 == &dynamic_object$1) || beg#lb294 == &dynamic_object$1 && (dynamic_object$1.next#lb176 == ((struct node *)NULL) || dynamic_object$1.next#lb176 == &dynamic_object$0 || dynamic_object$1.next#lb176 == &dynamic_object$1)) -backward precondition: not computed -backward postcondition: not computed -backward transformer: not computed -backward invariant: not computed -termination argument: not computed -terminates: unknown - -Checking properties of _start -*** 0 -(E) $guard#0 == TRUE - -*** 2 file line 39 -(E) __CPROVER_dead_object#2 == NULL - -*** 3 file line 38 -(E) __CPROVER_deallocated#3 == NULL - -*** 4 file line 42 -(E) __CPROVER_malloc_is_new_array#4 == FALSE - -*** 5 file line 40 -(E) __CPROVER_malloc_object#5 == NULL - -*** 6 file line 41 -(E) __CPROVER_malloc_size#6 == 0ul - -*** 7 file line 43 -(E) __CPROVER_memory_leak#7 == NULL - -*** 8 file line 31 -(E) __CPROVER_next_thread_id#8 == 0ul - -*** 9 file line 87 -(E) __CPROVER_pipe_count#9 == 0u - -*** 10 file line 65 -(E) __CPROVER_rounding_mode#10 == 0 - -*** 11 file line 29 -(E) __CPROVER_thread_id#11 == 0ul - -*** 12 file line 30 -(E) __CPROVER_threads_exited#12 == ARRAY_OF(FALSE) - -*** 16 file main.c line 62 function main -(E) p1#16 == nondet_symbol(ssa::nondet16.1) - -*** 18 file main.c line 62 function main -(E) p2#18 == nondet_symbol(ssa::nondet18.1) - -*** 20 file main.c line 64 function main -(E) list#20 == nondet_symbol(ssa::nondet20.1) - -*** 23 file main.c line 64 function main -(E) pp1#23 == nondet_symbol(ssa::nondet23.1) - -*** 24 file main.c line 64 function main -(E) pp1#24 == &p1 - -*** 26 file main.c line 64 function main -(E) pp2#26 == nondet_symbol(ssa::nondet26.1) - -*** 27 file main.c line 64 function main -(E) pp2#27 == &p2 - -*** 28 file main.c line 28 function create_sll -(E) p2#28 == ((struct node *)NULL) - -*** 30 file main.c line 30 function create_sll -(E) i#30 == nondet_symbol(ssa::nondet30.1) - -*** 31 file main.c line 30 function create_sll -(E) i#31 == 0 - -*** 32 file main.c line 30 function create_sll -(E) __CPROVER_deallocated#phi32 == ($guard#ls101 ? __CPROVER_deallocated#lb101 : __CPROVER_deallocated#3) -(E) __CPROVER_malloc_object#phi32 == ($guard#ls101 ? __CPROVER_malloc_object#lb101 : __CPROVER_malloc_object#5) -(E) __CPROVER_malloc_size#phi32 == ($guard#ls101 ? __CPROVER_malloc_size#lb101 : __CPROVER_malloc_size#6) -(E) __CPROVER_malloc_is_new_array#phi32 == ($guard#ls101 ? __CPROVER_malloc_is_new_array#lb101 : __CPROVER_malloc_is_new_array#4) -(E) __CPROVER_memory_leak#phi32 == ($guard#ls101 ? __CPROVER_memory_leak#lb101 : __CPROVER_memory_leak#7) -(E) i#phi32 == ($guard#ls101 ? i#lb101 : i#31) -(E) p2#phi32 == ($guard#ls101 ? p2#lb101 : p2#28) -(E) dynamic_object$0.next#phi32 == ($guard#ls101 ? dynamic_object$0.next#lb101 : dynamic_object$0.next) -(E) $cond#32 == i#phi32 >= 2 -(E) $guard#32 == $guard#0 - -*** 33 file main.c line 32 function create_sll -(E) $guard#33 == (!$cond#32 && $guard#32) - -*** 35 file main.c line 32 function create_sll -(E) ppnode#35 == nondet_symbol(ssa::nondet35.1) - -*** 36 file main.c line 32 function create_sll -(E) ppnode#36 == pp2#27 - -*** 38 file main.c line 21 function chain_node -(E) node#38 == nondet_symbol(ssa::nondet38.1) - -*** 41 file main.c line 11 function alloc_node -(E) ptr#41 == nondet_symbol(ssa::nondet41.1) - -*** 43 file main.c line 11 function alloc_node -(E) return_value_malloc$1#43 == nondet_symbol(ssa::nondet43.1) - -*** 46 file main.c line 11 function alloc_node -(E) malloc_size#46 == nondet_symbol(ssa::nondet46.1) - -*** 47 file main.c line 11 function alloc_node -(E) malloc_size#47 == sizeof(struct node) /*8ul*/ - -*** 50 file main.c line 11 function alloc_node -(E) malloc_res#50 == nondet_symbol(ssa::nondet50.1) - -*** 52 file main.c line 11 function alloc_node -(E) malloc_value$1#52 == nondet_symbol(ssa::nondet52.1) - -*** 53 file main.c line 11 function alloc_node -(E) malloc_value$1#53 == (void *)&dynamic_object$0 - -*** 54 file main.c line 11 function alloc_node -(E) malloc_res#54 == malloc_value$1#53 - -*** 56 file main.c line 11 function alloc_node -(E) __CPROVER_deallocated#56 == (malloc_res#54 == __CPROVER_deallocated#phi32 ? NULL : __CPROVER_deallocated#phi32) - -*** 58 file main.c line 11 function alloc_node -(E) record_malloc#58 == nondet_symbol(ssa::nondet58.1) - -*** 59 file main.c line 11 function alloc_node -(E) __CPROVER_malloc_object#59 == (record_malloc#58 ? malloc_res#54 : __CPROVER_malloc_object#phi32) - -*** 60 file main.c line 11 function alloc_node -(E) __CPROVER_malloc_size#60 == (record_malloc#58 ? malloc_size#47 : __CPROVER_malloc_size#phi32) - -*** 61 file main.c line 11 function alloc_node -(E) __CPROVER_malloc_is_new_array#61 == (!record_malloc#58 && __CPROVER_malloc_is_new_array#phi32) - -*** 63 file main.c line 11 function alloc_node -(E) record_may_leak#63 == nondet_symbol(ssa::nondet63.1) - -*** 64 file main.c line 11 function alloc_node -(E) __CPROVER_memory_leak#64 == (record_may_leak#63 ? malloc_res#54 : __CPROVER_memory_leak#phi32) - -*** 65 file main.c line 11 function alloc_node -(E) malloc#return_value#65 == malloc_res#54 - -*** 70 file main.c line 11 function alloc_node -(E) $cond#70 == TRUE - -*** 71 file main.c line 11 function alloc_node -(E) $guard#71 == FALSE - -*** 75 file main.c line 11 function alloc_node -(E) $guard#75 == ($cond#70 && $guard#33 || $guard#71) - -*** 77 file main.c line 11 function alloc_node -(E) return_value_malloc$1#77 == malloc#return_value#65 - -*** 79 file main.c line 11 function alloc_node -(E) ptr#79 == (struct node *)return_value_malloc$1#77 - -*** 81 file main.c line 12 function alloc_node -(E) $cond#81 == !(ptr#79 == ((struct node *)NULL)) - -*** 82 file main.c line 13 function alloc_node -(E) $guard#82 == (!$cond#81 && $guard#75) - -*** 83 file line 6 function abort -(E) $cond#83 == FALSE - -*** 84 file line 7 function abort -(E) $guard#84 == ($cond#83 && $guard#82) - -*** 85 file main.c line 15 function alloc_node -(E) dynamic_object$0.next#85 == ((struct node *)NULL) -(E) $guard#85 == ($cond#81 && $guard#75 || $guard#84) - -*** 86 file main.c line 16 function alloc_node -(E) alloc_node#return_value#86 == ptr#79 - -*** 89 file main.c line 16 function alloc_node -(E) $cond#89 == TRUE - -*** 90 file main.c line 17 function alloc_node -(E) $guard#90 == FALSE - -*** 92 file main.c line 17 function alloc_node -(E) $guard#92 == ($cond#89 && $guard#85 || $guard#90) - -*** 93 file main.c line 21 function chain_node -(E) node#93 == alloc_node#return_value#86 - -*** 95 file main.c line 22 function chain_node -(E) dynamic_object$0.next#95 == (ppnode#36 == &p2 ? p2#phi32 : deref#95) - -*** 96 file main.c line 23 function chain_node -(E) p2#96 == node#93 - -*** 100 file main.c line 30 function create_sll -(E) i#100 == 1 + i#phi32 - -*** 101 file main.c line 30 function create_sll -(E) $cond#101 == TRUE -loop back to location 32 - -*** 102 file main.c line 33 function create_sll -(E) $guard#102 == ($cond#32 && $guard#32) - -*** 103 file main.c line 35 function create_sll -(E) p1#103 == (pp2#27 == &p2 ? p2#phi32 : deref#103) - -*** 105 file main.c line 37 function create_sll -(E) i#105 == nondet_symbol(ssa::nondet105.1) - -*** 106 file main.c line 37 function create_sll -(E) i#106 == 0 - -*** 107 file main.c line 37 function create_sll -(E) __CPROVER_deallocated#phi107 == ($guard#ls176 ? __CPROVER_deallocated#lb176 : __CPROVER_deallocated#phi32) -(E) __CPROVER_malloc_object#phi107 == ($guard#ls176 ? __CPROVER_malloc_object#lb176 : __CPROVER_malloc_object#phi32) -(E) __CPROVER_malloc_size#phi107 == ($guard#ls176 ? __CPROVER_malloc_size#lb176 : __CPROVER_malloc_size#phi32) -(E) __CPROVER_malloc_is_new_array#phi107 == ($guard#ls176 ? __CPROVER_malloc_is_new_array#lb176 : __CPROVER_malloc_is_new_array#phi32) -(E) __CPROVER_memory_leak#phi107 == ($guard#ls176 ? __CPROVER_memory_leak#lb176 : __CPROVER_memory_leak#phi32) -(E) i#phi107 == ($guard#ls176 ? i#lb176 : i#106) -(E) p1#phi107 == ($guard#ls176 ? p1#lb176 : p1#103) -(E) dynamic_object$1.next#phi107 == ($guard#ls176 ? dynamic_object$1.next#lb176 : dynamic_object$1.next) -(E) $cond#107 == i#phi107 >= 2 -(E) $guard#107 == $guard#102 - -*** 108 file main.c line 39 function create_sll -(E) $guard#108 == (!$cond#107 && $guard#107) - -*** 110 file main.c line 39 function create_sll -(E) ppnode#110 == nondet_symbol(ssa::nondet110.1) - -*** 111 file main.c line 39 function create_sll -(E) ppnode#111 == pp1#24 - -*** 113 file main.c line 21 function chain_node -(E) node#113 == nondet_symbol(ssa::nondet113.1) - -*** 116 file main.c line 11 function alloc_node -(E) ptr#116 == nondet_symbol(ssa::nondet116.1) - -*** 118 file main.c line 11 function alloc_node -(E) return_value_malloc$1#118 == nondet_symbol(ssa::nondet118.1) - -*** 121 file main.c line 11 function alloc_node -(E) malloc_size#121 == nondet_symbol(ssa::nondet121.1) - -*** 122 file main.c line 11 function alloc_node -(E) malloc_size#122 == sizeof(struct node) /*8ul*/ - -*** 125 file main.c line 11 function alloc_node -(E) malloc_res#125 == nondet_symbol(ssa::nondet125.1) - -*** 127 file main.c line 11 function alloc_node -(E) malloc_value$1#127 == nondet_symbol(ssa::nondet127.1) - -*** 128 file main.c line 11 function alloc_node -(E) malloc_value$1#128 == (void *)&dynamic_object$1 - -*** 129 file main.c line 11 function alloc_node -(E) malloc_res#129 == malloc_value$1#128 - -*** 131 file main.c line 11 function alloc_node -(E) __CPROVER_deallocated#131 == (malloc_res#129 == __CPROVER_deallocated#phi107 ? NULL : __CPROVER_deallocated#phi107) - -*** 133 file main.c line 11 function alloc_node -(E) record_malloc#133 == nondet_symbol(ssa::nondet133.1) - -*** 134 file main.c line 11 function alloc_node -(E) __CPROVER_malloc_object#134 == (record_malloc#133 ? malloc_res#129 : __CPROVER_malloc_object#phi107) - -*** 135 file main.c line 11 function alloc_node -(E) __CPROVER_malloc_size#135 == (record_malloc#133 ? malloc_size#122 : __CPROVER_malloc_size#phi107) - -*** 136 file main.c line 11 function alloc_node -(E) __CPROVER_malloc_is_new_array#136 == (!record_malloc#133 && __CPROVER_malloc_is_new_array#phi107) - -*** 138 file main.c line 11 function alloc_node -(E) record_may_leak#138 == nondet_symbol(ssa::nondet138.1) - -*** 139 file main.c line 11 function alloc_node -(E) __CPROVER_memory_leak#139 == (record_may_leak#138 ? malloc_res#129 : __CPROVER_memory_leak#phi107) - -*** 140 file main.c line 11 function alloc_node -(E) malloc#return_value#140 == malloc_res#129 - -*** 145 file main.c line 11 function alloc_node -(E) $cond#145 == TRUE - -*** 146 file main.c line 11 function alloc_node -(E) $guard#146 == FALSE - -*** 150 file main.c line 11 function alloc_node -(E) $guard#150 == ($cond#145 && $guard#108 || $guard#146) - -*** 152 file main.c line 11 function alloc_node -(E) return_value_malloc$1#152 == malloc#return_value#140 - -*** 154 file main.c line 11 function alloc_node -(E) ptr#154 == (struct node *)return_value_malloc$1#152 - -*** 156 file main.c line 12 function alloc_node -(E) $cond#156 == !(ptr#154 == ((struct node *)NULL)) - -*** 157 file main.c line 13 function alloc_node -(E) $guard#157 == (!$cond#156 && $guard#150) - -*** 158 file line 6 function abort -(E) $cond#158 == FALSE - -*** 159 file line 7 function abort -(E) $guard#159 == ($cond#158 && $guard#157) - -*** 160 file main.c line 15 function alloc_node -(E) dynamic_object$1.next#160 == ((struct node *)NULL) -(E) $guard#160 == ($cond#156 && $guard#150 || $guard#159) - -*** 161 file main.c line 16 function alloc_node -(E) alloc_node#return_value#161 == ptr#154 - -*** 164 file main.c line 16 function alloc_node -(E) $cond#164 == TRUE - -*** 165 file main.c line 17 function alloc_node -(E) $guard#165 == FALSE - -*** 167 file main.c line 17 function alloc_node -(E) $guard#167 == ($cond#164 && $guard#160 || $guard#165) - -*** 168 file main.c line 21 function chain_node -(E) node#168 == alloc_node#return_value#161 - -*** 170 file main.c line 22 function chain_node -(E) dynamic_object$1.next#170 == (ppnode#111 == &p1 ? p1#phi107 : deref#170) - -*** 171 file main.c line 23 function chain_node -(E) p1#171 == node#168 - -*** 175 file main.c line 37 function create_sll -(E) i#175 == 1 + i#phi107 - -*** 176 file main.c line 37 function create_sll -(E) $cond#176 == TRUE -loop back to location 107 - -*** 177 file main.c line 40 function create_sll -(E) $guard#177 == ($cond#107 && $guard#107) - -*** 179 file main.c line 42 function create_sll -(E) list#179 == nondet_symbol(ssa::nondet179.1) - -*** 180 file main.c line 42 function create_sll -(E) list#180 == (pp1#24 == &p1 ? p1#phi107 : deref#180) - -*** 182 file main.c line 44 function create_sll -(E) i#182 == nondet_symbol(ssa::nondet182.1) - -*** 183 file main.c line 44 function create_sll -(E) i#183 == 0 - -*** 184 file main.c line 44 function create_sll -(E) __CPROVER_deallocated#phi184 == ($guard#ls253 ? __CPROVER_deallocated#lb253 : __CPROVER_deallocated#phi107) -(E) __CPROVER_malloc_object#phi184 == ($guard#ls253 ? __CPROVER_malloc_object#lb253 : __CPROVER_malloc_object#phi107) -(E) __CPROVER_malloc_size#phi184 == ($guard#ls253 ? __CPROVER_malloc_size#lb253 : __CPROVER_malloc_size#phi107) -(E) __CPROVER_malloc_is_new_array#phi184 == ($guard#ls253 ? __CPROVER_malloc_is_new_array#lb253 : __CPROVER_malloc_is_new_array#phi107) -(E) __CPROVER_memory_leak#phi184 == ($guard#ls253 ? __CPROVER_memory_leak#lb253 : __CPROVER_memory_leak#phi107) -(E) list#phi184 == ($guard#ls253 ? list#lb253 : list#180) -(E) i#phi184 == ($guard#ls253 ? i#lb253 : i#183) -(E) dynamic_object$2.next#phi184 == ($guard#ls253 ? dynamic_object$2.next#lb253 : dynamic_object$2.next) -(E) $cond#184 == i#phi184 >= 2 -(E) $guard#184 == $guard#177 - -*** 185 file main.c line 46 function create_sll -(E) $guard#185 == (!$cond#184 && $guard#184) - -*** 187 file main.c line 46 function create_sll -(E) ppnode#187 == nondet_symbol(ssa::nondet187.1) - -*** 188 file main.c line 46 function create_sll -(E) ppnode#188 == &list - -*** 190 file main.c line 21 function chain_node -(E) node#190 == nondet_symbol(ssa::nondet190.1) - -*** 193 file main.c line 11 function alloc_node -(E) ptr#193 == nondet_symbol(ssa::nondet193.1) - -*** 195 file main.c line 11 function alloc_node -(E) return_value_malloc$1#195 == nondet_symbol(ssa::nondet195.1) - -*** 198 file main.c line 11 function alloc_node -(E) malloc_size#198 == nondet_symbol(ssa::nondet198.1) - -*** 199 file main.c line 11 function alloc_node -(E) malloc_size#199 == sizeof(struct node) /*8ul*/ - -*** 202 file main.c line 11 function alloc_node -(E) malloc_res#202 == nondet_symbol(ssa::nondet202.1) - -*** 204 file main.c line 11 function alloc_node -(E) malloc_value$1#204 == nondet_symbol(ssa::nondet204.1) - -*** 205 file main.c line 11 function alloc_node -(E) malloc_value$1#205 == (void *)&dynamic_object$2 - -*** 206 file main.c line 11 function alloc_node -(E) malloc_res#206 == malloc_value$1#205 - -*** 208 file main.c line 11 function alloc_node -(E) __CPROVER_deallocated#208 == (malloc_res#206 == __CPROVER_deallocated#phi184 ? NULL : __CPROVER_deallocated#phi184) - -*** 210 file main.c line 11 function alloc_node -(E) record_malloc#210 == nondet_symbol(ssa::nondet210.1) - -*** 211 file main.c line 11 function alloc_node -(E) __CPROVER_malloc_object#211 == (record_malloc#210 ? malloc_res#206 : __CPROVER_malloc_object#phi184) - -*** 212 file main.c line 11 function alloc_node -(E) __CPROVER_malloc_size#212 == (record_malloc#210 ? malloc_size#199 : __CPROVER_malloc_size#phi184) - -*** 213 file main.c line 11 function alloc_node -(E) __CPROVER_malloc_is_new_array#213 == (!record_malloc#210 && __CPROVER_malloc_is_new_array#phi184) - -*** 215 file main.c line 11 function alloc_node -(E) record_may_leak#215 == nondet_symbol(ssa::nondet215.1) - -*** 216 file main.c line 11 function alloc_node -(E) __CPROVER_memory_leak#216 == (record_may_leak#215 ? malloc_res#206 : __CPROVER_memory_leak#phi184) - -*** 217 file main.c line 11 function alloc_node -(E) malloc#return_value#217 == malloc_res#206 - -*** 222 file main.c line 11 function alloc_node -(E) $cond#222 == TRUE - -*** 223 file main.c line 11 function alloc_node -(E) $guard#223 == FALSE - -*** 227 file main.c line 11 function alloc_node -(E) $guard#227 == ($cond#222 && $guard#185 || $guard#223) - -*** 229 file main.c line 11 function alloc_node -(E) return_value_malloc$1#229 == malloc#return_value#217 - -*** 231 file main.c line 11 function alloc_node -(E) ptr#231 == (struct node *)return_value_malloc$1#229 - -*** 233 file main.c line 12 function alloc_node -(E) $cond#233 == !(ptr#231 == ((struct node *)NULL)) - -*** 234 file main.c line 13 function alloc_node -(E) $guard#234 == (!$cond#233 && $guard#227) - -*** 235 file line 6 function abort -(E) $cond#235 == FALSE - -*** 236 file line 7 function abort -(E) $guard#236 == ($cond#235 && $guard#234) - -*** 237 file main.c line 15 function alloc_node -(E) dynamic_object$2.next#237 == ((struct node *)NULL) -(E) $guard#237 == ($cond#233 && $guard#227 || $guard#236) - -*** 238 file main.c line 16 function alloc_node -(E) alloc_node#return_value#238 == ptr#231 - -*** 241 file main.c line 16 function alloc_node -(E) $cond#241 == TRUE - -*** 242 file main.c line 17 function alloc_node -(E) $guard#242 == FALSE - -*** 244 file main.c line 17 function alloc_node -(E) $guard#244 == ($cond#241 && $guard#237 || $guard#242) - -*** 245 file main.c line 21 function chain_node -(E) node#245 == alloc_node#return_value#238 - -*** 247 file main.c line 22 function chain_node -(E) dynamic_object$2.next#247 == (ppnode#188 == &list ? list#phi184 : deref#247) - -*** 248 file main.c line 23 function chain_node -(E) list#248 == node#245 - -*** 252 file main.c line 44 function create_sll -(E) i#252 == 1 + i#phi184 - -*** 253 file main.c line 44 function create_sll -(E) $cond#253 == TRUE -loop back to location 184 - -*** 254 file main.c line 47 function create_sll -(E) $guard#254 == ($cond#184 && $guard#184) - -*** 255 file main.c line 49 function create_sll -(E) create_sll#return_value#255 == list#phi184 - -*** 257 file main.c line 49 function create_sll -(E) $cond#257 == TRUE - -*** 258 file main.c line 50 function create_sll -(E) $guard#258 == FALSE - -*** 259 file main.c line 50 function create_sll -(E) $guard#259 == ($cond#257 && $guard#254 || $guard#258) - -*** 262 file main.c line 64 function main -(E) list#262 == create_sll#return_value#255 - -*** 266 file main.c line 65 function main -(E) beg#266 == nondet_symbol(ssa::nondet266.1) - -*** 267 file main.c line 65 function main -(E) beg#267 == list#262 - -*** 269 file main.c line 65 function main -(E) end#269 == nondet_symbol(ssa::nondet269.1) - -*** 270 file main.c line 65 function main -(E) end#270 == p1#phi107 - -*** 271 file main.c line 53 function check_seq_next -(A) !(beg#267 == ((struct node *)NULL)) || !$guard#259 - -*** 272 file main.c line 54 function check_seq_next -(A) !(end#270 == ((struct node *)NULL)) || !$guard#259 - -*** 273 file main.c line 56 function check_seq_next -(E) beg#273 == (beg#267 == &dynamic_object$2 ? dynamic_object$2.next#phi184 : (beg#267 == &dynamic_object$1 ? dynamic_object$1.next#phi107 : (beg#267 == &dynamic_object$0 ? dynamic_object$0.next#phi32 : deref#273.next))) - -*** 274 file main.c line 56 function check_seq_next -(E) beg#phi274 == ($guard#ls277 ? beg#lb277 : beg#273) -(E) $cond#274 == (end#270 == beg#phi274) -(E) $guard#274 == $guard#259 - -*** 275 file main.c line 57 function check_seq_next -(E) $guard#275 == (!$cond#274 && $guard#274) -(A) !(beg#phi274 == ((struct node *)NULL)) || !$guard#275 - -*** 276 file main.c line 56 function check_seq_next -(E) beg#276 == (beg#phi274 == &dynamic_object$2 ? dynamic_object$2.next#phi184 : (beg#phi274 == &dynamic_object$1 ? dynamic_object$1.next#phi107 : (beg#phi274 == &dynamic_object$0 ? dynamic_object$0.next#phi32 : deref#276.next))) - -*** 277 file main.c line 56 function check_seq_next -(E) $cond#277 == TRUE -loop back to location 274 - -*** 278 file main.c line 58 function check_seq_next -(E) $guard#278 == ($cond#274 && $guard#274) - -*** 283 file main.c line 66 function main -(E) beg#283 == nondet_symbol(ssa::nondet283.1) - -*** 284 file main.c line 66 function main -(E) beg#284 == p1#phi107 - -*** 286 file main.c line 66 function main -(E) end#286 == nondet_symbol(ssa::nondet286.1) - -*** 287 file main.c line 66 function main -(E) end#287 == p2#phi32 - -*** 288 file main.c line 53 function check_seq_next -(A) !(beg#284 == ((struct node *)NULL)) || !$guard#278 - -*** 289 file main.c line 54 function check_seq_next -(A) !(end#287 == ((struct node *)NULL)) || !$guard#278 - -*** 290 file main.c line 56 function check_seq_next -(E) beg#290 == (beg#284 == &dynamic_object$1 ? dynamic_object$1.next#phi107 : (beg#284 == &dynamic_object$0 ? dynamic_object$0.next#phi32 : deref#290.next)) - -*** 291 file main.c line 56 function check_seq_next -(E) beg#phi291 == ($guard#ls294 ? beg#lb294 : beg#290) -(E) $cond#291 == (end#287 == beg#phi291) -(E) $guard#291 == $guard#278 - -*** 292 file main.c line 57 function check_seq_next -(E) $guard#292 == (!$cond#291 && $guard#291) -(A) !(beg#phi291 == ((struct node *)NULL)) || !$guard#292 - -*** 293 file main.c line 56 function check_seq_next -(E) beg#293 == (beg#phi291 == &dynamic_object$1 ? dynamic_object$1.next#phi107 : (beg#phi291 == &dynamic_object$0 ? dynamic_object$0.next#phi32 : deref#293.next)) - -*** 294 file main.c line 56 function check_seq_next -(E) $cond#294 == TRUE -loop back to location 291 - -*** 295 file main.c line 58 function check_seq_next -(E) $guard#295 == ($cond#291 && $guard#291) - -(enable) TRUE - - -Callee summaries: -Callee bindings: - -Loops not fully unwound -Running refinement loop with MiniSAT 2.2.1 with simplifier -** 0 of 6 failed (1 iterations) -** statistics: - number of solver instances: 1 - number of solver calls: 14 - number of summaries used: 0 - -[check_seq_next.assertion.1] assertion beg != (struct node *)(void *)0: OK -[check_seq_next.assertion.2] assertion end != (struct node *)(void *)0: OK -[check_seq_next.assertion.3] assertion beg != (struct node *)(void *)0: OK -[check_seq_next.assertion.4] assertion beg != (struct node *)(void *)0: OK -[check_seq_next.assertion.5] assertion end != (struct node *)(void *)0: OK -[check_seq_next.assertion.6] assertion beg != (struct node *)(void *)0: OK - -** 0 of 6 unknown -** 0 of 6 failed -VERIFICATION SUCCESSFUL -EXIT=0 -SIGNAL=0 diff --git a/regression/heap/sll1_simple/test.desc b/regression/heap/sll1_simple/test.desc deleted file mode 100644 index ed14b476a..000000000 --- a/regression/heap/sll1_simple/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap --inline --no-propagation -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/sll2_nondet_loops/main.c b/regression/heap/sll2_nondet_loops/main.c deleted file mode 100644 index 5f44c5a68..000000000 --- a/regression/heap/sll2_nondet_loops/main.c +++ /dev/null @@ -1,66 +0,0 @@ -#include - -extern int __VERIFIER_nondet_int(void); - -struct node { - struct node *next; -}; - -static struct node* alloc_node(void) -{ - struct node *ptr = malloc(sizeof *ptr); - if (!ptr) - abort(); - - ptr->next = NULL; - return ptr; -} - -static void chain_node(struct node **ppnode) -{ - struct node *node = alloc_node(); - node->next = *ppnode; - *ppnode = node; -} - -static struct node* create_sll(const struct node **pp1, const struct node **pp2) -{ - *pp2 = NULL; - - do - chain_node(pp2); - while (__VERIFIER_nondet_int()); - - *pp1 = *pp2; - - do - chain_node(pp1); - while (__VERIFIER_nondet_int()); - - struct node *list = *pp1; - - do - chain_node(&list); - while (__VERIFIER_nondet_int()); - - return list; -} - -void check_seq_next(const struct node *beg, const struct node *const end) { - assert(beg != NULL); - assert(end != NULL); - - for (beg = beg->next; end != beg; beg = beg->next) - assert(beg != NULL); -} - -void main() -{ - const struct node *p1, *p2; - - struct node *list = create_sll(&p1, &p2); - check_seq_next(list, p1); - check_seq_next(p1, p2); - -} - diff --git a/regression/heap/sll2_nondet_loops/test.desc b/regression/heap/sll2_nondet_loops/test.desc deleted file mode 100644 index ed14b476a..000000000 --- a/regression/heap/sll2_nondet_loops/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap --inline --no-propagation -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/sll_to_dll1_reverse/test.desc b/regression/heap/sll_to_dll1_reverse/test.desc deleted file mode 100644 index ed14b476a..000000000 --- a/regression/heap/sll_to_dll1_reverse/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap --inline --no-propagation -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ From b478462d8de38e2733f48b4ce142eaf271643081 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 11 Aug 2017 08:19:42 +0200 Subject: [PATCH 086/322] Comments and cleanup for heap branch. Add comments for methods and important unclear parts. Improve code formatting following cpplint. Remove auto keyword where reasonable and transform iterator-based loops to for-ranged loops. --- src/2ls/preprocessing_util.cpp | 9 +- src/2ls/show.cpp | 26 +- src/2ls/summary_checker_base.cpp | 4 +- src/2ls/summary_checker_base.h | 8 +- src/domains/heap_domain.cpp | 1250 +++++++++++------ src/domains/heap_domain.h | 255 ++-- src/domains/heap_interval_domain.cpp | 85 +- src/domains/heap_interval_domain.h | 16 +- src/domains/list_iterator.cpp | 158 ++- src/domains/list_iterator.h | 65 +- src/domains/ssa_analyzer.cpp | 22 + src/domains/strategy_solver_heap.cpp | 250 ++-- src/domains/strategy_solver_heap.h | 54 +- src/domains/strategy_solver_heap_interval.cpp | 50 +- src/domains/strategy_solver_heap_interval.h | 45 +- src/domains/template_generator_base.cpp | 51 +- src/domains/template_generator_base.h | 4 +- src/ssa/address_canonizer.cpp | 11 +- src/ssa/assignments.cpp | 32 +- src/ssa/local_ssa.cpp | 239 ++-- src/ssa/local_ssa.h | 39 +- src/ssa/malloc_ssa.cpp | 13 +- src/ssa/ssa_heap_domain.cpp | 574 +++++--- src/ssa/ssa_heap_domain.h | 73 +- src/ssa/ssa_inliner.cpp | 519 ++++--- src/ssa/ssa_inliner.h | 40 +- src/ssa/ssa_object.cpp | 44 +- src/ssa/ssa_pointed_objects.cpp | 413 ++++-- src/ssa/ssa_pointed_objects.h | 16 +- src/ssa/ssa_value_set.cpp | 209 +-- 30 files changed, 3068 insertions(+), 1506 deletions(-) diff --git a/src/2ls/preprocessing_util.cpp b/src/2ls/preprocessing_util.cpp index 6e5a03565..b58d24afd 100644 --- a/src/2ls/preprocessing_util.cpp +++ b/src/2ls/preprocessing_util.cpp @@ -581,7 +581,8 @@ Function: twols_parse_optionst::add_dynamic_object_symbols Outputs: - Purpose: + Purpose: Add symbols for all dynamic objects in the program into + the symbol table. \*******************************************************************/ @@ -598,8 +599,10 @@ void twols_parse_optionst::add_dynamic_object_symbols( auto &fun_call=to_code_function_call(i_it->code); const irep_idt fname= to_symbol_expr(fun_call.function()).get_identifier(); - auto n_it=i_it; ++n_it; - for(auto &o : heap_analysis[n_it].new_caller_objects(fname, i_it)) + auto n_it=i_it; + ++n_it; + for(const symbol_exprt &o : + heap_analysis[n_it].new_caller_objects(fname, i_it)) { // New symbol symbolt object_symbol; diff --git a/src/2ls/show.cpp b/src/2ls/show.cpp index 07f1e979c..56bae8bb4 100644 --- a/src/2ls/show.cpp +++ b/src/2ls/show.cpp @@ -38,14 +38,16 @@ Function: show_assignments \*******************************************************************/ -void show_assignments(const goto_functionst::goto_functiont &goto_function, - const namespacet &ns, - std::ostream &out, - const ssa_heap_analysist &heap_analysis) +void show_assignments( + const goto_functionst::goto_functiont &goto_function, + const namespacet &ns, + std::ostream &out, + const ssa_heap_analysist &heap_analysis) { ssa_objectst ssa_objects(goto_function, ns, heap_analysis); ssa_value_ait ssa_value_ai(goto_function, ns, heap_analysis); - assignmentst assignments(goto_function.body, ns, ssa_objects, ssa_value_ai, heap_analysis); + assignmentst assignments( + goto_function.body, ns, ssa_objects, ssa_value_ai, heap_analysis); assignments.output(ns, goto_function.body, out); } @@ -112,7 +114,8 @@ void show_defs(const goto_functionst::goto_functiont &goto_function, { ssa_objectst ssa_objects(goto_function, ns, heap_analysis); ssa_value_ait ssa_value_ai(goto_function, ns, heap_analysis); - assignmentst assignments(goto_function.body, ns, ssa_objects, ssa_value_ai, heap_analysis); + assignmentst assignments( + goto_function.body, ns, ssa_objects, ssa_value_ai, heap_analysis); ssa_ait ssa_analysis(assignments); ssa_analysis(goto_function, ns); ssa_analysis.output(ns, goto_function.body, out); @@ -139,7 +142,7 @@ void show_defs( const namespacet ns(goto_model.symbol_table); ssa_heap_analysist heap_analysis(ns); - + if(!function.empty()) { goto_functionst::function_mapt::const_iterator @@ -560,10 +563,11 @@ Function: show_value_set \*******************************************************************/ -void show_value_set(const goto_functionst::goto_functiont &goto_function, - const namespacet &ns, - std::ostream &out, - const ssa_heap_analysist &heap_analysis) +void show_value_set( + const goto_functionst::goto_functiont &goto_function, + const namespacet &ns, + std::ostream &out, + const ssa_heap_analysist &heap_analysis) { ssa_objectst ssa_objects(goto_function, ns, heap_analysis); ssa_value_ait ssa_value_ai(goto_function, ns, heap_analysis); diff --git a/src/2ls/summary_checker_base.cpp b/src/2ls/summary_checker_base.cpp index 6f740ad17..0c38ad113 100644 --- a/src/2ls/summary_checker_base.cpp +++ b/src/2ls/summary_checker_base.cpp @@ -230,8 +230,8 @@ void summary_checker_baset::check_properties( solver << summary_db.get(f_it->first).fw_invariant; solver << summary_db.get(f_it->first).fw_precondition; - if (options.get_bool_option("heap") && - summary_db.get(f_it->first).aux_precondition.is_not_nil()) + if(options.get_bool_option("heap") && + summary_db.get(f_it->first).aux_precondition.is_not_nil()) { solver << summary_db.get(f_it->first).aux_precondition; } diff --git a/src/2ls/summary_checker_base.h b/src/2ls/summary_checker_base.h index 653bd9881..ebf170a37 100644 --- a/src/2ls/summary_checker_base.h +++ b/src/2ls/summary_checker_base.h @@ -28,7 +28,7 @@ class graphml_witness_extt; class summary_checker_baset:public property_checkert { public: - inline summary_checker_baset(optionst &_options, const ssa_heap_analysist &_heap_analysis) : + summary_checker_baset(optionst &_options, const ssa_heap_analysist &_heap_analysis) : show_vcc(false), simplify(false), fixed_point(false), @@ -77,8 +77,10 @@ class summary_checker_baset:public property_checkert const goto_programt::const_targett, const local_SSAt::nodet::assertionst::const_iterator &); - void SSA_functions(const goto_modelt &, const namespacet &ns, - const ssa_heap_analysist &heap_analysis); + void SSA_functions( + const goto_modelt &, + const namespacet &ns, + const ssa_heap_analysist &heap_analysis); void summarize( const goto_modelt &, diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index b461645a2..47dc57fda 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -1,6 +1,10 @@ -/** - * Viktor Malik, 12.8.2016 (c). - */ +/*******************************************************************\ + +Module: Abstract domain for representing heap + +Author: Viktor Malik + +\*******************************************************************/ #include "heap_domain.h" #include "util.h" @@ -10,321 +14,488 @@ #include "../ssa/ssa_inliner.h" #include "../ssa/address_canonizer.h" -/** - * Initialize value. - * Clears each pointer paths and points_to predicates. - * @param value - */ +/*******************************************************************\ + +Function: heap_domaint::initialize + + Inputs: + + Outputs: + + Purpose: Initialize abstract value. + Clears value with empty value rows corresponding to template. + +\*******************************************************************/ + void heap_domaint::initialize(domaint::valuet &value) { - heap_valuet &val = static_cast(value); + heap_valuet &val=static_cast(value); - for (auto &templ_row : templ) + for(const template_rowt &templ_row : templ) { - if (templ_row.mem_kind == STACK) + if(templ_row.mem_kind==STACK) val.emplace_back(new stack_row_valuet()); - else if (templ_row.mem_kind == HEAP) - val.emplace_back(new heap_row_valuet(std::make_pair(templ_row.dyn_obj, templ_row.expr))); + else if(templ_row.mem_kind==HEAP) + val.emplace_back( + new heap_row_valuet(std::make_pair(templ_row.dyn_obj, templ_row.expr))); else assert(false); } } -/** - * Create domain template for given set of variables. - * Template contains a row for each member of each variable being pointer to struct, - * and a row for each flattened member of a struct. - * @param var_specs Set of program variables. - * @param ns Namespace - */ -void heap_domaint::make_template(const domaint::var_specst &var_specs, const namespacet &ns) +/*******************************************************************\ + +Function: heap_domaint::make_template + + Inputs: + + Outputs: + + Purpose: Create domain template for given set of variables. + Template contains a row for each pointer-typed variable and + field of a dynamic object. + +\*******************************************************************/ + +void heap_domaint::make_template( + const domaint::var_specst &var_specs, + const namespacet &ns) { - unsigned long size = var_specs.size(); + unsigned long size=var_specs.size(); templ.clear(); templ.reserve(size); - for (auto v = var_specs.begin(); v != var_specs.end(); ++v) + for(const var_spect &v : var_specs) { - if (v->kind == IN) continue; + if(v.kind==IN) + continue; // Create template for each pointer - const vart &var = v->var; - if (var.type().id() == ID_pointer) + const vart &var=v.var; + if(var.type().id()==ID_pointer) { - const typet &pointed_type = ns.follow(var.type().subtype()); - add_template_row(*v, pointed_type); + const typet &pointed_type=ns.follow(var.type().subtype()); + add_template_row(v, pointed_type); } } } -void heap_domaint::add_template_row(const var_spect &var_spec, const typet &pointed_type) +/*******************************************************************\ + +Function: heap_domaint::add_template_row + + Inputs: var_spec Variable specification + + Outputs: + + Purpose: Add a template row. + +\*******************************************************************/ + +void heap_domaint::add_template_row( + const var_spect &var_spec, + const typet &pointed_type) { - const vart &var = var_spec.var; + const vart &var=var_spec.var; templ.push_back(template_rowt()); - template_rowt &templ_row = templ.back(); - templ_row.expr = var; - templ_row.pre_guard = var_spec.pre_guard; - templ_row.post_guard = var_spec.post_guard; - templ_row.aux_expr = var_spec.aux_expr; - templ_row.kind = var_spec.kind; - - templ_row.mem_kind = STACK; - if (pointed_type.id() == ID_struct) + template_rowt &templ_row=templ.back(); + templ_row.expr=var; + templ_row.pre_guard=var_spec.pre_guard; + templ_row.post_guard=var_spec.post_guard; + templ_row.aux_expr=var_spec.aux_expr; + templ_row.kind=var_spec.kind; + + templ_row.mem_kind=STACK; + if(pointed_type.id()==ID_struct) { // Check if var is member field of heap object - const std::string identifier = id2string(to_symbol_expr(var_spec.var).get_identifier()); - for (auto &component : to_struct_type(pointed_type).components()) + const std::string identifier=id2string( + to_symbol_expr(var_spec.var).get_identifier()); + for(auto &component : to_struct_type(pointed_type).components()) { - if (identifier.find("." + id2string(component.get_name())) != std::string::npos) + if(identifier.find("."+id2string(component.get_name()))!= + std::string::npos) { - templ_row.mem_kind = HEAP; - templ_row.member = component.get_name(); + templ_row.mem_kind=HEAP; + templ_row.member=component.get_name(); - std::string var_id = id2string(to_symbol_expr(var).get_identifier()); - std::string do_id = var_id.substr(0, var_id.find_last_of('.')); - templ_row.dyn_obj = symbol_exprt(do_id, var.type().subtype()); + std::string var_id=id2string(to_symbol_expr(var).get_identifier()); + std::string do_id=var_id.substr(0, var_id.find_last_of('.')); + templ_row.dyn_obj=symbol_exprt(do_id, var.type().subtype()); } } } } -/** - * Create entry constraints expression for a value. - * @param value Value - * @return Conjuction of entry expressions for each template row - */ -exprt heap_domaint::to_pre_constraints(const heap_domaint::heap_valuet &value) const +/*******************************************************************\ + +Function: heap_domaint::to_pre_constraints + + Inputs: + + Outputs: Entry constraints expression for a value. + + Purpose: Create entry constraints as a conjuction of entry + expressions for each template row. + +\*******************************************************************/ + +exprt heap_domaint::to_pre_constraints(const heap_valuet &value) const { - assert(value.size() == templ.size()); + assert(value.size()==templ.size()); exprt::operandst c; - for (rowt row = 0; row < templ.size(); ++row) + for(rowt row=0; row(value[from]); - heap_row_valuet &heap_val_to = static_cast(value[to]); + Inputs: to Row to add new paths to + from Row to add paths from + dyn_obj Dynamic object that all the paths pass through (it belongs to + path segment from one pointer to another). - bool result = false; - if (heap_val_from.add_all_paths(heap_val_to, std::make_pair(templ[to].dyn_obj, templ[to].expr))) - result = true; - if (from != to) + Outputs: True if any path was added or changed, otherwise false. + + Purpose: Add all paths of one pointer as the destinations of another pointer. + +\*******************************************************************/ + +bool heap_domaint::add_transitivity( + const rowt &from, + const rowt &to, + heap_valuet &value) +{ + assert(from(value[from]); + heap_row_valuet &heap_val_to=static_cast(value[to]); + + bool result=false; + if(heap_val_from.add_all_paths( + heap_val_to, std::make_pair( + templ[to].dyn_obj, templ[to].expr))) + result=true; + if(from!=to) { - if (heap_val_to.add_pointed_by(from)) - result = true; + if(heap_val_to.add_pointed_by(from)) + result=true; } return result; } -bool heap_domaint::add_points_to(const heap_domaint::rowt &row, heap_domaint::heap_valuet &value, - const exprt &dest) +/*******************************************************************\ + +Function: heap_domaint::add_points_to + + Inputs: + + Outputs: + + Purpose: Add new object pointed by a row. + Calls add_points_to of the given row. + For stack rows, the destination is simply added into pointed + objects set. + For heap rows, a new path is added. + +\*******************************************************************/ + +bool heap_domaint::add_points_to( + const rowt &row, + heap_valuet &value, + const exprt &dest) { - assert(row < value.size()); + assert(row(value); - for (rowt row = 0; row < templ.size(); ++row) + const heap_valuet &val=static_cast(value); + for(rowt row=0; row " << std::endl << " "; - break; - case IN: - out << "(IN) "; - break; - case OUT: - case OUTL: - out << "(OUT) "; - break; - case OUTHEAP: - out << "(HEAP) "; - break; - default: - assert(false); + case LOOP: + out << "(LOOP) [ " << from_expr(ns, "", templ_row.pre_guard) << " | "; + out << from_expr(ns, "", templ_row.post_guard) << " | "; + out << from_expr(ns, "", templ_row.aux_expr) << " ] ===> " << std::endl + << " "; + break; + case IN: + out << "(IN) "; + break; + case OUT: + case OUTL: + out << "(OUT) "; + break; + case OUTHEAP: + out << "(HEAP) "; + break; + default: + assert(false); } out << "( " << from_expr(ns, "", templ_row.expr) << " == " - << from_expr(ns, "", val[row].get_row_expr(templ_row.expr, false)) << " )" + << from_expr(ns, "", val[row].get_row_expr(templ_row.expr, false)) + << " )" << std::endl; } } +/*******************************************************************\ + +Function: heap_domaint::output_domain + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + void heap_domaint::output_domain(std::ostream &out, const namespacet &ns) const { - for (unsigned i = 0; i < templ.size(); ++i) + for(unsigned i=0; i " << std::endl << " "; - break; - case IN: - out << "(IN) "; - out << from_expr(ns, "", templ_row.pre_guard) << " ===> " - << std::endl << " "; - break; - case OUT: - case OUTL: - out << "(OUT) "; - out << from_expr(ns, "", templ_row.post_guard) << " ===> " - << std::endl << " "; - break; - case OUTHEAP: - out << "(HEAP) [ " << from_expr(ns, "", templ_row.pre_guard) << " | "; - out << from_expr(ns, "", templ_row.post_guard) - << " ] ===> " << std::endl << " "; - break; - default: - assert(false); + case LOOP: + out << "(LOOP) [ " << from_expr(ns, "", templ_row.pre_guard) << " | "; + out << from_expr(ns, "", templ_row.post_guard) << " | "; + out << from_expr(ns, "", templ_row.aux_expr) + << " ] ===> " << std::endl << " "; + break; + case IN: + out << "(IN) "; + out << from_expr(ns, "", templ_row.pre_guard) << " ===> " + << std::endl << " "; + break; + case OUT: + case OUTL: + out << "(OUT) "; + out << from_expr(ns, "", templ_row.post_guard) << " ===> " + << std::endl << " "; + break; + case OUTHEAP: + out << "(HEAP) [ " << from_expr(ns, "", templ_row.pre_guard) << " | "; + out << from_expr(ns, "", templ_row.post_guard) + << " ] ===> " << std::endl << " "; + break; + default: + assert(false); } - const vart &var = templ_row.expr; + const vart &var=templ_row.expr; out << i << ": " << from_expr(ns, "", var) - << (templ_row.mem_kind == STACK ? " --points_to--> Locations" - : " --paths--> Destinations") + << (templ_row.mem_kind==STACK ? " --points_to--> Locations" + : " --paths--> Destinations") << std::endl; } } -void heap_domaint::project_on_vars(domaint::valuet &value, - const domaint::var_sett &vars, exprt &result) +/*******************************************************************\ + +Function: heap_domaint::project_on_vars + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void heap_domaint::project_on_vars( + domaint::valuet &value, + const domaint::var_sett &vars, + exprt &result) { - const heap_valuet &val = static_cast(value); - assert(val.size() == templ.size()); + const heap_valuet &val=static_cast(value); + assert(val.size()==templ.size()); exprt::operandst c; - for (rowt row = 0; row < templ.size(); ++row) + for(rowt row=0; row(value1); - const heap_valuet &val2 = static_cast(value2); - assert(val1.size() == templ.size()); - assert(val2.size() == val1.size()); + heap_valuet &val1=static_cast(value1); + const heap_valuet &val2=static_cast(value2); + assert(val1.size()==templ.size()); + assert(val2.size()==val1.size()); } -/** - * Get location number of a given symbol. - * @param expr Symbol expression. - * @return Number of location, or -1 if symbol is input. - */ +/*******************************************************************\ + +Function: heap_domaint::get_symbol_loc + + Inputs: Symbol expression. + + Outputs: Number of location, or -1 if symbol is input. + + Purpose: Get location number of a given symbol. + +\*******************************************************************/ + int heap_domaint::get_symbol_loc(const exprt &expr) { - assert(expr.id() == ID_symbol); - std::string expr_id = id2string(to_symbol_expr(expr).get_identifier()); - if (expr_id.find('#') == std::string::npos) return -1; - std::string loc_str = expr_id.substr(expr_id.find_last_not_of("0123456789") + 1); + assert(expr.id()==ID_symbol); + std::string expr_id=id2string(to_symbol_expr(expr).get_identifier()); + if(expr_id.find('#')==std::string::npos) return -1; + std::string loc_str=expr_id.substr(expr_id.find_last_not_of("0123456789")+1); assert(!loc_str.empty()); return std::stoi(loc_str); } -/** - * Get base name of a symbol. - * @param expr Symbol expression. - * @return Base name of a symbol (without suffix with location number). - */ +/*******************************************************************\ + +Function: heap_domaint::get_base_name + + Inputs: Symbol expression. + + Outputs: Base name of a symbol (without suffix with location number). + + Purpose: Get base name of a symbol. + +\*******************************************************************/ + std::string heap_domaint::get_base_name(const exprt &expr) { - assert(expr.id() == ID_symbol); - std::string result = id2string(to_symbol_expr(expr).get_identifier()); - result = result.substr(0, result.find_last_of('#')); + assert(expr.id()==ID_symbol); + std::string result=id2string(to_symbol_expr(expr).get_identifier()); + result=result.substr(0, result.find_last_of('#')); return result; } @@ -382,32 +574,48 @@ Function: heap_domaint::stack_row_valuet::get_row_expr Outputs: Formula corresponding to the template row - Purpose: Stack row is a disjuction of equalities between templ_expr and addresses of - dynamic objects from points_to set. + Purpose: Stack row is a disjuction of equalities between templ_expr + and addresses of dynamic objects from points_to set. \*******************************************************************/ + exprt heap_domaint::stack_row_valuet::get_row_expr(const vart &templ_expr, bool rename_templ_expr) const { - if (nondet) return true_exprt(); + if(nondet) + return true_exprt(); - if (empty()) + if(empty()) return false_exprt(); else - { // Points to expression + { + // Points to expression exprt::operandst result; - for (auto &pt : points_to) + for(const exprt &pt : points_to) { - result.push_back(equal_exprt(templ_expr, templ_expr.type() == pt.type() ? + result.push_back(equal_exprt(templ_expr, templ_expr.type()==pt.type() ? pt : address_of_exprt(pt))); } return disjunction(result); } } +/*******************************************************************\ + +Function: heap_domaint::stack_row_valuet::add_points_to + + Inputs: + + Outputs: + + Purpose: Add new object to the value of a stack row. The object is + simply added to the set. + +\*******************************************************************/ + bool heap_domaint::stack_row_valuet::add_points_to(const exprt &expr) { - auto new_pt = points_to.insert(expr); + auto new_pt=points_to.insert(expr); return new_pt.second; } @@ -416,28 +624,31 @@ bool heap_domaint::stack_row_valuet::add_points_to(const exprt &expr) Function: heap_domaint::heap_row_valuet::get_row_expr Inputs: templ_expr Template expression - rename_templ_expr True if templ_expr should be renamed (the corresponding template row - is of outheap type) + rename_templ_expr True if templ_expr should be renamed + (the corresponding template row is of + OUTHEAP type) Outputs: Formula corresponding to the template row Purpose: Heap row is disjunction of path sets, where each path set is a conjunction of paths. + nondet is TRUE empty is FALSE \*******************************************************************/ + exprt heap_domaint::heap_row_valuet::get_row_expr(const vart &templ_expr_, bool rename_templ_expr) const { - if (nondet) return true_exprt(); + if(nondet) return true_exprt(); - exprt templ_expr = templ_expr_; - if (rename_templ_expr) - templ_expr = rename_outheap(to_symbol_expr(templ_expr_)); + exprt templ_expr=templ_expr_; + if(rename_templ_expr) + templ_expr=rename_outheap(to_symbol_expr(templ_expr_)); - if (paths.empty()) + if(paths.empty()) { - if (self_linkage) + if(self_linkage) { return equal_exprt(templ_expr, address_of_exprt(dyn_obj.first)); } @@ -447,30 +658,31 @@ exprt heap_domaint::heap_row_valuet::get_row_expr(const vart &templ_expr_, else { exprt::operandst result; - for (auto &path_set : paths) + for(const pathsett &path_set : paths) { exprt::operandst path_set_expr; - for (auto &path : path_set) + for(const patht &path : path_set) { // path(o.m, d)[O] - const exprt &dest = templ_expr.type() == path.destination.type() ? - path.destination : address_of_exprt(path.destination); + const exprt &dest=templ_expr.type()==path.destination.type() ? + path.destination : address_of_exprt(path.destination); exprt::operandst path_expr; // o.m = d path_expr.push_back(equal_exprt(templ_expr, dest)); - for (const dyn_objt &obj1 : path.dyn_objects) + for(const dyn_objt &obj1 : path.dyn_objects) { // o.m = &o' - exprt equ_exprt = equal_exprt(templ_expr, address_of_exprt(obj1.first)); + exprt equ_exprt=equal_exprt(templ_expr, address_of_exprt(obj1.first)); exprt::operandst steps_expr; - exprt member_expr = obj1.second; + exprt member_expr=obj1.second; // o'.m = d steps_expr.push_back(equal_exprt(member_expr, dest)); - for (auto &obj2 : path.dyn_objects) - { // o'.m = o'' + for(const dyn_objt &obj2 : path.dyn_objects) + { + // o'.m = o'' steps_expr.push_back(equal_exprt(member_expr, address_of_exprt(obj2.first))); } @@ -485,15 +697,30 @@ exprt heap_domaint::heap_row_valuet::get_row_expr(const vart &templ_expr_, } } +/*******************************************************************\ + +Function: heap_domaint::heap_row_valuet::add_points_to + + Inputs: + + Outputs: + + Purpose: Add new object to heap row - create new path, or set + self_linkage flag in case the object is same as the row + object. + +\*******************************************************************/ + bool heap_domaint::heap_row_valuet::add_points_to(const exprt &dest) { - if (dest == dyn_obj.first) + if(dest==dyn_obj.first) { return add_self_linkage(); } else { - const dyn_objt through = self_linkage ? dyn_obj : std::make_pair(nil_exprt(), nil_exprt()); + const dyn_objt through=self_linkage ? dyn_obj : std::make_pair(nil_exprt(), + nil_exprt()); return add_path(dest, through); } } @@ -507,32 +734,37 @@ Function: heap_domaint::heap_row_valuet::add_path Outputs: True if the value was changed (a path was added) - Purpose: Add new path set if any path set does not contain the given destination. - If any path set already contains dest, do nothing since the pathset will be updated from - other rows. + Purpose: Add new path set if any path set does not contain + the given destination. + + If any path set already contains dest, do nothing since + the pathset will be updated from other rows. \*******************************************************************/ -bool heap_domaint::heap_row_valuet::add_path(const exprt &dest, const dyn_objt &dyn_obj) + +bool heap_domaint::heap_row_valuet::add_path( + const exprt &dest, + const dyn_objt &dyn_obj) { - bool new_path = true; - for (auto &path_set : paths) + bool new_path=true; + for(const pathsett &path_set : paths) { - auto p_it = path_set.find(dest); - if (p_it != path_set.end() && p_it->dyn_objects.empty()) + auto p_it=path_set.find(dest); + if(p_it!=path_set.end() && p_it->dyn_objects.empty()) { - new_path = false; + new_path=false; break; } } - if (new_path) + if(new_path) { pathsett new_path_set; std::set dyn_obj_set; - if (dyn_obj.first.id() != ID_nil) + if(dyn_obj.first.id()!=ID_nil) { dyn_obj_set.insert(dyn_obj); } - if (self_linkage) + if(self_linkage) { dyn_obj_set.insert(this->dyn_obj); } @@ -542,18 +774,34 @@ bool heap_domaint::heap_row_valuet::add_path(const exprt &dest, const dyn_objt & return new_path; } -bool heap_domaint::heap_row_valuet::add_path(const exprt &dest, const heap_domaint::dyn_objt &dyn_obj, - pathsett &path_set) +/*******************************************************************\ + +Function: heap_domaint::heap_row_valuet::add_path + + Inputs: dest Path destination + dyn_obj Dynamic object that the path goes through + path_set Path set to add the path to + + Outputs: True if the value was changed (a path was added) + + Purpose: Add new path to a path set + +\*******************************************************************/ + +bool heap_domaint::heap_row_valuet::add_path( + const exprt &dest, + const dyn_objt &dyn_obj, + pathsett &path_set) { - if (path_set.find(dest) == path_set.end()) + if(path_set.find(dest)==path_set.end()) { // Path does not exist yet std::set dyn_obj_set; - if (dyn_obj.first.id() != ID_nil) + if(dyn_obj.first.id()!=ID_nil) { // Path doesn't have zero length dyn_obj_set.insert(dyn_obj); } - if (self_linkage) + if(self_linkage) { dyn_obj_set.insert(this->dyn_obj); } @@ -563,7 +811,7 @@ bool heap_domaint::heap_row_valuet::add_path(const exprt &dest, const heap_domai else { // Path exists already - if (dyn_obj.first.id() != ID_nil) + if(dyn_obj.first.id()!=ID_nil) // Try to insert new dynamic object on the path return path_set.find(dest)->dyn_objects.insert(dyn_obj).second; else @@ -571,74 +819,126 @@ bool heap_domaint::heap_row_valuet::add_path(const exprt &dest, const heap_domai } } -bool heap_domaint::heap_row_valuet::join_path_sets(heap_domaint::heap_row_valuet::pathsett &dest, - const heap_domaint::heap_row_valuet::pathsett &src, - const dyn_objt &through) +/*******************************************************************\ + +Function: heap_domaint::heap_row_valuet::join_path_sets + + Inputs: src Source path set + dest Destination path set + + Outputs: True if the value was changed (dest was added) + + Purpose: Join two path sets. Add all paths from src to dest. + +\*******************************************************************/ + +bool heap_domaint::heap_row_valuet::join_path_sets( + pathsett &dest, + const pathsett &src, + const dyn_objt &through) { - bool result = false; - for (auto &path : src) + bool result=false; + for(const patht &path : src) { - if (add_path(path.destination, through, dest)) - result = true; - for (auto &o : path.dyn_objects) + if(add_path(path.destination, through, dest)) + result=true; + for(const dyn_objt &o : path.dyn_objects) { // Add all dynamic objects of the original path - if (add_path(path.destination, o, dest)) - result = true; + if(add_path(path.destination, o, dest)) + result=true; } } return result; } -bool heap_domaint::heap_row_valuet::add_all_paths(const heap_domaint::heap_row_valuet &other_val, - const heap_domaint::dyn_objt &dyn_obj) +/*******************************************************************\ + +Function: heap_domaint::heap_row_valuet::add_all_paths + + Inputs: + + Outputs: True if this has changed + + Purpose: Add all paths from other heap row. + +\*******************************************************************/ + +bool heap_domaint::heap_row_valuet::add_all_paths( + const heap_row_valuet &other_val, + const dyn_objt &dyn_obj) { - bool result = false; + bool result=false; - auto other_it = other_val.paths.begin(); - if (other_it != other_val.paths.end()) + auto other_it=other_val.paths.begin(); + if(other_it!=other_val.paths.end()) { - for (auto it = paths.begin(); it != paths.end(); ++it) + for(auto it=paths.begin(); it!=paths.end(); ++it) { - if (it->find(other_val.dyn_obj.first) != it->end()) + if(it->find(other_val.dyn_obj.first)!=it->end()) { - auto next_it = other_it; + auto next_it=other_it; ++next_it; - if (next_it != other_val.paths.end()) + if(next_it!=other_val.paths.end()) { // Duplicate element pointed by it - auto n_it = it; + auto n_it=it; ++n_it; paths.insert(n_it, *it); } // Add all paths to *it - if (join_path_sets(*it, *other_it, dyn_obj)) - result = true; + if(join_path_sets(*it, *other_it, dyn_obj)) + result=true; // Move other_it to next, or to first if next doesn't exist - other_it = next_it == other_val.paths.end() ? other_val.paths.begin() : next_it; + other_it= + next_it==other_val.paths.end() ? other_val.paths.begin() : next_it; } } } return result; } +/*******************************************************************\ + +Function: heap_domaint::heap_row_valuet::add_pointed_by + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + bool heap_domaint::heap_row_valuet::add_pointed_by(const rowt &row) { - auto new_pb = pointed_by.insert(row); + auto new_pb=pointed_by.insert(row); return new_pb.second; } +/*******************************************************************\ + +Function: heap_domaint::heap_row_valuet::add_self_linkage + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + bool heap_domaint::heap_row_valuet::add_self_linkage() { bool result; - result = !self_linkage; - self_linkage = true; - if (result) + result=!self_linkage; + self_linkage=true; + if(result) { - for (auto &path_set : paths) + for(const pathsett &path_set : paths) { - for (auto &path : path_set) + for(const patht &path : path_set) { path.dyn_objects.insert(dyn_obj); } @@ -655,13 +955,16 @@ Function: heap_domaint::heap_row_valuet::rename_outheap Outputs: Renamed expression - Purpose: Rename OUTHEAP row expression (used for post-expr). Simply remove 'lb' from suffix. + Purpose: Rename OUTHEAP row expression (used for post-expr). + Simply remove 'lb' from suffix. \*******************************************************************/ + exprt heap_domaint::heap_row_valuet::rename_outheap(const symbol_exprt &expr) { - const std::string id = id2string(expr.get_identifier()); - return symbol_exprt(id.substr(0, id.rfind("lb")) + id.substr(id.rfind("lb") + 2), expr.type()); + const std::string id=id2string(expr.get_identifier()); + return symbol_exprt(id.substr(0, id.rfind("lb"))+id.substr(id.rfind("lb")+2), + expr.type()); } /*******************************************************************\ @@ -670,20 +973,22 @@ Function: heap_domaint::get_new_heap_vars Inputs: - Outputs: List of variables (symbols) that were added to template during analysis + Outputs: List of variables (symbols) that were added to template + during analysis. Purpose: \*******************************************************************/ + const std::list heap_domaint::get_new_heap_vars() { std::list result; - for (auto &row : templ) + for(const template_rowt &row : templ) { - if (row.kind == OUTHEAP) + if(row.kind==OUTHEAP) { - assert(row.expr.id() == ID_symbol); - symbol_exprt expr = to_symbol_expr(row.expr); + assert(row.expr.id()==ID_symbol); + symbol_exprt expr=to_symbol_expr(row.expr); rename(expr); result.push_back(expr); } @@ -691,17 +996,31 @@ const std::list heap_domaint::get_new_heap_vars() return result; } -void heap_domaint::initialize_domain(const local_SSAt &SSA, const exprt &precondition, - template_generator_baset &template_generator) +/*******************************************************************\ + +Function: heap_domaint::initialize_domain + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void heap_domaint::initialize_domain( + const local_SSAt &SSA, + const exprt &precondition, + template_generator_baset &template_generator) { // Bind list iterators bind_iterators(SSA, precondition, template_generator); // Create preconditions for input variables if not exist exprt::operandst equs; - for (auto ¶m : SSA.params) + for(const symbol_exprt ¶m : SSA.params) create_precondition(param, precondition); - for (auto &global_in : SSA.globals_in) + for(const symbol_exprt &global_in : SSA.globals_in) create_precondition(global_in, precondition); } @@ -709,8 +1028,9 @@ void heap_domaint::initialize_domain(const local_SSAt &SSA, const exprt &precond Function: heap_domaint::bind_iterators - Inputs: SSA, calling context represented by precondition and reference - to template generator + Inputs: SSA + precondition Calling context + template_generator Outputs: @@ -718,39 +1038,51 @@ Function: heap_domaint::bind_iterators calling context. \*******************************************************************/ -void heap_domaint::bind_iterators(const local_SSAt &SSA, const exprt &precondition, - template_generator_baset &template_generator) + +void heap_domaint::bind_iterators( + const local_SSAt &SSA, + const exprt &precondition, + template_generator_baset &template_generator) { new_heap_row_specs.clear(); - for (const list_iteratort &iterator : SSA.iterators) + for(const list_iteratort &iterator : SSA.iterators) { - for (const list_iteratort::accesst &access : iterator.accesses) + for(const list_iteratort::accesst &access : iterator.accesses) { - exprt access_binding = iterator_access_bindings(iterator.pointer, iterator.init_pointer, - iterator.iterator_symbol(), iterator.fields, - access, 0, exprt::operandst(), precondition, - SSA); + exprt access_binding=iterator_access_bindings( + iterator.pointer, + iterator.init_pointer, + iterator.iterator_symbol(), + iterator.fields, + access, + 0, + exprt::operandst(), + precondition, + SSA); // Special treatment for first element in the list // @TODO this should be handled better - if (access.fields.size() > 1 && access.location != list_iteratort::IN_LOC) + if(access.fields.size()>1 && access.location!=list_iteratort::IN_LOC) { - const std::set first = collect_preconditions_rec(iterator.init_pointer, - precondition); - for (const exprt &value : first) + const std::set first=collect_preconditions_rec( + iterator.init_pointer, + precondition); + for(const exprt &value : first) { - if (value.id() == ID_address_of) + if(value.id()==ID_address_of) { - assert(to_address_of_expr(value).object().id() == ID_symbol); - const symbol_exprt &first_obj = to_symbol_expr(to_address_of_expr(value).object()); - const symbol_exprt new_value = recursive_member_symbol(first_obj, access.fields.back(), - access.location, ns); - const symbol_exprt old_value = recursive_member_symbol(first_obj, access.fields.back(), - list_iteratort::IN_LOC, ns); - const exprt binding = equal_exprt(new_value, old_value); - access_binding = or_exprt(access_binding, binding); - - add_new_heap_row_spec(old_value, (unsigned) access.location, binding); + assert(to_address_of_expr(value).object().id()==ID_symbol); + const symbol_exprt &first_obj=to_symbol_expr( + to_address_of_expr(value).object()); + const symbol_exprt new_value=recursive_member_symbol( + first_obj, access.fields.back(), access.location, ns); + const symbol_exprt old_value=recursive_member_symbol( + first_obj, access.fields.back(), list_iteratort::IN_LOC, ns); + const exprt binding=equal_exprt(new_value, old_value); + access_binding=or_exprt(access_binding, binding); + + add_new_heap_row_spec(old_value, (unsigned) access.location, + binding); } } } @@ -760,10 +1092,11 @@ void heap_domaint::bind_iterators(const local_SSAt &SSA, const exprt &preconditi } // Add template rows for bound heap objects - for (auto &row_spec : new_heap_row_specs) + for(const heap_row_spect &row_spec : new_heap_row_specs) { - new_output_template_row(row_spec.expr, row_spec.location_number, row_spec.post_guard, SSA, - template_generator); + new_output_template_row( + row_spec.expr, row_spec.location_number, row_spec.post_guard, SSA, + template_generator); } } @@ -778,30 +1111,36 @@ Function: heap_domaint::new_output_template_row Purpose: Insert new output template row into the template. \*******************************************************************/ -void heap_domaint::new_output_template_row(const symbol_exprt &var, const unsigned location_number, - const exprt &post_guard, const local_SSAt &SSA, - template_generator_baset &template_generator) + +void heap_domaint::new_output_template_row( + const symbol_exprt &var, + const unsigned location_number, + const exprt &post_guard, + const local_SSAt &SSA, + template_generator_baset &template_generator) { template_generator.var_specs.push_back(domaint::var_spect()); - domaint::var_spect &var_spec = template_generator.var_specs.back(); + domaint::var_spect &var_spec=template_generator.var_specs.back(); - local_SSAt::locationt loc = SSA.get_location(location_number); + local_SSAt::locationt loc=SSA.get_location(location_number); - const exprt pre_guard = SSA.guard_symbol(loc); + const exprt pre_guard=SSA.guard_symbol(loc); - const symbol_exprt pre_var = SSA.name(ssa_objectt(var, SSA.ns), local_SSAt::LOOP_BACK, loc); - const symbol_exprt post_var = SSA.name(ssa_objectt(var, SSA.ns), local_SSAt::OUT, loc); + const symbol_exprt pre_var=SSA.name( + ssa_objectt(var, SSA.ns), local_SSAt::LOOP_BACK, loc); + const symbol_exprt post_var=SSA.name( + ssa_objectt(var, SSA.ns), local_SSAt::OUT, loc); - var_spec.var = pre_var; - var_spec.pre_guard = pre_guard; - var_spec.post_guard = post_guard; - var_spec.aux_expr = true_exprt(); - var_spec.kind = OUTHEAP; + var_spec.var=pre_var; + var_spec.pre_guard=pre_guard; + var_spec.post_guard=post_guard; + var_spec.aux_expr=true_exprt(); + var_spec.kind=OUTHEAP; - renaming_map[pre_var] = post_var; + renaming_map[pre_var]=post_var; - assert(var.type().id() == ID_pointer); - const typet &pointed_type = ns.follow(var.type().subtype()); + assert(var.type().id()==ID_pointer); + const typet &pointed_type=ns.follow(var.type().subtype()); add_template_row(var_spec, pointed_type); } @@ -819,7 +1158,8 @@ Function: heap_domaint::create_precondition \*******************************************************************/ void heap_domaint::create_precondition( - const symbol_exprt &var, const exprt &precondition) + const symbol_exprt &var, + const exprt &precondition) { if(var.type().id()==ID_pointer) { @@ -839,28 +1179,27 @@ void heap_domaint::create_precondition( } else { - // For members of structs, find corresponding object - // in calling context and return its member + // For members of structs, find corresponding object in the calling + // context and return its member std::string var_id_str=id2string(var.get_identifier()); const symbol_exprt pointer( - var_id_str.substr(0, var_id_str.rfind("'obj")), - var.type()); + var_id_str.substr(0, var_id_str.rfind("'obj")), var.type()); const irep_idt member=var_id_str.substr(var_id_str.rfind(".")); exprt::operandst d; - std::set pointed_objs= - collect_preconditions_rec(pointer, precondition); - for(auto pointed : pointed_objs) + std::set pointed_objs=collect_preconditions_rec( + pointer, precondition); + for(exprt pointed : pointed_objs) { - if(pointed.id()== ID_address_of) + if(pointed.id()==ID_address_of) { const exprt pointed_object=to_address_of_expr(pointed).object(); if(pointed_object.id()==ID_symbol) { symbol_exprt pointed_member( - id2string(to_symbol_expr(pointed_object).get_identifier())+ - id2string(member), - var.type()); + id2string(to_symbol_expr(pointed_object).get_identifier())+ + id2string(member), + var.type()); d.push_back(equal_exprt(var, pointed_member)); } } @@ -874,16 +1213,52 @@ void heap_domaint::create_precondition( } } +/*******************************************************************\ + +Function: heap_domaint::get_iterator_bindings + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + const exprt heap_domaint::get_iterator_bindings() const { return conjunction(iterator_bindings); } +/*******************************************************************\ + +Function: heap_domaint::get_aux_bindings + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + const exprt heap_domaint::get_aux_bindings() const { return conjunction(aux_bindings); } +/*******************************************************************\ + +Function: heap_domaint::get_input_bindings + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + const exprt heap_domaint::get_input_bindings() const { return and_exprt(get_iterator_bindings(), get_aux_bindings()); @@ -905,57 +1280,65 @@ Function: heap_domaint::iterator_access_bindings Outputs: Formula corresponding to bindings - Purpose: Create bindings of iterator with corresponding dynamic objects. Function is called - recursively, if there is access with multiple fields. + Purpose: Create bindings of iterator with corresponding dynamic objects. + Function is called recursively, if there is access with multiple + fields. \*******************************************************************/ -const exprt heap_domaint::iterator_access_bindings(const symbol_exprt &src, - const exprt &init_pointer, - const symbol_exprt &iterator_sym, - const std::vector &fields, - const list_iteratort::accesst &access, - const unsigned level, - exprt::operandst guards, - const exprt &precondition, - const local_SSAt &SSA) + +const exprt heap_domaint::iterator_access_bindings( + const symbol_exprt &src, + const exprt &init_pointer, + const symbol_exprt &iterator_sym, + const std::vector &fields, + const list_iteratort::accesst &access, + const unsigned level, + exprt::operandst guards, + const exprt &precondition, + const local_SSAt &SSA) { - const std::set reachable = reachable_objects(init_pointer, fields, precondition); + const std::set reachable=reachable_objects( + init_pointer, fields, precondition); exprt::operandst d; - for (auto &r : reachable) + for(const symbol_exprt &r : reachable) { exprt::operandst c; equal_exprt points_to_eq(src, address_of_exprt(r)); c.push_back(points_to_eq); - if (level == 0) + if(level==0) { - equal_exprt address_eq(address_canonizer(address_of_exprt(iterator_sym), ns), - address_of_exprt(r)); + equal_exprt address_eq( + address_canonizer(address_of_exprt(iterator_sym), ns), + address_of_exprt(r)); c.push_back(address_eq); } - equal_exprt access_eq = access.binding(iterator_sym, r, level, ns); + equal_exprt access_eq=access.binding(iterator_sym, r, level, ns); c.push_back(access_eq); guards.push_back(conjunction(c)); - if (level < access.fields.size() - 1) + if(level heap_domaint::reachable_objects(const exprt &src, - const std::vector &fields, - const exprt &precondition) const + +const std::set heap_domaint::reachable_objects( + const exprt &src, + const std::vector &fields, + const exprt &precondition) const { std::set result; - if (!(src.id() == ID_symbol || src.id() == ID_member)) return result; + if(!(src.id()==ID_symbol || src.id()==ID_member)) return result; std::set pointed_objs; - if (src.id() == ID_member && to_member_expr(src).compound().get_bool(ID_pointed)) + if(src.id()==ID_member && to_member_expr(src).compound().get_bool(ID_pointed)) { - const member_exprt &member = to_member_expr(src); - const exprt pointer = get_pointer(member.compound(), pointed_level(member.compound()) - 1); + const member_exprt &member=to_member_expr(src); + const exprt pointer=get_pointer(member.compound(), + pointed_level(member.compound())-1); - std::set r = reachable_objects(pointer, {member.get_component_name()}, - precondition); + std::set r=reachable_objects( + pointer, {member.get_component_name()}, precondition); pointed_objs.insert(r.begin(), r.end()); } else { - if (src.type().id() == ID_pointer) + if(src.type().id()==ID_pointer) { - std::set values = collect_preconditions_rec(src, precondition); - for (auto &v : values) + std::set values=collect_preconditions_rec(src, precondition); + for(const exprt &v : values) { - if (v.id() == ID_address_of) + if(v.id()==ID_address_of) { - assert(to_address_of_expr(v).object().id() == ID_symbol); + assert(to_address_of_expr(v).object().id()==ID_symbol); pointed_objs.insert(to_symbol_expr(to_address_of_expr(v).object())); } } @@ -1021,42 +1407,58 @@ const std::set heap_domaint::reachable_objects(const exprt &src, } } - for (unsigned i = 0; i < fields.size(); ++i) + for(unsigned i=0; i reachable_objs = collect_preconditions_rec(obj_member, precondition); - for (const exprt &reachable : reachable_objs) + std::set reachable_objs=collect_preconditions_rec( + obj_member, precondition); + for(const exprt &reachable : reachable_objs) { - if (reachable.id() == ID_address_of) + if(reachable.id()==ID_address_of) { - const exprt &reachable_obj = to_address_of_expr(reachable).object(); - assert(reachable_obj.id() == ID_symbol); + const exprt &reachable_obj=to_address_of_expr(reachable).object(); + assert(reachable_obj.id()==ID_symbol); result.insert(to_symbol_expr(reachable_obj)); } } } - if (i != fields.size() - 1) - pointed_objs = result; + if(i!=fields.size()-1) + pointed_objs=result; } return result; } -void heap_domaint::add_new_heap_row_spec(const symbol_exprt &expr, const unsigned location_number, - const exprt &post_guard) +/*******************************************************************\ + +Function: heap_domaint::add_new_heap_row_spec + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void heap_domaint::add_new_heap_row_spec( + const symbol_exprt &expr, + const unsigned location_number, + const exprt &post_guard) { - auto it = new_heap_row_specs.emplace(expr, location_number, post_guard); - if (!it.second) + auto it=new_heap_row_specs.emplace(expr, location_number, post_guard); + if(!it.second) { - if (it.first->post_guard != post_guard) - it.first->post_guard = or_exprt(it.first->post_guard, post_guard); + if(it.first->post_guard!=post_guard) + it.first->post_guard=or_exprt(it.first->post_guard, post_guard); } } diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index 9795bcea9..b895f14ff 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -1,22 +1,30 @@ -/** - * Abstract domain for representing heap. - * - * Viktor Malik, 12.8.2016 (c). - */ +/*******************************************************************\ + +Module: Abstract domain for representing heap + +Author: Viktor Malik + +\*******************************************************************/ #ifndef CPROVER_2LS_DOMAINS_HEAP_DOMAIN_H #define CPROVER_2LS_DOMAINS_HEAP_DOMAIN_H -#include #include -#include "../ssa/local_ssa.h" + +#include +#include + +#include + #include "domain.h" #include "template_generator_base.h" class heap_domaint:public domaint { - public: +public: typedef unsigned rowt; + // Field of a dynamic object (a variable) typedef vart member_fieldt; + // We represent dynamic object by the object itself and its member field typedef std::pair dyn_objt; typedef enum { STACK, HEAP } mem_kindt; @@ -25,10 +33,10 @@ class heap_domaint:public domaint unsigned int _domain_number, replace_mapt &_renaming_map, const var_specst &var_specs, - const namespacet &ns_): - domaint(_domain_number, _renaming_map, ns_) + const namespacet &_ns): + domaint(_domain_number, _renaming_map, _ns) { - make_template(var_specs, ns_); + make_template(var_specs, _ns); } struct template_rowt @@ -44,25 +52,35 @@ class heap_domaint:public domaint }; typedef std::vector templatet; - /** - * Value of a row is set of paths in the heap leading from row variable - */ + /*******************************************************************\ + Base class for a value of a row + \*******************************************************************/ struct row_valuet { - bool nondet = false; /**< Row is nondeterministic - expression is TRUE */ + // Row is nondeterministic - row expression is TRUE + bool nondet=false; - virtual exprt get_row_expr(const vart &templ_expr, bool rename_templ_expr) const = 0; + virtual exprt get_row_expr( + const vart &templ_expr, + bool rename_templ_expr) const=0; - virtual bool empty() const = 0; + virtual bool empty() const=0; - virtual bool add_points_to(const exprt &dest) = 0; + virtual bool add_points_to(const exprt &dest)=0; }; - struct stack_row_valuet : public row_valuet + /*******************************************************************\ + Stack row - used for pointer-typed stack objects (variables). + Value is a set of objects that the pointer can point to. + \*******************************************************************/ + struct stack_row_valuet:public row_valuet { - std::set points_to; /**< Set of objects (or NULL) the row variable can point to */ + // Set of objects (or NULL) the row variable can point to + std::set points_to; - virtual exprt get_row_expr(const vart &templ_expr, bool rename_templ_expr) const override; + virtual exprt get_row_expr( + const vart &templ_expr, + bool rename_templ_expr) const override; virtual bool add_points_to(const exprt &expr) override; @@ -72,46 +90,60 @@ class heap_domaint:public domaint } }; - struct heap_row_valuet : public row_valuet + /*******************************************************************\ + Heap row - used for pointer-typed fields of dynamic objects. + + Value is a disjunction of conjunctions of paths leading from the dynamic + object via the field. + \*******************************************************************/ + struct heap_row_valuet:public row_valuet { - /** - * Path in a heap. Contains: - * - destination object - * - set of dynamic objects - this is the set of ssa objects that the path is composed of - * - boolean value expressing whether path can have zero length - * Paths are ordered by destination only as it is unique within a value row. - */ + /*******************************************************************\ + Path in a heap. Contains: + - destination object + - set of dynamic objects - set of SSA objects that the path is composed of + + Paths are ordered by destination only as it is unique within a value row. + \*******************************************************************/ struct patht { exprt destination; mutable std::set dyn_objects; - patht(const exprt &dest_) : destination(dest_) {} + patht(const exprt &dest_):destination(dest_) {} - patht(const exprt &dest_, const std::set &dyn_objs_) - : destination(dest_), dyn_objects(dyn_objs_) {} + patht(const exprt &dest_, const std::set &dyn_objs_): + destination(dest_), dyn_objects(dyn_objs_) {} bool operator<(const patht &rhs) const { - return destination < rhs.destination; + return destination pathsett; + // Set of pathsets interpreted as a disjnuction of pathsets std::list paths; - std::set pointed_by; /**< Set of rows whose variables point to this row */ + // Set of rows whose variables point to this row + std::set pointed_by; + + // Dynamic obejct corresponding to the row (contains both object and field) dyn_objt dyn_obj; - bool self_linkage = false; + // Self link on an abstract dynamic object + bool self_linkage=false; - heap_row_valuet(const dyn_objt &dyn_obj_) : dyn_obj(dyn_obj_) {} + explicit heap_row_valuet(const dyn_objt &dyn_obj_):dyn_obj(dyn_obj_) {} - virtual exprt get_row_expr(const vart &templ_expr_, bool rename_templ_expr) const override; + virtual exprt get_row_expr( + const vart &templ_expr_, + bool rename_templ_expr) const override; virtual bool add_points_to(const exprt &dest) override; @@ -122,45 +154,58 @@ class heap_domaint:public domaint bool add_path(const exprt &dest, const dyn_objt &dyn_obj); - bool add_path(const exprt &dest, const heap_domaint::dyn_objt &dyn_obj, pathsett &path_set); + bool add_path( + const exprt &dest, + const dyn_objt &dyn_obj, + pathsett &path_set); - bool join_path_sets(heap_domaint::heap_row_valuet::pathsett &dest, - const heap_domaint::heap_row_valuet::pathsett &src, - const dyn_objt &through); + bool join_path_sets( + pathsett &dest, + const pathsett &src, + const dyn_objt &through); - bool add_all_paths(const heap_row_valuet &other_val, const dyn_objt &dyn_obj); + bool add_all_paths( + const heap_row_valuet &other_val, + const dyn_objt &dyn_obj); bool add_pointed_by(const rowt &row); bool add_self_linkage(); - protected: + protected: static exprt rename_outheap(const symbol_exprt &expr); }; - class heap_valuet : public valuet, public std::vector> + class heap_valuet: + public valuet, + public std::vector> { - public: + public: row_valuet &operator[](const rowt &row) const { return *(this->at(row).get()); } }; - // Initialize value + // Initialize value and domain virtual void initialize(valuet &value) override; - void initialize_domain(const local_SSAt &SSA, const exprt &precondition, - template_generator_baset &template_generator); + void initialize_domain( + const local_SSAt &SSA, const exprt &precondition, + template_generator_baset &template_generator); // Value -> constraints exprt to_pre_constraints(const heap_valuet &value) const; - void make_not_post_constraints(const heap_valuet &value, exprt::operandst &cond_exprs, - exprt::operandst &value_exprs); + void make_not_post_constraints( + const heap_valuet &value, + exprt::operandst &cond_exprs, + exprt::operandst &value_exprs); // Row -> constraints - exprt get_row_pre_constraint(const rowt &row, const row_valuet &row_value) const; + exprt get_row_pre_constraint( + const rowt &row, + const row_valuet &row_value) const; exprt get_row_post_constraint(const rowt &row, const row_valuet &row_value); @@ -172,13 +217,17 @@ class heap_domaint:public domaint bool set_nondet(const rowt &row, heap_valuet &value); // Printing - virtual void output_value(std::ostream &out, const valuet &value, - const namespacet &ns) const override; + virtual void output_value( + std::ostream &out, const valuet &value, + const namespacet &ns) const override; - virtual void output_domain(std::ostream &out, const namespacet &ns) const override; + virtual void output_domain( + std::ostream &out, + const namespacet &ns) const override; // Projection - virtual void project_on_vars(valuet &value, const var_sett &vars, exprt &result) override; + virtual void + project_on_vars(valuet &value, const var_sett &vars, exprt &result) override; // Conversion of solver value to expression static exprt value_to_ptr_exprt(const exprt &expr); @@ -193,38 +242,49 @@ class heap_domaint:public domaint const exprt get_aux_bindings() const; const exprt get_input_bindings() const; - protected: +protected: templatet templ; + // Bindings computed during interprocedural analysis exprt::operandst iterator_bindings; exprt::operandst aux_bindings; - /** - * Specification of a new heap row. The row is added dynamically at the beginning of the analysis - * after binding of iterators to actual dynamic objects from calling context. - */ + /*******************************************************************\ + Specification of a new heap row that is added dynamically + at the beginning of the analysis, after binding of iterators to the actual + dynamic objects from the calling context. + + Contains row expression and a location where the corresponding + iterator occured. + \*******************************************************************/ class heap_row_spect { - public: - symbol_exprt expr; /**< Row expression */ - unsigned location_number; /**< Location where the corresponding iterator occured */ + public: + symbol_exprt expr; + unsigned location_number; mutable exprt post_guard; - heap_row_spect(const symbol_exprt &expr, unsigned int location_number, const exprt &post_guard) - : expr(expr), location_number(location_number), post_guard(post_guard) {} + heap_row_spect( + const symbol_exprt &expr, + unsigned int location_number, + const exprt &post_guard): + expr(expr), location_number(location_number), post_guard(post_guard) {} bool operator<(const heap_row_spect &rhs) const { - return std::tie(expr, location_number) < std::tie(rhs.expr, rhs.location_number); + return std::tie(expr, location_number)< + std::tie(rhs.expr, rhs.location_number); } bool operator==(const heap_row_spect &rhs) const { - return std::tie(expr, location_number) == std::tie(rhs.expr, rhs.location_number); + return std::tie(expr, location_number)== + std::tie(rhs.expr, rhs.location_number); } }; + // Set of new heap rows added during analysis (used for interprocedural) std::set new_heap_row_specs; void make_template(const var_specst &var_specs, const namespacet &ns); @@ -232,32 +292,46 @@ class heap_domaint:public domaint void add_template_row(const var_spect &var_spec, const typet &pointed_type); // Initializing functions - void bind_iterators(const local_SSAt &SSA, const exprt &precondition, - template_generator_baset &template_generator); + void bind_iterators( + const local_SSAt &SSA, + const exprt &precondition, + template_generator_baset &template_generator); void create_precondition(const symbol_exprt &var, const exprt &precondition); - void new_output_template_row(const symbol_exprt &var, const unsigned location_number, - const exprt &post_guard, const local_SSAt &SSA, - template_generator_baset &template_generator); - - const exprt iterator_access_bindings(const symbol_exprt &src, const exprt &init_pointer, - const symbol_exprt &iterator_sym, - const std::vector &fields, - const list_iteratort::accesst &access, const unsigned level, - exprt::operandst guards, const exprt &precondition, - const local_SSAt &SSA); + void new_output_template_row( + const symbol_exprt &var, + const unsigned location_number, + const exprt &post_guard, + const local_SSAt &SSA, + template_generator_baset &template_generator); + + const exprt iterator_access_bindings( + const symbol_exprt &src, + const exprt &init_pointer, + const symbol_exprt &iterator_sym, + const std::vector &fields, + const list_iteratort::accesst &access, + const unsigned level, + exprt::operandst guards, + const exprt &precondition, + const local_SSAt &SSA); + + const std::set reachable_objects( + const exprt &src, + const std::vector &fields, + const exprt &precondition) const; + + static const std::set collect_preconditions_rec( + const exprt &expr, + const exprt &precondition); + + + void add_new_heap_row_spec( + const symbol_exprt &expr, + const unsigned location_number, + const exprt &post_guard); - const std::set reachable_objects(const exprt &src, - const std::vector &fields, - const exprt &precondition) const; - - static const std::set collect_preconditions_rec(const exprt &expr, - const exprt &precondition); - - - void add_new_heap_row_spec(const symbol_exprt &expr, const unsigned location_number, - const exprt &post_guard); // Utility functions static int get_symbol_loc(const exprt &expr); @@ -266,5 +340,4 @@ class heap_domaint:public domaint friend class strategy_solver_heapt; }; - #endif // CPROVER_2LS_DOMAINS_HEAP_DOMAIN_H diff --git a/src/domains/heap_interval_domain.cpp b/src/domains/heap_interval_domain.cpp index 0b6f06775..381ea662e 100644 --- a/src/domains/heap_interval_domain.cpp +++ b/src/domains/heap_interval_domain.cpp @@ -1,43 +1,100 @@ -/** - * Viktor Malik, 3/30/17 (c). - */ +/*******************************************************************\ + +Module: Combination of heap and interval abstract domains + +Author: Viktor Malik + +\*******************************************************************/ #include "heap_interval_domain.h" +/*******************************************************************\ + +Function: heap_interval_domaint::initialize + + Inputs: + + Outputs: + + Purpose: Initialize abstract value. + +\*******************************************************************/ + void heap_interval_domaint::initialize(domaint::valuet &value) { - heap_interval_valuet &v = static_cast(value); + heap_interval_valuet &v=static_cast(value); heap_domain.initialize(v.heap_value); interval_domain.initialize(v.interval_value); } -void heap_interval_domaint::output_value(std::ostream &out, const domaint::valuet &value, - const namespacet &ns) const +/*******************************************************************\ + +Function: heap_interval_domaint::output_value + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void heap_interval_domaint::output_value( + std::ostream &out, + const domaint::valuet &value, + const namespacet &ns) const { - const heap_interval_valuet &v = static_cast(value); + const heap_interval_valuet &v= + static_cast(value); heap_domain.output_value(out, v.heap_value, ns); interval_domain.output_value(out, v.interval_value, ns); } -void heap_interval_domaint::output_domain(std::ostream &out, const namespacet &ns) const +/*******************************************************************\ + +Function: heap_interval_domaint::output_domain + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void heap_interval_domaint::output_domain( + std::ostream &out, + const namespacet &ns) const { heap_domain.output_domain(out, ns); interval_domain.output_domain(out, ns); } -void heap_interval_domaint::project_on_vars(domaint::valuet &value, const domaint::var_sett &vars, - exprt &result) +/*******************************************************************\ + +Function: heap_interval_domaint::project_on_vars + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void heap_interval_domaint::project_on_vars( + domaint::valuet &value, + const domaint::var_sett &vars, + exprt &result) { - heap_interval_valuet &v = static_cast(value); + heap_interval_valuet &v=static_cast(value); exprt heap_result; heap_domain.project_on_vars(v.heap_value, vars, heap_result); exprt interval_result; interval_domain.project_on_vars(v.interval_value, vars, interval_result); - result = and_exprt(heap_result, interval_result); + result=and_exprt(heap_result, interval_result); } - - diff --git a/src/domains/heap_interval_domain.h b/src/domains/heap_interval_domain.h index b3142fb79..e2e8e321e 100644 --- a/src/domains/heap_interval_domain.h +++ b/src/domains/heap_interval_domain.h @@ -1,8 +1,12 @@ -/** - * Viktor Malik, 3/30/17 (c). - */ -#ifndef INC_2LS_HEAP_INTERVAL_DOMAINT_H -#define INC_2LS_HEAP_INTERVAL_DOMAINT_H +/*******************************************************************\ + +Module: Combination of heap and interval abstract domains + +Author: Viktor Malik + +\*******************************************************************/ +#ifndef CPROVER_2LS_DOMAINS_HEAP_INTERVAL_DOMAIN_H +#define CPROVER_2LS_DOMAINS_HEAP_INTERVAL_DOMAIN_H #include "domain.h" @@ -48,4 +52,4 @@ class heap_interval_domaint : public domaint }; -#endif //INC_2LS_HEAP_INTERVAL_DOMAINT_H +#endif // CPROVER_2LS_DOMAINS_HEAP_INTERVAL_DOMAIN_H diff --git a/src/domains/list_iterator.cpp b/src/domains/list_iterator.cpp index 6d6b96bbe..be6e3e4cb 100644 --- a/src/domains/list_iterator.cpp +++ b/src/domains/list_iterator.cpp @@ -1,22 +1,42 @@ -/** - * Viktor Malik, 2/6/17 (c). - */ +/*******************************************************************\ + +Module: List iterator - abstraction for iterative access to a linked + list. + +Author: Viktor Malik + +\*******************************************************************/ #include -#include "../ssa/ssa_pointed_objects.h" -#include "../ssa/address_canonizer.h" +#include #include "list_iterator.h" -void list_iteratort::add_access(const member_exprt &expr, int location_number) const +/*******************************************************************\ + +Function: list_iteratort::add_access + + Inputs: + + Outputs: + + Purpose: Add new access to the iterator corresponding to + an expression from SSA. + +\*******************************************************************/ + +void list_iteratort::add_access( + const member_exprt &expr, + int location_number) const { - assert(expr.compound().get_bool(ID_iterator) && expr.compound().get_bool(ID_pointed)); + assert(expr.compound().get_bool(ID_iterator) && + expr.compound().get_bool(ID_pointed)); accesst access; - access.location = location_number; + access.location=location_number; - unsigned level = pointed_level(expr.compound()); - unsigned iterator_level = it_value_level(expr.compound()); - for (unsigned l = iterator_level; l < level; ++l) + unsigned level=pointed_level(expr.compound()); + unsigned iterator_level=it_value_level(expr.compound()); + for(unsigned l=iterator_level; l @@ -10,42 +16,63 @@ class list_iteratort { - public: - static const int IN_LOC = -1; +public: + // No location (used for input variables) + static const int IN_LOC=-1; + /*******************************************************************\ + Access to an object from a list iterator. + Contains: + - sequence of fields that are used to access the object from the + iterator + - location: + IN_LOC for read access + location number for write access + \*******************************************************************/ class accesst { - public: + public: std::vector fields; int location; - equal_exprt binding(const symbol_exprt &lhs, const symbol_exprt &rhs, - const unsigned level, const namespacet &ns) const; + equal_exprt binding( + const symbol_exprt &lhs, const symbol_exprt &rhs, + const unsigned level, const namespacet &ns) const; }; + // Pointer variable used to iterate the list (induction pointer) symbol_exprt pointer; + // Initial value of the induction pointer (before the first iteration) exprt init_pointer; + // Set of fields through which a step is done after each iteration std::vector fields; mutable std::list accesses; - list_iteratort(const symbol_exprt &pointer, const exprt &init_pointer, - const std::vector &fields) - : pointer(pointer), init_pointer(init_pointer), fields(fields) {} + list_iteratort( + const symbol_exprt &pointer, + const exprt &init_pointer, + const std::vector &fields): + pointer(pointer), init_pointer(init_pointer), fields(fields) {} bool operator<(const list_iteratort &rhs) const { - return std::tie(pointer, fields) < std::tie(rhs.pointer, rhs.fields); + return std::tie(pointer, fields)project_on_vars(*result, vars, _result); } +/*******************************************************************\ + +Function: ssa_analyzert::update_heap_out + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ void ssa_analyzert::update_heap_out(summaryt::var_sett &out) { heap_domaint &heap_domain = static_cast(*domain); @@ -185,6 +196,17 @@ void ssa_analyzert::update_heap_out(summaryt::var_sett &out) out.insert(new_heap_vars.begin(), new_heap_vars.end()); } +/*******************************************************************\ + +Function: ssa_analyzert::input_heap_bindings + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ const exprt ssa_analyzert::input_heap_bindings() { return static_cast(*domain).get_iterator_bindings(); diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index 483b6f4f1..e88b00276 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -1,22 +1,38 @@ -/** - * Viktor Malik, 12.8.2016 (c). - */ +/*******************************************************************\ + +Module: Strategy solver for heap shape analysis + +Author: Viktor Malik + +\*******************************************************************/ //#define DEBUG_OUTPUT #include "strategy_solver_heap.h" +/*******************************************************************\ + +Function: strategy_solver_heapt::iterate + + Inputs: + + Outputs: + + Purpose: Single iteration of invariant inference using heap shape + domain. + +\*******************************************************************/ + bool strategy_solver_heapt::iterate(invariantt &_inv) { - heap_domaint::heap_valuet &inv= - static_cast(_inv); + heap_domaint::heap_valuet &inv=static_cast(_inv); - bool improved = false; + bool improved=false; solver.new_context(); // Entry value constraints - exprt pre_expr = heap_domain.to_pre_constraints(inv); + exprt pre_expr=heap_domain.to_pre_constraints(inv); #ifdef DEBUG_OUTPUT debug() << "pre-inv: " << from_expr(ns, "", pre_expr) << eom; #endif @@ -32,14 +48,14 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) #ifdef DEBUG_OUTPUT debug() << "post-inv: "; #endif - for (unsigned i = 0; i < strategy_cond_exprs.size(); ++i) + for(unsigned i=0; i 0 ? " || " : "") + debug() << (i>0 ? " || " : "") << from_expr(ns, "", strategy_cond_exprs[i]); #endif - strategy_cond_literals[i] = solver.convert(strategy_cond_exprs[i]); - strategy_cond_exprs[i] = literal_exprt(strategy_cond_literals[i]); + strategy_cond_literals[i]=solver.convert(strategy_cond_exprs[i]); + strategy_cond_exprs[i]=literal_exprt(strategy_cond_literals[i]); } #ifdef DEBUG_OUTPUT debug() << eom; @@ -50,30 +66,29 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) debug() << "solve(): "; #endif - if (solver() == decision_proceduret::D_SATISFIABLE) // improvement check + if(solver()==decision_proceduret::D_SATISFIABLE) // improvement check { #ifdef DEBUG_OUTPUT debug() << "SAT" << eom; #endif #ifdef DEBUG_OUTPUT - for (unsigned i = 0; i < solver.activation_literals.size(); i++) + for(unsigned i=0; i=0 && !inv[member_val_index].nondet) + if(member_val_index>=0 && !inv[member_val_index].nondet) { // Add all paths from obj.next to p - if(heap_domain.add_transitivity(row, (unsigned) member_val_index, inv)) + if(heap_domain.add_transitivity( + row, (unsigned) member_val_index, inv)) { improved=true; debug() << "Add all paths: " - << from_expr(ns, "", heap_domain.templ[member_val_index].expr) + << from_expr( + ns, "", heap_domain.templ[member_val_index].expr) << ", through: " << from_expr(ns, "", obj) << eom; } } @@ -176,13 +196,14 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) { if(heap_domain.set_nondet(row, inv)) { - improved = true; + improved=true; debug() << "Set nondet" << eom; } } - if (templ_row.mem_kind==heap_domaint::HEAP) - { // Recursively update all rows that are dependent on this row + // Recursively update all rows that are dependent on this row + if(templ_row.mem_kind==heap_domaint::HEAP) + { updated_rows.clear(); if(!inv[row].nondet) update_rows_rec(row, inv); @@ -209,8 +230,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) exprt c=heap_domain.get_row_pre_constraint(i, inv[i]); debug() << "cond: " << from_expr(ns, "", c) << " " << from_expr(ns, "", solver.get(c)) << eom; - debug() << "guards: " - << from_expr(ns, "", heap_domain.templ[i].pre_guard) + debug() << "guards: " << from_expr(ns, "", heap_domain.templ[i].pre_guard) << " " << from_expr(ns, "", solver.get(heap_domain.templ[i].pre_guard)) << eom; @@ -229,41 +249,48 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) return improved; } -/** - * Find the template row that contains specified member field - * of a dynamic object at given location. - * Finds obj.member#loc with maximal loc less than actual_loc. - * @param obj - * @param member Member field to find - * @param actual_loc Actual location number - * @return Template row of obj.member - */ +/*******************************************************************\ + +Function: strategy_solver_heapt::find_member_row + + Inputs: object + field + actual location + + Outputs: Row number for obj.member#loc with maximal loc less than actual_loc + -1 if such template row does not exist + + Purpose: Find the template row that contains specified member field + of a dynamic object at the given location. + +\*******************************************************************/ + int strategy_solver_heapt::find_member_row( const exprt &obj, const irep_idt &member, int actual_loc, const domaint::kindt &kind) { - assert(obj.id() == ID_symbol); - std::string obj_id = heap_domain.get_base_name(obj); + assert(obj.id()==ID_symbol); + std::string obj_id=heap_domain.get_base_name(obj); - int result = -1; - int max_loc = -1; - for (unsigned i = 0; i < heap_domain.templ.size(); ++i) + int result=-1; + int max_loc=-1; + for(unsigned i=0; i max_loc && - (kind == domaint::OUT || kind == domaint::OUTHEAP || loc <= actual_loc)) + int loc=heap_domain.get_symbol_loc(templ_row.expr); + if(loc>max_loc && + (kind==domaint::OUT || kind==domaint::OUTHEAP || loc<=actual_loc)) { - max_loc = loc; - result = i; + max_loc=loc; + result=i; } } } @@ -271,23 +298,29 @@ int strategy_solver_heapt::find_member_row( return result; } -/** - * Recursively update rows that point to given row. - * @param row Pointed row - * @param value Heap value - * @return True if any change occured - */ +/*******************************************************************\ + +Function: strategy_solver_heapt::update_rows_rec + + Inputs: + + Outputs: + + Purpose: Recursively update rows that point to given row. + +\*******************************************************************/ + bool strategy_solver_heapt::update_rows_rec( const heap_domaint::rowt &row, heap_domaint::heap_valuet &value) { - heap_domaint::heap_row_valuet &row_value = - static_cast(value[row]); - const heap_domaint::template_rowt &templ_row = heap_domain.templ[row]; + heap_domaint::heap_row_valuet &row_value= + static_cast(value[row]); + const heap_domaint::template_rowt &templ_row=heap_domain.templ[row]; updated_rows.insert(row); - bool result = false; - for (auto &ptr : row_value.pointed_by) + bool result=false; + for(const heap_domaint::rowt &ptr : row_value.pointed_by) { if(heap_domain.templ[ptr].mem_kind==heap_domaint::HEAP && heap_domain.templ[ptr].member==templ_row.member) @@ -296,7 +329,8 @@ bool strategy_solver_heapt::update_rows_rec( result=true; debug() << "recursively updating row: " << ptr << eom; - debug() << "add all paths: " << from_expr(ns, "", templ_row.expr) << ", through: " + debug() << "add all paths: " << from_expr(ns, "", templ_row.expr) + << ", through: " << from_expr(ns, "", templ_row.dyn_obj) << eom; // Recursive update is called for each row only once if(updated_rows.find(ptr)==updated_rows.end()) @@ -306,14 +340,38 @@ bool strategy_solver_heapt::update_rows_rec( return result; } +/*******************************************************************\ + +Function: strategy_solver_heapt::print_solver_expr + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + void strategy_solver_heapt::print_solver_expr(const exprt &expr) { debug() << from_expr(ns, "", expr) << ": " << from_expr(ns, "", solver.get(expr)) << eom; forall_operands(it, expr) - print_solver_expr(*it); + print_solver_expr(*it); } +/*******************************************************************\ + +Function: strategy_solver_heapt::initialize + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + void strategy_solver_heapt::initialize( const local_SSAt &SSA, const exprt &precondition, @@ -322,14 +380,14 @@ void strategy_solver_heapt::initialize( heap_domain.initialize_domain(SSA, precondition, template_generator); const exprt input_bindings=heap_domain.get_input_bindings(); - if (!input_bindings.is_true()) + if(!input_bindings.is_true()) { solver << input_bindings; debug() << "Input bindings:" << eom; debug() << from_expr(ns, "", input_bindings) << eom; } - if (!heap_domain.new_heap_row_specs.empty()) + if(!heap_domain.new_heap_row_specs.empty()) { debug() << "New template:" << eom; heap_domain.output_domain(debug(), ns); diff --git a/src/domains/strategy_solver_heap.h b/src/domains/strategy_solver_heap.h index a2c0df33e..73f21f4af 100644 --- a/src/domains/strategy_solver_heap.h +++ b/src/domains/strategy_solver_heap.h @@ -1,23 +1,29 @@ -/** - * Strategy solver for heap verification. - * Viktor Malik, 12.8.2016 (c). - */ -#ifndef CPROVER_STRATEGY_SOLVER_HEAP_H -#define CPROVER_STRATEGY_SOLVER_HEAP_H +/*******************************************************************\ + +Module: Strategy solver for heap shape analysis + +Author: Viktor Malik + +\*******************************************************************/ +#ifndef CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_H +#define CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_H #include "../ssa/local_ssa.h" #include "strategy_solver_base.h" #include "heap_domain.h" #include "template_generator_base.h" -class strategy_solver_heapt : public strategy_solver_baset +class strategy_solver_heapt:public strategy_solver_baset { - public: - explicit strategy_solver_heapt(heap_domaint &_heap_domain, incremental_solvert &_solver, - const local_SSAt &SSA, const exprt &precondition, - message_handlert &message_handler, - template_generator_baset &template_generator) - : strategy_solver_baset(_solver, SSA.ns), heap_domain(_heap_domain) +public: + strategy_solver_heapt( + heap_domaint &_heap_domain, + incremental_solvert &_solver, + const local_SSAt &SSA, + const exprt &precondition, + message_handlert &message_handler, + template_generator_baset &template_generator): + strategy_solver_baset(_solver, SSA.ns), heap_domain(_heap_domain) { set_message_handler(message_handler); initialize(SSA, precondition, template_generator); @@ -25,21 +31,27 @@ class strategy_solver_heapt : public strategy_solver_baset virtual bool iterate(invariantt &_inv) override; - void initialize(const local_SSAt &SSA, const exprt &precondition, - template_generator_baset &template_generator); - - protected: + void initialize( + const local_SSAt &SSA, + const exprt &precondition, + template_generator_baset &template_generator); +protected: heap_domaint &heap_domain; std::set updated_rows; - int find_member_row(const exprt &obj, const irep_idt &member, int actual_loc, - const domaint::kindt &kind); + int find_member_row( + const exprt &obj, + const irep_idt &member, + int actual_loc, + const domaint::kindt &kind); - bool update_rows_rec(const heap_domaint::rowt &row, heap_domaint::heap_valuet &value); + bool update_rows_rec( + const heap_domaint::rowt &row, + heap_domaint::heap_valuet &value); void print_solver_expr(const exprt &expr); }; -#endif //CPROVER_STRATEGY_SOLVER_HEAP_H +#endif // CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_H diff --git a/src/domains/strategy_solver_heap_interval.cpp b/src/domains/strategy_solver_heap_interval.cpp index 4ce5a0a4a..ba0f61650 100644 --- a/src/domains/strategy_solver_heap_interval.cpp +++ b/src/domains/strategy_solver_heap_interval.cpp @@ -1,21 +1,53 @@ -/** - * Viktor Malik, 3/30/17 (c). - */ +/*******************************************************************\ + +Module: Strategy solver for combination of shape and interval domains. + +Author: Viktor Malik + +\*******************************************************************/ #include "strategy_solver_heap_interval.h" -bool strategy_solver_heap_intervalt::iterate(strategy_solver_baset::invariantt &_inv) +/*******************************************************************\ + +Function: strategy_solver_heap_intervalt::iterate + + Inputs: + + Outputs: + + Purpose: Since template rows for the shape part and the interval part + are disjoint, we simply call iterate method for each part + separately + +\*******************************************************************/ + +bool strategy_solver_heap_intervalt::iterate( + strategy_solver_baset::invariantt &_inv) { - heap_interval_domaint::heap_interval_valuet &inv = - static_cast(_inv); + heap_interval_domaint::heap_interval_valuet &inv= + static_cast(_inv); - bool heap_improved = heap_solver.iterate(inv.heap_value); - bool interval_improved = interval_solver.iterate(inv.interval_value); + bool heap_improved=heap_solver.iterate(inv.heap_value); + bool interval_improved=interval_solver.iterate(inv.interval_value); return heap_improved || interval_improved; } -void strategy_solver_heap_intervalt::set_message_handler(message_handlert &_message_handler) +/*******************************************************************\ + +Function: strategy_solver_heap_intervalt::set_message_handler + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void strategy_solver_heap_intervalt::set_message_handler( + message_handlert &_message_handler) { heap_solver.set_message_handler(_message_handler); interval_solver.set_message_handler(_message_handler); diff --git a/src/domains/strategy_solver_heap_interval.h b/src/domains/strategy_solver_heap_interval.h index 771ecb5ad..abedf3471 100644 --- a/src/domains/strategy_solver_heap_interval.h +++ b/src/domains/strategy_solver_heap_interval.h @@ -1,8 +1,13 @@ -/** - * Viktor Malik, 3/30/17 (c). - */ -#ifndef INC_2LS_STRATEGY_SOLVER_HEAP_INTERVALT_H -#define INC_2LS_STRATEGY_SOLVER_HEAP_INTERVALT_H +/*******************************************************************\ + +Module: Strategy solver for combination of shape and interval domains. + +Author: Viktor Malik + +\*******************************************************************/ + +#ifndef CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_INTERVAL_H +#define CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_INTERVAL_H #include "strategy_solver_base.h" @@ -10,24 +15,28 @@ #include "strategy_solver_heap.h" #include "strategy_solver_binsearch.h" -class strategy_solver_heap_intervalt : public strategy_solver_baset +class strategy_solver_heap_intervalt:public strategy_solver_baset { - public: - strategy_solver_heap_intervalt(heap_interval_domaint &_heap_interval_domain, - incremental_solvert &_solver, const local_SSAt &SSA, - const exprt &precondition, message_handlert &message_handler, - template_generator_baset &template_generator) - : strategy_solver_baset(_solver, SSA.ns), - heap_interval_domain(_heap_interval_domain), - heap_solver(heap_interval_domain.heap_domain, _solver, SSA, precondition, message_handler, - template_generator), - interval_solver(heap_interval_domain.interval_domain, _solver, SSA.ns) {} +public: + strategy_solver_heap_intervalt( + heap_interval_domaint &_heap_interval_domain, + incremental_solvert &_solver, + const local_SSAt &SSA, + const exprt &precondition, + message_handlert &message_handler, + template_generator_baset &template_generator): + strategy_solver_baset(_solver, SSA.ns), + heap_interval_domain(_heap_interval_domain), + heap_solver( + heap_interval_domain.heap_domain, _solver, SSA, precondition, + message_handler, template_generator), + interval_solver(heap_interval_domain.interval_domain, _solver, SSA.ns) {} virtual bool iterate(invariantt &_inv) override; virtual void set_message_handler(message_handlert &_message_handler) override; - protected: +protected: heap_interval_domaint &heap_interval_domain; strategy_solver_heapt heap_solver; @@ -35,4 +44,4 @@ class strategy_solver_heap_intervalt : public strategy_solver_baset }; -#endif //INC_2LS_STRATEGY_SOLVER_HEAP_INTERVALT_H +#endif // CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_INTERVAL_H diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index f07372a27..c5ece57e5 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -267,19 +267,30 @@ void template_generator_baset::filter_equality_domain() } } +/*******************************************************************\ + +Function: template_generator_baset::filter_heap_domain + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ void template_generator_baset::filter_heap_domain() { domaint::var_specst new_var_specs(var_specs); var_specs.clear(); - for(auto var=new_var_specs.begin(); var!=new_var_specs.end(); ++var) + for(auto &var : var_specs) { - if(var->var.id()==ID_symbol && var->var.type().id()==ID_pointer) + if(var.var.id()==ID_symbol && var.var.type().id()==ID_pointer) { // Filter out non-assigned OUT variables - if(var->kind!=domaint::OUT || - ssa_inlinert::get_original_identifier(to_symbol_expr(var->var))!= - to_symbol_expr(var->var).get_identifier()) - var_specs.push_back(*var); + if(var.kind!=domaint::OUT || + ssa_inlinert::get_original_identifier(to_symbol_expr(var.var))!= + to_symbol_expr(var.var).get_identifier()) + var_specs.push_back(var); } } } @@ -702,7 +713,7 @@ void template_generator_baset::instantiate_standard_domains( else if(options.get_bool_option("heap")) { filter_heap_domain(); - domain_ptr = new heap_domaint(domain_number, renaming_map, var_specs, SSA.ns); + domain_ptr=new heap_domaint(domain_number, renaming_map, var_specs, SSA.ns); } else if(options.get_bool_option("intervals")) { @@ -744,10 +755,11 @@ void template_generator_baset::instantiate_standard_domains( static_cast(domain_ptr)->add_quadratic_template( var_specs, SSA.ns); } - else if (options.get_bool_option("heap-interval")) + else if(options.get_bool_option("heap-interval")) { filter_heap_interval_domain(); - domain_ptr = new heap_interval_domaint(domain_number, renaming_map, var_specs, SSA.ns); + domain_ptr=new heap_interval_domaint( + domain_number, renaming_map, var_specs, SSA.ns); } } @@ -755,26 +767,27 @@ void template_generator_baset::filter_heap_interval_domain() { domaint::var_specst new_var_specs(var_specs); var_specs.clear(); - for(domaint::var_specst::const_iterator v = new_var_specs.begin(); + for(domaint::var_specst::const_iterator v=new_var_specs.begin(); v!=new_var_specs.end(); v++) { - const domaint::vart &s = v->var; + const domaint::vart &s=v->var; - if (s.type().id()==ID_unsignedbv || - s.type().id()==ID_signedbv || - s.type().id()==ID_floatbv) + if(s.type().id()==ID_unsignedbv || + s.type().id()==ID_signedbv || + s.type().id()==ID_floatbv) { var_specs.push_back(*v); continue; } - if (s.id() == ID_symbol && s.type().id() == ID_pointer && - id2string(to_symbol_expr(s).get_identifier()).find("__CPROVER") == std::string::npos) + if(s.id()==ID_symbol && s.type().id()==ID_pointer && + id2string(to_symbol_expr(s).get_identifier()).find("__CPROVER")== + std::string::npos) { // Filter out non-assigned OUT variables - if (v->kind != domaint::OUT || - ssa_inlinert::get_original_identifier(to_symbol_expr(s)) != - to_symbol_expr(s).get_identifier()) + if(v->kind!=domaint::OUT || + ssa_inlinert::get_original_identifier(to_symbol_expr(s))!= + to_symbol_expr(s).get_identifier()) { var_specs.push_back(*v); continue; diff --git a/src/domains/template_generator_base.h b/src/domains/template_generator_base.h index aec758b7c..a88dc2d03 100644 --- a/src/domains/template_generator_base.h +++ b/src/domains/template_generator_base.h @@ -73,8 +73,8 @@ class template_generator_baset:public messaget void filter_template_domain(); void filter_equality_domain(); - void filter_heap_domain(); - void filter_heap_interval_domain(); + void filter_heap_domain(); + void filter_heap_interval_domain(); void add_var( const domaint::vart &var_to_add, diff --git a/src/ssa/address_canonizer.cpp b/src/ssa/address_canonizer.cpp index 08a2a1781..d3581611f 100644 --- a/src/ssa/address_canonizer.cpp +++ b/src/ssa/address_canonizer.cpp @@ -76,12 +76,13 @@ exprt address_canonizer( return sum; } - else if (object.id() == ID_symbol && is_iterator(object)) + else if(object.id()==ID_symbol && is_iterator(object)) { - // address of iterator is dereferenced to a corresponding symbol - will be bound to real - // address during analysis - symbol_exprt iterator_addr(id2string(to_symbol_expr(object).get_identifier()) + "'addr", - address.type()); + // address of iterator is dereferenced to a corresponding symbol - + // will be bound to real address during analysis + symbol_exprt iterator_addr( + id2string(to_symbol_expr(object).get_identifier())+"'addr", + address.type()); return iterator_addr; } else diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index 6c3d2b9d6..b052f92ae 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -52,8 +52,10 @@ void assignmentst::build_assignment_map( to_code_function_call(it->code); // Get information from ssa_heap_analysis - auto n_it=it; ++n_it; - const irep_idt fname=to_symbol_expr(code_function_call.function()).get_identifier(); + auto n_it=it; + ++n_it; + const irep_idt fname=to_symbol_expr( + code_function_call.function()).get_identifier(); std::list new_objects; std::set modified_objects; @@ -70,32 +72,33 @@ void assignmentst::build_assignment_map( } for(objectst::const_iterator - o_it=ssa_objects.globals.begin(); + o_it=ssa_objects.globals.begin(); o_it!=ssa_objects.globals.end(); o_it++) { - if (id2string(o_it->get_identifier()) == id2string(fname) + "#return_value") + if(id2string(o_it->get_identifier())==id2string(fname)+"#return_value") assign(*o_it, it, ns); } // Assign all modified objects - for (auto &modified : modified_objects) + for(const exprt &modified : modified_objects) { - const exprt arg = ssa_heap_analysis[n_it].function_map.at(fname).corresponding_expr( - modified, code_function_call.arguments(), 0); + const exprt arg= + ssa_heap_analysis[n_it].function_map.at(fname). + corresponding_expr(modified, code_function_call.arguments(), 0); - if (arg != modified) + if(arg!=modified) { - const exprt arg_deref = dereference(arg, ssa_value_ai[it], "", ns); + const exprt arg_deref=dereference(arg, ssa_value_ai[it], "", ns); assign(arg_deref, it, ns); std::set symbols; find_symbols(arg_deref, symbols); - for (auto &symbol : symbols) + for(const symbol_exprt &symbol : symbols) { - if (symbol.type() == arg_deref.type()) + if(symbol.type()==arg_deref.type()) { - auto &aliases = ssa_value_ai[n_it](symbol, ns).value_set; - for (auto &alias : aliases) + auto &aliases=ssa_value_ai[n_it](symbol, ns).value_set; + for(auto &alias : aliases) { assign(alias.get_expr(), it, ns); } @@ -162,7 +165,8 @@ void assignmentst::assign( // object? ssa_objectt ssa_object(lhs, ns); - if(ssa_object && !ssa_object.is_unknown_obj()) // unknown objects are just placeholders + if(ssa_object && + !ssa_object.is_unknown_obj()) // unknown objects are just placeholders { assign(ssa_object, loc, ns); } diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 08cf19d48..0bcd8a7c7 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -18,12 +18,10 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include +#include #include -#include -#include - #include "local_ssa.h" #include "malloc_ssa.h" #include "ssa_dereference.h" @@ -98,18 +96,17 @@ void local_SSAt::get_entry_exit_vars() if(ns.lookup(identifier, symbol)) continue; - const symbol_exprt ¶m=symbol->symbol_expr(); - params.push_back(param); + 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 + // 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_globals(last, globals_out, true, true, last->function); } /*******************************************************************\ @@ -141,14 +138,15 @@ void local_SSAt::get_globals( << from_expr(ns, "", read_lhs(it->get_expr(), loc)) << std::endl; #endif - if(!with_returns && !is_pointed(it->get_expr()) && - id2string(it->get_identifier()).find("#return_value") != std::string::npos) + if(!with_returns && + id2string(it->get_identifier()).find( + "#return_value")!=std::string::npos) continue; - //filter out return values of other functions + // filter out return values of other functions if(with_returns && returns_for_function!="" && - id2string(it->get_identifier()).find("#return_value")== - id2string(it->get_identifier()).size()-std::string("#return_value").size() && + id2string(it->get_identifier()).find( + "#return_value")!=std::string::npos && id2string(it->get_identifier()).find( id2string(returns_for_function)+"#return_value")==std::string::npos) continue; @@ -158,8 +156,7 @@ void local_SSAt::get_globals( { const symbolt *symbol; irep_idt ptr_obj_id=root_obj.get(ID_ptr_object); - if(ns.lookup(ptr_obj_id, symbol)) - continue; + if(ns.lookup(ptr_obj_id, symbol)) continue; } if(rhs_value) @@ -541,30 +538,27 @@ void local_SSAt::build_function_call(locationt loc) return; } - assert(f.function().id()==ID_symbol); //no function pointers + assert(f.function().id()==ID_symbol); // no function pointers f=to_function_application_expr(read_rhs(f, loc)); irep_idt fname=to_symbol_expr(f.function()).get_identifier(); - //add equalities for arguments + // add equalities for arguments unsigned i=0; - for(auto &a : f.arguments()) + for(exprt &a : f.arguments()) { if(a.is_constant() || (a.id()==ID_typecast && to_typecast_expr(a).op().is_constant())) { - symbol_exprt arg( - id2string(fname)+"#arg"+i2string(i)+ - "#"+i2string(loc->location_number), - a.type()); + symbol_exprt arg(id2string(fname)+"#arg"+i2string(i)+ + "#"+i2string(loc->location_number), a.type()); n_it->equalities.push_back(equal_exprt(a, arg)); a=arg; } ++i; } - n_it->function_calls.push_back( - to_function_application_expr(f)); + n_it->function_calls.push_back(to_function_application_expr(f)); } } @@ -692,7 +686,7 @@ void local_SSAt::build_assertions(locationt loc) { if(loc->is_assert()) { - const exprt deref_rhs = dereference(loc->guard, loc); + const exprt deref_rhs=dereference(loc->guard, loc); collect_iterators_rhs(deref_rhs, loc); exprt c=read_rhs(loc->guard, loc); @@ -1062,32 +1056,6 @@ exprt local_SSAt::read_rhs_rec(const exprt &expr, locationt loc) const return tmp; } - // Argument is a struct-typed ssa object? - // May need to split up into members. - const typet &type=ns.follow(expr.type()); - - if(type.id()==ID_struct) - { - // build struct constructor - struct_exprt result(expr.type()); - - const struct_typet &struct_type=to_struct_type(type); - const struct_typet::componentst &components=struct_type.components(); - - result.operands().resize(components.size()); - - for(struct_typet::componentst::const_iterator - it=components.begin(); - it!=components.end(); - it++) - { - result.operands()[it-components.begin()]= - read_rhs(member_exprt(expr, it->get_name(), it->type()), loc); - } - - return result; - } - // is this an object we track? if(ssa_objects.objects.find(object)!= ssa_objects.objects.end()) @@ -1376,14 +1344,12 @@ void local_SSAt::assign_rec( { const if_exprt &if_expr=to_if_expr(lhs); - exprt new_rhs = if_exprt(if_expr.cond(), rhs, if_expr.true_case()); - assign_rec(if_expr.true_case(), new_rhs, and_exprt(guard, if_expr.cond()), loc); + exprt new_rhs=if_exprt(if_expr.cond(), rhs, if_expr.true_case()); + assign_rec(if_expr.true_case(), new_rhs, and_exprt(guard, if_expr.cond()), + loc); - assign_rec( - if_expr.false_case(), - rhs, - and_exprt(guard, not_exprt(if_expr.cond())), - loc); + assign_rec(if_expr.false_case(), rhs, + and_exprt(guard, not_exprt(if_expr.cond())), loc); } else if(lhs.id()==ID_byte_extract_little_endian || lhs.id()==ID_byte_extract_big_endian) @@ -1614,20 +1580,7 @@ std::list &operator<<( { dest.push_back(*c_it); } - } - -// for (auto &obj : src.unknown_objs) -// { -// const typet &obj_type = src.ns.follow(obj.type()); -// if (obj_type.id() == ID_struct) -// { -// for (auto &component : to_struct_type(obj_type).components()) -// { -// dest.push_back(src.unknown_obj_eq(obj, component)); -// } -// } -// } #endif return dest; @@ -1814,27 +1767,37 @@ bool local_SSAt::has_function_calls() const return found; } -/** - * If a location is malloc call, create "unknown object" for return type. This is later used - * as a placeholder for invalid of unknown dereference of an object of that type. - * @param loc Location - */ +/*******************************************************************\ + +Function: local_SSAt::build_unknown_objs + + Inputs: + + Outputs: + + Purpose: If a location is malloc call, create "unknown object" for + return type. This is later used as a placeholder for invalid + of unknown dereference of an object of that type. + +\*******************************************************************/ + void local_SSAt::build_unknown_objs(locationt loc) { - if (loc->is_assign()) + if(loc->is_assign()) { - const code_assignt &code_assign = to_code_assign(loc->code); - const exprt &rhs = code_assign.rhs(); - if (rhs.get_bool("#malloc_result")) + const code_assignt &code_assign=to_code_assign(loc->code); + const exprt &rhs=code_assign.rhs(); + if(rhs.get_bool("#malloc_result")) { - const exprt &addr_of_do = rhs.id() == ID_typecast ? to_typecast_expr(rhs).op() : rhs; - const exprt &dyn_obj = to_address_of_expr(addr_of_do).object(); - const typet &dyn_type = ns.follow(dyn_obj.type()); + const exprt &addr_of_do= + rhs.id()==ID_typecast ? to_typecast_expr(rhs).op() : rhs; + const exprt &dyn_obj=to_address_of_expr(addr_of_do).object(); + const typet &dyn_type=ns.follow(dyn_obj.type()); - std::string dyn_type_name = dyn_type.id_string(); - if (dyn_type.id() == ID_struct) - dyn_type_name += "_" + id2string(to_struct_type(dyn_type).get_tag()); - irep_idt identifier = "ssa::" + dyn_type_name + "_obj$unknown"; + std::string dyn_type_name=dyn_type.id_string(); + if(dyn_type.id()==ID_struct) + dyn_type_name+="_"+id2string(to_struct_type(dyn_type).get_tag()); + irep_idt identifier="ssa::"+dyn_type_name+"_obj$unknown"; symbol_exprt unknown_obj(identifier, dyn_obj.type()); unknown_objs.insert(unknown_obj); @@ -1842,27 +1805,48 @@ void local_SSAt::build_unknown_objs(locationt loc) } } -/** - * Create equality obj.component = &obj, which creates self-loop on "unknown" objects. - * @param obj "Unknown" object - * @param component Object's component - * @return Equality obj.component = &obj - */ -exprt local_SSAt::unknown_obj_eq(const symbol_exprt &obj, - const struct_typet::componentt &component) const +/*******************************************************************\ + +Function: local_SSAt::unknown_obj_eq + + Inputs: + + Outputs: + + Purpose: Create equality obj.component = &obj, which creates self-loop + on "unknown" objects. + +\*******************************************************************/ + +exprt local_SSAt::unknown_obj_eq( + const symbol_exprt &obj, + const struct_typet::componentt &component) const { - const irep_idt identifier = - id2string(obj.get_identifier()) + "." + id2string(component.get_name()); + const irep_idt identifier= + id2string(obj.get_identifier())+"."+id2string(component.get_name()); const symbol_exprt member(identifier, component.type()); return equal_exprt(member, address_of_exprt(obj)); } +/*******************************************************************\ + +Function: local_SSAt::collect_iterators_rhs + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + void local_SSAt::collect_iterators_rhs(const exprt &expr, locationt loc) { - if (expr.id() == ID_member) + if(expr.id()==ID_member) { - const member_exprt &member = to_member_expr(expr); - if (member.compound().get_bool(ID_iterator) && member.compound().id() == ID_symbol) + const member_exprt &member=to_member_expr(expr); + if(member.compound().get_bool(ID_iterator) && + member.compound().id()==ID_symbol) { new_iterator_access(to_member_expr(expr), loc, list_iteratort::IN_LOC); } @@ -1870,36 +1854,65 @@ void local_SSAt::collect_iterators_rhs(const exprt &expr, locationt loc) else { forall_operands(it, expr) - collect_iterators_rhs(*it, loc); + collect_iterators_rhs(*it, loc); } } +/*******************************************************************\ + +Function: local_SSAt::collect_iterators_lhs + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + void local_SSAt::collect_iterators_lhs(const ssa_objectt &object, local_SSAt::locationt loc) { - if (is_iterator(object.get_root_object()) && object.get_root_object().id() == ID_symbol) + if(is_iterator(object.get_root_object()) && + object.get_root_object().id()==ID_symbol) { - assert(object.get_expr().id() == ID_member); - new_iterator_access(to_member_expr(object.get_expr()), loc, loc->location_number); + assert(object.get_expr().id()==ID_member); + new_iterator_access(to_member_expr(object.get_expr()), loc, + loc->location_number); } } -void local_SSAt::new_iterator_access(const member_exprt &expr, local_SSAt::locationt loc, - int inst_loc_number) +/*******************************************************************\ + +Function: local_SSAt::new_iterator_access + + Inputs: + + Outputs: + + Purpose: Create new iterator access + +\*******************************************************************/ + +void local_SSAt::new_iterator_access( + const member_exprt &expr, + local_SSAt::locationt loc, + int inst_loc_number) { assert(is_iterator(expr.compound())); - const irep_idt pointer_id = expr.compound().get(ID_it_pointer); - const symbolt &pointer_symbol = ns.lookup(pointer_id); - exprt pointer_rhs = read_rhs(pointer_symbol.symbol_expr(), loc); - assert(pointer_rhs.id() == ID_symbol); + const irep_idt pointer_id=expr.compound().get(ID_it_pointer); + const symbolt &pointer_symbol=ns.lookup(pointer_id); + exprt pointer_rhs=read_rhs(pointer_symbol.symbol_expr(), loc); + assert(pointer_rhs.id()==ID_symbol); - unsigned init_value_level = expr.compound().get_unsigned_int(ID_it_init_value_level); - const exprt init_pointer = get_pointer(expr.compound(), init_value_level - 1); + unsigned init_value_level=expr.compound().get_unsigned_int( + ID_it_init_value_level); + const exprt init_pointer=get_pointer(expr.compound(), init_value_level-1); list_iteratort iterator(to_symbol_expr(pointer_rhs), init_pointer, get_iterator_fields(expr.compound())); - auto it = iterators.insert(iterator); + auto it=iterators.insert(iterator); it.first->add_access(expr, inst_loc_number); } diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 2c54b3c0f..4ff55c988 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -36,12 +36,13 @@ class local_SSAt const goto_functiont &_goto_function, const namespacet &_ns, const ssa_heap_analysist &_heap_analysis, - const std::string &_suffix = "") : + const std::string &_suffix=""): ns(_ns), goto_function(_goto_function), heap_analysis(_heap_analysis), ssa_objects(_goto_function, ns, _heap_analysis), ssa_value_ai(_goto_function, ns, _heap_analysis), - assignments(_goto_function.body, ns, ssa_objects, ssa_value_ai, heap_analysis), + assignments( + _goto_function.body, ns, ssa_objects, ssa_value_ai, heap_analysis), guard_map(_goto_function.body), ssa_analysis(assignments), suffix(_suffix) @@ -62,14 +63,13 @@ class local_SSAt public: inline nodet( locationt _location, - std::list::iterator _loophead) - : - enabling_expr(true_exprt()), - marked(false), - location(_location), - loophead(_loophead) - { - } + std::list::iterator _loophead): + enabling_expr(true_exprt()), + marked(false), + location(_location), + loophead(_loophead) + { + } typedef std::vector equalitiest; equalitiest equalities; @@ -113,12 +113,14 @@ class local_SSAt void mark_nodes() { for(nodest::iterator n_it=nodes.begin(); - n_it!=nodes.end(); n_it++) n_it->marked=true; + n_it!=nodes.end(); n_it++) + n_it->marked=true; } void unmark_nodes() { - for(nodest::iterator n_it=nodes.begin(); - n_it!=nodes.end(); n_it++) n_it->marked=false; + for(nodest::iterator n_it=nodes.begin(); + n_it!=nodes.end(); n_it++) + n_it->marked=false; } // for incremental unwinding @@ -128,7 +130,7 @@ class local_SSAt // function entry and exit variables typedef std::list var_listt; typedef std::set var_sett; - var_listt params; + var_listt params; var_sett globals_in, globals_out; std::set iterators; @@ -174,9 +176,14 @@ class local_SSAt void collect_iterators_rhs(const exprt &expr, locationt loc); void collect_iterators_lhs(const ssa_objectt &object, locationt loc); - void new_iterator_access(const member_exprt &expr, locationt loc, int inst_loc_number); + void new_iterator_access( + const member_exprt &expr, + locationt loc, + int inst_loc_number); - exprt unknown_obj_eq(const symbol_exprt &obj, const struct_typet::componentt &component) const; + exprt unknown_obj_eq( + const symbol_exprt &obj, + const struct_typet::componentt &component) const; void get_entry_exit_vars(); diff --git a/src/ssa/malloc_ssa.cpp b/src/ssa/malloc_ssa.cpp index 2c11f358f..28dce7ebe 100644 --- a/src/ssa/malloc_ssa.cpp +++ b/src/ssa/malloc_ssa.cpp @@ -195,12 +195,17 @@ static void replace_malloc_rec( { assert(!malloc_size.is_nil()); expr.op0()=malloc_size; - - expr=malloc_ssa(to_side_effect_expr(expr),"$"+std::to_string(loc_number)+suffix,symbol_table); + + expr=malloc_ssa( + to_side_effect_expr(expr), + "$"+i2string(loc_number)+suffix, + symbol_table); } else - Forall_operands(it,expr) - replace_malloc_rec(*it,suffix,symbol_table,malloc_size,loc_number); + { + Forall_operands(it, expr) + replace_malloc_rec(*it, suffix, symbol_table, malloc_size, loc_number); + } } /*******************************************************************\ diff --git a/src/ssa/ssa_heap_domain.cpp b/src/ssa/ssa_heap_domain.cpp index d5c7a8fdb..7ede3fb47 100644 --- a/src/ssa/ssa_heap_domain.cpp +++ b/src/ssa/ssa_heap_domain.cpp @@ -1,212 +1,283 @@ -/** - * Viktor Malik, 2/28/17 (c). - */ +/*******************************************************************\ + +Module: Dynamic objects analysis + +Author: Viktor Malik + +\*******************************************************************/ #include #include "ssa_heap_domain.h" -void ssa_heap_domaint::transform(const namespacet &ns, domain_baset::locationt from, - domain_baset::locationt to) +/*******************************************************************\ + +Function: ssa_heap_domaint::transform + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void ssa_heap_domaint::transform( + const namespacet &ns, domain_baset::locationt from, + domain_baset::locationt to) { - if (from->is_assign()) + if(from->is_assign()) { - const code_assignt &assign = to_code_assign(from->code); + const code_assignt &assign=to_code_assign(from->code); assign_lhs_rec(assign.lhs(), assign.rhs(), ns); } - else if (from->is_function_call() && from->function == to->function) + else if(from->is_function_call() && from->function==to->function) { - const code_function_callt &fun_call = to_code_function_call(from->code); - assert(fun_call.function().id() == ID_symbol); - const irep_idt &fun_id = to_symbol_expr(fun_call.function()).get_identifier(); + const code_function_callt &fun_call=to_code_function_call(from->code); + assert(fun_call.function().id()==ID_symbol); + const irep_idt &fun_id=to_symbol_expr(fun_call.function()).get_identifier(); - if (function_map.find(fun_id) != function_map.end()) + if(function_map.find(fun_id)!=function_map.end()) { - unsigned counter = 0; - for (auto &obj : function_map.at(fun_id).new_objects) + unsigned counter=0; + for(auto &obj : function_map.at(fun_id).new_objects) { - symbol_exprt new_obj = obj.first; + symbol_exprt new_obj=obj.first; rename_to_caller(new_obj, from, counter); const symbolt *symbol; - if (!ns.lookup(new_obj.get_identifier(), symbol)) - new_obj = symbol->symbol_expr(); + if(!ns.lookup(new_obj.get_identifier(), symbol)) + new_obj=symbol->symbol_expr(); - if (function_map[function].new_objects.find(new_obj) == - function_map[function].new_objects.end()) + if(function_map[function].new_objects.find(new_obj)== + function_map[function].new_objects.end()) { - function_map[function].new_objects.insert(std::make_pair(new_obj, std::set())); + function_map[function].new_objects.insert( + std::make_pair(new_obj, std::set())); } - for (auto &expr : obj.second) + for(auto &expr : obj.second) { - const exprt pointer = function_map.at(fun_id).corresponding_expr(expr, - fun_call.arguments(), 0); + const exprt pointer=function_map.at(fun_id).corresponding_expr( + expr, fun_call.arguments(), 0); - objectst old_objects = value_map[pointer]; - value_map[pointer] = {new_obj}; + objectst old_objects=value_map[pointer]; + value_map[pointer]={new_obj}; - if (is_function_output(pointer, function, ns, false)) + if(is_function_output(pointer, function, ns, false)) { function_map[function].new_objects.at(new_obj).insert(pointer); } - for (auto &o : old_objects) + for(auto &o : old_objects) { - if (o.id() == ID_symbol && o.type().get_bool("#dynamic") && - new_obj != o) - function_map[function].new_objects.at(to_symbol_expr(o)).erase(pointer); + if(o.id()==ID_symbol && o.type().get_bool("#dynamic") && + new_obj!=o) + function_map[function].new_objects.at(to_symbol_expr(o)).erase( + pointer); } } } - for (auto &obj : function_map.at(fun_id).modified_objects) + for(auto &obj : function_map.at(fun_id).modified_objects) { - const exprt caller_obj = function_map.at(fun_id).corresponding_expr(obj, - fun_call.arguments(), - 0); - if (is_function_output(caller_obj, function, ns, false)) + const exprt caller_obj=function_map.at(fun_id).corresponding_expr( + obj, fun_call.arguments(), 0); + if(is_function_output(caller_obj, function, ns, false)) function_map[function].modified_objects.insert(caller_obj); } } } } -bool ssa_heap_domaint::merge(const ssa_heap_domaint &other, domain_baset::locationt to) +/*******************************************************************\ + +Function: ssa_heap_domaint::merge + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool ssa_heap_domaint::merge( + const ssa_heap_domaint &other, + domain_baset::locationt to) { - bool result = false; + bool result=false; - if (to->function == "" || to->function == other.function) + if(to->function=="" || to->function==other.function) { - function = other.function; + function=other.function; // Merge value maps - union - for (auto &other_value : other.value_map) + for(auto &other_value : other.value_map) { - if (value_map.find(other_value.first) == value_map.end()) + if(value_map.find(other_value.first)==value_map.end()) { - value_map[other_value.first] = other_value.second; - result = true; + value_map[other_value.first]=other_value.second; + result=true; } else { - unsigned long old_size = value_map[other_value.first].size(); - value_map[other_value.first].insert(other_value.second.begin(), other_value.second.end()); - result = old_size != value_map[other_value.first].size(); + unsigned long old_size=value_map[other_value.first].size(); + value_map[other_value.first].insert(other_value.second.begin(), + other_value.second.end()); + result=old_size!=value_map[other_value.first].size(); } } } else { - function = to->function; + function=to->function; } - for (auto &f : other.function_map) + for(auto &f : other.function_map) { - auto &objects = function_map[f.first].new_objects; - const auto &other_objects = f.second.new_objects; + auto &objects=function_map[f.first].new_objects; + const auto &other_objects=f.second.new_objects; - if (f.first == function && function == other.function) + if(f.first==function && function==other.function) { - for (auto &other_object : other_objects) + for(auto &other_object : other_objects) { - if (objects.find(other_object.first) == objects.end()) + if(objects.find(other_object.first)==objects.end()) { - objects[other_object.first] = other_object.second; - result = true; + objects[other_object.first]=other_object.second; + result=true; } - else if (!other_object.second.empty()) + else if(!other_object.second.empty()) { - unsigned long old_size = objects[other_object.first].size(); + unsigned long old_size=objects[other_object.first].size(); std::set intersection; std::set_intersection(objects[other_object.first].begin(), objects[other_object.first].end(), other_object.second.begin(), other_object.second.end(), - std::inserter(intersection, intersection.begin())); - if (!intersection.empty()) - objects[other_object.first] = intersection; + std::inserter( + intersection, intersection.begin())); + if(!intersection.empty()) + objects[other_object.first]=intersection; else objects.erase(other_object.first); - if (old_size != objects[other_object.first].size()) - result = true; + if(old_size!=objects[other_object.first].size()) + result=true; } } } else { - for (auto &o : other_objects) + for(auto &o : other_objects) { - unsigned long old_size = objects[o.first].size(); - objects[o.first] = o.second; - if (old_size != objects[o.first].size()) - result = true; + unsigned long old_size=objects[o.first].size(); + objects[o.first]=o.second; + if(old_size!=objects[o.first].size()) + result=true; } } - function_map[f.first].params = f.second.params; + function_map[f.first].params=f.second.params; - unsigned long old_size = function_map[f.first].modified_objects.size(); - function_map[f.first].modified_objects.insert(f.second.modified_objects.begin(), - f.second.modified_objects.end()); - if (old_size != function_map[f.first].modified_objects.size()) - result = true; + unsigned long old_size=function_map[f.first].modified_objects.size(); + function_map[f.first].modified_objects.insert( + f.second.modified_objects.begin(), + f.second.modified_objects.end()); + if(old_size!=function_map[f.first].modified_objects.size()) + result=true; } return result; } -void ssa_heap_domaint::assign_rhs(const exprt &rhs, const irep_idt &function, objectst &objects, - const namespacet &ns) +/*******************************************************************\ + +Function: ssa_heap_domaint::assign_rhs + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void ssa_heap_domaint::assign_rhs( + const exprt &rhs, + const irep_idt &function, + objectst &objects, + const namespacet &ns) { - if (rhs.get_bool("#malloc_result")) + if(rhs.get_bool("#malloc_result")) { - exprt malloc_result = rhs; - if (malloc_result.id() == ID_typecast) - malloc_result = to_typecast_expr(malloc_result).op(); - assert(malloc_result.id() == ID_address_of); + exprt malloc_result=rhs; + if(malloc_result.id()==ID_typecast) + malloc_result=to_typecast_expr(malloc_result).op(); + assert(malloc_result.id()==ID_address_of); - const symbol_exprt new_object = to_symbol_expr(to_address_of_expr(malloc_result).object()); + const symbol_exprt new_object=to_symbol_expr( + to_address_of_expr(malloc_result).object()); - function_infot &function_info = function_map[function]; - if (function_info.new_objects.find(new_object) == function_info.new_objects.end()) + function_infot &function_info=function_map[function]; + if(function_info.new_objects.find(new_object)== + function_info.new_objects.end()) { - function_info.new_objects.insert(std::make_pair(new_object, std::set())); + function_info.new_objects.insert( + std::make_pair(new_object, std::set())); } - objects = {new_object}; + objects={new_object}; } - else if (rhs.id() == ID_typecast) + else if(rhs.id()==ID_typecast) { assign_rhs(to_typecast_expr(rhs).op(), function, objects, ns); } else { - auto values = value_map.find(rhs); - if (values != value_map.end()) + auto values=value_map.find(rhs); + if(values!=value_map.end()) { - objects = values->second; + objects=values->second; } } } -bool ssa_heap_domaint::is_function_output(const exprt &expr, const irep_idt &function, - const namespacet &ns, bool in_deref) +/*******************************************************************\ + +Function: ssa_heap_domaint::is_function_output + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool ssa_heap_domaint::is_function_output( + const exprt &expr, + const irep_idt &function, + const namespacet &ns, + bool in_deref) { - if (expr.id() == ID_dereference) + if(expr.id()==ID_dereference) { - return is_function_output(to_dereference_expr(expr).pointer(), function, ns, true); + return is_function_output(to_dereference_expr(expr).pointer(), function, ns, + true); } - else if (expr.id() == ID_member) + else if(expr.id()==ID_member) { - return is_function_output(to_member_expr(expr).compound(), function, ns, in_deref); + return is_function_output(to_member_expr(expr).compound(), function, ns, + in_deref); } - else if (expr.id() == ID_symbol) + else if(expr.id()==ID_symbol) { - const symbol_exprt &symbol_expr = to_symbol_expr(expr); - if (id2string(symbol_expr.get_identifier()).find("#return_value") != std::string::npos) + const symbol_exprt &symbol_expr=to_symbol_expr(expr); + if(id2string(symbol_expr.get_identifier()).find("#return_value")!= + std::string::npos) { - return symbol_expr.get_identifier() == id2string(function) + "#return_value"; + return symbol_expr.get_identifier()==id2string(function)+"#return_value"; } const symbolt *symbol; @@ -217,84 +288,175 @@ bool ssa_heap_domaint::is_function_output(const exprt &expr, const irep_idt &fun return false; } +/*******************************************************************\ + +Function: ssa_heap_domaint::value + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + const std::set ssa_heap_domaint::value(const exprt &expr) const { std::set result; - if (value_map.find(expr) != value_map.end()) + if(value_map.find(expr)!=value_map.end()) { - for (auto &value : value_map.at(expr)) + for(auto &value : value_map.at(expr)) { - if (value.id() == ID_symbol) + if(value.id()==ID_symbol) result.insert(to_symbol_expr(value)); } } return result; } +/*******************************************************************\ + +Function: ssa_heap_domaint::new_objects + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + const std::list ssa_heap_domaint::new_objects() const { return new_objects(function); } -const std::list ssa_heap_domaint::new_objects(const irep_idt &fname) const +/*******************************************************************\ + +Function: ssa_heap_domaint::new_objects + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +const std::list ssa_heap_domaint::new_objects( + const irep_idt &fname) const { std::list result; - if (function_map.find(fname) != function_map.end()) + if(function_map.find(fname)!=function_map.end()) { - for (auto &obj : function_map.at(fname).new_objects) + for(auto &obj : function_map.at(fname).new_objects) result.push_back(obj.first); } return result; } -void ssa_heap_domaint::rename_to_caller(symbol_exprt &object, domain_baset::locationt loc, - unsigned &index) const +/*******************************************************************\ + +Function: ssa_heap_domaint::rename_to_caller + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ +void ssa_heap_domaint::rename_to_caller( + symbol_exprt &object, domain_baset::locationt loc, + unsigned &index) const { - object.set_identifier("ssa::dynamic_object$" + std::to_string(loc->location_number) + "$" + - std::to_string(index++)); + object.set_identifier( + "ssa::dynamic_object$"+std::to_string(loc->location_number)+"$"+ + std::to_string(index++)); } -const std::list ssa_heap_domaint::new_caller_objects(const irep_idt &fname, - domain_baset::locationt loc) const +/*******************************************************************\ + +Function: ssa_heap_domaint::new_caller_objects + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +const std::list ssa_heap_domaint::new_caller_objects( + const irep_idt &fname, + domain_baset::locationt loc) const { - std::list result = new_objects(fname); - unsigned counter = 0; - for (symbol_exprt &o : result) + std::list result=new_objects(fname); + unsigned counter=0; + for(symbol_exprt &o : result) { rename_to_caller(o, loc, counter); } return result; } -const std::set ssa_heap_domaint::modified_objects(const irep_idt &fname) const +/*******************************************************************\ + +Function: ssa_heap_domaint::modified_objects + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +const std::set ssa_heap_domaint::modified_objects( + const irep_idt &fname) const { std::set result; - if (function_map.find(fname) != function_map.end()) + if(function_map.find(fname)!=function_map.end()) { - result = function_map.at(fname).modified_objects; + result=function_map.at(fname).modified_objects; } return result; } -void ssa_heap_domaint::assign_lhs_rec(const exprt &lhs, const exprt &rhs, const namespacet &ns) +/*******************************************************************\ + +Function: ssa_heap_domaint::assign_lhs_rec + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void ssa_heap_domaint::assign_lhs_rec( + const exprt &lhs, + const exprt &rhs, + const namespacet &ns) { objectst rhs_objects; assign_rhs(rhs, function, rhs_objects, ns); - if (!rhs_objects.empty()) - value_map[lhs] = rhs_objects; + if(!rhs_objects.empty()) + value_map[lhs]=rhs_objects; else value_map.erase(lhs); - if (is_function_output(lhs, function, ns, false)) + if(is_function_output(lhs, function, ns, false)) { - auto &objects = function_map[function].new_objects; - for (auto &o : rhs_objects) + auto &objects=function_map[function].new_objects; + for(const exprt &o : rhs_objects) { - if (o.id() == ID_symbol && o.type().get_bool("#dynamic")) + if(o.id()==ID_symbol && o.type().get_bool("#dynamic")) { - const symbol_exprt new_o = to_symbol_expr(o); - if (objects.find(new_o) != objects.end()) + const symbol_exprt new_o=to_symbol_expr(o); + if(objects.find(new_o)!=objects.end()) { objects[new_o].insert(lhs); } @@ -305,45 +467,70 @@ void ssa_heap_domaint::assign_lhs_rec(const exprt &lhs, const exprt &rhs, const update_modified(lhs, ns); } +/*******************************************************************\ + +Function: ssa_heap_domaint::update_modified + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + void ssa_heap_domaint::update_modified(const exprt &expr, const namespacet &ns) { - if (expr.id() == ID_member) + if(expr.id()==ID_member) { update_modified(to_member_expr(expr).compound(), ns); } - else if (expr.id() == ID_dereference) + else if(expr.id()==ID_dereference) { - for (const exprt &v : value_map[to_dereference_expr(expr).pointer()]) + for(const exprt &v : value_map[to_dereference_expr(expr).pointer()]) { - if (is_function_output(v, function, ns, false)) + if(is_function_output(v, function, ns, false)) function_map[function].modified_objects.insert(v); } } - else - if (is_function_output(expr, function, ns, false)) - function_map[function].modified_objects.insert(expr); + else if(is_function_output(expr, function, ns, false)) + function_map[function].modified_objects.insert(expr); } +/*******************************************************************\ + +Function: ssa_heap_analysist::initialize + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + void ssa_heap_analysist::initialize(const goto_functionst &goto_functions) { static_analysis_baset::initialize(goto_functions); - if (goto_functions.function_map.at("main").body_available()) + if(goto_functions.function_map.at("main").body_available()) { - locationt e = goto_functions.function_map.at("main").body.instructions.begin(); - ssa_heap_domaint &entry = operator[](e); + locationt e=goto_functions.function_map.at( + "main").body.instructions.begin(); + ssa_heap_domaint &entry=operator[](e); - entry.function = e->function; + entry.function=e->function; forall_goto_functions(f_it, goto_functions) { - if (f_it->second.body_available()) + if(f_it->second.body_available()) { - locationt f_e = f_it->second.body.instructions.begin(); - ssa_heap_domaint &f_entry = operator[](f_e); - for (auto ¶m : f_it->second.type.parameters()) + locationt f_e=f_it->second.body.instructions.begin(); + ssa_heap_domaint &f_entry=operator[](f_e); + for(auto ¶m : f_it->second.type.parameters()) { - entry.function_map[f_it->first].params.push_back(param.get_identifier()); + entry.function_map[f_it->first].params.push_back( + param.get_identifier()); const symbol_exprt param_expr(param.get_identifier(), param.type()); init_ptr_param(param_expr, f_entry); } @@ -352,21 +539,36 @@ void ssa_heap_analysist::initialize(const goto_functionst &goto_functions) } } -void ssa_heap_analysist::init_ptr_param(const exprt &expr, ssa_heap_domaint &f_entry) +/*******************************************************************\ + +Function: ssa_heap_analysist::init_ptr_param + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void ssa_heap_analysist::init_ptr_param( + const exprt &expr, + ssa_heap_domaint &f_entry) { - const typet &type = ns.follow(expr.type()); - if (type.id() == ID_pointer) + const typet &type=ns.follow(expr.type()); + if(type.id()==ID_pointer) { const dereference_exprt dereference(expr, type.subtype()); f_entry.value_map[expr].insert(dereference); init_ptr_param(dereference, f_entry); } - else if (type.id() == ID_struct) + else if(type.id()==ID_struct) { - assert(expr.id() == ID_dereference); - for (auto &component : to_struct_type(type).components()) + assert(expr.id()==ID_dereference); + for(auto &component : to_struct_type(type).components()) { - if (component.type().id() == ID_pointer && ns.follow(component.type().subtype()) == type) + if(component.type().id()==ID_pointer && + ns.follow(component.type().subtype())==type) { const member_exprt member(expr, component.get_name(), component.type()); f_entry.value_map[member].insert(expr); @@ -375,56 +577,86 @@ void ssa_heap_analysist::init_ptr_param(const exprt &expr, ssa_heap_domaint &f_e } } -const exprt ssa_heap_domaint::function_infot::corresponding_expr(const exprt &expr, - const code_function_callt::argumentst &arguments, - unsigned deref_level) const +/*******************************************************************\ + +Function: ssa_heap_domaint::function_infot::corresponding_expr + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +const exprt ssa_heap_domaint::function_infot::corresponding_expr( + const exprt &expr, + const code_function_callt::argumentst &arguments, + unsigned deref_level) const { - if (expr.id() == ID_symbol) + if(expr.id()==ID_symbol) { - const irep_idt expr_id = to_symbol_expr(expr).get_identifier(); - exprt result = expr; - for (unsigned i = 0; i < params.size(); ++i) + const irep_idt expr_id=to_symbol_expr(expr).get_identifier(); + exprt result=expr; + for(unsigned i=0; i -class ssa_heap_domaint : public domain_baset +class ssa_heap_domaint:public domain_baset { - public: - virtual void transform(const namespacet &ns, locationt from, locationt to) override; +public: + virtual void transform( + const namespacet &ns, + locationt from, + locationt to) override; bool merge(const ssa_heap_domaint &, locationt); irep_idt function; @@ -23,17 +31,17 @@ class ssa_heap_domaint : public domain_baset class function_infot { - public: + public: std::map > new_objects; std::set modified_objects; std::vector params; - const exprt corresponding_expr(const exprt &expr, - const code_function_callt::argumentst &arguments, - unsigned deref_level) const; - + const exprt corresponding_expr( + const exprt &expr, + const code_function_callt::argumentst &arguments, + unsigned deref_level) const; - protected: + protected: const exprt apply_deref(const exprt &expr, unsigned level) const; }; @@ -41,35 +49,44 @@ class ssa_heap_domaint : public domain_baset const std::list new_objects() const; const std::list new_objects(const irep_idt &fname) const; - const std::list new_caller_objects(const irep_idt &fname, locationt loc) const; + const std::list + new_caller_objects(const irep_idt &fname, locationt loc) const; const std::set modified_objects(const irep_idt &fname) const; - protected: - +protected: void assign_lhs_rec(const exprt &lhs, const exprt &rhs, const namespacet &ns); - void assign_rhs(const exprt &rhs, const irep_idt &function, objectst &objects, - const namespacet &ns); + void assign_rhs( + const exprt &rhs, + const irep_idt &function, + objectst &objects, + const namespacet &ns); - bool is_function_output(const exprt &expr, const irep_idt &function, - const namespacet &ns, bool in_deref); + bool is_function_output( + const exprt &expr, + const irep_idt &function, + const namespacet &ns, + bool in_deref); - void rename_to_caller(symbol_exprt &object, locationt loc, unsigned &index) const; + void rename_to_caller( + symbol_exprt &object, + locationt loc, + unsigned &index) const; void update_modified(const exprt &expr, const namespacet &ns); }; -class ssa_heap_analysist : public static_analysist +class ssa_heap_analysist:public static_analysist { - public: - explicit ssa_heap_analysist(const namespacet &_ns) - : static_analysist(_ns) {} +public: + explicit ssa_heap_analysist(const namespacet &_ns): + static_analysist(_ns) {} virtual void initialize(const goto_functionst &goto_functions) override; - protected: +protected: void init_ptr_param(const exprt &expr, ssa_heap_domaint &f_entry); }; -#endif //INC_2LS_SSA_HEAP_DOMAIN_H +#endif // CPROVER_2LS_SSA_SSA_HEAP_DOMAIN_H diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index eb178673c..e47f2126a 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -69,15 +69,10 @@ void ssa_inlinert::get_summary( bindings.push_back(get_replace_new_objects(SSA, *f_it, loc, summary)); - //equalities for arguments - bindings.push_back(get_replace_params( - summary.params, - *f_it, - cs_globals_in, - cs_globals_out, - SSA, - summary, - loc)); + // equalities for arguments + bindings.push_back( + get_replace_params( + summary.params, *f_it, cs_globals_in, cs_globals_out, SSA, summary, loc)); // equalities for globals_in if(forward) @@ -98,16 +93,18 @@ void ssa_inlinert::get_summary( summary.bw_transformer; } rename(transformer); - summaries.push_back(implies_exprt( - SSA.guard_symbol(n_it->location), 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( - cs_globals_in, cs_globals_out, summary, *f_it, SSA, loc)); + bindings.push_back( + get_replace_globals_out( + cs_globals_in, cs_globals_out, summary, *f_it, SSA, loc)); else - bindings.push_back(get_replace_globals_out( - cs_globals_out, cs_globals_in, summary, *f_it, SSA, loc)); + bindings.push_back( + get_replace_globals_out( + cs_globals_out, cs_globals_in, summary, *f_it, SSA, loc)); } /*******************************************************************\ @@ -129,12 +126,25 @@ exprt ssa_inlinert::get_summaries(const local_SSAt &SSA) return and_exprt(conjunction(bindings), conjunction(summaries)); } +/*******************************************************************\ + +Function: ssa_inlinert::get_summaries_to_loc + + Inputs: + + Outputs: + + Purpose: get summary for all function calls up to a given location + +\*******************************************************************/ + exprt ssa_inlinert::get_summaries_to_loc( - const local_SSAt &SSA, local_SSAt::locationt loc) + const local_SSAt &SSA, + local_SSAt::locationt loc) { - exprt::operandst summaries,bindings; - get_summaries(SSA,true,summaries,bindings, loc); - return and_exprt(conjunction(bindings),conjunction(summaries)); + exprt::operandst summaries, bindings; + get_summaries(SSA, true, summaries, bindings, loc); + return and_exprt(conjunction(bindings), conjunction(summaries)); } /*******************************************************************\ @@ -453,9 +463,9 @@ exprt ssa_inlinert::get_replace_globals_in( c.push_back(equal_exprt(lhs, rhs)); } #if 0 - else - warning() << "'" << it->get_identifier() - << "' not bound in caller" << eom; + else + warning() << "'" << it->get_identifier() + << "' not bound in caller" << eom; #endif } } @@ -527,8 +537,8 @@ exprt ssa_inlinert::get_replace_params( it!=funapp_expr.arguments().end(); it++, p_it++) { 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 + if(funapp_expr.arguments().size()!=params.size() && + ++next_p_it==params.end()) // TODO: handle ellipsis { warning() << "ignoring excess function arguments" << eom; break; @@ -552,81 +562,93 @@ exprt ssa_inlinert::get_replace_params( while(arg_type.id()==ID_pointer) { - std::list args_deref_in=apply_dereference(args_in, SSA.ssa_value_ai[loc], SSA.ns); - std::list params_deref_in=apply_dereference(params_in, summary.value_domain_in, SSA.ns); + std::list args_deref_in=apply_dereference( + args_in, SSA.ssa_value_ai[loc], SSA.ns); + std::list params_deref_in=apply_dereference( + params_in, summary.value_domain_in, SSA.ns); - local_SSAt::locationt next_loc=loc; ++next_loc; - std::list args_deref_out=apply_dereference(args_out, SSA.ssa_value_ai[next_loc], SSA.ns); - std::list params_deref_out=apply_dereference(params_out, summary.value_domain_out, SSA.ns); + local_SSAt::locationt next_loc=loc; + ++next_loc; + std::list args_deref_out=apply_dereference( + args_out, SSA.ssa_value_ai[next_loc], SSA.ns); + std::list params_deref_out=apply_dereference( + params_out, summary.value_domain_out, SSA.ns); - const typet arg_symbol_type = arg_type.subtype(); - arg_type = SSA.ns.follow(arg_symbol_type); + const typet arg_symbol_type=arg_type.subtype(); + arg_type=SSA.ns.follow(arg_symbol_type); if(contains_iterator(params_deref_out)) - { - // If the caller contains iterators, bindings are different since objects from caller will - // appear in the callee summary + { // If the caller contains iterators, bindings are different since + // objects from caller will appear in the callee summary assert(!args_deref_in.empty() && !args_deref_out.empty()); arg_type=SSA.ns.follow(args_deref_in.begin()->type()); assert(arg_type.id()==ID_struct); - for (const exprt &a : args_deref_in) + for(const exprt &a : args_deref_in) { - std::list aliases = apply_dereference({a}, SSA.ssa_value_ai[next_loc], SSA.ns); + std::list aliases=apply_dereference( + {a}, SSA.ssa_value_ai[next_loc], SSA.ns); aliases.push_front(a); - for (auto &alias : aliases) + for(auto &alias : aliases) { // Bind argument address c.push_back(equal_exprt( - param_out_transformer(alias, arg_type, summary.globals_out), - arg_out_transformer(alias, arg_symbol_type, params_deref_out.begin()->type(), SSA, - loc))); + param_out_transformer(alias, arg_type, summary.globals_out), + arg_out_transformer( + alias, arg_symbol_type, params_deref_out.begin()->type(), SSA, + loc))); - for (auto &component : to_struct_type(arg_type).components()) + for(auto &component : to_struct_type(arg_type).components()) { // Bind argument members at the input c.push_back(equal_exprt( - param_in_member_transformer(alias, component), - arg_in_member_transformer(alias, component, SSA, loc) - )); + param_in_member_transformer(alias, component), + arg_in_member_transformer(alias, component, SSA, loc))); } } } - for (const exprt &a : args_deref_out) + for(const exprt &a : args_deref_out) { - std::list aliases = apply_dereference({a}, SSA.ssa_value_ai[next_loc], SSA.ns); + std::list aliases=apply_dereference( + {a}, SSA.ssa_value_ai[next_loc], SSA.ns); aliases.push_front(a); - for (auto &alias : aliases) + for(auto &alias : aliases) { - const typet &alias_type = SSA.ns.follow(alias.type()); - assert(alias_type.id() == ID_struct); - for (auto &component : to_struct_type(alias_type).components()) + const typet &alias_type=SSA.ns.follow(alias.type()); + assert(alias_type.id()==ID_struct); + for(auto &component : to_struct_type(alias_type).components()) { - // Bind argument members at the output (args_deref_out might contain different objects - // than args_deref_in since function call may create new objects). - symbol_exprt arg_member(id2string(to_symbol_expr(alias).get_identifier()) + "." + - id2string(component.get_name()), component.type()); + // Bind argument members at the output (args_deref_out might + // contain different objects than args_deref_in since function + // call may create new objects). + symbol_exprt arg_member( + id2string(to_symbol_expr(alias).get_identifier())+"."+ + id2string(component.get_name()), component.type()); symbol_exprt member_lhs_out; - if (find_corresponding_symbol(arg_member, summary.globals_out, member_lhs_out)) + if(find_corresponding_symbol( + arg_member, summary.globals_out, member_lhs_out)) { rename(member_lhs_out); - c.push_back(equal_exprt(member_lhs_out, - arg_out_member_transformer(alias, component, SSA, loc))); + c.push_back( + equal_exprt( + member_lhs_out, + arg_out_member_transformer(alias, component, SSA, loc))); } } } } } else - { - // Bind objects pointed by argument and parameter when advancer is not present + { + // Bind objects pointed by argument and parameter when iterator is + // not present if(params_deref_in.size()==1) { - const exprt &p_in = params_deref_in.front(); + const exprt &p_in=params_deref_in.front(); exprt::operandst d; for(const exprt &a_in : args_deref_in) @@ -636,7 +658,7 @@ exprt ssa_inlinert::get_replace_params( param_in_transformer(p_in), arg_in_transformer(a_in, SSA, loc))); - if(arg_type.id() == ID_struct) + if(arg_type.id()==ID_struct) { for(auto &component : to_struct_type(arg_type).components()) { @@ -661,14 +683,16 @@ exprt ssa_inlinert::get_replace_params( binding.push_back(equal_exprt( param_out_transformer(p_out, arg_type, summary.globals_out), - arg_out_transformer(a_out, arg_symbol_type, p_out.type(), SSA, loc))); + arg_out_transformer( + a_out, arg_symbol_type, p_out.type(), SSA, loc))); if(arg_type.id()==ID_struct) { - for (auto &component : to_struct_type(arg_type).components()) + for(auto &component : to_struct_type(arg_type).components()) { binding.push_back(equal_exprt( - param_out_member_transformer(p_out, component, summary.globals_out), + param_out_member_transformer( + p_out, component, summary.globals_out), arg_out_member_transformer(a_out, component, SSA, loc))); } } @@ -681,12 +705,12 @@ exprt ssa_inlinert::get_replace_params( } } - args_in = args_deref_in; - args_out = args_deref_out; - params_in = params_deref_in; - params_out = params_deref_out; + args_in=args_deref_in; + args_out=args_deref_out; + params_in=params_deref_in; + params_out=params_deref_out; - if (args_in.empty() && args_out.empty()) break; + if(args_in.empty() && args_out.empty()) break; } } return conjunction(c); @@ -745,19 +769,20 @@ exprt ssa_inlinert::get_replace_globals_out( const summaryt &summary, const function_application_exprt &funapp_expr, const local_SSAt &SSA, - const local_SSAt::locationt &loc) + local_SSAt::locationt loc) { // equalities for globals_out exprt::operandst c; for(summaryt::var_sett::const_iterator it=cs_globals_out.begin(); - it!=cs_globals_out.end(); it++) + it!=cs_globals_out.end(); it++) { symbol_exprt lhs; const exprt rhs=*it; if(is_pointed(*it) || - id2string(it->get_identifier()).find("dynamic_object$") != std::string::npos) + id2string(it->get_identifier()).find("dynamic_object$")!= + std::string::npos) { if(!cs_heap_covered(*it) && !find_corresponding_symbol(*it, summary.globals_out, lhs)) @@ -784,10 +809,10 @@ exprt ssa_inlinert::get_replace_globals_out( { local_SSAt::locationt next_loc=loc; ++next_loc; - std::list caller_deref=apply_dereference(caller_global, - SSA.ssa_value_ai[next_loc], SSA.ns); - std::list callee_deref=apply_dereference(callee_global, summary.value_domain_out, - SSA.ns); + std::list caller_deref=apply_dereference( + caller_global, SSA.ssa_value_ai[next_loc], SSA.ns); + std::list callee_deref=apply_dereference( + callee_global, summary.value_domain_out, SSA.ns); if(!callee_deref.empty()) { @@ -804,15 +829,18 @@ exprt ssa_inlinert::get_replace_globals_out( exprt::operandst binding; binding.push_back(equal_exprt( param_out_transformer(callee, type, summary.globals_out), - arg_out_transformer(caller, symbol_type, callee.type(), SSA, loc))); + arg_out_transformer( + caller, symbol_type, callee.type(), SSA, loc))); if(type.id()==ID_struct) { for(auto &component : to_struct_type(type).components()) { binding.push_back(equal_exprt( - param_out_member_transformer(callee, component, summary.globals_out), - arg_out_member_transformer(caller, component, SSA, loc))); + param_out_member_transformer( + callee, component, summary.globals_out), + arg_out_member_transformer( + caller, component, SSA, loc))); } } @@ -828,8 +856,7 @@ exprt ssa_inlinert::get_replace_globals_out( callee_global=callee_deref; caller_global=caller_deref; - if(caller_global.empty()) - break; + if(caller_global.empty()) break; } } else @@ -916,22 +943,22 @@ void ssa_inlinert::rename(exprt &expr) irep_idt id=id2string(sexpr.get_identifier())+"@"+i2string(counter); sexpr.set_identifier(id); } - else if (expr.id() == ID_address_of) + else if(expr.id()==ID_address_of) { irep_idt id; - const exprt &obj = to_address_of_expr(expr).object(); - if (obj.id() == ID_symbol) + const exprt &obj=to_address_of_expr(expr).object(); + if(obj.id()==ID_symbol) { - const std::string &obj_id = id2string(to_symbol_expr(obj).get_identifier()); - if (obj_id.compare(obj_id.length() - 4, 4, "'obj") == 0) - id = obj_id.substr(0, obj_id.find_last_of("'")); + const std::string &obj_id=id2string(to_symbol_expr(obj).get_identifier()); + if(obj_id.compare(obj_id.length()-4, 4, "'obj")==0) + id=obj_id.substr(0, obj_id.find_last_of("'")); else - id = id2string(obj_id) + "'addr"; + id=id2string(obj_id)+"'addr"; - id = id2string(id) + "@" + i2string(counter); + id=id2string(id)+"@"+i2string(counter); } symbol_exprt addr_symbol(id, expr.type()); - expr = addr_symbol; + expr=addr_symbol; } Forall_operands(op, expr) rename(*op); @@ -1054,11 +1081,11 @@ void ssa_inlinert::rename_to_callee( replace_map[*it]=*p_it; } - replace_expr(replace_map,expr); + replace_expr(replace_map, expr); + + // arguments might contain globals, thus, we have to replace them separately + replace_map.clear(); - 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++) { @@ -1073,9 +1100,9 @@ void ssa_inlinert::rename_to_callee( #endif // rename objects not present in globals in to non-suffix version symbol_exprt to_replace(get_original_identifier(*it), it->type()); - replace_map[*it]=to_replace; + replace_map[*it] = to_replace; // to propagate #dynamic flag on type - replace_map[to_replace]=to_replace; + replace_map[to_replace] = to_replace; } } @@ -1236,19 +1263,21 @@ std::list ssa_inlinert::apply_dereference( exprt to_query=expr; // copy if(expr.id()==ID_symbol) { - to_symbol_expr(to_query).set_identifier(get_original_identifier(to_symbol_expr(expr))); + to_symbol_expr(to_query).set_identifier( + get_original_identifier(to_symbol_expr(expr))); } ssa_value_domaint::valuest values=value_domain(to_query, ns); - for(auto &v : values.value_set) + for(const ssa_objectt &v : values.value_set) { - assert(v.get_expr().id() == ID_symbol); + assert(v.get_expr().id()==ID_symbol); result.push_back(v.get_expr()); } } - else if (expr.id() == ID_typecast) + else if(expr.id()==ID_typecast) { - std::list tmp = apply_dereference({to_typecast_expr(expr).op()}, value_domain, ns); - for (auto &e : tmp) + std::list tmp=apply_dereference( + {to_typecast_expr(expr).op()}, value_domain, ns); + for(auto &e : tmp) result.push_back(e); } } @@ -1261,7 +1290,7 @@ Function: ssa_inlinert::contains_iterator Inputs: List of expressions - Outputs: True if the list contains an iterator + Outputs: True if the list contains an advancer Purpose: @@ -1269,79 +1298,157 @@ Function: ssa_inlinert::contains_iterator bool ssa_inlinert::contains_iterator(const std::list ¶ms) { - auto it = std::find_if(params.begin(), params.end(), - [](const exprt &p) { return is_iterator(p); }); - return (it != params.end()); + auto it=std::find_if(params.begin(), params.end(), + [](const exprt &p) { return is_iterator(p); }); + return (it!=params.end()); } +/*******************************************************************\ + +Function: ssa_inlinert::param_in_transformer + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + exprt ssa_inlinert::param_in_transformer(const exprt ¶m) { - assert(param.id() == ID_symbol); - symbol_exprt param_in = to_symbol_expr(param); + assert(param.id()==ID_symbol); + symbol_exprt param_in=to_symbol_expr(param); rename(param_in); return param_in; } -exprt ssa_inlinert::arg_in_transformer(const exprt &arg, const local_SSAt &SSA, - local_SSAt::locationt loc) +/*******************************************************************\ + +Function: ssa_inlinert::arg_in_transformer + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +exprt ssa_inlinert::arg_in_transformer( + const exprt &arg, const local_SSAt &SSA, + local_SSAt::locationt loc) { return SSA.read_rhs(arg, loc); } -exprt ssa_inlinert::param_in_member_transformer(const exprt ¶m, - const struct_union_typet::componentt &component) +/*******************************************************************\ + +Function: ssa_inlinert::param_in_member_transformer + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +exprt ssa_inlinert::param_in_member_transformer( + const exprt ¶m, + const struct_union_typet::componentt &component) { - assert(param.id() == ID_symbol); - symbol_exprt param_member(id2string(to_symbol_expr(param).get_identifier()) + "." + - id2string(component.get_name()), component.type()); + assert(param.id()==ID_symbol); + symbol_exprt param_member( + id2string(to_symbol_expr(param).get_identifier())+"."+ + id2string(component.get_name()), component.type()); rename(param_member); return param_member; } -exprt ssa_inlinert::arg_in_member_transformer(const exprt &arg, - const struct_union_typet::componentt &component, - const local_SSAt &SSA, local_SSAt::locationt loc) +/*******************************************************************\ + +Function: ssa_inlinert::arg_in_member_transformer + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +exprt ssa_inlinert::arg_in_member_transformer( + const exprt &arg, + const struct_union_typet::componentt &component, + const local_SSAt &SSA, local_SSAt::locationt loc) { - symbol_exprt arg_member(id2string(to_symbol_expr(arg).get_identifier()) + "." + + symbol_exprt arg_member(id2string(to_symbol_expr(arg).get_identifier())+"."+ id2string(component.get_name()), component.type()); return SSA.read_rhs(arg_member, loc); } -exprt ssa_inlinert::param_out_transformer(const exprt ¶m, const typet &type, - const local_SSAt::var_sett &globals_out) +/*******************************************************************\ + +Function: ssa_inlinert::param_out_transformer + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +exprt ssa_inlinert::param_out_transformer( + const exprt ¶m, const typet &type, + const local_SSAt::var_sett &globals_out) { - assert(param.id() == ID_symbol); + assert(param.id()==ID_symbol); - if (type.id() == ID_struct) + if(type.id()==ID_struct) { - address_of_exprt param_addr = address_of_exprt(param); + address_of_exprt param_addr=address_of_exprt(param); rename(param_addr); return param_addr; } else { - symbol_exprt param_out = to_symbol_expr(param); - if (find_corresponding_symbol(to_symbol_expr(param), globals_out, param_out)) + symbol_exprt param_out=to_symbol_expr(param); + if(find_corresponding_symbol(to_symbol_expr(param), globals_out, param_out)) rename(param_out); return param_out; } } -exprt ssa_inlinert::arg_out_transformer(const exprt &arg, const typet &arg_symbol_type, - const typet ¶m_type, const local_SSAt &SSA, - local_SSAt::locationt loc) +/*******************************************************************\ + +Function: ssa_inlinert::arg_out_transformer + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +exprt ssa_inlinert::arg_out_transformer( + const exprt &arg, const typet &arg_symbol_type, + const typet ¶m_type, const local_SSAt &SSA, + local_SSAt::locationt loc) { - const typet &arg_type = SSA.ns.follow(arg_symbol_type); - if (arg_type.id() == ID_struct) + const typet &arg_type=SSA.ns.follow(arg_symbol_type); + if(arg_type.id()==ID_struct) { - assert(arg.id() == ID_symbol); - symbol_exprt arg_symbol = to_symbol_expr(arg); - address_of_exprt arg_addr = address_of_exprt(arg_symbol); + assert(arg.id()==ID_symbol); + symbol_exprt arg_symbol=to_symbol_expr(arg); + address_of_exprt arg_addr=address_of_exprt(arg_symbol); const symbolt *symbol; - if (!SSA.ns.lookup(arg_symbol.get_identifier(), symbol)) + if(!SSA.ns.lookup(arg_symbol.get_identifier(), symbol)) { - arg_addr = address_of_exprt(symbol->symbol_expr()); + arg_addr=address_of_exprt(symbol->symbol_expr()); } covered_cs_heap_out.insert(arg_symbol); @@ -1349,80 +1456,138 @@ exprt ssa_inlinert::arg_out_transformer(const exprt &arg, const typet &arg_symbo } else { - const symbol_exprt &arg_out = SSA.name(ssa_objectt(arg, SSA.ns), local_SSAt::OUT, loc); + const symbol_exprt &arg_out=SSA.name(ssa_objectt(arg, SSA.ns), + local_SSAt::OUT, loc); covered_cs_heap_out.insert(arg_out); return arg_out; } } -exprt ssa_inlinert::param_out_member_transformer(const exprt ¶m, - const struct_union_typet::componentt &component, - const local_SSAt::var_sett &globals_out) +/*******************************************************************\ + +Function: ssa_inlinert::param_out_member_transformer + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +exprt ssa_inlinert::param_out_member_transformer( + const exprt ¶m, + const struct_union_typet::componentt &component, + const local_SSAt::var_sett &globals_out) { - assert(param.id() == ID_symbol); + assert(param.id()==ID_symbol); - symbol_exprt param_member(id2string(to_symbol_expr(param).get_identifier()) + "." + - id2string(component.get_name()), component.type()); + symbol_exprt param_member( + id2string(to_symbol_expr(param).get_identifier())+"."+ + id2string(component.get_name()), component.type()); symbol_exprt param_out; assert(find_corresponding_symbol(param_member, globals_out, param_out)); rename(param_out); return param_out; } -exprt ssa_inlinert::arg_out_member_transformer(const exprt &arg, - const struct_union_typet::componentt &component, - const local_SSAt &SSA, local_SSAt::locationt loc) +/*******************************************************************\ + +Function: ssa_inlinert::artg_out_transformer + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +exprt ssa_inlinert::arg_out_member_transformer( + const exprt &arg, + const struct_union_typet::componentt &component, + const local_SSAt &SSA, local_SSAt::locationt loc) { - symbol_exprt arg_member(id2string(to_symbol_expr(arg).get_identifier()) + "." + + symbol_exprt arg_member(id2string(to_symbol_expr(arg).get_identifier())+"."+ id2string(component.get_name()), component.type()); - const symbol_exprt &arg_member_out = SSA.name(ssa_objectt(arg_member, SSA.ns), local_SSAt::OUT, - loc); + const symbol_exprt &arg_member_out=SSA.name(ssa_objectt(arg_member, SSA.ns), + local_SSAt::OUT, + loc); covered_cs_heap_out.insert(arg_member_out); return arg_member_out; } +/*******************************************************************\ + +Function: ssa_inlinert::cs_heap_covered + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + bool ssa_inlinert::cs_heap_covered(const exprt &expr) { - return expr.id() == ID_symbol && - covered_cs_heap_out.find(to_symbol_expr(expr)) != covered_cs_heap_out.end(); + return expr.id()==ID_symbol && + covered_cs_heap_out.find(to_symbol_expr(expr))!= + covered_cs_heap_out.end(); } +/*******************************************************************\ + +Function: ssa_inlinert::get_replace_new_objects + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + exprt ssa_inlinert::get_replace_new_objects( const local_SSAt &SSA, const function_application_exprt funapp_expr, - local_SSAt::locationt loc, - const summaryt &summary) + local_SSAt::locationt loc, const summaryt &summary) { - const irep_idt &fname=to_symbol_expr(funapp_expr.function()).get_identifier(); - - auto next_loc=loc; ++next_loc; - const ssa_heap_domaint &heap_domain=SSA.heap_analysis[next_loc]; + exprt::operandst binding; - const std::list callee_objects=heap_domain.new_objects(fname); - const std::list caller_objects= - heap_domain.new_caller_objects(fname, loc); + const irep_idt &fname=to_symbol_expr(funapp_expr.function()).get_identifier(); - exprt::operandst binding; - auto callee_it=callee_objects.begin(); - for(auto caller_it=caller_objects.begin(); caller_it != caller_objects.end(); - ++caller_it, ++callee_it) + auto next_loc=loc; + ++next_loc; + if(SSA.heap_analysis.has_location(next_loc)) { - const typet symbol_type=caller_it->type(); - const typet type=SSA.ns.follow(symbol_type); + const ssa_heap_domaint &heap_domain=SSA.heap_analysis[next_loc]; - binding.push_back(equal_exprt( - param_out_transformer(*callee_it, type, summary.globals_out), - arg_out_transformer(*caller_it, symbol_type, type, SSA, loc))); + const std::list callee_objects=heap_domain.new_objects(fname); + const std::list caller_objects=heap_domain.new_caller_objects( + fname, loc); - if(type.id()==ID_struct) + auto callee_it=callee_objects.begin(); + for(auto caller_it=caller_objects.begin(); caller_it!=caller_objects.end(); + ++caller_it, ++callee_it) { - for(auto &component : to_struct_type(type).components()) + const typet symbol_type=caller_it->type(); + const typet type=SSA.ns.follow(symbol_type); + + binding.push_back(equal_exprt( + param_out_transformer(*callee_it, type, summary.globals_out), + arg_out_transformer(*caller_it, symbol_type, type, SSA, loc))); + + if(type.id()==ID_struct) { - binding.push_back(equal_exprt( - param_out_member_transformer( - *callee_it, component, summary.globals_out), - arg_out_member_transformer( - *caller_it, component, SSA, loc))); + for(auto &component : to_struct_type(type).components()) + { + binding.push_back( + equal_exprt( + param_out_member_transformer( + *callee_it, component, summary.globals_out), + arg_out_member_transformer(*caller_it, component, SSA, loc))); + } } } } diff --git a/src/ssa/ssa_inliner.h b/src/ssa/ssa_inliner.h index e5e58542a..4d0278ca2 100644 --- a/src/ssa/ssa_inliner.h +++ b/src/ssa/ssa_inliner.h @@ -41,8 +41,7 @@ class ssa_inlinert:public messaget exprt::operandst &bindings, local_SSAt::locationt loc=local_SSAt::locationt()); exprt get_summaries(const local_SSAt &SSA); - - exprt get_summaries_to_loc(const local_SSAt &SSA, local_SSAt::locationt loc); + exprt get_summaries_to_loc(const local_SSAt &SSA, local_SSAt::locationt loc); void replace( local_SSAt &SSA, @@ -108,9 +107,10 @@ class ssa_inlinert:public messaget static irep_idt get_original_identifier(const symbol_exprt &s); - static std::list apply_dereference(const std::list &exprs, - const ssa_value_domaint &value_domain, - const namespacet &ns); + static std::list apply_dereference( + const std::list &exprs, + const ssa_value_domaint &value_domain, + const namespacet &ns); protected: unsigned counter; @@ -120,7 +120,7 @@ class ssa_inlinert:public messaget local_SSAt::nodet::equalitiest new_equs; std::set rm_function_calls; - std::set covered_cs_heap_out; + std::set covered_cs_heap_out; void replace_globals_in( const local_SSAt::var_sett &globals_in, @@ -134,39 +134,39 @@ class ssa_inlinert:public messaget const local_SSAt::var_sett &cs_globals_out); exprt get_replace_globals_in( - const local_SSAt::var_sett &globals_in, + const local_SSAt::var_sett &globals_in, const local_SSAt::var_sett &globals); - exprt get_replace_new_objects( - const local_SSAt &SSA, - const function_application_exprt funapp_expr, - local_SSAt::locationt loc, - const summaryt &summary); exprt get_replace_params( const local_SSAt::var_listt ¶ms, 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 &SSA, - const summaryt &summary, - const local_SSAt::locationt &loc); + const local_SSAt::var_sett &cs_globals_out, const local_SSAt &SSA, + const summaryt &summary, const local_SSAt::locationt &loc); exprt get_replace_globals_out( const local_SSAt::var_sett &cs_globals_in, const local_SSAt::var_sett &cs_globals_out, const summaryt &summary, const function_application_exprt &funapp_expr, const local_SSAt &SSA, - const local_SSAt::locationt &loc); + local_SSAt::locationt loc); + exprt get_replace_new_objects( + const local_SSAt &SSA, + const function_application_exprt funapp_expr, + local_SSAt::locationt loc, const summaryt &summary); void rename(exprt &expr); void rename(local_SSAt::nodet &node); bool cs_heap_covered(const exprt &expr); -// Transformation functions for lists of input/output arguments/pointers (or their members) -// for binding purposes + // Transformation functions for lists of input/output arguments/pointers + // (or their members) for binding purposes exprt param_in_transformer(const exprt ¶m); - exprt arg_in_transformer(const exprt &arg, const local_SSAt &SSA, local_SSAt::locationt loc); + exprt arg_in_transformer( + const exprt &arg, + const local_SSAt &SSA, + local_SSAt::locationt loc); exprt param_in_member_transformer( const exprt ¶m, const struct_union_typet::componentt &component); diff --git a/src/ssa/ssa_object.cpp b/src/ssa/ssa_object.cpp index 31763b878..b8bbeed52 100644 --- a/src/ssa/ssa_object.cpp +++ b/src/ssa/ssa_object.cpp @@ -56,6 +56,18 @@ void collect_objects_rec( std::set &objects, std::set &literals); +/*******************************************************************\ + +Function: collect_ptr_objects + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + void collect_ptr_objects( const exprt &expr, const namespacet &ns, @@ -89,10 +101,22 @@ void collect_ptr_objects( else { forall_operands(it, expr) - collect_ptr_objects(*it, ns, objects, literals, dynamic); + collect_ptr_objects(*it, ns, objects, literals, dynamic); } } +/*******************************************************************\ + +Function: collect_objects_address_of_rec + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + void collect_objects_address_of_rec( const exprt &src, const namespacet &ns, @@ -180,7 +204,7 @@ void collect_objects_rec( if(type.id()==ID_struct) { std::string id=id2string(ssa_object.get_identifier()); - if (src.type().get_bool("#dynamic") || is_pointed(src)) + if(src.type().get_bool("#dynamic") || is_pointed(src)) objects.insert(ssa_object); // need to split up @@ -211,12 +235,14 @@ void collect_objects_rec( const symbolt *symbol; if(ssa_object.type().get_bool("#dynamic") || (root_object.id()==ID_symbol && - id2string(to_symbol_expr(root_object).get_identifier()).find("#return_value") == + id2string(to_symbol_expr(root_object).get_identifier()).find( + "#return_value")== std::string::npos && !ns.lookup(to_symbol_expr(root_object).get_identifier(), symbol) && (symbol->is_parameter || !symbol->is_procedure_local()))) { - collect_ptr_objects(ssa_object.symbol_expr(), ns, objects, literals, false); + collect_ptr_objects( + ssa_object.symbol_expr(), ns, objects, literals, false); } } } @@ -239,7 +265,9 @@ Function: ssa_objectst::collect_objects \*******************************************************************/ -void ssa_objectst::collect_objects(const goto_functionst::goto_functiont &src, const namespacet &ns) +void ssa_objectst::collect_objects( + const goto_functionst::goto_functiont &src, + const namespacet &ns) { // Add objects for parameters. for(goto_functionst::goto_functiont::parameter_identifierst:: @@ -261,15 +289,15 @@ void ssa_objectst::collect_objects(const goto_functionst::goto_functiont &src, c // Add new objects created within the function local_SSAt::locationt exit=--(src.body.instructions.end()); - if (heap_analysis.has_location(exit)) + if(heap_analysis.has_location(exit)) { - const std::list &new_objects=heap_analysis[exit].new_objects(); + const std::list &new_objects= + heap_analysis[exit].new_objects(); for(const symbol_exprt &o : new_objects) { collect_objects_rec(o, ns, objects, literals); } } - } /*******************************************************************\ diff --git a/src/ssa/ssa_pointed_objects.cpp b/src/ssa/ssa_pointed_objects.cpp index 70904114c..ceab4b2f4 100644 --- a/src/ssa/ssa_pointed_objects.cpp +++ b/src/ssa/ssa_pointed_objects.cpp @@ -1,105 +1,181 @@ -/** - * Viktor Malik, 2/15/17 (c). - */ +/*******************************************************************\ + +Module: Library of functions for working with pointed objects + +Author: Viktor Malik + +\*******************************************************************/ #include "ssa_pointed_objects.h" #include "ssa_object.h" +/*******************************************************************\ + +Function: level_str + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + const irep_idt level_str(const unsigned level, const irep_idt &suffix) { - return "#lvl_" + std::to_string(level) + "_" + id2string(suffix); + return "#lvl_"+std::to_string(level)+"_"+id2string(suffix); } +/*******************************************************************\ + +Function: it_field_str + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + const irep_idt it_field_str(const unsigned level) { - return id2string(ID_it_field) + "_" + std::to_string(level); + return id2string(ID_it_field)+"_"+std::to_string(level); } +/*******************************************************************\ + +Function: copy_iterator + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + void copy_iterator(exprt &dest, const exprt &src) { - if (src.get_bool(ID_iterator)) + if(src.get_bool(ID_iterator)) { dest.set(ID_iterator, true); dest.set(ID_it_pointer, src.get(ID_it_pointer)); dest.set(ID_it_init_value, src.get(ID_it_init_value)); dest.set(ID_it_init_value_level, src.get(ID_it_init_value_level)); - unsigned field_cnt = src.get_unsigned_int(ID_it_field_cnt); + unsigned field_cnt=src.get_unsigned_int(ID_it_field_cnt); dest.set(ID_it_field_cnt, field_cnt); - for (unsigned i = 0; i < field_cnt; ++i) + for(unsigned i=0; i fields) { dest.set(ID_it_field_cnt, (unsigned) fields.size()); - for (unsigned i = 0; i < fields.size(); ++i) + for(unsigned i=0; i get_iterator_fields(const exprt &expr) { assert(is_iterator(expr)); - unsigned cnt = expr.get_unsigned_int(ID_it_field_cnt); + unsigned cnt=expr.get_unsigned_int(ID_it_field_cnt); std::vector result; - for (unsigned i = 0; i < cnt; ++i) + for(unsigned i=0; i pointer_fields(const exprt &expr, const unsigned from_level) +/*******************************************************************\ + +Function: pointer_fields + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +const std::vector pointer_fields( + const exprt &expr, + const unsigned from_level) { std::vector result; - unsigned max_level = pointed_level(expr); - assert(from_level < max_level); - for (unsigned l = from_level; l < max_level; ++l) + unsigned max_level=pointed_level(expr); + assert(from_level #include @@ -48,4 +52,4 @@ const std::vector get_iterator_fields(const exprt &expr); const irep_idt iterator_to_initial_id(const exprt &expr, const irep_idt &expr_id); -#endif //CPROVER_SSA_POINTED_OBJECTS_H +#endif // CPROVER_2LS_SSA_SSA_POINTED_OBJECTS_H diff --git a/src/ssa/ssa_value_set.cpp b/src/ssa/ssa_value_set.cpp index de776e74b..663ec2e9b 100644 --- a/src/ssa/ssa_value_set.cpp +++ b/src/ssa/ssa_value_set.cpp @@ -60,13 +60,14 @@ void ssa_value_domaint::transform( { const code_function_callt &code_function_call= to_code_function_call(from->code); - const irep_idt &fname = to_symbol_expr(code_function_call.function()).get_identifier(); + const irep_idt &fname=to_symbol_expr( + code_function_call.function()).get_identifier(); - const ssa_value_ait & value_analysis = static_cast(ai); + const ssa_value_ait &value_analysis=static_cast(ai); - const ssa_heap_domaint *heap_domain = NULL; - if (value_analysis.heap_analysis.has_location(to)) - heap_domain = &value_analysis.heap_analysis[to]; + const ssa_heap_domaint *heap_domain=NULL; + if(value_analysis.heap_analysis.has_location(to)) + heap_domain=&value_analysis.heap_analysis[to]; // functions may alter state almost arbitrarily: @@ -87,46 +88,46 @@ void ssa_value_domaint::transform( std::list objects; - for (auto &argument : code_function_call.arguments()) + for(auto &argument : code_function_call.arguments()) { - exprt arg = argument; - exprt arg_expr = argument; - while (arg.type().id() == ID_pointer) + exprt arg=argument; + exprt arg_expr=argument; + while(arg.type().id()==ID_pointer) { - if (arg.id() == ID_symbol) + if(arg.id()==ID_symbol) { - symbol_exprt pointed_obj = pointed_object(arg, ns); + symbol_exprt pointed_obj=pointed_object(arg, ns); pointed_obj.type().set("#dynamic", true); std::set new_objects; - if (heap_domain) - new_objects = heap_domain->value(arg_expr); - if (new_objects.empty()) + if(heap_domain) + new_objects=heap_domain->value(arg_expr); + if(new_objects.empty()) { new_objects.insert(pointed_obj); } - auto it = new_objects.begin(); + auto it=new_objects.begin(); assign_lhs_rec(arg, address_of_exprt(*it), ns); objects.push_back(*it); - for (++it; it != new_objects.end(); ++it) + for(++it; it!=new_objects.end(); ++it) { assign_lhs_rec(arg, address_of_exprt(*it), ns, true); objects.push_back(*it); } - arg_expr = dereference_exprt(arg_expr, arg.type().subtype()); - arg = pointed_obj; + arg_expr=dereference_exprt(arg_expr, arg.type().subtype()); + arg=pointed_obj; } - else if (arg.id() == ID_address_of) + else if(arg.id()==ID_address_of) { - arg = arg_expr = to_address_of_expr(arg).object(); + arg=arg_expr=to_address_of_expr(arg).object(); } - else if (arg.id() == ID_typecast) + else if(arg.id()==ID_typecast) { - assert(arg_expr.id() == ID_typecast); - arg = arg_expr = to_typecast_expr(arg).op(); + assert(arg_expr.id()==ID_typecast); + arg=arg_expr=to_typecast_expr(arg).op(); } else break; @@ -141,35 +142,36 @@ void ssa_value_domaint::transform( } // the assignment of return value might be in next instruction - if (to->is_assign() && to_code_assign(to->code).rhs().id() == ID_symbol) + if(to->is_assign() && to_code_assign(to->code).rhs().id()==ID_symbol) { - const symbol_exprt &return_value = to_symbol_expr(to_code_assign(to->code).rhs()); - if (return_value.type().id() == ID_pointer && - return_value.get_identifier() == id2string(fname) + "#return_value") + const symbol_exprt &return_value=to_symbol_expr( + to_code_assign(to->code).rhs()); + if(return_value.type().id()==ID_pointer && + return_value.get_identifier()==id2string(fname)+"#return_value") { std::set new_objects; - if (heap_domain) - new_objects = heap_domain->value(return_value); - if (new_objects.empty()) + if(heap_domain) + new_objects=heap_domain->value(return_value); + if(new_objects.empty()) { - symbol_exprt pointed_obj = pointed_object(return_value, ns); + symbol_exprt pointed_obj=pointed_object(return_value, ns); pointed_obj.type().set("#dynamic", true); new_objects.insert(pointed_obj); } - auto it = new_objects.begin(); + auto it=new_objects.begin(); assign_lhs_rec(return_value, address_of_exprt(*it), ns); objects.push_back(*it); - for (++it; it != new_objects.end(); ++it) + for(++it; it!=new_objects.end(); ++it) { assign_lhs_rec(return_value, address_of_exprt(*it), ns, true); objects.push_back(*it); } - if (heap_domain) + if(heap_domain) { - for (auto &new_o : heap_domain->new_caller_objects(fname, from)) + for(auto &new_o : heap_domain->new_caller_objects(fname, from)) { objects.push_back(new_o); } @@ -177,11 +179,11 @@ void ssa_value_domaint::transform( } } - for (const symbol_exprt &o1 : objects) + for(const symbol_exprt &o1 : objects) { - for (const symbol_exprt &o2 : objects) + for(const symbol_exprt &o2 : objects) { - if (o1 != o2 && o1.type() == o2.type()) + if(o1!=o2 && o1.type()==o2.type()) value_map[ssa_objectt(o1, ns)].value_set.insert(ssa_objectt(o2, ns)); } } @@ -231,7 +233,7 @@ void ssa_value_domaint::assign_lhs_rec( auto rhs_it= rhs.id()==ID_struct ? rhs.operands().begin() : rhs.operands().end(); - + for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); @@ -239,10 +241,10 @@ void ssa_value_domaint::assign_lhs_rec( { member_exprt new_lhs(lhs, it->get_name(), it->type()); exprt new_rhs; - if (rhs_it != rhs.operands().end()) - new_rhs = *(rhs_it++); + if(rhs_it!=rhs.operands().end()) + new_rhs=*(rhs_it++); else - new_rhs = member_exprt(rhs, it->get_name(), it->type()); + new_rhs=member_exprt(rhs, it->get_name(), it->type()); assign_lhs_rec(new_lhs, new_rhs, ns, add); // recursive call } @@ -252,7 +254,7 @@ void ssa_value_domaint::assign_lhs_rec( // object? ssa_objectt ssa_object(lhs, ns); - if (ssa_object) + if(ssa_object) { assign_pointed_rhs_rec(rhs, ns); valuest tmp_values; @@ -543,8 +545,9 @@ Function: ssa_value_domaint::valuest::merge \*******************************************************************/ -bool ssa_value_domaint::valuest::merge(const valuest &src, bool is_loop_back, - const irep_idt &object_id) +bool ssa_value_domaint::valuest::merge( + const valuest &src, bool is_loop_back, + const irep_idt &object_id) { bool result=false; @@ -571,74 +574,76 @@ bool ssa_value_domaint::valuest::merge(const valuest &src, bool is_loop_back, } // value set - unsigned long old_size = value_set.size(); - for (auto &v : src.value_set) + unsigned long old_size=value_set.size(); + for(const ssa_objectt &v : src.value_set) { - if (is_loop_back) + if(is_loop_back) { - if (is_pointed(v.get_expr())) + if(is_pointed(v.get_expr())) { - unsigned level = pointed_level(v.get_expr()) - 1; - exprt expr = v.get_expr(); + unsigned level=pointed_level(v.get_expr())-1; + exprt expr=v.get_expr(); - auto it = value_set.end(); + auto it=value_set.end(); - while (level > 0) + while(level>0) { - const irep_idt ptr_root_id = pointer_root_id(expr); - it = std::find_if(value_set.begin(), value_set.end(), - [&ptr_root_id](const ssa_objectt &o) - { - return o.get_identifier() == ptr_root_id; - }); - if (it != value_set.end()) + const irep_idt ptr_root_id=pointer_root_id(expr); + it=std::find_if(value_set.begin(), value_set.end(), + [&ptr_root_id](const ssa_objectt &o) + { + return o.get_identifier()==ptr_root_id; + }); + if(it!=value_set.end()) break; else { - expr = get_pointer_root(expr, level--); + expr=get_pointer_root(expr, level--); } } - if (it != value_set.end()) + if(it!=value_set.end()) { - if (!it->get_expr().get_bool(ID_iterator)) + if(!it->get_expr().get_bool(ID_iterator)) { assert(it->get_expr().get_bool(ID_pointed)); ssa_objectt object_copy(*it); - object_copy.set_iterator(object_id, pointer_fields(v.get_expr(), level)); + object_copy.set_iterator( + object_id, pointer_fields(v.get_expr(), level)); value_set.erase(it); value_set.insert(object_copy); - result = true; + result=true; } continue; } } - if (is_iterator(v.get_expr())) continue; + if(is_iterator(v.get_expr())) continue; } else { - if (v.get_expr().get_bool(ID_iterator)) + if(v.get_expr().get_bool(ID_iterator)) { - const irep_idt &corresponding_id = iterator_to_initial_id(v.get_expr(), v.get_identifier()); - - auto it = std::find_if(value_set.begin(), value_set.end(), - [&corresponding_id](const ssa_objectt &o) - { - return o.get_expr().get_bool(ID_pointed) && - (o.get_identifier() == corresponding_id); - }); - if (it != value_set.end()) + const irep_idt &corresponding_id=iterator_to_initial_id( + v.get_expr(), v.get_identifier()); + + auto it=std::find_if(value_set.begin(), value_set.end(), + [&corresponding_id](const ssa_objectt &o) + { + return o.get_expr().get_bool(ID_pointed) && + (o.get_identifier()==corresponding_id); + }); + if(it!=value_set.end()) { - if (v != *it) - result = true; + if(v!=*it) + result=true; value_set.erase(it); } } } value_set.insert(v); } - if (value_set.size() != old_size) - result = true; + if(value_set.size()!=old_size) + result=true; // alignment alignment=merge_alignment(alignment, src.alignment); @@ -674,7 +679,8 @@ bool ssa_value_domaint::merge( { if(v_it==value_map.end() || it->firstfirst) { - if (!from->is_backwards_goto() || !is_iterator(it->first.get_root_object())) + if(!from->is_backwards_goto() || + !is_iterator(it->first.get_root_object())) value_map.insert(v_it, *it); result=true; it++; @@ -688,7 +694,8 @@ bool ssa_value_domaint::merge( assert(v_it->first==it->first); - if(v_it->second.merge(it->second, from->is_backwards_goto(), it->first.get_identifier())) + if(v_it->second.merge(it->second, from->is_backwards_goto(), + it->first.get_identifier())) result=true; v_it++; @@ -698,7 +705,21 @@ bool ssa_value_domaint::merge( return result; } -void ssa_value_domaint::assign_pointed_rhs_rec(const exprt &rhs, const namespacet &ns) +/*******************************************************************\ + +Function: ssa_value_domaint::assign_pointed_rhs_rec + + Inputs: + + Outputs: + + Purpose: Dynamically add p'obj to value set of p + +\*******************************************************************/ + +void ssa_value_domaint::assign_pointed_rhs_rec( + const exprt &rhs, + const namespacet &ns) { ssa_objectt ssa_object(rhs, ns); @@ -711,7 +732,7 @@ void ssa_value_domaint::assign_pointed_rhs_rec(const exprt &rhs, const namespace if(m_it==value_map.end()) { - const symbol_exprt pointed = pointed_object(rhs, ns); + const symbol_exprt pointed=pointed_object(rhs, ns); ssa_objectt pointed_obj(pointed, ns); value_map[ssa_object].value_set.insert(pointed_obj); } @@ -736,23 +757,23 @@ Function: ssa_value_ait::initialize \*******************************************************************/ -void ssa_value_ait::initialize(const goto_functionst::goto_functiont &goto_function) +void ssa_value_ait::initialize( + const goto_functionst::goto_functiont &goto_function) { ait::initialize(goto_function); // Initialize value sets for pointer parameters - if (!goto_function.type.parameters().empty()) + if(!goto_function.type.parameters().empty()) { - locationt e = goto_function.body.instructions.begin(); - ssa_value_domaint &entry = operator[](e); + locationt e=goto_function.body.instructions.begin(); + ssa_value_domaint &entry=operator[](e); - for (auto ¶m : goto_function.type.parameters()) + for(auto ¶m : goto_function.type.parameters()) { const symbol_exprt param_expr(param.get_identifier(), param.type()); assign_ptr_param(param_expr, entry); } - } } @@ -771,7 +792,8 @@ Function: ssa_value_ait::assign_ptr_param_rec \*******************************************************************/ -void ssa_value_ait::assign_ptr_param(const exprt &expr, ssa_value_domaint &entry) +void ssa_value_ait::assign_ptr_param( + const exprt &expr, ssa_value_domaint &entry) { const typet &type=ns.follow(expr.type()); if(type.id()==ID_pointer) @@ -806,7 +828,10 @@ Function: ssa_value_ait::assign \*******************************************************************/ -void ssa_value_ait::assign(const exprt &src, const exprt &dest, ssa_value_domaint &entry) +void ssa_value_ait::assign( + const exprt &src, + const exprt &dest, + ssa_value_domaint &entry) { ssa_objectt src_obj(src, ns); ssa_objectt dest_obj(dest, ns); From 941c778922b62d7d1700d1d267e652004e5d860e Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 11 Aug 2017 13:44:35 +0200 Subject: [PATCH 087/322] Update heap tests. Use new binary and add assertion to dll1_simple. --- regression/heap/Makefile | 4 ++-- regression/heap/dll1_simple/main.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/regression/heap/Makefile b/regression/heap/Makefile index d2ff74910..b5f2484a2 100644 --- a/regression/heap/Makefile +++ b/regression/heap/Makefile @@ -3,10 +3,10 @@ default: tests.log FLAGS = --verbosity 10 test: - @../test.pl -c "../../../src/summarizer/2ls $(FLAGS)" + @../test.pl -c "../../../src/2ls/2ls $(FLAGS)" tests.log: ../test.pl - @../test.pl -c "../../../src/summarizer/2ls $(FLAGS)" + @../test.pl -c "../../../src/2ls/2ls $(FLAGS)" show: @for dir in *; do \ diff --git a/regression/heap/dll1_simple/main.c b/regression/heap/dll1_simple/main.c index 0dae16a0d..2fc0f460f 100644 --- a/regression/heap/dll1_simple/main.c +++ b/regression/heap/dll1_simple/main.c @@ -35,7 +35,7 @@ static void chain_node(struct node **ppnode) *ppnode = node; } -static struct node* create_sll(const struct node **pp1, const struct node **pp2) +static struct node* create_sll() { struct node *list = NULL; @@ -92,9 +92,7 @@ void check_seq_prev(const struct node *beg, const struct node *const end) { void main() { - const struct node *p1, *p2; - - struct node *list = create_sll(&p1, &p2); + struct node *list = create_sll(); init_back_link(list); @@ -103,5 +101,7 @@ void main() // check_seq_next(p2, p1); remove_fw_link(list); + + assert(list->next == NULL); } From 0b3b0ba3207f0a3c14a37185fce48c4bc2e7e649 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 11 Aug 2017 13:46:48 +0200 Subject: [PATCH 088/322] Fix errors overlooked in merge of heap branch. Tests for the merge of heap branch used old 2ls binary, so some merge errors were overlooked. Now both heap tests work. --- src/domains/heap_domain.cpp | 3 ++- src/domains/template_generator_base.cpp | 2 +- src/solver/summarizer_fw.cpp | 2 +- src/ssa/local_ssa.cpp | 15 ++++++++------- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 47dc57fda..657ce9a63 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -457,7 +457,8 @@ void heap_domaint::project_on_vars( { const template_rowt &templ_row=templ[row]; - if(vars.find(templ_row.expr)==vars.end()) continue; + if(vars.find(templ_row.expr)==vars.end()) + continue; const row_valuet &row_val=val[row]; if(templ_row.kind==LOOP) diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index c5ece57e5..787f428c9 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -282,7 +282,7 @@ void template_generator_baset::filter_heap_domain() { domaint::var_specst new_var_specs(var_specs); var_specs.clear(); - for(auto &var : var_specs) + for(auto &var : new_var_specs) { if(var.var.id()==ID_symbol && var.var.type().id()==ID_pointer) { diff --git a/src/solver/summarizer_fw.cpp b/src/solver/summarizer_fw.cpp index 9d7aded5b..914d19289 100644 --- a/src/solver/summarizer_fw.cpp +++ b/src/solver/summarizer_fw.cpp @@ -180,7 +180,7 @@ void summarizer_fwt::do_summary( { summary.aux_precondition=advancer_bindings; } - } + } if(context_sensitive && !summary.fw_precondition.is_true()) { diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 0bcd8a7c7..24a9a2a9f 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -138,17 +138,18 @@ 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) + if(!with_returns && !is_pointed(it->get_expr()) && + id2string(it->get_identifier()).find("#return_value")!= + std::string::npos) continue; // filter out return values of other functions if(with_returns && returns_for_function!="" && - id2string(it->get_identifier()).find( - "#return_value")!=std::string::npos && - id2string(it->get_identifier()).find( - id2string(returns_for_function)+"#return_value")==std::string::npos) + id2string(it->get_identifier()).find("#return_value")== + id2string(it->get_identifier()).size()- + std::string("#return_value").size() && + id2string(it->get_identifier()).find( + id2string(returns_for_function)+"#return_value")==std::string::npos) continue; const exprt &root_obj=it->get_root_object(); From a568713beb0b539a6ecd95e7c0f81296bbe3e29b Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 17 Aug 2017 12:04:27 +0200 Subject: [PATCH 089/322] Changes needed for the merge of heap branch into master. Remove unnecessary includes and use <...> for includes from other directories. Use #if 0 to commented code. --- src/domains/heap_domain.cpp | 6 +- src/domains/heap_domain.h | 2 +- src/domains/strategy_solver_heap.h | 2 +- src/solver/summarizer_fw.cpp | 5 -- src/ssa/local_ssa.cpp | 102 ++++++++++++++--------------- src/ssa/ssa_inliner.cpp | 1 - src/ssa/ssa_object.cpp | 3 +- 7 files changed, 55 insertions(+), 66 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 657ce9a63..848c7e35a 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -7,12 +7,8 @@ Author: Viktor Malik \*******************************************************************/ #include "heap_domain.h" -#include "util.h" -#include "domain.h" #include -#include -#include "../ssa/ssa_inliner.h" -#include "../ssa/address_canonizer.h" +#include /*******************************************************************\ diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index b895f14ff..2c94f1c05 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -36,7 +36,7 @@ class heap_domaint:public domaint const namespacet &_ns): domaint(_domain_number, _renaming_map, _ns) { - make_template(var_specs, _ns); + make_template(var_specs, ns); } struct template_rowt diff --git a/src/domains/strategy_solver_heap.h b/src/domains/strategy_solver_heap.h index 73f21f4af..51435396d 100644 --- a/src/domains/strategy_solver_heap.h +++ b/src/domains/strategy_solver_heap.h @@ -8,7 +8,7 @@ Author: Viktor Malik #ifndef CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_H #define CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_H -#include "../ssa/local_ssa.h" +#include #include "strategy_solver_base.h" #include "heap_domain.h" #include "template_generator_base.h" diff --git a/src/solver/summarizer_fw.cpp b/src/solver/summarizer_fw.cpp index 914d19289..27f8dd1da 100644 --- a/src/solver/summarizer_fw.cpp +++ b/src/solver/summarizer_fw.cpp @@ -15,14 +15,9 @@ Author: Peter Schrammel #include #include "summarizer_fw.h" -#include "summary_db.h" #include #include -#include - -#include -#include // #define SHOW_WHOLE_RESULT diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 24a9a2a9f..23d9d29c2 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -18,12 +18,10 @@ Author: Daniel Kroening, kroening@kroening.com #include #include #include -#include #include #include "local_ssa.h" -#include "malloc_ssa.h" #include "ssa_dereference.h" #include "address_canonizer.h" @@ -157,7 +155,8 @@ void local_SSAt::get_globals( { const symbolt *symbol; irep_idt ptr_obj_id=root_obj.get(ID_ptr_object); - if(ns.lookup(ptr_obj_id, symbol)) continue; + if(ns.lookup(ptr_obj_id, symbol)) + continue; } if(rhs_value) @@ -1057,6 +1056,34 @@ exprt local_SSAt::read_rhs_rec(const exprt &expr, locationt loc) const return tmp; } +#if 0 + // Argument is a struct-typed ssa object? + // May need to split up into members. + const typet &type=ns.follow(expr.type()); + + if(type.id()==ID_struct) + { + // build struct constructor + struct_exprt result(expr.type()); + + const struct_typet &struct_type=to_struct_type(type); + const struct_typet::componentst &components=struct_type.components(); + + result.operands().resize(components.size()); + + for(struct_typet::componentst::const_iterator + it=components.begin(); + it!=components.end(); + it++) + { + result.operands()[it-components.begin()]= + read_rhs(member_exprt(expr, it->get_name(), it->type()), loc); + } + + return result; + } +#endif + // is this an object we track? if(ssa_objects.objects.find(object)!= ssa_objects.objects.end()) @@ -1382,27 +1409,6 @@ Function: local_SSAt::output void local_SSAt::output(std::ostream &out) const { - out << "params:"; - for (auto ¶m : params) - { - out << " " << from_expr(param); - } - out << '\n'; - - out << "globals in:"; - for (auto &glob : globals_in) - { - out << " " << from_expr(glob); - } - out << '\n'; - - out << "globals out:"; - for (auto &glob : globals_out) - { - out << " " << from_expr(glob); - } - out << "\n\n"; - for(nodest::const_iterator n_it=nodes.begin(); n_it!=nodes.end(); n_it++) @@ -1631,18 +1637,6 @@ decision_proceduret &operator<<( dest << *c_it; } } - -// for (auto &obj : src.unknown_objs) -// { -// const typet &obj_type = src.ns.follow(obj.type()); -// if (obj_type.id() == ID_struct) -// { -// for (auto &component : to_struct_type(obj_type).components()) -// { -// dest << src.unknown_obj_eq(obj, component); -// } -// } -// } #endif return dest; } @@ -1684,6 +1678,20 @@ incremental_solvert &operator<<( 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 @@ -1697,18 +1705,6 @@ incremental_solvert &operator<<( dest << *c_it; } } - -// for (auto &obj : src.unknown_objs) -// { -// const typet &obj_type = src.ns.follow(obj.type()); -// if (obj_type.id() == ID_struct) -// { -// for (auto &component : to_struct_type(obj_type).components()) -// { -// dest << src.unknown_obj_eq(obj, component); -// } -// } -// } #endif return dest; } @@ -1871,7 +1867,9 @@ Function: local_SSAt::collect_iterators_lhs \*******************************************************************/ -void local_SSAt::collect_iterators_lhs(const ssa_objectt &object, local_SSAt::locationt loc) +void local_SSAt::collect_iterators_lhs( + const ssa_objectt &object, + local_SSAt::locationt loc) { if(is_iterator(object.get_root_object()) && object.get_root_object().id()==ID_symbol) @@ -1910,8 +1908,10 @@ void local_SSAt::new_iterator_access( ID_it_init_value_level); const exprt init_pointer=get_pointer(expr.compound(), init_value_level-1); - list_iteratort iterator(to_symbol_expr(pointer_rhs), init_pointer, - get_iterator_fields(expr.compound())); + list_iteratort iterator( + to_symbol_expr(pointer_rhs), + init_pointer, + get_iterator_fields(expr.compound())); auto it=iterators.insert(iterator); it.first->add_access(expr, inst_loc_number); diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index e47f2126a..f46050310 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -12,7 +12,6 @@ Author: Peter Schrammel #include #include "ssa_inliner.h" -#include "ssa_dereference.h" /*******************************************************************\ diff --git a/src/ssa/ssa_object.cpp b/src/ssa/ssa_object.cpp index b8bbeed52..0ba150241 100644 --- a/src/ssa/ssa_object.cpp +++ b/src/ssa/ssa_object.cpp @@ -18,7 +18,6 @@ Author: Daniel Kroening, kroening@kroening.com #include #include "ssa_object.h" -#include "local_ssa.h" /*******************************************************************\ @@ -288,7 +287,7 @@ void ssa_objectst::collect_objects( } // Add new objects created within the function - local_SSAt::locationt exit=--(src.body.instructions.end()); + goto_programt::const_targett exit=--(src.body.instructions.end()); if(heap_analysis.has_location(exit)) { const std::list &new_objects= From 66810a78904c3df5cdec6c0c31498f1df0b328e4 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 1 Sep 2017 12:48:29 +0200 Subject: [PATCH 090/322] Improved formatting. Follow instructions in comments for the PR. --- src/2ls/2ls_parse_options.cpp | 23 ++++---- src/domains/heap_domain.cpp | 86 +++++++++++++--------------- src/domains/heap_domain.h | 10 ++-- src/domains/heap_interval_domain.h | 15 +++-- src/domains/list_iterator.cpp | 8 +-- src/domains/list_iterator.h | 10 ++-- src/domains/strategy_solver_heap.cpp | 4 +- src/ssa/local_ssa.cpp | 2 +- src/ssa/local_ssa.h | 2 +- src/ssa/malloc_ssa.cpp | 11 ++-- src/ssa/ssa_dereference.cpp | 14 +++-- src/ssa/ssa_heap_domain.cpp | 53 ++++++++++------- src/ssa/ssa_inliner.cpp | 7 ++- src/ssa/ssa_inliner.h | 6 +- src/ssa/ssa_object.cpp | 6 +- src/ssa/ssa_object.h | 27 +++++---- src/ssa/ssa_value_set.cpp | 3 +- 17 files changed, 158 insertions(+), 129 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 063eb40a5..11e8c2d6e 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -75,8 +75,8 @@ Function: twols_parse_optionst::twols_parse_optionst \*******************************************************************/ twols_parse_optionst::twols_parse_optionst(int argc, const char **argv): -parse_options_baset(TWOLS_OPTIONS, argc, argv), -language_uit(cmdline, ui_message_handler), + parse_options_baset(TWOLS_OPTIONS, argc, argv), + language_uit(cmdline, ui_message_handler), ui_message_handler(cmdline, "2LS " TWOLS_VERSION), recursion_detected(false), threads_detected(false) @@ -193,11 +193,11 @@ void twols_parse_optionst::get_command_line_options(optionst &options) options.set_option("equalities", true); options.set_option("std-invariants", true); } - else if (cmdline.isset("heap")) + else if(cmdline.isset("heap")) { options.set_option("heap", true); } - else if (cmdline.isset("heap-interval")) + else if(cmdline.isset("heap-interval")) { options.set_option("heap-interval", true); } @@ -447,7 +447,7 @@ int twols_parse_optionst::doit() Forall_goto_program_instructions(i_it, body) { if(i_it->is_assert()) - i_it->type=goto_program_instruction_typet::ASSUME; + i_it->type=goto_program_instruction_typet::ASSUME; } } } @@ -794,8 +794,8 @@ void twols_parse_optionst::show_stats( const code_assignt &assign=to_code_assign(instruction.code); expr_stats_rec(assign.lhs(), stats); expr_stats_rec(assign.rhs(), stats); + break; } - break; case ASSUME: expr_stats_rec(instruction.guard, stats); break; @@ -1129,16 +1129,16 @@ bool twols_parse_optionst::process_goto_program( #if 1 // Find, inline and remove malloc function - //TODO: find a better place for that + // TODO: find a better place for that Forall_goto_functions(it, goto_model.goto_functions) { - if (it->first == "malloc" || it->first == "free") + if(it->first=="malloc" || it->first=="free") it->second.type.set(ID_C_inlined, true); } goto_partial_inline(goto_model, ui_message_handler, 0); Forall_goto_functions(it, goto_model.goto_functions) { - if (it->first == "malloc" || it->first == "free") + if(it->first=="malloc" || it->first=="free") it->second.body.clear(); } #endif @@ -1157,7 +1157,7 @@ bool twols_parse_optionst::process_goto_program( goto_model.goto_functions.compute_loop_numbers(); // Replace malloc - replace_malloc(goto_model,""); + replace_malloc(goto_model, ""); // remove loop heads from function entries remove_loops_in_entry(goto_model); @@ -1357,8 +1357,8 @@ void twols_parse_optionst::report_success() xml.data="SUCCESS"; std::cout << xml; std::cout << std::endl; + break; } - break; default: assert(false); @@ -1667,6 +1667,7 @@ void twols_parse_optionst::help() " --heap use heap domain\n" " --zones use zone domain\n" " --octagons use octagon domain\n" + " --heap-interval use heap domain with interval domain for values\n" " --enum-solver use solver based on model enumeration\n" " --binsearch-solver use solver based on binary search\n" " --arrays do not ignore array contents\n" diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 848c7e35a..5a32e67d2 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -537,7 +537,8 @@ int heap_domaint::get_symbol_loc(const exprt &expr) { assert(expr.id()==ID_symbol); std::string expr_id=id2string(to_symbol_expr(expr).get_identifier()); - if(expr_id.find('#')==std::string::npos) return -1; + if(expr_id.find('#')==std::string::npos) + return -1; std::string loc_str=expr_id.substr(expr_id.find_last_not_of("0123456789")+1); assert(!loc_str.empty()); return std::stoi(loc_str); @@ -545,26 +546,6 @@ int heap_domaint::get_symbol_loc(const exprt &expr) /*******************************************************************\ -Function: heap_domaint::get_base_name - - Inputs: Symbol expression. - - Outputs: Base name of a symbol (without suffix with location number). - - Purpose: Get base name of a symbol. - -\*******************************************************************/ - -std::string heap_domaint::get_base_name(const exprt &expr) -{ - assert(expr.id()==ID_symbol); - std::string result=id2string(to_symbol_expr(expr).get_identifier()); - result=result.substr(0, result.find_last_of('#')); - return result; -} - -/*******************************************************************\ - Function: heap_domaint::stack_row_valuet::get_row_expr Inputs: templ_expr Template expression @@ -590,8 +571,9 @@ exprt heap_domaint::stack_row_valuet::get_row_expr(const vart &templ_expr, exprt::operandst result; for(const exprt &pt : points_to) { - result.push_back(equal_exprt(templ_expr, templ_expr.type()==pt.type() ? - pt : address_of_exprt(pt))); + result.push_back(equal_exprt( + templ_expr, + templ_expr.type()==pt.type() ? pt : address_of_exprt(pt))); } return disjunction(result); } @@ -634,10 +616,12 @@ Function: heap_domaint::heap_row_valuet::get_row_expr \*******************************************************************/ -exprt heap_domaint::heap_row_valuet::get_row_expr(const vart &templ_expr_, - bool rename_templ_expr) const +exprt heap_domaint::heap_row_valuet::get_row_expr( + const vart &templ_expr_, + bool rename_templ_expr) const { - if(nondet) return true_exprt(); + if(nondet) + return true_exprt(); exprt templ_expr=templ_expr_; if(rename_templ_expr) @@ -680,7 +664,8 @@ exprt heap_domaint::heap_row_valuet::get_row_expr(const vart &templ_expr_, for(const dyn_objt &obj2 : path.dyn_objects) { // o'.m = o'' - steps_expr.push_back(equal_exprt(member_expr, address_of_exprt(obj2.first))); + steps_expr.push_back( + equal_exprt(member_expr, address_of_exprt(obj2.first))); } path_expr.push_back(and_exprt(equ_exprt, disjunction(steps_expr))); @@ -716,8 +701,8 @@ bool heap_domaint::heap_row_valuet::add_points_to(const exprt &dest) } else { - const dyn_objt through=self_linkage ? dyn_obj : std::make_pair(nil_exprt(), - nil_exprt()); + const dyn_objt through= + self_linkage ? dyn_obj : std::make_pair(nil_exprt(), nil_exprt()); return add_path(dest, through); } } @@ -960,8 +945,9 @@ Function: heap_domaint::heap_row_valuet::rename_outheap exprt heap_domaint::heap_row_valuet::rename_outheap(const symbol_exprt &expr) { const std::string id=id2string(expr.get_identifier()); - return symbol_exprt(id.substr(0, id.rfind("lb"))+id.substr(id.rfind("lb")+2), - expr.type()); + return symbol_exprt( + id.substr(0, id.rfind("lb"))+id.substr(id.rfind("lb")+2), + expr.type()); } /*******************************************************************\ @@ -1078,8 +1064,10 @@ void heap_domaint::bind_iterators( const exprt binding=equal_exprt(new_value, old_value); access_binding=or_exprt(access_binding, binding); - add_new_heap_row_spec(old_value, (unsigned) access.location, - binding); + add_new_heap_row_spec( + old_value, + static_cast(access.location), + binding); } } } @@ -1222,7 +1210,7 @@ Function: heap_domaint::get_iterator_bindings \*******************************************************************/ -const exprt heap_domaint::get_iterator_bindings() const +exprt heap_domaint::get_iterator_bindings() const { return conjunction(iterator_bindings); } @@ -1239,7 +1227,7 @@ Function: heap_domaint::get_aux_bindings \*******************************************************************/ -const exprt heap_domaint::get_aux_bindings() const +exprt heap_domaint::get_aux_bindings() const { return conjunction(aux_bindings); } @@ -1256,7 +1244,7 @@ Function: heap_domaint::get_input_bindings \*******************************************************************/ -const exprt heap_domaint::get_input_bindings() const +exprt heap_domaint::get_input_bindings() const { return and_exprt(get_iterator_bindings(), get_aux_bindings()); } @@ -1333,9 +1321,13 @@ const exprt heap_domaint::iterator_access_bindings( else if(access.location!=list_iteratort::IN_LOC) { add_new_heap_row_spec( - recursive_member_symbol(r, access.fields.back(), list_iteratort::IN_LOC, - ns), - (unsigned) access.location, conjunction(guards)); + recursive_member_symbol( + r, + access.fields.back(), + list_iteratort::IN_LOC, + ns), + static_cast(access.location), + conjunction(guards)); } guards.pop_back(); @@ -1370,7 +1362,8 @@ const std::set heap_domaint::reachable_objects( { std::set result; - if(!(src.id()==ID_symbol || src.id()==ID_member)) return result; + if(!(src.id()==ID_symbol || src.id()==ID_member)) + return result; std::set pointed_objs; if(src.id()==ID_member && to_member_expr(src).compound().get_bool(ID_pointed)) @@ -1404,18 +1397,21 @@ const std::set heap_domaint::reachable_objects( } } - for(unsigned i=0; i reachable_objs=collect_preconditions_rec( - obj_member, precondition); + obj_member, + precondition); for(const exprt &reachable : reachable_objs) { if(reachable.id()==ID_address_of) diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index 2c94f1c05..169c1afd5 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -238,9 +238,9 @@ class heap_domaint:public domaint // Getters for protected fields const std::list get_new_heap_vars(); - const exprt get_iterator_bindings() const; - const exprt get_aux_bindings() const; - const exprt get_input_bindings() const; + exprt get_iterator_bindings() const; + exprt get_aux_bindings() const; + exprt get_input_bindings() const; protected: templatet templ; @@ -267,7 +267,7 @@ class heap_domaint:public domaint heap_row_spect( const symbol_exprt &expr, - unsigned int location_number, + unsigned location_number, const exprt &post_guard): expr(expr), location_number(location_number), post_guard(post_guard) {} @@ -335,8 +335,6 @@ class heap_domaint:public domaint // Utility functions static int get_symbol_loc(const exprt &expr); - static std::string get_base_name(const exprt &expr); - friend class strategy_solver_heapt; }; diff --git a/src/domains/heap_interval_domain.h b/src/domains/heap_interval_domain.h index e2e8e321e..8699873e0 100644 --- a/src/domains/heap_interval_domain.h +++ b/src/domains/heap_interval_domain.h @@ -13,9 +13,9 @@ Author: Viktor Malik #include "tpolyhedra_domain.h" #include "heap_domain.h" -class heap_interval_domaint : public domaint +class heap_interval_domaint:public domaint { - public: +public: heap_domaint heap_domain; tpolyhedra_domaint interval_domain; @@ -33,7 +33,7 @@ class heap_interval_domaint : public domaint class heap_interval_valuet:public valuet { - public: + public: heap_domaint::heap_valuet heap_value; tpolyhedra_domaint::templ_valuet interval_value; }; @@ -46,10 +46,13 @@ class heap_interval_domaint : public domaint const namespacet &ns) const override; virtual void output_domain( - std::ostream &out, const namespacet &ns) const override; + std::ostream &out, + const namespacet &ns) const override; - virtual void project_on_vars(valuet &value, const var_sett &vars, exprt &result) override; + virtual void project_on_vars( + valuet &value, + const var_sett &vars, + exprt &result) override; }; - #endif // CPROVER_2LS_DOMAINS_HEAP_INTERVAL_DOMAIN_H diff --git a/src/domains/list_iterator.cpp b/src/domains/list_iterator.cpp index be6e3e4cb..e26f1d153 100644 --- a/src/domains/list_iterator.cpp +++ b/src/domains/list_iterator.cpp @@ -26,7 +26,7 @@ Function: list_iteratort::add_access void list_iteratort::add_access( const member_exprt &expr, - int location_number) const + unsigned location_number) const { assert(expr.compound().get_bool(ID_iterator) && expr.compound().get_bool(ID_pointed)); @@ -63,7 +63,7 @@ const symbol_exprt list_iteratort::access_symbol_expr( unsigned level, const namespacet &ns) const { - int location=level==access.fields.size()-1 ? access.location : IN_LOC; + unsigned location=level==access.fields.size()-1 ? access.location : IN_LOC; if(level==0) { return recursive_member_symbol( @@ -121,7 +121,7 @@ Function: recursive_member_symbol const symbol_exprt recursive_member_symbol( const symbol_exprt &object, const irep_idt &field, - const int loc_num, + const unsigned loc_num, const namespacet &ns) { typet type=nil_typet(); @@ -163,7 +163,7 @@ equal_exprt list_iteratort::accesst::binding( const unsigned level, const namespacet &ns) const { - int loc=level==fields.size()-1 ? location : IN_LOC; + unsigned loc=level==fields.size()-1 ? location : IN_LOC; return equal_exprt( recursive_member_symbol(lhs, fields.at(level), loc, ns), recursive_member_symbol(rhs, fields.at(level), loc, ns)); diff --git a/src/domains/list_iterator.h b/src/domains/list_iterator.h index a5f2cf41f..9f7ab96d5 100644 --- a/src/domains/list_iterator.h +++ b/src/domains/list_iterator.h @@ -10,7 +10,7 @@ Author: Viktor Malik #ifndef CPROVER_2LS_DOMAINS_LIST_ITERATOR_H #define CPROVER_2LS_DOMAINS_LIST_ITERATOR_H - +#include #include #include @@ -18,7 +18,7 @@ class list_iteratort { public: // No location (used for input variables) - static const int IN_LOC=-1; + static const unsigned IN_LOC=std::numeric_limits::max(); /*******************************************************************\ Access to an object from a list iterator. @@ -33,7 +33,7 @@ class list_iteratort { public: std::vector fields; - int location; + unsigned location; equal_exprt binding( const symbol_exprt &lhs, const symbol_exprt &rhs, @@ -59,7 +59,7 @@ class list_iteratort return std::tie(pointer, fields) #include "strategy_solver_heap.h" /*******************************************************************\ @@ -272,7 +273,8 @@ int strategy_solver_heapt::find_member_row( const domaint::kindt &kind) { assert(obj.id()==ID_symbol); - std::string obj_id=heap_domain.get_base_name(obj); + std::string obj_id=id2string( + ssa_inlinert::get_original_identifier(to_symbol_expr(obj))); int result=-1; int max_loc=-1; diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 23d9d29c2..09b4c2798 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -1895,7 +1895,7 @@ Function: local_SSAt::new_iterator_access void local_SSAt::new_iterator_access( const member_exprt &expr, local_SSAt::locationt loc, - int inst_loc_number) + unsigned inst_loc_number) { assert(is_iterator(expr.compound())); diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 4ff55c988..977e75032 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -179,7 +179,7 @@ class local_SSAt void new_iterator_access( const member_exprt &expr, locationt loc, - int inst_loc_number); + unsigned inst_loc_number); exprt unknown_obj_eq( const symbol_exprt &obj, diff --git a/src/ssa/malloc_ssa.cpp b/src/ssa/malloc_ssa.cpp index 28dce7ebe..0a8b0803c 100644 --- a/src/ssa/malloc_ssa.cpp +++ b/src/ssa/malloc_ssa.cpp @@ -229,7 +229,7 @@ void replace_malloc( exprt malloc_size=nil_exprt(); Forall_goto_program_instructions(i_it, f_it->second.body) { - if (i_it->is_assign()) + if(i_it->is_assign()) { code_assignt &code_assign=to_code_assign(i_it->code); if(code_assign.lhs().id()==ID_symbol) @@ -244,10 +244,13 @@ void replace_malloc( lhs_id=="__builtin_alloca::alloca_size") malloc_size=code_assign.rhs(); } - replace_malloc_rec(code_assign.rhs(), suffix, - goto_model.symbol_table, malloc_size, i_it->location_number); + replace_malloc_rec( + code_assign.rhs(), + suffix, + goto_model.symbol_table, + malloc_size, + i_it->location_number); } } } } - diff --git a/src/ssa/ssa_dereference.cpp b/src/ssa/ssa_dereference.cpp index 0f487fe0f..32450d582 100644 --- a/src/ssa/ssa_dereference.cpp +++ b/src/ssa/ssa_dereference.cpp @@ -319,16 +319,18 @@ exprt dereference_rec( { if(src.id()==ID_dereference) { - const exprt &pointer=to_dereference_expr(src).pointer(); - exprt pointer_deref= - dereference(pointer, ssa_value_domain, nondet_prefix, ns); + const exprt &pointer=dereference_rec( + to_dereference_expr(src).pointer(), + ssa_value_domain, + nondet_prefix, + ns); const typet &pointed_type=ns.follow(pointer.type().subtype()); const ssa_value_domaint::valuest values=ssa_value_domain(pointer, ns); exprt result; - if (values.value_set.empty()) + if(values.value_set.empty()) { result=pointed_object(pointer, ns); } @@ -340,7 +342,7 @@ exprt dereference_rec( { std::string dyn_type_name=pointed_type.id_string(); if(pointed_type.id()==ID_struct) - dyn_type_name+= "_"+id2string(to_struct_type(pointed_type).get_tag()); + dyn_type_name+="_"+id2string(to_struct_type(pointed_type).get_tag()); irep_idt identifier="ssa::"+dyn_type_name+"_obj$unknown"; result=symbol_exprt(identifier, src.type()); @@ -351,7 +353,7 @@ exprt dereference_rec( result=ssa_alias_value(src, (it++)->get_expr(), ns); } - for (; it!=values.value_set.end(); ++it) + for(; it!=values.value_set.end(); ++it) { exprt guard=ssa_alias_guard(src, it->get_expr(), ns); exprt value=ssa_alias_value(src, it->get_expr(), ns); diff --git a/src/ssa/ssa_heap_domain.cpp b/src/ssa/ssa_heap_domain.cpp index 7ede3fb47..68bc6bc9f 100644 --- a/src/ssa/ssa_heap_domain.cpp +++ b/src/ssa/ssa_heap_domain.cpp @@ -22,7 +22,8 @@ Function: ssa_heap_domaint::transform \*******************************************************************/ void ssa_heap_domaint::transform( - const namespacet &ns, domain_baset::locationt from, + const namespacet &ns, + domain_baset::locationt from, domain_baset::locationt to) { if(from->is_assign()) @@ -122,8 +123,9 @@ bool ssa_heap_domaint::merge( else { unsigned long old_size=value_map[other_value.first].size(); - value_map[other_value.first].insert(other_value.second.begin(), - other_value.second.end()); + value_map[other_value.first].insert( + other_value.second.begin(), + other_value.second.end()); result=old_size!=value_map[other_value.first].size(); } } @@ -151,12 +153,13 @@ bool ssa_heap_domaint::merge( { unsigned long old_size=objects[other_object.first].size(); std::set intersection; - std::set_intersection(objects[other_object.first].begin(), - objects[other_object.first].end(), - other_object.second.begin(), - other_object.second.end(), - std::inserter( - intersection, intersection.begin())); + std::set_intersection( + objects[other_object.first].begin(), + objects[other_object.first].end(), + other_object.second.begin(), + other_object.second.end(), + std::inserter( + intersection, intersection.begin())); if(!intersection.empty()) objects[other_object.first]=intersection; else @@ -171,7 +174,7 @@ bool ssa_heap_domaint::merge( { for(auto &o : other_objects) { - unsigned long old_size=objects[o.first].size(); + std::size_t old_size=objects[o.first].size(); objects[o.first]=o.second; if(old_size!=objects[o.first].size()) result=true; @@ -180,7 +183,7 @@ bool ssa_heap_domaint::merge( function_map[f.first].params=f.second.params; - unsigned long old_size=function_map[f.first].modified_objects.size(); + std::size_t old_size=function_map[f.first].modified_objects.size(); function_map[f.first].modified_objects.insert( f.second.modified_objects.begin(), f.second.modified_objects.end()); @@ -263,13 +266,19 @@ bool ssa_heap_domaint::is_function_output( { if(expr.id()==ID_dereference) { - return is_function_output(to_dereference_expr(expr).pointer(), function, ns, - true); + return is_function_output( + to_dereference_expr(expr).pointer(), + function, + ns, + true); } else if(expr.id()==ID_member) { - return is_function_output(to_member_expr(expr).compound(), function, ns, - in_deref); + return is_function_output( + to_member_expr(expr).compound(), + function, + ns, + in_deref); } else if(expr.id()==ID_symbol) { @@ -598,7 +607,7 @@ const exprt ssa_heap_domaint::function_infot::corresponding_expr( { const irep_idt expr_id=to_symbol_expr(expr).get_identifier(); exprt result=expr; - for(unsigned i=0; i callee_objects=heap_domain.new_objects(fname); - const std::list caller_objects=heap_domain.new_caller_objects( - fname, loc); + const std::list callee_objects= + heap_domain.new_objects(fname); + const std::list caller_objects= + heap_domain.new_caller_objects(fname, loc); auto callee_it=callee_objects.begin(); for(auto caller_it=caller_objects.begin(); caller_it!=caller_objects.end(); diff --git a/src/ssa/ssa_inliner.h b/src/ssa/ssa_inliner.h index 4d0278ca2..08e1e6347 100644 --- a/src/ssa/ssa_inliner.h +++ b/src/ssa/ssa_inliner.h @@ -140,8 +140,10 @@ class ssa_inlinert:public messaget const local_SSAt::var_listt ¶ms, 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 &SSA, - const summaryt &summary, const local_SSAt::locationt &loc); + const local_SSAt::var_sett &cs_globals_out, + const local_SSAt &SSA, + const summaryt &summary, + const local_SSAt::locationt &loc); exprt get_replace_globals_out( const local_SSAt::var_sett &cs_globals_in, const local_SSAt::var_sett &cs_globals_out, diff --git a/src/ssa/ssa_object.cpp b/src/ssa/ssa_object.cpp index 0ba150241..caae37ed8 100644 --- a/src/ssa/ssa_object.cpp +++ b/src/ssa/ssa_object.cpp @@ -241,7 +241,11 @@ void collect_objects_rec( (symbol->is_parameter || !symbol->is_procedure_local()))) { collect_ptr_objects( - ssa_object.symbol_expr(), ns, objects, literals, false); + ssa_object.symbol_expr(), + ns, + objects, + literals, + false); } } } diff --git a/src/ssa/ssa_object.h b/src/ssa/ssa_object.h index 80384a03a..0d2cb18e6 100644 --- a/src/ssa/ssa_object.h +++ b/src/ssa/ssa_object.h @@ -86,28 +86,30 @@ class ssa_objectt return get_root_object_rec(expr); } - inline bool is_unknown_obj() + bool is_unknown_obj() { - std::string id_str = id2string(identifier); - return id_str.find("$unknown") != std::string::npos; + std::string id_str=id2string(identifier); + return id_str.find("$unknown")!=std::string::npos; } - inline void set_flag(const irep_idt flag, bool value) + void set_flag(const irep_idt flag, bool value) { expr.set(flag, value); } - inline void set_iterator(const irep_idt &pointer_id, const std::vector &fields) + void set_iterator( + const irep_idt &pointer_id, + const std::vector &fields) { - assert(expr.id() == ID_symbol && expr.get_bool(ID_pointed)); + assert(expr.id()==ID_symbol && expr.get_bool(ID_pointed)); expr.set(ID_iterator, true); expr.set(ID_it_pointer, pointer_id); set_iterator_fields(expr, fields); expr.set(ID_it_init_value, to_symbol_expr(expr).get_identifier()); expr.set(ID_it_init_value_level, expr.get(ID_pointed_level)); - const irep_idt new_id = id2string(pointer_id) + id2string("'it"); + const irep_idt new_id=id2string(pointer_id)+id2string("'it"); to_symbol_expr(expr).set_identifier(new_id); - identifier = identifiert(new_id); + identifier=identifiert(new_id); } protected: @@ -131,10 +133,11 @@ class ssa_objectst const ssa_heap_analysist &heap_analysis; - ssa_objectst(const goto_functionst::goto_functiont &goto_function, - const namespacet &ns, - const ssa_heap_analysist &_heap_analysis) - : heap_analysis(_heap_analysis) + ssa_objectst( + const goto_functionst::goto_functiont &goto_function, + const namespacet &ns, + const ssa_heap_analysist &_heap_analysis): + heap_analysis(_heap_analysis) { collect_objects(goto_function, ns); categorize_objects(goto_function, ns); diff --git a/src/ssa/ssa_value_set.cpp b/src/ssa/ssa_value_set.cpp index 663ec2e9b..10f8de4bf 100644 --- a/src/ssa/ssa_value_set.cpp +++ b/src/ssa/ssa_value_set.cpp @@ -546,7 +546,8 @@ Function: ssa_value_domaint::valuest::merge \*******************************************************************/ bool ssa_value_domaint::valuest::merge( - const valuest &src, bool is_loop_back, + const valuest &src, + bool is_loop_back, const irep_idt &object_id) { bool result=false; From 583db78b0d6d0df09b69a73e8437794d1f8edf5b Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 7 Sep 2017 12:27:40 +0200 Subject: [PATCH 091/322] Fix in ssa_inliner: use utility function for obtaining identifier of pointer object. Instead of working with identifier string and stripping away 'obj suffix, we create an utility function for getting identifier of pointed objects in ssa_pointed_objects. --- src/ssa/ssa_inliner.cpp | 4 ++-- src/ssa/ssa_pointed_objects.cpp | 18 ++++++++++++++++++ src/ssa/ssa_pointed_objects.h | 1 + 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index 7ee1e5673..a35f7b502 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -949,8 +949,8 @@ void ssa_inlinert::rename(exprt &expr) if(obj.id()==ID_symbol) { const std::string &obj_id=id2string(to_symbol_expr(obj).get_identifier()); - if(obj_id.compare(obj_id.length()-4, 4, "'obj")==0) - id=obj_id.substr(0, obj_id.find_last_of("'")); + if(is_pointed(obj)) + id = get_pointer_id(obj); else id=id2string(obj_id)+"'addr"; diff --git a/src/ssa/ssa_pointed_objects.cpp b/src/ssa/ssa_pointed_objects.cpp index ceab4b2f4..8e3ea25ec 100644 --- a/src/ssa/ssa_pointed_objects.cpp +++ b/src/ssa/ssa_pointed_objects.cpp @@ -482,6 +482,24 @@ const exprt get_pointer_root(const exprt &expr, unsigned level) return pointer; } +const irep_idt get_pointer_id(const exprt &expr) +{ + exprt pointer=get_pointer(expr, pointed_level(expr)-1); + if(pointer.id()==ID_symbol) + return to_symbol_expr(pointer).get_identifier(); + else if(pointer.id()==ID_member) + { + const member_exprt &member=to_member_expr(pointer); + if(member.compound().id()==ID_symbol) + { + return id2string(to_symbol_expr(member.compound()).get_identifier())+ + "."+ + id2string(member.get_component_name()); + } + } + return irep_idt(); +} + /*******************************************************************\ Function: iterator_to_initial_id diff --git a/src/ssa/ssa_pointed_objects.h b/src/ssa/ssa_pointed_objects.h index af88da67e..f9492a1ea 100644 --- a/src/ssa/ssa_pointed_objects.h +++ b/src/ssa/ssa_pointed_objects.h @@ -40,6 +40,7 @@ const std::vector pointer_fields(const exprt &expr, const unsigned fro const exprt get_pointer(const exprt &expr, unsigned level); const exprt get_pointer_root(const exprt &expr, unsigned level); +const irep_idt get_pointer_id(const exprt &expr); void copy_pointed_info(exprt &dest, const exprt &src, const unsigned max_level); void copy_pointed_info(exprt &dest, const exprt &src); From e7e390cd328beb14404d9bf86484b2031311963b Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 22 Sep 2017 09:13:55 +0200 Subject: [PATCH 092/322] Repair code formatting for heap branch so that cpplint succeedes. --- regression/Makefile | 3 +- regression/heap/sll_simple/main.c | 48 ++++ regression/heap/sll_simple/test.desc | 6 + src/2ls/2ls_parse_options.cpp | 7 +- src/2ls/2ls_parse_options.h | 6 +- src/2ls/preprocessing_util.cpp | 32 +-- src/2ls/show.cpp | 28 ++- src/2ls/summary_checker_base.cpp | 2 +- src/2ls/summary_checker_base.h | 3 +- src/2ls/summary_checker_bmc.h | 5 +- src/domains/heap_domain.cpp | 122 +++++---- src/domains/heap_domain.h | 8 +- src/domains/list_iterator.cpp | 20 +- src/domains/list_iterator.h | 6 +- src/domains/ssa_analyzer.cpp | 24 +- src/domains/strategy_solver_heap.cpp | 38 +-- src/domains/strategy_solver_heap_interval.h | 8 +- src/domains/template_generator_base.cpp | 4 +- .../template_generator_callingcontext.cpp | 15 +- src/ssa/assignments.h | 17 +- src/ssa/local_ssa.cpp | 31 ++- src/ssa/local_ssa.h | 18 +- src/ssa/malloc_ssa.cpp | 2 - src/ssa/ssa_db.h | 1 - src/ssa/ssa_dereference.cpp | 2 + src/ssa/ssa_heap_domain.cpp | 14 +- src/ssa/ssa_inliner.cpp | 232 ++++++++++++------ src/ssa/ssa_inliner.h | 3 +- src/ssa/ssa_object.cpp | 3 +- src/ssa/ssa_pointed_objects.cpp | 40 +-- src/ssa/ssa_pointed_objects.h | 8 +- src/ssa/ssa_value_set.cpp | 35 +-- src/ssa/ssa_value_set.h | 20 +- 33 files changed, 523 insertions(+), 288 deletions(-) create mode 100644 regression/heap/sll_simple/main.c create mode 100644 regression/heap/sll_simple/test.desc diff --git a/regression/Makefile b/regression/Makefile index b22a878c1..78916c1c3 100644 --- a/regression/Makefile +++ b/regression/Makefile @@ -1,4 +1,5 @@ -DIRS = nontermination termination kiki preconditions interprocedural invariants +DIRS = heap nontermination termination kiki \ + preconditions interprocedural invariants test: $(foreach var,$(DIRS), make -C $(var) test;) diff --git a/regression/heap/sll_simple/main.c b/regression/heap/sll_simple/main.c new file mode 100644 index 000000000..56e995a4d --- /dev/null +++ b/regression/heap/sll_simple/main.c @@ -0,0 +1,48 @@ +#include + +struct item { + struct item *null; + struct item *next; + struct item *data; +}; + +struct item* alloc_or_die(void) +{ + struct item *pi = malloc(sizeof(*pi)); + if (!pi) + abort(); + + pi->null = NULL; + pi->data = malloc(sizeof(struct item)); +#if 1 + if (!pi->data) + abort(); +#endif + return pi; +} + +struct item* create_sll(void) +{ + struct item *sll = alloc_or_die(); + struct item *now = sll; + + // NOTE: running this on bare metal may cause the machine to swap a bit + do { + now->next = alloc_or_die(); + now->next->next = NULL; + now = now->next; + } while (__VERIFIER_nondet_int()); + + return sll; +} + +int main() +{ + struct item *sll = create_sll(); + + assert(sll); + assert(sll->next); + + return 0; +} + diff --git a/regression/heap/sll_simple/test.desc b/regression/heap/sll_simple/test.desc new file mode 100644 index 000000000..ed14b476a --- /dev/null +++ b/regression/heap/sll_simple/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap --inline --no-propagation +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 11e8c2d6e..976ec86af 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -522,7 +522,7 @@ int twols_parse_optionst::doit() heap_analysis(goto_model.goto_functions); add_dynamic_object_symbols(heap_analysis, goto_model); } - + try { std::unique_ptr checker; @@ -1063,7 +1063,8 @@ bool twols_parse_optionst::process_goto_program( try { status() << "Function Pointer Removal" << eom; - remove_function_pointers(goto_model, cmdline.isset("pointer-check")); + remove_function_pointers( + goto_model, cmdline.isset("pointer-check")); // do partial inlining if(options.get_bool_option("inline-partial")) @@ -1667,7 +1668,7 @@ void twols_parse_optionst::help() " --heap use heap domain\n" " --zones use zone domain\n" " --octagons use octagon domain\n" - " --heap-interval use heap domain with interval domain for values\n" + " --heap-interval use heap domain with interval domain for values\n" // NOLINT(*) " --enum-solver use solver based on model enumeration\n" " --binsearch-solver use solver based on binary search\n" " --arrays do not ignore array contents\n" diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index a992325af..52d866207 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -161,7 +161,7 @@ class twols_parse_optionst: void replace_types_rec(const replace_symbolt &replace_const, exprt &expr); exprt evaluate_casts_in_constants( const exprt &expr, - const typet& parent_type, + const typet &parent_type, bool &valid); void remove_multiple_dereferences(goto_modelt &goto_model); void remove_multiple_dereferences( @@ -177,7 +177,9 @@ class twols_parse_optionst: void remove_loops_in_entry(goto_modelt &goto_model); void create_dynamic_objects(goto_modelt &goto_model); void add_dynamic_object_rec(exprt &expr, symbol_tablet &symbol_table); - void add_dynamic_object_symbols(const ssa_heap_analysist &heap_analysis, goto_modelt &goto_model); + void add_dynamic_object_symbols( + const ssa_heap_analysist &heap_analysis, + goto_modelt &goto_model); }; #endif diff --git a/src/2ls/preprocessing_util.cpp b/src/2ls/preprocessing_util.cpp index b58d24afd..47d98a908 100644 --- a/src/2ls/preprocessing_util.cpp +++ b/src/2ls/preprocessing_util.cpp @@ -485,8 +485,8 @@ void twols_parse_optionst::remove_loops_in_entry(goto_modelt &goto_model) { Forall_goto_functions(f_it, goto_model.goto_functions) { - if (f_it->second.body_available() && - f_it->second.body.instructions.begin()->is_target()) + if(f_it->second.body_available() && + f_it->second.body.instructions.begin()->is_target()) { auto new_entry= f_it->second.body.insert_before(f_it->second.body.instructions.begin()); @@ -514,9 +514,9 @@ void twols_parse_optionst::create_dynamic_objects(goto_modelt &goto_model) { Forall_goto_program_instructions(i_it, f_it->second.body) { - if (i_it->is_assign()) + if(i_it->is_assign()) { - code_assignt &code_assign = to_code_assign(i_it->code); + code_assignt &code_assign=to_code_assign(i_it->code); add_dynamic_object_rec(code_assign.lhs(), goto_model.symbol_table); add_dynamic_object_rec(code_assign.rhs(), goto_model.symbol_table); } @@ -540,28 +540,28 @@ Function: twols_parse_optionst::add_dynamic_object_rec void twols_parse_optionst::add_dynamic_object_rec( exprt &expr, symbol_tablet &symbol_table) { - if (expr.id() == ID_symbol) + if (expr.id()==ID_symbol) { const symbolt &symbol= symbol_table.lookup(to_symbol_expr(expr).get_identifier()); - if (symbol.is_parameter && symbol.type.id() == ID_pointer) + if(symbol.is_parameter && symbol.type.id()==ID_pointer) { // New symbol symbolt object_symbol; - object_symbol.base_name = id2string(symbol.base_name) + "'obj"; - object_symbol.name = id2string(symbol.name) + "'obj"; - const typet &pointed_type = symbol.type.subtype(); + object_symbol.base_name=id2string(symbol.base_name)+"'obj"; + object_symbol.name=id2string(symbol.name)+"'obj"; + const typet &pointed_type=symbol.type.subtype(); // Follow pointed type - if (pointed_type.id() == ID_symbol) + if(pointed_type.id()==ID_symbol) { - const symbolt type_symbol = symbol_table.lookup( - to_symbol_type(pointed_type).get_identifier()); - object_symbol.type = type_symbol.type; + const symbolt type_symbol=symbol_table.lookup( + to_symbol_type(pointed_type).get_identifier()); + object_symbol.type=type_symbol.type; } else - object_symbol.type = pointed_type; - object_symbol.mode = ID_C; + object_symbol.type=pointed_type; + object_symbol.mode=ID_C; symbol_table.add(object_symbol); } @@ -569,7 +569,7 @@ void twols_parse_optionst::add_dynamic_object_rec( else { Forall_operands(it, expr) - add_dynamic_object_rec(*it, symbol_table); + add_dynamic_object_rec(*it, symbol_table); } } diff --git a/src/2ls/show.cpp b/src/2ls/show.cpp index 56bae8bb4..15336c99e 100644 --- a/src/2ls/show.cpp +++ b/src/2ls/show.cpp @@ -47,7 +47,11 @@ void show_assignments( ssa_objectst ssa_objects(goto_function, ns, heap_analysis); ssa_value_ait ssa_value_ai(goto_function, ns, heap_analysis); assignmentst assignments( - goto_function.body, ns, ssa_objects, ssa_value_ai, heap_analysis); + goto_function.body, + ns, + ssa_objects, + ssa_value_ai, + heap_analysis); assignments.output(ns, goto_function.body, out); } @@ -89,7 +93,7 @@ void show_assignments( out << ">>>> Function " << f_it->first << "\n"; show_assignments(f_it->second, ns, out, heap_analysis); - + out << "\n"; } } @@ -107,15 +111,20 @@ Function: show_defs \*******************************************************************/ -void show_defs(const goto_functionst::goto_functiont &goto_function, - const namespacet &ns, - std::ostream &out, - const ssa_heap_analysist &heap_analysis) +void show_defs( + const goto_functionst::goto_functiont &goto_function, + const namespacet &ns, + std::ostream &out, + const ssa_heap_analysist &heap_analysis) { ssa_objectst ssa_objects(goto_function, ns, heap_analysis); ssa_value_ait ssa_value_ai(goto_function, ns, heap_analysis); assignmentst assignments( - goto_function.body, ns, ssa_objects, ssa_value_ai, heap_analysis); + goto_function.body, + ns, + ssa_objects, + ssa_value_ai, + heap_analysis); ssa_ait ssa_analysis(assignments); ssa_analysis(goto_function, ns); ssa_analysis.output(ns, goto_function.body, out); @@ -159,7 +168,7 @@ void show_defs( out << ">>>> Function " << f_it->first << "\n"; show_defs(f_it->second, ns, out, heap_analysis); - + out << "\n"; } } @@ -612,9 +621,8 @@ void show_value_sets( out << ">>>> Function " << f_it->first << "\n"; show_value_set(f_it->second, ns, out, heap_analysis); - + out << "\n"; } } } - diff --git a/src/2ls/summary_checker_base.cpp b/src/2ls/summary_checker_base.cpp index 0c38ad113..63aa43f15 100644 --- a/src/2ls/summary_checker_base.cpp +++ b/src/2ls/summary_checker_base.cpp @@ -67,7 +67,7 @@ void summary_checker_baset::SSA_functions( ssa_db.create(f_it->first, f_it->second, ns, heap_analysis); local_SSAt &SSA=ssa_db.get(f_it->first); - + // simplify, if requested if(simplify) { diff --git a/src/2ls/summary_checker_base.h b/src/2ls/summary_checker_base.h index ebf170a37..8e37ad3c2 100644 --- a/src/2ls/summary_checker_base.h +++ b/src/2ls/summary_checker_base.h @@ -28,7 +28,8 @@ class graphml_witness_extt; class summary_checker_baset:public property_checkert { public: - summary_checker_baset(optionst &_options, const ssa_heap_analysist &_heap_analysis) : + summary_checker_baset( + optionst &_options, const ssa_heap_analysist &_heap_analysis): show_vcc(false), simplify(false), fixed_point(false), diff --git a/src/2ls/summary_checker_bmc.h b/src/2ls/summary_checker_bmc.h index ecb6c71c2..6821ceea7 100644 --- a/src/2ls/summary_checker_bmc.h +++ b/src/2ls/summary_checker_bmc.h @@ -14,8 +14,9 @@ Author: Peter Schrammel class summary_checker_bmct:public summary_checker_baset { public: - inline summary_checker_bmct(optionst &_options, const ssa_heap_analysist &heap_analysis) : - summary_checker_baset(_options, heap_analysis) + summary_checker_bmct( + optionst &_options, const ssa_heap_analysist &heap_analysis): + summary_checker_baset(_options, heap_analysis) { } diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 5a32e67d2..67effc3ad 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -33,7 +33,10 @@ void heap_domaint::initialize(domaint::valuet &value) val.emplace_back(new stack_row_valuet()); else if(templ_row.mem_kind==HEAP) val.emplace_back( - new heap_row_valuet(std::make_pair(templ_row.dyn_obj, templ_row.expr))); + new heap_row_valuet( + std::make_pair( + templ_row.dyn_obj, + templ_row.expr))); else assert(false); } @@ -175,8 +178,8 @@ void heap_domaint::make_not_post_constraints( { value_exprs[row]=templ[row].expr; rename(value_exprs[row]); - cond_exprs[row]=and_exprt(templ[row].aux_expr, not_exprt( - get_row_post_constraint(row, value[row]))); + const exprt row_expr=not_exprt(get_row_post_constraint(row, value[row])); + cond_exprs[row]=and_exprt(templ[row].aux_expr, row_expr); } } @@ -206,8 +209,8 @@ exprt heap_domaint::get_row_pre_constraint( if(k==OUTHEAP && row_value.empty()) return true_exprt(); - return implies_exprt( - templ_row.pre_guard, row_value.get_row_expr(templ_row.expr, false)); + const exprt row_expr=row_value.get_row_expr(templ_row.expr, false); + return implies_exprt(templ_row.pre_guard, row_expr); } /*******************************************************************\ @@ -232,9 +235,9 @@ exprt heap_domaint::get_row_post_constraint( if(templ_row.kind==IN) return true_exprt(); - exprt c=implies_exprt( - templ_row.post_guard, row_value.get_row_expr( - templ_row.expr, templ_row.kind==OUTHEAP)); + const exprt row_expr= + row_value.get_row_expr(templ_row.expr, templ_row.kind==OUTHEAP); + exprt c=implies_exprt(templ_row.post_guard, row_expr); if(templ_row.kind==LOOP) rename(c); return c; @@ -268,9 +271,11 @@ bool heap_domaint::add_transitivity( bool result=false; if(heap_val_from.add_all_paths( - heap_val_to, std::make_pair( - templ[to].dyn_obj, templ[to].expr))) + heap_val_to, + std::make_pair(templ[to].dyn_obj, templ[to].expr))) + { result=true; + } if(from!=to) { if(heap_val_to.add_pointed_by(from)) @@ -421,10 +426,11 @@ void heap_domaint::output_domain(std::ostream &out, const namespacet &ns) const } const vart &var=templ_row.expr; - out << i << ": " << from_expr(ns, "", var) - << (templ_row.mem_kind==STACK ? " --points_to--> Locations" - : " --paths--> Destinations") - << std::endl; + const std::string info= + templ_row.mem_kind==STACK + ? " --points_to--> Locations" + : " --paths--> Destinations"; + out << i << ": " << from_expr(ns, "", var) << info << std::endl; } } @@ -459,9 +465,8 @@ void heap_domaint::project_on_vars( const row_valuet &row_val=val[row]; if(templ_row.kind==LOOP) { - c.push_back( - implies_exprt( - templ_row.pre_guard, row_val.get_row_expr(templ_row.expr, false))); + const exprt row_expr=row_val.get_row_expr(templ_row.expr, false); + c.push_back(implies_exprt(templ_row.pre_guard, row_expr)); } else { @@ -557,8 +562,9 @@ Function: heap_domaint::stack_row_valuet::get_row_expr \*******************************************************************/ -exprt heap_domaint::stack_row_valuet::get_row_expr(const vart &templ_expr, - bool rename_templ_expr) const +exprt heap_domaint::stack_row_valuet::get_row_expr( + const vart &templ_expr, + bool rename_templ_expr) const { if(nondet) return true_exprt(); @@ -566,14 +572,15 @@ exprt heap_domaint::stack_row_valuet::get_row_expr(const vart &templ_expr, if(empty()) return false_exprt(); else - { + { // Points to expression exprt::operandst result; for(const exprt &pt : points_to) { - result.push_back(equal_exprt( - templ_expr, - templ_expr.type()==pt.type() ? pt : address_of_exprt(pt))); + result.push_back( + equal_exprt( + templ_expr, + templ_expr.type()==pt.type() ? pt : address_of_exprt(pt))); } return disjunction(result); } @@ -662,10 +669,12 @@ exprt heap_domaint::heap_row_valuet::get_row_expr( steps_expr.push_back(equal_exprt(member_expr, dest)); for(const dyn_objt &obj2 : path.dyn_objects) - { + { // o'.m = o'' steps_expr.push_back( - equal_exprt(member_expr, address_of_exprt(obj2.first))); + equal_exprt( + member_expr, + address_of_exprt(obj2.first))); } path_expr.push_back(and_exprt(equ_exprt, disjunction(steps_expr))); @@ -1055,12 +1064,20 @@ void heap_domaint::bind_iterators( if(value.id()==ID_address_of) { assert(to_address_of_expr(value).object().id()==ID_symbol); - const symbol_exprt &first_obj=to_symbol_expr( - to_address_of_expr(value).object()); - const symbol_exprt new_value=recursive_member_symbol( - first_obj, access.fields.back(), access.location, ns); - const symbol_exprt old_value=recursive_member_symbol( - first_obj, access.fields.back(), list_iteratort::IN_LOC, ns); + const symbol_exprt &first_obj= + to_symbol_expr(to_address_of_expr(value).object()); + const symbol_exprt new_value= + recursive_member_symbol( + first_obj, + access.fields.back(), + access.location, + ns); + const symbol_exprt old_value= + recursive_member_symbol( + first_obj, + access.fields.back(), + list_iteratort::IN_LOC, + ns); const exprt binding=equal_exprt(new_value, old_value); access_binding=or_exprt(access_binding, binding); @@ -1080,7 +1097,10 @@ void heap_domaint::bind_iterators( for(const heap_row_spect &row_spec : new_heap_row_specs) { new_output_template_row( - row_spec.expr, row_spec.location_number, row_spec.post_guard, SSA, + row_spec.expr, + row_spec.location_number, + row_spec.post_guard, + SSA, template_generator); } } @@ -1111,10 +1131,10 @@ void heap_domaint::new_output_template_row( const exprt pre_guard=SSA.guard_symbol(loc); - const symbol_exprt pre_var=SSA.name( - ssa_objectt(var, SSA.ns), local_SSAt::LOOP_BACK, loc); - const symbol_exprt post_var=SSA.name( - ssa_objectt(var, SSA.ns), local_SSAt::OUT, loc); + const symbol_exprt pre_var= + SSA.name(ssa_objectt(var, SSA.ns), local_SSAt::LOOP_BACK, loc); + const symbol_exprt post_var= + SSA.name(ssa_objectt(var, SSA.ns), local_SSAt::OUT, loc); var_spec.var=pre_var; var_spec.pre_guard=pre_guard; @@ -1168,12 +1188,13 @@ void heap_domaint::create_precondition( // context and return its member std::string var_id_str=id2string(var.get_identifier()); const symbol_exprt pointer( - var_id_str.substr(0, var_id_str.rfind("'obj")), var.type()); + var_id_str.substr(0, var_id_str.rfind("'obj")), + var.type()); const irep_idt member=var_id_str.substr(var_id_str.rfind(".")); exprt::operandst d; - std::set pointed_objs=collect_preconditions_rec( - pointer, precondition); + std::set pointed_objs= + collect_preconditions_rec(pointer, precondition); for(exprt pointed : pointed_objs) { if(pointed.id()==ID_address_of) @@ -1282,8 +1303,8 @@ const exprt heap_domaint::iterator_access_bindings( const exprt &precondition, const local_SSAt &SSA) { - const std::set reachable=reachable_objects( - init_pointer, fields, precondition); + const std::set reachable= + reachable_objects(init_pointer, fields, precondition); exprt::operandst d; for(const symbol_exprt &r : reachable) @@ -1315,8 +1336,15 @@ const exprt heap_domaint::iterator_access_bindings( to_symbol_expr(access_eq.lhs()), ns); c.push_back( iterator_access_bindings( - new_src, r, new_iterator_sym, {access.fields.at(level)}, access, - level+1, guards, precondition, SSA)); + new_src, + r, + new_iterator_sym, + {access.fields.at(level)}, + access, + level+1, + guards, + precondition, + SSA)); } else if(access.location!=list_iteratort::IN_LOC) { @@ -1369,11 +1397,11 @@ const std::set heap_domaint::reachable_objects( if(src.id()==ID_member && to_member_expr(src).compound().get_bool(ID_pointed)) { const member_exprt &member=to_member_expr(src); - const exprt pointer=get_pointer(member.compound(), - pointed_level(member.compound())-1); + const exprt pointer= + get_pointer(member.compound(), pointed_level(member.compound())-1); - std::set r=reachable_objects( - pointer, {member.get_component_name()}, precondition); + std::set r= + reachable_objects(pointer, {member.get_component_name()}, precondition); pointed_objs.insert(r.begin(), r.end()); } else diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index 169c1afd5..d5ebcf539 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -110,7 +110,7 @@ class heap_domaint:public domaint exprt destination; mutable std::set dyn_objects; - patht(const exprt &dest_):destination(dest_) {} + patht(const exprt &dest_):destination(dest_) {} // NOLINT(*) patht(const exprt &dest_, const std::set &dyn_objs_): destination(dest_), dyn_objects(dyn_objs_) {} @@ -191,7 +191,8 @@ class heap_domaint:public domaint virtual void initialize(valuet &value) override; void initialize_domain( - const local_SSAt &SSA, const exprt &precondition, + const local_SSAt &SSA, + const exprt &precondition, template_generator_baset &template_generator); // Value -> constraints @@ -218,7 +219,8 @@ class heap_domaint:public domaint // Printing virtual void output_value( - std::ostream &out, const valuet &value, + std::ostream &out, + const valuet &value, const namespacet &ns) const override; virtual void output_domain( diff --git a/src/domains/list_iterator.cpp b/src/domains/list_iterator.cpp index e26f1d153..cdd70b94e 100644 --- a/src/domains/list_iterator.cpp +++ b/src/domains/list_iterator.cpp @@ -28,8 +28,9 @@ void list_iteratort::add_access( const member_exprt &expr, unsigned location_number) const { - assert(expr.compound().get_bool(ID_iterator) && - expr.compound().get_bool(ID_pointed)); + assert( + expr.compound().get_bool(ID_iterator) && + expr.compound().get_bool(ID_pointed)); accesst access; access.location=location_number; @@ -96,9 +97,10 @@ Function: list_iteratort::iterator_symbol const symbol_exprt list_iteratort::iterator_symbol() const { - symbol_exprt iterator(id2string(pointer.get_identifier()).substr(0, id2string( - pointer.get_identifier()).find_last_of('#'))+"'it", - pointer.type().subtype()); + std::size_t pos=id2string(pointer.get_identifier()).find_last_of('#'); + symbol_exprt iterator( + id2string(pointer.get_identifier()).substr(0, pos)+"'it", + pointer.type().subtype()); iterator.set(ID_iterator, true); return iterator; @@ -164,7 +166,9 @@ equal_exprt list_iteratort::accesst::binding( const namespacet &ns) const { unsigned loc=level==fields.size()-1 ? location : IN_LOC; - return equal_exprt( - recursive_member_symbol(lhs, fields.at(level), loc, ns), - recursive_member_symbol(rhs, fields.at(level), loc, ns)); + const symbol_exprt lhs_sym= + recursive_member_symbol(lhs, fields.at(level), loc, ns); + const symbol_exprt rhs_sym= + recursive_member_symbol(rhs, fields.at(level), loc, ns); + return equal_exprt(lhs_sym, rhs_sym); } diff --git a/src/domains/list_iterator.h b/src/domains/list_iterator.h index 9f7ab96d5..b2d48af8c 100644 --- a/src/domains/list_iterator.h +++ b/src/domains/list_iterator.h @@ -36,8 +36,10 @@ class list_iteratort unsigned location; equal_exprt binding( - const symbol_exprt &lhs, const symbol_exprt &rhs, - const unsigned level, const namespacet &ns) const; + const symbol_exprt &lhs, + const symbol_exprt &rhs, + const unsigned level, + const namespacet &ns) const; }; // Pointer variable used to iterate the list (induction pointer) diff --git a/src/domains/ssa_analyzer.cpp b/src/domains/ssa_analyzer.cpp index f5e2cc212..301cb1ff2 100644 --- a/src/domains/ssa_analyzer.cpp +++ b/src/domains/ssa_analyzer.cpp @@ -109,15 +109,23 @@ void ssa_analyzert::operator()( { strategy_solver=new strategy_solver_heapt( *static_cast(domain), - solver, SSA, precondition, get_message_handler(), template_generator); + solver, + SSA, + precondition, + get_message_handler(), + template_generator); result=new heap_domaint::heap_valuet(); } - else if (template_generator.options.get_bool_option("heap-interval")) + else if(template_generator.options.get_bool_option("heap-interval")) { - strategy_solver = new strategy_solver_heap_intervalt( - *static_cast(domain), solver, SSA, precondition, - get_message_handler(), template_generator); - result = new heap_interval_domaint::heap_interval_valuet(); + strategy_solver=new strategy_solver_heap_intervalt( + *static_cast(domain), + solver, + SSA, + precondition, + get_message_handler(), + template_generator); + result=new heap_interval_domaint::heap_interval_valuet(); } else { @@ -190,9 +198,9 @@ Function: ssa_analyzert::update_heap_out \*******************************************************************/ void ssa_analyzert::update_heap_out(summaryt::var_sett &out) { - heap_domaint &heap_domain = static_cast(*domain); + heap_domaint &heap_domain=static_cast(*domain); - auto new_heap_vars = heap_domain.get_new_heap_vars(); + auto new_heap_vars=heap_domain.get_new_heap_vars(); out.insert(new_heap_vars.begin(), new_heap_vars.end()); } diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index 623062179..8542a014e 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -6,7 +6,7 @@ Author: Viktor Malik \*******************************************************************/ -//#define DEBUG_OUTPUT +// #define DEBUG_OUTPUT #include #include "strategy_solver_heap.h" @@ -42,7 +42,9 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) // Exit value constraints exprt::operandst strategy_cond_exprs; heap_domain.make_not_post_constraints( - inv, strategy_cond_exprs, strategy_value_exprs); + inv, + strategy_cond_exprs, + strategy_value_exprs); strategy_cond_literals.resize(strategy_cond_exprs.size()); @@ -128,10 +130,9 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) if(heap_domain.add_points_to(row, inv, ptr_value)) { improved=true; - debug() << "Add " - << (templ_row.mem_kind==heap_domaint::STACK ? "points to " - : "path to ") - << from_expr(ns, "", ptr_value) << eom; + const std::string info= + templ_row.mem_kind==heap_domaint::STACK?"points to ":"path to "; + debug() << "Add " << info << from_expr(ns, "", ptr_value) << eom; } } else if(ptr_value.id()==ID_address_of) @@ -160,10 +161,9 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) if(heap_domain.add_points_to(row, inv, obj)) { improved=true; - debug() << "Add " - << (templ_row.mem_kind==heap_domaint::STACK ? "points to " - : "path to ") - << from_expr(ns, "", obj) << eom; + const std::string info= + templ_row.mem_kind==heap_domaint::STACK?"points to ":"path to "; + debug() << "Add " << info << from_expr(ns, "", obj) << eom; } // If the template row is of heap kind, we need to ensure the @@ -176,18 +176,24 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) // Find row with corresponding member field of the pointed object // (obj.member) int member_val_index; - member_val_index=find_member_row( - obj, templ_row.member, actual_loc, templ_row.kind); + member_val_index= + find_member_row( + obj, + templ_row.member, + actual_loc, + templ_row.kind); if(member_val_index>=0 && !inv[member_val_index].nondet) { // Add all paths from obj.next to p if(heap_domain.add_transitivity( - row, (unsigned) member_val_index, inv)) + row, + static_cast(member_val_index), + inv)) { improved=true; - debug() << "Add all paths: " - << from_expr( - ns, "", heap_domain.templ[member_val_index].expr) + const std::string expr_str= + from_expr(ns, "", heap_domain.templ[member_val_index].expr); + debug() << "Add all paths: " << expr_str << ", through: " << from_expr(ns, "", obj) << eom; } } diff --git a/src/domains/strategy_solver_heap_interval.h b/src/domains/strategy_solver_heap_interval.h index abedf3471..449fa7423 100644 --- a/src/domains/strategy_solver_heap_interval.h +++ b/src/domains/strategy_solver_heap_interval.h @@ -28,8 +28,12 @@ class strategy_solver_heap_intervalt:public strategy_solver_baset strategy_solver_baset(_solver, SSA.ns), heap_interval_domain(_heap_interval_domain), heap_solver( - heap_interval_domain.heap_domain, _solver, SSA, precondition, - message_handler, template_generator), + heap_interval_domain.heap_domain, + _solver, + SSA, + precondition, + message_handler, + template_generator), interval_solver(heap_interval_domain.interval_domain, _solver, SSA.ns) {} virtual bool iterate(invariantt &_inv) override; diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index 787f428c9..d640bb449 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -758,8 +758,8 @@ void template_generator_baset::instantiate_standard_domains( else if(options.get_bool_option("heap-interval")) { filter_heap_interval_domain(); - domain_ptr=new heap_interval_domaint( - domain_number, renaming_map, var_specs, SSA.ns); + domain_ptr= + new heap_interval_domaint(domain_number, renaming_map, var_specs, SSA.ns); } } diff --git a/src/domains/template_generator_callingcontext.cpp b/src/domains/template_generator_callingcontext.cpp index 437415cdf..ba9adfd4d 100644 --- a/src/domains/template_generator_callingcontext.cpp +++ b/src/domains/template_generator_callingcontext.cpp @@ -93,14 +93,17 @@ void template_generator_callingcontextt::collect_variables_callingcontext( v_it!=cs_globals_in.end(); v_it++) { symbol_exprt dummy; - if (ssa_inlinert::find_corresponding_symbol(*v_it, globals_in, dummy) || - id2string(v_it->get_identifier()).find("dynamic_object$") != std::string::npos) + if(ssa_inlinert::find_corresponding_symbol(*v_it, globals_in, dummy) || + id2string(v_it->get_identifier()).find("dynamic_object$")!= + std::string::npos) + { add_var( *v_it, guard, guard, domaint::OUT, // the same for both forward and backward var_specs); + } } // TODO: actually, the context should contain both, @@ -108,17 +111,15 @@ void template_generator_callingcontextt::collect_variables_callingcontext( if(!forward) return; - std::set args; // add function arguments for(exprt::operandst::const_iterator a_it=f_it->arguments().begin(); a_it!=f_it->arguments().end(); a_it++) { - find_symbols(*a_it,args); - + std::set args; + find_symbols(*a_it,args); exprt arg=*a_it; - + add_vars(args, guard, guard, domaint::OUT, var_specs); } - add_vars(args, guard, guard, domaint::OUT, var_specs); } /*******************************************************************\ diff --git a/src/ssa/assignments.h b/src/ssa/assignments.h index 4d19f681e..6ca3ec3a1 100644 --- a/src/ssa/assignments.h +++ b/src/ssa/assignments.h @@ -43,14 +43,15 @@ class assignmentst return it->second; } - explicit assignmentst(const goto_programt &_goto_program, - const namespacet &_ns, - const ssa_objectst &_ssa_objects, - const ssa_value_ait &_ssa_value_ai, - const ssa_heap_analysist &_ssa_heap_analysis) : - ssa_objects(_ssa_objects), - ssa_value_ai(_ssa_value_ai), - ssa_heap_analysis(_ssa_heap_analysis) + assignmentst( + const goto_programt &_goto_program, + const namespacet &_ns, + const ssa_objectst &_ssa_objects, + const ssa_value_ait &_ssa_value_ai, + const ssa_heap_analysist &_ssa_heap_analysis): + ssa_objects(_ssa_objects), + ssa_value_ai(_ssa_value_ai), + ssa_heap_analysis(_ssa_heap_analysis) { build_assignment_map(_goto_program, _ns); } diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 09b4c2798..ddd63ecd4 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -550,8 +550,10 @@ void local_SSAt::build_function_call(locationt loc) if(a.is_constant() || (a.id()==ID_typecast && to_typecast_expr(a).op().is_constant())) { - symbol_exprt arg(id2string(fname)+"#arg"+i2string(i)+ - "#"+i2string(loc->location_number), a.type()); + const std::string arg_name= + id2string(fname)+"#arg"+i2string(i)+"#"+ + i2string(loc->location_number); + symbol_exprt arg(arg_name, a.type()); n_it->equalities.push_back(equal_exprt(a, arg)); a=arg; } @@ -1373,11 +1375,17 @@ void local_SSAt::assign_rec( const if_exprt &if_expr=to_if_expr(lhs); exprt new_rhs=if_exprt(if_expr.cond(), rhs, if_expr.true_case()); - assign_rec(if_expr.true_case(), new_rhs, and_exprt(guard, if_expr.cond()), - loc); - - assign_rec(if_expr.false_case(), rhs, - and_exprt(guard, not_exprt(if_expr.cond())), loc); + assign_rec( + if_expr.true_case(), + new_rhs, + and_exprt(guard, if_expr.cond()), + loc); + + assign_rec( + if_expr.false_case(), + rhs, + and_exprt(guard, not_exprt(if_expr.cond())), + loc); } else if(lhs.id()==ID_byte_extract_little_endian || lhs.id()==ID_byte_extract_big_endian) @@ -1392,7 +1400,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(*) } /*******************************************************************\ @@ -1875,8 +1883,10 @@ void local_SSAt::collect_iterators_lhs( object.get_root_object().id()==ID_symbol) { assert(object.get_expr().id()==ID_member); - new_iterator_access(to_member_expr(object.get_expr()), loc, - loc->location_number); + new_iterator_access( + to_member_expr(object.get_expr()), + loc, + loc->location_number); } } @@ -1916,4 +1926,3 @@ void local_SSAt::new_iterator_access( auto it=iterators.insert(iterator); it.first->add_access(expr, inst_loc_number); } - diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 977e75032..3a54d2171 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -42,7 +42,11 @@ class local_SSAt ssa_objects(_goto_function, ns, _heap_analysis), ssa_value_ai(_goto_function, ns, _heap_analysis), assignments( - _goto_function.body, ns, ssa_objects, ssa_value_ai, heap_analysis), + _goto_function.body, + ns, + ssa_objects, + ssa_value_ai, + heap_analysis), guard_map(_goto_function.body), ssa_analysis(assignments), suffix(_suffix) @@ -155,7 +159,9 @@ class local_SSAt // auxiliary functions enum kindt { PHI, OUT, LOOP_BACK, LOOP_SELECT }; virtual symbol_exprt name( - const ssa_objectt &, kindt kind, locationt loc) const; + const ssa_objectt &, + kindt kind, + locationt loc) const; symbol_exprt name(const ssa_objectt &, const ssa_domaint::deft &) const; symbol_exprt name_input(const ssa_objectt &) const; virtual exprt nondet_symbol( @@ -172,7 +178,10 @@ class local_SSAt symbol_exprt read_rhs(const ssa_objectt &, locationt loc) const; exprt read_node_in(const ssa_objectt &, locationt loc) const; void assign_rec( - const exprt &lhs, const exprt &rhs, const exprt &guard, locationt loc); + const exprt &lhs, + const exprt &rhs, + const exprt &guard, + locationt loc); void collect_iterators_rhs(const exprt &expr, locationt loc); void collect_iterators_lhs(const ssa_objectt &object, locationt loc); @@ -215,7 +224,8 @@ class local_SSAt nodest::iterator find_node(locationt loc); nodest::const_iterator find_node(locationt loc) const; void find_nodes( - locationt loc, std::list &_nodes) const; + locationt loc, + std::list &_nodes) const; inline locationt get_location(unsigned location_number) const { diff --git a/src/ssa/malloc_ssa.cpp b/src/ssa/malloc_ssa.cpp index 0a8b0803c..80f69de3c 100644 --- a/src/ssa/malloc_ssa.cpp +++ b/src/ssa/malloc_ssa.cpp @@ -15,8 +15,6 @@ Author: Daniel Kroening, kroening@kroening.com #include #include -#include -#include #include "malloc_ssa.h" diff --git a/src/ssa/ssa_db.h b/src/ssa/ssa_db.h index 958c969b5..1fa7d4543 100644 --- a/src/ssa/ssa_db.h +++ b/src/ssa/ssa_db.h @@ -12,7 +12,6 @@ Author: Peter Schrammel #include #include -#include #include #include diff --git a/src/ssa/ssa_dereference.cpp b/src/ssa/ssa_dereference.cpp index 32450d582..557759138 100644 --- a/src/ssa/ssa_dereference.cpp +++ b/src/ssa/ssa_dereference.cpp @@ -393,7 +393,9 @@ exprt dereference_rec( { exprt tmp=src; Forall_operands(it, tmp) + { *it=dereference_rec(*it, ssa_value_domain, nondet_prefix, ns); + } return tmp; } } diff --git a/src/ssa/ssa_heap_domain.cpp b/src/ssa/ssa_heap_domain.cpp index 68bc6bc9f..deab41dba 100644 --- a/src/ssa/ssa_heap_domain.cpp +++ b/src/ssa/ssa_heap_domain.cpp @@ -53,7 +53,9 @@ void ssa_heap_domaint::transform( function_map[function].new_objects.end()) { function_map[function].new_objects.insert( - std::make_pair(new_obj, std::set())); + std::make_pair( + new_obj, + std::set())); } for(auto &expr : obj.second) @@ -159,7 +161,8 @@ bool ssa_heap_domaint::merge( other_object.second.begin(), other_object.second.end(), std::inserter( - intersection, intersection.begin())); + intersection, + intersection.begin())); if(!intersection.empty()) objects[other_object.first]=intersection; else @@ -227,7 +230,9 @@ void ssa_heap_domaint::assign_rhs( function_info.new_objects.end()) { function_info.new_objects.insert( - std::make_pair(new_object, std::set())); + std::make_pair( + new_object, + std::set())); } objects={new_object}; @@ -376,7 +381,8 @@ Function: ssa_heap_domaint::rename_to_caller \*******************************************************************/ void ssa_heap_domaint::rename_to_caller( - symbol_exprt &object, domain_baset::locationt loc, + symbol_exprt &object, + domain_baset::locationt loc, unsigned &index) const { object.set_identifier( diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index a35f7b502..6f0e73d91 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -71,7 +71,13 @@ void ssa_inlinert::get_summary( // equalities for arguments bindings.push_back( get_replace_params( - summary.params, *f_it, cs_globals_in, cs_globals_out, SSA, summary, loc)); + summary.params, + *f_it, + cs_globals_in, + cs_globals_out, + SSA, + summary, + loc)); // equalities for globals_in if(forward) @@ -99,11 +105,21 @@ void ssa_inlinert::get_summary( if(forward) bindings.push_back( get_replace_globals_out( - cs_globals_in, cs_globals_out, summary, *f_it, SSA, loc)); + cs_globals_in, + cs_globals_out, + summary, + *f_it, + SSA, + loc)); else bindings.push_back( get_replace_globals_out( - cs_globals_out, cs_globals_in, summary, *f_it, SSA, loc)); + cs_globals_out, + cs_globals_in, + summary, + *f_it, + SSA, + loc)); } /*******************************************************************\ @@ -561,17 +577,17 @@ exprt ssa_inlinert::get_replace_params( while(arg_type.id()==ID_pointer) { - std::list args_deref_in=apply_dereference( - args_in, SSA.ssa_value_ai[loc], SSA.ns); - std::list params_deref_in=apply_dereference( - params_in, summary.value_domain_in, SSA.ns); + std::list args_deref_in= + apply_dereference(args_in, SSA.ssa_value_ai[loc], SSA.ns); + std::list params_deref_in= + apply_dereference(params_in, summary.value_domain_in, SSA.ns); local_SSAt::locationt next_loc=loc; ++next_loc; - std::list args_deref_out=apply_dereference( - args_out, SSA.ssa_value_ai[next_loc], SSA.ns); - std::list params_deref_out=apply_dereference( - params_out, summary.value_domain_out, SSA.ns); + std::list args_deref_out= + apply_dereference(args_out, SSA.ssa_value_ai[next_loc], SSA.ns); + std::list params_deref_out= + apply_dereference(params_out, summary.value_domain_out, SSA.ns); const typet arg_symbol_type=arg_type.subtype(); arg_type=SSA.ns.follow(arg_symbol_type); @@ -586,33 +602,40 @@ exprt ssa_inlinert::get_replace_params( for(const exprt &a : args_deref_in) { - std::list aliases=apply_dereference( - {a}, SSA.ssa_value_ai[next_loc], SSA.ns); + std::list aliases= + apply_dereference({a}, SSA.ssa_value_ai[next_loc], SSA.ns); aliases.push_front(a); for(auto &alias : aliases) { - // Bind argument address - c.push_back(equal_exprt( - param_out_transformer(alias, arg_type, summary.globals_out), + const exprt lhs_expr= + param_out_transformer(alias, arg_type, summary.globals_out); + const exprt rhs_expr= arg_out_transformer( - alias, arg_symbol_type, params_deref_out.begin()->type(), SSA, - loc))); + alias, + arg_symbol_type, + params_deref_out.begin()->type(), + SSA, + loc); + // Bind argument address + c.push_back(equal_exprt(lhs_expr, rhs_expr)); for(auto &component : to_struct_type(arg_type).components()) { + const exprt lhs_comp_expr= + param_in_member_transformer(alias, component); + const exprt rhs_comp_expr= + arg_in_member_transformer(alias, component, SSA, loc); // Bind argument members at the input - c.push_back(equal_exprt( - param_in_member_transformer(alias, component), - arg_in_member_transformer(alias, component, SSA, loc))); + c.push_back(equal_exprt(lhs_comp_expr, rhs_comp_expr)); } } } for(const exprt &a : args_deref_out) { - std::list aliases=apply_dereference( - {a}, SSA.ssa_value_ai[next_loc], SSA.ns); + std::list aliases= + apply_dereference({a}, SSA.ssa_value_ai[next_loc], SSA.ns); aliases.push_front(a); for(auto &alias : aliases) { @@ -632,10 +655,9 @@ exprt ssa_inlinert::get_replace_params( arg_member, summary.globals_out, member_lhs_out)) { rename(member_lhs_out); - c.push_back( - equal_exprt( - member_lhs_out, - arg_out_member_transformer(alias, component, SSA, loc))); + const exprt arg_out= + arg_out_member_transformer(alias, component, SSA, loc); + c.push_back(equal_exprt(member_lhs_out, arg_out)); } } } @@ -653,17 +675,19 @@ exprt ssa_inlinert::get_replace_params( for(const exprt &a_in : args_deref_in) { exprt::operandst binding; - binding.push_back(equal_exprt( - param_in_transformer(p_in), - arg_in_transformer(a_in, SSA, loc))); + const exprt lhs_expr=param_in_transformer(p_in); + const exprt rhs_expr=arg_in_transformer(a_in, SSA, loc); + binding.push_back(equal_exprt(lhs_expr, rhs_expr)); if(arg_type.id()==ID_struct) { for(auto &component : to_struct_type(arg_type).components()) { - binding.push_back(equal_exprt( - param_in_member_transformer(p_in, component), - arg_in_member_transformer(a_in, component, SSA, loc))); + const exprt lhs_comp_expr= + param_in_member_transformer(p_in, component); + const exprt rhs_comp_expr= + arg_in_member_transformer(a_in, component, SSA, loc); + binding.push_back(equal_exprt(lhs_comp_expr, rhs_comp_expr)); } } d.push_back(conjunction(binding)); @@ -680,19 +704,32 @@ exprt ssa_inlinert::get_replace_params( { exprt::operandst binding; - binding.push_back(equal_exprt( - param_out_transformer(p_out, arg_type, summary.globals_out), + const exprt lhs_expr= + param_out_transformer(p_out, arg_type, summary.globals_out); + const exprt rhs_expr= arg_out_transformer( - a_out, arg_symbol_type, p_out.type(), SSA, loc))); + a_out, + arg_symbol_type, + p_out.type(), + SSA, + loc); + binding.push_back(equal_exprt(lhs_expr, rhs_expr)); if(arg_type.id()==ID_struct) { for(auto &component : to_struct_type(arg_type).components()) { - binding.push_back(equal_exprt( + const exprt lhs_comp_expr= param_out_member_transformer( - p_out, component, summary.globals_out), - arg_out_member_transformer(a_out, component, SSA, loc))); + p_out, + component, + summary.globals_out); + const exprt rhs_comp_expr= + arg_out_member_transformer(a_out, component, SSA, loc); + binding.push_back( + equal_exprt( + lhs_comp_expr, + rhs_comp_expr)); } } d.push_back(conjunction(binding)); @@ -709,7 +746,8 @@ exprt ssa_inlinert::get_replace_params( params_in=params_deref_in; params_out=params_deref_out; - if(args_in.empty() && args_out.empty()) break; + if(args_in.empty() && args_out.empty()) + break; } } return conjunction(c); @@ -808,10 +846,13 @@ exprt ssa_inlinert::get_replace_globals_out( { local_SSAt::locationt next_loc=loc; ++next_loc; - std::list caller_deref=apply_dereference( - caller_global, SSA.ssa_value_ai[next_loc], SSA.ns); - std::list callee_deref=apply_dereference( - callee_global, summary.value_domain_out, SSA.ns); + std::list caller_deref= + apply_dereference( + caller_global, + SSA.ssa_value_ai[next_loc], + SSA.ns); + std::list callee_deref= + apply_dereference(callee_global, summary.value_domain_out, SSA.ns); if(!callee_deref.empty()) { @@ -826,20 +867,32 @@ exprt ssa_inlinert::get_replace_globals_out( if(!cs_heap_covered(caller)) { exprt::operandst binding; - binding.push_back(equal_exprt( - param_out_transformer(callee, type, summary.globals_out), + const exprt lhs_expr= + param_out_transformer(callee, type, summary.globals_out); + const exprt rhs_expr= arg_out_transformer( - caller, symbol_type, callee.type(), SSA, loc))); + caller, + symbol_type, + callee.type(), + SSA, + loc); + binding.push_back(equal_exprt(lhs_expr, rhs_expr)); if(type.id()==ID_struct) { for(auto &component : to_struct_type(type).components()) { - binding.push_back(equal_exprt( + const exprt lhs_comp_expr= param_out_member_transformer( - callee, component, summary.globals_out), - arg_out_member_transformer( - caller, component, SSA, loc))); + callee, + component, + summary.globals_out); + const exprt rhs_comp_expr= + arg_out_member_transformer(caller, component, SSA, loc); + binding.push_back( + equal_exprt( + lhs_comp_expr, + rhs_comp_expr)); } } @@ -855,7 +908,8 @@ exprt ssa_inlinert::get_replace_globals_out( callee_global=callee_deref; caller_global=caller_deref; - if(caller_global.empty()) break; + if(caller_global.empty()) + break; } } else @@ -950,7 +1004,7 @@ void ssa_inlinert::rename(exprt &expr) { const std::string &obj_id=id2string(to_symbol_expr(obj).get_identifier()); if(is_pointed(obj)) - id = get_pointer_id(obj); + id=get_pointer_id(obj); else id=id2string(obj_id)+"'addr"; @@ -1099,9 +1153,9 @@ void ssa_inlinert::rename_to_callee( #endif // rename objects not present in globals in to non-suffix version symbol_exprt to_replace(get_original_identifier(*it), it->type()); - replace_map[*it] = to_replace; + replace_map[*it]=to_replace; // to propagate #dynamic flag on type - replace_map[to_replace] = to_replace; + replace_map[to_replace]=to_replace; } } @@ -1297,8 +1351,10 @@ Function: ssa_inlinert::contains_iterator bool ssa_inlinert::contains_iterator(const std::list ¶ms) { - auto it=std::find_if(params.begin(), params.end(), - [](const exprt &p) { return is_iterator(p); }); + auto it=std::find_if( + params.begin(), + params.end(), + [](const exprt &p) { return is_iterator(p); }); return (it!=params.end()); } @@ -1335,7 +1391,8 @@ Function: ssa_inlinert::arg_in_transformer \*******************************************************************/ exprt ssa_inlinert::arg_in_transformer( - const exprt &arg, const local_SSAt &SSA, + const exprt &arg, + const local_SSAt &SSA, local_SSAt::locationt loc) { return SSA.read_rhs(arg, loc); @@ -1380,10 +1437,13 @@ Function: ssa_inlinert::arg_in_member_transformer exprt ssa_inlinert::arg_in_member_transformer( const exprt &arg, const struct_union_typet::componentt &component, - const local_SSAt &SSA, local_SSAt::locationt loc) + const local_SSAt &SSA, + local_SSAt::locationt loc) { - symbol_exprt arg_member(id2string(to_symbol_expr(arg).get_identifier())+"."+ - id2string(component.get_name()), component.type()); + symbol_exprt arg_member( + id2string(to_symbol_expr(arg).get_identifier())+"."+ + id2string(component.get_name()), + component.type()); return SSA.read_rhs(arg_member, loc); } @@ -1400,7 +1460,8 @@ Function: ssa_inlinert::param_out_transformer \*******************************************************************/ exprt ssa_inlinert::param_out_transformer( - const exprt ¶m, const typet &type, + const exprt ¶m, + const typet &type, const local_SSAt::var_sett &globals_out) { assert(param.id()==ID_symbol); @@ -1433,8 +1494,10 @@ Function: ssa_inlinert::arg_out_transformer \*******************************************************************/ exprt ssa_inlinert::arg_out_transformer( - const exprt &arg, const typet &arg_symbol_type, - const typet ¶m_type, const local_SSAt &SSA, + const exprt &arg, + const typet &arg_symbol_type, + const typet ¶m_type, + const local_SSAt &SSA, local_SSAt::locationt loc) { const typet &arg_type=SSA.ns.follow(arg_symbol_type); @@ -1455,8 +1518,8 @@ exprt ssa_inlinert::arg_out_transformer( } else { - const symbol_exprt &arg_out=SSA.name(ssa_objectt(arg, SSA.ns), - local_SSAt::OUT, loc); + const symbol_exprt &arg_out= + SSA.name(ssa_objectt(arg, SSA.ns), local_SSAt::OUT, loc); covered_cs_heap_out.insert(arg_out); return arg_out; } @@ -1505,13 +1568,14 @@ Function: ssa_inlinert::artg_out_transformer exprt ssa_inlinert::arg_out_member_transformer( const exprt &arg, const struct_union_typet::componentt &component, - const local_SSAt &SSA, local_SSAt::locationt loc) + const local_SSAt &SSA, + local_SSAt::locationt loc) { - symbol_exprt arg_member(id2string(to_symbol_expr(arg).get_identifier())+"."+ - id2string(component.get_name()), component.type()); - const symbol_exprt &arg_member_out=SSA.name(ssa_objectt(arg_member, SSA.ns), - local_SSAt::OUT, - loc); + symbol_exprt arg_member( + id2string(to_symbol_expr(arg).get_identifier())+"."+ + id2string(component.get_name()), component.type()); + const symbol_exprt &arg_member_out= + SSA.name(ssa_objectt(arg_member, SSA.ns), local_SSAt::OUT, loc); covered_cs_heap_out.insert(arg_member_out); return arg_member_out; } @@ -1550,7 +1614,8 @@ Function: ssa_inlinert::get_replace_new_objects exprt ssa_inlinert::get_replace_new_objects( const local_SSAt &SSA, const function_application_exprt funapp_expr, - local_SSAt::locationt loc, const summaryt &summary) + local_SSAt::locationt loc, + const summaryt &summary) { exprt::operandst binding; @@ -1574,19 +1639,24 @@ exprt ssa_inlinert::get_replace_new_objects( const typet symbol_type=caller_it->type(); const typet type=SSA.ns.follow(symbol_type); - binding.push_back(equal_exprt( - param_out_transformer(*callee_it, type, summary.globals_out), - arg_out_transformer(*caller_it, symbol_type, type, SSA, loc))); + const exprt lhs_expr= + param_out_transformer(*callee_it, type, summary.globals_out); + const exprt rhs_expr= + arg_out_transformer(*caller_it, symbol_type, type, SSA, loc); + binding.push_back(equal_exprt(lhs_expr, rhs_expr)); if(type.id()==ID_struct) { for(auto &component : to_struct_type(type).components()) { - binding.push_back( - equal_exprt( - param_out_member_transformer( - *callee_it, component, summary.globals_out), - arg_out_member_transformer(*caller_it, component, SSA, loc))); + const exprt lhs_comp_expr= + param_out_member_transformer( + *callee_it, + component, + summary.globals_out); + const exprt rhs_comp_expr= + arg_out_member_transformer(*caller_it, component, SSA, loc); + binding.push_back(equal_exprt(lhs_comp_expr, rhs_comp_expr)); } } } diff --git a/src/ssa/ssa_inliner.h b/src/ssa/ssa_inliner.h index 08e1e6347..487bfe667 100644 --- a/src/ssa/ssa_inliner.h +++ b/src/ssa/ssa_inliner.h @@ -154,7 +154,8 @@ class ssa_inlinert:public messaget exprt get_replace_new_objects( const local_SSAt &SSA, const function_application_exprt funapp_expr, - local_SSAt::locationt loc, const summaryt &summary); + local_SSAt::locationt loc, + const summaryt &summary); void rename(exprt &expr); void rename(local_SSAt::nodet &node); diff --git a/src/ssa/ssa_object.cpp b/src/ssa/ssa_object.cpp index caae37ed8..f2affa7a3 100644 --- a/src/ssa/ssa_object.cpp +++ b/src/ssa/ssa_object.cpp @@ -235,8 +235,7 @@ void collect_objects_rec( if(ssa_object.type().get_bool("#dynamic") || (root_object.id()==ID_symbol && id2string(to_symbol_expr(root_object).get_identifier()).find( - "#return_value")== - std::string::npos && + "#return_value")==std::string::npos && !ns.lookup(to_symbol_expr(root_object).get_identifier(), symbol) && (symbol->is_parameter || !symbol->is_procedure_local()))) { diff --git a/src/ssa/ssa_pointed_objects.cpp b/src/ssa/ssa_pointed_objects.cpp index 8e3ea25ec..3b6eab677 100644 --- a/src/ssa/ssa_pointed_objects.cpp +++ b/src/ssa/ssa_pointed_objects.cpp @@ -96,22 +96,20 @@ void copy_pointed_info(exprt &dest, const exprt &src, const unsigned max_level) { const irep_idt lvl_pointed_id=src.get(level_str(l, ID_pointer_id)); dest.set(level_str(l, ID_pointer_id), lvl_pointed_id); - dest.set( - level_str(l, ID_pointer_subtype), - src.get(level_str(l, ID_pointer_subtype))); + const irep_idt lvl_pointed_subtype= + src.get(level_str(l, ID_pointer_subtype)); + dest.set(level_str(l, ID_pointer_subtype), lvl_pointed_subtype); if(lvl_pointed_id==ID_symbol) { - dest.set( - level_str(l, ID_pointer_sym), src.get(level_str(l, ID_pointer_sym))); + const irep_idt lvl_pointer_sym=src.get(level_str(l, ID_pointer_sym)); + dest.set(level_str(l, ID_pointer_sym), lvl_pointer_sym); } else { - dest.set( - level_str(l, ID_pointer_compound), - src.get(level_str(l, ID_pointer_compound))); - dest.set( - level_str(l, ID_pointer_field), - src.get(level_str(l, ID_pointer_field))); + const irep_idt lvl_str=src.get(level_str(l, ID_pointer_compound)); + dest.set(level_str(l, ID_pointer_compound), lvl_str); + const irep_idt lvl_ptr_field=src.get(level_str(l, ID_pointer_field)); + dest.set(level_str(l, ID_pointer_field), lvl_ptr_field); } } } @@ -157,7 +155,8 @@ symbol_exprt pointed_object(const exprt &expr, const namespacet &ns) if(ssa_object.get_expr().id()==ID_symbol) { pointed.set( - level_str(level, ID_pointer_sym), ssa_object.get_identifier()); + level_str(level, ID_pointer_sym), + ssa_object.get_identifier()); } else { @@ -168,7 +167,8 @@ symbol_exprt pointed_object(const exprt &expr, const namespacet &ns) level_str(level, ID_pointer_compound), to_symbol_expr(member.compound()).get_identifier()); pointed.set( - level_str(level, ID_pointer_field), member.get_component_name()); + level_str(level, ID_pointer_field), + member.get_component_name()); } if(pointed_type.id()==ID_symbol) @@ -262,23 +262,27 @@ const exprt get_pointer(const exprt &expr, unsigned level) { exprt pointer; - const typet &pointed_type=symbol_typet( - expr.get(level_str(level, ID_pointer_subtype))); + const typet &pointed_type= + symbol_typet(expr.get(level_str(level, ID_pointer_subtype))); if(expr.get(level_str(level, ID_pointer_id))==ID_symbol) { pointer=symbol_exprt( - expr.get(level_str(level, ID_pointer_sym)), pointer_typet(pointed_type)); + expr.get(level_str(level, ID_pointer_sym)), + pointer_typet(pointed_type)); copy_pointed_info(pointer, expr, level-1); } else { assert(expr.get(level_str(level, ID_pointer_id))==ID_member); symbol_exprt compound( - expr.get(level_str(level, ID_pointer_compound)), expr.type()); + expr.get(level_str(level, ID_pointer_compound)), + expr.type()); copy_pointed_info(compound, expr, level-1); pointer=member_exprt( - compound, pointer_level_field(expr, level), pointer_typet(pointed_type)); + compound, + pointer_level_field(expr, level), + pointer_typet(pointed_type)); } return pointer; } diff --git a/src/ssa/ssa_pointed_objects.h b/src/ssa/ssa_pointed_objects.h index f9492a1ea..95d06e15e 100644 --- a/src/ssa/ssa_pointed_objects.h +++ b/src/ssa/ssa_pointed_objects.h @@ -36,7 +36,9 @@ unsigned it_value_level(const exprt &expr); const irep_idt pointer_root_id(const exprt &expr); const irep_idt pointer_level_field(const exprt &expr, const unsigned level); -const std::vector pointer_fields(const exprt &expr, const unsigned from_level); +const std::vector pointer_fields( + const exprt &expr, + const unsigned from_level); const exprt get_pointer(const exprt &expr, unsigned level); const exprt get_pointer_root(const exprt &expr, unsigned level); @@ -51,6 +53,8 @@ const exprt symbolic_dereference(const exprt &expr, const namespacet &ns); void set_iterator_fields(exprt &dest, const std::vector fields); const std::vector get_iterator_fields(const exprt &expr); -const irep_idt iterator_to_initial_id(const exprt &expr, const irep_idt &expr_id); +const irep_idt iterator_to_initial_id( + const exprt &expr, + const irep_idt &expr_id); #endif // CPROVER_2LS_SSA_SSA_POINTED_OBJECTS_H diff --git a/src/ssa/ssa_value_set.cpp b/src/ssa/ssa_value_set.cpp index 10f8de4bf..27875522c 100644 --- a/src/ssa/ssa_value_set.cpp +++ b/src/ssa/ssa_value_set.cpp @@ -590,11 +590,11 @@ bool ssa_value_domaint::valuest::merge( while(level>0) { const irep_idt ptr_root_id=pointer_root_id(expr); - it=std::find_if(value_set.begin(), value_set.end(), - [&ptr_root_id](const ssa_objectt &o) - { - return o.get_identifier()==ptr_root_id; - }); + it=std::find_if( + value_set.begin(), + value_set.end(), + [&ptr_root_id](const ssa_objectt &o) + { return o.get_identifier()==ptr_root_id; }); if(it!=value_set.end()) break; else @@ -610,7 +610,10 @@ bool ssa_value_domaint::valuest::merge( assert(it->get_expr().get_bool(ID_pointed)); ssa_objectt object_copy(*it); object_copy.set_iterator( - object_id, pointer_fields(v.get_expr(), level)); + object_id, + pointer_fields( + v.get_expr(), + level)); value_set.erase(it); value_set.insert(object_copy); result=true; @@ -627,12 +630,12 @@ bool ssa_value_domaint::valuest::merge( const irep_idt &corresponding_id=iterator_to_initial_id( v.get_expr(), v.get_identifier()); - auto it=std::find_if(value_set.begin(), value_set.end(), - [&corresponding_id](const ssa_objectt &o) - { - return o.get_expr().get_bool(ID_pointed) && - (o.get_identifier()==corresponding_id); - }); + auto it=std::find_if( + value_set.begin(), + value_set.end(), + [&corresponding_id](const ssa_objectt &o) + { return o.get_expr().get_bool(ID_pointed) && + (o.get_identifier()==corresponding_id); }); if(it!=value_set.end()) { if(v!=*it) @@ -794,20 +797,22 @@ Function: ssa_value_ait::assign_ptr_param_rec \*******************************************************************/ void ssa_value_ait::assign_ptr_param( - const exprt &expr, ssa_value_domaint &entry) + const exprt &expr, + ssa_value_domaint &entry) { const typet &type=ns.follow(expr.type()); if(type.id()==ID_pointer) { if(expr.id()==ID_symbol) - { // pointer variable + { + // pointer variable symbol_exprt pointed_expr=pointed_object(expr, ns); assign(expr, pointed_expr, entry); assign_ptr_param(pointed_expr, entry); } } else if(type.id()==ID_struct) - { + { // split structure into fields for(auto &component : to_struct_type(type).components()) { diff --git a/src/ssa/ssa_value_set.h b/src/ssa/ssa_value_set.h index a2f0d5fbe..d2ee2654f 100644 --- a/src/ssa/ssa_value_set.h +++ b/src/ssa/ssa_value_set.h @@ -41,9 +41,10 @@ class ssa_value_domaint:public ai_domain_baset void output(std::ostream &, const namespacet &) const; - bool merge(const valuest &src, - bool is_loop_back=false, - const irep_idt &object_id=irep_idt()); + bool merge( + const valuest &src, + bool is_loop_back=false, + const irep_idt &object_id=irep_idt()); inline void clear() { @@ -103,16 +104,19 @@ class ssa_value_domaint:public ai_domain_baset class ssa_value_ait:public ait { public: - ssa_value_ait(const goto_functionst::goto_functiont &goto_function, - const namespacet &ns_, - const ssa_heap_analysist &_heap_analysis) - : ns(ns_), heap_analysis(_heap_analysis) + ssa_value_ait( + const goto_functionst::goto_functiont &goto_function, + const namespacet &ns_, + const ssa_heap_analysist &_heap_analysis): + ns(ns_), + heap_analysis(_heap_analysis) { operator()(goto_function, ns_); } protected: - virtual void initialize(const goto_functionst::goto_functiont &goto_function) override; + virtual void initialize( + const goto_functionst::goto_functiont &goto_function) override; void assign_ptr_param(const exprt &expr, ssa_value_domaint &entry); From 53d1c900f3f374986ad6123274fee1ea3a5b18a7 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 22 Sep 2017 16:36:23 +0200 Subject: [PATCH 093/322] Strategy solver for heap domain does not fail when the solver returns address of something different than a symbol. Instead, we consider this as nondeterministic value. Fixes #2. --- src/domains/strategy_solver_heap.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index 8542a014e..caa9b3922 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -140,7 +140,17 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) // Template row pointer points to the heap (p = &obj) debug() << from_expr(ns, "", ptr_value) << eom; assert(ptr_value.id()==ID_address_of); - assert(to_address_of_expr(ptr_value).object().id()==ID_symbol); + if(to_address_of_expr(ptr_value).object().id()!=ID_symbol) + { + // If solver did not return address of a symbol, it is considered + // as nondet value. + if(heap_domain.set_nondet(row, inv)) + { + improved=true; + debug() << "Set nondet" << eom; + } + continue; + } symbol_exprt obj=to_symbol_expr( to_address_of_expr(ptr_value).object()); From e12bca489b584de05a757e28a03893bc1a77815b Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 30 Oct 2017 07:33:15 +0100 Subject: [PATCH 094/322] Fix bugs in heap-interval domain combination. If both domains return True, result is just True, not True && True. Also improve filtering of variables. --- src/domains/heap_interval_domain.cpp | 4 +++- src/domains/template_generator_base.cpp | 9 ++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/domains/heap_interval_domain.cpp b/src/domains/heap_interval_domain.cpp index 381ea662e..95ca71fac 100644 --- a/src/domains/heap_interval_domain.cpp +++ b/src/domains/heap_interval_domain.cpp @@ -96,5 +96,7 @@ void heap_interval_domaint::project_on_vars( exprt interval_result; interval_domain.project_on_vars(v.interval_value, vars, interval_result); - result=and_exprt(heap_result, interval_result); + result=heap_result; + if(interval_result!=true_exprt()) + result=and_exprt(result, interval_result); } diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index d640bb449..f12c18900 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -772,6 +772,11 @@ void template_generator_baset::filter_heap_interval_domain() { const domaint::vart &s=v->var; + if(s.id()==ID_symbol && is_pointed(s) && + id2string(to_symbol_expr(s).get_identifier()).find(".")!= + std::string::npos) + continue; + if(s.type().id()==ID_unsignedbv || s.type().id()==ID_signedbv || s.type().id()==ID_floatbv) @@ -780,9 +785,7 @@ void template_generator_baset::filter_heap_interval_domain() continue; } - if(s.id()==ID_symbol && s.type().id()==ID_pointer && - id2string(to_symbol_expr(s).get_identifier()).find("__CPROVER")== - std::string::npos) + if(s.id()==ID_symbol && s.type().id()==ID_pointer) { // Filter out non-assigned OUT variables if(v->kind!=domaint::OUT || From 7b0d7de006419ba6d61ac9dff738b106157837b1 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Mon, 6 Nov 2017 00:37:02 +0000 Subject: [PATCH 095/322] Abort if tests fail --- regression/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regression/Makefile b/regression/Makefile index 78916c1c3..0b4d2b0bd 100644 --- a/regression/Makefile +++ b/regression/Makefile @@ -2,7 +2,7 @@ DIRS = heap nontermination termination kiki \ preconditions interprocedural invariants test: - $(foreach var,$(DIRS), make -C $(var) test;) + $(foreach var,$(DIRS), make -C $(var) test || exit 1;) clean: $(foreach var,$(DIRS), make -C $(var) clean;) From a2506b367f39d74cfb538d836fe0686329792d6a Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Mon, 6 Nov 2017 01:35:17 +0000 Subject: [PATCH 096/322] Fix formatting and remove buggy linter rules --- scripts/cpplint.py | 19 ------ src/2ls/2ls_parse_options.cpp | 7 ++- src/2ls/dynamic_cfg.cpp | 3 +- src/2ls/graphml_witness_ext.h | 3 +- src/2ls/instrument_goto.cpp | 3 +- src/2ls/preprocessing_util.cpp | 2 +- src/2ls/summary_checker_ai.h | 3 +- src/2ls/summary_checker_base.h | 3 +- src/2ls/summary_checker_bmc.h | 3 +- src/2ls/summary_checker_kind.h | 3 +- src/2ls/summary_checker_nonterm.h | 3 +- src/domains/incremental_solver.h | 6 +- src/domains/lexlinrank_domain.cpp | 14 +++-- src/domains/linrank_domain.cpp | 13 ++-- src/domains/predabs_domain.cpp | 7 ++- src/domains/predabs_domain.h | 4 +- src/domains/ssa_analyzer.cpp | 3 + src/domains/template_generator_base.cpp | 63 ++++++++++--------- src/domains/template_generator_base.h | 3 +- .../template_generator_callingcontext.cpp | 2 +- src/domains/template_generator_ranking.cpp | 8 +-- src/domains/tpolyhedra_domain.h | 26 +++++--- src/domains/util.cpp | 5 +- src/domains/util.h | 9 ++- src/solver/summarizer_bw.h | 15 +++-- src/solver/summarizer_fw.h | 15 +++-- src/ssa/assignments.h | 6 +- src/ssa/local_ssa.cpp | 20 +++--- src/ssa/ssa_heap_domain.cpp | 3 +- src/ssa/ssa_inliner.cpp | 14 +++-- src/ssa/ssa_inliner.h | 12 ++-- src/ssa/ssa_unwinder.cpp | 33 ++++++---- src/ssa/ssa_unwinder.h | 16 +++-- src/ssa/ssa_value_set.cpp | 3 +- src/ssa/ssa_value_set.h | 13 ++-- src/ssa/unwindable_local_ssa.h | 5 +- 36 files changed, 210 insertions(+), 160 deletions(-) diff --git a/scripts/cpplint.py b/scripts/cpplint.py index 57d9025d7..0d738f589 100644 --- a/scripts/cpplint.py +++ b/scripts/cpplint.py @@ -4738,27 +4738,8 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state, 'If parameters or arguments require a line break, each parameter should be put on its own line.') # Skip to the end of the bracket start_linenum = nested_close_linenum - else: - if(not Match('^\s*[^,]+,$', arg_line)): - error(filename, start_linenum, 'whitespace/indent', 4, - 'If parameters or arguments require a line break, each parameter should be put on its own line.') start_linenum+=1 - # For the final line we also need to check one parameter on it - # e.g. we require bracket on same line as last parameter - # foo( - # x); - if not Search(r'^\s*[^,]+\)', close_line): - # If this is true, the we failed because we just had the close bracket - if Search(r'[^,]*\)', close_line): - error(filename, close_linenum, 'whitespace/indent', 4, - 'If parameters or arguments require a line break, the closing bracket should be on the same line as the final parameter') - else: - # In this case the problem is we had a bracket - # i.e. more than one parameter on the last line - error(filename, close_linenum, 'whitespace/indent', 4, - 'If parameters or arguments require a line break, each parameter should be put on its own line.') - if (Search(r'\([^\)]*$', elided_prev) and initial_spaces-2 != prev_initial_spaces) and not Search(r'for|while|if|;', elided_prev): error(filename, linenum, 'whitespace/indent', 4, diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 976ec86af..f34f42022 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -488,9 +488,9 @@ int twols_parse_optionst::doit() status() << "Havocking loops and function calls" << eom; else if(options.get_bool_option("equalities")) status() << "Using (dis)equalities domain" << eom; - else if (options.get_bool_option("heap")) + else if(options.get_bool_option("heap")) status() << "Using heap domain" << eom; - else if (options.get_bool_option("heap-interval")) + else if(options.get_bool_option("heap-interval")) status() << "Using heap domain with interval domain for values" << eom; else { @@ -1064,7 +1064,8 @@ bool twols_parse_optionst::process_goto_program( { status() << "Function Pointer Removal" << eom; remove_function_pointers( - goto_model, cmdline.isset("pointer-check")); + goto_model, + cmdline.isset("pointer-check")); // do partial inlining if(options.get_bool_option("inline-partial")) diff --git a/src/2ls/dynamic_cfg.cpp b/src/2ls/dynamic_cfg.cpp index 807ec5ed3..d6507a3d9 100644 --- a/src/2ls/dynamic_cfg.cpp +++ b/src/2ls/dynamic_cfg.cpp @@ -293,7 +293,8 @@ 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..6294ffc1b 100644 --- a/src/2ls/graphml_witness_ext.h +++ b/src/2ls/graphml_witness_ext.h @@ -28,7 +28,8 @@ class graphml_witness_extt:public graphml_witnesst protected: graphmlt::node_indext add_node( - std::map &loc_to_node, + std::map &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/preprocessing_util.cpp b/src/2ls/preprocessing_util.cpp index 47d98a908..753c0eb39 100644 --- a/src/2ls/preprocessing_util.cpp +++ b/src/2ls/preprocessing_util.cpp @@ -540,7 +540,7 @@ Function: twols_parse_optionst::add_dynamic_object_rec void twols_parse_optionst::add_dynamic_object_rec( exprt &expr, symbol_tablet &symbol_table) { - if (expr.id()==ID_symbol) + if(expr.id()==ID_symbol) { const symbolt &symbol= symbol_table.lookup(to_symbol_expr(expr).get_identifier()); diff --git a/src/2ls/summary_checker_ai.h b/src/2ls/summary_checker_ai.h index 600c1fce6..87b477902 100644 --- a/src/2ls/summary_checker_ai.h +++ b/src/2ls/summary_checker_ai.h @@ -15,7 +15,8 @@ class summary_checker_ait:public summary_checker_baset { public: inline summary_checker_ait( - optionst &_options, const ssa_heap_analysist &heap_analysis): + optionst &_options, + const ssa_heap_analysist &heap_analysis): summary_checker_baset(_options, heap_analysis) { } diff --git a/src/2ls/summary_checker_base.h b/src/2ls/summary_checker_base.h index 8e37ad3c2..0d65062ce 100644 --- a/src/2ls/summary_checker_base.h +++ b/src/2ls/summary_checker_base.h @@ -29,7 +29,8 @@ class summary_checker_baset:public property_checkert { public: summary_checker_baset( - optionst &_options, const ssa_heap_analysist &_heap_analysis): + optionst &_options, + const ssa_heap_analysist &_heap_analysis): show_vcc(false), simplify(false), fixed_point(false), diff --git a/src/2ls/summary_checker_bmc.h b/src/2ls/summary_checker_bmc.h index 6821ceea7..907b873cf 100644 --- a/src/2ls/summary_checker_bmc.h +++ b/src/2ls/summary_checker_bmc.h @@ -15,7 +15,8 @@ class summary_checker_bmct:public summary_checker_baset { public: summary_checker_bmct( - optionst &_options, const ssa_heap_analysist &heap_analysis): + optionst &_options, + const ssa_heap_analysist &heap_analysis): summary_checker_baset(_options, heap_analysis) { } diff --git a/src/2ls/summary_checker_kind.h b/src/2ls/summary_checker_kind.h index 77e8885d8..d5596b642 100644 --- a/src/2ls/summary_checker_kind.h +++ b/src/2ls/summary_checker_kind.h @@ -15,7 +15,8 @@ class summary_checker_kindt:public summary_checker_baset { public: inline summary_checker_kindt( - optionst &_options, const ssa_heap_analysist &heap_analysis): + optionst &_options, + const ssa_heap_analysist &heap_analysis): summary_checker_baset(_options, heap_analysis) { } diff --git a/src/2ls/summary_checker_nonterm.h b/src/2ls/summary_checker_nonterm.h index 48245e20e..d8a87afa3 100644 --- a/src/2ls/summary_checker_nonterm.h +++ b/src/2ls/summary_checker_nonterm.h @@ -15,7 +15,8 @@ class summary_checker_nontermt:public summary_checker_baset { public: explicit summary_checker_nontermt( - optionst &_options, const ssa_heap_analysist &heap_analysis): + optionst &_options, + const ssa_heap_analysist &heap_analysis): summary_checker_baset(_options, heap_analysis) { } diff --git a/src/domains/incremental_solver.h b/src/domains/incremental_solver.h index 08f5b1ae2..b4a0599c4 100644 --- a/src/domains/incremental_solver.h +++ b/src/domains/incremental_solver.h @@ -203,8 +203,10 @@ static inline incremental_solvert &operator<<( *dest.solver << src; #else if(!dest.activation_literals.empty()) - dest.debug_add_to_formula( - or_exprt(src, literal_exprt(!dest.activation_literals.back()))); + { + literal_exprt act_lit(!dest.activation_literals.back()); + dest.debug_add_to_formula(or_exprt(src, act_lit)); + } else dest.debug_add_to_formula(src); #endif diff --git a/src/domains/lexlinrank_domain.cpp b/src/domains/lexlinrank_domain.cpp index 0fc5aa5ea..60424d65e 100644 --- a/src/domains/lexlinrank_domain.cpp +++ b/src/domains/lexlinrank_domain.cpp @@ -611,16 +611,18 @@ void lexlinrank_domaint::project_on_vars( if(is_row_value_false(v[row])) { // (g=> false) - c.push_back(implies_exprt( - and_exprt(templ[row].pre_guard, templ[row].post_guard), - false_exprt())); + c.push_back( + implies_exprt( + and_exprt(templ[row].pre_guard, templ[row].post_guard), + false_exprt())); } else if(is_row_value_true(v[row])) { // (g=> true) - c.push_back(implies_exprt( - and_exprt(templ[row].pre_guard, templ[row].post_guard), - true_exprt())); + c.push_back( + implies_exprt( + and_exprt(templ[row].pre_guard, templ[row].post_guard), + true_exprt())); } else { diff --git a/src/domains/linrank_domain.cpp b/src/domains/linrank_domain.cpp index 064ce3859..fe87be000 100644 --- a/src/domains/linrank_domain.cpp +++ b/src/domains/linrank_domain.cpp @@ -457,8 +457,10 @@ void linrank_domaint::project_on_vars( else if(is_row_value_false(v[row])) { // (g=> false) - c.push_back(implies_exprt( - and_exprt(templ[row].pre_guard, templ[row].post_guard), false_exprt())); + c.push_back( + implies_exprt( + and_exprt(templ[row].pre_guard, templ[row].post_guard), + false_exprt())); } else { @@ -504,9 +506,10 @@ void linrank_domaint::project_on_vars( #endif exprt decreasing=binary_relation_exprt(sum_pre, ID_gt, sum_post); #endif - c.push_back(implies_exprt( - and_exprt(templ[row].pre_guard, templ[row].post_guard), - decreasing)); + c.push_back( + implies_exprt( + and_exprt(templ[row].pre_guard, templ[row].post_guard), + decreasing)); } } result=conjunction(c); diff --git a/src/domains/predabs_domain.cpp b/src/domains/predabs_domain.cpp index ec05e41ac..12d298aad 100644 --- a/src/domains/predabs_domain.cpp +++ b/src/domains/predabs_domain.cpp @@ -276,9 +276,10 @@ void predabs_domaint::project_on_vars( const row_valuet &row_v=v[row]; if(templ_row.kind==LOOP) { - c.push_back(implies_exprt( - templ_row.pre_guard, - implies_exprt(row_v, templ_row.expr))); + c.push_back( + implies_exprt( + templ_row.pre_guard, + implies_exprt(row_v, templ_row.expr))); } else { 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/ssa_analyzer.cpp b/src/domains/ssa_analyzer.cpp index 301cb1ff2..b8a85fb53 100644 --- a/src/domains/ssa_analyzer.cpp +++ b/src/domains/ssa_analyzer.cpp @@ -34,11 +34,14 @@ Author: Peter Schrammel #include "strategy_solver_heap.h" #include "strategy_solver_heap_interval.h" +// NOLINTNEXTLINE(*) #define BINSEARCH_SOLVER strategy_solver_binsearcht(\ *static_cast(domain), solver, SSA.ns) #if 0 +// NOLINTNEXTLINE(*) #define BINSEARCH_SOLVER strategy_solver_binsearch2t(\ *static_cast(domain), solver, SSA.ns) +// NOLINTNEXTLINE(*) #define BINSEARCH_SOLVER strategy_solver_binsearch3t(\ *static_cast(domain), solver, SSA, SSA.ns) #endif diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index f12c18900..38f6f83fc 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -321,8 +321,9 @@ void template_generator_baset::add_var( exprt post_var=post_renaming_map[var]; exprt aux_var=aux_renaming_map[var]; aux_expr=and_exprt( - implies_exprt(and_exprt(post_guard, not_exprt(init_guard)), - equal_exprt(aux_var, post_var)), + implies_exprt( + and_exprt(post_guard, not_exprt(init_guard)), + equal_exprt(aux_var, post_var)), implies_exprt(init_guard, equal_exprt(aux_var, init_renaming_map[var]))); post_guard=or_exprt(post_guard, init_guard); } @@ -625,11 +626,14 @@ bool template_generator_baset::instantiate_custom_templates( if(contains_new_var) add_post_vars=true; - static_cast(domain_ptr)->add_template_row( - expr, pre_guard, - contains_new_var ? and_exprt(pre_guard, post_guard) : post_guard, - aux_expr, - contains_new_var ? domaint::OUT : domaint::LOOP); + static_cast(domain_ptr) + ->add_template_row( + expr, + pre_guard, + contains_new_var ? + and_exprt(pre_guard, post_guard) : post_guard, + aux_expr, + contains_new_var ? domaint::OUT : domaint::LOOP); } // pred abs domain else if(predabs) @@ -650,11 +654,14 @@ bool template_generator_baset::instantiate_custom_templates( if(contains_new_var) add_post_vars=true; - static_cast(domain_ptr)->add_template_row( - expr, pre_guard, - contains_new_var ? and_exprt(pre_guard, post_guard) : post_guard, - aux_expr, - contains_new_var ? domaint::OUT : domaint::LOOP); + static_cast(domain_ptr) + ->add_template_row( + expr, + pre_guard, + contains_new_var ? + and_exprt(pre_guard, post_guard) : post_guard, + aux_expr, + contains_new_var ? domaint::OUT : domaint::LOOP); } else // neither pred abs, nor polyhedra { @@ -720,40 +727,40 @@ void template_generator_baset::instantiate_standard_domains( domain_ptr= new tpolyhedra_domaint(domain_number, renaming_map, SSA.ns); filter_template_domain(); - static_cast(domain_ptr)->add_interval_template( - var_specs, SSA.ns); + static_cast(domain_ptr) + ->add_interval_template(var_specs, SSA.ns); } else if(options.get_bool_option("zones")) { domain_ptr= new tpolyhedra_domaint(domain_number, renaming_map, SSA.ns); filter_template_domain(); - static_cast(domain_ptr)->add_difference_template( - var_specs, SSA.ns); - static_cast(domain_ptr)->add_interval_template( - var_specs, SSA.ns); + static_cast(domain_ptr) + ->add_difference_template(var_specs, SSA.ns); + static_cast(domain_ptr) + ->add_interval_template(var_specs, SSA.ns); } else if(options.get_bool_option("octagons")) { domain_ptr= new tpolyhedra_domaint(domain_number, renaming_map, SSA.ns); filter_template_domain(); - static_cast(domain_ptr)->add_sum_template( - var_specs, SSA.ns); - static_cast(domain_ptr)->add_difference_template( - var_specs, SSA.ns); - static_cast(domain_ptr)->add_interval_template( - var_specs, SSA.ns); + static_cast(domain_ptr) + ->add_sum_template(var_specs, SSA.ns); + static_cast(domain_ptr) + ->add_difference_template(var_specs, SSA.ns); + static_cast(domain_ptr) + ->add_interval_template(var_specs, SSA.ns); } else if(options.get_bool_option("qzones")) { domain_ptr= new tpolyhedra_domaint(domain_number, renaming_map, SSA.ns); filter_template_domain(); - static_cast(domain_ptr)->add_difference_template( - var_specs, SSA.ns); - static_cast(domain_ptr)->add_quadratic_template( - var_specs, SSA.ns); + static_cast(domain_ptr) + ->add_difference_template(var_specs, SSA.ns); + static_cast(domain_ptr) + ->add_quadratic_template(var_specs, SSA.ns); } else if(options.get_bool_option("heap-interval")) { diff --git a/src/domains/template_generator_base.h b/src/domains/template_generator_base.h index a88dc2d03..50b3fff03 100644 --- a/src/domains/template_generator_base.h +++ b/src/domains/template_generator_base.h @@ -104,7 +104,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_callingcontext.cpp b/src/domains/template_generator_callingcontext.cpp index ba9adfd4d..e4c51cbcb 100644 --- a/src/domains/template_generator_callingcontext.cpp +++ b/src/domains/template_generator_callingcontext.cpp @@ -116,7 +116,7 @@ void template_generator_callingcontextt::collect_variables_callingcontext( a_it!=f_it->arguments().end(); a_it++) { std::set args; - find_symbols(*a_it,args); + find_symbols(*a_it, args); exprt arg=*a_it; add_vars(args, guard, guard, domaint::OUT, var_specs); } diff --git a/src/domains/template_generator_ranking.cpp b/src/domains/template_generator_ranking.cpp index fab04e251..c7a27b0cc 100644 --- a/src/domains/template_generator_ranking.cpp +++ b/src/domains/template_generator_ranking.cpp @@ -133,11 +133,11 @@ void template_generator_rankingt::collect_variables_ranking( filter_ranking_domain(new_var_specs); #ifndef LEXICOGRAPHIC - static_cast(domain_ptr)->add_template( - new_var_specs, SSA.ns); + static_cast(domain_ptr) + ->add_template(new_var_specs, SSA.ns); #else - static_cast(domain_ptr)->add_template( - new_var_specs, SSA.ns); + static_cast(domain_ptr) + ->add_template(new_var_specs, SSA.ns); #endif var_specs.insert( diff --git a/src/domains/tpolyhedra_domain.h b/src/domains/tpolyhedra_domain.h index 866a5accb..0e178c1e8 100644 --- a/src/domains/tpolyhedra_domain.h +++ b/src/domains/tpolyhedra_domain.h @@ -73,7 +73,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); @@ -97,13 +98,18 @@ class tpolyhedra_domaint:public domaint // printing virtual void output_value( - std::ostream &out, const valuet &value, const namespacet &ns) const; + std::ostream &out, + const valuet &value, + const namespacet &ns) const; virtual void output_domain( - std::ostream &out, const namespacet &ns) const; + std::ostream &out, + const namespacet &ns) const; // projection virtual void project_on_vars( - valuet &value, const var_sett &vars, exprt &result); + valuet &value, + const var_sett &vars, + exprt &result); unsigned template_size(); @@ -116,13 +122,17 @@ class tpolyhedra_domaint:public domaint kindt kind); void add_interval_template( - const var_specst &var_specs, const namespacet &ns); + const var_specst &var_specs, + const namespacet &ns); void add_difference_template( - const var_specst &var_specs, const namespacet &ns); + const var_specst &var_specs, + const namespacet &ns); void add_sum_template( - const var_specst &var_specs, const namespacet &ns); + const var_specst &var_specs, + const namespacet &ns); void add_quadratic_template( - const var_specst &var_specs, const namespacet &ns); + const var_specst &var_specs, + const namespacet &ns); symbol_exprt get_row_symb_value(const rowt &row); diff --git a/src/domains/util.cpp b/src/domains/util.cpp index ec12ad55a..4833531e6 100644 --- a/src/domains/util.cpp +++ b/src/domains/util.cpp @@ -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 && diff --git a/src/domains/util.h b/src/domains/util.h index de0c316ef..790473db4 100644 --- a/src/domains/util.h +++ b/src/domains/util.h @@ -21,9 +21,14 @@ constant_exprt simplify_const(const exprt &expr); ieee_floatt simplify_const_float(const exprt &expr); mp_integer simplify_const_int(const exprt &expr); void pretty_print_termination_argument( - std::ostream &out, const namespacet &ns, const exprt &expr); + std::ostream &out, + const namespacet &ns, + const exprt &expr); void merge_and( - exprt & result, const exprt &expr1, const exprt &expr2, const namespacet &ns); + exprt & result, + const exprt &expr1, + const exprt &expr2, + const namespacet &ns); constant_exprt make_zero(const typet &type); constant_exprt make_one(const typet &type); constant_exprt make_minusone(const typet &type); diff --git a/src/solver/summarizer_bw.h b/src/solver/summarizer_bw.h index 540f8fedd..638a70733 100644 --- a/src/solver/summarizer_bw.h +++ b/src/solver/summarizer_bw.h @@ -23,14 +23,13 @@ Author: Peter Schrammel class summarizer_bwt:public summarizer_baset { public: - explicit summarizer_bwt( - optionst &_options, - summary_dbt &_summary_db, - ssa_dbt &_ssa_db, - ssa_unwindert &_ssa_unwinder, - ssa_inlinert &_ssa_inliner): - summarizer_baset( - _options, _summary_db, _ssa_db, _ssa_unwinder, _ssa_inliner) + summarizer_bwt( + optionst &options, + summary_dbt &summary_db, + ssa_dbt &ssa_db, + ssa_unwindert &ssa_unwinder, + ssa_inlinert &ssa_inliner): + summarizer_baset(options, summary_db, ssa_db, ssa_unwinder, ssa_inliner) { } diff --git a/src/solver/summarizer_fw.h b/src/solver/summarizer_fw.h index f21255c55..6ee541620 100644 --- a/src/solver/summarizer_fw.h +++ b/src/solver/summarizer_fw.h @@ -23,14 +23,13 @@ Author: Peter Schrammel class summarizer_fwt:public summarizer_baset { public: - explicit summarizer_fwt( - optionst &_options, - summary_dbt &_summary_db, - ssa_dbt &_ssa_db, - ssa_unwindert &_ssa_unwinder, - ssa_inlinert &_ssa_inliner): - summarizer_baset( - _options, _summary_db, _ssa_db, _ssa_unwinder, _ssa_inliner) + summarizer_fwt( + optionst &options, + summary_dbt &summary_db, + ssa_dbt &ssa_db, + ssa_unwindert &ssa_unwinder, + ssa_inlinert &ssa_inliner): + summarizer_baset(options, summary_db, ssa_db, ssa_unwinder, ssa_inliner) { } diff --git a/src/ssa/assignments.h b/src/ssa/assignments.h index 6ca3ec3a1..3694fb4fc 100644 --- a/src/ssa/assignments.h +++ b/src/ssa/assignments.h @@ -65,11 +65,13 @@ class assignmentst void build_assignment_map(const goto_programt &, const namespacet &); void assign( - const exprt &lhs, locationt, + const exprt &lhs, + locationt, const namespacet &ns); void assign( - const ssa_objectt &lhs, locationt, + const ssa_objectt &lhs, + locationt, const namespacet &ns); }; diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index ddd63ecd4..5ef8cf09a 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -200,9 +200,10 @@ void local_SSAt::collect_custom_templates() if(nn_it->templates.empty()) continue; - n_it->loophead->templates.insert(n_it->loophead->templates.end(), - nn_it->templates.begin(), - nn_it->templates.end()); + n_it->loophead->templates.insert( + n_it->loophead->templates.end(), + nn_it->templates.begin(), + nn_it->templates.end()); nn_it->templates.clear(); } } @@ -716,8 +717,10 @@ void local_SSAt::assertions_to_constraints() n_it!=nodes.end(); n_it++) { - n_it->constraints.insert(n_it->constraints.end(), - n_it->assertions.begin(), n_it->assertions.end()); + n_it->constraints.insert( + n_it->constraints.end(), + n_it->assertions.begin(), + n_it->assertions.end()); } } @@ -1041,9 +1044,10 @@ exprt local_SSAt::read_rhs_rec(const exprt &expr, locationt loc) const else if(expr.id()==ID_index) { const index_exprt &index_expr=to_index_expr(expr); - return index_exprt(read_rhs(index_expr.array(), loc), - read_rhs(index_expr.index(), loc), - expr.type()); + return index_exprt( + read_rhs(index_expr.array(), loc), + read_rhs(index_expr.index(), loc), + expr.type()); } ssa_objectt object(expr, ns); diff --git a/src/ssa/ssa_heap_domain.cpp b/src/ssa/ssa_heap_domain.cpp index deab41dba..7a641297d 100644 --- a/src/ssa/ssa_heap_domain.cpp +++ b/src/ssa/ssa_heap_domain.cpp @@ -658,7 +658,8 @@ const exprt ssa_heap_domaint::function_infot::apply_deref( const exprt &expr, unsigned level) const { - if(level==0) return expr; + if(level==0) + return expr; exprt deref; if(expr.id()==ID_address_of) diff --git a/src/ssa/ssa_inliner.cpp b/src/ssa/ssa_inliner.cpp index 6f0e73d91..bce39e7e8 100644 --- a/src/ssa/ssa_inliner.cpp +++ b/src/ssa/ssa_inliner.cpp @@ -196,8 +196,8 @@ void ssa_inlinert::get_summaries( if(summary_db.exists(fname)) { - get_summary(SSA, n_it, f_it, summary_db.get(fname), - forward, summaries, bindings); + get_summary( + SSA, n_it, f_it, summary_db.get(fname), forward, summaries, bindings); } } } @@ -370,15 +370,17 @@ void ssa_inlinert::replace( { rename(precondition); node->constraints.push_back( - implies_exprt(SSA.guard_symbol(node->location), - precondition)); + implies_exprt( + SSA.guard_symbol(node->location), + precondition)); } else { rename(precondition); node->assertions.push_back( - implies_exprt(SSA.guard_symbol(node->location), - precondition)); + implies_exprt( + SSA.guard_symbol(node->location), + precondition)); } exprt transformer; if(forward) diff --git a/src/ssa/ssa_inliner.h b/src/ssa/ssa_inliner.h index 487bfe667..57634bf7a 100644 --- a/src/ssa/ssa_inliner.h +++ b/src/ssa/ssa_inliner.h @@ -47,10 +47,8 @@ class ssa_inlinert:public messaget 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); @@ -64,10 +62,8 @@ class ssa_inlinert:public messaget 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::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); void replace( diff --git a/src/ssa/ssa_unwinder.cpp b/src/ssa/ssa_unwinder.cpp index aecf2166c..26ec5c232 100644 --- a/src/ssa/ssa_unwinder.cpp +++ b/src/ssa/ssa_unwinder.cpp @@ -280,8 +280,9 @@ void ssa_local_unwindert::unwind(unsigned k) return; current_enabling_expr= - symbol_exprt("unwind::"+id2string(fname)+"::enable"+i2string(k), - bool_typet()); + symbol_exprt( + "unwind::"+id2string(fname)+"::enable"+i2string(k), + bool_typet()); SSA.enabling_exprs.push_back(current_enabling_expr); // TODO: just for exploratory integration, must go away @@ -559,8 +560,9 @@ void ssa_local_unwindert::add_loop_connector(loopt &loop) SSA.increment_unwindings(0); } else if(e_it->lhs().id()==ID_symbol && - !has_prefix(id2string(to_symbol_expr(e_it->lhs()).get_identifier()), - "ssa::$guard")) + !has_prefix( + id2string(to_symbol_expr(e_it->lhs()).get_identifier()), + "ssa::$guard")) { // this is needed for while loops node.equalities.push_back(*e_it); SSA.decrement_unwindings(0); @@ -569,8 +571,9 @@ void ssa_local_unwindert::add_loop_connector(loopt &loop) } } // continuation guard and condition - exprt g_rhs=and_exprt(SSA.guard_symbol(loop.body_nodes.back().location), - SSA.cond_symbol(loop.body_nodes.back().location)); + exprt g_rhs=and_exprt( + SSA.guard_symbol(loop.body_nodes.back().location), + SSA.cond_symbol(loop.body_nodes.back().location)); SSA.decrement_unwindings(0); exprt g_lhs=SSA.guard_symbol(loop.body_nodes.begin()->location); SSA.increment_unwindings(0); @@ -591,8 +594,10 @@ Function: ssa_local_unwindert::add_exit_merges void ssa_local_unwindert::add_exit_merges(loopt &loop, unsigned k) { - SSA.nodes.push_back(local_SSAt::nodet(loop.body_nodes.begin()->location, - SSA.nodes.end())); // add new node + SSA.nodes.push_back( + local_SSAt::nodet( + loop.body_nodes.begin()->location, + SSA.nodes.end())); // add new node local_SSAt::nodet &node=SSA.nodes.back(); node.enabling_expr=current_enabling_expr; @@ -716,8 +721,9 @@ Function: ssa_local_unwindert::get_continuation_condition exprt ssa_local_unwindert::get_continuation_condition(const loopt& loop) const { SSA.current_location=loop.body_nodes.back().location; // TODO: must go away - return and_exprt(SSA.guard_symbol(loop.body_nodes.back().location), - SSA.cond_symbol(loop.body_nodes.back().location)); + return and_exprt( + SSA.guard_symbol(loop.body_nodes.back().location), + SSA.cond_symbol(loop.body_nodes.back().location)); } /*******************************************************************\ @@ -895,9 +901,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..840d97b24 100644 --- a/src/ssa/ssa_unwinder.h +++ b/src/ssa/ssa_unwinder.h @@ -50,12 +50,16 @@ class ssa_local_unwindert // TODO: these two should be possible with unwindable_local_ssa facilities exprt rename_invariant(const exprt& inv_in) const; 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; #endif // 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 { @@ -110,7 +114,8 @@ class ssa_local_unwindert exprt get_continuation_condition(const loopt& loop) const; void loop_continuation_conditions( - const loopt& loop, exprt::operandst &loop_cont) const; + const loopt& loop, + exprt::operandst &loop_cont) const; void add_loop_body(loopt &loop); void add_assertions(loopt &loop, bool is_last); @@ -118,7 +123,10 @@ class ssa_local_unwindert void add_loop_connector(loopt &loop); void add_exit_merges(loopt &loop, unsigned k); equal_exprt build_exit_merge( - exprt e, const exprt &exits, unsigned k, locationt loc); + exprt e, + const exprt &exits, + unsigned k, + locationt loc); void add_hoisted_assertions(loopt &loop, bool is_last); }; diff --git a/src/ssa/ssa_value_set.cpp b/src/ssa/ssa_value_set.cpp index 27875522c..4af078da2 100644 --- a/src/ssa/ssa_value_set.cpp +++ b/src/ssa/ssa_value_set.cpp @@ -621,7 +621,8 @@ bool ssa_value_domaint::valuest::merge( continue; } } - if(is_iterator(v.get_expr())) continue; + if(is_iterator(v.get_expr())) + continue; } else { diff --git a/src/ssa/ssa_value_set.h b/src/ssa/ssa_value_set.h index d2ee2654f..e2e79c791 100644 --- a/src/ssa/ssa_value_set.h +++ b/src/ssa/ssa_value_set.h @@ -19,7 +19,9 @@ class ssa_value_domaint:public ai_domain_baset public: virtual void transform(locationt, locationt, ai_baset &, const namespacet &); virtual void output( - std::ostream &, const ai_baset &, const namespacet &) const; + std::ostream &, + const ai_baset &, + const namespacet &) const; bool merge(const ssa_value_domaint &, locationt, locationt); struct valuest @@ -70,18 +72,21 @@ class ssa_value_domaint:public ai_domain_baset protected: void assign_lhs_rec( - const exprt &lhs, const exprt &rhs, + const exprt &lhs, + const exprt &rhs, const namespacet &, bool add=false); void assign_rhs_rec( - valuest &lhs, const exprt &rhs, + valuest &lhs, + const exprt &rhs, const namespacet &, bool offset, unsigned alignment) const; void assign_rhs_rec_address_of( - valuest &lhs, const exprt &rhs, + valuest &lhs, + const exprt &rhs, const namespacet &, bool offset, unsigned alignment) const; diff --git a/src/ssa/unwindable_local_ssa.h b/src/ssa/unwindable_local_ssa.h index 3e7cf337b..ba1000d1c 100644 --- a/src/ssa/unwindable_local_ssa.h +++ b/src/ssa/unwindable_local_ssa.h @@ -38,7 +38,10 @@ class unwindable_local_SSAt:public local_SSAt return name(obj, kind, loc, loc); } symbol_exprt name( - const ssa_objectt &, kindt, locationt def_loc, locationt current_loc) const; + const ssa_objectt &, + kindt, + locationt def_loc, + locationt current_loc) const; virtual exprt nondet_symbol( std::string prefix, const typet &type, From 36dae0f5ec3fc188e26ac13951b04ec0d3ddcacf Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Mon, 6 Nov 2017 01:45:40 +0000 Subject: [PATCH 097/322] Set termination/global2 and interprocedural/contextsensitive to KNOWNBUG --- regression/interprocedural/contextsensitive5/test.desc | 2 +- regression/termination/global2/test.desc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/regression/interprocedural/contextsensitive5/test.desc b/regression/interprocedural/contextsensitive5/test.desc index 8f7a7b6f1..d30d23301 100644 --- a/regression/interprocedural/contextsensitive5/test.desc +++ b/regression/interprocedural/contextsensitive5/test.desc @@ -1,4 +1,4 @@ -CORE +KNOWNBUG main.c --equalities --context-sensitive ^EXIT=0$ diff --git a/regression/termination/global2/test.desc b/regression/termination/global2/test.desc index 9ebb38e34..bbaf10625 100644 --- a/regression/termination/global2/test.desc +++ b/regression/termination/global2/test.desc @@ -1,4 +1,4 @@ -CORE +KNOWNBUG main.c ^EXIT=0$ From 2e8254daf2fbfe9586fe54235b91e27832ad4c85 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Mon, 6 Nov 2017 01:48:55 +0000 Subject: [PATCH 098/322] version 0.5.3 --- src/2ls/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/2ls/version.h b/src/2ls/version.h index ec3fd48d6..19db87b69 100644 --- a/src/2ls/version.h +++ b/src/2ls/version.h @@ -9,6 +9,6 @@ Author: Peter Schrammel #ifndef CPROVER_2LS_2LS_VERSION_H #define CPROVER_2LS_2LS_VERSION_H -#define TWOLS_VERSION "0.5.2" +#define TWOLS_VERSION "0.5.3" #endif From 52b653296cd8b6bf32ead4c153cd087a3cd76405 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Mon, 6 Nov 2017 02:07:26 +0000 Subject: [PATCH 099/322] Fix compiler warning --- src/2ls/summary_checker_nonterm.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/2ls/summary_checker_nonterm.cpp b/src/2ls/summary_checker_nonterm.cpp index 9c5bd6705..ec784d87d 100644 --- a/src/2ls/summary_checker_nonterm.cpp +++ b/src/2ls/summary_checker_nonterm.cpp @@ -210,15 +210,17 @@ void summary_checker_nontermt::check_properties( cover_goals.add(p); } - status() << "Running " << solver.solver->decision_procedure_text() << eom; + status() << "Running " << solver.solver->decision_procedure_text() + << messaget::eom; cover_goals(); solver.pop_context(); - std::cout << "** " << cover_goals.number_covered() - << " of " << cover_goals.size() << " failed (" - << cover_goals.iterations() << " iterations)" << eom; + status() << "** " << cover_goals.number_covered() + << " of " << cover_goals.size() << " failed (" + << cover_goals.iterations() << " iterations)" + << messaget::eom; } /*******************************************************************\ From 85f21bc184120d8106ff415452945fb876dbbffa Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Mon, 6 Nov 2017 17:11:04 +0000 Subject: [PATCH 100/322] Fix nontermination witnesses --- src/2ls/2ls_parse_options.cpp | 4 +++- src/ssa/ssa_build_goto_trace.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index f34f42022..a93e62f77 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -279,6 +279,7 @@ void twols_parse_optionst::get_command_line_options(optionst &options) if(cmdline.isset("nontermination")) { options.set_option("nontermination", true); + options.set_option("all-properties", true); options.set_option("inline", true); if(!cmdline.isset("unwind")) options.set_option("unwind", std::numeric_limits::max()); @@ -598,7 +599,8 @@ int twols_parse_optionst::doit() report_properties(options, goto_model, checker->property_map); report_success(); if(cmdline.isset("graphml-witness") && - !options.get_bool_option("termination")) + !options.get_bool_option("termination") && + !options.get_bool_option("nontermination")) output_graphml_proof(options, goto_model, *checker); retval=0; break; diff --git a/src/ssa/ssa_build_goto_trace.cpp b/src/ssa/ssa_build_goto_trace.cpp index 2a24e33c6..89d966bd1 100644 --- a/src/ssa/ssa_build_goto_trace.cpp +++ b/src/ssa/ssa_build_goto_trace.cpp @@ -14,7 +14,7 @@ Author: Daniel Kroening, Peter Schrammel #include "ssa_build_goto_trace.h" -#define TERM_CEX 1 +#define TERM_CEX 0 /*******************************************************************\ From e7dadfa2b6182401650cebac33157d988add7e34 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Mon, 6 Nov 2017 17:14:49 +0000 Subject: [PATCH 101/322] Remove old nontermination witnesses --- src/2ls/summary_checker_ai.cpp | 18 ------------------ src/ssa/ssa_build_goto_trace.cpp | 14 -------------- 2 files changed, 32 deletions(-) diff --git a/src/2ls/summary_checker_ai.cpp b/src/2ls/summary_checker_ai.cpp index 765090016..8b4513532 100644 --- a/src/2ls/summary_checker_ai.cpp +++ b/src/2ls/summary_checker_ai.cpp @@ -9,8 +9,6 @@ Author: Peter Schrammel #include "summary_checker_ai.h" #include -#define TERM_CEX 0 - /*******************************************************************\ Function: summary_checker_ait::operator() @@ -158,22 +156,6 @@ property_checkert::resultt summary_checker_ait::report_termination() return property_checkert::PASS; if(one_nonterminate) { -#if TERM_CEX - if(options.get_option("graphml-witness")!="" && - !functions.empty()) - { - property_map.clear(); - incremental_solvert &solver=ssa_db.get_solver(functions.begin()->first); - if(solver()==decision_proceduret::D_SATISFIABLE) - { - irep_idt pid="non-termination"; - property_map[pid].result=property_checkert::FAIL; - ssa_build_goto_tracet build_goto_trace( - *functions.begin()->second, solver.get_solver(), true); - build_goto_trace(property_map[pid].error_trace); - } - } -#endif #if 1 return property_checkert::FAIL; #else diff --git a/src/ssa/ssa_build_goto_trace.cpp b/src/ssa/ssa_build_goto_trace.cpp index 89d966bd1..b5866a5bd 100644 --- a/src/ssa/ssa_build_goto_trace.cpp +++ b/src/ssa/ssa_build_goto_trace.cpp @@ -14,8 +14,6 @@ Author: Daniel Kroening, Peter Schrammel #include "ssa_build_goto_trace.h" -#define TERM_CEX 0 - /*******************************************************************\ Function: ssa_build_goto_tracet::finalize_lhs @@ -309,9 +307,6 @@ void ssa_build_goto_tracet::operator()( unwindable_local_SSA.current_unwindings.clear(); unsigned last_level=0; unsigned step_nr=1; -#if TERM_CEX - bool stop_next=false; -#endif while(current_pc!=unwindable_local_SSA.goto_function.body.instructions.end()) { @@ -358,12 +353,6 @@ void ssa_build_goto_tracet::operator()( // get successor if(current_pc->is_goto() && taken) { -#if TERM_CEX - if(termination && stop_next) - { - break; - } -#endif if(current_pc->is_backwards_goto()) { if(unwindable_local_SSA.current_unwindings.back()==0) @@ -378,9 +367,6 @@ void ssa_build_goto_tracet::operator()( unwindable_local_SSA.current_unwindings, 100) << std::endl; -#endif -#if TERM_CEX - stop_next=true; #endif } current_pc=current_pc->get_target(); From 4a68dc4726cc3b55195b5a1cf6e26984ff848a70 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Mon, 6 Nov 2017 22:25:35 +0000 Subject: [PATCH 102/322] Update CBMC pointer --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 596b2c259..378297417 100755 --- a/install.sh +++ b/install.sh @@ -1,7 +1,7 @@ #!/bin/bash CBMC_REPO=https://github.com/peterschrammel/cbmc -CBMC_VERSION=2ls-prerequisites-0.5 +CBMC_VERSION=2ls-prerequisites-0.6 if [ "$1" != "" ] then From e18072cb890f2d56fd87e16f4a2f1c41a11b38ad Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Mon, 6 Nov 2017 22:54:48 +0000 Subject: [PATCH 103/322] Better nontermination property ids --- src/2ls/summary_checker_nonterm.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/2ls/summary_checker_nonterm.cpp b/src/2ls/summary_checker_nonterm.cpp index ec784d87d..2819619ae 100644 --- a/src/2ls/summary_checker_nonterm.cpp +++ b/src/2ls/summary_checker_nonterm.cpp @@ -144,8 +144,9 @@ void summary_checker_nontermt::check_properties( { if(n_it->loophead!=SSA.nodes.end()) // we've found a loop { - irep_idt property_id= - irep_idt(n_it->loophead->location->location_number, 0); + irep_idt property_id( + id2string(n_it->location->function)+"."+ + std::to_string(n_it->location->loop_number)+".term"); exprt lsguard= SSA.name(SSA.guard_symbol(), local_SSAt::LOOP_SELECT, n_it->location); @@ -283,8 +284,9 @@ void summary_checker_nontermt::check_properties_linear( // we use continues further, therefore we put incrementation here loop_counter++; - irep_idt property_id= - irep_idt(n_it->loophead->location->location_number, 0); + irep_idt property_id( + id2string(n_it->location->function)+"."+ + std::to_string(n_it->location->loop_number)+".term"); const ssa_domaint::phi_nodest &phi_nodes= SSA.ssa_analysis[n_it->loophead->location].phi_nodes; From 354b5c22bca1b312ecea2d1a642291d22eb94a86 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sat, 11 Nov 2017 14:53:50 +0000 Subject: [PATCH 104/322] Download the chosen SAT solver --- install.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 378297417..299186752 100755 --- a/install.sh +++ b/install.sh @@ -12,7 +12,16 @@ git clone $CBMC_REPO cd cbmc CBMC=`pwd` git checkout $CBMC_VERSION -make -C src minisat2-download +if grep '^MINISAT2' src/config.inc > /dev/null +then + make -C src minisat2-download > /dev/null +elif grep '^GLUCOSE' src/config.inc +then + make -C src glucose-download +else + echo "SAT solver not supported" + exit 1 +fi if [ "$COMPILER" != "" ] then make -C src CXX=$COMPILER From 1c895e38d771c89d1824201ee1b475ca03e6edf0 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sat, 11 Nov 2017 14:56:43 +0000 Subject: [PATCH 105/322] Make invariant bound more configurable --- src/2ls/2ls_parse_options.cpp | 1 + src/2ls/summary_checker_kind.cpp | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index a93e62f77..828123bfa 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -319,6 +319,7 @@ void twols_parse_optionst::get_command_line_options(optionst &options) options.set_option("competition-mode", true); options.set_option("all-properties", false); options.set_option("inline", true); + options.set_option("give-up-invariants", "1"); } // instrumentation / output diff --git a/src/2ls/summary_checker_kind.cpp b/src/2ls/summary_checker_kind.cpp index 330fe62b6..3e8906773 100644 --- a/src/2ls/summary_checker_kind.cpp +++ b/src/2ls/summary_checker_kind.cpp @@ -8,8 +8,6 @@ Author: Peter Schrammel #include "summary_checker_kind.h" -#define GIVE_UP_INVARIANTS 4 - /*******************************************************************\ Function: summary_checker_kindt::operator() @@ -33,6 +31,8 @@ property_checkert::resultt summary_checker_kindt::operator()( property_checkert::resultt result=property_checkert::UNKNOWN; unsigned max_unwind=options.get_unsigned_int_option("unwind"); + unsigned give_up_invariants= + options.get_unsigned_int_option("give-up-invariants"); status() << "Max-unwind is " << max_unwind << eom; ssa_unwinder.init_localunwinders(); @@ -47,7 +47,7 @@ property_checkert::resultt summary_checker_kindt::operator()( result=check_properties(); bool magic_limit_not_reached= - unwind Date: Sat, 11 Nov 2017 15:07:57 +0000 Subject: [PATCH 106/322] version 0.5.4 --- src/2ls/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/2ls/version.h b/src/2ls/version.h index 19db87b69..d20069838 100644 --- a/src/2ls/version.h +++ b/src/2ls/version.h @@ -9,6 +9,6 @@ Author: Peter Schrammel #ifndef CPROVER_2LS_2LS_VERSION_H #define CPROVER_2LS_2LS_VERSION_H -#define TWOLS_VERSION "0.5.3" +#define TWOLS_VERSION "0.5.4" #endif From bdfb547b048fc0cb9d380e4a150b8a35140a4146 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sat, 11 Nov 2017 22:21:04 +0000 Subject: [PATCH 107/322] Switch off nontermination case in --termination --- src/2ls/summary_checker_ai.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/2ls/summary_checker_ai.cpp b/src/2ls/summary_checker_ai.cpp index 8b4513532..6f36857ab 100644 --- a/src/2ls/summary_checker_ai.cpp +++ b/src/2ls/summary_checker_ai.cpp @@ -156,7 +156,7 @@ property_checkert::resultt summary_checker_ait::report_termination() return property_checkert::PASS; if(one_nonterminate) { -#if 1 +#if 0 return property_checkert::FAIL; #else // rely on nontermination checker to find counterexample From 18552d41b9fe4a9cf3ef099d179235a81c2ede3a Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sun, 12 Nov 2017 11:04:43 +0000 Subject: [PATCH 108/322] Fix nontermination tests --- regression/nontermination/abort4/main.c | 15 +++++++++++++++ regression/nontermination/abort4/test.desc | 6 ++++++ regression/nontermination/abort5/main.c | 15 +++++++++++++++ regression/nontermination/abort5/test.desc | 6 ++++++ regression/nontermination/abort6/main.c | 15 +++++++++++++++ regression/nontermination/abort6/test.desc | 6 ++++++ regression/nontermination/float3/main.c | 10 ++++++++++ regression/nontermination/float3/test.desc | 6 ++++++ regression/nontermination/nontermloop1/main.c | 9 +++++++++ regression/nontermination/nontermloop1/test.desc | 6 ++++++ regression/nontermination/nontermloop2/main.c | 10 ++++++++++ regression/nontermination/nontermloop2/test.desc | 6 ++++++ regression/nontermination/nontermloop3/main.c | 11 +++++++++++ regression/nontermination/nontermloop3/test.desc | 6 ++++++ regression/nontermination/nontermloop4/main.c | 6 ++++++ regression/nontermination/nontermloop4/test.desc | 6 ++++++ regression/nontermination/phase3/main.c | 12 ++++++++++++ regression/nontermination/phase3/test.desc | 9 +++++++++ regression/nontermination/phase4/main.c | 11 +++++++++++ regression/nontermination/phase4/test.desc | 6 ++++++ regression/termination/abort4/test.desc | 7 +++++-- regression/termination/abort5/test.desc | 7 +++++-- regression/termination/abort6/test.desc | 7 +++++-- regression/termination/float3/test.desc | 7 +++++-- regression/termination/nontermloop1/test.desc | 7 +++++-- regression/termination/nontermloop2/test.desc | 3 +++ regression/termination/nontermloop3/test.desc | 7 +++++-- regression/termination/nontermloop4/test.desc | 7 +++++-- regression/termination/phase3/test.desc | 7 +++++-- regression/termination/phase4/test.desc | 7 +++++-- 30 files changed, 225 insertions(+), 18 deletions(-) create mode 100644 regression/nontermination/abort4/main.c create mode 100644 regression/nontermination/abort4/test.desc create mode 100644 regression/nontermination/abort5/main.c create mode 100644 regression/nontermination/abort5/test.desc create mode 100644 regression/nontermination/abort6/main.c create mode 100644 regression/nontermination/abort6/test.desc create mode 100644 regression/nontermination/float3/main.c create mode 100644 regression/nontermination/float3/test.desc create mode 100644 regression/nontermination/nontermloop1/main.c create mode 100644 regression/nontermination/nontermloop1/test.desc create mode 100644 regression/nontermination/nontermloop2/main.c create mode 100644 regression/nontermination/nontermloop2/test.desc create mode 100644 regression/nontermination/nontermloop3/main.c create mode 100644 regression/nontermination/nontermloop3/test.desc create mode 100644 regression/nontermination/nontermloop4/main.c create mode 100644 regression/nontermination/nontermloop4/test.desc create mode 100644 regression/nontermination/phase3/main.c create mode 100644 regression/nontermination/phase3/test.desc create mode 100644 regression/nontermination/phase4/main.c create mode 100644 regression/nontermination/phase4/test.desc diff --git a/regression/nontermination/abort4/main.c b/regression/nontermination/abort4/main.c new file mode 100644 index 000000000..6872899e8 --- /dev/null +++ b/regression/nontermination/abort4/main.c @@ -0,0 +1,15 @@ +void foo() +{ + while(1); +} + +void bar() +{ +} + +int main(int argc, char** argv) +{ + foo(); + bar(); + return 0; +} diff --git a/regression/nontermination/abort4/test.desc b/regression/nontermination/abort4/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/abort4/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/abort5/main.c b/regression/nontermination/abort5/main.c new file mode 100644 index 000000000..25f0cf975 --- /dev/null +++ b/regression/nontermination/abort5/main.c @@ -0,0 +1,15 @@ +void foo() +{ + while(1); +} + +void bar() +{ +} + +int main(int argc, char** argv) +{ + if(argc>=0) foo(); + bar(); + return 0; //status should be NO +} diff --git a/regression/nontermination/abort5/test.desc b/regression/nontermination/abort5/test.desc new file mode 100644 index 000000000..2d9665fb2 --- /dev/null +++ b/regression/nontermination/abort5/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--context-sensitive +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/abort6/main.c b/regression/nontermination/abort6/main.c new file mode 100644 index 000000000..fba8054e7 --- /dev/null +++ b/regression/nontermination/abort6/main.c @@ -0,0 +1,15 @@ +void foo() +{ + while(1); +} + +void bar() +{ +} + +int main(int argc, char** argv) +{ + if(argc>=5) foo(); + bar(); + return 0; //status should be UNKNOWN +} diff --git a/regression/nontermination/abort6/test.desc b/regression/nontermination/abort6/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/abort6/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/float3/main.c b/regression/nontermination/float3/main.c new file mode 100644 index 000000000..9915bcd95 --- /dev/null +++ b/regression/nontermination/float3/main.c @@ -0,0 +1,10 @@ +void main() +{ + float x = 10.0; + + while(x>0) // does not terminate + { + x = x*0.1 + 0.1; + } + assert(x>=0.0); +} diff --git a/regression/nontermination/float3/test.desc b/regression/nontermination/float3/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/float3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/nontermloop1/main.c b/regression/nontermination/nontermloop1/main.c new file mode 100644 index 000000000..c117788fe --- /dev/null +++ b/regression/nontermination/nontermloop1/main.c @@ -0,0 +1,9 @@ +void main() +{ + int x; + + while(1) + { + ++x; + } +} diff --git a/regression/nontermination/nontermloop1/test.desc b/regression/nontermination/nontermloop1/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/nontermloop1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/nontermloop2/main.c b/regression/nontermination/nontermloop2/main.c new file mode 100644 index 000000000..55c33c4b9 --- /dev/null +++ b/regression/nontermination/nontermloop2/main.c @@ -0,0 +1,10 @@ +void main() +{ + int x = 1; + + while(x!=0) + { + if(x==1) x++; + else x--; + } +} diff --git a/regression/nontermination/nontermloop2/test.desc b/regression/nontermination/nontermloop2/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/nontermloop2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/nontermloop3/main.c b/regression/nontermination/nontermloop3/main.c new file mode 100644 index 000000000..955c8ba66 --- /dev/null +++ b/regression/nontermination/nontermloop3/main.c @@ -0,0 +1,11 @@ +void main() +{ + char x; + // __CPROVER_assume(-3<=x && x<=3); + + while(1) + { + // x = (x-1)%4; + x--; + } +} diff --git a/regression/nontermination/nontermloop3/test.desc b/regression/nontermination/nontermloop3/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/nontermloop3/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/nontermloop4/main.c b/regression/nontermination/nontermloop4/main.c new file mode 100644 index 000000000..537dde2a5 --- /dev/null +++ b/regression/nontermination/nontermloop4/main.c @@ -0,0 +1,6 @@ +void main() +{ + while(1) + { + } +} diff --git a/regression/nontermination/nontermloop4/test.desc b/regression/nontermination/nontermloop4/test.desc new file mode 100644 index 000000000..b69d21c78 --- /dev/null +++ b/regression/nontermination/nontermloop4/test.desc @@ -0,0 +1,6 @@ +CORE +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/nontermination/phase3/main.c b/regression/nontermination/phase3/main.c new file mode 100644 index 000000000..67c31f21f --- /dev/null +++ b/regression/nontermination/phase3/main.c @@ -0,0 +1,12 @@ +void main() +{ + unsigned char x = 1; + unsigned char y = 1; + + while(x>0) //does not terminate + { + if(x<100) x++; + y++; + } + assert(x==0); +} diff --git a/regression/nontermination/phase3/test.desc b/regression/nontermination/phase3/test.desc new file mode 100644 index 000000000..0c5568437 --- /dev/null +++ b/regression/nontermination/phase3/test.desc @@ -0,0 +1,9 @@ +KNOWNBUG +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- +-- +this can be proved by the termination checker with octagon invariants \ No newline at end of file diff --git a/regression/nontermination/phase4/main.c b/regression/nontermination/phase4/main.c new file mode 100644 index 000000000..f80f66a97 --- /dev/null +++ b/regression/nontermination/phase4/main.c @@ -0,0 +1,11 @@ +void main() +{ + unsigned char x = 1; + unsigned char y = 1; + + while(x>0) //does not terminate + { + y++; + } + assert(x==0); +} diff --git a/regression/nontermination/phase4/test.desc b/regression/nontermination/phase4/test.desc new file mode 100644 index 000000000..982a29212 --- /dev/null +++ b/regression/nontermination/phase4/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--octagons +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ diff --git a/regression/termination/abort4/test.desc b/regression/termination/abort4/test.desc index b69d21c78..a27ac3470 100644 --- a/regression/termination/abort4/test.desc +++ b/regression/termination/abort4/test.desc @@ -1,6 +1,9 @@ CORE main.c -^EXIT=10$ +^EXIT=5$ ^SIGNAL=0$ -^VERIFICATION FAILED$ +^VERIFICATION INCONCLUSIVE$ +-- +-- +can be refuted with nontermination checker diff --git a/regression/termination/abort5/test.desc b/regression/termination/abort5/test.desc index 2d9665fb2..ad6260222 100644 --- a/regression/termination/abort5/test.desc +++ b/regression/termination/abort5/test.desc @@ -1,6 +1,9 @@ CORE main.c --context-sensitive -^EXIT=10$ +^EXIT=5$ ^SIGNAL=0$ -^VERIFICATION FAILED$ +^VERIFICATION INCONCLUSIVE$ +-- +-- +can be refuted with nontermination checker diff --git a/regression/termination/abort6/test.desc b/regression/termination/abort6/test.desc index b69d21c78..a27ac3470 100644 --- a/regression/termination/abort6/test.desc +++ b/regression/termination/abort6/test.desc @@ -1,6 +1,9 @@ CORE main.c -^EXIT=10$ +^EXIT=5$ ^SIGNAL=0$ -^VERIFICATION FAILED$ +^VERIFICATION INCONCLUSIVE$ +-- +-- +can be refuted with nontermination checker diff --git a/regression/termination/float3/test.desc b/regression/termination/float3/test.desc index b69d21c78..a27ac3470 100644 --- a/regression/termination/float3/test.desc +++ b/regression/termination/float3/test.desc @@ -1,6 +1,9 @@ CORE main.c -^EXIT=10$ +^EXIT=5$ ^SIGNAL=0$ -^VERIFICATION FAILED$ +^VERIFICATION INCONCLUSIVE$ +-- +-- +can be refuted with nontermination checker diff --git a/regression/termination/nontermloop1/test.desc b/regression/termination/nontermloop1/test.desc index b69d21c78..a27ac3470 100644 --- a/regression/termination/nontermloop1/test.desc +++ b/regression/termination/nontermloop1/test.desc @@ -1,6 +1,9 @@ CORE main.c -^EXIT=10$ +^EXIT=5$ ^SIGNAL=0$ -^VERIFICATION FAILED$ +^VERIFICATION INCONCLUSIVE$ +-- +-- +can be refuted with nontermination checker diff --git a/regression/termination/nontermloop2/test.desc b/regression/termination/nontermloop2/test.desc index 8314a397f..a27ac3470 100644 --- a/regression/termination/nontermloop2/test.desc +++ b/regression/termination/nontermloop2/test.desc @@ -4,3 +4,6 @@ main.c ^EXIT=5$ ^SIGNAL=0$ ^VERIFICATION INCONCLUSIVE$ +-- +-- +can be refuted with nontermination checker diff --git a/regression/termination/nontermloop3/test.desc b/regression/termination/nontermloop3/test.desc index b69d21c78..a27ac3470 100644 --- a/regression/termination/nontermloop3/test.desc +++ b/regression/termination/nontermloop3/test.desc @@ -1,6 +1,9 @@ CORE main.c -^EXIT=10$ +^EXIT=5$ ^SIGNAL=0$ -^VERIFICATION FAILED$ +^VERIFICATION INCONCLUSIVE$ +-- +-- +can be refuted with nontermination checker diff --git a/regression/termination/nontermloop4/test.desc b/regression/termination/nontermloop4/test.desc index b69d21c78..a27ac3470 100644 --- a/regression/termination/nontermloop4/test.desc +++ b/regression/termination/nontermloop4/test.desc @@ -1,6 +1,9 @@ CORE main.c -^EXIT=10$ +^EXIT=5$ ^SIGNAL=0$ -^VERIFICATION FAILED$ +^VERIFICATION INCONCLUSIVE$ +-- +-- +can be refuted with nontermination checker diff --git a/regression/termination/phase3/test.desc b/regression/termination/phase3/test.desc index 982a29212..e8087cc8b 100644 --- a/regression/termination/phase3/test.desc +++ b/regression/termination/phase3/test.desc @@ -1,6 +1,9 @@ CORE main.c --octagons -^EXIT=10$ +^EXIT=5$ ^SIGNAL=0$ -^VERIFICATION FAILED$ +^VERIFICATION INCONCLUSIVE$ +-- +-- +can be refuted with nontermination checker diff --git a/regression/termination/phase4/test.desc b/regression/termination/phase4/test.desc index 982a29212..e8087cc8b 100644 --- a/regression/termination/phase4/test.desc +++ b/regression/termination/phase4/test.desc @@ -1,6 +1,9 @@ CORE main.c --octagons -^EXIT=10$ +^EXIT=5$ ^SIGNAL=0$ -^VERIFICATION FAILED$ +^VERIFICATION INCONCLUSIVE$ +-- +-- +can be refuted with nontermination checker From dd9bbf971ac832ca50c1396736cbc35c9ab8b058 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sun, 12 Nov 2017 14:36:00 +0000 Subject: [PATCH 109/322] Fix invariant extraction for heap-interval --- src/2ls/dynamic_cfg.cpp | 26 ++++++++------------------ src/2ls/dynamic_cfg.h | 2 +- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/2ls/dynamic_cfg.cpp b/src/2ls/dynamic_cfg.cpp index d6507a3d9..9146c717b 100644 --- a/src/2ls/dynamic_cfg.cpp +++ b/src/2ls/dynamic_cfg.cpp @@ -33,7 +33,7 @@ void dynamic_cfgt::operator()( build_cfg(goto_program, ssa_unwinder); assumptionst assumptions; - build_from_invariants(ssa, summary, assumptions); + build_from_invariants(ssa, summary.fw_invariant, assumptions); add_assumptions(assumptions); } @@ -273,30 +273,20 @@ Function: dynamic_cfgt::build_from_invariants void dynamic_cfgt::build_from_invariants( const unwindable_local_SSAt &ssa, - const summaryt &summary, + const exprt &invariants, assumptionst &assumptions) { - if(summary.fw_invariant.is_nil() || - summary.fw_invariant.is_true()) + if(invariants.is_nil() || invariants.is_true()) return; // expected format /\_i g_i=> inv_i - if(summary.fw_invariant.id()==ID_implies) + if(invariants.id()==ID_implies) { - build_from_invariant( - ssa, summary.fw_invariant, - assumptions); + build_from_invariant(ssa, invariants, assumptions); } - else if(summary.fw_invariant.id()==ID_and) + else if(invariants.id()==ID_and) { - for(unsigned i=0; i void build_from_invariants( const unwindable_local_SSAt &ssa, - const summaryt &summary, + const exprt &invariants, assumptionst &assumptions); void build_from_invariant( const unwindable_local_SSAt &ssa, From 4bdda5fef1af561d3f8f3b144ed04848adf8fce1 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sun, 12 Nov 2017 22:28:34 +0000 Subject: [PATCH 110/322] Do not report properties when checking nontermination --- src/2ls/2ls_parse_options.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 828123bfa..5fe4da3aa 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -591,7 +591,8 @@ int twols_parse_optionst::doit() bool report_assertions= !options.get_bool_option("preconditions") && - !options.get_bool_option("termination"); + !options.get_bool_option("termination") && + !options.get_bool_option("nontermination"); // do actual analysis switch((*checker)(goto_model)) { From 52c29bf9ba984dd7abcfd5643265658e6287c770 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Tue, 14 Nov 2017 00:30:55 +0000 Subject: [PATCH 111/322] Output correctness witness for termination --- src/2ls/2ls_parse_options.cpp | 4 +--- src/2ls/dynamic_cfg.cpp | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 5fe4da3aa..8b86e7edc 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -600,9 +600,7 @@ int twols_parse_optionst::doit() if(report_assertions) report_properties(options, goto_model, checker->property_map); report_success(); - if(cmdline.isset("graphml-witness") && - !options.get_bool_option("termination") && - !options.get_bool_option("nontermination")) + if(cmdline.isset("graphml-witness")) output_graphml_proof(options, goto_model, *checker); retval=0; break; diff --git a/src/2ls/dynamic_cfg.cpp b/src/2ls/dynamic_cfg.cpp index 9146c717b..f7cd221b4 100644 --- a/src/2ls/dynamic_cfg.cpp +++ b/src/2ls/dynamic_cfg.cpp @@ -193,6 +193,23 @@ void dynamic_cfgt::build_cfg( nodes[node].id.iteration_stack=iteration_stack; nodes[node].is_loop_head=true; } + else + { + // alternative loop head detection when unwinder was not used + for(const auto &incoming : it->incoming_edges) + { + if(incoming->is_backwards_goto() && + incoming!=it) + { + iteration_stack.push_back(0); + loop_node_stack.push_back(node); + max_iteration_stack.push_back(0); + nodes[node].id.iteration_stack=iteration_stack; + nodes[node].is_loop_head=true; + break; + } + } + } const std::set &iedges=incoming_edges[it]; for(const auto &from : iedges) From c222be9f3a65b1f8da15df28e5e82e2179b4f988 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sat, 18 Nov 2017 11:57:41 +0000 Subject: [PATCH 112/322] Update test.pl --- regression/heap/Makefile | 4 +- regression/interprocedural/Makefile | 4 +- regression/interprocedural/equal1/test.desc | 2 +- regression/interprocedural/equal2/test.desc | 2 +- regression/interprocedural/equal3/test.desc | 2 +- regression/interprocedural/equal4/test.desc | 2 +- regression/interprocedural/equal7/test.desc | 2 +- regression/interprocedural/global1/test.desc | 2 +- regression/interprocedural/global2/test.desc | 2 +- regression/interprocedural/global3/test.desc | 2 +- regression/interprocedural/ite2/test.desc | 2 +- regression/interprocedural/ite3/test.desc | 2 +- regression/interprocedural/ite4/test.desc | 2 +- .../interprocedural/partialinline1/test.desc | 2 +- regression/interprocedural/pointer1/test.desc | 2 +- regression/interprocedural/pointer2/test.desc | 2 +- regression/interprocedural/simple1/test.desc | 2 +- regression/interprocedural/simple2/test.desc | 2 +- regression/interprocedural/sum1/test.desc | 2 +- regression/invariants/Makefile | 4 +- regression/invariants/equal5/test.desc | 2 +- regression/invariants/equal8/test.desc | 2 +- regression/invariants/loop16/test.desc | 2 +- regression/invariants/loop2/test.desc | 2 +- regression/invariants/loop3/test.desc | 2 +- regression/invariants/loop4/test.desc | 2 +- regression/invariants/loop5/test.desc | 2 +- regression/invariants/loop6/test.desc | 2 +- regression/invariants/loop7/test.desc | 2 +- regression/invariants/loop8/test.desc | 2 +- regression/invariants/unwind1/test.desc | 2 +- regression/invariants/unwind12/test.desc | 2 +- regression/invariants/unwind13/test.desc | 2 +- regression/invariants/unwind2/test.desc | 2 +- regression/invariants/unwind20/test.desc | 2 +- regression/invariants/unwind3/test.desc | 2 +- regression/invariants/unwind4/test.desc | 2 +- regression/invariants/unwind5/test.desc | 2 +- regression/kiki/Makefile | 4 +- regression/nontermination/Makefile | 4 +- regression/preconditions/Makefile | 4 +- regression/preconditions/precond1/test.desc | 2 +- regression/preconditions/precond2/test.desc | 2 +- regression/preconditions/precond3/test.desc | 2 +- regression/preconditions/precond6/test.desc | 2 +- .../precond_contextsensitive1/test.desc | 2 +- .../precond_contextsensitive2/test.desc | 2 +- regression/termination/Makefile | 4 +- .../termination/precond_term1/test.desc | 2 +- regression/termination/running2/test.desc | 2 +- regression/termination/running4/test.desc | 2 +- regression/test.pl | 265 +++++++++++++++--- 52 files changed, 277 insertions(+), 104 deletions(-) diff --git a/regression/heap/Makefile b/regression/heap/Makefile index b5f2484a2..34cd734b9 100644 --- a/regression/heap/Makefile +++ b/regression/heap/Makefile @@ -3,10 +3,10 @@ default: tests.log FLAGS = --verbosity 10 test: - @../test.pl -c "../../../src/2ls/2ls $(FLAGS)" + @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" tests.log: ../test.pl - @../test.pl -c "../../../src/2ls/2ls $(FLAGS)" + @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" show: @for dir in *; do \ diff --git a/regression/interprocedural/Makefile b/regression/interprocedural/Makefile index b5f2484a2..34cd734b9 100644 --- a/regression/interprocedural/Makefile +++ b/regression/interprocedural/Makefile @@ -3,10 +3,10 @@ default: tests.log FLAGS = --verbosity 10 test: - @../test.pl -c "../../../src/2ls/2ls $(FLAGS)" + @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" tests.log: ../test.pl - @../test.pl -c "../../../src/2ls/2ls $(FLAGS)" + @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" show: @for dir in *; do \ diff --git a/regression/interprocedural/equal1/test.desc b/regression/interprocedural/equal1/test.desc index 278810d48..2912759b4 100644 --- a/regression/interprocedural/equal1/test.desc +++ b/regression/interprocedural/equal1/test.desc @@ -3,4 +3,4 @@ main.c --equalities ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 1 failed$ +^\*\* 0 of 1 failed$ diff --git a/regression/interprocedural/equal2/test.desc b/regression/interprocedural/equal2/test.desc index 278810d48..2912759b4 100644 --- a/regression/interprocedural/equal2/test.desc +++ b/regression/interprocedural/equal2/test.desc @@ -3,4 +3,4 @@ main.c --equalities ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 1 failed$ +^\*\* 0 of 1 failed$ diff --git a/regression/interprocedural/equal3/test.desc b/regression/interprocedural/equal3/test.desc index 278810d48..2912759b4 100644 --- a/regression/interprocedural/equal3/test.desc +++ b/regression/interprocedural/equal3/test.desc @@ -3,4 +3,4 @@ main.c --equalities ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 1 failed$ +^\*\* 0 of 1 failed$ diff --git a/regression/interprocedural/equal4/test.desc b/regression/interprocedural/equal4/test.desc index 278810d48..2912759b4 100644 --- a/regression/interprocedural/equal4/test.desc +++ b/regression/interprocedural/equal4/test.desc @@ -3,4 +3,4 @@ main.c --equalities ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 1 failed$ +^\*\* 0 of 1 failed$ diff --git a/regression/interprocedural/equal7/test.desc b/regression/interprocedural/equal7/test.desc index b7d19f8c7..f94239d37 100644 --- a/regression/interprocedural/equal7/test.desc +++ b/regression/interprocedural/equal7/test.desc @@ -3,4 +3,4 @@ main.c ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 1 failed$ +^\*\* 0 of 1 failed$ diff --git a/regression/interprocedural/global1/test.desc b/regression/interprocedural/global1/test.desc index a6987a69a..33f531990 100644 --- a/regression/interprocedural/global1/test.desc +++ b/regression/interprocedural/global1/test.desc @@ -3,4 +3,4 @@ main.c --zones ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 2 failed$ +^\*\* 0 of 2 failed$ diff --git a/regression/interprocedural/global2/test.desc b/regression/interprocedural/global2/test.desc index 1ec61b8c3..90e74250c 100644 --- a/regression/interprocedural/global2/test.desc +++ b/regression/interprocedural/global2/test.desc @@ -3,4 +3,4 @@ main.c ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 2 failed$ +^\*\* 0 of 2 failed$ diff --git a/regression/interprocedural/global3/test.desc b/regression/interprocedural/global3/test.desc index 1ec61b8c3..90e74250c 100644 --- a/regression/interprocedural/global3/test.desc +++ b/regression/interprocedural/global3/test.desc @@ -3,4 +3,4 @@ main.c ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 2 failed$ +^\*\* 0 of 2 failed$ diff --git a/regression/interprocedural/ite2/test.desc b/regression/interprocedural/ite2/test.desc index a6987a69a..33f531990 100644 --- a/regression/interprocedural/ite2/test.desc +++ b/regression/interprocedural/ite2/test.desc @@ -3,4 +3,4 @@ main.c --zones ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 2 failed$ +^\*\* 0 of 2 failed$ diff --git a/regression/interprocedural/ite3/test.desc b/regression/interprocedural/ite3/test.desc index 1ec61b8c3..90e74250c 100644 --- a/regression/interprocedural/ite3/test.desc +++ b/regression/interprocedural/ite3/test.desc @@ -3,4 +3,4 @@ main.c ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 2 failed$ +^\*\* 0 of 2 failed$ diff --git a/regression/interprocedural/ite4/test.desc b/regression/interprocedural/ite4/test.desc index a6987a69a..33f531990 100644 --- a/regression/interprocedural/ite4/test.desc +++ b/regression/interprocedural/ite4/test.desc @@ -3,4 +3,4 @@ main.c --zones ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 2 failed$ +^\*\* 0 of 2 failed$ diff --git a/regression/interprocedural/partialinline1/test.desc b/regression/interprocedural/partialinline1/test.desc index 0eb76f70f..9b5e46ea4 100644 --- a/regression/interprocedural/partialinline1/test.desc +++ b/regression/interprocedural/partialinline1/test.desc @@ -3,5 +3,5 @@ main.c --inline-partial 7 ^EXIT=10$ ^SIGNAL=0$ -^** 1 of 2 failed$ +^\*\* 1 of 2 failed$ diff --git a/regression/interprocedural/pointer1/test.desc b/regression/interprocedural/pointer1/test.desc index 754436e9d..505faef4e 100644 --- a/regression/interprocedural/pointer1/test.desc +++ b/regression/interprocedural/pointer1/test.desc @@ -3,4 +3,4 @@ main.c ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 1 failed$ +^\*\* 0 of 1 failed$ diff --git a/regression/interprocedural/pointer2/test.desc b/regression/interprocedural/pointer2/test.desc index 754436e9d..505faef4e 100644 --- a/regression/interprocedural/pointer2/test.desc +++ b/regression/interprocedural/pointer2/test.desc @@ -3,4 +3,4 @@ main.c ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 1 failed$ +^\*\* 0 of 1 failed$ diff --git a/regression/interprocedural/simple1/test.desc b/regression/interprocedural/simple1/test.desc index b7d19f8c7..f94239d37 100644 --- a/regression/interprocedural/simple1/test.desc +++ b/regression/interprocedural/simple1/test.desc @@ -3,4 +3,4 @@ main.c ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 1 failed$ +^\*\* 0 of 1 failed$ diff --git a/regression/interprocedural/simple2/test.desc b/regression/interprocedural/simple2/test.desc index b7d19f8c7..f94239d37 100644 --- a/regression/interprocedural/simple2/test.desc +++ b/regression/interprocedural/simple2/test.desc @@ -3,4 +3,4 @@ main.c ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 1 failed$ +^\*\* 0 of 1 failed$ diff --git a/regression/interprocedural/sum1/test.desc b/regression/interprocedural/sum1/test.desc index 618e68d44..413320cde 100644 --- a/regression/interprocedural/sum1/test.desc +++ b/regression/interprocedural/sum1/test.desc @@ -3,4 +3,4 @@ main.c --octagons ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 4 failed$ +^\*\* 0 of 4 failed$ diff --git a/regression/invariants/Makefile b/regression/invariants/Makefile index b5f2484a2..34cd734b9 100644 --- a/regression/invariants/Makefile +++ b/regression/invariants/Makefile @@ -3,10 +3,10 @@ default: tests.log FLAGS = --verbosity 10 test: - @../test.pl -c "../../../src/2ls/2ls $(FLAGS)" + @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" tests.log: ../test.pl - @../test.pl -c "../../../src/2ls/2ls $(FLAGS)" + @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" show: @for dir in *; do \ diff --git a/regression/invariants/equal5/test.desc b/regression/invariants/equal5/test.desc index 815e990cc..0f9dc0560 100644 --- a/regression/invariants/equal5/test.desc +++ b/regression/invariants/equal5/test.desc @@ -3,4 +3,4 @@ main.c --equalities ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 2 failed$ +^\*\* 0 of 2 failed$ diff --git a/regression/invariants/equal8/test.desc b/regression/invariants/equal8/test.desc index 278810d48..2912759b4 100644 --- a/regression/invariants/equal8/test.desc +++ b/regression/invariants/equal8/test.desc @@ -3,4 +3,4 @@ main.c --equalities ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 1 failed$ +^\*\* 0 of 1 failed$ diff --git a/regression/invariants/loop16/test.desc b/regression/invariants/loop16/test.desc index 1ec61b8c3..90e74250c 100644 --- a/regression/invariants/loop16/test.desc +++ b/regression/invariants/loop16/test.desc @@ -3,4 +3,4 @@ main.c ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 2 failed$ +^\*\* 0 of 2 failed$ diff --git a/regression/invariants/loop2/test.desc b/regression/invariants/loop2/test.desc index 1ec61b8c3..90e74250c 100644 --- a/regression/invariants/loop2/test.desc +++ b/regression/invariants/loop2/test.desc @@ -3,4 +3,4 @@ main.c ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 2 failed$ +^\*\* 0 of 2 failed$ diff --git a/regression/invariants/loop3/test.desc b/regression/invariants/loop3/test.desc index 1ec61b8c3..90e74250c 100644 --- a/regression/invariants/loop3/test.desc +++ b/regression/invariants/loop3/test.desc @@ -3,4 +3,4 @@ main.c ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 2 failed$ +^\*\* 0 of 2 failed$ diff --git a/regression/invariants/loop4/test.desc b/regression/invariants/loop4/test.desc index 1ec61b8c3..90e74250c 100644 --- a/regression/invariants/loop4/test.desc +++ b/regression/invariants/loop4/test.desc @@ -3,4 +3,4 @@ main.c ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 2 failed$ +^\*\* 0 of 2 failed$ diff --git a/regression/invariants/loop5/test.desc b/regression/invariants/loop5/test.desc index b7d19f8c7..f94239d37 100644 --- a/regression/invariants/loop5/test.desc +++ b/regression/invariants/loop5/test.desc @@ -3,4 +3,4 @@ main.c ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 1 failed$ +^\*\* 0 of 1 failed$ diff --git a/regression/invariants/loop6/test.desc b/regression/invariants/loop6/test.desc index d6f6483b8..1d9f49346 100644 --- a/regression/invariants/loop6/test.desc +++ b/regression/invariants/loop6/test.desc @@ -3,4 +3,4 @@ main.c --octagons ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 1 failed$ +^\*\* 0 of 1 failed$ diff --git a/regression/invariants/loop7/test.desc b/regression/invariants/loop7/test.desc index c268c1153..8fcbb550d 100644 --- a/regression/invariants/loop7/test.desc +++ b/regression/invariants/loop7/test.desc @@ -3,4 +3,4 @@ main.c ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 4 failed$ +^\*\* 0 of 4 failed$ diff --git a/regression/invariants/loop8/test.desc b/regression/invariants/loop8/test.desc index 1ec61b8c3..90e74250c 100644 --- a/regression/invariants/loop8/test.desc +++ b/regression/invariants/loop8/test.desc @@ -3,4 +3,4 @@ main.c ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 2 failed$ +^\*\* 0 of 2 failed$ diff --git a/regression/invariants/unwind1/test.desc b/regression/invariants/unwind1/test.desc index eb75b46d7..4219263bb 100644 --- a/regression/invariants/unwind1/test.desc +++ b/regression/invariants/unwind1/test.desc @@ -3,4 +3,4 @@ main.c --unwind 5 ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 1 failed$ +^\*\* 0 of 1 failed$ diff --git a/regression/invariants/unwind12/test.desc b/regression/invariants/unwind12/test.desc index 6bcc42b93..b6ea5068e 100644 --- a/regression/invariants/unwind12/test.desc +++ b/regression/invariants/unwind12/test.desc @@ -3,4 +3,4 @@ main.c --unwind 7 ^EXIT=10$ ^SIGNAL=0$ -^** 1 of 2 failed$ +^\*\* 1 of 2 failed$ diff --git a/regression/invariants/unwind13/test.desc b/regression/invariants/unwind13/test.desc index 6bcc42b93..b6ea5068e 100644 --- a/regression/invariants/unwind13/test.desc +++ b/regression/invariants/unwind13/test.desc @@ -3,4 +3,4 @@ main.c --unwind 7 ^EXIT=10$ ^SIGNAL=0$ -^** 1 of 2 failed$ +^\*\* 1 of 2 failed$ diff --git a/regression/invariants/unwind2/test.desc b/regression/invariants/unwind2/test.desc index eb75b46d7..4219263bb 100644 --- a/regression/invariants/unwind2/test.desc +++ b/regression/invariants/unwind2/test.desc @@ -3,4 +3,4 @@ main.c --unwind 5 ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 1 failed$ +^\*\* 0 of 1 failed$ diff --git a/regression/invariants/unwind20/test.desc b/regression/invariants/unwind20/test.desc index 744e6bbe7..f3b7f654b 100644 --- a/regression/invariants/unwind20/test.desc +++ b/regression/invariants/unwind20/test.desc @@ -3,4 +3,4 @@ main.c --unwind 10 ^EXIT=10$ ^SIGNAL=0$ -^** 2 of 2 failed$ +^\*\* 2 of 2 failed$ diff --git a/regression/invariants/unwind3/test.desc b/regression/invariants/unwind3/test.desc index eb75b46d7..4219263bb 100644 --- a/regression/invariants/unwind3/test.desc +++ b/regression/invariants/unwind3/test.desc @@ -3,4 +3,4 @@ main.c --unwind 5 ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 1 failed$ +^\*\* 0 of 1 failed$ diff --git a/regression/invariants/unwind4/test.desc b/regression/invariants/unwind4/test.desc index a73bcb48a..57d1fa962 100644 --- a/regression/invariants/unwind4/test.desc +++ b/regression/invariants/unwind4/test.desc @@ -3,4 +3,4 @@ main.c --unwind 20 ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 1 failed$ +^\*\* 0 of 1 failed$ diff --git a/regression/invariants/unwind5/test.desc b/regression/invariants/unwind5/test.desc index 0abefceba..d9beae8e6 100644 --- a/regression/invariants/unwind5/test.desc +++ b/regression/invariants/unwind5/test.desc @@ -3,4 +3,4 @@ main.c --unwind 10 ^EXIT=0$ ^SIGNAL=0$ -^** 0 of 1 failed$ +^\*\* 0 of 1 failed$ diff --git a/regression/kiki/Makefile b/regression/kiki/Makefile index b5f2484a2..34cd734b9 100644 --- a/regression/kiki/Makefile +++ b/regression/kiki/Makefile @@ -3,10 +3,10 @@ default: tests.log FLAGS = --verbosity 10 test: - @../test.pl -c "../../../src/2ls/2ls $(FLAGS)" + @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" tests.log: ../test.pl - @../test.pl -c "../../../src/2ls/2ls $(FLAGS)" + @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" show: @for dir in *; do \ diff --git a/regression/nontermination/Makefile b/regression/nontermination/Makefile index cbda9642d..5911eab86 100644 --- a/regression/nontermination/Makefile +++ b/regression/nontermination/Makefile @@ -3,10 +3,10 @@ default: tests.log FLAGS = --verbosity 10 --nontermination test: - @../test.pl -c "../../../src/2ls/2ls $(FLAGS)" + @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" tests.log: ../test.pl - @../test.pl -c "../../../src/2ls/2ls $(FLAGS)" + @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" show: @for dir in *; do \ diff --git a/regression/preconditions/Makefile b/regression/preconditions/Makefile index b5f2484a2..34cd734b9 100644 --- a/regression/preconditions/Makefile +++ b/regression/preconditions/Makefile @@ -3,10 +3,10 @@ default: tests.log FLAGS = --verbosity 10 test: - @../test.pl -c "../../../src/2ls/2ls $(FLAGS)" + @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" tests.log: ../test.pl - @../test.pl -c "../../../src/2ls/2ls $(FLAGS)" + @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" show: @for dir in *; do \ diff --git a/regression/preconditions/precond1/test.desc b/regression/preconditions/precond1/test.desc index bb6885e71..c14aa11eb 100644 --- a/regression/preconditions/precond1/test.desc +++ b/regression/preconditions/precond1/test.desc @@ -3,4 +3,4 @@ main.c --preconditions ^EXIT=5$ ^SIGNAL=0$ -^\[foo\]: x <= 2147483647 && -((signed __CPROVER_bitvector\[33\])x) <= 0$ +^\[foo\]: x <= 2147483647 && -\(\(signed __CPROVER_bitvector\[33\]\)x\) <= 0$ diff --git a/regression/preconditions/precond2/test.desc b/regression/preconditions/precond2/test.desc index dd3d5c389..372261595 100644 --- a/regression/preconditions/precond2/test.desc +++ b/regression/preconditions/precond2/test.desc @@ -3,4 +3,4 @@ main.c --preconditions --sufficient ^EXIT=5$ ^SIGNAL=0$ -^\[foo\]: !(x <= -1 && -((signed __CPROVER_bitvector\[33\])x) <= 2147483648)$ +^\[foo\]: !\(x <= -1 && -\(\(signed __CPROVER_bitvector\[33\]\)x\) <= 2147483648\)$ diff --git a/regression/preconditions/precond3/test.desc b/regression/preconditions/precond3/test.desc index 7428405d1..fc7cbc9ac 100644 --- a/regression/preconditions/precond3/test.desc +++ b/regression/preconditions/precond3/test.desc @@ -3,4 +3,4 @@ main.c --preconditions --sufficient --equalities ^EXIT=5$ ^SIGNAL=0$ -^\[foo\]: !(x == ((char \*)NULL))$ +^\[foo\]: !\(x == \(\(char \*\)NULL\)\)$ diff --git a/regression/preconditions/precond6/test.desc b/regression/preconditions/precond6/test.desc index bb6885e71..c14aa11eb 100644 --- a/regression/preconditions/precond6/test.desc +++ b/regression/preconditions/precond6/test.desc @@ -3,4 +3,4 @@ main.c --preconditions ^EXIT=5$ ^SIGNAL=0$ -^\[foo\]: x <= 2147483647 && -((signed __CPROVER_bitvector\[33\])x) <= 0$ +^\[foo\]: x <= 2147483647 && -\(\(signed __CPROVER_bitvector\[33\]\)x\) <= 0$ diff --git a/regression/preconditions/precond_contextsensitive1/test.desc b/regression/preconditions/precond_contextsensitive1/test.desc index 1da5cbf57..15e66e08d 100644 --- a/regression/preconditions/precond_contextsensitive1/test.desc +++ b/regression/preconditions/precond_contextsensitive1/test.desc @@ -3,4 +3,4 @@ main.c --context-sensitive --preconditions ^EXIT=5$ ^SIGNAL=0$ -^\[sign\]: sign#return_value#phi17 <= 0 && -((signed __CPROVER_bitvector\[33\])sign#return_value#phi17) <= 0 ==> x <= 0 && -((signed __CPROVER_bitvector\[33\])x) <= 0$ +^\[sign\]: sign#return_value#phi17 <= 0 && -\(\(signed __CPROVER_bitvector\[33\]\)sign#return_value#phi17\) <= 0 ==> x <= 0 && -\(\(signed __CPROVER_bitvector\[33\]\)x\) <= 0$ diff --git a/regression/preconditions/precond_contextsensitive2/test.desc b/regression/preconditions/precond_contextsensitive2/test.desc index f757b9ab1..ac8b82f52 100644 --- a/regression/preconditions/precond_contextsensitive2/test.desc +++ b/regression/preconditions/precond_contextsensitive2/test.desc @@ -3,4 +3,4 @@ main.c --context-sensitive --preconditions ^EXIT=5$ ^SIGNAL=0$ -^\[_start\]: argc' <= 268435456 && -((signed __CPROVER_bitvector\[33\])argc') <= -2$ +^\[_start\]: argc' <= 268435456 && -\(\(signed __CPROVER_bitvector\[33\]\)argc'\) <= -2$ diff --git a/regression/termination/Makefile b/regression/termination/Makefile index f92c8b2be..59cfebf8f 100644 --- a/regression/termination/Makefile +++ b/regression/termination/Makefile @@ -3,10 +3,10 @@ default: tests.log FLAGS = --verbosity 10 --termination test: - @../test.pl -c "../../../src/2ls/2ls $(FLAGS)" + @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" tests.log: ../test.pl - @../test.pl -c "../../../src/2ls/2ls $(FLAGS)" + @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" show: @for dir in *; do \ diff --git a/regression/termination/precond_term1/test.desc b/regression/termination/precond_term1/test.desc index bd5d69778..25aca4d27 100644 --- a/regression/termination/precond_term1/test.desc +++ b/regression/termination/precond_term1/test.desc @@ -3,4 +3,4 @@ main.c --preconditions ^EXIT=5$ ^SIGNAL=0$ -\[_start\]: !(argc' <= 1 && -((signed __CPROVER_bitvector\[33\])argc') <= -1) +\[_start\]: !\(argc' <= 1 && -\(\(signed __CPROVER_bitvector\[33\]\)argc'\) <= -1\) diff --git a/regression/termination/running2/test.desc b/regression/termination/running2/test.desc index e1b15b6c5..3d12f7f73 100644 --- a/regression/termination/running2/test.desc +++ b/regression/termination/running2/test.desc @@ -3,4 +3,4 @@ main.c --context-sensitive --preconditions ^EXIT=5$ ^SIGNAL=0$ -\[g\]: !(n <= 999 && -((signed __CPROVER_bitvector\[33\])n) <= -1 && incx <= 0 && -((signed __CPROVER_bitvector\[33\])incx) <= 0) +\[g\]: !\(n <= 999 && -\(\(signed __CPROVER_bitvector\[33\]\)n\) <= -1 && incx <= 0 && -\(\(signed __CPROVER_bitvector\[33\]\)incx\) <= 0\) diff --git a/regression/termination/running4/test.desc b/regression/termination/running4/test.desc index 619557518..59010e364 100644 --- a/regression/termination/running4/test.desc +++ b/regression/termination/running4/test.desc @@ -3,4 +3,4 @@ main.c --context-sensitive --preconditions ^EXIT=5$ ^SIGNAL=0$ -\[bar\]: !(n <= 10000 && -((signed __CPROVER_bitvector\[33\])n) <= -100 && incx <= 0 && -((signed __CPROVER_bitvector\[33\])incx) <= 0) +\[bar\]: !\(n <= 10000 && -\(\(signed __CPROVER_bitvector\[33\]\)n\) <= -100 && incx <= 0 && -\(\(signed __CPROVER_bitvector\[33\]\)incx\) <= 0\) diff --git a/regression/test.pl b/regression/test.pl index 62779cb12..8cd558fea 100755 --- a/regression/test.pl +++ b/regression/test.pl @@ -3,17 +3,29 @@ use subs; use strict; use warnings; +use File::Basename; + +use Cwd; + +my $has_thread_pool = eval +{ + # "http://www.cpan.org/authors/id/J/JW/JWU/Thread-Pool-Simple/Thread-Pool-Simple-0.25.tar.gz" + # Debian/Ubuntu: libthread-pool-simple-perl + require Thread::Pool::Simple; + Thread::Pool::Simple->import(); + 1; +}; # test.pl # # runs a test and check its output -sub run($$$$) { - my ($input, $cmd, $options, $output) = @_; - my $cmdline = "$cmd $options $input >$output 2>&1"; +sub run($$$$$) { + my ($name, $input, $cmd, $options, $output) = @_; + my $cmdline = "$cmd $options '$input' >'$output' 2>&1"; print LOG "Running $cmdline\n"; - system $cmdline; + system("bash", "-c", "cd '$name' ; $cmdline"); my $exit_value = $? >> 8; my $signal_num = $? & 127; my $dumped_core = $? & 128; @@ -24,15 +36,21 @@ ($$$$) print LOG " Core: $dumped_core\n"; if($signal_num != 0) { - $failed = 1; print "Killed by signal $signal_num"; if($dumped_core) { print " (code dumped)"; } } - system "echo EXIT=$exit_value >>$output"; - system "echo SIGNAL=$signal_num >>$output"; + open my $FH, ">>$name/$output"; + print $FH "EXIT=$exit_value\n"; + print $FH "SIGNAL=$signal_num\n"; + close $FH; + + if($signal_num == 2) { + print "\nProgram under test interrupted; stopping\n"; + exit 1; + } return $failed; } @@ -48,13 +66,34 @@ ($) return @data; } -sub test($$$$$) { - my ($name, $test, $t_level, $cmd, $ign) = @_; - my ($level, $input, $options, @results) = load($test); +sub test($$$$$$$) { + my ($name, $test, $t_level, $cmd, $ign, $dry_run, $defines) = @_; + my ($level, $input, $options, $grep_options, @results) = load("$test"); + my @keys = keys %{$defines}; + foreach my $key (@keys) { + my $value = $defines->{$key}; + $options =~ s/(\$$key$|\$$key )/$value /g; + } + if (scalar @keys) { + foreach my $word (split(/\s/, $options)) { + if ((substr($word, 0, 1) cmp '$') == 0) { + print "$name: variable \"$word\" not replaced; consider passing \"-D$word\"=..."; + } + } + } + + # If the 4th line is activate-multi-line-match we enable multi-line checks + if($grep_options ne "activate-multi-line-match") { + # No such flag, so we add it back in + unshift @results, $grep_options; + $grep_options = ""; + } + $options =~ s/$ign//g if(defined($ign)); - my $output = $input; - $output =~ s/\.(c|o|gb|xml)$/.out/; + my $descriptor = basename($test); + my $output = $descriptor; + $output =~ s/\.[^.]*$/.out/; if($output eq $input) { print("Error in test file -- $test\n"); @@ -64,6 +103,7 @@ ($$$$$) print LOG "Test '$name'\n"; print LOG " Level: $level\n"; print LOG " Input: $input\n"; + print LOG " Descriptor: $descriptor\n"; print LOG " Output: $output\n"; print LOG " Options: $options\n"; print LOG " Results:\n"; @@ -83,9 +123,14 @@ ($$$$$) die "Level must be one of CORE, THOROUGH, FUTURE or KNOWNBUG\n"; } - my $failed = -1; + my $failed = 2; if($level & $t_level) { - $failed = run($input, $cmd, $options, $output); + + if ($dry_run) { + return 0; + } + + $failed = run($name, $input, $cmd, $options, $output); if(!$failed) { print LOG "Execution [OK]\n"; @@ -96,8 +141,45 @@ ($$$$$) $included--; } else { my $r; - system "grep \"$result\" '$output' >/dev/null"; - $r = ($included ? $? != 0 : $? == 0); + + my $dir = getcwd(); + my $abs_path = "$dir/$name/$output"; + open(my $fh => $abs_path) || die "Cannot open '$name/$output': $!"; + + # Multi line therefore we run each check across the whole output + if($grep_options eq "activate-multi-line-match") { + local $/ = undef; + binmode $fh; + my $whole_file = <$fh>; + $whole_file =~ s/\r\n/\n/g; + my $is_match = $whole_file =~ /$result/; + $r = ($included ? !$is_match : $is_match); + } + else + { + my $found_line = 0; + while(my $line = <$fh>) { + $line =~ s/\r$//; + if($line =~ /$result/) { + # We've found the line, therefore if it is included we set + # the result to 0 (OK) If it is excluded, we set the result + # to 1 (FAILED) + $r = !$included; + $found_line = 1; + last; + } + } + + if($found_line == 0) { + # None of the lines matched, therefore the result is set to + # 0 (OK) if and only if the line was not meant to be included + $r = $included; + } + + } + close($fh); + + if($r) { print LOG "$result [FAILED]\n"; $failed = 1; @@ -111,18 +193,22 @@ ($$$$$) } } else { print LOG "Execution [SKIPPED]\n"; + return 2; } print LOG "\n"; - return $failed; + # if the test is a KNOWNBUG then the test should fail + my $should_fail = $level eq 8; + + return ($should_fail != $failed); } sub dirs() { my @list; opendir CWD, "."; - @list = grep { !/^\./ && -d "$_" && !/CVS/ && -s "$_/test.desc" } readdir CWD; + @list = grep { !/^\./ && -d "$_" && !/CVS/ } readdir CWD; closedir CWD; @list = sort @list; @@ -148,11 +234,16 @@ ($$$$) -c CMD run tests on CMD - required option -i options in test.desc matching the specified perl regex are ignored + -j run tests in parallel (requires Thread::Pool::Simple) + -n dry-run: print the tests that would be run, but don't actually run them + -p print logs of each failed test (if any) -h show this help and exit -C core: run all essential tests (default if none of C/T/F/K are given) -T thorough: run expensive tests -F future: run checks for future features -K known: run tests associated with known bugs + -D Define - replace \$key string with "value" string in + test descriptors test.pl expects a test.desc file in each subdirectory. The file test.desc @@ -161,6 +252,7 @@ ($$$$)
+ -- @@ -168,61 +260,106 @@ ($$$$) where - is one of CORE, THOROUGH, FUTURE or KNOWNBUG -
is a file with extension .c/.i/.cpp/.ii/.xml/.class - additional options to be passed to CMD - one or more lines of regualar expressions that must occur in the output - one or more lines of expressions that must not occur in output - free form text + is one of CORE, THOROUGH, FUTURE or KNOWNBUG +
is a file with extension .c/.i/.gb/.cpp/.ii/.xml/.class/.jar + additional options to be passed to CMD + The fourth line can optionally be activate-multi-line-match, if this is the + case then each of the rules will be matched over multiple lines (so can contain) + the new line symbol (\\n) inside them. + one or more lines of regualar expressions that must occur in the output + one or more lines of expressions that must not occur in output + free form text EOF exit 1; } use Getopt::Std; +use Getopt::Long qw(:config pass_through bundling); $main::VERSION = 0.1; $Getopt::Std::STANDARD_HELP_VERSION = 1; -our ($opt_c, $opt_i, $opt_h, $opt_C, $opt_T, $opt_F, $opt_K); # the variables for getopt -getopts('c:i:hCTFK') or &main::HELP_MESSAGE(\*STDOUT, "", $main::VERSION, ""); +our ($opt_c, $opt_i, $opt_j, $opt_n, $opt_p, $opt_h, $opt_C, $opt_T, $opt_F, $opt_K, %defines); # the variables for getopt +$opt_j = 0; +GetOptions("D=s", \%defines); +getopts('c:i:j:nphCTFK') or &main::HELP_MESSAGE(\*STDOUT, "", $main::VERSION, ""); $opt_c or &main::HELP_MESSAGE(\*STDOUT, "", $main::VERSION, ""); +(!$opt_j || $has_thread_pool) or &main::HELP_MESSAGE(\*STDOUT, "", $main::VERSION, ""); $opt_h and &main::HELP_MESSAGE(\*STDOUT, "", $main::VERSION, ""); my $t_level = 0; $t_level += 2 if($opt_T); $t_level += 4 if($opt_F); $t_level += 8 if($opt_K); $t_level += 1 if($opt_C || 0 == $t_level); - +my $dry_run = $opt_n; open LOG,">tests.log"; print "Loading\n"; my @tests = @ARGV != 0 ? @ARGV : dirs(); -my $count = @tests; +my $count = 0; +for (@tests){ + my @testfiles = glob "$_/*desc"; + $count += $#testfiles+1; +} print " $count " . (1==$count?"test":"tests") . " found\n\n"; use Cwd qw(getcwd); -my $failures = 0; -my $skips = 0; +my $cwd = getcwd; +my $failures :shared = 0; +my $skips :shared = 0; +my $pool :shared = undef; + +sub do_test($) +{ + my ($test) = @_; + my $failed_skipped = 0; + my @files = glob "$test/*.desc"; + for (0..$#files){ + defined($pool) or print " Running $files[$_]"; + my $start_time = time(); + $failed_skipped = test( + $test, $files[$_], $t_level, $opt_c, $opt_i, $dry_run, \%defines); + my $runtime = time() - $start_time; + + lock($skips); + defined($pool) and print " Running $test $files[$_]"; + if(2 == $failed_skipped) { + $skips++; + print " [SKIPPED]\n"; + } elsif(0 == $failed_skipped) { + print " [OK] in $runtime seconds\n"; + } else { + $failures++; + print " [FAILED]\n"; + } + } +} + +if($opt_j>1 && $has_thread_pool && $count>1) +{ + $pool = Thread::Pool::Simple->new( + min => 2, + max => $opt_j, + load => 3, + do => [\&do_test] + ); +} + print "Running tests\n"; foreach my $test (@tests) { - print " Running $test"; - - my $cwd = getcwd; - chdir $test; - my $failed_skipped = test($test, "test.desc", $t_level, $opt_c, $opt_i); - chdir $cwd; - - if($failed_skipped < 0) { - $skips++; - print " [SKIPPED]\n"; - } elsif(0 == $failed_skipped) { - print " [OK]\n"; - } else { - $failures++; - print " [FAILED]\n"; + if(defined($pool)) + { + $pool->add($test); + } + else + { + do_test($test); } } + +defined($pool) and $pool->join(); + print "\n"; if($failures == 0) { @@ -237,5 +374,41 @@ ($$$$) close LOG; -exit $failures; +if($opt_p && $failures != 0) { + open LOG,") { + chomp $line; + if ($line =~ /^Test '(.+)'/) { + $current_test = $1; + $printed_this_test = 0; + } elsif ($line =~ /Descriptor:\s+([^\s]+)/) { + $descriptor_file = $1; + } elsif ($line =~ /Output:\s+([^\s]+)/) { + $output_file = $1; + } elsif ($line =~ /\[FAILED\]\s*$/) { + # print a descriptive header before dumping the test.desc lines that + # actually weren't matched (and print this header just once) + if(0 == $printed_this_test) { + $printed_this_test = 1; + print "\n\n"; + print "Failed test: $current_test\n"; + open FH, "<$current_test/$output_file"; + while (my $f = ) { + print $f; + } + close FH; + print "\n\nFailed $descriptor_file lines:\n"; + } + print "$line\n"; + } + } +} + +exit $failures; From 126061375a2846a291eb8d8d3c4704508d611eab Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sat, 18 Nov 2017 12:35:01 +0000 Subject: [PATCH 113/322] Deactivate tests whose result depends on SAT solver used --- regression/termination/float6/test.desc | 5 ++++- regression/termination/running4/test.desc | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/regression/termination/float6/test.desc b/regression/termination/float6/test.desc index 8314a397f..0d2310c63 100644 --- a/regression/termination/float6/test.desc +++ b/regression/termination/float6/test.desc @@ -1,6 +1,9 @@ -CORE +KNOWNBUG main.c ^EXIT=5$ ^SIGNAL=0$ ^VERIFICATION INCONCLUSIVE$ +-- +-- +result is brittle and depends on bounds on the search and the SAT solver used diff --git a/regression/termination/running4/test.desc b/regression/termination/running4/test.desc index 59010e364..e31982902 100644 --- a/regression/termination/running4/test.desc +++ b/regression/termination/running4/test.desc @@ -1,6 +1,9 @@ -CORE +KNOWNBUG main.c --context-sensitive --preconditions ^EXIT=5$ ^SIGNAL=0$ \[bar\]: !\(n <= 10000 && -\(\(signed __CPROVER_bitvector\[33\]\)n\) <= -100 && incx <= 0 && -\(\(signed __CPROVER_bitvector\[33\]\)incx\) <= 0\) +-- +-- +result is brittle and depends on bounds on the search and the SAT solver used From 30f069daa46ef03038c104c7310a4ed14642dfeb Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sat, 18 Nov 2017 13:14:37 +0000 Subject: [PATCH 114/322] version 0.5.5 --- src/2ls/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/2ls/version.h b/src/2ls/version.h index d20069838..6be6c12db 100644 --- a/src/2ls/version.h +++ b/src/2ls/version.h @@ -9,6 +9,6 @@ Author: Peter Schrammel #ifndef CPROVER_2LS_2LS_VERSION_H #define CPROVER_2LS_2LS_VERSION_H -#define TWOLS_VERSION "0.5.4" +#define TWOLS_VERSION "0.5.5" #endif From a4b616f710b61d981fa23d8733d68769dff78e7a Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sat, 11 Nov 2017 15:57:44 +0000 Subject: [PATCH 115/322] More heap tests --- regression/heap/array_unwind1/main.c | 15 +++++++++++ regression/heap/array_unwind1/test.desc | 8 ++++++ regression/heap/array_unwind2/main.c | 15 +++++++++++ regression/heap/array_unwind2/test.desc | 8 ++++++ regression/heap/list_iter1/main.c | 25 +++++++++++++++++++ regression/heap/list_iter1/test.desc | 10 ++++++++ regression/heap/list_iter2/main.c | 33 +++++++++++++++++++++++++ regression/heap/list_iter2/test.desc | 10 ++++++++ regression/heap/list_iter3/main.c | 33 +++++++++++++++++++++++++ regression/heap/list_iter3/test.desc | 10 ++++++++ regression/heap/list_iter4/main.c | 28 +++++++++++++++++++++ regression/heap/list_iter4/test.desc | 8 ++++++ regression/heap/list_unwind1/main.c | 22 +++++++++++++++++ regression/heap/list_unwind1/test.desc | 8 ++++++ regression/heap/list_unwind2/main.c | 22 +++++++++++++++++ regression/heap/list_unwind2/test.desc | 8 ++++++ regression/heap/sll_simple/test.desc | 2 +- 17 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 regression/heap/array_unwind1/main.c create mode 100644 regression/heap/array_unwind1/test.desc create mode 100644 regression/heap/array_unwind2/main.c create mode 100644 regression/heap/array_unwind2/test.desc create mode 100644 regression/heap/list_iter1/main.c create mode 100644 regression/heap/list_iter1/test.desc create mode 100644 regression/heap/list_iter2/main.c create mode 100644 regression/heap/list_iter2/test.desc create mode 100644 regression/heap/list_iter3/main.c create mode 100644 regression/heap/list_iter3/test.desc create mode 100644 regression/heap/list_iter4/main.c create mode 100644 regression/heap/list_iter4/test.desc create mode 100644 regression/heap/list_unwind1/main.c create mode 100644 regression/heap/list_unwind1/test.desc create mode 100644 regression/heap/list_unwind2/main.c create mode 100644 regression/heap/list_unwind2/test.desc diff --git a/regression/heap/array_unwind1/main.c b/regression/heap/array_unwind1/main.c new file mode 100644 index 000000000..dceaa92ce --- /dev/null +++ b/regression/heap/array_unwind1/main.c @@ -0,0 +1,15 @@ +#include +#include + +void main() +{ + int *a[2]; + a[0]=malloc(sizeof(int)); + for(int i=0; i<2; ++i) + { + a[i]=malloc(sizeof(int)); + *a[i]=i; + } + assert(*a[0]==0); + assert(*a[1]==2); +} diff --git a/regression/heap/array_unwind1/test.desc b/regression/heap/array_unwind1/test.desc new file mode 100644 index 000000000..fddf53028 --- /dev/null +++ b/regression/heap/array_unwind1/test.desc @@ -0,0 +1,8 @@ +KNOWNBUG +main.c +--incremental-bmc --heap-interval +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +^\[main\.assertion\.1\] assertion \*a\[0\]==0: OK +^\[main\.assertion\.2\] assertion \*a\[1\]==2: FAILURE diff --git a/regression/heap/array_unwind2/main.c b/regression/heap/array_unwind2/main.c new file mode 100644 index 000000000..cc0435077 --- /dev/null +++ b/regression/heap/array_unwind2/main.c @@ -0,0 +1,15 @@ +#include +#include + +void main() +{ + int *a[2]; + a[0]=malloc(sizeof(int)); + for(int i=0; i<2; ++i) + { + a[i]=malloc(sizeof(int)); + *a[i]=i; + } + assert(*a[0]==1); + assert(*a[1]==1); +} diff --git a/regression/heap/array_unwind2/test.desc b/regression/heap/array_unwind2/test.desc new file mode 100644 index 000000000..63d86204c --- /dev/null +++ b/regression/heap/array_unwind2/test.desc @@ -0,0 +1,8 @@ +KNOWNBUG +main.c +--incremental-bmc --heap-interval +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +^\[main\.assertion\.1\] assertion \*a\[0\]==1: FAILURE +^\[main\.assertion\.2\] assertion \*a\[1\]==1: OK diff --git a/regression/heap/list_iter1/main.c b/regression/heap/list_iter1/main.c new file mode 100644 index 000000000..cfb4639a9 --- /dev/null +++ b/regression/heap/list_iter1/main.c @@ -0,0 +1,25 @@ +#include +#include + +struct list +{ + int x; + struct list *n; +}; + +void main() +{ + struct list *l; + struct list *nl1=malloc(sizeof(struct list)); + nl1->x=0; + nl1->n=l; + l=nl1; + struct list *nl2=malloc(sizeof(struct list)); + nl2->x=1; + nl2->n=l; + l=nl2; + assert(l->n->x==0); + assert(l->n->x==1); + assert(l->x==2); + assert(l->x==1); +} diff --git a/regression/heap/list_iter1/test.desc b/regression/heap/list_iter1/test.desc new file mode 100644 index 000000000..6b9b3ed96 --- /dev/null +++ b/regression/heap/list_iter1/test.desc @@ -0,0 +1,10 @@ +KNOWNBUG +main.c +--incremental-bmc --independent-properties --heap-interval +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +^\[main\.assertion\.1\] assertion l->n->x==0: OK +^\[main\.assertion\.2\] assertion l->n->x==1: FAILURE +^\[main\.assertion\.3\] assertion l->x==2: FAILURE +^\[main\.assertion\.4\] assertion l->x==1: OK diff --git a/regression/heap/list_iter2/main.c b/regression/heap/list_iter2/main.c new file mode 100644 index 000000000..d53a6b3e5 --- /dev/null +++ b/regression/heap/list_iter2/main.c @@ -0,0 +1,33 @@ +#include +#include + +struct list +{ + int x; + struct list *n; +}; + +void main() +{ + struct list *l; + struct list *nl1=malloc(sizeof(struct list)); + nl1->x=-1; + nl1->n=l; + l=nl1; + struct list *nl2=malloc(sizeof(struct list)); + nl2->x=-1; + nl2->n=l; + l=nl2; + + struct list *m=l; + for(int i=0; i<2; ++i) + { + m->x=i; + m=m->n; + } + + assert(l->n->x==0); + assert(l->n->x==1); + assert(l->x==2); + assert(l->x==1); +} diff --git a/regression/heap/list_iter2/test.desc b/regression/heap/list_iter2/test.desc new file mode 100644 index 000000000..6b9b3ed96 --- /dev/null +++ b/regression/heap/list_iter2/test.desc @@ -0,0 +1,10 @@ +KNOWNBUG +main.c +--incremental-bmc --independent-properties --heap-interval +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +^\[main\.assertion\.1\] assertion l->n->x==0: OK +^\[main\.assertion\.2\] assertion l->n->x==1: FAILURE +^\[main\.assertion\.3\] assertion l->x==2: FAILURE +^\[main\.assertion\.4\] assertion l->x==1: OK diff --git a/regression/heap/list_iter3/main.c b/regression/heap/list_iter3/main.c new file mode 100644 index 000000000..4cc233ea3 --- /dev/null +++ b/regression/heap/list_iter3/main.c @@ -0,0 +1,33 @@ +#include +#include + +struct list +{ + int x; + struct list *n; +}; + +void main() +{ + struct list *l; + struct list *nl1=malloc(sizeof(struct list)); + nl1->x=-1; + nl1->n=l; + l=nl1; + struct list *nl2=malloc(sizeof(struct list)); + nl2->x=-1; + nl2->n=l; + l=nl2; + + struct list *m=l; + for(int i=0; m!=NULL; ++i) + { + m->x=i; + m=m->n; + } + + assert(l->n->x==0); + assert(l->n->x==1); + assert(l->x==2); + assert(l->x==1); +} diff --git a/regression/heap/list_iter3/test.desc b/regression/heap/list_iter3/test.desc new file mode 100644 index 000000000..6b9b3ed96 --- /dev/null +++ b/regression/heap/list_iter3/test.desc @@ -0,0 +1,10 @@ +KNOWNBUG +main.c +--incremental-bmc --independent-properties --heap-interval +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +^\[main\.assertion\.1\] assertion l->n->x==0: OK +^\[main\.assertion\.2\] assertion l->n->x==1: FAILURE +^\[main\.assertion\.3\] assertion l->x==2: FAILURE +^\[main\.assertion\.4\] assertion l->x==1: OK diff --git a/regression/heap/list_iter4/main.c b/regression/heap/list_iter4/main.c new file mode 100644 index 000000000..8266624ac --- /dev/null +++ b/regression/heap/list_iter4/main.c @@ -0,0 +1,28 @@ +#include +#include + +struct list +{ + int x; + struct list *n; +}; + +void main() +{ + struct list *l; + struct list *nl1=malloc(sizeof(struct list)); + nl1->x=0; + nl1->n=l; + l=nl1; + struct list *nl2=malloc(sizeof(struct list)); + nl2->x=1; + nl2->n=l; + l=nl2; + + struct list *m=l; + for(int i=0; i<2; ++i) + { + assert(m->x==i); + assert(m->x==-1); + } +} diff --git a/regression/heap/list_iter4/test.desc b/regression/heap/list_iter4/test.desc new file mode 100644 index 000000000..39b8f9acd --- /dev/null +++ b/regression/heap/list_iter4/test.desc @@ -0,0 +1,8 @@ +KNOWNBUG +main.c +--incremental-bmc --independent-properties --heap-interval +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +^\[main\.assertion\.1\] assertion m->x==i: OK +^\[main\.assertion\.2\] assertion m->x==-1: FAILURE diff --git a/regression/heap/list_unwind1/main.c b/regression/heap/list_unwind1/main.c new file mode 100644 index 000000000..5a27f15e4 --- /dev/null +++ b/regression/heap/list_unwind1/main.c @@ -0,0 +1,22 @@ +#include +#include + +struct list +{ + int x; + struct list *n; +}; + +void main() +{ + struct list *l; + for(int i=0; i<2; ++i) + { + struct list *nl=malloc(sizeof(struct list)); + nl->x=i; + nl->n=l; + l=nl; + } + assert(l->n->x==0); + assert(l->x==2); +} diff --git a/regression/heap/list_unwind1/test.desc b/regression/heap/list_unwind1/test.desc new file mode 100644 index 000000000..2569ab217 --- /dev/null +++ b/regression/heap/list_unwind1/test.desc @@ -0,0 +1,8 @@ +KNOWNBUG +main.c +--incremental-bmc --heap-interval +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +^\[main\.assertion\.1\] assertion l->n->x==0: OK +^\[main\.assertion\.2\] assertion l->x==2: FAILURE diff --git a/regression/heap/list_unwind2/main.c b/regression/heap/list_unwind2/main.c new file mode 100644 index 000000000..3341fcdec --- /dev/null +++ b/regression/heap/list_unwind2/main.c @@ -0,0 +1,22 @@ +#include +#include + +struct list +{ + int x; + struct list *n; +}; + +void main() +{ + struct list *l; + for(int i=0; i<2; ++i) + { + struct list *nl=malloc(sizeof(struct list)); + nl->x=i; + nl->n=l; + l=nl; + } + assert(l->n->x==1); + assert(l->x==1); +} diff --git a/regression/heap/list_unwind2/test.desc b/regression/heap/list_unwind2/test.desc new file mode 100644 index 000000000..22c105e62 --- /dev/null +++ b/regression/heap/list_unwind2/test.desc @@ -0,0 +1,8 @@ +KNOWNBUG +main.c +--incremental-bmc --heap-interval +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +^\[main\.assertion\.1\] assertion l->n->x==1: FAILURE +^\[main\.assertion\.2\] assertion l->x==1: OK diff --git a/regression/heap/sll_simple/test.desc b/regression/heap/sll_simple/test.desc index ed14b476a..b13e412ea 100644 --- a/regression/heap/sll_simple/test.desc +++ b/regression/heap/sll_simple/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap --inline --no-propagation +--heap --inline --no-propagation --heap-interval ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ From b4eda8cda31357e66f1d778d096bd655926428c9 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sun, 19 Nov 2017 11:38:13 +0000 Subject: [PATCH 116/322] Fix can_convert_ssa_expr --- src/ssa/ssa_build_goto_trace.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ssa/ssa_build_goto_trace.cpp b/src/ssa/ssa_build_goto_trace.cpp index b5866a5bd..3767e726c 100644 --- a/src/ssa/ssa_build_goto_trace.cpp +++ b/src/ssa/ssa_build_goto_trace.cpp @@ -77,8 +77,7 @@ bool ssa_build_goto_tracet::can_convert_ssa_expr(const exprt &expr) if(expr.id()==ID_member) { const member_exprt &member=to_member_expr(expr); - can_convert_ssa_expr(member.struct_op()); - return true; + return can_convert_ssa_expr(member.struct_op()); } else if(expr.id()==ID_index) { @@ -216,8 +215,9 @@ bool ssa_build_goto_tracet::record_step( #if 0 std::cout << "ASSIGN " << from_expr(unwindable_local_SSA.ns, "", code_assign) - << ": " << from_expr(unwindable_local_SSA.ns, "", rhs_ssa) - << "==" << from_expr(unwindable_local_SSA.ns, "", rhs_simplified) + << ": " << from_expr(unwindable_local_SSA.ns, "", lhs_simplified) + << " := " + << from_expr(unwindable_local_SSA.ns, "", rhs_simplified) << std::endl; #endif step.type=goto_trace_stept::ASSIGNMENT; From 31349997e691584f24051f0c30d9e350d8bfc95d Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sat, 11 Nov 2017 16:47:53 +0000 Subject: [PATCH 117/322] Improve debug output --- src/ssa/unwindable_local_ssa.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/ssa/unwindable_local_ssa.cpp b/src/ssa/unwindable_local_ssa.cpp index 8b49f8e76..cc09bb1f3 100644 --- a/src/ssa/unwindable_local_ssa.cpp +++ b/src/ssa/unwindable_local_ssa.cpp @@ -282,7 +282,7 @@ void unwindable_local_SSAt::rename(exprt &expr, locationt current_loc) if(expr.id()==ID_symbol) { symbol_exprt &s=to_symbol_expr(expr); - locationt def_loc; + locationt def_loc=goto_function.body.instructions.end(); // we could reuse name(), // but then we would have to search in the ssa_objects // ENHANCEMENT: maybe better to attach base name, ssa name, @@ -294,13 +294,15 @@ void unwindable_local_SSAt::rename(exprt &expr, locationt current_loc) s.set_identifier(id2string(id)+unwind_suffix); #if 0 - std::cout << "DEF_LOC: " << def_loc->location_number << std::endl; - std::cout << "DEF_LEVEL: " << def_level << std::endl; - std::cout << "O.size: " << current_unwindings.size() << std::endl; - std::cout << "current: " << current_unwinding << std::endl; std::cout << "RENAME_SYMBOL: " << id << " --> " << s.get_identifier() << std::endl; + std::cout << "DEF_LOC: " + << (def_loc!=goto_function.body.instructions.end() + ? def_loc->location_number : -1) << std::endl; + std::cout << "DEF_LEVEL: " << def_level << std::endl; + std::cout << "O.size: " << current_unwindings.size() << std::endl; + std::cout << "current: " << current_unwinding << std::endl << std::endl; #endif } if(expr.id()==ID_nondet_symbol) From a291ad01969f9f1fb5e87e0f8e275d75669de2c4 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sat, 11 Nov 2017 22:18:52 +0000 Subject: [PATCH 118/322] Fix show_ssa for ssa_heap_analysis --- src/2ls/2ls_parse_options.cpp | 28 ++++++++++++--------- src/2ls/show.cpp | 14 +++++++---- src/2ls/show.h | 2 ++ src/ssa/local_ssa.h | 2 +- src/ssa/unwindable_local_ssa.cpp | 42 ++++++++++++++++++++++++++++++++ src/ssa/unwindable_local_ssa.h | 2 ++ 6 files changed, 73 insertions(+), 17 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 8b86e7edc..80a1387e5 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -391,6 +391,16 @@ int twols_parse_optionst::doit() if(get_goto_program(options, goto_model)) return 6; + const namespacet ns(goto_model.symbol_table); + ssa_heap_analysist heap_analysis(ns); + if((options.get_bool_option("heap") || + options.get_bool_option("heap-interval")) && + !options.get_bool_option("inline")) + { + heap_analysis(goto_model.goto_functions); + add_dynamic_object_symbols(heap_analysis, goto_model); + } + if(cmdline.isset("show-stats")) { show_stats(goto_model, std::cout); @@ -403,7 +413,13 @@ int twols_parse_optionst::doit() { bool simplify=!cmdline.isset("no-simplify"); irep_idt function=cmdline.get_value("function"); - show_ssa(goto_model, function, simplify, std::cout, ui_message_handler); + show_ssa( + goto_model, + heap_analysis, + function, + simplify, + std::cout, + ui_message_handler); return 7; } @@ -515,16 +531,6 @@ int twols_parse_optionst::doit() status() << eom; } - const namespacet ns(goto_model.symbol_table); - ssa_heap_analysist heap_analysis(ns); - if((options.get_bool_option("heap") || - options.get_bool_option("heap-interval")) && - !options.get_bool_option("inline")) - { - heap_analysis(goto_model.goto_functions); - add_dynamic_object_symbols(heap_analysis, goto_model); - } - try { std::unique_ptr checker; diff --git a/src/2ls/show.cpp b/src/2ls/show.cpp index 15336c99e..ce0b64e94 100644 --- a/src/2ls/show.cpp +++ b/src/2ls/show.cpp @@ -18,7 +18,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include -#include +#include #include #include @@ -251,12 +251,15 @@ Function: show_ssa void show_ssa( const goto_functionst::goto_functiont &goto_function, + const ssa_heap_analysist &heap_analysis, bool simplify, const namespacet &ns, std::ostream &out) { - ssa_heap_analysist heap_analysis(ns); - local_SSAt local_SSA(goto_function, ns, heap_analysis); + if(!goto_function.body_available()) + return; + + unwindable_local_SSAt local_SSA(goto_function, ns, heap_analysis); if(simplify) ::simplify(local_SSA, ns); local_SSA.output_verbose(out); @@ -276,6 +279,7 @@ Function: show_ssa void show_ssa( const goto_modelt &goto_model, + const ssa_heap_analysist &heap_analysis, const irep_idt &function, bool simplify, std::ostream &out, @@ -291,7 +295,7 @@ void show_ssa( if(f_it==goto_model.goto_functions.function_map.end()) out << "function " << function << " not found\n"; else - show_ssa(f_it->second, simplify, ns, out); + show_ssa(f_it->second, heap_analysis, simplify, ns, out); } else { @@ -304,7 +308,7 @@ void show_ssa( out << ">>>> Function " << f_it->first << "\n"; - show_ssa(f_it->second, simplify, ns, out); + show_ssa(f_it->second, heap_analysis, simplify, ns, out); out << "\n"; } diff --git a/src/2ls/show.h b/src/2ls/show.h index 2e9557eac..7051e56a5 100644 --- a/src/2ls/show.h +++ b/src/2ls/show.h @@ -19,9 +19,11 @@ Author: Daniel Kroening, kroening@kroening.com #include class message_handlert; +class ssa_heap_analysist; void show_ssa( const goto_modelt &, + const ssa_heap_analysist &, const irep_idt &function, bool simplify, std::ostream &, diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 3a54d2171..7bbc7ff31 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -59,7 +59,7 @@ class local_SSAt } void output(std::ostream &) const; - void output_verbose(std::ostream &) const; + virtual void output_verbose(std::ostream &) const; // the SSA node for a location class nodet diff --git a/src/ssa/unwindable_local_ssa.cpp b/src/ssa/unwindable_local_ssa.cpp index cc09bb1f3..e53155c7f 100644 --- a/src/ssa/unwindable_local_ssa.cpp +++ b/src/ssa/unwindable_local_ssa.cpp @@ -461,3 +461,45 @@ void unwindable_local_SSAt::compute_loop_hierarchy() } while(i_it!=goto_function.body.instructions.begin()); } + +/*******************************************************************\ + +Function: unwindable_local_SSAt::output_verbose + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void unwindable_local_SSAt::output_verbose(std::ostream &out) const +{ + for(const auto &node : nodes) + { + if(node.empty()) + continue; + out << "*** " << node.location->location_number + << " " << node.location->source_location << "\n"; + node.output(out, ns); + for(const auto &e : node.equalities) + { + std::set symbols; + find_symbols(e, symbols); + for(const auto &s : symbols) + { + if(s.type().get_bool("#dynamic")) + out << s.get_identifier() << "\n"; + } + } + if(node.loophead!=nodes.end()) + out << "loop back to location " + << node.loophead->location->location_number << "\n"; + if(!node.enabling_expr.is_true()) + out << "enabled if " + << from_expr(ns, "", node.enabling_expr) << "\n"; + out << "\n"; + } + out << "(enable) " << from_expr(ns, "", get_enabling_exprs()) << "\n\n"; +} diff --git a/src/ssa/unwindable_local_ssa.h b/src/ssa/unwindable_local_ssa.h index ba1000d1c..11f518225 100644 --- a/src/ssa/unwindable_local_ssa.h +++ b/src/ssa/unwindable_local_ssa.h @@ -81,6 +81,8 @@ class unwindable_local_SSAt:public local_SSAt locationt &loc, odometert &odometer) const; + void output_verbose(std::ostream &) const override; + protected: irep_idt get_ssa_name(const symbol_exprt &, locationt &loc) const; From ca29943ae40a806971302e0e3cd2dd5ed3ac3cd5 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 8 Sep 2017 08:57:54 +0200 Subject: [PATCH 119/322] Heap analysis: use symbolic dereferencing when accessing objects in the heap. We transform p->n into p'obj.n which represents a concretised object. In the same time, changes are reflected on actual heap objects (dynamic_object$...). This is because dynamic_object is an abstraction and so the analysis might be unsound when dealing with 2 different objects represented by the same dynamic_object. We also introduce simple may_alias analysis here. --- src/domains/template_generator_base.cpp | 4 + src/ssa/Makefile | 3 +- src/ssa/assignments.cpp | 2 + src/ssa/local_ssa.cpp | 109 ++++++++++++-- src/ssa/local_ssa.h | 31 +++- src/ssa/may_alias_analysis.cpp | 182 ++++++++++++++++++++++++ src/ssa/may_alias_analysis.h | 52 +++++++ src/ssa/ssa_dereference.cpp | 9 ++ src/ssa/ssa_object.cpp | 8 +- src/ssa/ssa_pointed_objects.cpp | 20 ++- src/ssa/ssa_pointed_objects.h | 1 + 11 files changed, 391 insertions(+), 30 deletions(-) create mode 100644 src/ssa/may_alias_analysis.cpp create mode 100644 src/ssa/may_alias_analysis.h diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index 38f6f83fc..6cd3d55ff 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -286,6 +286,10 @@ void template_generator_baset::filter_heap_domain() { if(var.var.id()==ID_symbol && var.var.type().id()==ID_pointer) { + if(is_pointed(var.var) && + id2string(to_symbol_expr(var.var).get_identifier()).find(".")!= + std::string::npos) + continue; // Filter out non-assigned OUT variables if(var.kind!=domaint::OUT || ssa_inlinert::get_original_identifier(to_symbol_expr(var.var))!= diff --git a/src/ssa/Makefile b/src/ssa/Makefile index 788963786..81460b00c 100644 --- a/src/ssa/Makefile +++ b/src/ssa/Makefile @@ -4,7 +4,8 @@ SRC = local_ssa.cpp ssa_var_collector.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 + unwindable_local_ssa.cpp ssa_db.cpp \ + ssa_pointed_objects.cpp ssa_heap_domain.cpp may_alias_analysis.cpp include ../config.inc include $(CBMC)/src/config.inc diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index b052f92ae..5af7d35a8 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -40,6 +40,8 @@ void assignmentst::build_assignment_map( const code_assignt &code_assign=to_code_assign(it->code); exprt lhs_deref=dereference(code_assign.lhs(), ssa_value_ai[it], "", ns); assign(lhs_deref, it, ns); + exprt lhs_symbolic_deref=symbolic_dereference(code_assign.lhs(), ns); + assign(lhs_symbolic_deref, it, ns); } else if(it->is_decl()) { diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 5ef8cf09a..11371d9e4 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -462,7 +462,30 @@ void local_SSAt::build_transfer(locationt loc) exprt deref_lhs=dereference(code_assign.lhs(), loc); exprt deref_rhs=dereference(code_assign.rhs(), loc); - assign_rec(deref_lhs, deref_rhs, true_exprt(), loc); + if(deref_lhs.get_bool("#heap_access") || deref_rhs.get_bool("#heap_access")) + { + exprt symbolic_deref_lhs=symbolic_dereference(code_assign.lhs(), ns); + exprt symbolic_deref_rhs=symbolic_dereference(code_assign.rhs(), ns); + + exprt rhs=all_symbolic_deref_defined(symbolic_deref_rhs, ns, loc) + ? symbolic_deref_rhs : deref_rhs; + + if(deref_lhs.get_bool("#heap_access") && + has_symbolic_deref(symbolic_deref_lhs)) + { + assign_rec(symbolic_deref_lhs, rhs, true_exprt(), loc); + assign_rec( + deref_lhs, name(ssa_objectt(symbolic_deref_lhs, ns), OUT, loc), + true_exprt(), + loc); + } + else + { + assign_rec(deref_lhs, rhs, true_exprt(), loc); + } + } + else + assign_rec(deref_lhs, deref_rhs, true_exprt(), loc); } } @@ -1172,7 +1195,8 @@ 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": + kind==OBJECT_SELECT?"os":"")+ i2string(cnt)+ (kind==LOOP_SELECT?std::string(""):suffix); @@ -1378,18 +1402,44 @@ void local_SSAt::assign_rec( { const if_exprt &if_expr=to_if_expr(lhs); - exprt new_rhs=if_exprt(if_expr.cond(), rhs, if_expr.true_case()); - assign_rec( - if_expr.true_case(), - new_rhs, - and_exprt(guard, if_expr.cond()), - loc); - - assign_rec( - if_expr.false_case(), - rhs, - and_exprt(guard, not_exprt(if_expr.cond())), - loc); + exprt::operandst other_cond_conj; + if(if_expr.true_case().get_bool("#heap_access") && + if_expr.cond().id()==ID_equal) + { + const exprt heap_object=if_expr.true_case(); + const ssa_objectt ptr_object(to_equal_expr(if_expr.cond()).lhs(), ns); + if(ptr_object) + { + const irep_idt ptr_id=ptr_object.get_identifier(); + const exprt cond=read_rhs(if_expr.cond(), loc); + + for(const dyn_obj_assignt &do_assign : dyn_obj_assigns[heap_object]) + { + if(!alias_analysis[loc].aliases.same_set( + ptr_id, do_assign.pointer_id)) + { + other_cond_conj.push_back(do_assign.cond); + } + } + + dyn_obj_assigns[heap_object].emplace_back(ptr_id, cond); + } + } + + exprt cond=if_expr.cond(); + if(!other_cond_conj.empty()) + { + const exprt other_cond=or_exprt( + not_exprt(conjunction(other_cond_conj)), + name(guard_symbol(), OBJECT_SELECT, loc)); + cond=and_exprt(cond, other_cond); + } + exprt new_rhs=if_exprt(cond, rhs, if_expr.true_case()); + assign_rec(if_expr.true_case(), new_rhs, and_exprt(guard, if_expr.cond()), + loc); + + assign_rec(if_expr.false_case(), rhs, + and_exprt(guard, not_exprt(if_expr.cond())), loc); } else if(lhs.id()==ID_byte_extract_little_endian || lhs.id()==ID_byte_extract_big_endian) @@ -1930,3 +1980,34 @@ void local_SSAt::new_iterator_access( auto it=iterators.insert(iterator); it.first->add_access(expr, inst_loc_number); } + +/*******************************************************************\ + +Function: local_SSAt::all_symbolic_deref_defined + + Inputs: + + Outputs: + + Purpose: Create new iterator access + +\*******************************************************************/ +bool local_SSAt::all_symbolic_deref_defined( + const exprt &expr, + const namespacet &ns, + locationt loc) const +{ + bool result=true; + ssa_objectt ssa_object(expr, ns); + if(ssa_object && has_symbolic_deref(ssa_object.get_expr())) + { + const ssa_domaint &ssa_domain=ssa_analysis[loc]; + auto def_it=ssa_domain.def_map.find(ssa_object.get_identifier()); + if(def_it==ssa_domain.def_map.end() || def_it->second.def.is_input()) + result=false; + } + else forall_operands(it, expr) + result=result && all_symbolic_deref_defined(*it, ns, loc); + return result; +} + diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 7bbc7ff31..0ebfb3945 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -20,6 +20,7 @@ Author: Daniel Kroening, kroening@kroening.com #include "guard_map.h" #include "ssa_object.h" #include "ssa_heap_domain.h" +#include "may_alias_analysis.h" #define TEMPLATE_PREFIX "__CPROVER_template" #define TEMPLATE_DECL TEMPLATE_PREFIX @@ -42,11 +43,8 @@ class local_SSAt ssa_objects(_goto_function, ns, _heap_analysis), ssa_value_ai(_goto_function, ns, _heap_analysis), assignments( - _goto_function.body, - ns, - ssa_objects, - ssa_value_ai, - heap_analysis), + _goto_function.body, ns, ssa_objects, ssa_value_ai, heap_analysis), + alias_analysis(_goto_function, ns), guard_map(_goto_function.body), ssa_analysis(assignments), suffix(_suffix) @@ -142,6 +140,20 @@ class local_SSAt // unknown heap objects var_sett unknown_objs; + // Maps members of dynamic object to a set of pointers used to access those + // objects when assigning them + class dyn_obj_assignt + { + public: + const irep_idt pointer_id; + const exprt cond; + + dyn_obj_assignt(const irep_idt &pointer_id, const exprt &cond): + pointer_id(pointer_id), cond(cond) {} + }; + typedef std::list dyn_obj_assignst; + std::map dyn_obj_assigns; + bool has_function_calls() const; const namespacet &ns; @@ -157,7 +169,7 @@ class local_SSAt exprt edge_guard(locationt from, locationt to) const; // auxiliary functions - enum kindt { PHI, OUT, LOOP_BACK, LOOP_SELECT }; + enum kindt { PHI, OUT, LOOP_BACK, LOOP_SELECT, OBJECT_SELECT }; virtual symbol_exprt name( const ssa_objectt &, kindt kind, @@ -201,6 +213,11 @@ class local_SSAt exprt dereference(const exprt &expr, locationt loc) const; + bool all_symbolic_deref_defined( + const exprt &expr, + const namespacet &ns, + locationt loc) const; + const ssa_heap_analysist &heap_analysis; ssa_objectst ssa_objects; @@ -208,6 +225,8 @@ class local_SSAt ssa_value_ait ssa_value_ai; assignmentst assignments; + may_alias_analysist alias_analysis; + // protected: guard_mapt guard_map; diff --git a/src/ssa/may_alias_analysis.cpp b/src/ssa/may_alias_analysis.cpp new file mode 100644 index 000000000..4b09b9ec8 --- /dev/null +++ b/src/ssa/may_alias_analysis.cpp @@ -0,0 +1,182 @@ +/*******************************************************************\ + +Module: May-alias analysis for a single function + +Author: Viktor Malik, imalik@fit.vutbr.cz + +\*******************************************************************/ + +#include "may_alias_analysis.h" + +/*******************************************************************\ + +Function: may_alias_domaint::transform + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ +void may_alias_domaint::transform( + ai_domain_baset::locationt from, + ai_domain_baset::locationt to, + ai_baset &ai, + const namespacet &ns) +{ + if(from->is_assign()) + { + const code_assignt &code_assign=to_code_assign(from->code); + + const exprt lhs_deref=dereference(code_assign.lhs(), ns); + const exprt rhs_deref=dereference(code_assign.rhs(), ns); + + std::set aliases; + get_rhs_aliases(rhs_deref, aliases); + assign_lhs_aliases(lhs_deref, aliases); + } +} + +/*******************************************************************\ + +Function: may_alias_domaint::merge + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ +bool may_alias_domaint::merge( + const may_alias_domaint &other, + ai_domain_baset::locationt from, + ai_domain_baset::locationt to) +{ + bool changed=false; + + // do union + for(aliasest::const_iterator it=other.aliases.begin(); + it!=other.aliases.end(); it++) + { + irep_idt other_root=other.aliases.find(it); + + if(!aliases.same_set(*it, other_root)) + { + aliases.make_union(*it, other_root); + changed=true; + } + } + + return changed; +} + +/*******************************************************************\ + +Function: may_alias_domaint::assign_lhs_aliases + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ +void may_alias_domaint::assign_lhs_aliases( + const exprt &lhs, + const std::set &alias_set) +{ + if(lhs.type().id()==ID_pointer) + { + if(lhs.id()==ID_symbol) + { + irep_idt identifier=to_symbol_expr(lhs).get_identifier(); + + aliases.isolate(identifier); + + for(const irep_idt &alias : alias_set) + { + aliases.make_union(identifier, alias); + } + } + } +} + +/*******************************************************************\ + +Function: may_alias_domaint::get_rhs_aliases + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ +void may_alias_domaint::get_rhs_aliases( + const exprt &rhs, + std::set &alias_set) +{ + if(rhs.id()==ID_symbol && + id2string(to_symbol_expr(rhs).get_identifier()).find("__CPROVER_")== + std::string::npos) + { + irep_idt identifier=to_symbol_expr(rhs).get_identifier(); + alias_set.insert(identifier); + + for(aliasest::const_iterator it=aliases.begin(); + it!=aliases.end(); + it++) + if(aliases.same_set(*it, identifier)) + alias_set.insert(*it); + } + else if(rhs.id()==ID_if) + { + get_rhs_aliases(to_if_expr(rhs).true_case(), alias_set); + get_rhs_aliases(to_if_expr(rhs).false_case(), alias_set); + } + else if(rhs.id()==ID_typecast) + { + get_rhs_aliases(to_typecast_expr(rhs).op(), alias_set); + } +} + +/*******************************************************************\ + +Function: may_alias_domaint::dereference + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ +const exprt may_alias_domaint::dereference( + const exprt &expr, + const namespacet &ns) +{ + exprt deref=symbolic_dereference(expr, ns); + members_to_symbols(deref, ns); + return deref; +} + +/*******************************************************************\ + +Function: may_alias_domaint::members_to_symbols + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ +void may_alias_domaint::members_to_symbols(exprt &expr, const namespacet &ns) +{ + ssa_objectt object(expr, ns); + if(object) + expr=object.symbol_expr(); + Forall_operands(it, expr)members_to_symbols(*it, ns); +} diff --git a/src/ssa/may_alias_analysis.h b/src/ssa/may_alias_analysis.h new file mode 100644 index 000000000..011763736 --- /dev/null +++ b/src/ssa/may_alias_analysis.h @@ -0,0 +1,52 @@ +/*******************************************************************\ + +Module: May-alias analysis for a single function + +Author: Viktor Malik, imalik@fit.vutbr.cz + +\*******************************************************************/ + +#ifndef CPROVER_2LS_SSA_MAY_ALIAS_ANALYSIS_H +#define CPROVER_2LS_SSA_MAY_ALIAS_ANALYSIS_H + +#include +#include +#include "ssa_value_set.h" + +class may_alias_domaint:public ai_domain_baset +{ +public: + void transform( + locationt from, + locationt to, + ai_baset &ai, + const namespacet &ns) override; + + bool merge(const may_alias_domaint &other, locationt from, locationt to); + + typedef union_find aliasest; + aliasest aliases; + +protected: + void assign_lhs_aliases( + const exprt &lhs, + const std::set &rhs_alias_set); + void get_rhs_aliases(const exprt &rhs, std::set &alias_set); + + static const exprt dereference(const exprt &expr, const namespacet &ns); + static void members_to_symbols(exprt &expr, const namespacet &ns); +}; + +class may_alias_analysist:public ait +{ +public: + may_alias_analysist( + const goto_functionst::goto_functiont &goto_function, + const namespacet &ns) + { + operator()(goto_function, ns); + } +}; + + +#endif // CPROVER_2LS_SSA_MAY_ALIAS_ANALYSIS_H diff --git a/src/ssa/ssa_dereference.cpp b/src/ssa/ssa_dereference.cpp index 557759138..67d84f0de 100644 --- a/src/ssa/ssa_dereference.cpp +++ b/src/ssa/ssa_dereference.cpp @@ -351,6 +351,7 @@ exprt dereference_rec( else { result=ssa_alias_value(src, (it++)->get_expr(), ns); + result.set("#heap_access", result.get_bool("#dynamic")); } for(; it!=values.value_set.end(); ++it) @@ -358,6 +359,10 @@ exprt dereference_rec( exprt guard=ssa_alias_guard(src, it->get_expr(), ns); exprt value=ssa_alias_value(src, it->get_expr(), ns); result=if_exprt(guard, value, result); + result.set( + "#heap_access", + result.get_bool("#heap_access") || + value.type().get_bool("#dynamic")); } } @@ -368,6 +373,7 @@ exprt dereference_rec( member_exprt tmp=to_member_expr(src); tmp.struct_op()= dereference_rec(tmp.struct_op(), ssa_value_domain, nondet_prefix, ns); + tmp.set("#heap_access", tmp.struct_op().get_bool("#heap_access")); #ifdef DEBUG std::cout << "dereference_rec tmp: " << from_expr(ns, "", tmp) << '\n'; @@ -383,6 +389,7 @@ exprt dereference_rec( address_of_exprt tmp=to_address_of_expr(src); tmp.object()= dereference_rec(tmp.object(), ssa_value_domain, nondet_prefix, ns); + tmp.set("#heap_access", tmp.object().get_bool("#heap_access")); if(tmp.object().is_nil()) return nil_exprt(); @@ -395,6 +402,8 @@ exprt dereference_rec( Forall_operands(it, tmp) { *it=dereference_rec(*it, ssa_value_domain, nondet_prefix, ns); + if(it->get_bool("#heap_access")) + tmp.set("#heap_access", true); } return tmp; } diff --git a/src/ssa/ssa_object.cpp b/src/ssa/ssa_object.cpp index f2affa7a3..eae7869e3 100644 --- a/src/ssa/ssa_object.cpp +++ b/src/ssa/ssa_object.cpp @@ -231,13 +231,7 @@ void collect_objects_rec( objects.insert(ssa_object); const exprt &root_object=ssa_object.get_root_object(); - const symbolt *symbol; - if(ssa_object.type().get_bool("#dynamic") || - (root_object.id()==ID_symbol && - id2string(to_symbol_expr(root_object).get_identifier()).find( - "#return_value")==std::string::npos && - !ns.lookup(to_symbol_expr(root_object).get_identifier(), symbol) && - (symbol->is_parameter || !symbol->is_procedure_local()))) + if(ssa_object.type().get_bool("#dynamic") || !is_pointed(root_object)) { collect_ptr_objects( ssa_object.symbol_expr(), diff --git a/src/ssa/ssa_pointed_objects.cpp b/src/ssa/ssa_pointed_objects.cpp index 3b6eab677..ecb215cff 100644 --- a/src/ssa/ssa_pointed_objects.cpp +++ b/src/ssa/ssa_pointed_objects.cpp @@ -377,19 +377,30 @@ const exprt symbolic_dereference(const exprt &expr, const namespacet &ns) const ssa_objectt pointer_object(pointer, ns); assert(pointer_object); - return pointed_object(pointer_object.symbol_expr(), ns); + symbol_exprt sym_deref=pointed_object(pointer_object.symbol_expr(), ns); + sym_deref.set("#has_symbolic_deref", true); + return sym_deref; } else if(expr.id()==ID_member) { member_exprt member=to_member_expr(expr); member.compound()=symbolic_dereference(member.compound(), ns); + member.set( + "#has_symbolic_deref", + has_symbolic_deref(member.compound())); + return member; } else { exprt tmp=expr; - Forall_operands(it, tmp)*it=symbolic_dereference(*it, ns); + Forall_operands(it, tmp) + { + *it=symbolic_dereference(*it, ns); + if(has_symbolic_deref(*it)) + tmp.set("#has_symbolic_deref", true); + } return tmp; } } @@ -529,3 +540,8 @@ const irep_idt iterator_to_initial_id( return id_str.replace( id_str.find(iterator_id_str), iterator_id_str.length(), init_value_id_str); } + +bool has_symbolic_deref(const exprt &expr) +{ + return expr.get_bool("#has_symbolic_deref"); +} diff --git a/src/ssa/ssa_pointed_objects.h b/src/ssa/ssa_pointed_objects.h index 95d06e15e..bb3fc3da6 100644 --- a/src/ssa/ssa_pointed_objects.h +++ b/src/ssa/ssa_pointed_objects.h @@ -49,6 +49,7 @@ void copy_pointed_info(exprt &dest, const exprt &src); void copy_iterator(exprt &dest, const exprt &src); const exprt symbolic_dereference(const exprt &expr, const namespacet &ns); +bool has_symbolic_deref(const exprt &expr); void set_iterator_fields(exprt &dest, const std::vector fields); const std::vector get_iterator_fields(const exprt &expr); From 8ace140d8451eddac507840b13535ef0a4278764 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 5 Oct 2017 14:11:17 +0200 Subject: [PATCH 120/322] Fix bug in dereference, #dynamic flag must be checked on type, not on object itself. --- src/ssa/ssa_dereference.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ssa/ssa_dereference.cpp b/src/ssa/ssa_dereference.cpp index 67d84f0de..ce4478e5c 100644 --- a/src/ssa/ssa_dereference.cpp +++ b/src/ssa/ssa_dereference.cpp @@ -351,7 +351,7 @@ exprt dereference_rec( else { result=ssa_alias_value(src, (it++)->get_expr(), ns); - result.set("#heap_access", result.get_bool("#dynamic")); + result.set("#heap_access", result.type().get_bool("#dynamic")); } for(; it!=values.value_set.end(); ++it) From 15ea861f9f8c5a04713ad5b55616a821ff1db9ca Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 6 Oct 2017 07:43:33 +0200 Subject: [PATCH 121/322] Dereference: always add unknown_object when pointer points to multiple dynamic objects. This is needed for a situation when dereference leading to multiple dynamic objects occurs on the left hand side (so that each object is assigned either RHS or its new value). --- src/ssa/ssa_dereference.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ssa/ssa_dereference.cpp b/src/ssa/ssa_dereference.cpp index ce4478e5c..1e3d57d7f 100644 --- a/src/ssa/ssa_dereference.cpp +++ b/src/ssa/ssa_dereference.cpp @@ -338,7 +338,8 @@ exprt dereference_rec( { auto it=values.value_set.begin(); - if(values.null || values.unknown) + if(values.null || values.unknown || + (values.value_set.size()>1 && it->type().get_bool("#dynamic"))) { std::string dyn_type_name=pointed_type.id_string(); if(pointed_type.id()==ID_struct) From dbf71d80b33076cc09b5e8064ad27be37946158b Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 6 Oct 2017 09:34:35 +0200 Subject: [PATCH 122/322] Heap analysis: do RHS 'concretisation' only if heap objects are accessed. --- src/ssa/local_ssa.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 11371d9e4..d5567cec7 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -467,7 +467,8 @@ void local_SSAt::build_transfer(locationt loc) exprt symbolic_deref_lhs=symbolic_dereference(code_assign.lhs(), ns); exprt symbolic_deref_rhs=symbolic_dereference(code_assign.rhs(), ns); - exprt rhs=all_symbolic_deref_defined(symbolic_deref_rhs, ns, loc) + exprt rhs=deref_rhs.get_bool("#heap_access") && + all_symbolic_deref_defined(symbolic_deref_rhs, ns, loc) ? symbolic_deref_rhs : deref_rhs; if(deref_lhs.get_bool("#heap_access") && From 913fee389f1c0036775bf6fa5a10cf5abd4ea7c7 Mon Sep 17 00:00:00 2001 From: Martin Hruska Date: Tue, 10 Oct 2017 19:05:01 +0200 Subject: [PATCH 123/322] solving heap object concretisation in the right-hand side of assignment --- src/ssa/assignments.cpp | 3 +++ src/ssa/local_ssa.cpp | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index 5af7d35a8..0758f3085 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -42,6 +42,9 @@ void assignmentst::build_assignment_map( assign(lhs_deref, it, ns); exprt lhs_symbolic_deref=symbolic_dereference(code_assign.lhs(), ns); assign(lhs_symbolic_deref, it, ns); + + exprt rhs_symbolic_deref=symbolic_dereference(code_assign.rhs(), ns); + assign(rhs_symbolic_deref, it, ns); } else if(it->is_decl()) { diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index d5567cec7..766a3ea18 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -482,7 +482,12 @@ void local_SSAt::build_transfer(locationt loc) } else { - assign_rec(deref_lhs, rhs, true_exprt(), loc); + assign_rec(symbolic_deref_rhs, deref_rhs, true_exprt(), loc); + assign_rec( + deref_lhs, + name(ssa_objectt(symbolic_deref_rhs, ns), OUT, loc), + true_exprt(), + loc); } } else From 5f5507290c0e7b711ebdf85b58bdd136770a6596 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 27 Oct 2017 10:00:27 +0200 Subject: [PATCH 124/322] Do not fail if symbolic dereference cannot be done. Instead, return the original (not dereferenced) expression. --- src/ssa/ssa_pointed_objects.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ssa/ssa_pointed_objects.cpp b/src/ssa/ssa_pointed_objects.cpp index ecb215cff..707812f11 100644 --- a/src/ssa/ssa_pointed_objects.cpp +++ b/src/ssa/ssa_pointed_objects.cpp @@ -375,7 +375,8 @@ const exprt symbolic_dereference(const exprt &expr, const namespacet &ns) const exprt &pointer=symbolic_dereference( to_dereference_expr(expr).pointer(), ns); const ssa_objectt pointer_object(pointer, ns); - assert(pointer_object); + if (!pointer_object) + return expr; symbol_exprt sym_deref=pointed_object(pointer_object.symbol_expr(), ns); sym_deref.set("#has_symbolic_deref", true); From fe0711ef1500b6cfa3623c3507e7a68c0f09cb3e Mon Sep 17 00:00:00 2001 From: Martin Hruska Date: Fri, 27 Oct 2017 16:37:38 +0200 Subject: [PATCH 125/322] Addressing cases where a pointer has (not) been redefined before its dereference appears on the right handed side. Also fixing assignments of right-handed side from a wrong SSA line --- src/ssa/assignments.cpp | 6 +++++- src/ssa/local_ssa.cpp | 30 +++++++++++++++++++++--------- src/ssa/ssa_domain.cpp | 16 ++++++++++++++++ 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index 0758f3085..c3d59aba7 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -44,7 +44,11 @@ void assignmentst::build_assignment_map( assign(lhs_symbolic_deref, it, ns); exprt rhs_symbolic_deref=symbolic_dereference(code_assign.rhs(), ns); - assign(rhs_symbolic_deref, it, ns); + if (has_symbolic_deref(rhs_symbolic_deref)) + { + rhs_symbolic_deref.set("#is_rhs_assign", true); + assign(rhs_symbolic_deref, it, ns); + } } else if(it->is_decl()) { diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 766a3ea18..116b81f04 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -461,15 +461,32 @@ void local_SSAt::build_transfer(locationt loc) exprt deref_lhs=dereference(code_assign.lhs(), loc); exprt deref_rhs=dereference(code_assign.rhs(), loc); + exprt rhs = deref_rhs; if(deref_lhs.get_bool("#heap_access") || deref_rhs.get_bool("#heap_access")) { exprt symbolic_deref_lhs=symbolic_dereference(code_assign.lhs(), ns); exprt symbolic_deref_rhs=symbolic_dereference(code_assign.rhs(), ns); - exprt rhs=deref_rhs.get_bool("#heap_access") && - all_symbolic_deref_defined(symbolic_deref_rhs, ns, loc) - ? symbolic_deref_rhs : deref_rhs; + if (deref_rhs.get_bool("#heap_access")) + { + const member_exprt &member=to_member_expr(symbolic_deref_rhs); + const exprt pointer=get_pointer(member.compound(), pointed_level(member.compound())-1); + const auto pointer_def = ssa_analysis[loc].def_map.find(ssa_objectt(pointer, ns).get_identifier())->second.def; + const auto symbolic_def = ssa_analysis[loc].def_map.find( + ssa_objectt(symbolic_deref_rhs, ns).get_identifier())->second.def; + + if (!symbolic_def.is_assignment() + || (pointer_def.is_assignment() && pointer_def.loc->location_number > symbolic_def.loc->location_number)) + { + assign_rec(symbolic_deref_rhs, deref_rhs, true_exprt(), loc); + rhs = name(ssa_objectt(symbolic_deref_rhs, ns), OUT, loc); + } + else + { + rhs = symbolic_deref_rhs; + } + } if(deref_lhs.get_bool("#heap_access") && has_symbolic_deref(symbolic_deref_lhs)) @@ -482,12 +499,7 @@ void local_SSAt::build_transfer(locationt loc) } else { - assign_rec(symbolic_deref_rhs, deref_rhs, true_exprt(), loc); - assign_rec( - deref_lhs, - name(ssa_objectt(symbolic_deref_rhs, ns), OUT, loc), - true_exprt(), - loc); + assign_rec(deref_lhs, rhs, true_exprt(), loc); } } else diff --git a/src/ssa/ssa_domain.cpp b/src/ssa/ssa_domain.cpp index a9848e8af..2295be5de 100644 --- a/src/ssa/ssa_domain.cpp +++ b/src/ssa/ssa_domain.cpp @@ -88,6 +88,22 @@ void ssa_domaint::transform( o_it!=assigns.end(); o_it++) { + if (o_it->get_expr().get_bool("#is_rhs_assign") && is_pointed(o_it->get_root_object())) + { // the second part excluded cases when a result of malloc is at the right-handed side + const auto object_ai_it = static_cast(ai)[from].def_map.find(o_it->get_identifier()); + if (object_ai_it != static_cast(ai)[from].def_map.end() + && object_ai_it->second.def.is_assignment()) + { + const exprt pointer=get_pointer(o_it->get_root_object(), pointed_level(o_it->get_root_object())-1); + const auto def_pointer = static_cast(ai)[from].def_map.find( + ssa_objectt(pointer, ns).get_identifier())->second.def; + if (!def_pointer.is_assignment() + || def_pointer.loc->location_number < object_ai_it->second.def.loc->location_number) + { + continue; + } + } + } irep_idt identifier=o_it->get_identifier(); def_entryt &def_entry=def_map[identifier]; From 41d8f2079e1ce0c9620a229e68b1fb51ac490469 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Sat, 28 Oct 2017 16:14:31 +0200 Subject: [PATCH 126/322] RHS concretisation: handle when the RHS is an object (and not a member of an object). --- src/ssa/local_ssa.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 116b81f04..54ab70eb0 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -468,10 +468,10 @@ void local_SSAt::build_transfer(locationt loc) exprt symbolic_deref_lhs=symbolic_dereference(code_assign.lhs(), ns); exprt symbolic_deref_rhs=symbolic_dereference(code_assign.rhs(), ns); - if (deref_rhs.get_bool("#heap_access")) + ssa_objectt rhs_object(symbolic_deref_rhs, ns); + if (deref_rhs.get_bool("#heap_access") && rhs_object) { - const member_exprt &member=to_member_expr(symbolic_deref_rhs); - const exprt pointer=get_pointer(member.compound(), pointed_level(member.compound())-1); + const exprt pointer=get_pointer(rhs_object.get_root_object(), pointed_level(rhs_object.get_root_object())-1); const auto pointer_def = ssa_analysis[loc].def_map.find(ssa_objectt(pointer, ns).get_identifier())->second.def; const auto symbolic_def = ssa_analysis[loc].def_map.find( ssa_objectt(symbolic_deref_rhs, ns).get_identifier())->second.def; From 16b0046c8ed6f162ebaa4dbfd6ff29b537e5776e Mon Sep 17 00:00:00 2001 From: Martin Hruska Date: Thu, 2 Nov 2017 10:15:06 +0100 Subject: [PATCH 127/322] concretisation also for assertion --- src/ssa/local_ssa.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 54ab70eb0..a833df7d0 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -733,7 +733,27 @@ void local_SSAt::build_assertions(locationt loc) const exprt deref_rhs=dereference(loc->guard, loc); collect_iterators_rhs(deref_rhs, loc); - exprt c=read_rhs(loc->guard, loc); + const exprt symbolic_deref_rhs=symbolic_dereference(loc->guard, ns); + exprt rhs=all_symbolic_deref_defined(symbolic_deref_rhs, ns, loc) + ? symbolic_deref_rhs : deref_rhs; + + ssa_objectt rhs_object(symbolic_deref_rhs, ns); + if (symbolic_deref_rhs.get_bool("#heap_access") && rhs_object) + { + const exprt pointer=get_pointer(rhs_object.get_root_object(), pointed_level(rhs_object.get_root_object())-1); + const auto pointer_def = ssa_analysis[loc].def_map.find(ssa_objectt(pointer, ns).get_identifier())->second.def; + const auto symbolic_def = ssa_analysis[loc].def_map.find( + ssa_objectt(symbolic_deref_rhs, ns).get_identifier())->second.def; + + if (!symbolic_def.is_assignment() + || (pointer_def.is_assignment() && pointer_def.loc->location_number > symbolic_def.loc->location_number)) + { + assign_rec(symbolic_deref_rhs, deref_rhs, true_exprt(), loc); + rhs = name(ssa_objectt(symbolic_deref_rhs, ns), OUT, loc); + } + } + + exprt c=read_rhs(rhs, loc); exprt g=guard_symbol(loc); (--nodes.end())->assertions.push_back(implies_exprt(g, c)); } From 514c4870480a4b70ea3807b6f8482ebe0c4fb1c3 Mon Sep 17 00:00:00 2001 From: Martin Hruska Date: Thu, 2 Nov 2017 12:21:18 +0100 Subject: [PATCH 128/322] refactoring concretisation of rhs to a function --- src/ssa/local_ssa.cpp | 92 +++++++++++++++++++++++-------------------- src/ssa/local_ssa.h | 5 +++ 2 files changed, 55 insertions(+), 42 deletions(-) diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index a833df7d0..a02c7d0d0 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -461,32 +461,11 @@ void local_SSAt::build_transfer(locationt loc) exprt deref_lhs=dereference(code_assign.lhs(), loc); exprt deref_rhs=dereference(code_assign.rhs(), loc); - exprt rhs = deref_rhs; if(deref_lhs.get_bool("#heap_access") || deref_rhs.get_bool("#heap_access")) { exprt symbolic_deref_lhs=symbolic_dereference(code_assign.lhs(), ns); - exprt symbolic_deref_rhs=symbolic_dereference(code_assign.rhs(), ns); - - ssa_objectt rhs_object(symbolic_deref_rhs, ns); - if (deref_rhs.get_bool("#heap_access") && rhs_object) - { - const exprt pointer=get_pointer(rhs_object.get_root_object(), pointed_level(rhs_object.get_root_object())-1); - const auto pointer_def = ssa_analysis[loc].def_map.find(ssa_objectt(pointer, ns).get_identifier())->second.def; - const auto symbolic_def = ssa_analysis[loc].def_map.find( - ssa_objectt(symbolic_deref_rhs, ns).get_identifier())->second.def; - - if (!symbolic_def.is_assignment() - || (pointer_def.is_assignment() && pointer_def.loc->location_number > symbolic_def.loc->location_number)) - { - assign_rec(symbolic_deref_rhs, deref_rhs, true_exprt(), loc); - rhs = name(ssa_objectt(symbolic_deref_rhs, ns), OUT, loc); - } - else - { - rhs = symbolic_deref_rhs; - } - } + const exprt rhs=concretise_symbolic_deref_rhs(code_assign.rhs(), ns, loc); if(deref_lhs.get_bool("#heap_access") && has_symbolic_deref(symbolic_deref_lhs)) @@ -733,26 +712,7 @@ void local_SSAt::build_assertions(locationt loc) const exprt deref_rhs=dereference(loc->guard, loc); collect_iterators_rhs(deref_rhs, loc); - const exprt symbolic_deref_rhs=symbolic_dereference(loc->guard, ns); - exprt rhs=all_symbolic_deref_defined(symbolic_deref_rhs, ns, loc) - ? symbolic_deref_rhs : deref_rhs; - - ssa_objectt rhs_object(symbolic_deref_rhs, ns); - if (symbolic_deref_rhs.get_bool("#heap_access") && rhs_object) - { - const exprt pointer=get_pointer(rhs_object.get_root_object(), pointed_level(rhs_object.get_root_object())-1); - const auto pointer_def = ssa_analysis[loc].def_map.find(ssa_objectt(pointer, ns).get_identifier())->second.def; - const auto symbolic_def = ssa_analysis[loc].def_map.find( - ssa_objectt(symbolic_deref_rhs, ns).get_identifier())->second.def; - - if (!symbolic_def.is_assignment() - || (pointer_def.is_assignment() && pointer_def.loc->location_number > symbolic_def.loc->location_number)) - { - assign_rec(symbolic_deref_rhs, deref_rhs, true_exprt(), loc); - rhs = name(ssa_objectt(symbolic_deref_rhs, ns), OUT, loc); - } - } - + const exprt rhs=concretise_symbolic_deref_rhs(loc->guard, ns, loc); exprt c=read_rhs(rhs, loc); exprt g=guard_symbol(loc); (--nodes.end())->assertions.push_back(implies_exprt(g, c)); @@ -2049,3 +2009,51 @@ bool local_SSAt::all_symbolic_deref_defined( return result; } + +/********************************************************************\ + +Function: local_SSAt::concretise_rhs + + Inputs: + + Outputs: + + Purpose: Concretise symbolic rhs and return resulting expr + +\*******************************************************************/ + +exprt local_SSAt::concretise_symbolic_deref_rhs( + const exprt &rhs, + const namespacet &ns, + const locationt loc) +{ + const exprt deref_rhs=dereference(rhs, loc); + const exprt symbolic_deref_rhs=symbolic_dereference(rhs, ns); + ssa_objectt rhs_object(symbolic_deref_rhs, ns); + if(symbolic_deref_rhs.get_bool("#heap_access") && rhs_object) + { + const exprt pointer=get_pointer( + rhs_object.get_root_object(), + pointed_level(rhs_object.get_root_object())-1); + const auto pointer_def=ssa_analysis[loc].def_map.find( + ssa_objectt(pointer, ns).get_identifier())->second.def; + const auto symbolic_def=ssa_analysis[loc].def_map.find( + ssa_objectt(symbolic_deref_rhs, ns).get_identifier())->second.def; + + if(!symbolic_def.is_assignment() + || (pointer_def.is_assignment() + && pointer_def.loc->location_number > symbolic_def.loc->location_number)) + { + assign_rec(symbolic_deref_rhs, deref_rhs, true_exprt(), loc); + return name(ssa_objectt(symbolic_deref_rhs, ns), OUT, loc); + } + else + { + return symbolic_deref_rhs; + } + } + + return (all_symbolic_deref_defined(symbolic_deref_rhs, ns, loc) && + !deref_rhs.get_bool("#heap_access")) + ? symbolic_deref_rhs : deref_rhs; +} \ No newline at end of file diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 0ebfb3945..1bed222ce 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -218,6 +218,11 @@ class local_SSAt const namespacet &ns, locationt loc) const; + exprt concretise_symbolic_deref_rhs( + const exprt &rhs, + const namespacet &ns, + const locationt loc); + const ssa_heap_analysist &heap_analysis; ssa_objectst ssa_objects; From 5c7c0d4df09f5097423a7af49b14d6726de81799 Mon Sep 17 00:00:00 2001 From: Martin Hruska Date: Thu, 2 Nov 2017 12:27:44 +0100 Subject: [PATCH 129/322] adding rhs (assertion) concretisation test case --- regression/heap/sll_rhs_concretisation/main.c | 28 +++++++++++++++++++ .../heap/sll_rhs_concretisation/test.desc | 6 ++++ src/ssa/local_ssa.cpp | 5 ++-- 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 regression/heap/sll_rhs_concretisation/main.c create mode 100644 regression/heap/sll_rhs_concretisation/test.desc diff --git a/regression/heap/sll_rhs_concretisation/main.c b/regression/heap/sll_rhs_concretisation/main.c new file mode 100644 index 000000000..bef846bbc --- /dev/null +++ b/regression/heap/sll_rhs_concretisation/main.c @@ -0,0 +1,28 @@ +#include +#include + +extern int __VERIFIER_nondet_int(void); + +struct list{ + struct list* next; +}; + +int main() +{ + struct list *p,*q; + p = malloc(sizeof(struct list)); + q = malloc(sizeof(struct list)); + + p->next = malloc(sizeof(struct list)); + q->next = malloc(sizeof(struct list)); + p = q; + + while(__VERIFIER_nondet_int) { + q = p->next; + q->next = malloc(sizeof(struct list)); + assert(q->next != NULL); + p = q; + } + + return 1; +} diff --git a/regression/heap/sll_rhs_concretisation/test.desc b/regression/heap/sll_rhs_concretisation/test.desc new file mode 100644 index 000000000..ed14b476a --- /dev/null +++ b/regression/heap/sll_rhs_concretisation/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap --inline --no-propagation +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index a02c7d0d0..3023ae1c2 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -2030,7 +2030,7 @@ exprt local_SSAt::concretise_symbolic_deref_rhs( const exprt deref_rhs=dereference(rhs, loc); const exprt symbolic_deref_rhs=symbolic_dereference(rhs, ns); ssa_objectt rhs_object(symbolic_deref_rhs, ns); - if(symbolic_deref_rhs.get_bool("#heap_access") && rhs_object) + if(deref_rhs.get_bool("#heap_access") && rhs_object) { const exprt pointer=get_pointer( rhs_object.get_root_object(), @@ -2053,7 +2053,6 @@ exprt local_SSAt::concretise_symbolic_deref_rhs( } } - return (all_symbolic_deref_defined(symbolic_deref_rhs, ns, loc) && - !deref_rhs.get_bool("#heap_access")) + return (all_symbolic_deref_defined(symbolic_deref_rhs, ns, loc)) ? symbolic_deref_rhs : deref_rhs; } \ No newline at end of file From b0b81b2bb65f5fccd204144827e045b0e4e53639 Mon Sep 17 00:00:00 2001 From: Martin Hruska Date: Thu, 2 Nov 2017 14:36:35 +0100 Subject: [PATCH 130/322] recursive concretisation of rhs --- src/ssa/local_ssa.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 3023ae1c2..706287495 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -2030,6 +2030,7 @@ exprt local_SSAt::concretise_symbolic_deref_rhs( const exprt deref_rhs=dereference(rhs, loc); const exprt symbolic_deref_rhs=symbolic_dereference(rhs, ns); ssa_objectt rhs_object(symbolic_deref_rhs, ns); + if(deref_rhs.get_bool("#heap_access") && rhs_object) { const exprt pointer=get_pointer( @@ -2052,7 +2053,12 @@ exprt local_SSAt::concretise_symbolic_deref_rhs( return symbolic_deref_rhs; } } + else + { + forall_operands(it, rhs) + concretise_symbolic_deref_rhs(*it, ns, loc); + } - return (all_symbolic_deref_defined(symbolic_deref_rhs, ns, loc)) - ? symbolic_deref_rhs : deref_rhs; + return all_symbolic_deref_defined(symbolic_deref_rhs, ns, loc) + ? symbolic_deref_rhs : deref_rhs; } \ No newline at end of file From 3b3b5d123870eff3c315fea57b82cb21e7858679 Mon Sep 17 00:00:00 2001 From: Martin Hruska Date: Thu, 2 Nov 2017 14:37:13 +0100 Subject: [PATCH 131/322] taking care about assertion in assigments --- src/ssa/assignments.cpp | 36 +++++++++++++++++++++++++ src/ssa/assignments.h | 5 ++++ src/ssa/local_ssa.cpp | 60 ++++++++++++++++++++--------------------- 3 files changed, 71 insertions(+), 30 deletions(-) diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index c3d59aba7..a00fcedbd 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -50,6 +50,10 @@ void assignmentst::build_assignment_map( assign(rhs_symbolic_deref, it, ns); } } + else if (it->is_assert()) + { + build_assertion(it->guard, it, ns); + } else if(it->is_decl()) { const code_declt &code_decl=to_code_decl(it->code); @@ -238,6 +242,38 @@ void assignmentst::assign( /*******************************************************************\ +Function: assignmentst::build_assertion + + Inputs: + + Outputs: + + Purpose: Adds to assignments dereferences from assertion + +\*******************************************************************/ + +void assignmentst::build_assertion( + const exprt &expr, + const locationt& loc, + const namespacet &ns) +{ + exprt rhs_symbolic_deref=symbolic_dereference(expr, ns); + ssa_objectt rhs_object(rhs_symbolic_deref, ns); + + if (has_symbolic_deref(rhs_symbolic_deref) && rhs_object) + { + rhs_symbolic_deref.set("#is_rhs_assign", true); + assign(rhs_symbolic_deref, loc, ns); + } + else if (has_symbolic_deref(rhs_symbolic_deref)) + { + forall_operands(it, expr) + build_assertion(*it, loc, ns); + } +} + +/*******************************************************************\ + Function: assignmentst::output Inputs: diff --git a/src/ssa/assignments.h b/src/ssa/assignments.h index 3694fb4fc..6ce88d37a 100644 --- a/src/ssa/assignments.h +++ b/src/ssa/assignments.h @@ -73,6 +73,11 @@ class assignmentst const ssa_objectt &lhs, locationt, const namespacet &ns); + + void build_assertion( + const exprt &expr, + const locationt& loc, + const namespacet &ns); }; #endif diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 706287495..b6a42cb35 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -2023,42 +2023,42 @@ Function: local_SSAt::concretise_rhs \*******************************************************************/ exprt local_SSAt::concretise_symbolic_deref_rhs( - const exprt &rhs, - const namespacet &ns, - const locationt loc) + const exprt &rhs, + const namespacet &ns, + const locationt loc) { - const exprt deref_rhs=dereference(rhs, loc); - const exprt symbolic_deref_rhs=symbolic_dereference(rhs, ns); - ssa_objectt rhs_object(symbolic_deref_rhs, ns); + const exprt deref_rhs=dereference(rhs, loc); + const exprt symbolic_deref_rhs=symbolic_dereference(rhs, ns); + ssa_objectt rhs_object(symbolic_deref_rhs, ns); - if(deref_rhs.get_bool("#heap_access") && rhs_object) + if(deref_rhs.get_bool("#heap_access") && rhs_object) + { + const exprt pointer=get_pointer( + rhs_object.get_root_object(), + pointed_level(rhs_object.get_root_object())-1); + const auto pointer_def=ssa_analysis[loc].def_map.find( + ssa_objectt(pointer, ns).get_identifier())->second.def; + const auto symbolic_def=ssa_analysis[loc].def_map.find( + ssa_objectt(symbolic_deref_rhs, ns).get_identifier())->second.def; + + if(!symbolic_def.is_assignment() + || (pointer_def.is_assignment() + && pointer_def.loc->location_number > symbolic_def.loc->location_number)) { - const exprt pointer=get_pointer( - rhs_object.get_root_object(), - pointed_level(rhs_object.get_root_object())-1); - const auto pointer_def=ssa_analysis[loc].def_map.find( - ssa_objectt(pointer, ns).get_identifier())->second.def; - const auto symbolic_def=ssa_analysis[loc].def_map.find( - ssa_objectt(symbolic_deref_rhs, ns).get_identifier())->second.def; - - if(!symbolic_def.is_assignment() - || (pointer_def.is_assignment() - && pointer_def.loc->location_number > symbolic_def.loc->location_number)) - { - assign_rec(symbolic_deref_rhs, deref_rhs, true_exprt(), loc); - return name(ssa_objectt(symbolic_deref_rhs, ns), OUT, loc); - } - else - { - return symbolic_deref_rhs; - } + assign_rec(symbolic_deref_rhs, deref_rhs, true_exprt(), loc); + return name(ssa_objectt(symbolic_deref_rhs, ns), OUT, loc); } else { - forall_operands(it, rhs) - concretise_symbolic_deref_rhs(*it, ns, loc); + return symbolic_deref_rhs; } + } + else + { + forall_operands(it, rhs) + concretise_symbolic_deref_rhs(*it, ns, loc); + } - return all_symbolic_deref_defined(symbolic_deref_rhs, ns, loc) - ? symbolic_deref_rhs : deref_rhs; + return all_symbolic_deref_defined(symbolic_deref_rhs, ns, loc) + ? symbolic_deref_rhs : deref_rhs; } \ No newline at end of file From 6e8cecedbcedcb84a85fb45f20ece823a81dbc3f Mon Sep 17 00:00:00 2001 From: Martin Hruska Date: Thu, 2 Nov 2017 17:00:08 +0100 Subject: [PATCH 132/322] making test case more difficult --- regression/heap/sll_rhs_concretisation/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/regression/heap/sll_rhs_concretisation/main.c b/regression/heap/sll_rhs_concretisation/main.c index bef846bbc..180ee9d30 100644 --- a/regression/heap/sll_rhs_concretisation/main.c +++ b/regression/heap/sll_rhs_concretisation/main.c @@ -18,11 +18,15 @@ int main() p = q; while(__VERIFIER_nondet_int) { + assert(p->next != NULL); q = p->next; + assert(q != NULL); q->next = malloc(sizeof(struct list)); + q->next->next = q; assert(q->next != NULL); p = q; + assert(p == q); } - return 1; + return 0; } From 0ecd4cc5879271a0c055e963ab33b8b33f11ba87 Mon Sep 17 00:00:00 2001 From: Martin Hruska Date: Thu, 2 Nov 2017 17:01:00 +0100 Subject: [PATCH 133/322] remember concretisation of rhs --- src/ssa/assignments.cpp | 12 ++++++------ src/ssa/assignments.h | 6 +++--- src/ssa/local_ssa.cpp | 21 ++++++++++++++------- src/ssa/local_ssa.h | 6 +++--- 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index a00fcedbd..b2840ab73 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -50,7 +50,7 @@ void assignmentst::build_assignment_map( assign(rhs_symbolic_deref, it, ns); } } - else if (it->is_assert()) + else if(it->is_assert()) { build_assertion(it->guard, it, ns); } @@ -253,19 +253,19 @@ Function: assignmentst::build_assertion \*******************************************************************/ void assignmentst::build_assertion( - const exprt &expr, - const locationt& loc, - const namespacet &ns) + const exprt &expr, + const locationt& loc, + const namespacet &ns) { exprt rhs_symbolic_deref=symbolic_dereference(expr, ns); ssa_objectt rhs_object(rhs_symbolic_deref, ns); - if (has_symbolic_deref(rhs_symbolic_deref) && rhs_object) + if(has_symbolic_deref(rhs_symbolic_deref) && rhs_object) { rhs_symbolic_deref.set("#is_rhs_assign", true); assign(rhs_symbolic_deref, loc, ns); } - else if (has_symbolic_deref(rhs_symbolic_deref)) + else if(has_symbolic_deref(rhs_symbolic_deref)) { forall_operands(it, expr) build_assertion(*it, loc, ns); diff --git a/src/ssa/assignments.h b/src/ssa/assignments.h index 6ce88d37a..4dd00f4ef 100644 --- a/src/ssa/assignments.h +++ b/src/ssa/assignments.h @@ -75,9 +75,9 @@ class assignmentst const namespacet &ns); void build_assertion( - const exprt &expr, - const locationt& loc, - const namespacet &ns); + const exprt &expr, + const locationt& loc, + const namespacet &ns); }; #endif diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index b6a42cb35..034e6cf4c 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -2034,16 +2034,19 @@ exprt local_SSAt::concretise_symbolic_deref_rhs( if(deref_rhs.get_bool("#heap_access") && rhs_object) { const exprt pointer=get_pointer( - rhs_object.get_root_object(), - pointed_level(rhs_object.get_root_object())-1); + rhs_object.get_root_object(), + pointed_level(rhs_object.get_root_object())-1); + const auto pointer_id=ssa_objectt(pointer, ns).get_identifier(); const auto pointer_def=ssa_analysis[loc].def_map.find( - ssa_objectt(pointer, ns).get_identifier())->second.def; + pointer_id)->second.def; + const auto symbolic_id=ssa_objectt(symbolic_deref_rhs, ns).get_identifier(); const auto symbolic_def=ssa_analysis[loc].def_map.find( - ssa_objectt(symbolic_deref_rhs, ns).get_identifier())->second.def; + symbolic_id)->second.def; if(!symbolic_def.is_assignment() || (pointer_def.is_assignment() - && pointer_def.loc->location_number > symbolic_def.loc->location_number)) + && pointer_def.loc->location_number> + symbolic_def.loc->location_number)) { assign_rec(symbolic_deref_rhs, deref_rhs, true_exprt(), loc); return name(ssa_objectt(symbolic_deref_rhs, ns), OUT, loc); @@ -2055,8 +2058,12 @@ exprt local_SSAt::concretise_symbolic_deref_rhs( } else { - forall_operands(it, rhs) - concretise_symbolic_deref_rhs(*it, ns, loc); + exprt rhs_copy=rhs; + Forall_operands(it, rhs_copy) + { + *it=concretise_symbolic_deref_rhs(*it, ns, loc); + } + return rhs_copy; } return all_symbolic_deref_defined(symbolic_deref_rhs, ns, loc) diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 1bed222ce..0a8c4b17d 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -219,9 +219,9 @@ class local_SSAt locationt loc) const; exprt concretise_symbolic_deref_rhs( - const exprt &rhs, - const namespacet &ns, - const locationt loc); + const exprt &rhs, + const namespacet &ns, + const locationt loc); const ssa_heap_analysist &heap_analysis; From ce27a7bc48ac1de3fc5f7820475663f7d693faf9 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 9 Nov 2017 08:18:23 +0100 Subject: [PATCH 134/322] k-induction: do not unwind if dynamic objects are present Since k-induction contains bug related to dynamic objects, we need to avoid generating heap invariants for unwindings larger than 0. --- src/2ls/2ls_parse_options.cpp | 23 ++++++++++++++++++--- src/2ls/2ls_parse_options.h | 1 + src/2ls/summary_checker_kind.cpp | 1 + src/domains/heap_domain.h | 5 +++++ src/domains/strategy_solver_heap_interval.h | 4 +++- src/ssa/malloc_ssa.cpp | 21 ++++++++++++++----- src/ssa/malloc_ssa.h | 2 +- 7 files changed, 47 insertions(+), 10 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 80a1387e5..2bd4bb75e 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -182,6 +182,11 @@ void twols_parse_optionst::get_command_line_options(optionst &options) else options.set_option("std-invariants", false); + if(cmdline.isset("no-propagation")) + options.set_option("constant-propagation", false); + else + options.set_option("constant-propagation", true); + // magic error label if(cmdline.isset("error-label")) options.set_option("error-label", cmdline.get_value("error-label")); @@ -319,7 +324,7 @@ void twols_parse_optionst::get_command_line_options(optionst &options) options.set_option("competition-mode", true); options.set_option("all-properties", false); options.set_option("inline", true); - options.set_option("give-up-invariants", "1"); + options.set_option("give-up-invariants", "2"); } // instrumentation / output @@ -531,6 +536,16 @@ int twols_parse_optionst::doit() status() << eom; } + // don't use k-induction with dynamic memory + if(options.get_bool_option("competition-mode") && + dynamic_memory_detected) + { + options.set_option("k-induction", false); + options.set_option("std-invariants", false); + options.set_option("incremental-bmc", false); + options.set_option("unwind", 0); + } + try { std::unique_ptr checker; @@ -1167,7 +1182,7 @@ bool twols_parse_optionst::process_goto_program( goto_model.goto_functions.compute_loop_numbers(); // Replace malloc - replace_malloc(goto_model, ""); + dynamic_memory_detected=replace_malloc(goto_model, ""); // remove loop heads from function entries remove_loops_in_entry(goto_model); @@ -1187,7 +1202,9 @@ bool twols_parse_optionst::process_goto_program( filter_assertions(goto_model); #endif - if(!cmdline.isset("no-propagation")) + if(options.get_bool_option("constant-propagation") && + !(options.get_bool_option("competition-mode") && + dynamic_memory_detected)) { status() << "Constant Propagation" << eom; propagate_constants(goto_model); diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index 52d866207..4b1a795f8 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -75,6 +75,7 @@ class twols_parse_optionst: ui_message_handlert ui_message_handler; bool recursion_detected; bool threads_detected; + bool dynamic_memory_detected; virtual void register_languages(); void get_command_line_options(optionst &options); diff --git a/src/2ls/summary_checker_kind.cpp b/src/2ls/summary_checker_kind.cpp index 3e8906773..0fe1c9110 100644 --- a/src/2ls/summary_checker_kind.cpp +++ b/src/2ls/summary_checker_kind.cpp @@ -6,6 +6,7 @@ Author: Peter Schrammel \*******************************************************************/ +#include #include "summary_checker_kind.h" /*******************************************************************\ diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index d5ebcf539..97b19a51c 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -244,6 +244,11 @@ class heap_domaint:public domaint exprt get_aux_bindings() const; exprt get_input_bindings() const; + bool empty() const + { + return templ.empty(); + } + protected: templatet templ; diff --git a/src/domains/strategy_solver_heap_interval.h b/src/domains/strategy_solver_heap_interval.h index 449fa7423..8005a821c 100644 --- a/src/domains/strategy_solver_heap_interval.h +++ b/src/domains/strategy_solver_heap_interval.h @@ -34,7 +34,9 @@ class strategy_solver_heap_intervalt:public strategy_solver_baset precondition, message_handler, template_generator), - interval_solver(heap_interval_domain.interval_domain, _solver, SSA.ns) {} + interval_solver(heap_interval_domain.interval_domain, _solver, SSA.ns) + { + } virtual bool iterate(invariantt &_inv) override; diff --git a/src/ssa/malloc_ssa.cpp b/src/ssa/malloc_ssa.cpp index 80f69de3c..f981e07ce 100644 --- a/src/ssa/malloc_ssa.cpp +++ b/src/ssa/malloc_ssa.cpp @@ -181,7 +181,7 @@ Function: replace_malloc_rec \*******************************************************************/ -static void replace_malloc_rec( +static bool replace_malloc_rec( exprt &expr, const std::string &suffix, symbol_tablet &symbol_table, @@ -198,11 +198,17 @@ static void replace_malloc_rec( to_side_effect_expr(expr), "$"+i2string(loc_number)+suffix, symbol_table); + return true; } else { + bool result=false; Forall_operands(it, expr) - replace_malloc_rec(*it, suffix, symbol_table, malloc_size, loc_number); + { + if (replace_malloc_rec(*it, suffix, symbol_table, malloc_size, loc_number)) + result=true; + } + return result; } } @@ -218,10 +224,11 @@ Function: replace_malloc \*******************************************************************/ -void replace_malloc( +bool replace_malloc( goto_modelt &goto_model, const std::string &suffix) { + bool result=false; Forall_goto_functions(f_it, goto_model.goto_functions) { exprt malloc_size=nil_exprt(); @@ -242,13 +249,17 @@ void replace_malloc( lhs_id=="__builtin_alloca::alloca_size") malloc_size=code_assign.rhs(); } - replace_malloc_rec( + if(replace_malloc_rec( code_assign.rhs(), suffix, goto_model.symbol_table, malloc_size, - i_it->location_number); + i_it->location_number)) + { + result=true; + } } } } + return result; } diff --git a/src/ssa/malloc_ssa.h b/src/ssa/malloc_ssa.h index 5ef4e5ed4..bd6c2ec5c 100644 --- a/src/ssa/malloc_ssa.h +++ b/src/ssa/malloc_ssa.h @@ -17,7 +17,7 @@ exprt malloc_ssa( const std::string &suffix, symbol_tablet &); -void replace_malloc( +bool replace_malloc( goto_modelt &goto_model, const std::string &suffix); From 9900ebf21bb74a63b58b0c5ec45def2a43d88c8e Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 14 Nov 2017 11:26:36 +0100 Subject: [PATCH 135/322] Heap domain: improve updating of rows. If the value row is not updated by the value obtained from the solver (it is already there), set it to nondeterministic since this could introduce unsoundness. --- src/domains/heap_domain.cpp | 14 ++++++++++---- src/ssa/assignments.cpp | 2 +- src/ssa/local_ssa.cpp | 32 +++++++++++++++++++++----------- src/ssa/malloc_ssa.cpp | 2 +- src/ssa/ssa_domain.cpp | 30 ++++++++++++++++++++---------- src/ssa/ssa_pointed_objects.cpp | 2 +- 6 files changed, 54 insertions(+), 28 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 67effc3ad..46a535d70 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -601,8 +601,11 @@ Function: heap_domaint::stack_row_valuet::add_points_to bool heap_domaint::stack_row_valuet::add_points_to(const exprt &expr) { - auto new_pt=points_to.insert(expr); - return new_pt.second; + if(points_to.find(expr)==points_to.end()) + points_to.insert(expr); + else + nondet=true; + return true; } /*******************************************************************\ @@ -706,14 +709,17 @@ bool heap_domaint::heap_row_valuet::add_points_to(const exprt &dest) { if(dest==dyn_obj.first) { - return add_self_linkage(); + if(!add_self_linkage()) + nondet=true; } else { const dyn_objt through= self_linkage ? dyn_obj : std::make_pair(nil_exprt(), nil_exprt()); - return add_path(dest, through); + if(!add_path(dest, through)) + nondet=true; } + return true; } /*******************************************************************\ diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index b2840ab73..3894febf6 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -44,7 +44,7 @@ void assignmentst::build_assignment_map( assign(lhs_symbolic_deref, it, ns); exprt rhs_symbolic_deref=symbolic_dereference(code_assign.rhs(), ns); - if (has_symbolic_deref(rhs_symbolic_deref)) + if(has_symbolic_deref(rhs_symbolic_deref)) { rhs_symbolic_deref.set("#is_rhs_assign", true); assign(rhs_symbolic_deref, it, ns); diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 034e6cf4c..e0458c405 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -472,7 +472,8 @@ void local_SSAt::build_transfer(locationt loc) { assign_rec(symbolic_deref_lhs, rhs, true_exprt(), loc); assign_rec( - deref_lhs, name(ssa_objectt(symbolic_deref_lhs, ns), OUT, loc), + deref_lhs, + name(ssa_objectt(symbolic_deref_lhs, ns), OUT, loc), true_exprt(), loc); } @@ -1193,8 +1194,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==OBJECT_SELECT?"os":"")+ + (kind==PHI?"phi": + kind==LOOP_BACK?"lb": + kind==LOOP_SELECT?"ls": + kind==OBJECT_SELECT?"os":"")+ i2string(cnt)+ (kind==LOOP_SELECT?std::string(""):suffix); @@ -1433,11 +1436,17 @@ void local_SSAt::assign_rec( cond=and_exprt(cond, other_cond); } exprt new_rhs=if_exprt(cond, rhs, if_expr.true_case()); - assign_rec(if_expr.true_case(), new_rhs, and_exprt(guard, if_expr.cond()), - loc); - - assign_rec(if_expr.false_case(), rhs, - and_exprt(guard, not_exprt(if_expr.cond())), loc); + assign_rec( + if_expr.true_case(), + new_rhs, + and_exprt(guard, if_expr.cond()), + loc); + + assign_rec( + if_expr.false_case(), + rhs, + and_exprt(guard, not_exprt(if_expr.cond())), + loc); } else if(lhs.id()==ID_byte_extract_little_endian || lhs.id()==ID_byte_extract_big_endian) @@ -2066,6 +2075,7 @@ exprt local_SSAt::concretise_symbolic_deref_rhs( return rhs_copy; } - return all_symbolic_deref_defined(symbolic_deref_rhs, ns, loc) - ? symbolic_deref_rhs : deref_rhs; -} \ No newline at end of file + return + all_symbolic_deref_defined(symbolic_deref_rhs, ns, loc)? + symbolic_deref_rhs:deref_rhs; +} diff --git a/src/ssa/malloc_ssa.cpp b/src/ssa/malloc_ssa.cpp index f981e07ce..5dd19ae63 100644 --- a/src/ssa/malloc_ssa.cpp +++ b/src/ssa/malloc_ssa.cpp @@ -205,7 +205,7 @@ static bool replace_malloc_rec( bool result=false; Forall_operands(it, expr) { - if (replace_malloc_rec(*it, suffix, symbol_table, malloc_size, loc_number)) + if(replace_malloc_rec(*it, suffix, symbol_table, malloc_size, loc_number)) result=true; } return result; diff --git a/src/ssa/ssa_domain.cpp b/src/ssa/ssa_domain.cpp index 2295be5de..3e2d2bb65 100644 --- a/src/ssa/ssa_domain.cpp +++ b/src/ssa/ssa_domain.cpp @@ -88,17 +88,27 @@ void ssa_domaint::transform( o_it!=assigns.end(); o_it++) { - if (o_it->get_expr().get_bool("#is_rhs_assign") && is_pointed(o_it->get_root_object())) - { // the second part excluded cases when a result of malloc is at the right-handed side - const auto object_ai_it = static_cast(ai)[from].def_map.find(o_it->get_identifier()); - if (object_ai_it != static_cast(ai)[from].def_map.end() - && object_ai_it->second.def.is_assignment()) + if(o_it->get_expr().get_bool("#is_rhs_assign") && + is_pointed(o_it->get_root_object())) + { + // the second part excluded cases + // when a result of malloc is at the right-handed side + const auto object_ai_it= + static_cast(ai)[from].def_map.find(o_it->get_identifier()); + if(object_ai_it!=static_cast(ai)[from].def_map.end() && + object_ai_it->second.def.is_assignment()) { - const exprt pointer=get_pointer(o_it->get_root_object(), pointed_level(o_it->get_root_object())-1); - const auto def_pointer = static_cast(ai)[from].def_map.find( - ssa_objectt(pointer, ns).get_identifier())->second.def; - if (!def_pointer.is_assignment() - || def_pointer.loc->location_number < object_ai_it->second.def.loc->location_number) + const exprt pointer= + get_pointer( + o_it->get_root_object(), + pointed_level(o_it->get_root_object())-1); + const auto def_pointer= + static_cast(ai)[from] + .def_map.find( + ssa_objectt(pointer, ns).get_identifier())->second.def; + if(!def_pointer.is_assignment() || + def_pointer.loc->location_number< + object_ai_it->second.def.loc->location_number) { continue; } diff --git a/src/ssa/ssa_pointed_objects.cpp b/src/ssa/ssa_pointed_objects.cpp index 707812f11..bfcdaddee 100644 --- a/src/ssa/ssa_pointed_objects.cpp +++ b/src/ssa/ssa_pointed_objects.cpp @@ -375,7 +375,7 @@ const exprt symbolic_dereference(const exprt &expr, const namespacet &ns) const exprt &pointer=symbolic_dereference( to_dereference_expr(expr).pointer(), ns); const ssa_objectt pointer_object(pointer, ns); - if (!pointer_object) + if(!pointer_object) return expr; symbol_exprt sym_deref=pointed_object(pointer_object.symbol_expr(), ns); From d7fa36652af023e03c08330932a7cbbc34060d98 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sun, 19 Nov 2017 23:33:53 +0000 Subject: [PATCH 136/322] Deactivate goto-into-loop unwinding --- regression/invariants/gotoloop1/test.desc | 5 ++++- regression/invariants/gotoloop2/test.desc | 5 ++++- src/2ls/2ls_parse_options.cpp | 9 ++++++++- src/2ls/2ls_parse_options.h | 2 +- src/2ls/preprocessing_util.cpp | 6 +++++- 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/regression/invariants/gotoloop1/test.desc b/regression/invariants/gotoloop1/test.desc index daff41f71..dba2249f8 100644 --- a/regression/invariants/gotoloop1/test.desc +++ b/regression/invariants/gotoloop1/test.desc @@ -1,6 +1,9 @@ -CORE +KNOWNBUG main.c --unwind 1 ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ +-- +-- +feature deactivated diff --git a/regression/invariants/gotoloop2/test.desc b/regression/invariants/gotoloop2/test.desc index daff41f71..dba2249f8 100644 --- a/regression/invariants/gotoloop2/test.desc +++ b/regression/invariants/gotoloop2/test.desc @@ -1,6 +1,9 @@ -CORE +KNOWNBUG main.c --unwind 1 ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ +-- +-- +feature deactivated diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 2bd4bb75e..a41209c6f 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -55,7 +55,7 @@ Author: Daniel Kroening, Peter Schrammel #include "show.h" #include "horn_encoding.h" -#define UNWIND_GOTO_INTO_LOOP 1 +#define UNWIND_GOTO_INTO_LOOP 0 #define REMOVE_MULTIPLE_DEREFERENCES 1 #define IGNORE_RECURSION 1 #define IGNORE_THREADS 1 @@ -1139,6 +1139,13 @@ bool twols_parse_optionst::process_goto_program( #if UNWIND_GOTO_INTO_LOOP unwind_goto_into_loop(goto_model, 2); +#else + if(unwind_goto_into_loop(goto_model, 2)) + { + status() << "Irreducible control flow not supported" << eom; + report_unknown(); + return 5; + } #endif remove_skip(goto_model.goto_functions); diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index 4b1a795f8..d1008e193 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -158,7 +158,7 @@ class twols_parse_optionst: void inline_main(goto_modelt &goto_model); void propagate_constants(goto_modelt &goto_model); void nondet_locals(goto_modelt &goto_model); - void unwind_goto_into_loop(goto_modelt &goto_model, unsigned k); + bool unwind_goto_into_loop(goto_modelt &goto_model, unsigned k); void replace_types_rec(const replace_symbolt &replace_const, exprt &expr); exprt evaluate_casts_in_constants( const exprt &expr, diff --git a/src/2ls/preprocessing_util.cpp b/src/2ls/preprocessing_util.cpp index 753c0eb39..b31229afb 100644 --- a/src/2ls/preprocessing_util.cpp +++ b/src/2ls/preprocessing_util.cpp @@ -137,10 +137,11 @@ Function: twols_parse_optionst::unwind_goto_into_loop \*******************************************************************/ -void twols_parse_optionst::unwind_goto_into_loop( +bool twols_parse_optionst::unwind_goto_into_loop( goto_modelt &goto_model, unsigned k) { + bool result=false; typedef std::vector > loopst; @@ -170,6 +171,7 @@ void twols_parse_optionst::unwind_goto_into_loop( (*s_it)->location_numberlocation_number) { has_goto_into_loop=true; + result=true; break; } } @@ -204,6 +206,8 @@ void twols_parse_optionst::unwind_goto_into_loop( } goto_model.goto_functions.update(); goto_model.goto_functions.compute_loop_numbers(); + + return result; } /*******************************************************************\ From 6737dab70bcfbdca0c5fc30842b8a595df489b8b Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sun, 19 Nov 2017 23:46:40 +0000 Subject: [PATCH 137/322] Version 0.5.6 --- src/2ls/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/2ls/version.h b/src/2ls/version.h index 6be6c12db..87ebf03dc 100644 --- a/src/2ls/version.h +++ b/src/2ls/version.h @@ -9,6 +9,6 @@ Author: Peter Schrammel #ifndef CPROVER_2LS_2LS_VERSION_H #define CPROVER_2LS_2LS_VERSION_H -#define TWOLS_VERSION "0.5.5" +#define TWOLS_VERSION "0.5.6" #endif From 57def9d2af01e8e17d93a8141bad42527479c7a9 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Mon, 20 Nov 2017 21:59:28 +0000 Subject: [PATCH 138/322] Validate witnesses before reporting status --- src/2ls/2ls_parse_options.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index a41209c6f..44e2ed560 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -629,11 +629,33 @@ int twols_parse_optionst::doit() case property_checkert::FAIL: if(report_assertions) report_properties(options, goto_model, checker->property_map); - report_failure(); if(cmdline.isset("graphml-witness")) { +#if 1 + // validate witness + bool witness_valid=false; + for(const auto &p : checker->property_map) + { + if(p.second.result!=property_checkert::FAIL) + continue; + + witness_valid= + !p.second.error_trace.steps.empty() && + (options.get_bool_option("nontermination") || + p.second.error_trace.steps.back().is_assert()); + break; + } + if(!witness_valid) + { + retval=5; + error() << "Internal witness validation failed" << eom; + report_unknown(); + break; + } +#endif output_graphml_cex(options, goto_model, *checker); } + report_failure(); retval=10; break; From 3589104b2d09676acf6c9d66dc47823f7586bf75 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Wed, 22 Nov 2017 01:00:35 +0000 Subject: [PATCH 139/322] Update cbmc prerequisites --- src/2ls/graphml_witness_ext.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/2ls/graphml_witness_ext.cpp b/src/2ls/graphml_witness_ext.cpp index 11fa4bc3b..4ce2952a4 100644 --- a/src/2ls/graphml_witness_ext.cpp +++ b/src/2ls/graphml_witness_ext.cpp @@ -42,7 +42,6 @@ void graphml_witness_extt::operator()( // CFG to CFA const graphmlt::node_indext sink=graphml.add_node(); graphml[sink].node_name="sink"; - graphml[sink].thread_nr=0; graphml[sink].is_violation=false; graphml[sink].has_invariant=false; From 8b8635eaf98a6e986a78803b53e2d8bfe58b1c29 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 20 Nov 2017 14:17:34 +0100 Subject: [PATCH 140/322] Symbolic dereference: improve concretisation of objects on RHS. Use same principle for assignment RHS as for assertion. --- src/ssa/assignments.cpp | 15 +++++---------- src/ssa/assignments.h | 4 ++-- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index 3894febf6..556d0d037 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -43,16 +43,11 @@ void assignmentst::build_assignment_map( exprt lhs_symbolic_deref=symbolic_dereference(code_assign.lhs(), ns); assign(lhs_symbolic_deref, it, ns); - exprt rhs_symbolic_deref=symbolic_dereference(code_assign.rhs(), ns); - if(has_symbolic_deref(rhs_symbolic_deref)) - { - rhs_symbolic_deref.set("#is_rhs_assign", true); - assign(rhs_symbolic_deref, it, ns); - } + assign_symbolic_rhs(code_assign.rhs(), it, ns); } else if(it->is_assert()) { - build_assertion(it->guard, it, ns); + assign_symbolic_rhs(it->guard, it, ns); } else if(it->is_decl()) { @@ -252,9 +247,9 @@ Function: assignmentst::build_assertion \*******************************************************************/ -void assignmentst::build_assertion( +void assignmentst::assign_symbolic_rhs( const exprt &expr, - const locationt& loc, + const locationt &loc, const namespacet &ns) { exprt rhs_symbolic_deref=symbolic_dereference(expr, ns); @@ -268,7 +263,7 @@ void assignmentst::build_assertion( else if(has_symbolic_deref(rhs_symbolic_deref)) { forall_operands(it, expr) - build_assertion(*it, loc, ns); + assign_symbolic_rhs(*it, loc, ns); } } diff --git a/src/ssa/assignments.h b/src/ssa/assignments.h index 4dd00f4ef..f316e158f 100644 --- a/src/ssa/assignments.h +++ b/src/ssa/assignments.h @@ -74,9 +74,9 @@ class assignmentst locationt, const namespacet &ns); - void build_assertion( + void assign_symbolic_rhs( const exprt &expr, - const locationt& loc, + const locationt &loc, const namespacet &ns); }; From 72ffb14cee31e6a446855e1a2749d38657b38d13 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 20 Nov 2017 15:03:29 +0100 Subject: [PATCH 141/322] Temporary fix: do not dynamically add pointed objects. This is only needed for interprocedural analysis to ensure that everything points somewhere. It breaks some SV-COMP benchmarks. --- regression/heap/dll2_segments/test.desc | 2 +- src/ssa/ssa_value_set.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/regression/heap/dll2_segments/test.desc b/regression/heap/dll2_segments/test.desc index f4875431c..901c52dd3 100644 --- a/regression/heap/dll2_segments/test.desc +++ b/regression/heap/dll2_segments/test.desc @@ -1,4 +1,4 @@ -CORE +KNOWNBUG main.c --heap --context-sensitive --no-propagation ^EXIT=0$ diff --git a/src/ssa/ssa_value_set.cpp b/src/ssa/ssa_value_set.cpp index 4af078da2..91538ce28 100644 --- a/src/ssa/ssa_value_set.cpp +++ b/src/ssa/ssa_value_set.cpp @@ -256,7 +256,12 @@ void ssa_value_domaint::assign_lhs_rec( if(ssa_object) { + // TODO: this is required for interprocedural analysis, + // but interferes with intraprocedural analysis +#if 0 assign_pointed_rhs_rec(rhs, ns); +#endif + valuest tmp_values; assign_rhs_rec(tmp_values, rhs, ns, false, 0); From 75f98d396e85121c2054118ab1fba4c22b40c31f Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Tue, 21 Nov 2017 22:28:13 +0000 Subject: [PATCH 142/322] Adding missing initialisation --- src/2ls/2ls_parse_options.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 44e2ed560..25a42a8ef 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -79,7 +79,8 @@ twols_parse_optionst::twols_parse_optionst(int argc, const char **argv): language_uit(cmdline, ui_message_handler), ui_message_handler(cmdline, "2LS " TWOLS_VERSION), recursion_detected(false), - threads_detected(false) + threads_detected(false), + dynamic_memory_detected(false) { } From 1e94ab144e649959e7a782dc4ed85a031d86527a Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Wed, 22 Nov 2017 00:06:25 +0000 Subject: [PATCH 143/322] Termination analysis does not support linked lists --- src/2ls/2ls_parse_options.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 25a42a8ef..3a58f82e2 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -539,6 +539,7 @@ int twols_parse_optionst::doit() // don't use k-induction with dynamic memory if(options.get_bool_option("competition-mode") && + options.get_bool_option("k-induction") && dynamic_memory_detected) { options.set_option("k-induction", false); @@ -546,6 +547,17 @@ int twols_parse_optionst::doit() options.set_option("incremental-bmc", false); options.set_option("unwind", 0); } + // don't do nontermination with dynamic memory + if(options.get_bool_option("competition-mode") && + (options.get_bool_option("termination") || + options.get_bool_option("nontermination")) && + dynamic_memory_detected) + { + error() << "Termination analysis does not support " + << "dynamic memory allocation" << eom; + report_unknown(); + return 5; + } try { From b80716645dc4e4a0eb83e394829fb08a54c40fc2 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Wed, 22 Nov 2017 00:19:30 +0000 Subject: [PATCH 144/322] Restrict dynamic memory allocation detection to loops --- src/ssa/malloc_ssa.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/ssa/malloc_ssa.cpp b/src/ssa/malloc_ssa.cpp index 5dd19ae63..a3df38505 100644 --- a/src/ssa/malloc_ssa.cpp +++ b/src/ssa/malloc_ssa.cpp @@ -231,9 +231,26 @@ bool replace_malloc( bool result=false; Forall_goto_functions(f_it, goto_model.goto_functions) { + goto_programt::const_targett loop_end=f_it->second.body.instructions.end(); exprt malloc_size=nil_exprt(); Forall_goto_program_instructions(i_it, f_it->second.body) { + if(loop_end==f_it->second.body.instructions.end()) + { + for(const auto &incoming : i_it->incoming_edges) + { + if(incoming->is_backwards_goto() && + incoming!=i_it) + { + loop_end=incoming; + } + } + } + else if(i_it==loop_end) + { + loop_end=f_it->second.body.instructions.end(); + } + if(i_it->is_assign()) { code_assignt &code_assign=to_code_assign(i_it->code); @@ -256,7 +273,7 @@ bool replace_malloc( malloc_size, i_it->location_number)) { - result=true; + result=(loop_end!=f_it->second.body.instructions.end()); } } } From 97db31081c4f28ef20c337776b4f580f84e927e7 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Wed, 22 Nov 2017 00:59:22 +0000 Subject: [PATCH 145/322] Version 0.5.7 --- src/2ls/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/2ls/version.h b/src/2ls/version.h index 87ebf03dc..306cc43d6 100644 --- a/src/2ls/version.h +++ b/src/2ls/version.h @@ -9,6 +9,6 @@ Author: Peter Schrammel #ifndef CPROVER_2LS_2LS_VERSION_H #define CPROVER_2LS_2LS_VERSION_H -#define TWOLS_VERSION "0.5.6" +#define TWOLS_VERSION "0.5.7" #endif From a9b40b5d064b2f03b6be3ca2692897fe830cd73d Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Wed, 22 Nov 2017 23:11:02 +0000 Subject: [PATCH 146/322] Fix nontermination --trace option --- src/2ls/2ls_parse_options.cpp | 38 +++++++++++++++++------------ src/2ls/summary_checker_nonterm.cpp | 2 +- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 3a58f82e2..c966187b8 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -640,25 +640,31 @@ int twols_parse_optionst::doit() break; case property_checkert::FAIL: + { if(report_assertions) report_properties(options, goto_model, checker->property_map); + + // validate trace + bool trace_valid=false; + for(const auto &p : checker->property_map) + { + if(p.second.result!=property_checkert::FAIL) + continue; + + if(options.get_bool_option("trace")) + show_counterexample(goto_model, p.second.error_trace); + + trace_valid= + !p.second.error_trace.steps.empty() && + (options.get_bool_option("nontermination") || + p.second.error_trace.steps.back().is_assert()); + break; + } + if(cmdline.isset("graphml-witness")) { #if 1 - // validate witness - bool witness_valid=false; - for(const auto &p : checker->property_map) - { - if(p.second.result!=property_checkert::FAIL) - continue; - - witness_valid= - !p.second.error_trace.steps.empty() && - (options.get_bool_option("nontermination") || - p.second.error_trace.steps.back().is_assert()); - break; - } - if(!witness_valid) + if(!trace_valid) { retval=5; error() << "Internal witness validation failed" << eom; @@ -671,7 +677,7 @@ int twols_parse_optionst::doit() report_failure(); retval=10; break; - + } case property_checkert::UNKNOWN: if(report_assertions) report_properties(options, goto_model, checker->property_map); @@ -1360,7 +1366,7 @@ void twols_parse_optionst::report_properties( << eom; } - if(cmdline.isset("trace") && + if(options.get_bool_option("trace") && it->second.result==property_checkert::FAIL) show_counterexample(goto_model, it->second.error_trace); if(cmdline.isset("json-cex") && diff --git a/src/2ls/summary_checker_nonterm.cpp b/src/2ls/summary_checker_nonterm.cpp index 2819619ae..6160a97e4 100644 --- a/src/2ls/summary_checker_nonterm.cpp +++ b/src/2ls/summary_checker_nonterm.cpp @@ -131,7 +131,7 @@ void summary_checker_nontermt::check_properties( property_map, false, false, - options.get_bool_option("show-trace") || + options.get_bool_option("trace") || options.get_option("graphml-witness")!="" || options.get_option("json-cex")!=""); From 051d86a36583a6cb3e26741caf4db2051f60e1c9 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sat, 25 Nov 2017 14:36:37 +0000 Subject: [PATCH 147/322] Add object-bits dummy option --- src/2ls/2ls_parse_options.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index d1008e193..3dfb006b5 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -31,6 +31,7 @@ class optionst; "(non-incremental)" \ "(no-assertions)(no-assumptions)" \ "(16)(32)(64)(LP64)(ILP64)(LLP64)(ILP32)(LP32)" \ + "(object-bits):" \ "(little-endian)(big-endian)" \ "(error-label):(verbosity):(no-library)" \ "(version)" \ From ebba4617b39347aba1f5311589425e01e42b265f Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 24 Nov 2017 21:38:34 +0100 Subject: [PATCH 148/322] Improve calculation of size parameter for malloc. We call constant propagation to get the correct size even if the size parameter is a variable. --- src/ssa/malloc_ssa.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/ssa/malloc_ssa.cpp b/src/ssa/malloc_ssa.cpp index a3df38505..8c4a1003f 100644 --- a/src/ssa/malloc_ssa.cpp +++ b/src/ssa/malloc_ssa.cpp @@ -15,6 +15,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include #include "malloc_ssa.h" @@ -264,7 +265,19 @@ bool replace_malloc( id2string(to_symbol_expr(code_assign.lhs()).get_identifier()); if(lhs_id=="malloc::malloc_size" || lhs_id=="__builtin_alloca::alloca_size") - malloc_size=code_assign.rhs(); + { + namespacet ns(goto_model.symbol_table); + goto_functionst::goto_functiont function_copy=f_it->second; + constant_propagator_ait const_propagator(function_copy, ns); + forall_goto_program_instructions(copy_i_it, function_copy.body) + { + if(copy_i_it->location_number==i_it->location_number) + { + assert(copy_i_it->is_assign()); + malloc_size=to_code_assign(copy_i_it->code).rhs(); + } + } + } } if(replace_malloc_rec( code_assign.rhs(), From 6108ad34b1a07d5da0e43f2548667c97526a5c49 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 24 Nov 2017 22:06:27 +0100 Subject: [PATCH 149/322] Hack to disable programs containing pointer arithmetics. We add an assertion to ssa_value_set. This should be used for competition mode only. --- src/ssa/ssa_value_set.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/ssa/ssa_value_set.cpp b/src/ssa/ssa_value_set.cpp index 91538ce28..d8e6bffb0 100644 --- a/src/ssa/ssa_value_set.cpp +++ b/src/ssa/ssa_value_set.cpp @@ -7,6 +7,7 @@ Author: Daniel Kroening, kroening@kroening.com \*******************************************************************/ // #define DEBUG +#define COMPETITION #ifdef DEBUG #include @@ -366,6 +367,11 @@ void ssa_value_domaint::assign_rhs_rec( } else if(rhs.id()==ID_plus) { +#ifdef COMPETITION + bool pointer=false; + bool arithmetics=false; +#endif + forall_operands(it, rhs) { if(it->type().id()==ID_pointer) @@ -375,8 +381,22 @@ void ssa_value_domaint::assign_rhs_rec( pointer_offset=1; unsigned a=merge_alignment(integer2ulong(pointer_offset), alignment); assign_rhs_rec(dest, *it, ns, true, a); + +#ifdef COMPETITION + pointer=true; +#endif + } + else if(it->type().id()==ID_unsignedbv || it->type().id()==ID_signedbv) + { +#ifdef COMPETITION + arithmetics=true; +#endif } } + +#ifdef COMPETITION + assert(!(pointer && arithmetics)); +#endif } else if(rhs.id()==ID_minus) { @@ -388,6 +408,12 @@ void ssa_value_domaint::assign_rhs_rec( pointer_offset=1; unsigned a=merge_alignment(integer2ulong(pointer_offset), alignment); assign_rhs_rec(dest, rhs.op0(), ns, true, a); + +#ifdef COMPETITION + assert( + !(rhs.op1().type().id()==ID_unsignedbv || + rhs.op1().type().id()==ID_signedbv)); +#endif } } else if(rhs.id()==ID_dereference) From fd05fb4ccfee531ec8a153c9348066df35e85173 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sun, 26 Nov 2017 14:21:15 +0000 Subject: [PATCH 150/322] Hack to disable assertion hoisting for overflow-shl --- src/ssa/ssa_unwinder.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ssa/ssa_unwinder.cpp b/src/ssa/ssa_unwinder.cpp index 26ec5c232..fa372d597 100644 --- a/src/ssa/ssa_unwinder.cpp +++ b/src/ssa/ssa_unwinder.cpp @@ -7,6 +7,7 @@ Author: Peter Schrammel, Saurabh Joshi \*******************************************************************/ // #define DEBUG +#define COMPETITION #include @@ -472,7 +473,9 @@ void ssa_local_unwindert::add_assertions(loopt &loop, bool is_last) if(!is_last) // only add assumptions if we are not in %0 iteration { if(is_kinduction) + { node.constraints.push_back(*a_it); + } else if(is_bmc) { // only add in base case @@ -663,7 +666,11 @@ void ssa_local_unwindert::add_hoisted_assertions(loopt &loop, bool is_last) it!=loop.assertion_hoisting_map.end(); ++it) { if(!is_last // only add assumptions if we are not in %0 iteration - && is_kinduction && !it->second.assertions.empty()) + && is_kinduction && !it->second.assertions.empty() +#ifdef COMPETITION + && !(it->first->guard.id()==ID_not && + it->first->guard.op0().id()==ID_overflow_shl)) +#endif { exprt e=disjunction(it->second.exit_conditions); SSA.rename(e, loop.body_nodes.begin()->location); From 7c58b9c40a9026ac46b7d84d3648913fde14d3fd Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sun, 26 Nov 2017 14:28:26 +0000 Subject: [PATCH 151/322] Mark regression tests that require further attention --- regression/kiki/malloc2/test.desc | 5 ++++- regression/preconditions/precond4/test.desc | 5 ++++- regression/preconditions/precond5/test.desc | 5 ++++- regression/termination/equality_through_array3/test.desc | 5 ++++- regression/termination/pointer2/test.desc | 5 ++++- 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/regression/kiki/malloc2/test.desc b/regression/kiki/malloc2/test.desc index f1e0e7a98..f3b3afa29 100644 --- a/regression/kiki/malloc2/test.desc +++ b/regression/kiki/malloc2/test.desc @@ -1,6 +1,9 @@ -CORE +KNOWNBUG main.c --inline --havoc --unwind 5 ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ +-- +-- +Needs fix for 6108ad3 diff --git a/regression/preconditions/precond4/test.desc b/regression/preconditions/precond4/test.desc index 2f2eca914..3c1c8d834 100644 --- a/regression/preconditions/precond4/test.desc +++ b/regression/preconditions/precond4/test.desc @@ -1,6 +1,9 @@ -CORE +KNOWNBUG main.c --preconditions ^EXIT=5$ ^SIGNAL=0$ ^$ +-- +-- +Needs fix for 6108ad3 diff --git a/regression/preconditions/precond5/test.desc b/regression/preconditions/precond5/test.desc index 2f2eca914..3c1c8d834 100644 --- a/regression/preconditions/precond5/test.desc +++ b/regression/preconditions/precond5/test.desc @@ -1,6 +1,9 @@ -CORE +KNOWNBUG main.c --preconditions ^EXIT=5$ ^SIGNAL=0$ ^$ +-- +-- +Needs fix for 6108ad3 diff --git a/regression/termination/equality_through_array3/test.desc b/regression/termination/equality_through_array3/test.desc index 9efefbc73..462ea0673 100644 --- a/regression/termination/equality_through_array3/test.desc +++ b/regression/termination/equality_through_array3/test.desc @@ -1,4 +1,4 @@ -CORE +KNOWNBUG main.c ^EXIT=0$ @@ -6,3 +6,6 @@ main.c ^VERIFICATION SUCCESSFUL$ -- ^warning: ignoring +-- +-- +Needs fix for 6108ad3 diff --git a/regression/termination/pointer2/test.desc b/regression/termination/pointer2/test.desc index 9ebb38e34..96f2f993d 100644 --- a/regression/termination/pointer2/test.desc +++ b/regression/termination/pointer2/test.desc @@ -1,6 +1,9 @@ -CORE +KNOWNBUG main.c ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ +-- +-- +Needs fix for 6108ad3 From 32f6a9806ca38edd46509e7b9b48f670d4ef842e Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Mon, 27 Nov 2017 22:35:50 +0000 Subject: [PATCH 152/322] Version 0.6.0 --- src/2ls/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/2ls/version.h b/src/2ls/version.h index 306cc43d6..fb5db29f8 100644 --- a/src/2ls/version.h +++ b/src/2ls/version.h @@ -9,6 +9,6 @@ Author: Peter Schrammel #ifndef CPROVER_2LS_2LS_VERSION_H #define CPROVER_2LS_2LS_VERSION_H -#define TWOLS_VERSION "0.5.7" +#define TWOLS_VERSION "0.6.0" #endif From f3d2a90963fa708ad7cb937e49b84e8da337f0ea Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 23 Jan 2018 15:32:04 +0100 Subject: [PATCH 153/322] Pointed objects: do not create empty object Instead, when the object type is not supported, create new nondeterministic symbol. --- src/ssa/ssa_pointed_objects.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ssa/ssa_pointed_objects.cpp b/src/ssa/ssa_pointed_objects.cpp index bfcdaddee..b48671827 100644 --- a/src/ssa/ssa_pointed_objects.cpp +++ b/src/ssa/ssa_pointed_objects.cpp @@ -183,7 +183,7 @@ symbol_exprt pointed_object(const exprt &expr, const namespacet &ns) return pointed; } else - return symbol_exprt(""); + return symbol_exprt("ssa::nondet_symbol", expr.type().subtype()); } /*******************************************************************\ From c8842b863021c6970b49a093866e3a2b6db3c66d Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 8 Jan 2018 18:03:16 +0100 Subject: [PATCH 154/322] Improve heap domain by tracking symbolic execution paths Heap abstract value is now a disjunction of heap configurations, where each configuration corresponds to a path that was symbolically executed to obtain that configuration. A symbolic path is defined by evaluations of all loop-select guards in the program. --- src/domains/heap_domain.cpp | 459 +++++++++++++++------------ src/domains/heap_domain.h | 104 +++--- src/domains/strategy_solver_heap.cpp | 76 ++++- src/domains/strategy_solver_heap.h | 8 +- src/ssa/local_ssa.cpp | 1 + src/ssa/local_ssa.h | 4 + 6 files changed, 401 insertions(+), 251 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 46a535d70..ba2072c9c 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -29,16 +29,11 @@ void heap_domaint::initialize(domaint::valuet &value) for(const template_rowt &templ_row : templ) { - if(templ_row.mem_kind==STACK) - val.emplace_back(new stack_row_valuet()); - else if(templ_row.mem_kind==HEAP) - val.emplace_back( - new heap_row_valuet( - std::make_pair( - templ_row.dyn_obj, - templ_row.expr))); - else - assert(false); + dyn_objt dyn_obj= + templ_row.mem_kind==HEAP + ? std::make_pair(templ_row.dyn_obj, templ_row.expr) + : std::make_pair(nil_exprt(), nil_exprt()); + val.emplace_back(templ_row.mem_kind, dyn_obj); } } @@ -247,18 +242,21 @@ exprt heap_domaint::get_row_post_constraint( Function: heap_domaint::add_transitivity - Inputs: to Row to add new paths to + Inputs: sym_path Symbolic path + to Row to add new paths to from Row to add paths from dyn_obj Dynamic object that all the paths pass through (it belongs to path segment from one pointer to another). Outputs: True if any path was added or changed, otherwise false. - Purpose: Add all paths of one pointer as the destinations of another pointer. + Purpose: Add all paths of one pointer as the destinations of another pointer + in the given symbolic path. \*******************************************************************/ bool heap_domaint::add_transitivity( + const exprt &sym_path, const rowt &from, const rowt &to, heap_valuet &value) @@ -266,8 +264,8 @@ bool heap_domaint::add_transitivity( assert(from(value[from]); - heap_row_valuet &heap_val_to=static_cast(value[to]); + heap_row_configt &heap_val_from=value[from].get_heap_config(sym_path); + heap_row_configt &heap_val_to=value[to].get_heap_config(sym_path); bool result=false; if(heap_val_from.add_all_paths( @@ -293,10 +291,10 @@ Function: heap_domaint::add_points_to Outputs: - Purpose: Add new object pointed by a row. + Purpose: Add new object pointed by a row in the given symbolic path. Calls add_points_to of the given row. For stack rows, the destination is simply added into pointed - objects set. + objects set of the configuration corresponding to the symbolic path. For heap rows, a new path is added. \*******************************************************************/ @@ -304,10 +302,11 @@ Function: heap_domaint::add_points_to bool heap_domaint::add_points_to( const rowt &row, heap_valuet &value, + const exprt &sym_path, const exprt &dest) { assert(rowdyn_objects.empty()) - { - new_path=false; - break; - } - } - if(new_path) - { - pathsett new_path_set; - std::set dyn_obj_set; - if(dyn_obj.first.id()!=ID_nil) - { - dyn_obj_set.insert(dyn_obj); - } - if(self_linkage) - { - dyn_obj_set.insert(this->dyn_obj); - } - new_path_set.emplace(dest, dyn_obj_set); - paths.push_back(new_path_set); - } - return new_path; -} - -/*******************************************************************\ - -Function: heap_domaint::heap_row_valuet::add_path - - Inputs: dest Path destination - dyn_obj Dynamic object that the path goes through - path_set Path set to add the path to - - Outputs: True if the value was changed (a path was added) - - Purpose: Add new path to a path set - -\*******************************************************************/ - -bool heap_domaint::heap_row_valuet::add_path( - const exprt &dest, - const dyn_objt &dyn_obj, - pathsett &path_set) -{ - if(path_set.find(dest)==path_set.end()) + if(paths.find(dest)==paths.end()) { // Path does not exist yet std::set dyn_obj_set; @@ -802,7 +745,7 @@ bool heap_domaint::heap_row_valuet::add_path( { dyn_obj_set.insert(this->dyn_obj); } - path_set.emplace(dest, dyn_obj_set); + paths.emplace(dest, dyn_obj_set); return true; } else @@ -810,7 +753,7 @@ bool heap_domaint::heap_row_valuet::add_path( // Path exists already if(dyn_obj.first.id()!=ID_nil) // Try to insert new dynamic object on the path - return path_set.find(dest)->dyn_objects.insert(dyn_obj).second; + return paths.find(dest)->dyn_objects.insert(dyn_obj).second; else return false; } @@ -818,78 +761,30 @@ bool heap_domaint::heap_row_valuet::add_path( /*******************************************************************\ -Function: heap_domaint::heap_row_valuet::join_path_sets - - Inputs: src Source path set - dest Destination path set - - Outputs: True if the value was changed (dest was added) - - Purpose: Join two path sets. Add all paths from src to dest. - -\*******************************************************************/ - -bool heap_domaint::heap_row_valuet::join_path_sets( - pathsett &dest, - const pathsett &src, - const dyn_objt &through) -{ - bool result=false; - for(const patht &path : src) - { - if(add_path(path.destination, through, dest)) - result=true; - for(const dyn_objt &o : path.dyn_objects) - { // Add all dynamic objects of the original path - if(add_path(path.destination, o, dest)) - result=true; - } - } - return result; -} - -/*******************************************************************\ - -Function: heap_domaint::heap_row_valuet::add_all_paths +Function: heap_domaint::heap_row_configt::add_all_paths Inputs: Outputs: True if this has changed - Purpose: Add all paths from other heap row. + Purpose: Add all paths from other heap configuration. \*******************************************************************/ -bool heap_domaint::heap_row_valuet::add_all_paths( - const heap_row_valuet &other_val, +bool heap_domaint::heap_row_configt::add_all_paths( + const heap_row_configt &other_config, const dyn_objt &dyn_obj) { bool result=false; - - auto other_it=other_val.paths.begin(); - if(other_it!=other_val.paths.end()) + for(auto &path : other_config.paths) { - for(auto it=paths.begin(); it!=paths.end(); ++it) + if(add_path(path.destination, dyn_obj)) { - if(it->find(other_val.dyn_obj.first)!=it->end()) + result=true; + for(auto &o : path.dyn_objects) { - auto next_it=other_it; - ++next_it; - if(next_it!=other_val.paths.end()) - { // Duplicate element pointed by it - auto n_it=it; - ++n_it; - paths.insert(n_it, *it); - } - - // Add all paths to *it - - if(join_path_sets(*it, *other_it, dyn_obj)) + if(add_path(path.destination, o)) result=true; - - // Move other_it to next, or to first if next doesn't exist - other_it= - next_it==other_val.paths.end() ? other_val.paths.begin() : next_it; } } } @@ -898,7 +793,7 @@ bool heap_domaint::heap_row_valuet::add_all_paths( /*******************************************************************\ -Function: heap_domaint::heap_row_valuet::add_pointed_by +Function: heap_domaint::heap_row_configt::add_pointed_by Inputs: @@ -908,7 +803,7 @@ Function: heap_domaint::heap_row_valuet::add_pointed_by \*******************************************************************/ -bool heap_domaint::heap_row_valuet::add_pointed_by(const rowt &row) +bool heap_domaint::heap_row_configt::add_pointed_by(const rowt &row) { auto new_pb=pointed_by.insert(row); return new_pb.second; @@ -916,7 +811,7 @@ bool heap_domaint::heap_row_valuet::add_pointed_by(const rowt &row) /*******************************************************************\ -Function: heap_domaint::heap_row_valuet::add_self_linkage +Function: heap_domaint::heap_row_configt::add_self_linkage Inputs: @@ -926,19 +821,16 @@ Function: heap_domaint::heap_row_valuet::add_self_linkage \*******************************************************************/ -bool heap_domaint::heap_row_valuet::add_self_linkage() +bool heap_domaint::heap_row_configt::add_self_linkage() { bool result; result=!self_linkage; self_linkage=true; if(result) { - for(const pathsett &path_set : paths) + for(const patht &path : paths) { - for(const patht &path : path_set) - { - path.dyn_objects.insert(dyn_obj); - } + path.dyn_objects.insert(dyn_obj); } } return result; @@ -946,7 +838,7 @@ bool heap_domaint::heap_row_valuet::add_self_linkage() /*******************************************************************\ -Function: heap_domaint::heap_row_valuet::rename_outheap +Function: heap_domaint::heap_row_configt::rename_outheap Inputs: expr Expression to be renamed @@ -957,7 +849,7 @@ Function: heap_domaint::heap_row_valuet::rename_outheap \*******************************************************************/ -exprt heap_domaint::heap_row_valuet::rename_outheap(const symbol_exprt &expr) +exprt heap_domaint::heap_row_configt::rename_outheap(const symbol_exprt &expr) { const std::string id=id2string(expr.get_identifier()); return symbol_exprt( @@ -1524,10 +1416,181 @@ const std::set heap_domaint::collect_preconditions_rec( else { forall_operands(it, precondition) - { - std::set op_result=collect_preconditions_rec(expr, *it); - result.insert(op_result.begin(), op_result.end()); - } + { + std::set op_result=collect_preconditions_rec(expr, *it); + result.insert(op_result.begin(), op_result.end()); + } } return result; } + +/*******************************************************************\ + +Function: heap_domaint::row_valuet::empty + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ +bool heap_domaint::row_valuet::empty() const +{ + for(auto &config : configurations) + { + if(!config.second->empty()) + return false; + } + return true; +} + +/*******************************************************************\ + +Function: heap_domaint::row_valuet::set_nondet + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ +bool heap_domaint::row_valuet::set_nondet(const exprt &sym_path) +{ + bool result=!get_config(sym_path).nondet; + get_config(sym_path).nondet=true; + return result; +} + +/*******************************************************************\ + +Function: heap_domaint::row_valuet::add_points_to + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ +bool heap_domaint::row_valuet::add_points_to( + const exprt &sym_path, + const exprt &dest) +{ + return get_config(sym_path).add_points_to(dest); +} + +/*******************************************************************\ + +Function: heap_domaint::row_valuet::get_row_expr + + Inputs: + + Outputs: + + Purpose: Get expression corresponding to the template row. The expression is + a disjunction of configurations, where each configuration is + a conjunction of the guard and the configuration expression. + +\*******************************************************************/ +exprt heap_domaint::row_valuet::get_row_expr( + const exprt &templ_expr, + bool rename_templ_expr) const +{ + exprt::operandst result; + for(auto &config : configurations) + { + result.push_back( + and_exprt( + config.first, + config.second->get_row_config_expr(templ_expr, rename_templ_expr))); + } + return disjunction(result); +} + +/*******************************************************************\ + +Function: heap_domaint::row_valuet::is_nondet + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ +bool heap_domaint::row_valuet::is_nondet(const exprt &sym_path) +{ + return get_config(sym_path).nondet; +} + +/*******************************************************************\ + +Function: heap_domaint::row_valuet::get_config + + Inputs: + + Outputs: + + Purpose: Get configuration for the given symbolic path. If the configuration + does not exist, it is created. This (or one of the following two + functions shoulf be used for every access to a configuration). + +\*******************************************************************/ +heap_domaint::row_configt &heap_domaint::row_valuet::get_config( + const exprt &sym_path) +{ + if(configurations.find(sym_path)==configurations.end()) + { + if(mem_kind==STACK) + configurations.emplace(std::make_pair(sym_path, new stack_row_configt())); + else if(mem_kind==HEAP) + configurations.emplace( + std::make_pair( + sym_path, + new heap_row_configt(dyn_obj))); + else + assert(false); + } + return *(configurations.at(sym_path).get()); +} + +/*******************************************************************\ + +Function: heap_domaint::row_valuet::get_stack_config + + Inputs: + + Outputs: + + Purpose: Get configuration for the given symbolic path interpreted as + a stack configuration. + +\*******************************************************************/ +heap_domaint::stack_row_configt &heap_domaint::row_valuet::get_stack_config( + const exprt &sym_path) +{ + assert(mem_kind==STACK); + return static_cast(get_config(sym_path)); +} + +/*******************************************************************\ + +Function: heap_domaint::row_valuet::get_heap_config + + Inputs: + + Outputs: + + Purpose: Get configuration for the given symbolic path interpreted as + a heap configuration. + +\*******************************************************************/ +heap_domaint::heap_row_configt &heap_domaint::row_valuet::get_heap_config( + const exprt &sym_path) +{ + assert(mem_kind==HEAP); + return static_cast(get_config(sym_path)); +} + diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index 97b19a51c..f18340cff 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -53,32 +53,34 @@ class heap_domaint:public domaint typedef std::vector templatet; /*******************************************************************\ - Base class for a value of a row + Base class for a value of a memory configuration \*******************************************************************/ - struct row_valuet + struct row_configt { // Row is nondeterministic - row expression is TRUE bool nondet=false; - virtual exprt get_row_expr( + virtual exprt get_row_config_expr( const vart &templ_expr, bool rename_templ_expr) const=0; virtual bool empty() const=0; virtual bool add_points_to(const exprt &dest)=0; + + virtual ~row_configt() {} }; /*******************************************************************\ - Stack row - used for pointer-typed stack objects (variables). - Value is a set of objects that the pointer can point to. + Stack row configuration - used for pointer-typed stack objects (variables). + Configuration is a set of objects that the pointer can point to. \*******************************************************************/ - struct stack_row_valuet:public row_valuet + struct stack_row_configt:public row_configt { // Set of objects (or NULL) the row variable can point to std::set points_to; - virtual exprt get_row_expr( + virtual exprt get_row_config_expr( const vart &templ_expr, bool rename_templ_expr) const override; @@ -91,12 +93,12 @@ class heap_domaint:public domaint }; /*******************************************************************\ - Heap row - used for pointer-typed fields of dynamic objects. + Heap row configuration - used for pointer-typed fields of dynamic objects. - Value is a disjunction of conjunctions of paths leading from the dynamic - object via the field. + Configuration is a disjunction of conjunctions of paths leading from + the dynamic object via the field. \*******************************************************************/ - struct heap_row_valuet:public row_valuet + struct heap_row_configt:public row_configt { /*******************************************************************\ Path in a heap. Contains: @@ -127,10 +129,8 @@ class heap_domaint:public domaint }; // Set of paths interpreted as a conjunction of paths - typedef std::set pathsett; + std::set paths; - // Set of pathsets interpreted as a disjnuction of pathsets - std::list paths; // Set of rows whose variables point to this row std::set pointed_by; @@ -139,9 +139,9 @@ class heap_domaint:public domaint // Self link on an abstract dynamic object bool self_linkage=false; - explicit heap_row_valuet(const dyn_objt &dyn_obj_):dyn_obj(dyn_obj_) {} + explicit heap_row_configt(const dyn_objt &dyn_obj_):dyn_obj(dyn_obj_) {} - virtual exprt get_row_expr( + virtual exprt get_row_config_expr( const vart &templ_expr_, bool rename_templ_expr) const override; @@ -154,18 +154,8 @@ class heap_domaint:public domaint bool add_path(const exprt &dest, const dyn_objt &dyn_obj); - bool add_path( - const exprt &dest, - const dyn_objt &dyn_obj, - pathsett &path_set); - - bool join_path_sets( - pathsett &dest, - const pathsett &src, - const dyn_objt &through); - bool add_all_paths( - const heap_row_valuet &other_val, + const heap_row_configt &other_config, const dyn_objt &dyn_obj); bool add_pointed_by(const rowt &row); @@ -176,15 +166,46 @@ class heap_domaint:public domaint static exprt rename_outheap(const symbol_exprt &expr); }; + /*******************************************************************\ + Row value is a disjunction of configurations. + \*******************************************************************/ + struct row_valuet + { + mem_kindt mem_kind; + dyn_objt dyn_obj; + + // Each configuration belongs to a specific symbolic path in program whose + // execution lead to the given configuration. + // Path is a conjunction of guards - hence an expression + std::map> configurations; + + row_valuet(const mem_kindt &mem_kind, const dyn_objt &dyn_obj): + mem_kind(mem_kind), dyn_obj(dyn_obj) {} + + // Allow move constructor only + row_valuet(const row_valuet &)=delete; + row_valuet(row_valuet &&)=default; + + row_configt &get_config(const exprt &sym_path); + stack_row_configt &get_stack_config(const exprt &sym_path); + heap_row_configt &get_heap_config(const exprt &sym_path); + + // Row manipulation functions + bool add_points_to(const exprt &sym_path, const exprt &dest); + bool set_nondet(const exprt &sym_path); + + // Row status functions + bool empty() const; + bool is_nondet(const exprt &sym_path); + + exprt get_row_expr(const exprt &templ_expr, bool rename_templ_expr) const; + }; + + // Heap value is a conjunction of rows class heap_valuet: public valuet, - public std::vector> + public std::vector { - public: - row_valuet &operator[](const rowt &row) const - { - return *(this->at(row).get()); - } }; // Initialize value and domain @@ -211,11 +232,22 @@ class heap_domaint:public domaint exprt get_row_post_constraint(const rowt &row, const row_valuet &row_value); // Row modifications - bool add_transitivity(const rowt &from, const rowt &to, heap_valuet &value); + bool add_transitivity( + const exprt &sym_path, + const rowt &from, + const rowt &to, + heap_valuet &value); - bool add_points_to(const rowt &row, heap_valuet &value, const exprt &dest); + bool add_points_to( + const rowt &row, + heap_valuet &value, + const exprt &sym_path, + const exprt &dest); - bool set_nondet(const rowt &row, heap_valuet &value); + bool set_nondet( + const rowt &row, + heap_valuet &value, + const exprt &sym_path); // Printing virtual void output_value( diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index caa9b3922..d8645a13d 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -122,16 +122,20 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) // Value from the solver must be converted into an expression exprt ptr_value=heap_domain.value_to_ptr_exprt(value); + exprt sym_path=get_symbolic_path(row); + debug() << "Symbolic path: " << from_expr(ns, "", sym_path) << eom; + if((ptr_value.id()==ID_constant && to_constant_expr(ptr_value).get_value()==ID_NULL) || ptr_value.id()==ID_symbol) { // Add equality p == NULL or p == symbol - if(heap_domain.add_points_to(row, inv, ptr_value)) + if(heap_domain.add_points_to(row, inv, sym_path, ptr_value)) { improved=true; const std::string info= - templ_row.mem_kind==heap_domaint::STACK?"points to ":"path to "; + templ_row.mem_kind==heap_domaint::STACK ? "points to " + : "path to "; debug() << "Add " << info << from_expr(ns, "", ptr_value) << eom; } } @@ -144,7 +148,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) { // If solver did not return address of a symbol, it is considered // as nondet value. - if(heap_domain.set_nondet(row, inv)) + if(heap_domain.set_nondet(row, inv, sym_path)) { improved=true; debug() << "Set nondet" << eom; @@ -159,7 +163,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) ns.follow(templ_row.expr.type().subtype())!=ns.follow(obj.type())) { // If types disagree, it's a nondet (solver assigned random value) - if(heap_domain.set_nondet(row, inv)) + if(heap_domain.set_nondet(row, inv, sym_path)) { improved=true; debug() << "Set nondet" << eom; @@ -168,11 +172,12 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) } // Add equality p == &obj - if(heap_domain.add_points_to(row, inv, obj)) + if(heap_domain.add_points_to(row, inv, sym_path, obj)) { improved=true; const std::string info= - templ_row.mem_kind==heap_domaint::STACK?"points to ":"path to "; + templ_row.mem_kind==heap_domaint::STACK ? "points to " + : "path to "; debug() << "Add " << info << from_expr(ns, "", obj) << eom; } @@ -192,10 +197,12 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) templ_row.member, actual_loc, templ_row.kind); - if(member_val_index>=0 && !inv[member_val_index].nondet) + if(member_val_index>=0 && + !inv[member_val_index].is_nondet(sym_path)) { // Add all paths from obj.next to p if(heap_domain.add_transitivity( + sym_path, row, static_cast(member_val_index), inv)) @@ -211,7 +218,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) } else { - if(heap_domain.set_nondet(row, inv)) + if(heap_domain.set_nondet(row, inv, sym_path)) { improved=true; debug() << "Set nondet" << eom; @@ -222,8 +229,8 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) if(templ_row.mem_kind==heap_domaint::HEAP) { updated_rows.clear(); - if(!inv[row].nondet) - update_rows_rec(row, inv); + if(!inv[row].is_nondet(sym_path)) + update_rows_rec(sym_path, row, inv); } } } @@ -329,11 +336,12 @@ Function: strategy_solver_heapt::update_rows_rec \*******************************************************************/ bool strategy_solver_heapt::update_rows_rec( + const exprt &sym_path, const heap_domaint::rowt &row, heap_domaint::heap_valuet &value) { - heap_domaint::heap_row_valuet &row_value= - static_cast(value[row]); + heap_domaint::heap_row_configt &row_value= + value[row].get_heap_config(sym_path); const heap_domaint::template_rowt &templ_row=heap_domain.templ[row]; updated_rows.insert(row); @@ -343,7 +351,7 @@ bool strategy_solver_heapt::update_rows_rec( if(heap_domain.templ[ptr].mem_kind==heap_domaint::HEAP && heap_domain.templ[ptr].member==templ_row.member) { - if(heap_domain.add_transitivity(ptr, row, value)) + if(heap_domain.add_transitivity(sym_path, ptr, row, value)) result=true; debug() << "recursively updating row: " << ptr << eom; @@ -352,7 +360,7 @@ bool strategy_solver_heapt::update_rows_rec( << from_expr(ns, "", templ_row.dyn_obj) << eom; // Recursive update is called for each row only once if(updated_rows.find(ptr)==updated_rows.end()) - result=update_rows_rec(ptr, value) || result; + result=update_rows_rec(sym_path, ptr, value) || result; } } return result; @@ -374,8 +382,7 @@ void strategy_solver_heapt::print_solver_expr(const exprt &expr) { debug() << from_expr(ns, "", expr) << ": " << from_expr(ns, "", solver.get(expr)) << eom; - forall_operands(it, expr) - print_solver_expr(*it); + forall_operands(it, expr)print_solver_expr(*it); } /*******************************************************************\ @@ -411,3 +418,40 @@ void strategy_solver_heapt::initialize( heap_domain.output_domain(debug(), ns); } } + +/*******************************************************************\ + +Function: strategy_solver_heapt::get_symbolic_path + + Inputs: + + Outputs: + + Purpose: Get symbolic path of a model returned by the solver. A symbolic path + is identified by evaluations of all loop guards, except the guard of + the loop correponding to the given template row. + +\*******************************************************************/ +const exprt strategy_solver_heapt::get_symbolic_path( + const heap_domaint::rowt &row) +{ + if(!heap_domain.templ[row].kind==domaint::LOOP) + return true_exprt(); + + exprt::operandst path; + const exprt &row_loop_guard= + to_and_expr(heap_domain.templ[row].pre_guard).op1(); + for(const exprt &guard : loop_guards) + { + if(guard==row_loop_guard) + continue; + + exprt guard_value=solver.get(guard); + assert(guard_value.is_true() || guard_value.is_false()); + if(guard_value.is_true()) + path.push_back(guard); + else + path.push_back(not_exprt(guard)); + } + return conjunction(path); +} diff --git a/src/domains/strategy_solver_heap.h b/src/domains/strategy_solver_heap.h index 51435396d..2f4c370e0 100644 --- a/src/domains/strategy_solver_heap.h +++ b/src/domains/strategy_solver_heap.h @@ -23,7 +23,9 @@ class strategy_solver_heapt:public strategy_solver_baset const exprt &precondition, message_handlert &message_handler, template_generator_baset &template_generator): - strategy_solver_baset(_solver, SSA.ns), heap_domain(_heap_domain) + strategy_solver_baset(_solver, SSA.ns), + heap_domain(_heap_domain), + loop_guards(SSA.loop_guards) { set_message_handler(message_handler); initialize(SSA, precondition, template_generator); @@ -38,6 +40,7 @@ class strategy_solver_heapt:public strategy_solver_baset protected: heap_domaint &heap_domain; + std::set loop_guards; std::set updated_rows; int find_member_row( @@ -47,9 +50,12 @@ class strategy_solver_heapt:public strategy_solver_baset const domaint::kindt &kind); bool update_rows_rec( + const exprt &sym_path, const heap_domaint::rowt &row, heap_domaint::heap_valuet &value); + const exprt get_symbolic_path(const heap_domaint::rowt &row); + void print_solver_expr(const exprt &expr); }; diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index e0458c405..0422ef8a9 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -390,6 +390,7 @@ void local_SSAt::build_phi_nodes(locationt loc) const locationt &iloc=get_location(incoming_it->first); exprt incoming_value=name(*o_it, LOOP_BACK, iloc); exprt incoming_select=name(guard_symbol(), LOOP_SELECT, iloc); + loop_guards.insert(to_symbol_expr(incoming_select)); if(rhs.is_nil()) // first rhs=incoming_value; diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 0a8c4b17d..cf33ead80 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -238,6 +238,10 @@ class local_SSAt ssa_ait ssa_analysis; std::string suffix; // an extra suffix + // Collect all loop_guards that will represent symbolic paths used in heap + // domain + var_sett loop_guards; + void get_globals( locationt loc, std::set &globals, From f0abdeefe9c929714f762ab8250fc40e97cab8e1 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 8 Jan 2018 18:09:41 +0100 Subject: [PATCH 155/322] Add test for the heap domain. These tests are now correctly handled thanks to tracking of symbolic paths in the heap domain. --- regression/heap/built_from_end/main.c | 39 +++++++++++++++++++++ regression/heap/built_from_end/test.desc | 6 ++++ regression/heap/simple_true/main.c | 44 ++++++++++++++++++++++++ regression/heap/simple_true/test.desc | 6 ++++ 4 files changed, 95 insertions(+) create mode 100644 regression/heap/built_from_end/main.c create mode 100644 regression/heap/built_from_end/test.desc create mode 100644 regression/heap/simple_true/main.c create mode 100644 regression/heap/simple_true/test.desc diff --git a/regression/heap/built_from_end/main.c b/regression/heap/built_from_end/main.c new file mode 100644 index 000000000..a25f56363 --- /dev/null +++ b/regression/heap/built_from_end/main.c @@ -0,0 +1,39 @@ +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +extern int __VERIFIER_nondet_int(); +/* + * Simple example: build a list with only 1s and finally a 0 (arbitrary length); + * afterwards, go through it and check if the list does have the correct form, and in particular + * finishes by a 0. + */ +#include + +void exit(int s) { + _EXIT: goto _EXIT; +} + +typedef struct node { + int h; + struct node *n; +} *List; + +int main() { + /* Build a list of the form 1->...->1->0 */ + List t; + List p = 0; + while (__VERIFIER_nondet_int()) { + t = (List) malloc(sizeof(struct node)); + if (t == 0) exit(1); + t->h = 1; + t->n = p; + p = t; + } + while (p!=0) { + if (p->h != 1) { + ERROR: __VERIFIER_error(); + } + p = p->n; + } + +} + diff --git a/regression/heap/built_from_end/test.desc b/regression/heap/built_from_end/test.desc new file mode 100644 index 000000000..6b6d935ce --- /dev/null +++ b/regression/heap/built_from_end/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-interval --inline --no-propagation +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/simple_true/main.c b/regression/heap/simple_true/main.c new file mode 100644 index 000000000..996941232 --- /dev/null +++ b/regression/heap/simple_true/main.c @@ -0,0 +1,44 @@ +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +extern int __VERIFIER_nondet_int(); +/* + * Simple example: build a list with only 1s and finally a 0 (arbitrary length); + * afterwards, go through it and check if the list does have the correct form, and in particular + * finishes by a 0. + */ +#include + +void exit(int s) { + _EXIT: goto _EXIT; +} + +typedef struct node { + int h; + struct node *n; +} *List; + +int main() { + /* Build a list of the form 1->...->1->0 */ + List a = (List) malloc(sizeof(struct node)); + if (a == 0) exit(1); + List t; + List p = a; + while (__VERIFIER_nondet_int()) { + p->h = 1; + t = (List) malloc(sizeof(struct node)); + if (t == 0) exit(1); + p->n = t; + p = p->n; + } + p->h = 1; + p->n = 0; + p = a; + while (p!=0) { + if (p->h != 1) { + ERROR: __VERIFIER_error(); + } + p = p->n; + } + return 0; +} + diff --git a/regression/heap/simple_true/test.desc b/regression/heap/simple_true/test.desc new file mode 100644 index 000000000..6b6d935ce --- /dev/null +++ b/regression/heap/simple_true/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-interval --inline --no-propagation +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ From 45d96c6d7891dd2cdf225b86064a997d7fd8a5c8 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 16 Jan 2018 13:31:46 +0100 Subject: [PATCH 156/322] Move the function for finding value of a symbolic path into strategy_solver_base --- src/domains/strategy_solver_base.cpp | 18 ++++++++ src/domains/strategy_solver_base.h | 7 +++ src/domains/strategy_solver_heap.cpp | 69 +++++++--------------------- src/domains/strategy_solver_heap.h | 3 -- 4 files changed, 42 insertions(+), 55 deletions(-) diff --git a/src/domains/strategy_solver_base.cpp b/src/domains/strategy_solver_base.cpp index edf2329ba..bac8d3a14 100644 --- a/src/domains/strategy_solver_base.cpp +++ b/src/domains/strategy_solver_base.cpp @@ -8,3 +8,21 @@ Author: Peter Schrammel #include "strategy_solver_base.h" +void strategy_solver_baset::find_symbolic_path( + std::set &loop_guards, + const exprt &filter_guard) +{ + exprt::operandst path; + for(const exprt &guard : loop_guards) + { + if(guard==filter_guard) + continue; + + exprt guard_value=solver.get(guard); + if(guard_value.is_true()) + path.push_back(guard); + else if(guard_value.is_false()) + path.push_back(not_exprt(guard)); + } + symbolic_path=conjunction(path); +} diff --git a/src/domains/strategy_solver_base.h b/src/domains/strategy_solver_base.h index 2e33c0946..c2d8f79e3 100644 --- a/src/domains/strategy_solver_base.h +++ b/src/domains/strategy_solver_base.h @@ -33,6 +33,7 @@ class strategy_solver_baset:public messaget inline unsigned get_number_of_solver_calls() { return solver_calls; } inline unsigned get_number_of_solver_instances() { return solver_instances; } + inline exprt &get_symbolic_path() { return symbolic_path; } protected: incremental_solvert &solver; @@ -42,9 +43,15 @@ class strategy_solver_baset:public messaget bvt strategy_cond_literals; exprt::operandst strategy_value_exprs; + exprt symbolic_path; + // statistics for additional solvers unsigned solver_instances; unsigned solver_calls; + + void find_symbolic_path( + std::set &loop_guards, + const exprt &filter_guard = nil_exprt()); }; #endif diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index d8645a13d..5f5e37ea1 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -9,6 +9,7 @@ Author: Viktor Malik // #define DEBUG_OUTPUT #include +#include #include "strategy_solver_heap.h" /*******************************************************************\ @@ -122,15 +123,17 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) // Value from the solver must be converted into an expression exprt ptr_value=heap_domain.value_to_ptr_exprt(value); - exprt sym_path=get_symbolic_path(row); - debug() << "Symbolic path: " << from_expr(ns, "", sym_path) << eom; + const exprt loop_guard=to_and_expr( + heap_domain.templ[row].pre_guard).op1(); + find_symbolic_path(loop_guards, loop_guard); + debug() << "Symbolic path: " << from_expr(ns, "", symbolic_path) << eom; if((ptr_value.id()==ID_constant && to_constant_expr(ptr_value).get_value()==ID_NULL) || ptr_value.id()==ID_symbol) { // Add equality p == NULL or p == symbol - if(heap_domain.add_points_to(row, inv, sym_path, ptr_value)) + if(heap_domain.add_points_to(row, inv, symbolic_path, ptr_value)) { improved=true; const std::string info= @@ -148,7 +151,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) { // If solver did not return address of a symbol, it is considered // as nondet value. - if(heap_domain.set_nondet(row, inv, sym_path)) + if(heap_domain.set_nondet(row, inv, symbolic_path)) { improved=true; debug() << "Set nondet" << eom; @@ -163,7 +166,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) ns.follow(templ_row.expr.type().subtype())!=ns.follow(obj.type())) { // If types disagree, it's a nondet (solver assigned random value) - if(heap_domain.set_nondet(row, inv, sym_path)) + if(heap_domain.set_nondet(row, inv, symbolic_path)) { improved=true; debug() << "Set nondet" << eom; @@ -172,7 +175,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) } // Add equality p == &obj - if(heap_domain.add_points_to(row, inv, sym_path, obj)) + if(heap_domain.add_points_to(row, inv, symbolic_path, obj)) { improved=true; const std::string info= @@ -198,11 +201,11 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) actual_loc, templ_row.kind); if(member_val_index>=0 && - !inv[member_val_index].is_nondet(sym_path)) + !inv[member_val_index].is_nondet(symbolic_path)) { // Add all paths from obj.next to p if(heap_domain.add_transitivity( - sym_path, + symbolic_path, row, static_cast(member_val_index), inv)) @@ -218,7 +221,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) } else { - if(heap_domain.set_nondet(row, inv, sym_path)) + if(heap_domain.set_nondet(row, inv, symbolic_path)) { improved=true; debug() << "Set nondet" << eom; @@ -229,8 +232,8 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) if(templ_row.mem_kind==heap_domaint::HEAP) { updated_rows.clear(); - if(!inv[row].is_nondet(sym_path)) - update_rows_rec(sym_path, row, inv); + if(!inv[row].is_nondet(symbolic_path)) + update_rows_rec(row, inv); } } } @@ -336,12 +339,11 @@ Function: strategy_solver_heapt::update_rows_rec \*******************************************************************/ bool strategy_solver_heapt::update_rows_rec( - const exprt &sym_path, const heap_domaint::rowt &row, heap_domaint::heap_valuet &value) { heap_domaint::heap_row_configt &row_value= - value[row].get_heap_config(sym_path); + value[row].get_heap_config(symbolic_path); const heap_domaint::template_rowt &templ_row=heap_domain.templ[row]; updated_rows.insert(row); @@ -351,7 +353,7 @@ bool strategy_solver_heapt::update_rows_rec( if(heap_domain.templ[ptr].mem_kind==heap_domaint::HEAP && heap_domain.templ[ptr].member==templ_row.member) { - if(heap_domain.add_transitivity(sym_path, ptr, row, value)) + if(heap_domain.add_transitivity(symbolic_path, ptr, row, value)) result=true; debug() << "recursively updating row: " << ptr << eom; @@ -360,7 +362,7 @@ bool strategy_solver_heapt::update_rows_rec( << from_expr(ns, "", templ_row.dyn_obj) << eom; // Recursive update is called for each row only once if(updated_rows.find(ptr)==updated_rows.end()) - result=update_rows_rec(sym_path, ptr, value) || result; + result=update_rows_rec(ptr, value) || result; } } return result; @@ -418,40 +420,3 @@ void strategy_solver_heapt::initialize( heap_domain.output_domain(debug(), ns); } } - -/*******************************************************************\ - -Function: strategy_solver_heapt::get_symbolic_path - - Inputs: - - Outputs: - - Purpose: Get symbolic path of a model returned by the solver. A symbolic path - is identified by evaluations of all loop guards, except the guard of - the loop correponding to the given template row. - -\*******************************************************************/ -const exprt strategy_solver_heapt::get_symbolic_path( - const heap_domaint::rowt &row) -{ - if(!heap_domain.templ[row].kind==domaint::LOOP) - return true_exprt(); - - exprt::operandst path; - const exprt &row_loop_guard= - to_and_expr(heap_domain.templ[row].pre_guard).op1(); - for(const exprt &guard : loop_guards) - { - if(guard==row_loop_guard) - continue; - - exprt guard_value=solver.get(guard); - assert(guard_value.is_true() || guard_value.is_false()); - if(guard_value.is_true()) - path.push_back(guard); - else - path.push_back(not_exprt(guard)); - } - return conjunction(path); -} diff --git a/src/domains/strategy_solver_heap.h b/src/domains/strategy_solver_heap.h index 2f4c370e0..4eb4b159a 100644 --- a/src/domains/strategy_solver_heap.h +++ b/src/domains/strategy_solver_heap.h @@ -50,12 +50,9 @@ class strategy_solver_heapt:public strategy_solver_baset const domaint::kindt &kind); bool update_rows_rec( - const exprt &sym_path, const heap_domaint::rowt &row, heap_domaint::heap_valuet &value); - const exprt get_symbolic_path(const heap_domaint::rowt &row); - void print_solver_expr(const exprt &expr); }; From 07a2206bcae7d88e033d6efdce609ff245598fd8 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 12 Feb 2018 08:33:36 +0100 Subject: [PATCH 157/322] Abstract domains: project_on_vars: if vars is empty, return whole abstract value Implement this in tpolyhedra and heap domains. --- src/domains/heap_domain.cpp | 2 +- src/domains/tpolyhedra_domain.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index ba2072c9c..fedd588e3 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -458,7 +458,7 @@ void heap_domaint::project_on_vars( { const template_rowt &templ_row=templ[row]; - if(vars.find(templ_row.expr)==vars.end()) + if(!vars.empty() && vars.find(templ_row.expr)==vars.end()) continue; const row_valuet &row_val=val[row]; diff --git a/src/domains/tpolyhedra_domain.cpp b/src/domains/tpolyhedra_domain.cpp index 55f8e5447..ea70494bb 100644 --- a/src/domains/tpolyhedra_domain.cpp +++ b/src/domains/tpolyhedra_domain.cpp @@ -661,7 +661,7 @@ void tpolyhedra_domaint::project_on_vars( bool pure=true; for(const auto &symbol : symbols) { - if(vars.find(symbol)==vars.end()) + if(!vars.empty() && vars.find(symbol)==vars.end()) { pure=false; break; From ab62de8262fc6c267bf00eee7122ffb8de581758 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 12 Feb 2018 08:37:52 +0100 Subject: [PATCH 158/322] Add concept of symbolic paths A symbolic path in a program is defined by conjunction of literals containing loop-select guards of all loops in the program. A symbolic path can be obtained from the solver during invariant inference. Each domain should implement possibility to restrict invariant computation to certain paths only. Support for symbolic paths implemented in tpolyhedra, heap, and heap-interval domains. --- src/domains/heap_domain.cpp | 156 +++++++-------------------- src/domains/heap_domain.h | 6 ++ src/domains/heap_interval_domain.cpp | 70 ++++++++++++ src/domains/heap_interval_domain.h | 6 ++ src/domains/strategy_solver_base.cpp | 29 +++-- src/domains/strategy_solver_base.h | 8 +- src/domains/symbolic_path.cpp | 42 ++++++++ src/domains/symbolic_path.h | 30 ++++++ src/domains/tpolyhedra_domain.cpp | 43 ++++++++ src/domains/tpolyhedra_domain.h | 6 ++ 10 files changed, 265 insertions(+), 131 deletions(-) create mode 100644 src/domains/symbolic_path.cpp create mode 100644 src/domains/symbolic_path.h diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index fedd588e3..0cc8e6d3f 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -1426,171 +1426,89 @@ const std::set heap_domaint::collect_preconditions_rec( /*******************************************************************\ -Function: heap_domaint::row_valuet::empty +Function: heap_domaint::restrict_to_sympath - Inputs: + Inputs: Symbolic path Outputs: - Purpose: + Purpose: Restrict template to a given symbolic path. + For each template row, we add all other loop guards in their + positive or negative form (as specified by path) to aux_expr. \*******************************************************************/ -bool heap_domaint::row_valuet::empty() const +void heap_domaint::restrict_to_sympath(const symbolic_patht &sympath) { - for(auto &config : configurations) + for(auto &row : templ) { - if(!config.second->empty()) - return false; + const exprt c=sympath.get_expr(row.pre_guard.op1()); + row.aux_expr=and_exprt(row.aux_expr, c); } - return true; } /*******************************************************************\ -Function: heap_domaint::row_valuet::set_nondet +Function: heap_domaint::clear_aux_symbols Inputs: Outputs: - Purpose: + Purpose: Reset aux symbols to true (remove all restricitions). \*******************************************************************/ -bool heap_domaint::row_valuet::set_nondet(const exprt &sym_path) +void heap_domaint::clear_aux_symbols() { - bool result=!get_config(sym_path).nondet; - get_config(sym_path).nondet=true; - return result; + for(auto &row : templ) + row.aux_expr=true_exprt(); } /*******************************************************************\ -Function: heap_domaint::row_valuet::add_points_to +Function: heap_domaint::eliminate_sympaths - Inputs: + Inputs: Vector of symbolic paths Outputs: - Purpose: + Purpose: Restrict template to other paths than those specified. \*******************************************************************/ -bool heap_domaint::row_valuet::add_points_to( - const exprt &sym_path, - const exprt &dest) +void heap_domaint::eliminate_sympaths( + const std::vector &sympaths) { - return get_config(sym_path).add_points_to(dest); -} - -/*******************************************************************\ - -Function: heap_domaint::row_valuet::get_row_expr - - Inputs: - - Outputs: - - Purpose: Get expression corresponding to the template row. The expression is - a disjunction of configurations, where each configuration is - a conjunction of the guard and the configuration expression. - -\*******************************************************************/ -exprt heap_domaint::row_valuet::get_row_expr( - const exprt &templ_expr, - bool rename_templ_expr) const -{ - exprt::operandst result; - for(auto &config : configurations) + for(auto &row : templ) { - result.push_back( - and_exprt( - config.first, - config.second->get_row_config_expr(templ_expr, rename_templ_expr))); + exprt::operandst paths; + for(auto &sympath : sympaths) + { + const exprt path_expr=sympath.get_expr(row.pre_guard.op1()); + paths.push_back(path_expr); + } + row.aux_expr=paths.empty() + ? true_exprt() + : static_cast(not_exprt(disjunction(paths))); } - return disjunction(result); -} - -/*******************************************************************\ - -Function: heap_domaint::row_valuet::is_nondet - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ -bool heap_domaint::row_valuet::is_nondet(const exprt &sym_path) -{ - return get_config(sym_path).nondet; } /*******************************************************************\ -Function: heap_domaint::row_valuet::get_config +Function: heap_domaint::undo_restriction Inputs: Outputs: - Purpose: Get configuration for the given symbolic path. If the configuration - does not exist, it is created. This (or one of the following two - functions shoulf be used for every access to a configuration). + Purpose: Undo last restriction (remove last conjunct from each aux_expr). \*******************************************************************/ -heap_domaint::row_configt &heap_domaint::row_valuet::get_config( - const exprt &sym_path) +void heap_domaint::undo_restriction() { - if(configurations.find(sym_path)==configurations.end()) + for(auto &row : templ) { - if(mem_kind==STACK) - configurations.emplace(std::make_pair(sym_path, new stack_row_configt())); - else if(mem_kind==HEAP) - configurations.emplace( - std::make_pair( - sym_path, - new heap_row_configt(dyn_obj))); - else - assert(false); + if(row.aux_expr.id()==ID_and) + { + row.aux_expr=to_and_expr(row.aux_expr).op0(); + } } - return *(configurations.at(sym_path).get()); } - -/*******************************************************************\ - -Function: heap_domaint::row_valuet::get_stack_config - - Inputs: - - Outputs: - - Purpose: Get configuration for the given symbolic path interpreted as - a stack configuration. - -\*******************************************************************/ -heap_domaint::stack_row_configt &heap_domaint::row_valuet::get_stack_config( - const exprt &sym_path) -{ - assert(mem_kind==STACK); - return static_cast(get_config(sym_path)); -} - -/*******************************************************************\ - -Function: heap_domaint::row_valuet::get_heap_config - - Inputs: - - Outputs: - - Purpose: Get configuration for the given symbolic path interpreted as - a heap configuration. - -\*******************************************************************/ -heap_domaint::heap_row_configt &heap_domaint::row_valuet::get_heap_config( - const exprt &sym_path) -{ - assert(mem_kind==HEAP); - return static_cast(get_config(sym_path)); -} - diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index f18340cff..de4133053 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -269,6 +269,12 @@ class heap_domaint:public domaint // Join of values virtual void join(valuet &value1, const valuet &value2) override; + // Restriction to symbolic paths + void restrict_to_sympath(const symbolic_patht &sympath); + void undo_restriction(); + void eliminate_sympaths(const std::vector &sympaths); + void clear_aux_symbols(); + // Getters for protected fields const std::list get_new_heap_vars(); diff --git a/src/domains/heap_interval_domain.cpp b/src/domains/heap_interval_domain.cpp index 95ca71fac..e38d89332 100644 --- a/src/domains/heap_interval_domain.cpp +++ b/src/domains/heap_interval_domain.cpp @@ -100,3 +100,73 @@ void heap_interval_domaint::project_on_vars( if(interval_result!=true_exprt()) result=and_exprt(result, interval_result); } + +/*******************************************************************\ + +Function: heap_interval_domaint::restrict_to_sympath + + Inputs: Symbolic path + + Outputs: + + Purpose: Restrict template to a given symbolic path. + +\*******************************************************************/ +void heap_interval_domaint::restrict_to_sympath( + const symbolic_patht &sympath) +{ + heap_domain.restrict_to_sympath(sympath); + interval_domain.restrict_to_sympath(sympath); +} + +/*******************************************************************\ + +Function: heap_interval_domaint::clear_aux_symbols + + Inputs: + + Outputs: + + Purpose: Reset aux symbols to true (remove all restricitions). + +\*******************************************************************/ +void heap_interval_domaint::clear_aux_symbols() +{ + heap_domain.clear_aux_symbols(); + interval_domain.clear_aux_symbols(); +} + +/*******************************************************************\ + +Function: heap_interval_domaint::eliminate_sympaths + + Inputs: Vector of symbolic paths + + Outputs: + + Purpose: Restrict template to other paths than those specified. + +\*******************************************************************/ +void heap_interval_domaint::eliminate_sympaths( + const std::vector &sympaths) +{ + heap_domain.eliminate_sympaths(sympaths); + interval_domain.eliminate_sympaths(sympaths); +} + +/*******************************************************************\ + +Function: heap_interval_domaint::undo_restriction + + Inputs: + + Outputs: + + Purpose: Undo last restriction. + +\*******************************************************************/ +void heap_interval_domaint::undo_restriction() +{ + heap_domain.undo_restriction(); + interval_domain.undo_restriction(); +} diff --git a/src/domains/heap_interval_domain.h b/src/domains/heap_interval_domain.h index 8699873e0..cf6179f6f 100644 --- a/src/domains/heap_interval_domain.h +++ b/src/domains/heap_interval_domain.h @@ -53,6 +53,12 @@ class heap_interval_domaint:public domaint valuet &value, const var_sett &vars, exprt &result) override; + + // Restriction to symbolic paths + void restrict_to_sympath(const symbolic_patht &sympath); + void undo_restriction(); + void eliminate_sympaths(const std::vector &sympaths); + void clear_aux_symbols(); }; #endif // CPROVER_2LS_DOMAINS_HEAP_INTERVAL_DOMAIN_H diff --git a/src/domains/strategy_solver_base.cpp b/src/domains/strategy_solver_base.cpp index bac8d3a14..f82dbb7e8 100644 --- a/src/domains/strategy_solver_base.cpp +++ b/src/domains/strategy_solver_base.cpp @@ -8,21 +8,34 @@ Author: Peter Schrammel #include "strategy_solver_base.h" +/*******************************************************************\ + +Function: strategy_solver_baset::find_symbolic_path + + Inputs: + + Outputs: + + Purpose: Find symbolic path that is explored by the current solver + iteration. A path is specified by a conjunction of literals + containing loop-select guards of all loops in program. + +\*******************************************************************/ void strategy_solver_baset::find_symbolic_path( std::set &loop_guards, - const exprt &filter_guard) + const exprt ¤t_guard) { - exprt::operandst path; - for(const exprt &guard : loop_guards) + for(const symbol_exprt &guard : loop_guards) { - if(guard==filter_guard) + if(guard==current_guard) + { + symbolic_path[guard]=true; continue; - + } exprt guard_value=solver.get(guard); if(guard_value.is_true()) - path.push_back(guard); + symbolic_path[guard]=true; else if(guard_value.is_false()) - path.push_back(not_exprt(guard)); + symbolic_path[guard]=false; } - symbolic_path=conjunction(path); } diff --git a/src/domains/strategy_solver_base.h b/src/domains/strategy_solver_base.h index c2d8f79e3..375e8a19b 100644 --- a/src/domains/strategy_solver_base.h +++ b/src/domains/strategy_solver_base.h @@ -12,6 +12,7 @@ Author: Peter Schrammel #include "domain.h" #include "incremental_solver.h" #include "util.h" +#include "symbolic_path.h" class strategy_solver_baset:public messaget { @@ -33,7 +34,8 @@ class strategy_solver_baset:public messaget inline unsigned get_number_of_solver_calls() { return solver_calls; } inline unsigned get_number_of_solver_instances() { return solver_instances; } - inline exprt &get_symbolic_path() { return symbolic_path; } + + symbolic_patht symbolic_path; protected: incremental_solvert &solver; @@ -43,15 +45,13 @@ class strategy_solver_baset:public messaget bvt strategy_cond_literals; exprt::operandst strategy_value_exprs; - exprt symbolic_path; - // statistics for additional solvers unsigned solver_instances; unsigned solver_calls; void find_symbolic_path( std::set &loop_guards, - const exprt &filter_guard = nil_exprt()); + const exprt ¤t_guard=nil_exprt()); }; #endif diff --git a/src/domains/symbolic_path.cpp b/src/domains/symbolic_path.cpp new file mode 100644 index 000000000..858c7cf3d --- /dev/null +++ b/src/domains/symbolic_path.cpp @@ -0,0 +1,42 @@ +/*******************************************************************\ + +Module: Symbolic path in a program + +Author: Viktor Malik + +\*******************************************************************/ + + +#include "symbolic_path.h" + +/*******************************************************************\ + +Function: symbolic_patht::get_expr + + Inputs: + + Outputs: + + Purpose: Get expression correcponding to the path. There is an option + not to include selected loop guard (this is useful when + analysing that loop). + +\*******************************************************************/ +const exprt symbolic_patht::get_expr( + const exprt &except_guard, + bool except_true_only) const +{ + exprt::operandst path; + for(const auto &guard : path_map) + { + if(except_guard.is_not_nil() && guard.first==except_guard && + (!except_true_only || guard.second)) + continue; + + if(guard.second) + path.push_back(guard.first); + else + path.push_back(not_exprt(guard.first)); + } + return path.empty() ? true_exprt() : conjunction(path); +} diff --git a/src/domains/symbolic_path.h b/src/domains/symbolic_path.h new file mode 100644 index 000000000..c00dbc742 --- /dev/null +++ b/src/domains/symbolic_path.h @@ -0,0 +1,30 @@ +/*******************************************************************\ + +Module: Symbolic path in a program + +Author: Viktor Malik + +\*******************************************************************/ + +#ifndef CPROVER_2LS_DOMAINS_SYMBOLIC_PATH_H +#define CPROVER_2LS_DOMAINS_SYMBOLIC_PATH_H + +#include +#include + +class symbolic_patht +{ +public: + std::map path_map; + + const exprt get_expr( + const exprt &except_guard=nil_exprt(), + bool except_true_only=false) const; + + bool &operator[](const exprt &expr) { return path_map[expr]; } + + void clear() { path_map.clear(); } +}; + + +#endif // CPROVER_2LS_DOMAINS_SYMBOLIC_PATH_H diff --git a/src/domains/tpolyhedra_domain.cpp b/src/domains/tpolyhedra_domain.cpp index ea70494bb..1c6e1be44 100644 --- a/src/domains/tpolyhedra_domain.cpp +++ b/src/domains/tpolyhedra_domain.cpp @@ -1168,3 +1168,46 @@ void tpolyhedra_domaint::add_sum_template( } } } + +void tpolyhedra_domaint::restrict_to_sympath(const symbolic_patht &sympath) +{ + for(auto &row : templ) + { + const exprt c=sympath.get_expr(row.pre_guard.op1()); + row.aux_expr=and_exprt(row.aux_expr, c); + } +} + +void tpolyhedra_domaint::clear_aux_symbols() +{ + for(auto &row : templ) + row.aux_expr=true_exprt(); +} + +void tpolyhedra_domaint::undo_restriction() +{ + for(auto &row : templ) + { + if(row.aux_expr.id()==ID_and) + { + row.aux_expr=to_and_expr(row.aux_expr).op0(); + } + } +} + +void tpolyhedra_domaint::eliminate_sympaths( + const std::vector &sympaths) +{ + for(auto &row : templ) + { + exprt::operandst paths; + for(const symbolic_patht &sympath : sympaths) + { + const exprt path_expr=sympath.get_expr(row.pre_guard.op1()); + paths.push_back(path_expr); + } + row.aux_expr=paths.empty() + ? true_exprt() + : static_cast(not_exprt(disjunction(paths))); + } +} diff --git a/src/domains/tpolyhedra_domain.h b/src/domains/tpolyhedra_domain.h index 0e178c1e8..42ca064c1 100644 --- a/src/domains/tpolyhedra_domain.h +++ b/src/domains/tpolyhedra_domain.h @@ -16,6 +16,7 @@ Author: Peter Schrammel #include #include "domain.h" +#include "symbolic_path.h" class tpolyhedra_domaint:public domaint { @@ -134,6 +135,11 @@ class tpolyhedra_domaint:public domaint const var_specst &var_specs, const namespacet &ns); + void restrict_to_sympath(const symbolic_patht &sympath); + void undo_restriction(); + void eliminate_sympaths(const std::vector &sympaths); + void clear_aux_symbols(); + symbol_exprt get_row_symb_value(const rowt &row); void rename_for_row(exprt &expr, const rowt &row); From 8e084da113546ecbb1a693132c0b5282998e15e6 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 12 Feb 2018 08:42:09 +0100 Subject: [PATCH 159/322] Heap-interval domain: improve domain combination If heap part is improved, restrict the interval domain to the symbolic path found by the heap part. Also add the current state of the invariant of one part as a context to solving of the other part. --- src/domains/strategy_solver_heap_interval.cpp | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/domains/strategy_solver_heap_interval.cpp b/src/domains/strategy_solver_heap_interval.cpp index ba0f61650..1cc65c85c 100644 --- a/src/domains/strategy_solver_heap_interval.cpp +++ b/src/domains/strategy_solver_heap_interval.cpp @@ -16,9 +16,10 @@ Function: strategy_solver_heap_intervalt::iterate Outputs: - Purpose: Since template rows for the shape part and the interval part - are disjoint, we simply call iterate method for each part - separately + Purpose: Run iteration of each solver separately, but every time + in the context of the current invariant found by the other + solver. The interval solving is also restricted to + a symbolic path found by the heap solver. \*******************************************************************/ @@ -28,8 +29,30 @@ bool strategy_solver_heap_intervalt::iterate( heap_interval_domaint::heap_interval_valuet &inv= static_cast(_inv); + // Run one iteration of heap solver in the context of invariant from + // the interval solver + solver.new_context(); + solver << heap_interval_domain.interval_domain.to_pre_constraints( + inv.interval_value); bool heap_improved=heap_solver.iterate(inv.heap_value); + solver.pop_context(); + + if(heap_improved) + { + // If heap part was improved, restrict interval part to found symbolic path + symbolic_path=heap_solver.symbolic_path; + heap_interval_domain.interval_domain.restrict_to_sympath(symbolic_path); + } + + // Run one interation of interval solver in the context of invariant from + // the heap solver + solver.new_context(); + solver << heap_interval_domain.heap_domain.to_pre_constraints(inv.heap_value); bool interval_improved=interval_solver.iterate(inv.interval_value); + solver.pop_context(); + + if(heap_improved) + heap_interval_domain.interval_domain.undo_restriction(); return heap_improved || interval_improved; } From 3e1e5f3fa75c97afdc02d877786ab702a4234763 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 12 Feb 2018 08:51:23 +0100 Subject: [PATCH 160/322] Heap domain: undo solving in symbolic paths This will be replaced by a more generic way using a solver for powerset domain (capable of finding different invariants for different symbolic paths in an abstract domain). --- src/domains/heap_domain.cpp | 103 ++++++++++++++------------- src/domains/heap_domain.h | 95 +++++++----------------- src/domains/strategy_solver_heap.cpp | 23 +++--- 3 files changed, 89 insertions(+), 132 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 0cc8e6d3f..a2b1a968b 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -29,11 +29,16 @@ void heap_domaint::initialize(domaint::valuet &value) for(const template_rowt &templ_row : templ) { - dyn_objt dyn_obj= - templ_row.mem_kind==HEAP - ? std::make_pair(templ_row.dyn_obj, templ_row.expr) - : std::make_pair(nil_exprt(), nil_exprt()); - val.emplace_back(templ_row.mem_kind, dyn_obj); + if(templ_row.mem_kind==STACK) + val.emplace_back(new stack_row_valuet()); + else if(templ_row.mem_kind==HEAP) + val.emplace_back( + new heap_row_valuet( + std::make_pair( + templ_row.dyn_obj, + templ_row.expr))); + else + assert(false); } } @@ -242,21 +247,18 @@ exprt heap_domaint::get_row_post_constraint( Function: heap_domaint::add_transitivity - Inputs: sym_path Symbolic path - to Row to add new paths to + Inputs: to Row to add new paths to from Row to add paths from dyn_obj Dynamic object that all the paths pass through (it belongs to path segment from one pointer to another). Outputs: True if any path was added or changed, otherwise false. - Purpose: Add all paths of one pointer as the destinations of another pointer - in the given symbolic path. + Purpose: Add all paths of one pointer as the destinations of another pointer. \*******************************************************************/ bool heap_domaint::add_transitivity( - const exprt &sym_path, const rowt &from, const rowt &to, heap_valuet &value) @@ -264,8 +266,8 @@ bool heap_domaint::add_transitivity( assert(from(value[from]); + heap_row_valuet &heap_val_to=static_cast(value[to]); bool result=false; if(heap_val_from.add_all_paths( @@ -291,10 +293,10 @@ Function: heap_domaint::add_points_to Outputs: - Purpose: Add new object pointed by a row in the given symbolic path. + Purpose: Add new object pointed by a row. Calls add_points_to of the given row. For stack rows, the destination is simply added into pointed - objects set of the configuration corresponding to the symbolic path. + objects set. For heap rows, a new path is added. \*******************************************************************/ @@ -302,11 +304,10 @@ Function: heap_domaint::add_points_to bool heap_domaint::add_points_to( const rowt &row, heap_valuet &value, - const exprt &sym_path, const exprt &dest) { assert(row templatet; /*******************************************************************\ - Base class for a value of a memory configuration + Base class for a value of a row \*******************************************************************/ - struct row_configt + struct row_valuet { // Row is nondeterministic - row expression is TRUE bool nondet=false; - virtual exprt get_row_config_expr( + virtual exprt get_row_expr( const vart &templ_expr, - bool rename_templ_expr) const=0; + bool rename_templ_expr) const =0; - virtual bool empty() const=0; + virtual bool empty() const =0; virtual bool add_points_to(const exprt &dest)=0; - virtual ~row_configt() {} + virtual ~row_valuet() {} }; /*******************************************************************\ - Stack row configuration - used for pointer-typed stack objects (variables). - Configuration is a set of objects that the pointer can point to. + Stack row - used for pointer-typed stack objects (variables). + Value is a set of objects that the pointer can point to. \*******************************************************************/ - struct stack_row_configt:public row_configt + struct stack_row_valuet:public row_valuet { // Set of objects (or NULL) the row variable can point to std::set points_to; - virtual exprt get_row_config_expr( + virtual exprt get_row_expr( const vart &templ_expr, bool rename_templ_expr) const override; @@ -93,12 +93,12 @@ class heap_domaint:public domaint }; /*******************************************************************\ - Heap row configuration - used for pointer-typed fields of dynamic objects. + Heap row - used for pointer-typed fields of dynamic objects. - Configuration is a disjunction of conjunctions of paths leading from - the dynamic object via the field. + Value is a disjunction of conjunctions of paths leading from the dynamic + object via the field. \*******************************************************************/ - struct heap_row_configt:public row_configt + struct heap_row_valuet:public row_valuet { /*******************************************************************\ Path in a heap. Contains: @@ -134,14 +134,14 @@ class heap_domaint:public domaint // Set of rows whose variables point to this row std::set pointed_by; - // Dynamic obejct corresponding to the row (contains both object and field) + // Dynamic object corresponding to the row (contains both object and field) dyn_objt dyn_obj; // Self link on an abstract dynamic object bool self_linkage=false; - explicit heap_row_configt(const dyn_objt &dyn_obj_):dyn_obj(dyn_obj_) {} + explicit heap_row_valuet(const dyn_objt &dyn_obj_):dyn_obj(dyn_obj_) {} - virtual exprt get_row_config_expr( + virtual exprt get_row_expr( const vart &templ_expr_, bool rename_templ_expr) const override; @@ -155,7 +155,7 @@ class heap_domaint:public domaint bool add_path(const exprt &dest, const dyn_objt &dyn_obj); bool add_all_paths( - const heap_row_configt &other_config, + const heap_row_valuet &other_val, const dyn_objt &dyn_obj); bool add_pointed_by(const rowt &row); @@ -166,46 +166,16 @@ class heap_domaint:public domaint static exprt rename_outheap(const symbol_exprt &expr); }; - /*******************************************************************\ - Row value is a disjunction of configurations. - \*******************************************************************/ - struct row_valuet - { - mem_kindt mem_kind; - dyn_objt dyn_obj; - - // Each configuration belongs to a specific symbolic path in program whose - // execution lead to the given configuration. - // Path is a conjunction of guards - hence an expression - std::map> configurations; - - row_valuet(const mem_kindt &mem_kind, const dyn_objt &dyn_obj): - mem_kind(mem_kind), dyn_obj(dyn_obj) {} - - // Allow move constructor only - row_valuet(const row_valuet &)=delete; - row_valuet(row_valuet &&)=default; - - row_configt &get_config(const exprt &sym_path); - stack_row_configt &get_stack_config(const exprt &sym_path); - heap_row_configt &get_heap_config(const exprt &sym_path); - - // Row manipulation functions - bool add_points_to(const exprt &sym_path, const exprt &dest); - bool set_nondet(const exprt &sym_path); - - // Row status functions - bool empty() const; - bool is_nondet(const exprt &sym_path); - - exprt get_row_expr(const exprt &templ_expr, bool rename_templ_expr) const; - }; - // Heap value is a conjunction of rows class heap_valuet: public valuet, - public std::vector + public std::vector> { + public: + row_valuet &operator[](const rowt &row) const + { + return *(this->at(row).get()); + } }; // Initialize value and domain @@ -232,22 +202,11 @@ class heap_domaint:public domaint exprt get_row_post_constraint(const rowt &row, const row_valuet &row_value); // Row modifications - bool add_transitivity( - const exprt &sym_path, - const rowt &from, - const rowt &to, - heap_valuet &value); + bool add_transitivity(const rowt &from, const rowt &to, heap_valuet &value); - bool add_points_to( - const rowt &row, - heap_valuet &value, - const exprt &sym_path, - const exprt &dest); + bool add_points_to(const rowt &row, heap_valuet &value, const exprt &dest); - bool set_nondet( - const rowt &row, - heap_valuet &value, - const exprt &sym_path); + bool set_nondet(const rowt &row, heap_valuet &value); // Printing virtual void output_value( diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index 5f5e37ea1..1b2ec7cf0 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -126,14 +126,13 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) const exprt loop_guard=to_and_expr( heap_domain.templ[row].pre_guard).op1(); find_symbolic_path(loop_guards, loop_guard); - debug() << "Symbolic path: " << from_expr(ns, "", symbolic_path) << eom; if((ptr_value.id()==ID_constant && to_constant_expr(ptr_value).get_value()==ID_NULL) || ptr_value.id()==ID_symbol) { // Add equality p == NULL or p == symbol - if(heap_domain.add_points_to(row, inv, symbolic_path, ptr_value)) + if(heap_domain.add_points_to(row, inv, ptr_value)) { improved=true; const std::string info= @@ -151,7 +150,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) { // If solver did not return address of a symbol, it is considered // as nondet value. - if(heap_domain.set_nondet(row, inv, symbolic_path)) + if(heap_domain.set_nondet(row, inv)) { improved=true; debug() << "Set nondet" << eom; @@ -166,7 +165,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) ns.follow(templ_row.expr.type().subtype())!=ns.follow(obj.type())) { // If types disagree, it's a nondet (solver assigned random value) - if(heap_domain.set_nondet(row, inv, symbolic_path)) + if(heap_domain.set_nondet(row, inv)) { improved=true; debug() << "Set nondet" << eom; @@ -175,7 +174,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) } // Add equality p == &obj - if(heap_domain.add_points_to(row, inv, symbolic_path, obj)) + if(heap_domain.add_points_to(row, inv, obj)) { improved=true; const std::string info= @@ -200,12 +199,10 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) templ_row.member, actual_loc, templ_row.kind); - if(member_val_index>=0 && - !inv[member_val_index].is_nondet(symbolic_path)) + if(member_val_index>=0 && !inv[member_val_index].nondet) { // Add all paths from obj.next to p if(heap_domain.add_transitivity( - symbolic_path, row, static_cast(member_val_index), inv)) @@ -221,7 +218,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) } else { - if(heap_domain.set_nondet(row, inv, symbolic_path)) + if(heap_domain.set_nondet(row, inv)) { improved=true; debug() << "Set nondet" << eom; @@ -232,7 +229,7 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) if(templ_row.mem_kind==heap_domaint::HEAP) { updated_rows.clear(); - if(!inv[row].is_nondet(symbolic_path)) + if(!inv[row].nondet) update_rows_rec(row, inv); } } @@ -342,8 +339,8 @@ bool strategy_solver_heapt::update_rows_rec( const heap_domaint::rowt &row, heap_domaint::heap_valuet &value) { - heap_domaint::heap_row_configt &row_value= - value[row].get_heap_config(symbolic_path); + heap_domaint::heap_row_valuet &row_value= + static_cast(value[row]); const heap_domaint::template_rowt &templ_row=heap_domain.templ[row]; updated_rows.insert(row); @@ -353,7 +350,7 @@ bool strategy_solver_heapt::update_rows_rec( if(heap_domain.templ[ptr].mem_kind==heap_domaint::HEAP && heap_domain.templ[ptr].member==templ_row.member) { - if(heap_domain.add_transitivity(symbolic_path, ptr, row, value)) + if(heap_domain.add_transitivity(ptr, row, value)) result=true; debug() << "recursively updating row: " << ptr << eom; From d6dd9806cb71d424c8cbd7d33407119aef09d918 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 12 Feb 2018 08:55:05 +0100 Subject: [PATCH 161/322] Add new abstract domain for computing invariants for different symbolic paths A value in the domain is a set of invariants in the compound domain (in this case the heap interval domain). Each invariant holds for a different symbolic path in the analysed program. We infer an invariant for each path separately, using the possibility to restrict solving to certain paths only. After computation of an invariant, we check whether the corresponding symbolic path is feasible and if not, we remove the invariant. --- src/2ls/2ls_parse_options.cpp | 3 + src/2ls/2ls_parse_options.h | 1 + src/domains/Makefile | 4 +- src/domains/heap_interval_sympath_domain.cpp | 83 +++++++ src/domains/heap_interval_sympath_domain.h | 68 ++++++ src/domains/ssa_analyzer.cpp | 31 ++- src/domains/strategy_solver_heap_interval.cpp | 6 + src/domains/strategy_solver_heap_interval.h | 1 + .../strategy_solver_heap_interval_sympath.cpp | 221 ++++++++++++++++++ .../strategy_solver_heap_interval_sympath.h | 65 ++++++ src/domains/template_generator_base.cpp | 9 +- 11 files changed, 480 insertions(+), 12 deletions(-) create mode 100644 src/domains/heap_interval_sympath_domain.cpp create mode 100644 src/domains/heap_interval_sympath_domain.h create mode 100644 src/domains/strategy_solver_heap_interval_sympath.cpp create mode 100644 src/domains/strategy_solver_heap_interval_sympath.h diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index c966187b8..a78b4c0b1 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -206,6 +206,8 @@ void twols_parse_optionst::get_command_line_options(optionst &options) else if(cmdline.isset("heap-interval")) { options.set_option("heap-interval", true); + if(cmdline.isset("sympath")) + options.set_option("sympath", true); } else { @@ -1743,6 +1745,7 @@ void twols_parse_optionst::help() " --zones use zone domain\n" " --octagons use octagon domain\n" " --heap-interval use heap domain with interval domain for values\n" // NOLINT(*) + " --sympath compute invariant for each symbolic path (only usable with --heap-interval switch)" // NOLINT(*) " --enum-solver use solver based on model enumeration\n" " --binsearch-solver use solver based on binary search\n" " --arrays do not ignore array contents\n" diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index 3dfb006b5..612e35f5c 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -38,6 +38,7 @@ class optionst; "(i386-linux)(i386-macos)(i386-win32)(win32)(winx64)(gcc)" \ "(ppc-macos)(unsigned-char)" \ "(havoc)(intervals)(zones)(octagons)(equalities)(heap)(heap-interval)"\ + "(sympath)" \ "(enum-solver)(binsearch-solver)(arrays)"\ "(string-abstraction)(no-arch)(arch):(floatbv)(fixedbv)" \ "(round-to-nearest)(round-to-plus-inf)(round-to-minus-inf)(round-to-zero)" \ diff --git a/src/domains/Makefile b/src/domains/Makefile index d7a9d1540..28f310666 100644 --- a/src/domains/Makefile +++ b/src/domains/Makefile @@ -1,6 +1,6 @@ SRC = tpolyhedra_domain.cpp equality_domain.cpp domain.cpp \ predabs_domain.cpp heap_domain.cpp list_iterator.cpp \ - heap_interval_domain.cpp \ + heap_interval_domain.cpp heap_interval_sympath_domain.cpp symbolic_path.cpp\ ssa_analyzer.cpp util.cpp incremental_solver.cpp \ strategy_solver_base.cpp strategy_solver_equality.cpp \ linrank_domain.cpp lexlinrank_domain.cpp\ @@ -10,7 +10,7 @@ SRC = tpolyhedra_domain.cpp equality_domain.cpp domain.cpp \ template_generator_callingcontext.cpp template_generator_ranking.cpp \ strategy_solver_binsearch2.cpp strategy_solver_binsearch3.cpp \ strategy_solver_predabs.cpp strategy_solver_heap.cpp \ - strategy_solver_heap_interval.cpp + strategy_solver_heap_interval.cpp strategy_solver_heap_interval_sympath.cpp \ #solver_enumeration.cpp include ../config.inc diff --git a/src/domains/heap_interval_sympath_domain.cpp b/src/domains/heap_interval_sympath_domain.cpp new file mode 100644 index 000000000..8fc09f9c4 --- /dev/null +++ b/src/domains/heap_interval_sympath_domain.cpp @@ -0,0 +1,83 @@ +/*******************************************************************\ + +Module: Abstract domain for computing invariants in heap-interval + domain for different symbolic paths in program. + +Author: Viktor Malik + +\*******************************************************************/ + +#include "heap_interval_sympath_domain.h" + +/*******************************************************************\ + +Function: heap_interval_sympath_domaint::output_value + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ +void heap_interval_sympath_domaint::output_value( + std::ostream &out, + const domaint::valuet &value, + const namespacet &ns) const +{ + const heap_interval_sympath_valuet &v= + static_cast(value); + for(auto &config : v) + { + out << from_expr(ns, "", config.first) << "==>\n"; + heap_interval_domain.output_value(out, config.second, ns); + } +} + +/*******************************************************************\ + +Function: heap_interval_sympath_domaint::output_domain + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ +void heap_interval_sympath_domaint::output_domain( + std::ostream &out, + const namespacet &ns) const +{ + heap_interval_domain.output_domain(out, ns); +} + +/*******************************************************************\ + +Function: heap_interval_sympath_domaint::project_on_vars + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ +void heap_interval_sympath_domaint::project_on_vars( + domaint::valuet &value, + const domaint::var_sett &vars, + exprt &result) +{ + heap_interval_sympath_valuet &v= + static_cast(value); + exprt::operandst c; + for(auto &config : v) + { + exprt config_result; + heap_interval_domain.project_on_vars(config.second, vars, config_result); + c.push_back(and_exprt(config.first, config_result)); + } + c.push_back(no_loops_path); + + result=c.empty() ? true_exprt() : disjunction(c); +} diff --git a/src/domains/heap_interval_sympath_domain.h b/src/domains/heap_interval_sympath_domain.h new file mode 100644 index 000000000..fbd38eb59 --- /dev/null +++ b/src/domains/heap_interval_sympath_domain.h @@ -0,0 +1,68 @@ +/*******************************************************************\ + +Module: Abstract domain for computing invariants in heap-interval + domain for different symbolic paths in program. + +Author: Viktor Malik + +\*******************************************************************/ + +#ifndef CPROVER_2LS_DOMAINS_HEAP_INTERVAL_SYMPATH_DOMAIN_H +#define CPROVER_2LS_DOMAINS_HEAP_INTERVAL_SYMPATH_DOMAIN_H + + +#include "domain.h" +#include "heap_interval_domain.h" + +class heap_interval_sympath_domaint:public domaint +{ +public: + heap_interval_domaint heap_interval_domain; + + heap_interval_sympath_domaint( + unsigned int _domain_number, + replace_mapt &_renaming_map, + const var_specst &var_specs, + const local_SSAt &SSA): + domaint(_domain_number, _renaming_map, SSA.ns), + heap_interval_domain(_domain_number, _renaming_map, var_specs, SSA.ns) + { + exprt::operandst false_loop_guards; + for(auto &g : SSA.loop_guards) + false_loop_guards.push_back(not_exprt(g)); + no_loops_path=conjunction(false_loop_guards); + } + + // Value is a map from expression (symbolic path) to an invariant in heap + // interval domain + class heap_interval_sympath_valuet: + public valuet, + public std::map + { + }; + + void output_value( + std::ostream &out, + const valuet &value, + const namespacet &ns) const override; + + void output_domain( + std::ostream &out, + const namespacet &ns) const override; + + void project_on_vars( + valuet &value, + const var_sett &vars, + exprt &result) override; + +protected: + // Special path containing conjunction negations of all loop-select guards + // This must be stored explicitly since the solver is not able to explore this + // path even though it can be feasible + exprt no_loops_path; + + friend class strategy_solver_heap_interval_sympatht; +}; + + +#endif //CPROVER_2LS_DOMAINS_HEAP_INTERVAL_SYMPATH_DOMAIN_H diff --git a/src/domains/ssa_analyzer.cpp b/src/domains/ssa_analyzer.cpp index b8a85fb53..5b048f561 100644 --- a/src/domains/ssa_analyzer.cpp +++ b/src/domains/ssa_analyzer.cpp @@ -33,6 +33,7 @@ Author: Peter Schrammel #include "ssa_analyzer.h" #include "strategy_solver_heap.h" #include "strategy_solver_heap_interval.h" +#include "strategy_solver_heap_interval_sympath.h" // NOLINTNEXTLINE(*) #define BINSEARCH_SOLVER strategy_solver_binsearcht(\ @@ -121,14 +122,28 @@ void ssa_analyzert::operator()( } else if(template_generator.options.get_bool_option("heap-interval")) { - strategy_solver=new strategy_solver_heap_intervalt( - *static_cast(domain), - solver, - SSA, - precondition, - get_message_handler(), - template_generator); - result=new heap_interval_domaint::heap_interval_valuet(); + if(template_generator.options.get_bool_option("sympath")) + { + strategy_solver=new strategy_solver_heap_interval_sympatht( + *static_cast(domain), + solver, + SSA, + precondition, + get_message_handler(), + template_generator); + result=new heap_interval_sympath_domaint::heap_interval_sympath_valuet(); + } + else + { + strategy_solver=new strategy_solver_heap_intervalt( + *static_cast(domain), + solver, + SSA, + precondition, + get_message_handler(), + template_generator); + result=new heap_interval_domaint::heap_interval_valuet(); + } } else { diff --git a/src/domains/strategy_solver_heap_interval.cpp b/src/domains/strategy_solver_heap_interval.cpp index 1cc65c85c..1932f3852 100644 --- a/src/domains/strategy_solver_heap_interval.cpp +++ b/src/domains/strategy_solver_heap_interval.cpp @@ -75,3 +75,9 @@ void strategy_solver_heap_intervalt::set_message_handler( heap_solver.set_message_handler(_message_handler); interval_solver.set_message_handler(_message_handler); } + +void strategy_solver_heap_intervalt::clear_symbolic_path() +{ + heap_solver.symbolic_path.clear(); + interval_solver.symbolic_path.clear(); +} diff --git a/src/domains/strategy_solver_heap_interval.h b/src/domains/strategy_solver_heap_interval.h index 8005a821c..bb6c1baca 100644 --- a/src/domains/strategy_solver_heap_interval.h +++ b/src/domains/strategy_solver_heap_interval.h @@ -41,6 +41,7 @@ class strategy_solver_heap_intervalt:public strategy_solver_baset virtual bool iterate(invariantt &_inv) override; virtual void set_message_handler(message_handlert &_message_handler) override; + void clear_symbolic_path(); protected: heap_interval_domaint &heap_interval_domain; diff --git a/src/domains/strategy_solver_heap_interval_sympath.cpp b/src/domains/strategy_solver_heap_interval_sympath.cpp new file mode 100644 index 000000000..f940883fd --- /dev/null +++ b/src/domains/strategy_solver_heap_interval_sympath.cpp @@ -0,0 +1,221 @@ +/*******************************************************************\ + +Module: Strategy solver for heap-interval domain using symbolic paths + +Author: Viktor Malik + +\*******************************************************************/ + +// #define DEBUG + +#include "strategy_solver_heap_interval_sympath.h" + +/*******************************************************************\ + +Function: strategy_solver_heap_interval_sympatht::set_message_handler + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ +void strategy_solver_heap_interval_sympatht::set_message_handler( + message_handlert &_message_handler) +{ + solver.set_message_handler(_message_handler); +} + +/*******************************************************************\ + +Function: strategy_solver_heap_interval_sympatht::iterate + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ +bool strategy_solver_heap_interval_sympatht::iterate( + strategy_solver_baset::invariantt &_inv) +{ + heap_interval_sympath_domaint::heap_interval_sympath_valuet &inv= + static_cast + (_inv); + + bool improved; + if(!new_path) + { + // Computing invariant for the same symbolic path + +#ifdef DEBUG + std::cerr << "------------------------------------------\n"; + std::cerr << "Same path\n"; + std::cerr << from_expr(ns, "", sympath) << "\n"; +#endif + + const exprt sympath=symbolic_path.get_expr(); + + domain.heap_interval_domain.restrict_to_sympath(symbolic_path); + improved=heap_interval_solver.iterate(inv.at(sympath)); + if(!improved) + { + // Invariant for the current symbolic path cannot be improved + +#ifdef DEBUG + std::cerr << "End of path\n"; + std::cerr << "++++++++++++++++++++++++++++++++++++++++++\n"; +#endif + + // Check if the computed path is really feasible + if(!is_current_path_feasible(inv)) + inv.erase(sympath); + + visited_paths.push_back(symbolic_path); + domain.heap_interval_domain.clear_aux_symbols(); + domain.heap_interval_domain.eliminate_sympaths(visited_paths); + clear_symbolic_path(); + improved=true; + new_path=true; + } + else if(heap_interval_solver.symbolic_path.get_expr()!=sympath) + { + // The path has been altered during computation (solver has found another + // loop-select guard that can be true + +#ifdef DEBUG + std::cerr << "Path altered\n"; +#endif + + auto new_sympath=heap_interval_solver.symbolic_path.get_expr(); + inv.emplace(new_sympath, std::move(inv.at(sympath))); + inv.erase(sympath); + symbolic_path=heap_interval_solver.symbolic_path; + } + domain.heap_interval_domain.undo_restriction(); + } + else + { + // Computing invariant for a new path + heap_interval_domaint::heap_interval_valuet new_value; + domain.heap_interval_domain.initialize(new_value); + improved=heap_interval_solver.iterate(new_value); + + if(improved) + { +#ifdef DEBUG + std::cerr << "Symbolic path:\n"; + std::cerr << from_expr(ns, "", sympath) << "\n"; +#endif + symbolic_path=heap_interval_solver.symbolic_path; + const exprt sympath=heap_interval_solver.symbolic_path.get_expr(); + inv.emplace(sympath, std::move(new_value)); + new_path=false; + } + } + return improved; +} + +/*******************************************************************\ + +Function: strategy_solver_heap_interval_sympatht::clear_symbolic_path + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ +void strategy_solver_heap_interval_sympatht::clear_symbolic_path() +{ + symbolic_path.clear(); + heap_interval_solver.clear_symbolic_path(); +} + +/*******************************************************************\ + +Function: strategy_solver_heap_interval_sympatht::is_current_path_feasible + + Inputs: + + Outputs: + + Purpose: Check if the current symbolic path is feasible while the computed + invariant holds. + A path is reachable iff: + - for each loop whose loop-select guard occurs in positive form, + if its loop head is reachable, then also loop end must be + reachable (g#lb => g#le must be SAT) + - for each loop whose loop-select guard occurs in negative form, + if its loop head is reachable, then its end is not reachable + (g#lb => !g#le must be SAT) + +\*******************************************************************/ +bool strategy_solver_heap_interval_sympatht::is_current_path_feasible( + heap_interval_sympath_domaint::heap_interval_sympath_valuet &value) +{ + bool result=true; + auto sympath=symbolic_path.get_expr(); + solver.new_context(); + + // Path invariant + exprt invariant; + domain.heap_interval_domain.project_on_vars(value.at(sympath), {}, invariant); + solver << invariant; + + for(auto &guard : symbolic_path.path_map) + { + // Build condition of reachability of current loop + exprt loop_cond=loop_conds_map.at(guard.first); + if(!guard.second) + loop_cond.op1()=not_exprt(loop_cond.op1()); + + solver.new_context(); + + // Push states of other loop select gurads and condition of reachablility + // of the current loop + const exprt sympath_no_current=symbolic_path.get_expr(guard.first, true); + solver << sympath_no_current; + solver << loop_cond; + + // If loop is not reachable in the current context of computed summary, + // the path is infeasible + if(solver()==decision_proceduret::D_UNSATISFIABLE) + result=false; + + solver.pop_context(); + } + + solver.pop_context(); + return result; +} + +/*******************************************************************\ + +Function: strategy_solver_heap_interval_sympatht::build_loop_conds_map + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ +void strategy_solver_heap_interval_sympatht::build_loop_conds_map( + const local_SSAt &SSA) +{ + for(auto &node : SSA.nodes) + { + if(node.loophead!=SSA.nodes.end()) + { + const exprt ls_guard= + SSA.name(SSA.guard_symbol(), local_SSAt::LOOP_SELECT, node.location); + const exprt lb_guard=SSA.guard_symbol(node.loophead->location); + const exprt le_guard=SSA.guard_symbol(node.location); + loop_conds_map.emplace(ls_guard, and_exprt(lb_guard, le_guard)); + } + } +} diff --git a/src/domains/strategy_solver_heap_interval_sympath.h b/src/domains/strategy_solver_heap_interval_sympath.h new file mode 100644 index 000000000..7a5ce767b --- /dev/null +++ b/src/domains/strategy_solver_heap_interval_sympath.h @@ -0,0 +1,65 @@ +/*******************************************************************\ + +Module: Strategy solver for heap-interval domain using symbolic paths + +Author: Viktor Malik + +\*******************************************************************/ + +#ifndef CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_INTERVAL_SYMPATH_H +#define CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_INTERVAL_SYMPATH_H + + +#include "strategy_solver_base.h" +#include "heap_interval_sympath_domain.h" +#include "strategy_solver_heap_interval.h" + +class strategy_solver_heap_interval_sympatht:public strategy_solver_baset +{ +public: + strategy_solver_heap_interval_sympatht( + heap_interval_sympath_domaint &_domain, + incremental_solvert &_solver, + const local_SSAt &SSA, + const exprt &precondition, + message_handlert &message_handler, + template_generator_baset &template_generator): + strategy_solver_baset(_solver, SSA.ns), + domain(_domain), + heap_interval_solver( + domain.heap_interval_domain, + _solver, + SSA, + precondition, + message_handler, + template_generator) + { + build_loop_conds_map(SSA); + } + + virtual bool iterate(invariantt &inv) override; + + virtual void set_message_handler(message_handlert &_message_handler) override; + + void clear_symbolic_path(); + +protected: + heap_interval_sympath_domaint &domain; + strategy_solver_heap_intervalt heap_interval_solver; + + std::vector visited_paths; + bool new_path=true; + + // Mapping for each loop: + // g#ls -> (g#lh && g#le) + // ^ loop select ^ loop head ^ loop end + // This is used to check feasibility of symbolic paths + std::map loop_conds_map; + void build_loop_conds_map(const local_SSAt &SSA); + + bool is_current_path_feasible( + heap_interval_sympath_domaint::heap_interval_sympath_valuet &value); +}; + + +#endif // CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_INTERVAL_SYMPATH_ diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index 6cd3d55ff..0f03b6722 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -20,6 +20,7 @@ Author: Peter Schrammel #include "predabs_domain.h" #include "heap_domain.h" #include "heap_interval_domain.h" +#include "heap_interval_sympath_domain.h" #ifdef DEBUG #include @@ -769,8 +770,12 @@ void template_generator_baset::instantiate_standard_domains( else if(options.get_bool_option("heap-interval")) { filter_heap_interval_domain(); - domain_ptr= - new heap_interval_domaint(domain_number, renaming_map, var_specs, SSA.ns); + if(options.get_bool_option("sympath")) + domain_ptr=new heap_interval_sympath_domaint( + domain_number, renaming_map, var_specs, SSA); + else + domain_ptr=new heap_interval_domaint( + domain_number, renaming_map, var_specs, SSA.ns); } } From 87a77409c07da4d27805c48097df923e5f56727c Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 12 Feb 2018 09:37:25 +0100 Subject: [PATCH 162/322] Heap domain: if a row is nondet, clear all pointing rows Since information in pointing rows could have been inferred based on nondet row, we have to recompute values of these rows. --- src/domains/heap_domain.cpp | 34 ++++++++++++++++++++++++++++ src/domains/heap_domain.h | 6 +++++ src/domains/strategy_solver_heap.cpp | 16 +++++++++++++ src/domains/strategy_solver_heap.h | 3 +++ 4 files changed, 59 insertions(+) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index a2b1a968b..25a421c03 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -610,6 +610,23 @@ bool heap_domaint::stack_row_valuet::add_points_to(const exprt &expr) /*******************************************************************\ +Function: heap_domaint::stack_row_valuet::clear + + Inputs: + + Outputs: + + Purpose: Clear stack row value + +\*******************************************************************/ +void heap_domaint::stack_row_valuet::clear() +{ + nondet=false; + points_to.clear(); +} + +/*******************************************************************\ + Function: heap_domaint::heap_row_valuet::get_row_expr Inputs: templ_expr Template expression @@ -860,6 +877,23 @@ exprt heap_domaint::heap_row_valuet::rename_outheap(const symbol_exprt &expr) /*******************************************************************\ +Function: heap_domaint::heap_row_valuet::clear + + Inputs: + + Outputs: Clear heap row value + + Purpose: + +\*******************************************************************/ +void heap_domaint::heap_row_valuet::clear() +{ + nondet=false; + paths.clear(); +} + +/*******************************************************************\ + Function: heap_domaint::get_new_heap_vars Inputs: diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index c3328fc2e..d466e63f0 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -68,6 +68,8 @@ class heap_domaint:public domaint virtual bool add_points_to(const exprt &dest)=0; + virtual void clear()=0; + virtual ~row_valuet() {} }; @@ -90,6 +92,8 @@ class heap_domaint:public domaint { return points_to.empty(); } + + virtual void clear() override; }; /*******************************************************************\ @@ -152,6 +156,8 @@ class heap_domaint:public domaint return paths.empty() && !self_linkage; } + virtual void clear() override; + bool add_path(const exprt &dest, const dyn_objt &dyn_obj); bool add_all_paths( diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index 1b2ec7cf0..5eadf165e 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -231,6 +231,8 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) updated_rows.clear(); if(!inv[row].nondet) update_rows_rec(row, inv); + else + clear_pointing_rows(row, inv); } } } @@ -417,3 +419,17 @@ void strategy_solver_heapt::initialize( heap_domain.output_domain(debug(), ns); } } + +void strategy_solver_heapt::clear_pointing_rows( + const heap_domaint::rowt &row, + heap_domaint::heap_valuet &value) +{ + heap_domaint::heap_row_valuet &row_value= + static_cast(value[row]); + + for(auto &ptr : row_value.pointed_by) + { + debug() << "Clearing row: " << ptr << eom; + value[ptr].clear(); + } +} diff --git a/src/domains/strategy_solver_heap.h b/src/domains/strategy_solver_heap.h index 4eb4b159a..f7a0859a8 100644 --- a/src/domains/strategy_solver_heap.h +++ b/src/domains/strategy_solver_heap.h @@ -52,6 +52,9 @@ class strategy_solver_heapt:public strategy_solver_baset bool update_rows_rec( const heap_domaint::rowt &row, heap_domaint::heap_valuet &value); + void clear_pointing_rows( + const heap_domaint::rowt &row, + heap_domaint::heap_valuet &value); void print_solver_expr(const exprt &expr); }; From 35917d0a5bec799289eba597c16566d4acd37d18 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 12 Feb 2018 09:46:45 +0100 Subject: [PATCH 163/322] New tests for heap manipulation Tests were taken from SV-COMP'18 HeapReach category. We can now solve these tasks thanks to new abstract domain with symbolic paths. --- regression/heap/built_from_end/test.desc | 2 +- regression/heap/list_false/main.c | 53 +++++++++++++++++++++++ regression/heap/list_false/test.desc | 7 +++ regression/heap/list_true/main.c | 55 ++++++++++++++++++++++++ regression/heap/list_true/test.desc | 6 +++ regression/heap/simple_false/main.c | 45 +++++++++++++++++++ regression/heap/simple_false/test.desc | 7 +++ regression/heap/simple_true/test.desc | 2 +- 8 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 regression/heap/list_false/main.c create mode 100644 regression/heap/list_false/test.desc create mode 100644 regression/heap/list_true/main.c create mode 100644 regression/heap/list_true/test.desc create mode 100644 regression/heap/simple_false/main.c create mode 100644 regression/heap/simple_false/test.desc diff --git a/regression/heap/built_from_end/test.desc b/regression/heap/built_from_end/test.desc index 6b6d935ce..e086f8559 100644 --- a/regression/heap/built_from_end/test.desc +++ b/regression/heap/built_from_end/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-interval --inline --no-propagation +--heap-interval --inline --no-propagation --sympath ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/list_false/main.c b/regression/heap/list_false/main.c new file mode 100644 index 000000000..386921ee1 --- /dev/null +++ b/regression/heap/list_false/main.c @@ -0,0 +1,53 @@ +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +extern int __VERIFIER_nondet_int(); +/* + * Simple example: build a list with only 1s, then 2s and finally + * on 3 (arbitrary length); afterwards, go through it and check + * if the the list does have the correct form, and in particular + * finishes by a 3. + */ +#include + +void exit(int s) { + _EXIT: goto _EXIT; +} + +typedef struct node { + int h; + struct node *n; +} *List; + +int main() { + /* Build a list of the form 1->...->1->2->....->2->3 */ + List a = (List) malloc(sizeof(struct node)); + if (a == 0) exit(1); + List t; + List p = a; + while (__VERIFIER_nondet_int()) { + p->h = 1; + t = (List) malloc(sizeof(struct node)); + if (t == 0) exit(1); + p->n = t; + p = p->n; + } + while (__VERIFIER_nondet_int()) { + p->h = 2; + t = (List) malloc(sizeof(struct node)); + if (t == 0) exit(1); + p->n = t; + p = p->n; + } + p->h = 3; + + /* Check it */ + p = a; + while (p->h == 2) + p = p->n; + while (p->h == 1) + p = p->n; + if(p->h != 3) + ERROR: __VERIFIER_error(); + + return 0; +} diff --git a/regression/heap/list_false/test.desc b/regression/heap/list_false/test.desc new file mode 100644 index 000000000..93984c1aa --- /dev/null +++ b/regression/heap/list_false/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--heap-interval --sympath --inline --no-propagation --k-induction +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +^\[main.assertion.1\] : FAILURE diff --git a/regression/heap/list_true/main.c b/regression/heap/list_true/main.c new file mode 100644 index 000000000..f0647ca1f --- /dev/null +++ b/regression/heap/list_true/main.c @@ -0,0 +1,55 @@ +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +extern int __VERIFIER_nondet_int(); +/* + * Simple example: build a list with only 1s, then 2s and finally + * on 3 (arbitrary length); afterwards, go through it and check + * if the the list does have the correct form, and in particular + * finishes by a 3. + */ +#include + +void exit(int s) { + _EXIT: goto _EXIT; +} + +typedef struct node { + int h; + struct node *n; +} *List; + +int main() { + /* Build a list of the form 1->...->1->2->....->2->3 */ + List a = (List) malloc(sizeof(struct node)); + if (a == 0) exit(1); + List t; + List p = a; + while (__VERIFIER_nondet_int()) { + p->h = 1; + t = (List) malloc(sizeof(struct node)); + if (t == 0) exit(1); + t->n = NULL; + p->n = t; + p = p->n; + } + while (__VERIFIER_nondet_int()) { + p->h = 2; + t = (List) malloc(sizeof(struct node)); + if (t == 0) exit(1); + t->n = NULL; + p->n = t; + p = p->n; + } + p->h = 3; + + /* Check it */ + p = a; + while (p->h == 1) + p = p->n; + while (p->h == 2) + p = p->n; + if(p->h != 3) + ERROR: __VERIFIER_error(); + + return 0; +} diff --git a/regression/heap/list_true/test.desc b/regression/heap/list_true/test.desc new file mode 100644 index 000000000..c03cf0e85 --- /dev/null +++ b/regression/heap/list_true/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-interval --sympath --inline --no-propagation +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap/simple_false/main.c b/regression/heap/simple_false/main.c new file mode 100644 index 000000000..e3d4f0af8 --- /dev/null +++ b/regression/heap/simple_false/main.c @@ -0,0 +1,45 @@ +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +extern int __VERIFIER_nondet_int(); +/* + * Simple example: build a list with only 1s and finally a 0 (arbitrary length); + * afterwards, go through it and check if the list does have the correct form, and in particular + * finishes by a 0. + */ +#include + +void exit(int s) { + _EXIT: goto _EXIT; +} + +typedef struct node { + int h; + struct node *n; +} *List; + +int main() { + /* Build a list of the form 1->...->1->0 */ + List a = (List) malloc(sizeof(struct node)); + if (a == 0) exit(1); + List t; + List p = a; + a->h = 2; + while (__VERIFIER_nondet_int()) { + p->h = 1; + t = (List) malloc(sizeof(struct node)); + if (t == 0) exit(1); + p->n = t; + p = p->n; + } + p->h = 2; + p->n = 0; + p = a; + while (p!=0) { + if (p->h != 2) { + ERROR: __VERIFIER_error(); + } + p = p->n; + } + return 0; +} + diff --git a/regression/heap/simple_false/test.desc b/regression/heap/simple_false/test.desc new file mode 100644 index 000000000..93984c1aa --- /dev/null +++ b/regression/heap/simple_false/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--heap-interval --sympath --inline --no-propagation --k-induction +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +^\[main.assertion.1\] : FAILURE diff --git a/regression/heap/simple_true/test.desc b/regression/heap/simple_true/test.desc index 6b6d935ce..e086f8559 100644 --- a/regression/heap/simple_true/test.desc +++ b/regression/heap/simple_true/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-interval --inline --no-propagation +--heap-interval --inline --no-propagation --sympath ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ From b5b5892cb25bd0765d04d76409118695b34d2b10 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 12 Feb 2018 09:58:19 +0100 Subject: [PATCH 164/322] Fix formatting errors --- src/domains/heap_domain.h | 4 ++-- src/domains/heap_interval_sympath_domain.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index d466e63f0..73ff01a9b 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -62,9 +62,9 @@ class heap_domaint:public domaint virtual exprt get_row_expr( const vart &templ_expr, - bool rename_templ_expr) const =0; + bool rename_templ_expr) const=0; - virtual bool empty() const =0; + virtual bool empty() const=0; virtual bool add_points_to(const exprt &dest)=0; diff --git a/src/domains/heap_interval_sympath_domain.h b/src/domains/heap_interval_sympath_domain.h index fbd38eb59..796dd6eaf 100644 --- a/src/domains/heap_interval_sympath_domain.h +++ b/src/domains/heap_interval_sympath_domain.h @@ -65,4 +65,4 @@ class heap_interval_sympath_domaint:public domaint }; -#endif //CPROVER_2LS_DOMAINS_HEAP_INTERVAL_SYMPATH_DOMAIN_H +#endif // CPROVER_2LS_DOMAINS_HEAP_INTERVAL_SYMPATH_DOMAIN_H From af68bb21b2ccf4acff51c5403032d1562b6ed38e Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 12 Feb 2018 17:00:51 +0100 Subject: [PATCH 165/322] Make map keys non-const This is required by the standard (keys must be copyable and moveable). --- src/domains/heap_interval_sympath_domain.h | 2 +- src/domains/strategy_solver_heap_interval_sympath.h | 2 +- src/domains/symbolic_path.h | 2 +- src/ssa/local_ssa.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/domains/heap_interval_sympath_domain.h b/src/domains/heap_interval_sympath_domain.h index 796dd6eaf..5a3fee8fc 100644 --- a/src/domains/heap_interval_sympath_domain.h +++ b/src/domains/heap_interval_sympath_domain.h @@ -37,7 +37,7 @@ class heap_interval_sympath_domaint:public domaint // interval domain class heap_interval_sympath_valuet: public valuet, - public std::map + public std::map { }; diff --git a/src/domains/strategy_solver_heap_interval_sympath.h b/src/domains/strategy_solver_heap_interval_sympath.h index 7a5ce767b..6fb7fc17b 100644 --- a/src/domains/strategy_solver_heap_interval_sympath.h +++ b/src/domains/strategy_solver_heap_interval_sympath.h @@ -54,7 +54,7 @@ class strategy_solver_heap_interval_sympatht:public strategy_solver_baset // g#ls -> (g#lh && g#le) // ^ loop select ^ loop head ^ loop end // This is used to check feasibility of symbolic paths - std::map loop_conds_map; + std::map loop_conds_map; void build_loop_conds_map(const local_SSAt &SSA); bool is_current_path_feasible( diff --git a/src/domains/symbolic_path.h b/src/domains/symbolic_path.h index c00dbc742..44974bea5 100644 --- a/src/domains/symbolic_path.h +++ b/src/domains/symbolic_path.h @@ -15,7 +15,7 @@ Author: Viktor Malik class symbolic_patht { public: - std::map path_map; + std::map path_map; const exprt get_expr( const exprt &except_guard=nil_exprt(), diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index cf33ead80..087fbe32e 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -152,7 +152,7 @@ class local_SSAt pointer_id(pointer_id), cond(cond) {} }; typedef std::list dyn_obj_assignst; - std::map dyn_obj_assigns; + std::map dyn_obj_assigns; bool has_function_calls() const; From 64daeeb0607fbd903c4576280763ec27faaaac9e Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 26 Feb 2018 08:06:03 +0100 Subject: [PATCH 166/322] Set "record_malloc" and "record_may_leak" variables to true This is useful when analysing pointer and memory safety, respectively. --- src/2ls/2ls_parse_options.cpp | 6 +++++ src/ssa/malloc_ssa.cpp | 49 +++++++++++++++++++++++++++++++++++ src/ssa/malloc_ssa.h | 3 +++ 3 files changed, 58 insertions(+) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index a78b4c0b1..94bb89c5b 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -1234,6 +1234,12 @@ bool twols_parse_optionst::process_goto_program( // Replace malloc dynamic_memory_detected=replace_malloc(goto_model, ""); + // Allow recording of mallocs and memory leaks + if (options.get_bool_option("pointer-check")) + allow_record_malloc(goto_model); + if (options.get_bool_option("memory-leak-check")) + allow_record_memleak(goto_model); + // remove loop heads from function entries remove_loops_in_entry(goto_model); diff --git a/src/ssa/malloc_ssa.cpp b/src/ssa/malloc_ssa.cpp index 8c4a1003f..7727b6f7e 100644 --- a/src/ssa/malloc_ssa.cpp +++ b/src/ssa/malloc_ssa.cpp @@ -293,3 +293,52 @@ bool replace_malloc( } return result; } + +void set_var_always_to_true(goto_modelt &goto_model, + bool (*name_cond)(std::string &)) +{ + Forall_goto_functions(f_it, goto_model.goto_functions) + { + Forall_goto_program_instructions(i_it, f_it->second.body) + { + if(i_it->is_decl()) + { + code_declt &code_decl=to_code_decl(i_it->code); + if(code_decl.symbol().id()==ID_symbol) + { + std::string decl_id= + id2string(to_symbol_expr(code_decl.symbol()).get_identifier()); + if (name_cond(decl_id)) + { + auto assign=f_it->second.body.insert_after(i_it); + assign->make_assignment(); + assign->code=code_assignt(code_decl.symbol(), true_exprt()); + } + } + } + } + f_it->second.body.compute_location_numbers(); + f_it->second.body.compute_target_numbers(); + f_it->second.body.compute_incoming_edges(); + } +} + +void allow_record_malloc(goto_modelt &goto_model) +{ + set_var_always_to_true( + goto_model, [](std::string &name) + { + return name.find("malloc::")!=std::string::npos && + name.find("::record_malloc")!=std::string::npos; + }); +} + +void allow_record_memleak(goto_modelt &goto_model) +{ + set_var_always_to_true( + goto_model, [](std::string &name) + { + return name.find("malloc::")!=std::string::npos && + name.find("::record_may_leak")!=std::string::npos; + }); +} diff --git a/src/ssa/malloc_ssa.h b/src/ssa/malloc_ssa.h index bd6c2ec5c..5470b5835 100644 --- a/src/ssa/malloc_ssa.h +++ b/src/ssa/malloc_ssa.h @@ -21,4 +21,7 @@ bool replace_malloc( goto_modelt &goto_model, const std::string &suffix); +void allow_record_malloc(goto_modelt &goto_model); +void allow_record_memleak(goto_modelt &goto_model); + #endif From 5f59a7d16a30868a65a2fb4472b33b534a857f9c Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 26 Feb 2018 08:10:45 +0100 Subject: [PATCH 167/322] Heap domain: handle incompatible pointer types in get_row_expr If there is and incompatibility between the type of the template row expression and the address of pointed object, use typecast. This is currently used when dealing with CPROVER-specific pointer variables, which are of (void *) type. Hence, we allow incompatible type returned by the solver for these variables only. --- src/domains/heap_domain.cpp | 16 +++++++++++----- src/domains/heap_domain.h | 9 ++++++++- src/domains/strategy_solver_heap.cpp | 19 ++++++++++++++----- src/domains/strategy_solver_heap.h | 2 ++ 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 25a421c03..1456a0066 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -30,10 +30,11 @@ void heap_domaint::initialize(domaint::valuet &value) for(const template_rowt &templ_row : templ) { if(templ_row.mem_kind==STACK) - val.emplace_back(new stack_row_valuet()); + val.emplace_back(new stack_row_valuet(ns)); else if(templ_row.mem_kind==HEAP) val.emplace_back( new heap_row_valuet( + ns, std::make_pair( templ_row.dyn_obj, templ_row.expr))); @@ -577,10 +578,15 @@ exprt heap_domaint::stack_row_valuet::get_row_expr( exprt::operandst result; for(const exprt &pt : points_to) { - result.push_back( - equal_exprt( - templ_expr, - templ_expr.type()==pt.type() ? pt : address_of_exprt(pt))); + exprt value; + if (templ_expr.type() == pt.type()) + value = pt; + else if (ns.follow(templ_expr.type().subtype()) == ns.follow(pt.type())) + value = address_of_exprt(pt); + else + value=typecast_exprt(address_of_exprt(pt), + ns.follow(templ_expr.type())); + result.push_back(equal_exprt(templ_expr, value)); } return disjunction(result); } diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index 73ff01a9b..c99120cea 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -60,6 +60,10 @@ class heap_domaint:public domaint // Row is nondeterministic - row expression is TRUE bool nondet=false; + const namespacet &ns; + + row_valuet(const namespacet &ns):ns(ns) {} + virtual exprt get_row_expr( const vart &templ_expr, bool rename_templ_expr) const=0; @@ -82,6 +86,8 @@ class heap_domaint:public domaint // Set of objects (or NULL) the row variable can point to std::set points_to; + stack_row_valuet(const namespacet &ns):row_valuet(ns) {} + virtual exprt get_row_expr( const vart &templ_expr, bool rename_templ_expr) const override; @@ -143,7 +149,8 @@ class heap_domaint:public domaint // Self link on an abstract dynamic object bool self_linkage=false; - explicit heap_row_valuet(const dyn_objt &dyn_obj_):dyn_obj(dyn_obj_) {} + heap_row_valuet(const namespacet &ns, const dyn_objt &dyn_obj_): + row_valuet(ns), dyn_obj(dyn_obj_) {} virtual exprt get_row_expr( const vart &templ_expr_, diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index 5eadf165e..062a091e4 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -164,13 +164,16 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) if(obj.type()!=templ_row.expr.type() && ns.follow(templ_row.expr.type().subtype())!=ns.follow(obj.type())) { - // If types disagree, it's a nondet (solver assigned random value) - if(heap_domain.set_nondet(row, inv)) + if(!is_cprover_symbol(templ_row.expr)) { - improved=true; - debug() << "Set nondet" << eom; + // If types disagree, it's a nondet (solver assigned random value) + if(heap_domain.set_nondet(row, inv)) + { + improved=true; + debug() << "Set nondet" << eom; + } + continue; } - continue; } // Add equality p == &obj @@ -433,3 +436,9 @@ void strategy_solver_heapt::clear_pointing_rows( value[ptr].clear(); } } + +bool strategy_solver_heapt::is_cprover_symbol(const exprt &expr) +{ + return expr.id()==ID_symbol && + id2string(to_symbol_expr(expr).get_identifier()).find("__CPROVER_")==0; +} diff --git a/src/domains/strategy_solver_heap.h b/src/domains/strategy_solver_heap.h index f7a0859a8..56bbc9b84 100644 --- a/src/domains/strategy_solver_heap.h +++ b/src/domains/strategy_solver_heap.h @@ -57,6 +57,8 @@ class strategy_solver_heapt:public strategy_solver_baset heap_domaint::heap_valuet &value); void print_solver_expr(const exprt &expr); + + bool is_cprover_symbol(const exprt &expr); }; From 424cf5ec03016e4bfa6121fb2091424801627614 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 2 Mar 2018 10:01:08 +0100 Subject: [PATCH 168/322] Heap domain: improve transitive row updating When adding paths from other row, remove the other row as a destination if it has been added to another path. When clearing pointed rows, do not clear itself and remove poining row from the pointed_by set. --- src/domains/heap_domain.cpp | 3 +++ src/domains/strategy_solver_heap.cpp | 11 +++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 1456a0066..5762ea790 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -802,8 +802,11 @@ bool heap_domaint::heap_row_valuet::add_all_paths( bool result=false; for(auto &path : other_val.paths) { + bool new_dest = (paths.find(path.destination) == paths.end()); if(add_path(path.destination, dyn_obj)) { + if (!new_dest) + paths.erase(dyn_obj.first); result=true; for(auto &o : path.dyn_objects) { diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index 062a091e4..419f3e441 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -430,11 +430,18 @@ void strategy_solver_heapt::clear_pointing_rows( heap_domaint::heap_row_valuet &row_value= static_cast(value[row]); + std::vector to_remove; for(auto &ptr : row_value.pointed_by) { - debug() << "Clearing row: " << ptr << eom; - value[ptr].clear(); + if (ptr != row) + { + debug() << "Clearing row: " << ptr << eom; + value[ptr].clear(); + to_remove.push_back(ptr); + } } + for (auto &r : to_remove) + row_value.pointed_by.erase(r); } bool strategy_solver_heapt::is_cprover_symbol(const exprt &expr) From b624ec979af06f905ecd925fee2dc3373fc8903a Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 2 Mar 2018 10:03:28 +0100 Subject: [PATCH 169/322] Track allocation sites of dynamic objects in assignmenst and SSA domain This information is used to prevent creation of PHI nodes for dynamic objects for 'if' branches in case where the object allocation occurs in one incoming branch only. --- src/ssa/assignments.cpp | 12 ++++++++ src/ssa/assignments.h | 9 ++++++ src/ssa/ssa_domain.cpp | 67 +++++++++++++++++++++++++++++++++++++++++ src/ssa/ssa_domain.h | 9 +++++- 4 files changed, 96 insertions(+), 1 deletion(-) diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index 556d0d037..0c850edc4 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -33,6 +33,7 @@ void assignmentst::build_assignment_map( { // make sure we have the location in the map assignment_map[it]; + allocation_map[it]; // now fill it if(it->is_assign()) @@ -44,6 +45,17 @@ void assignmentst::build_assignment_map( assign(lhs_symbolic_deref, it, ns); assign_symbolic_rhs(code_assign.rhs(), it, ns); + + if (code_assign.rhs().get_bool("#malloc_result")) + { + exprt object = code_assign.rhs(); + if (object.id() == ID_typecast) + object = to_typecast_expr(object).op(); + if (object.id() == ID_address_of) + object = to_address_of_expr(object).object(); + + allocation_map[it].insert(ssa_objectt(object, ns)); + } } else if(it->is_assert()) { diff --git a/src/ssa/assignments.h b/src/ssa/assignments.h index f316e158f..981355157 100644 --- a/src/ssa/assignments.h +++ b/src/ssa/assignments.h @@ -28,6 +28,8 @@ class assignmentst typedef std::map assignment_mapt; assignment_mapt assignment_map; + assignment_mapt allocation_map; + bool assigns(locationt loc, const ssa_objectt &object) const { assignment_mapt::const_iterator it=assignment_map.find(loc); @@ -43,6 +45,13 @@ class assignmentst return it->second; } + inline const objectst &get_allocations(locationt loc) const + { + auto it = allocation_map.find(loc); + assert(it!=allocation_map.end()); + return it->second; + } + assignmentst( const goto_programt &_goto_program, const namespacet &_ns, diff --git a/src/ssa/ssa_domain.cpp b/src/ssa/ssa_domain.cpp index 3e2d2bb65..005e8efe4 100644 --- a/src/ssa/ssa_domain.cpp +++ b/src/ssa/ssa_domain.cpp @@ -13,6 +13,7 @@ Author: Daniel Kroening, kroening@kroening.com #endif #include +#include #include "ssa_domain.h" @@ -121,6 +122,17 @@ void ssa_domaint::transform( def_entry.def.kind=deft::ASSIGNMENT; def_entry.source=from; } + + auto allocations= + static_cast(ai).assignments.get_allocations(from); + for (auto &alloc : allocations) + { + irep_idt identifier = alloc.get_identifier(); + def_entryt &def_entry=def_map[identifier]; + def_entry.def.loc=from; + def_entry.def.kind=deft::ALLOCATION; + def_entry.source=from; + } } else if(from->is_dead()) { @@ -210,6 +222,41 @@ bool ssa_domaint::merge( } else { + // Do not create PHIs for allocations + if(d_it_a->second.def.kind==deft::ALLOCATION || + d_it_b->second.def.kind==deft::ALLOCATION) + continue; + + // Do not create PHIs for join of PHI and allocation with assignment + auto alloc_def = get_object_allocation_def(id, def_map); + if(alloc_def != def_map.end()) + { + if(d_it_b->second.def.kind!=deft::ASSIGNMENT&& + to->location_number>alloc_def->second.def.loc->location_number&& + to->location_number>d_it_a->second.def.loc->location_number) + { + def_map[id]=d_it_a->second; + def_map[id2string(id).substr(0, id2string(id).find_first_of("."))]= + alloc_def->second; + result=true; + continue; + } + } + alloc_def = get_object_allocation_def(id, b.def_map); + if(alloc_def != b.def_map.end()) + { + if(d_it_a->second.def.kind!=deft::ASSIGNMENT&& + to->location_number>alloc_def->second.def.loc->location_number && + to->location_number>d_it_b->second.def.loc->location_number) + { + def_map[id]=d_it_b->second; + def_map[id2string(id).substr(0, id2string(id).find_first_of("."))]= + alloc_def->second; + result=true; + continue; + } + } + // Arg! Data coming from two sources from two different definitions! // We produce a new phi node. loc_def_mapt &phi_node=phi_nodes[id]; @@ -233,6 +280,26 @@ bool ssa_domaint::merge( return result; } +ssa_domaint::def_mapt::const_iterator ssa_domaint::get_object_allocation_def( + const irep_idt &id, + const ssa_domaint::def_mapt &def_map) +{ + auto def = def_map.find(id); + std::string id_str = id2string(id); + if(def!=def_map.end() && + def->second.def.kind == deft::ASSIGNMENT && + id_str.find("ssa::dynamic_object$")!=std::string::npos) + { + // Check if corresponding dynamic object has been allocated in that branch + std::string dyn_obj_id = id_str.substr(0, id_str.find_first_of(".")); + auto dyn_obj_def = def_map.find(dyn_obj_id); + if(dyn_obj_def!=def_map.end() && + dyn_obj_def->second.def.kind==deft::ALLOCATION) + return dyn_obj_def; + } + return def_map.end(); +} + /*******************************************************************\ Function: ssa_ait::initialize diff --git a/src/ssa/ssa_domain.h b/src/ssa/ssa_domain.h index 679fdbc59..c6767973b 100644 --- a/src/ssa/ssa_domain.h +++ b/src/ssa/ssa_domain.h @@ -20,7 +20,7 @@ class ssa_domaint:public ai_domain_baset struct deft { deft():kind(ASSIGNMENT) { } - typedef enum { INPUT, ASSIGNMENT, PHI } kindt; + typedef enum { INPUT, ASSIGNMENT, PHI, ALLOCATION } kindt; kindt kind; locationt loc; @@ -42,6 +42,7 @@ class ssa_domaint:public ai_domain_baset case deft::INPUT: out << "INPUT"; break; case deft::ASSIGNMENT: out << d.loc->location_number; break; case deft::PHI: out << "PHI" << d.loc->location_number; break; + case deft::ALLOCATION: out << "ALLOC" << d.loc->location_number; break; } return out; } @@ -84,6 +85,12 @@ class ssa_domaint:public ai_domain_baset const ssa_domaint &b, locationt from, locationt to); + +private: + static std::map::const_iterator + get_object_allocation_def( + const irep_idt &id, + const def_mapt &def_map); }; class ssa_ait:public ait From 942511dd68cd6b350f8ae7e8de2b8d1783381ecc Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 2 Mar 2018 10:06:08 +0100 Subject: [PATCH 170/322] For dynamic objects allocated in a loop, add allocation guard to post condition This prevents from getting non-deterministic values of dynamic object fields incoming from other branches (where the dynamic object was not allocated) during analysis. --- src/domains/template_generator_base.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index 0f03b6722..1f4237dc1 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -171,17 +171,32 @@ void template_generator_baset::collect_variables_loop( o_it!=SSA.ssa_objects.objects.end(); o_it++) { - ssa_domaint::phi_nodest::const_iterator p_it= - phi_nodes.find(o_it->get_identifier()); + const std::string id = id2string(o_it->get_identifier()); + ssa_domaint::phi_nodest::const_iterator p_it=phi_nodes.find(id); if(p_it==phi_nodes.end()) // object not modified in this loop continue; + exprt obj_post_guard = post_guard; + // For dynamic objects allocated within the given loop, we need to add + // guard of their allocation + if (id.find("ssa::dynamic_object$") != std::string::npos) + { + std::string obj_id = id.substr(0, id.find_first_of(".")); + auto obj_def = SSA.ssa_analysis[n_it->location].def_map.find(obj_id); + if(obj_def!=SSA.ssa_analysis[n_it->location].def_map.end() && + obj_def->second.def.kind==ssa_domaint::deft::ALLOCATION) + { + obj_post_guard=and_exprt(SSA.guard_symbol(obj_def->second.def.loc), + post_guard); + } + } + symbol_exprt pre_var; get_pre_var(SSA, o_it, n_it, pre_var); exprt init_expr; get_init_expr(SSA, o_it, n_it, init_expr); - add_var(pre_var, pre_guard, post_guard, domaint::LOOP, var_specs); + add_var(pre_var, pre_guard, obj_post_guard, domaint::LOOP, var_specs); #ifdef DEBUG std::cout << "Adding " << from_expr(ns, "", in) << " " << From 5e6503e77743cf3427e9f4852476c5ffa4124b0b Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 2 Mar 2018 10:07:58 +0100 Subject: [PATCH 171/322] Add possibility to use object created in given SSA node at RHS of assignment This is needed for correct RHS concretisation. --- src/ssa/local_ssa.cpp | 31 ++++++++++++++++++------------- src/ssa/local_ssa.h | 3 ++- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 0422ef8a9..7e94396be 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -474,9 +474,10 @@ void local_SSAt::build_transfer(locationt loc) assign_rec(symbolic_deref_lhs, rhs, true_exprt(), loc); assign_rec( deref_lhs, - name(ssa_objectt(symbolic_deref_lhs, ns), OUT, loc), + symbolic_deref_lhs, true_exprt(), - loc); + loc, + true); } else { @@ -1310,7 +1311,8 @@ void local_SSAt::assign_rec( const exprt &lhs, const exprt &rhs, const exprt &guard, - locationt loc) + locationt loc, + bool fresh_rhs) { const typet &type=ns.follow(lhs.type()); @@ -1330,7 +1332,7 @@ void local_SSAt::assign_rec( { member_exprt new_lhs(lhs, it->get_name(), it->type()); member_exprt new_rhs(rhs, it->get_name(), it->type()); - assign_rec(new_lhs, new_rhs, guard, loc); + assign_rec(new_lhs, new_rhs, guard, loc, fresh_rhs); } return; @@ -1346,7 +1348,8 @@ void local_SSAt::assign_rec( collect_iterators_lhs(lhs_object, loc); collect_iterators_rhs(rhs, loc); - exprt ssa_rhs=read_rhs(rhs, loc); + exprt ssa_rhs=fresh_rhs ? name(ssa_objectt(rhs, ns), OUT, loc) + : read_rhs(rhs, loc); const symbol_exprt ssa_symbol=name(lhs_object, OUT, loc); @@ -1359,7 +1362,7 @@ void local_SSAt::assign_rec( const index_exprt &index_expr=to_index_expr(lhs); exprt ssa_array=index_expr.array(); exprt new_rhs=with_exprt(ssa_array, index_expr.index(), rhs); - assign_rec(index_expr.array(), new_rhs, guard, loc); + assign_rec(index_expr.array(), new_rhs, guard, loc, fresh_rhs); } else if(lhs.id()==ID_member) { @@ -1372,14 +1375,14 @@ void local_SSAt::assign_rec( { union_exprt new_rhs( member_expr.get_component_name(), rhs, compound.type()); - assign_rec(member_expr.struct_op(), new_rhs, guard, loc); + assign_rec(member_expr.struct_op(), new_rhs, guard, loc, fresh_rhs); } else if(compound_type.id()==ID_struct) { exprt member_name(ID_member_name); member_name.set(ID_component_name, member_expr.get_component_name()); with_exprt new_rhs(compound, member_name, rhs); - assign_rec(compound, new_rhs, guard, loc); + assign_rec(compound, new_rhs, guard, loc, fresh_rhs); } } else if(lhs.id()==ID_complex_real) @@ -1389,7 +1392,7 @@ void local_SSAt::assign_rec( const complex_typet &complex_type=to_complex_type(op.type()); exprt imag_op=unary_exprt(ID_complex_imag, op, complex_type.subtype()); complex_exprt new_rhs(rhs, imag_op, complex_type); - assign_rec(op, new_rhs, guard, loc); + assign_rec(op, new_rhs, guard, loc, fresh_rhs); } else if(lhs.id()==ID_complex_imag) { @@ -1398,7 +1401,7 @@ void local_SSAt::assign_rec( const complex_typet &complex_type=to_complex_type(op.type()); exprt real_op=unary_exprt(ID_complex_real, op, complex_type.subtype()); complex_exprt new_rhs(real_op, rhs, complex_type); - assign_rec(op, new_rhs, guard, loc); + assign_rec(op, new_rhs, guard, loc, fresh_rhs); } else if(lhs.id()==ID_if) { @@ -1436,7 +1439,8 @@ void local_SSAt::assign_rec( name(guard_symbol(), OBJECT_SELECT, loc)); cond=and_exprt(cond, other_cond); } - exprt new_rhs=if_exprt(cond, rhs, if_expr.true_case()); + exprt orig_rhs = fresh_rhs ? name(ssa_objectt(rhs, ns), OUT, loc) : rhs; + exprt new_rhs=if_exprt(cond, orig_rhs, if_expr.true_case()); assign_rec( if_expr.true_case(), new_rhs, @@ -1447,7 +1451,8 @@ void local_SSAt::assign_rec( if_expr.false_case(), rhs, and_exprt(guard, not_exprt(if_expr.cond())), - loc); + loc, + fresh_rhs); } else if(lhs.id()==ID_byte_extract_little_endian || lhs.id()==ID_byte_extract_big_endian) @@ -1459,7 +1464,7 @@ void local_SSAt::assign_rec( exprt new_rhs=byte_extract_exprt( byte_extract_expr.id(), rhs, byte_extract_expr.offset(), new_lhs.type()); - assign_rec(new_lhs, new_rhs, guard, loc); + assign_rec(new_lhs, new_rhs, guard, loc, fresh_rhs); } else throw "UNKNOWN LHS: "+lhs.id_string(); // NOLINT(*) diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 087fbe32e..316df0366 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -193,7 +193,8 @@ class local_SSAt const exprt &lhs, const exprt &rhs, const exprt &guard, - locationt loc); + locationt loc, + bool fresh_rhs=false); void collect_iterators_rhs(const exprt &expr, locationt loc); void collect_iterators_lhs(const ssa_objectt &object, locationt loc); From 66a12ca1b0f89ab1c2f4ac93279e74cd9d0c1828 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 2 Mar 2018 10:08:48 +0100 Subject: [PATCH 172/322] Copy pointed info to member expression on symbolic dereference --- src/ssa/ssa_pointed_objects.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ssa/ssa_pointed_objects.cpp b/src/ssa/ssa_pointed_objects.cpp index b48671827..b5c51fad1 100644 --- a/src/ssa/ssa_pointed_objects.cpp +++ b/src/ssa/ssa_pointed_objects.cpp @@ -386,6 +386,7 @@ const exprt symbolic_dereference(const exprt &expr, const namespacet &ns) { member_exprt member=to_member_expr(expr); member.compound()=symbolic_dereference(member.compound(), ns); + copy_pointed_info(member, member.compound()); member.set( "#has_symbolic_deref", From 26684c85f25d77ef7841b14946d3ab6946bc04fe Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 2 Mar 2018 10:10:29 +0100 Subject: [PATCH 173/322] Add new test to heap directory This test demonstrates the power of the combination of pointer and interval domains. --- regression/heap/packet_filter/main.c | 79 +++++++++++++++++++++++++ regression/heap/packet_filter/test.desc | 6 ++ 2 files changed, 85 insertions(+) create mode 100644 regression/heap/packet_filter/main.c create mode 100644 regression/heap/packet_filter/test.desc diff --git a/regression/heap/packet_filter/main.c b/regression/heap/packet_filter/main.c new file mode 100644 index 000000000..b95dbe119 --- /dev/null +++ b/regression/heap/packet_filter/main.c @@ -0,0 +1,79 @@ +extern unsigned __VERIFIER_nondet_uint(); +extern int __VERIFIER_nondet_int(); +extern char *__VERIFIER_nondet_charp(); + +#include +#include + +#define LOW 0 +#define HIGH 1 + +typedef struct packet { + unsigned size; + unsigned prio; + char *payload; +} Packet; + +typedef struct packet_list_node { + struct packet packet; + struct packet_list_node *next; +} *Node; + +struct packet_queue { + struct packet_list_node *front; +}; + + +Packet receive() { + Packet packet; + packet.size = __VERIFIER_nondet_uint(); + packet.prio = __VERIFIER_nondet_int() ? LOW : HIGH; + packet.payload = __VERIFIER_nondet_charp(); + return packet; +} + +extern void send(struct packet p); + +void append_to_queue(Packet p, Node *q) { + Node node = malloc(sizeof(*node)); + node->packet = p; + node->next = *q; + *q = node; +} + +void process_prio_queue(Node q) { + for (Node node = q; node != NULL; node = node->next) { + assert(node->packet.prio == HIGH || node->packet.size < 500); + send(node->packet); + } +} + +void process_normal_queue(Node q) { + for (Node node = q; node != NULL; node = node->next) { + assert(node->packet.prio == LOW && node->packet.size >= 500); + send(node->packet); + } +} + +int main() { + Node prio_queue = NULL; + Node normal_queue = NULL; + + while (__VERIFIER_nondet_int()) { + Packet new_packet = receive(); + if (new_packet.size > 0) { + if (new_packet.prio == HIGH) { + append_to_queue(new_packet, &prio_queue); + } else if (new_packet.size < 500) { + append_to_queue(new_packet, &prio_queue); + } else { + append_to_queue(new_packet, &normal_queue); + } + } + } + + process_prio_queue(prio_queue); + process_normal_queue(normal_queue); + + return 0; +} diff --git a/regression/heap/packet_filter/test.desc b/regression/heap/packet_filter/test.desc new file mode 100644 index 000000000..c03cf0e85 --- /dev/null +++ b/regression/heap/packet_filter/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-interval --sympath --inline --no-propagation +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ From 4af058e75ab06999adc7eae6687c98e84326743b Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 6 Mar 2018 08:32:22 +0100 Subject: [PATCH 174/322] For objects allocated in loops, create one concrete and one abstract object The concrete object has "$co" suffix and there is always only one allocated. It is created non-deterministically, but with the condition that no other pointer in the loop points to this object (i.e. it has not been allocated before). --- src/ssa/assignments.cpp | 29 +++++-- src/ssa/local_ssa.cpp | 5 +- src/ssa/malloc_ssa.cpp | 176 ++++++++++++++++++++++++++++++++-------- src/ssa/malloc_ssa.h | 6 +- 4 files changed, 171 insertions(+), 45 deletions(-) diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index 0c850edc4..06ea0673b 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -46,15 +46,32 @@ void assignmentst::build_assignment_map( assign_symbolic_rhs(code_assign.rhs(), it, ns); + // At allocations site, save newly allocated object(s) if (code_assign.rhs().get_bool("#malloc_result")) { - exprt object = code_assign.rhs(); - if (object.id() == ID_typecast) - object = to_typecast_expr(object).op(); - if (object.id() == ID_address_of) - object = to_address_of_expr(object).object(); + exprt alloc_res=code_assign.rhs(); + if(alloc_res.id()==ID_typecast) + alloc_res=to_typecast_expr(alloc_res).op(); + if(alloc_res.id()==ID_if) + { + exprt object=to_if_expr(alloc_res).false_case(); + if(object.id()==ID_address_of) + object=to_address_of_expr(object).object(); + + exprt concrete_object=to_if_expr(alloc_res).true_case(); + if(concrete_object.id()==ID_address_of) + concrete_object=to_address_of_expr(concrete_object).object(); - allocation_map[it].insert(ssa_objectt(object, ns)); + allocation_map[it].insert(ssa_objectt(object, ns)); + allocation_map[it].insert(ssa_objectt(concrete_object, ns)); + } + else + { + exprt object=alloc_res; + if(object.id()==ID_address_of) + object=to_address_of_expr(object).object(); + allocation_map[it].insert(ssa_objectt(object, ns)); + } } } else if(it->is_assert()) diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 7e94396be..117d8a674 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -1861,8 +1861,11 @@ void local_SSAt::build_unknown_objs(locationt loc) const exprt &rhs=code_assign.rhs(); if(rhs.get_bool("#malloc_result")) { - const exprt &addr_of_do= + const exprt &malloc_res= rhs.id()==ID_typecast ? to_typecast_expr(rhs).op() : rhs; + const exprt &addr_of_do= + malloc_res.id()==ID_if ? to_if_expr(malloc_res).false_case() + : malloc_res; const exprt &dyn_obj=to_address_of_expr(addr_of_do).object(); const typet &dyn_type=ns.follow(dyn_obj.type()); diff --git a/src/ssa/malloc_ssa.cpp b/src/ssa/malloc_ssa.cpp index 7727b6f7e..b79d5026d 100644 --- a/src/ssa/malloc_ssa.cpp +++ b/src/ssa/malloc_ssa.cpp @@ -54,6 +54,105 @@ inline static typet c_sizeof_type_rec(const exprt &expr) /*******************************************************************\ +Function: create_dynamic_object + + Inputs: + + Outputs: + + Purpose: Create new dynamic object, insert it into the symbol table + and return its address. + +\*******************************************************************/ + +exprt create_dynamic_object( + const std::string &suffix, + const typet &type, + symbol_tablet &symbol_table, + bool concrete) +{ + symbolt value_symbol; + + value_symbol.base_name="dynamic_object"+suffix; + value_symbol.name="ssa::"+id2string(value_symbol.base_name); + value_symbol.is_lvalue=true; + value_symbol.type=type; + value_symbol.type.set("#dynamic", true); + value_symbol.mode=ID_C; + symbol_table.add(value_symbol); + + address_of_exprt address_of_object; + + if(type.id()==ID_array) + { + address_of_object.type()=pointer_typet(value_symbol.type.subtype()); + index_exprt index_expr(value_symbol.type.subtype()); + index_expr.array()=value_symbol.symbol_expr(); + index_expr.index()=gen_zero(index_type()); + address_of_object.op0()=index_expr; + } + else + { + address_of_object.op0()=value_symbol.symbol_expr(); + if(concrete) + address_of_object.op0().set("#concrete", true); + address_of_object.type()=pointer_typet(value_symbol.type); + } + + return address_of_object; +} + +/*******************************************************************\ + +Function: collect_pointer_vars + + Inputs: + + Outputs: + + Purpose: Collect all variables (symbols and their members) of pointer + type with given pointed type. + +\*******************************************************************/ + +std::vector collect_pointer_vars( + const symbol_tablet &symbol_table, + const typet &pointed_type) +{ + namespacet ns(symbol_table); + std::vector pointers; + forall_symbols(it, symbol_table.symbols) + { + if(ns.follow(it->second.type).id()==ID_struct) + { + for(auto &component : to_struct_type( + ns.follow(it->second.type)).components()) + { + if(component.type().id()==ID_pointer) + { + if(ns.follow(component.type().subtype())==ns.follow(pointed_type)) + { + pointers.push_back( + member_exprt( + it->second.symbol_expr(), component.get_name(), + component.type())); + } + } + } + } + if(it->second.type.id()==ID_pointer) + { + if(ns.follow(it->second.type.subtype())==ns.follow(pointed_type)) + { + pointers.push_back(it->second.symbol_expr()); + } + } + } + return pointers; +} + +/*******************************************************************\ + Function: malloc_ssa Inputs: @@ -67,7 +166,8 @@ Function: malloc_ssa exprt malloc_ssa( const side_effect_exprt &code, const std::string &suffix, - symbol_tablet &symbol_table) + symbol_tablet &symbol_table, + bool alloc_concrete) { if(code.operands().size()!=1) throw "malloc expected to have one operand"; @@ -132,34 +232,38 @@ exprt malloc_ssa( std::cout << "OBJECT_TYPE: " << from_type(ns, "", object_type) << std::endl; #endif - // value - symbolt value_symbol; - - value_symbol.base_name="dynamic_object"+suffix; - value_symbol.name="ssa::"+id2string(value_symbol.base_name); - value_symbol.is_lvalue=true; - value_symbol.type=object_type; - value_symbol.type.set("#dynamic", true); - value_symbol.mode=ID_C; - symbol_table.add(value_symbol); - - address_of_exprt address_of; + auto pointers=collect_pointer_vars(symbol_table, object_type); - if(object_type.id()==ID_array) + exprt object=create_dynamic_object( + suffix, object_type, symbol_table, !alloc_concrete); + exprt result; + if(alloc_concrete) { - address_of.type()=pointer_typet(value_symbol.type.subtype()); - index_exprt index_expr(value_symbol.type.subtype()); - index_expr.array()=value_symbol.symbol_expr(); - index_expr.index()=gen_zero(index_type()); - address_of.op0()=index_expr; + exprt concrete_object=create_dynamic_object( + suffix+"$co", object_type, symbol_table, true); + + // Create nondet symbol + symbolt nondet_symbol; + nondet_symbol.base_name="nondet"+suffix; + nondet_symbol.name="ssa::"+id2string(nondet_symbol.base_name); + nondet_symbol.is_lvalue=true; + nondet_symbol.type=bool_typet(); + nondet_symbol.mode=ID_C; + symbol_table.add(nondet_symbol); + + exprt::operandst pointer_equs; + for(auto &ptr : pointers) + { + pointer_equs.push_back(equal_exprt(ptr, concrete_object)); + } + exprt cond=and_exprt( + nondet_symbol.symbol_expr(), + not_exprt(disjunction(pointer_equs))); + + result=if_exprt(cond, concrete_object, object); } else - { - address_of.op0()=value_symbol.symbol_expr(); - address_of.type()=pointer_typet(value_symbol.type); - } - - exprt result=address_of; + result=object; if(result.type()!=code.type()) result=typecast_exprt(result, code.type()); @@ -187,7 +291,8 @@ static bool replace_malloc_rec( const std::string &suffix, symbol_tablet &symbol_table, const exprt &malloc_size, - unsigned loc_number) + unsigned loc_number, + bool alloc_concrete) { if(expr.id()==ID_side_effect && to_side_effect_expr(expr).get_statement()==ID_malloc) @@ -196,9 +301,8 @@ static bool replace_malloc_rec( expr.op0()=malloc_size; expr=malloc_ssa( - to_side_effect_expr(expr), - "$"+i2string(loc_number)+suffix, - symbol_table); + to_side_effect_expr(expr), "$"+i2string(loc_number)+suffix, symbol_table, + alloc_concrete); return true; } else @@ -206,7 +310,8 @@ static bool replace_malloc_rec( bool result=false; Forall_operands(it, expr) { - if(replace_malloc_rec(*it, suffix, symbol_table, malloc_size, loc_number)) + if(replace_malloc_rec( + *it, suffix, symbol_table, malloc_size, loc_number, alloc_concrete)) result=true; } return result; @@ -227,7 +332,8 @@ Function: replace_malloc bool replace_malloc( goto_modelt &goto_model, - const std::string &suffix) + const std::string &suffix, + bool alloc_concrete) { bool result=false; Forall_goto_functions(f_it, goto_model.goto_functions) @@ -280,11 +386,9 @@ bool replace_malloc( } } if(replace_malloc_rec( - code_assign.rhs(), - suffix, - goto_model.symbol_table, - malloc_size, - i_it->location_number)) + code_assign.rhs(), suffix, goto_model.symbol_table, malloc_size, + i_it->location_number, + alloc_concrete && loop_end!=f_it->second.body.instructions.end())) { result=(loop_end!=f_it->second.body.instructions.end()); } diff --git a/src/ssa/malloc_ssa.h b/src/ssa/malloc_ssa.h index 5470b5835..753dc6e57 100644 --- a/src/ssa/malloc_ssa.h +++ b/src/ssa/malloc_ssa.h @@ -15,11 +15,13 @@ Author: Daniel Kroening, kroening@kroening.com exprt malloc_ssa( const side_effect_exprt &, const std::string &suffix, - symbol_tablet &); + symbol_tablet &, + bool alloc_concrete); bool replace_malloc( goto_modelt &goto_model, - const std::string &suffix); + const std::string &suffix, + bool alloc_concrete); void allow_record_malloc(goto_modelt &goto_model); void allow_record_memleak(goto_modelt &goto_model); From 585925569f07fd65835fe4c397afefbc028f76fa Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 6 Mar 2018 08:37:44 +0100 Subject: [PATCH 175/322] Collect allocation guards of concrete/abstract objects and use them in template These guards are used in the post-condition of template rows of the heap domain that contain members of dynamic objects in the same loop where the object was allocated. This is required to make sure that the object is analysed only when it is created. --- src/domains/template_generator_base.cpp | 3 ++ src/ssa/local_ssa.cpp | 47 +++++++++++++++++++++++++ src/ssa/local_ssa.h | 5 +++ 3 files changed, 55 insertions(+) diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index 1f4237dc1..a3e5fe80a 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -189,6 +189,9 @@ void template_generator_baset::collect_variables_loop( { obj_post_guard=and_exprt(SSA.guard_symbol(obj_def->second.def.loc), post_guard); + auto alloc_guard=SSA.allocation_guards.find(obj_id); + if(alloc_guard!=SSA.allocation_guards.end()) + obj_post_guard=and_exprt(obj_post_guard, alloc_guard->second); } } diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 117d8a674..d328af57e 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -460,6 +460,9 @@ void local_SSAt::build_transfer(locationt loc) id2string(code_assign.rhs().get(ID_identifier)). find(TEMPLATE_PREFIX)!=std::string::npos) return; + // build allocation guards map + collect_allocation_guards(code_assign, loc); + exprt deref_lhs=dereference(code_assign.lhs(), loc); exprt deref_rhs=dereference(code_assign.rhs(), loc); @@ -2088,3 +2091,47 @@ exprt local_SSAt::concretise_symbolic_deref_rhs( all_symbolic_deref_defined(symbolic_deref_rhs, ns, loc)? symbolic_deref_rhs:deref_rhs; } + +/********************************************************************\ + +Function: local_SSAt::collect_allocation_guards + + Inputs: + + Outputs: + + Purpose: Collect allocation guards for the given location + +\*******************************************************************/ + +void local_SSAt::collect_allocation_guards( + const code_assignt &assign, + locationt loc) +{ + if(!assign.rhs().get_bool("#malloc_result")) + return; + + exprt rhs=assign.rhs(); + if(rhs.id()==ID_typecast) + rhs=to_typecast_expr(rhs).op(); + if(rhs.id()==ID_if) + { + const if_exprt &malloc_res=to_if_expr(rhs); + assert(malloc_res.true_case().id()==ID_address_of); + assert(malloc_res.false_case().id()==ID_address_of); + + const exprt &object=to_address_of_expr(malloc_res.false_case()).object(); + const exprt &co_object=to_address_of_expr(malloc_res.true_case()).object(); + assert(object.id()==ID_symbol && co_object.id()==ID_symbol); + + std::string co_object_id=id2string( + to_symbol_expr(co_object).get_identifier()); + std::string object_id=id2string(to_symbol_expr(object).get_identifier()); + allocation_guards.emplace( + to_symbol_expr(co_object).get_identifier(), + read_rhs(malloc_res.cond(), loc)); + allocation_guards.emplace( + to_symbol_expr(object).get_identifier(), + read_rhs(not_exprt(malloc_res.cond()), loc)); + } +} diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 316df0366..dc2d6ab16 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -154,6 +154,9 @@ class local_SSAt typedef std::list dyn_obj_assignst; std::map dyn_obj_assigns; + // Map dynamic object names to guards of their allocation + std::map allocation_guards; + bool has_function_calls() const; const namespacet &ns; @@ -278,6 +281,8 @@ class local_SSAt void build_assertions(locationt loc); void build_unknown_objs(locationt loc); + void collect_allocation_guards(const code_assignt &assign, locationt loc); + // custom templates void collect_custom_templates(); replace_mapt template_newvars; From 7c5cada8148d8ae52b0390b056f6b8d197b24f83 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 6 Mar 2018 08:40:26 +0100 Subject: [PATCH 176/322] Perform some pointer safety checks on concrete objects only Modify assertions for dereferencing deallocated objects to perform checks on concrete objects only. Since a concrete object allocated within a loop has a non-deterministic position within the abstract object, this approach is sound. --- src/ssa/local_ssa.cpp | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index d328af57e..0ef28d6e3 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -715,10 +715,36 @@ void local_SSAt::build_assertions(locationt loc) { if(loc->is_assert()) { - const exprt deref_rhs=dereference(loc->guard, loc); + exprt assert=loc->guard; + if(assert.id()==ID_not && assert.op0().id()==ID_equal && + assert.op0().op1().id()==ID_pointer_object && + assert.op0().op1().op0().id()==ID_symbol) + { + std::string id=id2string( + to_symbol_expr(assert.op0().op1().op0()).get_identifier()); + if(id.find("__CPROVER_deallocated")!=std::string::npos) + { + const exprt &dealloc_symbol=assert.op0().op1().op0(); + exprt::operandst d; + for(auto &global : assignments.ssa_objects.globals) + { + if(global.get_expr().get_bool("#concrete")) + { + d.push_back( + equal_exprt( + dealloc_symbol, typecast_exprt( + address_of_exprt(global.symbol_expr()), + dealloc_symbol.type()))); + } + } + assert=implies_exprt(disjunction(d), assert); + } + } + + const exprt deref_rhs=dereference(assert, loc); collect_iterators_rhs(deref_rhs, loc); - const exprt rhs=concretise_symbolic_deref_rhs(loc->guard, ns, loc); + const exprt rhs=concretise_symbolic_deref_rhs(assert, ns, loc); exprt c=read_rhs(rhs, loc); exprt g=guard_symbol(loc); (--nodes.end())->assertions.push_back(implies_exprt(g, c)); From b3eff2a8ecb173719f606471839bd27068dc5c03 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 6 Mar 2018 08:45:36 +0100 Subject: [PATCH 177/322] Heap domain: allow template row to contain a pair of variables as expression A pair is stored as an "and" expression. This is used to track dependency between a pair of pointer variables. --- src/domains/heap_domain.cpp | 89 ++++++++-- src/domains/heap_domain.h | 4 + src/domains/strategy_solver_heap.cpp | 238 +++++++++++++++++---------- src/domains/strategy_solver_heap.h | 4 + 4 files changed, 242 insertions(+), 93 deletions(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 5762ea790..0297a304b 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -130,6 +130,36 @@ void heap_domaint::add_template_row( /*******************************************************************\ +Function: heap_domaint::add_template_row_pair + + Inputs: var_spec Variable specification + + Outputs: + + Purpose: Add a template row with a pair of variables as expression. + +\*******************************************************************/ + +void heap_domaint::add_template_row_pair( + const domaint::var_spect &var_spec1, + const domaint::var_spect &var_spec2, + const typet &pointed_type) +{ + const exprt var_pair=and_exprt(var_spec1.var, var_spec2.var); + + templ.push_back(template_rowt()); + template_rowt &templ_row=templ.back(); + templ_row.expr=var_pair; + templ_row.pre_guard=var_spec1.pre_guard; + templ_row.post_guard=var_spec1.post_guard; + templ_row.aux_expr=var_spec1.aux_expr; + templ_row.kind=var_spec1.kind; + + templ_row.mem_kind=STACK; +} + +/*******************************************************************\ + Function: heap_domaint::to_pre_constraints Inputs: @@ -460,8 +490,17 @@ void heap_domaint::project_on_vars( { const template_rowt &templ_row=templ[row]; - if(!vars.empty() && vars.find(templ_row.expr)==vars.end()) - continue; + if(!vars.empty()) + { + if(templ_row.expr.id()==ID_and) + { + if(vars.find(templ_row.expr.op0())==vars.end() && + vars.find(templ_row.expr.op1())==vars.end()) + continue; + } + else if(vars.find(templ_row.expr)==vars.end()) + continue; + } const row_valuet &row_val=val[row]; if(templ_row.kind==LOOP) @@ -552,6 +591,36 @@ int heap_domaint::get_symbol_loc(const exprt &expr) /*******************************************************************\ +Function: ptr_equality + + Inputs: Pointer expression (variable) + Value (object or address) of the pointer + + Outputs: Equality between pointer and its value with correct types + + Purpose: + +\*******************************************************************/ + +const exprt ptr_equality( + const exprt &ptr_expr, + const exprt &ptr_value, + const namespacet &ns) +{ + exprt value; + if(ptr_expr.type()==ptr_value.type()) + value=ptr_value; + else if(ns.follow(ptr_expr.type().subtype())==ns.follow(ptr_value.type())) + value=address_of_exprt(ptr_value); + else + value=typecast_exprt( + address_of_exprt(ptr_value), + ns.follow(ptr_expr.type())); + return equal_exprt(ptr_expr, value); +} + +/*******************************************************************\ + Function: heap_domaint::stack_row_valuet::get_row_expr Inputs: templ_expr Template expression @@ -578,15 +647,15 @@ exprt heap_domaint::stack_row_valuet::get_row_expr( exprt::operandst result; for(const exprt &pt : points_to) { - exprt value; - if (templ_expr.type() == pt.type()) - value = pt; - else if (ns.follow(templ_expr.type().subtype()) == ns.follow(pt.type())) - value = address_of_exprt(pt); + if(templ_expr.id()==ID_and) + { + result.push_back( + and_exprt( + ptr_equality(templ_expr.op0(), pt.op0(), ns), + ptr_equality(templ_expr.op1(), pt.op1(), ns))); + } else - value=typecast_exprt(address_of_exprt(pt), - ns.follow(templ_expr.type())); - result.push_back(equal_exprt(templ_expr, value)); + result.push_back(ptr_equality(templ_expr, pt, ns)); } return disjunction(result); } diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index c99120cea..e0c83cc01 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -307,6 +307,10 @@ class heap_domaint:public domaint void make_template(const var_specst &var_specs, const namespacet &ns); void add_template_row(const var_spect &var_spec, const typet &pointed_type); + void add_template_row_pair( + const var_spect &var_spec1, + const var_spect &var_spec2, + const typet &pointed_type); // Initializing functions void bind_iterators( diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index 419f3e441..9b42527fe 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -116,117 +116,103 @@ bool strategy_solver_heapt::iterate(invariantt &_inv) const heap_domaint::template_rowt &templ_row=heap_domain.templ[row]; - int actual_loc=heap_domain.get_symbol_loc(templ_row.expr); - - exprt pointer=strategy_value_exprs[row]; - exprt value=solver.get(pointer); - // Value from the solver must be converted into an expression - exprt ptr_value=heap_domain.value_to_ptr_exprt(value); - const exprt loop_guard=to_and_expr( heap_domain.templ[row].pre_guard).op1(); find_symbolic_path(loop_guards, loop_guard); - if((ptr_value.id()==ID_constant && - to_constant_expr(ptr_value).get_value()==ID_NULL) || - ptr_value.id()==ID_symbol) - { - // Add equality p == NULL or p == symbol - if(heap_domain.add_points_to(row, inv, ptr_value)) - { - improved=true; - const std::string info= - templ_row.mem_kind==heap_domaint::STACK ? "points to " - : "path to "; - debug() << "Add " << info << from_expr(ns, "", ptr_value) << eom; - } - } - else if(ptr_value.id()==ID_address_of) + if(templ_row.expr.id()==ID_and) { - // Template row pointer points to the heap (p = &obj) - debug() << from_expr(ns, "", ptr_value) << eom; - assert(ptr_value.id()==ID_address_of); - if(to_address_of_expr(ptr_value).object().id()!=ID_symbol) + // Handle template row with a pair of variables in the expression + exprt points_to1=get_points_to_dest( + strategy_value_exprs[row].op0(), templ_row.expr.op0()); + exprt points_to2=get_points_to_dest( + strategy_value_exprs[row].op1(), templ_row.expr.op1()); + + if(points_to1.is_nil() || points_to2.is_nil()) { - // If solver did not return address of a symbol, it is considered - // as nondet value. if(heap_domain.set_nondet(row, inv)) { improved=true; debug() << "Set nondet" << eom; } - continue; } - - symbol_exprt obj=to_symbol_expr( - to_address_of_expr(ptr_value).object()); - - if(obj.type()!=templ_row.expr.type() && - ns.follow(templ_row.expr.type().subtype())!=ns.follow(obj.type())) + else { - if(!is_cprover_symbol(templ_row.expr)) + if(heap_domain.add_points_to( + row, inv, and_exprt(points_to1, points_to2))) { - // If types disagree, it's a nondet (solver assigned random value) - if(heap_domain.set_nondet(row, inv)) - { - improved=true; - debug() << "Set nondet" << eom; - } - continue; + improved=true; + const std::string info= + templ_row.mem_kind==heap_domaint::STACK ? "points to " + : "path to "; + debug() << "Add " << info + << from_expr(ns, "", and_exprt(points_to1, points_to2)) + << eom; } } + continue; + } - // Add equality p == &obj - if(heap_domain.add_points_to(row, inv, obj)) + int actual_loc=heap_domain.get_symbol_loc(templ_row.expr); + + exprt points_to=get_points_to_dest( + strategy_value_exprs[row], templ_row.expr); + + if(points_to.is_nil()) + { + if(heap_domain.set_nondet(row, inv)) + { + improved=true; + debug() << "Set nondet" << eom; + } + continue; + } + else + { + if(heap_domain.add_points_to(row, inv, points_to)) { improved=true; const std::string info= templ_row.mem_kind==heap_domaint::STACK ? "points to " : "path to "; - debug() << "Add " << info << from_expr(ns, "", obj) << eom; + debug() << "Add " << info << from_expr(ns, "", points_to) << eom; } + } - // If the template row is of heap kind, we need to ensure the - // transitive closure over the set of all paths - if(templ_row.mem_kind==heap_domaint::HEAP && - obj.type().get_bool("#dynamic") && - id2string(obj.get_identifier()).find("$unknown")== - std::string::npos) + // If the template row is of heap kind, we need to ensure the + // transitive closure over the set of all paths + if(templ_row.mem_kind==heap_domaint::HEAP && + points_to.type().get_bool("#dynamic") && + points_to.id()==ID_symbol && + id2string(to_symbol_expr(points_to).get_identifier()).find( + "$unknown")== + std::string::npos) + { + // Find row with corresponding member field of the pointed object + // (obj.member) + int member_val_index; + member_val_index= + find_member_row( + points_to, + templ_row.member, + actual_loc, + templ_row.kind); + if(member_val_index>=0 && !inv[member_val_index].nondet) { - // Find row with corresponding member field of the pointed object - // (obj.member) - int member_val_index; - member_val_index= - find_member_row( - obj, - templ_row.member, - actual_loc, - templ_row.kind); - if(member_val_index>=0 && !inv[member_val_index].nondet) + // Add all paths from obj.next to p + if(heap_domain.add_transitivity( + row, + static_cast(member_val_index), + inv)) { - // Add all paths from obj.next to p - if(heap_domain.add_transitivity( - row, - static_cast(member_val_index), - inv)) - { - improved=true; - const std::string expr_str= - from_expr(ns, "", heap_domain.templ[member_val_index].expr); - debug() << "Add all paths: " << expr_str - << ", through: " << from_expr(ns, "", obj) << eom; - } + improved=true; + const std::string expr_str= + from_expr(ns, "", heap_domain.templ[member_val_index].expr); + debug() << "Add all paths: " << expr_str + << ", through: " << from_expr(ns, "", points_to) << eom; } } } - else - { - if(heap_domain.set_nondet(row, inv)) - { - improved=true; - debug() << "Set nondet" << eom; - } - } // Recursively update all rows that are dependent on this row if(templ_row.mem_kind==heap_domaint::HEAP) @@ -313,7 +299,8 @@ int strategy_solver_heapt::find_member_row( templ_row.mem_kind==heap_domaint::HEAP) { std::string id=id2string(to_symbol_expr(templ_row.expr).get_identifier()); - if(id.find(obj_id)!=std::string::npos) + if(id.find(obj_id)!=std::string::npos && + id.find_first_of(".")==obj_id.length()) { int loc=heap_domain.get_symbol_loc(templ_row.expr); if(loc>max_loc && @@ -423,6 +410,18 @@ void strategy_solver_heapt::initialize( } } +/*******************************************************************\ + +Function: strategy_solver_heapt::clear_pointing_rows + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + void strategy_solver_heapt::clear_pointing_rows( const heap_domaint::rowt &row, heap_domaint::heap_valuet &value) @@ -444,8 +443,81 @@ void strategy_solver_heapt::clear_pointing_rows( row_value.pointed_by.erase(r); } +/*******************************************************************\ + +Function: strategy_solver_heapt::is_cprover_symbol + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + bool strategy_solver_heapt::is_cprover_symbol(const exprt &expr) { return expr.id()==ID_symbol && id2string(to_symbol_expr(expr).get_identifier()).find("__CPROVER_")==0; } + +/*******************************************************************\ + +Function: strategy_solver_heapt::get_points_to_dest + + Inputs: + + Outputs: + + Purpose: Get an address where the given pointer points to in the current + solver iteration. Returns nil_exprt if the value of the pointer + is nondet. + +\*******************************************************************/ + +const exprt strategy_solver_heapt::get_points_to_dest( + const exprt &pointer, + const exprt &templ_row_expr) +{ + exprt value=solver.get(pointer); + // Value from the solver must be converted into an expression + exprt ptr_value=heap_domain.value_to_ptr_exprt(value); + + if((ptr_value.id()==ID_constant && + to_constant_expr(ptr_value).get_value()==ID_NULL) || + ptr_value.id()==ID_symbol) + { + // Add equality p == NULL or p == symbol + return ptr_value; + } + else if(ptr_value.id()==ID_address_of) + { + // Template row pointer points to the heap (p = &obj) + debug() << from_expr(ns, "", ptr_value) << eom; + assert(ptr_value.id()==ID_address_of); + if(to_address_of_expr(ptr_value).object().id()!=ID_symbol) + { + // If solver did not return address of a symbol, it is considered + // as nondet value. + return nil_exprt(); + } + + symbol_exprt obj=to_symbol_expr( + to_address_of_expr(ptr_value).object()); + + if(obj.type()!=templ_row_expr.type() && + ns.follow(templ_row_expr.type().subtype())!=ns.follow(obj.type())) + { + if(!is_cprover_symbol(templ_row_expr)) + { + // If types disagree, it's a nondet (solver assigned random value) + return nil_exprt(); + } + } + + // Add equality p == &obj + return obj; + } + else + return nil_exprt(); +} diff --git a/src/domains/strategy_solver_heap.h b/src/domains/strategy_solver_heap.h index 56bbc9b84..5ec0000a9 100644 --- a/src/domains/strategy_solver_heap.h +++ b/src/domains/strategy_solver_heap.h @@ -43,6 +43,10 @@ class strategy_solver_heapt:public strategy_solver_baset std::set loop_guards; std::set updated_rows; + const exprt get_points_to_dest( + const exprt &pointer, + const exprt &templ_row_expr); + int find_member_row( const exprt &obj, const irep_idt &member, From cf4c5e3689dbb664aed259497a4c31193c40a296 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 6 Mar 2018 08:47:25 +0100 Subject: [PATCH 178/322] Heap domain: track dependency between __CPROVER_deallocated and other pointers This is useful to prove that a deallocated object is never dereferenced. Since the assertions checks for this property are done on conrete objects only, we need to prove that once a concrete object was deallocated, it cannot be reached in the next iteration. --- src/domains/heap_domain.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index 0297a304b..c594a47fc 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -76,6 +76,25 @@ void heap_domaint::make_template( { const typet &pointed_type=ns.follow(var.type().subtype()); add_template_row(v, pointed_type); + + if(var.id()==ID_symbol && + id2string(to_symbol_expr(var).get_identifier()).find( + "__CPROVER_deallocated")!=std::string::npos) + { + for(const var_spect &v_other : var_specs) + { + if(!(v_other.var.type().id()==ID_pointer && v_other.kind==LOOP && + v_other.pre_guard==v.pre_guard)) + continue; + + if(v_other.var.id()==ID_symbol && + id2string(to_symbol_expr(v_other.var).get_identifier()).find( + "__CPROVER_")!=std::string::npos) + continue; + + add_template_row_pair(v, v_other, pointed_type); + } + } } } } From 5ba86f455153f1f7c67284482e39e87d0753a683 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 6 Mar 2018 08:51:23 +0100 Subject: [PATCH 179/322] Allow recording free --- src/2ls/2ls_parse_options.cpp | 10 ++++-- src/ssa/malloc_ssa.cpp | 63 +++++++++++++++++++++++++++++++++++ src/ssa/malloc_ssa.h | 1 + 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 94bb89c5b..214f42c75 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -1232,12 +1232,16 @@ bool twols_parse_optionst::process_goto_program( goto_model.goto_functions.compute_loop_numbers(); // Replace malloc - dynamic_memory_detected=replace_malloc(goto_model, ""); + dynamic_memory_detected=replace_malloc( + goto_model, "", options.get_bool_option("pointer-check")); // Allow recording of mallocs and memory leaks - if (options.get_bool_option("pointer-check")) + if(options.get_bool_option("pointer-check")) + { allow_record_malloc(goto_model); - if (options.get_bool_option("memory-leak-check")) + allow_record_free(goto_model); + } + if(options.get_bool_option("memory-leak-check")) allow_record_memleak(goto_model); // remove loop heads from function entries diff --git a/src/ssa/malloc_ssa.cpp b/src/ssa/malloc_ssa.cpp index b79d5026d..a9baa516c 100644 --- a/src/ssa/malloc_ssa.cpp +++ b/src/ssa/malloc_ssa.cpp @@ -398,6 +398,23 @@ bool replace_malloc( return result; } +/*******************************************************************\ + +Function: set_var_always_to_true + + Inputs: goto_model + name_cond Function returning true for names of variables + to be set. + + Outputs: + + Purpose: Set undefined boolean variable to true. + Finds declaration of a variable whose name matches the given + condition and adds an instruction var = TRUE after + the declaration. + +\*******************************************************************/ + void set_var_always_to_true(goto_modelt &goto_model, bool (*name_cond)(std::string &)) { @@ -427,6 +444,18 @@ void set_var_always_to_true(goto_modelt &goto_model, } } +/*******************************************************************\ + +Function: allow_record_malloc + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + void allow_record_malloc(goto_modelt &goto_model) { set_var_always_to_true( @@ -437,6 +466,18 @@ void allow_record_malloc(goto_modelt &goto_model) }); } +/*******************************************************************\ + +Function: allow_record_memleak + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + void allow_record_memleak(goto_modelt &goto_model) { set_var_always_to_true( @@ -446,3 +487,25 @@ void allow_record_memleak(goto_modelt &goto_model) name.find("::record_may_leak")!=std::string::npos; }); } + +/*******************************************************************\ + +Function: allow_record_free + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void allow_record_free(goto_modelt &goto_model) +{ + set_var_always_to_true( + goto_model, [](std::string &name) + { + return name.find("free::")!=std::string::npos && + name.find("::record")!=std::string::npos; + }); +} diff --git a/src/ssa/malloc_ssa.h b/src/ssa/malloc_ssa.h index 753dc6e57..17df4bbb5 100644 --- a/src/ssa/malloc_ssa.h +++ b/src/ssa/malloc_ssa.h @@ -25,5 +25,6 @@ bool replace_malloc( void allow_record_malloc(goto_modelt &goto_model); void allow_record_memleak(goto_modelt &goto_model); +void allow_record_free(goto_modelt &goto_model); #endif From 1a282c0224f3acb0d317447e2f8fe8ee7f516a20 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 6 Mar 2018 08:51:50 +0100 Subject: [PATCH 180/322] Do not use pointer access paths in the heap domain It shows that tracking the points-to relation is enough since we use abstract objects and a path is expressed by field of an abstract object pointing to the same object. --- src/domains/heap_domain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index c594a47fc..f2fc57af8 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -136,7 +136,7 @@ void heap_domaint::add_template_row( if(identifier.find("."+id2string(component.get_name()))!= std::string::npos) { - templ_row.mem_kind=HEAP; +// templ_row.mem_kind=HEAP; templ_row.member=component.get_name(); std::string var_id=id2string(to_symbol_expr(var).get_identifier()); From 7ade32c290c5230d7ba2f54af9b9f1d163719e64 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 6 Mar 2018 08:54:03 +0100 Subject: [PATCH 181/322] Make unwinder to handle "object-select" guard --- src/ssa/unwindable_local_ssa.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ssa/unwindable_local_ssa.cpp b/src/ssa/unwindable_local_ssa.cpp index e53155c7f..da31f1b7a 100644 --- a/src/ssa/unwindable_local_ssa.cpp +++ b/src/ssa/unwindable_local_ssa.cpp @@ -350,6 +350,8 @@ irep_idt unwindable_local_SSAt::get_ssa_name( pos1+=2; else if(s.substr(pos1+1, 2)=="ls") pos1+=2; + else if(s.substr(pos1+1, 2)=="os") + pos1+=2; else if(s.substr(pos1+1, 3)=="phi") pos1+=3; else if((pos2==pos1+13) && (s.substr(pos1+1, 12)=="return_value")) From 8705014d52be94d96ec0bc45b0774788b3837067 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 6 Mar 2018 09:06:58 +0100 Subject: [PATCH 182/322] Add tests for memory safety Tests check pointer safety for linked lists. --- regression/memsafety/Makefile | 20 ++++++++++ regression/memsafety/built_from_end/main.c | 38 ++++++++++++++++++ regression/memsafety/built_from_end/test.desc | 6 +++ regression/memsafety/simple_false/main.c | 39 +++++++++++++++++++ regression/memsafety/simple_false/test.desc | 7 ++++ regression/memsafety/simple_true/main.c | 38 ++++++++++++++++++ regression/memsafety/simple_true/test.desc | 6 +++ 7 files changed, 154 insertions(+) create mode 100644 regression/memsafety/Makefile create mode 100644 regression/memsafety/built_from_end/main.c create mode 100644 regression/memsafety/built_from_end/test.desc create mode 100644 regression/memsafety/simple_false/main.c create mode 100644 regression/memsafety/simple_false/test.desc create mode 100644 regression/memsafety/simple_true/main.c create mode 100644 regression/memsafety/simple_true/test.desc diff --git a/regression/memsafety/Makefile b/regression/memsafety/Makefile new file mode 100644 index 000000000..34cd734b9 --- /dev/null +++ b/regression/memsafety/Makefile @@ -0,0 +1,20 @@ +default: tests.log + +FLAGS = --verbosity 10 + +test: + @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" + +tests.log: ../test.pl + @../test.pl -p -c "../../../src/2ls/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/memsafety/built_from_end/main.c b/regression/memsafety/built_from_end/main.c new file mode 100644 index 000000000..f3e3fbf11 --- /dev/null +++ b/regression/memsafety/built_from_end/main.c @@ -0,0 +1,38 @@ +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +extern int __VERIFIER_nondet_int(); +/* + * Simple example: build a list with only 1s and finally a 0 (arbitrary length); + * afterwards, go through it and check if the list does have the correct form, and in particular + * finishes by a 0. + */ +#include + +void exit(int s) { + _EXIT: goto _EXIT; +} + +typedef struct node { + int h; + struct node *n; +} *List; + +int main() { + /* Build a list of the form 1->...->1->0 */ + List t; + List p = 0; + while (__VERIFIER_nondet_int()) { + t = (List) malloc(sizeof(struct node)); + if (t == 0) exit(1); + t->h = 1; + t->n = p; + p = t; + } + while (p!=0) { + t = p->n; + free(p); + p = t; + } + +} + diff --git a/regression/memsafety/built_from_end/test.desc b/regression/memsafety/built_from_end/test.desc new file mode 100644 index 000000000..02a269a04 --- /dev/null +++ b/regression/memsafety/built_from_end/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-interval --inline --sympath --pointer-check --no-assertions +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/memsafety/simple_false/main.c b/regression/memsafety/simple_false/main.c new file mode 100644 index 000000000..ee661872a --- /dev/null +++ b/regression/memsafety/simple_false/main.c @@ -0,0 +1,39 @@ +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +extern int __VERIFIER_nondet_int(); + +#include + +void exit(int s) { + _EXIT: goto _EXIT; +} + +typedef struct node { + int h; + struct node *n; +} *List; + +int main() { + /* Build a list of the form 1->...->1->0 */ + List a = (List) malloc(sizeof(struct node)); + if (a == 0) exit(1); + a->n = 0; + List t; + List p = a; + while (__VERIFIER_nondet_int()) { + t = (List) malloc(sizeof(struct node)); + if (t == 0) exit(1); + t->n = 0; + p->n = t; + p = p->n; + } + p->n = a; + p = a; + while (p!=0) { + t = p->n; + free(p); + p = t; + } + return 0; +} + diff --git a/regression/memsafety/simple_false/test.desc b/regression/memsafety/simple_false/test.desc new file mode 100644 index 000000000..0812ec27e --- /dev/null +++ b/regression/memsafety/simple_false/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--heap-interval --sympath --inline --pointer-check --k-induction +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +\[main.pointer_dereference.23\] dereference failure: deallocated dynamic object in \*p: FAILURE diff --git a/regression/memsafety/simple_true/main.c b/regression/memsafety/simple_true/main.c new file mode 100644 index 000000000..79d7b5e74 --- /dev/null +++ b/regression/memsafety/simple_true/main.c @@ -0,0 +1,38 @@ +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +extern int __VERIFIER_nondet_int(); + +#include + +void exit(int s) { + _EXIT: goto _EXIT; +} + +typedef struct node { + int h; + struct node *n; +} *List; + +int main() { + /* Build a list of the form 1->...->1->0 */ + List a = (List) malloc(sizeof(struct node)); + if (a == 0) exit(1); + a->n = 0; + List t; + List p = a; + while (__VERIFIER_nondet_int()) { + t = (List) malloc(sizeof(struct node)); + if (t == 0) exit(1); + t->n = 0; + p->n = t; + p = p->n; + } + p = a; + while (p!=0) { + t = p->n; + free(p); + p = t; + } + return 0; +} + diff --git a/regression/memsafety/simple_true/test.desc b/regression/memsafety/simple_true/test.desc new file mode 100644 index 000000000..02a269a04 --- /dev/null +++ b/regression/memsafety/simple_true/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-interval --inline --sympath --pointer-check --no-assertions +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ From 18b148ba7c5c9d0ed1e2a6d88a9a1d0a73758272 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 6 Mar 2018 15:11:53 +0100 Subject: [PATCH 183/322] Add another example to heap that uses domain combination --- regression/heap/process_queue/main.c | 69 +++++++++++++++++++++++++ regression/heap/process_queue/test.desc | 6 +++ 2 files changed, 75 insertions(+) create mode 100644 regression/heap/process_queue/main.c create mode 100644 regression/heap/process_queue/test.desc diff --git a/regression/heap/process_queue/main.c b/regression/heap/process_queue/main.c new file mode 100644 index 000000000..62ae5fe3b --- /dev/null +++ b/regression/heap/process_queue/main.c @@ -0,0 +1,69 @@ +extern int __VERIFIER_nondet_int(); + +#include +#include + +#define MAX_PROC 1000 + +struct process_node { + int process_id; + int time_to_wait; + + struct process_node *next; +}; + +extern void run_process(int id); + +void append_to_queue(struct process_node *n, struct process_node **q) { + n->next = *q; + *q = n; +} + +struct process_node *choose_next(struct process_node **q) { + struct process_node *node = *q; + struct process_node *prev = NULL; + struct process_node *result = NULL; + while (node != NULL) { + int node_time = node->time_to_wait; + if (node_time == 1) { + result = node; + if (prev == NULL) + *q = node->next; + else + prev->next = node->next; + } else { + node->time_to_wait = node_time - 1; + } + prev = node; + node = node->next; + } + return result; +} + +void check_queue(struct process_node *q) { + for (struct process_node *n = q; n != NULL; n = n->next) + assert(n->time_to_wait >= 1); +} + + +int main() { + struct process_node *queue = NULL; + int next_time = 1; + + while (__VERIFIER_nondet_int()) { + if (next_time < MAX_PROC && __VERIFIER_nondet_int()) { + int new_id = __VERIFIER_nondet_int(); + + struct process_node *new_process = malloc(sizeof(*new_process)); + new_process->process_id = __VERIFIER_nondet_int(); + new_process->time_to_wait = next_time++; + append_to_queue(new_process, &queue); + } else if (next_time > 1){ + struct process_node *p = choose_next(&queue); + next_time--; + run_process(p->process_id); + } + + check_queue(queue); + } +} diff --git a/regression/heap/process_queue/test.desc b/regression/heap/process_queue/test.desc new file mode 100644 index 000000000..c03cf0e85 --- /dev/null +++ b/regression/heap/process_queue/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-interval --sympath --inline --no-propagation +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ From 0be684ce3395b232f80a041dfece8b6c95459cc1 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 6 Mar 2018 16:54:40 +0100 Subject: [PATCH 184/322] Split assignments having the same symbolic dereference object on both sides. --- src/2ls/2ls_parse_options.cpp | 2 ++ src/2ls/2ls_parse_options.h | 1 + src/2ls/preprocessing_util.cpp | 60 ++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 214f42c75..df4876823 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -1244,6 +1244,8 @@ bool twols_parse_optionst::process_goto_program( if(options.get_bool_option("memory-leak-check")) allow_record_memleak(goto_model); + split_same_symbolic_object_assignments(goto_model); + // remove loop heads from function entries remove_loops_in_entry(goto_model); diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index 612e35f5c..29337a18a 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -183,6 +183,7 @@ class twols_parse_optionst: void add_dynamic_object_symbols( const ssa_heap_analysist &heap_analysis, goto_modelt &goto_model); + void split_same_symbolic_object_assignments(goto_modelt &goto_model); }; #endif diff --git a/src/2ls/preprocessing_util.cpp b/src/2ls/preprocessing_util.cpp index b31229afb..76fd6d1b9 100644 --- a/src/2ls/preprocessing_util.cpp +++ b/src/2ls/preprocessing_util.cpp @@ -626,3 +626,63 @@ void twols_parse_optionst::add_dynamic_object_symbols( } } } + +/*******************************************************************\ + +Function: twols_parse_optionst::split_same_symbolic_object_assignments + + Inputs: + + Outputs: + + Purpose: Split assignments that have same symbolic dereference object + on both sides into two separate assignments. + +\*******************************************************************/ + +void twols_parse_optionst::split_same_symbolic_object_assignments( + goto_modelt &goto_model) +{ + const namespacet ns(goto_model.symbol_table); + unsigned counter=0; + Forall_goto_functions(f_it, goto_model.goto_functions) + { + Forall_goto_program_instructions(i_it, f_it->second.body) + { + if(i_it->is_assign()) + { + code_assignt &assign=to_code_assign(i_it->code); + auto lhs_sym_deref=symbolic_dereference(assign.lhs(), ns); + if((lhs_sym_deref.id()==ID_symbol || lhs_sym_deref.id()==ID_member) + && has_symbolic_deref(lhs_sym_deref)) + { + const exprt &lhs_symbol=lhs_sym_deref.id()==ID_member + ? to_member_expr(lhs_sym_deref).compound() + : lhs_sym_deref; + auto rhs_sym_deref=symbolic_dereference(assign.rhs(), ns); + + std::set rhs_symbols; + find_symbols(rhs_sym_deref, rhs_symbols); + + if(rhs_symbols.find(to_symbol_expr(lhs_symbol))!=rhs_symbols.end()) + { + symbolt tmp_symbol; + tmp_symbol.type=assign.lhs().type(); + tmp_symbol.name="$symderef_tmp"+i2string(counter++); + tmp_symbol.base_name=tmp_symbol.name; + tmp_symbol.pretty_name=tmp_symbol.name; + + goto_model.symbol_table.add(tmp_symbol); + + auto new_assign=f_it->second.body.insert_after(i_it); + new_assign->make_assignment(); + new_assign->code=code_assignt( + assign.lhs(), tmp_symbol.symbol_expr()); + + assign.lhs()=tmp_symbol.symbol_expr(); + } + } + } + } + } +} From 06e0128dac0c41d144a6a283e1523e75b5bde6cf Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 6 Mar 2018 16:56:33 +0100 Subject: [PATCH 185/322] Update process_queue test This version of the test did not previously work because of a bug related to symbolic dereference objects occuring on both sides of an assignment. --- regression/heap/process_queue/main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/regression/heap/process_queue/main.c b/regression/heap/process_queue/main.c index 62ae5fe3b..52f5e782b 100644 --- a/regression/heap/process_queue/main.c +++ b/regression/heap/process_queue/main.c @@ -24,15 +24,14 @@ struct process_node *choose_next(struct process_node **q) { struct process_node *prev = NULL; struct process_node *result = NULL; while (node != NULL) { - int node_time = node->time_to_wait; - if (node_time == 1) { + if (node->time_to_wait == 1) { result = node; if (prev == NULL) *q = node->next; else prev->next = node->next; } else { - node->time_to_wait = node_time - 1; + node->time_to_wait--; } prev = node; node = node->next; From 0ce8606b65c25766725f0126f5177d1a3582e903 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Wed, 7 Mar 2018 14:45:53 +0100 Subject: [PATCH 186/322] Fix bug in splitting assignments having same symbolic deref on both sides The bug was related to finding the symbol at LHS (since there may be multiple chained members and we need to get to the root object). --- src/2ls/preprocessing_util.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/2ls/preprocessing_util.cpp b/src/2ls/preprocessing_util.cpp index 76fd6d1b9..2cecd55b7 100644 --- a/src/2ls/preprocessing_util.cpp +++ b/src/2ls/preprocessing_util.cpp @@ -656,15 +656,15 @@ void twols_parse_optionst::split_same_symbolic_object_assignments( if((lhs_sym_deref.id()==ID_symbol || lhs_sym_deref.id()==ID_member) && has_symbolic_deref(lhs_sym_deref)) { - const exprt &lhs_symbol=lhs_sym_deref.id()==ID_member - ? to_member_expr(lhs_sym_deref).compound() - : lhs_sym_deref; + while(lhs_sym_deref.id()==ID_member) + lhs_sym_deref=to_member_expr(lhs_sym_deref).compound(); + auto rhs_sym_deref=symbolic_dereference(assign.rhs(), ns); std::set rhs_symbols; find_symbols(rhs_sym_deref, rhs_symbols); - if(rhs_symbols.find(to_symbol_expr(lhs_symbol))!=rhs_symbols.end()) + if(rhs_symbols.find(to_symbol_expr(lhs_sym_deref))!=rhs_symbols.end()) { symbolt tmp_symbol; tmp_symbol.type=assign.lhs().type(); From 42afc71b0524369e28be4c474aae546749dd4ec7 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 15 Mar 2018 16:05:12 +0100 Subject: [PATCH 187/322] Symbolic paths: set loop-select guard to true only if the loop head is reachable Loop guards collected in the SSA form are pairs (loop-select and loop head guards). When checking the solver for symbolic path, both guards must be true to set the appropriate loop-select guard in the sympath. --- src/domains/heap_interval_sympath_domain.h | 2 +- src/domains/strategy_solver_base.cpp | 19 ++++++++++--------- src/domains/strategy_solver_base.h | 2 +- src/domains/strategy_solver_heap.h | 2 +- src/ssa/local_ssa.cpp | 5 ++++- src/ssa/local_ssa.h | 2 +- 6 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/domains/heap_interval_sympath_domain.h b/src/domains/heap_interval_sympath_domain.h index 5a3fee8fc..d695a23dc 100644 --- a/src/domains/heap_interval_sympath_domain.h +++ b/src/domains/heap_interval_sympath_domain.h @@ -29,7 +29,7 @@ class heap_interval_sympath_domaint:public domaint { exprt::operandst false_loop_guards; for(auto &g : SSA.loop_guards) - false_loop_guards.push_back(not_exprt(g)); + false_loop_guards.push_back(not_exprt(g.first)); no_loops_path=conjunction(false_loop_guards); } diff --git a/src/domains/strategy_solver_base.cpp b/src/domains/strategy_solver_base.cpp index f82dbb7e8..c43d17b86 100644 --- a/src/domains/strategy_solver_base.cpp +++ b/src/domains/strategy_solver_base.cpp @@ -22,20 +22,21 @@ Function: strategy_solver_baset::find_symbolic_path \*******************************************************************/ void strategy_solver_baset::find_symbolic_path( - std::set &loop_guards, + std::set> &loop_guards, const exprt ¤t_guard) { - for(const symbol_exprt &guard : loop_guards) + for(const auto &guard : loop_guards) { - if(guard==current_guard) + if(guard.first==current_guard) { - symbolic_path[guard]=true; + symbolic_path[guard.first]=true; continue; } - exprt guard_value=solver.get(guard); - if(guard_value.is_true()) - symbolic_path[guard]=true; - else if(guard_value.is_false()) - symbolic_path[guard]=false; + exprt ls_guard_value=solver.get(guard.first); + exprt lh_guard_value=solver.get(guard.second); + if(ls_guard_value.is_true() && lh_guard_value.is_true()) + symbolic_path[guard.first]=true; + else if(ls_guard_value.is_false()) + symbolic_path[guard.first]=false; } } diff --git a/src/domains/strategy_solver_base.h b/src/domains/strategy_solver_base.h index 375e8a19b..7915b5ef9 100644 --- a/src/domains/strategy_solver_base.h +++ b/src/domains/strategy_solver_base.h @@ -50,7 +50,7 @@ class strategy_solver_baset:public messaget unsigned solver_calls; void find_symbolic_path( - std::set &loop_guards, + std::set> &loop_guards, const exprt ¤t_guard=nil_exprt()); }; diff --git a/src/domains/strategy_solver_heap.h b/src/domains/strategy_solver_heap.h index 5ec0000a9..4007eded5 100644 --- a/src/domains/strategy_solver_heap.h +++ b/src/domains/strategy_solver_heap.h @@ -40,7 +40,7 @@ class strategy_solver_heapt:public strategy_solver_baset protected: heap_domaint &heap_domain; - std::set loop_guards; + std::set> loop_guards; std::set updated_rows; const exprt get_points_to_dest( diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 0ef28d6e3..1b19c1d6e 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -390,7 +390,10 @@ void local_SSAt::build_phi_nodes(locationt loc) const locationt &iloc=get_location(incoming_it->first); exprt incoming_value=name(*o_it, LOOP_BACK, iloc); exprt incoming_select=name(guard_symbol(), LOOP_SELECT, iloc); - loop_guards.insert(to_symbol_expr(incoming_select)); + loop_guards.insert( + std::make_pair( + to_symbol_expr(incoming_select), + to_symbol_expr(guard_symbol(loc)))); if(rhs.is_nil()) // first rhs=incoming_value; diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index dc2d6ab16..55b899797 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -244,7 +244,7 @@ class local_SSAt // Collect all loop_guards that will represent symbolic paths used in heap // domain - var_sett loop_guards; + std::set> loop_guards; void get_globals( locationt loc, From ebb2d97f15db17db990ab0dcb1229b3f9aa5c198 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 16 Mar 2018 07:42:11 +0100 Subject: [PATCH 188/322] Remove dead GOTO instructions GOTO instructions having "false" as guard are removed since some of them were backwards jumps treated as loops. --- src/2ls/2ls_parse_options.cpp | 6 +++--- src/2ls/2ls_parse_options.h | 1 + src/2ls/preprocessing_util.cpp | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index df4876823..dc3c6e315 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -1264,14 +1264,14 @@ bool twols_parse_optionst::process_goto_program( filter_assertions(goto_model); #endif - if(options.get_bool_option("constant-propagation") && - !(options.get_bool_option("competition-mode") && - dynamic_memory_detected)) + if(options.get_bool_option("constant-propagation")) { status() << "Constant Propagation" << eom; propagate_constants(goto_model); } + remove_dead_goto(goto_model); + // if we aim to cover, replace // all assertions by false to prevent simplification if(cmdline.isset("cover-assertions")) diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index 29337a18a..ec41357ec 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -184,6 +184,7 @@ class twols_parse_optionst: const ssa_heap_analysist &heap_analysis, goto_modelt &goto_model); void split_same_symbolic_object_assignments(goto_modelt &goto_model); + void remove_dead_goto(goto_modelt &goto_model); }; #endif diff --git a/src/2ls/preprocessing_util.cpp b/src/2ls/preprocessing_util.cpp index 2cecd55b7..9759ff7de 100644 --- a/src/2ls/preprocessing_util.cpp +++ b/src/2ls/preprocessing_util.cpp @@ -686,3 +686,18 @@ void twols_parse_optionst::split_same_symbolic_object_assignments( } } } + +void twols_parse_optionst::remove_dead_goto(goto_modelt &goto_model) +{ + Forall_goto_functions(f_it, goto_model.goto_functions) + { + Forall_goto_program_instructions(i_it, f_it->second.body) + { + if (i_it->is_goto()) + { + if (i_it->guard.is_false()) + i_it->make_skip(); + } + } + } +} From 56210f3bf596d5cc6832495a17028038bea99a80 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 16 Mar 2018 12:25:02 +0100 Subject: [PATCH 189/322] Remove dead GOTO instruction only for backwards goto --- src/2ls/preprocessing_util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/2ls/preprocessing_util.cpp b/src/2ls/preprocessing_util.cpp index 9759ff7de..2e1c07b50 100644 --- a/src/2ls/preprocessing_util.cpp +++ b/src/2ls/preprocessing_util.cpp @@ -693,7 +693,7 @@ void twols_parse_optionst::remove_dead_goto(goto_modelt &goto_model) { Forall_goto_program_instructions(i_it, f_it->second.body) { - if (i_it->is_goto()) + if (i_it->is_backwards_goto()) { if (i_it->guard.is_false()) i_it->make_skip(); From 1fdd369897dcf67dadf02c6acc8522cdaf7ecb68 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 20 Mar 2018 15:33:45 +0100 Subject: [PATCH 190/322] Better verification of free safety for multiple frees within a loop Previously, we set free::record to true, which in case of multiple frees in a loop caused just the last free to be recorded into the invariant. Now, we let free::record to be undefined, but instead update template rows for __CPROVER_deallocated only if one of free::record in the loop is true. --- src/2ls/2ls_parse_options.cpp | 2 +- src/domains/template_generator_base.cpp | 28 +++++++++++++++++++++++++ src/domains/template_generator_base.h | 5 +++++ src/ssa/local_ssa.cpp | 18 ++++++++++++++++ src/ssa/local_ssa.h | 3 +++ 5 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index dc3c6e315..cd6abf560 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -1239,7 +1239,7 @@ bool twols_parse_optionst::process_goto_program( if(options.get_bool_option("pointer-check")) { allow_record_malloc(goto_model); - allow_record_free(goto_model); +// allow_record_free(goto_model); } if(options.get_bool_option("memory-leak-check")) allow_record_memleak(goto_model); diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index a3e5fe80a..3b679f315 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -195,6 +195,16 @@ void template_generator_baset::collect_variables_loop( } } + if (id.find("__CPROVER_deallocated") != std::string::npos) + { + auto record_frees = collect_record_frees(SSA, n_it->loophead, n_it); + exprt::operandst d; + for (auto &r : record_frees) + d.push_back(equal_exprt(r, true_exprt())); + if (!d.empty()) + obj_post_guard = and_exprt(obj_post_guard, disjunction(d)); + } + symbol_exprt pre_var; get_pre_var(SSA, o_it, n_it, pre_var); exprt init_expr; @@ -832,3 +842,21 @@ void template_generator_baset::filter_heap_interval_domain() } } } + +std::vector template_generator_baset::collect_record_frees( + const local_SSAt &SSA, + local_SSAt::nodest::const_iterator loop_begin, + local_SSAt::nodest::const_iterator loop_end) +{ + std::vector result; + for (auto &node : SSA.nodes) + { + if(node.location->location_number>loop_begin->location->location_number && + node.location->location_numberlocation->location_number && + node.record_free.is_not_nil()) + { + result.push_back(SSA.read_lhs(node.record_free, node.location)); + } + } + return result; +} diff --git a/src/domains/template_generator_base.h b/src/domains/template_generator_base.h index 50b3fff03..1c42a6c0c 100644 --- a/src/domains/template_generator_base.h +++ b/src/domains/template_generator_base.h @@ -71,6 +71,11 @@ class template_generator_baset:public messaget const local_SSAt &SSA, bool forward); + std::vector collect_record_frees( + const local_SSAt &SSA, + local_SSAt::nodest::const_iterator loop_begin, + local_SSAt::nodest::const_iterator loop_end); + void filter_template_domain(); void filter_equality_domain(); void filter_heap_domain(); diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 1b19c1d6e..6d685a639 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -58,6 +58,7 @@ void local_SSAt::build_SSA() build_assertions(i_it); build_function_call(i_it); build_unknown_objs(i_it); + collect_record_frees(i_it); } // collect custom templates in loop heads @@ -2164,3 +2165,20 @@ void local_SSAt::collect_allocation_guards( read_rhs(not_exprt(malloc_res.cond()), loc)); } } + +void local_SSAt::collect_record_frees(local_SSAt::locationt loc) +{ + if (loc->is_decl()) + { + const exprt &symbol = to_code_decl(loc->code).symbol(); + if (symbol.id() != ID_symbol) + return; + + std::string id = id2string(to_symbol_expr(symbol).get_identifier()); + if(id.find("free::")!=std::string::npos && + id.find("::record")!=std::string::npos) + { + (--nodes.end())->record_free = symbol; + } + } +} diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 55b899797..86eb4c087 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -96,6 +96,8 @@ class local_SSAt std::list::iterator loophead; // link to loop head node // otherwise points to nodes.end() + exprt record_free = nil_exprt(); + void output(std::ostream &, const namespacet &) const; inline bool empty() const @@ -282,6 +284,7 @@ class local_SSAt void build_unknown_objs(locationt loc); void collect_allocation_guards(const code_assignt &assign, locationt loc); + void collect_record_frees(locationt loc); // custom templates void collect_custom_templates(); From d04098e4001e7b8d76113869bb330c3b32522ac1 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 5 Apr 2018 07:59:20 +0200 Subject: [PATCH 191/322] Create new regression directory with benchmark for SAS 2018 paper --- regression/sas18/Makefile | 20 +++++++ .../{heap => sas18}/packet_filter/main.c | 0 .../{heap => sas18}/packet_filter/test.desc | 0 .../{heap => sas18}/process_queue/main.c | 0 .../{heap => sas18}/process_queue/test.desc | 0 regression/sas18/quick_sort_split/main.c | 60 +++++++++++++++++++ regression/sas18/quick_sort_split/test.desc | 6 ++ regression/sas18/running_example/main.c | 32 ++++++++++ regression/sas18/running_example/test.desc | 6 ++ regression/sas18/shared_mem1/main.c | 48 +++++++++++++++ regression/sas18/shared_mem1/test.desc | 6 ++ regression/sas18/shared_mem2/main.c | 45 ++++++++++++++ regression/sas18/shared_mem2/test.desc | 6 ++ 13 files changed, 229 insertions(+) create mode 100644 regression/sas18/Makefile rename regression/{heap => sas18}/packet_filter/main.c (100%) rename regression/{heap => sas18}/packet_filter/test.desc (100%) rename regression/{heap => sas18}/process_queue/main.c (100%) rename regression/{heap => sas18}/process_queue/test.desc (100%) create mode 100644 regression/sas18/quick_sort_split/main.c create mode 100644 regression/sas18/quick_sort_split/test.desc create mode 100644 regression/sas18/running_example/main.c create mode 100644 regression/sas18/running_example/test.desc create mode 100644 regression/sas18/shared_mem1/main.c create mode 100644 regression/sas18/shared_mem1/test.desc create mode 100644 regression/sas18/shared_mem2/main.c create mode 100644 regression/sas18/shared_mem2/test.desc diff --git a/regression/sas18/Makefile b/regression/sas18/Makefile new file mode 100644 index 000000000..34cd734b9 --- /dev/null +++ b/regression/sas18/Makefile @@ -0,0 +1,20 @@ +default: tests.log + +FLAGS = --verbosity 10 + +test: + @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" + +tests.log: ../test.pl + @../test.pl -p -c "../../../src/2ls/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/heap/packet_filter/main.c b/regression/sas18/packet_filter/main.c similarity index 100% rename from regression/heap/packet_filter/main.c rename to regression/sas18/packet_filter/main.c diff --git a/regression/heap/packet_filter/test.desc b/regression/sas18/packet_filter/test.desc similarity index 100% rename from regression/heap/packet_filter/test.desc rename to regression/sas18/packet_filter/test.desc diff --git a/regression/heap/process_queue/main.c b/regression/sas18/process_queue/main.c similarity index 100% rename from regression/heap/process_queue/main.c rename to regression/sas18/process_queue/main.c diff --git a/regression/heap/process_queue/test.desc b/regression/sas18/process_queue/test.desc similarity index 100% rename from regression/heap/process_queue/test.desc rename to regression/sas18/process_queue/test.desc diff --git a/regression/sas18/quick_sort_split/main.c b/regression/sas18/quick_sort_split/main.c new file mode 100644 index 000000000..2079e9965 --- /dev/null +++ b/regression/sas18/quick_sort_split/main.c @@ -0,0 +1,60 @@ +extern int __VERIFIER_nondet_int(); + +#include +#include + +#define LOW -1 +#define HIGH 1 + +struct node { + int expected_list; + int value; + struct node *next; +}; + +void append_to_list(struct node **list, int val, int exp) { + struct node *node = malloc(sizeof(*node)); + node->next = *list; + node->value = val; + node->expected_list = exp; + *list = node; +} + +struct node *create_list() { + struct node *list = NULL; + while (__VERIFIER_nondet_int()) { + int v = __VERIFIER_nondet_int(); + if (v < 0) + append_to_list(&list, v, LOW); + else + append_to_list(&list, v, HIGH); + } + return list; +} + +int main() { + struct node *list = create_list(); + + struct node *low = NULL; + struct node *high = NULL; + + // Split list into low and high + struct node *p = list; + while (p) { + struct node *l = p->value >= 0 ? high : low; + struct node *next = p->next; + p->next = l; + l = p; + p = next; + } + + // Check that low and high contain expected elements + while (low) { + assert(low->expected_list == LOW); + low = low->next; + } + while (high) { + assert(high->expected_list == HIGH); + high = high->next; + } +} diff --git a/regression/sas18/quick_sort_split/test.desc b/regression/sas18/quick_sort_split/test.desc new file mode 100644 index 000000000..c03cf0e85 --- /dev/null +++ b/regression/sas18/quick_sort_split/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-interval --sympath --inline --no-propagation +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/running_example/main.c b/regression/sas18/running_example/main.c new file mode 100644 index 000000000..0ff9fc4b9 --- /dev/null +++ b/regression/sas18/running_example/main.c @@ -0,0 +1,32 @@ +extern int __VERIFIER_nondet_int(); + +#include + +typedef struct node { + int val; + struct node *next; +} Node; + +int main() { + Node *p, *list = malloc(sizeof(*list)); + list->next = NULL; + list->val = 10; + while (__VERIFIER_nondet_int()) { + int x; + __CPROVER_assume(x >= 10 && x <= 20); + p = malloc(sizeof(*p)); + list->next = p; + p->next = NULL; + p->val = x; + list = p; + } + + while (1) { + for (p = list; p!= NULL; p = p->next) { + assert(p->val <= 20 && p->val >= 10); + if (p->val < 20) p->val++; + else p->val /= 2; + } + } + +} diff --git a/regression/sas18/running_example/test.desc b/regression/sas18/running_example/test.desc new file mode 100644 index 000000000..c03cf0e85 --- /dev/null +++ b/regression/sas18/running_example/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-interval --sympath --inline --no-propagation +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/shared_mem1/main.c b/regression/sas18/shared_mem1/main.c new file mode 100644 index 000000000..4df22d2ac --- /dev/null +++ b/regression/sas18/shared_mem1/main.c @@ -0,0 +1,48 @@ +extern int __VERIFIER_nondet_int(); + +#include +#include + +struct mem { + int val; +}; + +struct list_node { + int x; + struct mem *mem; + struct list_node *next; +}; + +int main() { + struct mem *m = malloc(sizeof(*m)); + m->val = 100; + + struct list_node *head = malloc(sizeof(*head)); + head->x = 1; + head->mem = m; + head->next = head; + + struct list_node *list = head; + + while (__VERIFIER_nondet_int()) { + int x; + if (x > 0 && x < 10) { + struct list_node *n = malloc(sizeof(*n)); + n->x = x; + n->mem = m; + n->next = head; + list->next = n; + } + } + + list = head; + while (list) { + if (list->mem->val <= 100) + list->mem->val += list->x; + else + list->mem->val -= list->x; + list = list->next; + + assert(m->val > 90 && m->val < 110); + } +} diff --git a/regression/sas18/shared_mem1/test.desc b/regression/sas18/shared_mem1/test.desc new file mode 100644 index 000000000..c03cf0e85 --- /dev/null +++ b/regression/sas18/shared_mem1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-interval --sympath --inline --no-propagation +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/shared_mem2/main.c b/regression/sas18/shared_mem2/main.c new file mode 100644 index 000000000..08a27e3a7 --- /dev/null +++ b/regression/sas18/shared_mem2/main.c @@ -0,0 +1,45 @@ +extern int __VERIFIER_nondet_int(); + +#include +#include + +struct mem { + int val; +}; + +struct list_node { + int x; + struct mem *mem; + struct list_node *next; +}; + +int main() { + struct mem *m = malloc(sizeof(*m)); + m->val = 0; + + struct list_node *head = malloc(sizeof(*head)); + head->x = 1; + head->mem = m; + head->next = head; + + struct list_node *list = head; + + while (__VERIFIER_nondet_int()) { + int x; + if (x > 0 && x < 10) { + struct list_node *n = malloc(sizeof(*n)); + n->x = x; + n->mem = m; + n->next = head; + list->next = n; + } + } + + list = head; + while (m->val < 100) { + if (list->mem->val + list->x <= 100) + list->mem->val += list->x; + list = list->next; + } + assert(m->val == 100); +} diff --git a/regression/sas18/shared_mem2/test.desc b/regression/sas18/shared_mem2/test.desc new file mode 100644 index 000000000..c03cf0e85 --- /dev/null +++ b/regression/sas18/shared_mem2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-interval --sympath --inline --no-propagation +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ From d6428b5e119ac9ad4d33dd8c9fe5988ed7b35cc0 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 9 Apr 2018 11:43:16 +0200 Subject: [PATCH 192/322] Add combination of heap and zones domain Currently, this is a part of heap-interval domain. This should be refactored to heap-polyhedra domain in future. --- src/2ls/2ls_parse_options.cpp | 9 +++++++++ src/2ls/2ls_parse_options.h | 3 ++- src/domains/heap_interval_domain.cpp | 16 ++++++++-------- src/domains/heap_interval_domain.h | 18 ++++++++++++++---- src/domains/heap_interval_sympath_domain.h | 6 ++++-- src/domains/ssa_analyzer.cpp | 3 ++- src/domains/strategy_solver_heap_interval.cpp | 6 +++--- src/domains/strategy_solver_heap_interval.h | 2 +- .../strategy_solver_heap_interval_sympath.cpp | 17 ++++++++--------- src/domains/template_generator_base.cpp | 10 +++++++--- src/domains/tpolyhedra_domain.cpp | 5 +++++ 11 files changed, 63 insertions(+), 32 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index cd6abf560..1681807b0 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -209,6 +209,12 @@ void twols_parse_optionst::get_command_line_options(optionst &options) if(cmdline.isset("sympath")) options.set_option("sympath", true); } + else if(cmdline.isset("heap-zones")) + { + options.set_option("heap-zones", true); + if(cmdline.isset("sympath")) + options.set_option("sympath", true); + } else { if(cmdline.isset("zones")) @@ -518,6 +524,8 @@ int twols_parse_optionst::doit() status() << "Using heap domain" << eom; else if(options.get_bool_option("heap-interval")) status() << "Using heap domain with interval domain for values" << eom; + else if(options.get_bool_option("heap-zones")) + status() << "Using heap domain with zones domain for values" << eom; else { if(options.get_bool_option("intervals")) @@ -1757,6 +1765,7 @@ void twols_parse_optionst::help() " --zones use zone domain\n" " --octagons use octagon domain\n" " --heap-interval use heap domain with interval domain for values\n" // NOLINT(*) + " --heap-zones use heap domain with zones domain for values\n" // NOLINT(*) " --sympath compute invariant for each symbolic path (only usable with --heap-interval switch)" // NOLINT(*) " --enum-solver use solver based on model enumeration\n" " --binsearch-solver use solver based on binary search\n" diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index ec41357ec..771a6ac52 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -37,7 +37,8 @@ class optionst; "(version)" \ "(i386-linux)(i386-macos)(i386-win32)(win32)(winx64)(gcc)" \ "(ppc-macos)(unsigned-char)" \ - "(havoc)(intervals)(zones)(octagons)(equalities)(heap)(heap-interval)"\ + "(havoc)(intervals)(zones)(octagons)(equalities)"\ + "(heap)(heap-interval)(heap-zones)"\ "(sympath)" \ "(enum-solver)(binsearch-solver)(arrays)"\ "(string-abstraction)(no-arch)(arch):(floatbv)(fixedbv)" \ diff --git a/src/domains/heap_interval_domain.cpp b/src/domains/heap_interval_domain.cpp index e38d89332..27edf9e06 100644 --- a/src/domains/heap_interval_domain.cpp +++ b/src/domains/heap_interval_domain.cpp @@ -25,7 +25,7 @@ void heap_interval_domaint::initialize(domaint::valuet &value) heap_interval_valuet &v=static_cast(value); heap_domain.initialize(v.heap_value); - interval_domain.initialize(v.interval_value); + polyhedra_domain.initialize(v.interval_value); } /*******************************************************************\ @@ -49,7 +49,7 @@ void heap_interval_domaint::output_value( static_cast(value); heap_domain.output_value(out, v.heap_value, ns); - interval_domain.output_value(out, v.interval_value, ns); + polyhedra_domain.output_value(out, v.interval_value, ns); } /*******************************************************************\ @@ -69,7 +69,7 @@ void heap_interval_domaint::output_domain( const namespacet &ns) const { heap_domain.output_domain(out, ns); - interval_domain.output_domain(out, ns); + polyhedra_domain.output_domain(out, ns); } /*******************************************************************\ @@ -94,7 +94,7 @@ void heap_interval_domaint::project_on_vars( exprt heap_result; heap_domain.project_on_vars(v.heap_value, vars, heap_result); exprt interval_result; - interval_domain.project_on_vars(v.interval_value, vars, interval_result); + polyhedra_domain.project_on_vars(v.interval_value, vars, interval_result); result=heap_result; if(interval_result!=true_exprt()) @@ -116,7 +116,7 @@ void heap_interval_domaint::restrict_to_sympath( const symbolic_patht &sympath) { heap_domain.restrict_to_sympath(sympath); - interval_domain.restrict_to_sympath(sympath); + polyhedra_domain.restrict_to_sympath(sympath); } /*******************************************************************\ @@ -133,7 +133,7 @@ Function: heap_interval_domaint::clear_aux_symbols void heap_interval_domaint::clear_aux_symbols() { heap_domain.clear_aux_symbols(); - interval_domain.clear_aux_symbols(); + polyhedra_domain.clear_aux_symbols(); } /*******************************************************************\ @@ -151,7 +151,7 @@ void heap_interval_domaint::eliminate_sympaths( const std::vector &sympaths) { heap_domain.eliminate_sympaths(sympaths); - interval_domain.eliminate_sympaths(sympaths); + polyhedra_domain.eliminate_sympaths(sympaths); } /*******************************************************************\ @@ -168,5 +168,5 @@ Function: heap_interval_domaint::undo_restriction void heap_interval_domaint::undo_restriction() { heap_domain.undo_restriction(); - interval_domain.undo_restriction(); + polyhedra_domain.undo_restriction(); } diff --git a/src/domains/heap_interval_domain.h b/src/domains/heap_interval_domain.h index cf6179f6f..485628b66 100644 --- a/src/domains/heap_interval_domain.h +++ b/src/domains/heap_interval_domain.h @@ -16,19 +16,29 @@ Author: Viktor Malik class heap_interval_domaint:public domaint { public: + enum polyhedra_kindt { + INTERVAL, ZONES, OCTAGONS + }; + heap_domaint heap_domain; - tpolyhedra_domaint interval_domain; + tpolyhedra_domaint polyhedra_domain; heap_interval_domaint( unsigned int _domain_number, replace_mapt &_renaming_map, const var_specst &var_specs, - const namespacet &ns): + const namespacet &ns, + const polyhedra_kindt polyhedra_kind): domaint(_domain_number, _renaming_map, ns), heap_domain(_domain_number, _renaming_map, var_specs, ns), - interval_domain(_domain_number, _renaming_map, ns) + polyhedra_domain(_domain_number, _renaming_map, ns) { - interval_domain.add_interval_template(var_specs, ns); + if (polyhedra_kind == INTERVAL) + polyhedra_domain.add_interval_template(var_specs, ns); + else if (polyhedra_kind == ZONES) { + polyhedra_domain.add_difference_template(var_specs, ns); + polyhedra_domain.add_interval_template(var_specs, ns); + } } class heap_interval_valuet:public valuet diff --git a/src/domains/heap_interval_sympath_domain.h b/src/domains/heap_interval_sympath_domain.h index d695a23dc..e6ba7ec1a 100644 --- a/src/domains/heap_interval_sympath_domain.h +++ b/src/domains/heap_interval_sympath_domain.h @@ -23,9 +23,11 @@ class heap_interval_sympath_domaint:public domaint unsigned int _domain_number, replace_mapt &_renaming_map, const var_specst &var_specs, - const local_SSAt &SSA): + const local_SSAt &SSA, + const heap_interval_domaint::polyhedra_kindt polyhedra_kind): domaint(_domain_number, _renaming_map, SSA.ns), - heap_interval_domain(_domain_number, _renaming_map, var_specs, SSA.ns) + heap_interval_domain( + _domain_number, _renaming_map, var_specs, SSA.ns, polyhedra_kind) { exprt::operandst false_loop_guards; for(auto &g : SSA.loop_guards) diff --git a/src/domains/ssa_analyzer.cpp b/src/domains/ssa_analyzer.cpp index 5b048f561..352fe8a6d 100644 --- a/src/domains/ssa_analyzer.cpp +++ b/src/domains/ssa_analyzer.cpp @@ -120,7 +120,8 @@ void ssa_analyzert::operator()( template_generator); result=new heap_domaint::heap_valuet(); } - else if(template_generator.options.get_bool_option("heap-interval")) + else if(template_generator.options.get_bool_option("heap-interval") + || template_generator.options.get_bool_option("heap-zones")) { if(template_generator.options.get_bool_option("sympath")) { diff --git a/src/domains/strategy_solver_heap_interval.cpp b/src/domains/strategy_solver_heap_interval.cpp index 1932f3852..cf3112e93 100644 --- a/src/domains/strategy_solver_heap_interval.cpp +++ b/src/domains/strategy_solver_heap_interval.cpp @@ -32,7 +32,7 @@ bool strategy_solver_heap_intervalt::iterate( // Run one iteration of heap solver in the context of invariant from // the interval solver solver.new_context(); - solver << heap_interval_domain.interval_domain.to_pre_constraints( + solver << heap_interval_domain.polyhedra_domain.to_pre_constraints( inv.interval_value); bool heap_improved=heap_solver.iterate(inv.heap_value); solver.pop_context(); @@ -41,7 +41,7 @@ bool strategy_solver_heap_intervalt::iterate( { // If heap part was improved, restrict interval part to found symbolic path symbolic_path=heap_solver.symbolic_path; - heap_interval_domain.interval_domain.restrict_to_sympath(symbolic_path); + heap_interval_domain.polyhedra_domain.restrict_to_sympath(symbolic_path); } // Run one interation of interval solver in the context of invariant from @@ -52,7 +52,7 @@ bool strategy_solver_heap_intervalt::iterate( solver.pop_context(); if(heap_improved) - heap_interval_domain.interval_domain.undo_restriction(); + heap_interval_domain.polyhedra_domain.undo_restriction(); return heap_improved || interval_improved; } diff --git a/src/domains/strategy_solver_heap_interval.h b/src/domains/strategy_solver_heap_interval.h index bb6c1baca..61b2b9cda 100644 --- a/src/domains/strategy_solver_heap_interval.h +++ b/src/domains/strategy_solver_heap_interval.h @@ -34,7 +34,7 @@ class strategy_solver_heap_intervalt:public strategy_solver_baset precondition, message_handler, template_generator), - interval_solver(heap_interval_domain.interval_domain, _solver, SSA.ns) + interval_solver(heap_interval_domain.polyhedra_domain, _solver, SSA.ns) { } diff --git a/src/domains/strategy_solver_heap_interval_sympath.cpp b/src/domains/strategy_solver_heap_interval_sympath.cpp index f940883fd..4f05e0f04 100644 --- a/src/domains/strategy_solver_heap_interval_sympath.cpp +++ b/src/domains/strategy_solver_heap_interval_sympath.cpp @@ -6,7 +6,7 @@ Author: Viktor Malik \*******************************************************************/ -// #define DEBUG + #define DEBUG #include "strategy_solver_heap_interval_sympath.h" @@ -53,7 +53,7 @@ bool strategy_solver_heap_interval_sympatht::iterate( #ifdef DEBUG std::cerr << "------------------------------------------\n"; std::cerr << "Same path\n"; - std::cerr << from_expr(ns, "", sympath) << "\n"; + std::cerr << from_expr(ns, "", symbolic_path.get_expr()) << "\n"; #endif const exprt sympath=symbolic_path.get_expr(); @@ -84,15 +84,14 @@ bool strategy_solver_heap_interval_sympatht::iterate( { // The path has been altered during computation (solver has found another // loop-select guard that can be true - -#ifdef DEBUG - std::cerr << "Path altered\n"; -#endif - auto new_sympath=heap_interval_solver.symbolic_path.get_expr(); inv.emplace(new_sympath, std::move(inv.at(sympath))); inv.erase(sympath); symbolic_path=heap_interval_solver.symbolic_path; +#ifdef DEBUG + std::cerr << "Path altered\n"; + std::cerr << from_expr(ns, "", symbolic_path.get_expr()) << "\n"; +#endif } domain.heap_interval_domain.undo_restriction(); } @@ -105,11 +104,11 @@ bool strategy_solver_heap_interval_sympatht::iterate( if(improved) { + symbolic_path=heap_interval_solver.symbolic_path; #ifdef DEBUG std::cerr << "Symbolic path:\n"; - std::cerr << from_expr(ns, "", sympath) << "\n"; + std::cerr << from_expr(ns, "", symbolic_path.get_expr()) << "\n"; #endif - symbolic_path=heap_interval_solver.symbolic_path; const exprt sympath=heap_interval_solver.symbolic_path.get_expr(); inv.emplace(sympath, std::move(new_value)); new_path=false; diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index 3b679f315..5a36d7b69 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -795,15 +795,19 @@ void template_generator_baset::instantiate_standard_domains( static_cast(domain_ptr) ->add_quadratic_template(var_specs, SSA.ns); } - else if(options.get_bool_option("heap-interval")) + else if(options.get_bool_option("heap-interval") || + options.get_bool_option("heap-zones")) { filter_heap_interval_domain(); + auto polyhedra_kind=options.get_bool_option("heap-interval") + ? heap_interval_domaint::INTERVAL + : heap_interval_domaint::ZONES; if(options.get_bool_option("sympath")) domain_ptr=new heap_interval_sympath_domaint( - domain_number, renaming_map, var_specs, SSA); + domain_number, renaming_map, var_specs, SSA, polyhedra_kind); else domain_ptr=new heap_interval_domaint( - domain_number, renaming_map, var_specs, SSA.ns); + domain_number, renaming_map, var_specs, SSA.ns, polyhedra_kind); } } diff --git a/src/domains/tpolyhedra_domain.cpp b/src/domains/tpolyhedra_domain.cpp index 1c6e1be44..389bf2d57 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 "domain.h" #define SYMB_BOUND_VAR "symb_bound#" @@ -1051,6 +1052,8 @@ void tpolyhedra_domaint::add_difference_template( for(var_specst::const_iterator v1=var_specs.begin(); v1!=var_specs.end(); ++v1) { + if (v1->var.type().id() == ID_pointer) + continue; var_specst::const_iterator v2=v1; ++v2; for(; v2!=var_specs.end(); ++v2) { @@ -1059,6 +1062,8 @@ void tpolyhedra_domaint::add_difference_template( continue; if(k==LOOP && v1->pre_guard!=v2->pre_guard) continue; // TEST: we need better heuristics + if (v2->var.type().id() == ID_pointer) + continue; exprt pre_g, post_g, aux_expr; merge_and(pre_g, v1->pre_guard, v2->pre_guard, ns); From 4cb88ab3e52768df02e2a800d77db919b059d95e Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 9 Apr 2018 11:44:56 +0200 Subject: [PATCH 193/322] Modify SAS 2018 tests to use __VERIFIER_error instead of assert --- regression/sas18/packet_filter/main.c | 8 +++++--- regression/sas18/process_queue/main.c | 5 +++-- regression/sas18/quick_sort_split/main.c | 8 +++++--- regression/sas18/running_example/main.c | 4 +++- regression/sas18/shared_mem1/main.c | 5 +++-- regression/sas18/shared_mem2/main.c | 4 ++-- 6 files changed, 21 insertions(+), 13 deletions(-) diff --git a/regression/sas18/packet_filter/main.c b/regression/sas18/packet_filter/main.c index b95dbe119..b2a16f4b4 100644 --- a/regression/sas18/packet_filter/main.c +++ b/regression/sas18/packet_filter/main.c @@ -1,9 +1,9 @@ extern unsigned __VERIFIER_nondet_uint(); extern int __VERIFIER_nondet_int(); extern char *__VERIFIER_nondet_charp(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); #include -#include #define LOW 0 #define HIGH 1 @@ -43,14 +43,16 @@ void append_to_queue(Packet p, Node *q) { void process_prio_queue(Node q) { for (Node node = q; node != NULL; node = node->next) { - assert(node->packet.prio == HIGH || node->packet.size < 500); + if (!(node->packet.prio == HIGH || node->packet.size < 500)) + __VERIFIER_error(); send(node->packet); } } void process_normal_queue(Node q) { for (Node node = q; node != NULL; node = node->next) { - assert(node->packet.prio == LOW && node->packet.size >= 500); + if (!(node->packet.prio == LOW && node->packet.size >= 500)) + __VERIFIER_error(); send(node->packet); } } diff --git a/regression/sas18/process_queue/main.c b/regression/sas18/process_queue/main.c index 52f5e782b..1299105de 100644 --- a/regression/sas18/process_queue/main.c +++ b/regression/sas18/process_queue/main.c @@ -1,7 +1,7 @@ extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); #include -#include #define MAX_PROC 1000 @@ -41,7 +41,8 @@ struct process_node *choose_next(struct process_node **q) { void check_queue(struct process_node *q) { for (struct process_node *n = q; n != NULL; n = n->next) - assert(n->time_to_wait >= 1); + if (!n->time_to_wait >= 1) + __VERIFIER_error(); } diff --git a/regression/sas18/quick_sort_split/main.c b/regression/sas18/quick_sort_split/main.c index 2079e9965..c286aa4e8 100644 --- a/regression/sas18/quick_sort_split/main.c +++ b/regression/sas18/quick_sort_split/main.c @@ -1,7 +1,7 @@ extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); #include -#include #define LOW -1 #define HIGH 1 @@ -50,11 +50,13 @@ int main() { // Check that low and high contain expected elements while (low) { - assert(low->expected_list == LOW); + if (!low->expected_list == LOW) + __VERIFIER_error(); low = low->next; } while (high) { - assert(high->expected_list == HIGH); + if (!high->expected_list == HIGH) + __VERIFIER_error(); high = high->next; } } diff --git a/regression/sas18/running_example/main.c b/regression/sas18/running_example/main.c index 0ff9fc4b9..eb49e6853 100644 --- a/regression/sas18/running_example/main.c +++ b/regression/sas18/running_example/main.c @@ -1,4 +1,5 @@ extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); #include @@ -23,7 +24,8 @@ int main() { while (1) { for (p = list; p!= NULL; p = p->next) { - assert(p->val <= 20 && p->val >= 10); + if (!(p->val <= 20 && p->val >= 10)) + __VERIFIER_error(); if (p->val < 20) p->val++; else p->val /= 2; } diff --git a/regression/sas18/shared_mem1/main.c b/regression/sas18/shared_mem1/main.c index 4df22d2ac..d80939e92 100644 --- a/regression/sas18/shared_mem1/main.c +++ b/regression/sas18/shared_mem1/main.c @@ -1,7 +1,7 @@ extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); #include -#include struct mem { int val; @@ -43,6 +43,7 @@ int main() { list->mem->val -= list->x; list = list->next; - assert(m->val > 90 && m->val < 110); + if (!(m->val > 90 && m->val < 110)) + __VERIFIER_error(); } } diff --git a/regression/sas18/shared_mem2/main.c b/regression/sas18/shared_mem2/main.c index 08a27e3a7..dd4f6466d 100644 --- a/regression/sas18/shared_mem2/main.c +++ b/regression/sas18/shared_mem2/main.c @@ -1,7 +1,6 @@ extern int __VERIFIER_nondet_int(); #include -#include struct mem { int val; @@ -41,5 +40,6 @@ int main() { list->mem->val += list->x; list = list->next; } - assert(m->val == 100); + if (!m->val == 100) + __VERIFIER_nondet_int(); } From ff40be053bdd2f8370ee78941d91399689c86b57 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 9 Apr 2018 11:51:35 +0200 Subject: [PATCH 194/322] Add 2 more tests to SAS'18 benchmark --- regression/sas18/hash_fun/main.c | 42 +++++++++++++++++++++++++++++ regression/sas18/hash_fun/test.desc | 6 +++++ regression/sas18/min_max/main.c | 40 +++++++++++++++++++++++++++ regression/sas18/min_max/test.desc | 6 +++++ 4 files changed, 94 insertions(+) create mode 100644 regression/sas18/hash_fun/main.c create mode 100644 regression/sas18/hash_fun/test.desc create mode 100644 regression/sas18/min_max/main.c create mode 100644 regression/sas18/min_max/test.desc diff --git a/regression/sas18/hash_fun/main.c b/regression/sas18/hash_fun/main.c new file mode 100644 index 000000000..08fd2104a --- /dev/null +++ b/regression/sas18/hash_fun/main.c @@ -0,0 +1,42 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +#define INTERVAL_SIZE 100 + +struct node { + int hash; + struct node *next; +}; + +int hash_fun(); + +void append_to_list(struct node **list, int hash) { + struct node *node = malloc(sizeof(*node)); + node->next = *list; + node->hash = hash; + *list = node; +} + +int main() { + struct node *list = NULL; + + int base = __VERIFIER_nondet_int(); + + while (__VERIFIER_nondet_int()) { + if (base >= 0 && base <= 1000000) { + base = base; + int hash = hash_fun(); + + if (hash > base && hash < base + INTERVAL_SIZE) + append_to_list(&list, hash); + } + } + + while (list) { + if (!(list->hash >= base && list->hash < base + INTERVAL_SIZE)) + __VERIFIER_error(); + list = list->next; + } +} diff --git a/regression/sas18/hash_fun/test.desc b/regression/sas18/hash_fun/test.desc new file mode 100644 index 000000000..9fa90aa33 --- /dev/null +++ b/regression/sas18/hash_fun/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-zones --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/min_max/main.c b/regression/sas18/min_max/main.c new file mode 100644 index 000000000..76b129535 --- /dev/null +++ b/regression/sas18/min_max/main.c @@ -0,0 +1,40 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include +#include + +#define APPEND(l,i) {i->next=l; l=i;} + +typedef struct node { + struct node *next; + int val; +} Node; + +int main() { + Node *l = NULL; + int min = INT_MAX, max = -INT_MAX; + + while (__VERIFIER_nondet_int()) { + Node *p = malloc(sizeof(*p)); + p->val = __VERIFIER_nondet_int(); + APPEND(l, p) + + if (min > p->val) { + min = p->val; + } + if (max < p->val) { + max = p->val; + } + + } + + Node *i = l; + while (i != NULL) { + if (i->val < min) + __VERIFIER_error(); + if (i->val > max) + __VERIFIER_error(); + i = i->next; + } +} diff --git a/regression/sas18/min_max/test.desc b/regression/sas18/min_max/test.desc new file mode 100644 index 000000000..9fa90aa33 --- /dev/null +++ b/regression/sas18/min_max/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-zones --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ From 2bfac82c02f0c8979505839ef5f8a507ddead9e5 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 10 Apr 2018 10:47:10 +0200 Subject: [PATCH 195/322] Add new example to SAS'18 benchmark --- regression/sas18/calendar/main.c | 40 ++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 regression/sas18/calendar/main.c diff --git a/regression/sas18/calendar/main.c b/regression/sas18/calendar/main.c new file mode 100644 index 000000000..2ee9630e5 --- /dev/null +++ b/regression/sas18/calendar/main.c @@ -0,0 +1,40 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +#define APPEND(l,i) {i->next=l; l=i;} + +typedef struct node { + struct node *next; + int event1; + int event2; +} Node; + +int main() { + Node *l = NULL; + + while (__VERIFIER_nondet_int()) { + int ev1 = __VERIFIER_nondet_int(); + int ev2 = __VERIFIER_nondet_int(); + if (ev1 < 0 || ev1 > 3 || ev2 < 0 || ev2 > 3) + continue; + + if (((ev1 == 0) && (ev2 == 2)) || ((ev1 == 1) && (ev2 == 3)) || ((ev1 == 0) && (ev2 == 3))) + continue; + + Node *p = malloc(sizeof(*p)); + p->event1 = ev1; + p->event2 = ev2; + APPEND(l,p) + } + + Node *i = l; + + while (i != NULL) { + if (((i->event1 == 1) && (i->event2 == 3)) || ((i->event1 == 0) && (i->event2 == 2))) + __VERIFIER_error(); + i = i->next; + } +} + From 6524bf1bb2ef5bc45d2530da5182a4f60741c0da Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 10 Apr 2018 14:05:09 +0200 Subject: [PATCH 196/322] Add new example to SAS'18 benchmark Also add forgotten test.desc to the prevously added example. --- regression/sas18/calendar/test.desc | 6 ++++ regression/sas18/cart/main.c | 46 +++++++++++++++++++++++++++++ regression/sas18/cart/test.desc | 6 ++++ 3 files changed, 58 insertions(+) create mode 100644 regression/sas18/calendar/test.desc create mode 100644 regression/sas18/cart/main.c create mode 100644 regression/sas18/cart/test.desc diff --git a/regression/sas18/calendar/test.desc b/regression/sas18/calendar/test.desc new file mode 100644 index 000000000..9fa90aa33 --- /dev/null +++ b/regression/sas18/calendar/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-zones --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/cart/main.c b/regression/sas18/cart/main.c new file mode 100644 index 000000000..3144e411e --- /dev/null +++ b/regression/sas18/cart/main.c @@ -0,0 +1,46 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +#define APPEND(l,i) {i->next=l; l=i;} + +typedef struct node { + struct node *next; + int stock; + int order; +} Node; + +int main() { + Node *l = NULL; + + while (__VERIFIER_nondet_int()) { + int stock = __VERIFIER_nondet_int(); + if (stock < 0) + continue; + + Node *p = malloc(sizeof(*p)); + p->stock = stock; + p->order = 0; + APPEND(l,p) + } + + Node *i = l; + while (i != NULL) { + int order = __VERIFIER_nondet_int(); + if (order < 0 || i->stock < order) + continue; + i->order = order; + i->stock = i->stock; + i = i->next; + } + + + i = l; + while (i != NULL) { + if (i->order > i->stock) + __VERIFIER_error(); + i = i->next; + } +} + diff --git a/regression/sas18/cart/test.desc b/regression/sas18/cart/test.desc new file mode 100644 index 000000000..9fa90aa33 --- /dev/null +++ b/regression/sas18/cart/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-zones --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ From 4863739a4006ee89ba333c965376478b2fd20578 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 10 Apr 2018 15:13:45 +0200 Subject: [PATCH 197/322] Add combination of heap domain with multiple value domains Value domains are tried from the weakest towards the strongest. Currently tries interval and then zones (if the result is 'unknown'). Can be turned on with --heap-values-incremental switch. --- src/2ls/2ls_parse_options.cpp | 235 +++++++++++++++++++--------------- src/2ls/2ls_parse_options.h | 2 +- 2 files changed, 130 insertions(+), 107 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 1681807b0..0161289f9 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -215,6 +215,12 @@ void twols_parse_optionst::get_command_line_options(optionst &options) if(cmdline.isset("sympath")) options.set_option("sympath", true); } + else if(cmdline.isset("heap-values-incremental")) + { + options.set_option("heap-interval", true); + if(cmdline.isset("sympath")) + options.set_option("sympath", true); + } else { if(cmdline.isset("zones")) @@ -571,137 +577,153 @@ int twols_parse_optionst::doit() try { - std::unique_ptr checker; - if(!options.get_bool_option("k-induction") && - !options.get_bool_option("incremental-bmc")) - checker=std::unique_ptr( - new summary_checker_ait(options, heap_analysis)); - if(options.get_bool_option("k-induction") && - !options.get_bool_option("incremental-bmc")) - checker=std::unique_ptr( - new summary_checker_kindt(options, heap_analysis)); - if(!options.get_bool_option("k-induction") && - options.get_bool_option("incremental-bmc")) - checker=std::unique_ptr( - new summary_checker_bmct(options, heap_analysis)); - if(options.get_bool_option("nontermination")) - checker=std::unique_ptr( - new summary_checker_nontermt(options, heap_analysis)); - - checker->set_message_handler(get_message_handler()); - checker->simplify=!cmdline.isset("no-simplify"); - checker->fixed_point=!cmdline.isset("no-fixed-point"); - + bool finished=false; int retval; - if(cmdline.isset("show-vcc")) - { - std::cout << "VERIFICATION CONDITIONS:\n\n"; - checker->show_vcc=true; - (*checker)(goto_model); - return 0; - } - - if(cmdline.isset("horn-encoding")) + while(!finished) { - status() << "Horn-clause encoding" << eom; - namespacet ns(symbol_table); - - std::string out_file=cmdline.get_value("horn-encoding"); - - if(out_file=="-") + std::unique_ptr checker; + if(!options.get_bool_option("k-induction") && + !options.get_bool_option("incremental-bmc")) + checker=std::unique_ptr( + new summary_checker_ait(options, heap_analysis)); + if(options.get_bool_option("k-induction") && + !options.get_bool_option("incremental-bmc")) + checker=std::unique_ptr( + new summary_checker_kindt(options, heap_analysis)); + if(!options.get_bool_option("k-induction") && + options.get_bool_option("incremental-bmc")) + checker=std::unique_ptr( + new summary_checker_bmct(options, heap_analysis)); + if(options.get_bool_option("nontermination")) + checker=std::unique_ptr( + new summary_checker_nontermt(options, heap_analysis)); + + checker->set_message_handler(get_message_handler()); + checker->simplify=!cmdline.isset("no-simplify"); + checker->fixed_point=!cmdline.isset("no-fixed-point"); + + if(cmdline.isset("show-vcc")) { - horn_encoding(goto_model, std::cout); + std::cout << "VERIFICATION CONDITIONS:\n\n"; + checker->show_vcc=true; + (*checker)(goto_model); + return 0; } - else + + if(cmdline.isset("horn-encoding")) { + status() << "Horn-clause encoding" << eom; + namespacet ns(symbol_table); + + std::string out_file=cmdline.get_value("horn-encoding"); + + if(out_file=="-") + { + horn_encoding(goto_model, std::cout); + } + else + { #ifdef _MSC_VER - std::ofstream out(widen(out_file).c_str()); + std::ofstream out(widen(out_file).c_str()); #else - std::ofstream out(out_file.c_str()); + std::ofstream out(out_file.c_str()); #endif - if(!out) - { - error() << "Failed to open output file " - << out_file << eom; - return 1; + if(!out) + { + error() << "Failed to open output file " + << out_file << eom; + return 1; + } + + horn_encoding(goto_model, out); } - horn_encoding(goto_model, out); + return 0; } - return 0; - } - - bool report_assertions= - !options.get_bool_option("preconditions") && - !options.get_bool_option("termination") && - !options.get_bool_option("nontermination"); - // do actual analysis - switch((*checker)(goto_model)) - { - case property_checkert::PASS: - if(report_assertions) - report_properties(options, goto_model, checker->property_map); - report_success(); - if(cmdline.isset("graphml-witness")) - output_graphml_proof(options, goto_model, *checker); - retval=0; - break; - - case property_checkert::FAIL: - { - if(report_assertions) - report_properties(options, goto_model, checker->property_map); + bool report_assertions= + !options.get_bool_option("preconditions") && + !options.get_bool_option("termination") && + !options.get_bool_option("nontermination"); + // do actual analysis + switch((*checker)(goto_model)) + { + case property_checkert::PASS: + if(report_assertions) + report_properties(options, goto_model, checker->property_map); + report_success(); + if(cmdline.isset("graphml-witness")) + output_graphml_proof(options, goto_model, *checker); + retval=0; + finished = true; + break; - // validate trace - bool trace_valid=false; - for(const auto &p : checker->property_map) + case property_checkert::FAIL: { - if(p.second.result!=property_checkert::FAIL) - continue; + if(report_assertions) + report_properties(options, goto_model, checker->property_map); - if(options.get_bool_option("trace")) - show_counterexample(goto_model, p.second.error_trace); + // validate trace + bool trace_valid=false; + for(const auto &p : checker->property_map) + { + if(p.second.result!=property_checkert::FAIL) + continue; - trace_valid= - !p.second.error_trace.steps.empty() && - (options.get_bool_option("nontermination") || - p.second.error_trace.steps.back().is_assert()); - break; - } + if(options.get_bool_option("trace")) + show_counterexample(goto_model, p.second.error_trace); - if(cmdline.isset("graphml-witness")) - { + trace_valid= + !p.second.error_trace.steps.empty() && + (options.get_bool_option("nontermination") || + p.second.error_trace.steps.back().is_assert()); + break; + } + + if(cmdline.isset("graphml-witness")) + { #if 1 - if(!trace_valid) + if(!trace_valid) + { + retval=5; + error() << "Internal witness validation failed" << eom; + report_unknown(); + break; + } +#endif + output_graphml_cex(options, goto_model, *checker); + } + report_failure(); + retval=10; + finished = true; + break; + } + case property_checkert::UNKNOWN: + if(cmdline.isset("heap-values-incremental") && + options.get_bool_option("heap-interval")) + { + options.set_option("heap-interval", false); + options.set_option("heap-zones", true); + } + else { + if(report_assertions) + report_properties(options, goto_model, checker->property_map); retval=5; - error() << "Internal witness validation failed" << eom; + finished = true; report_unknown(); - break; } -#endif - output_graphml_cex(options, goto_model, *checker); - } - report_failure(); - retval=10; - break; - } - case property_checkert::UNKNOWN: - if(report_assertions) - report_properties(options, goto_model, checker->property_map); - retval=5; - report_unknown(); - break; + break; - default: - assert(false); - } + default: + assert(false); + } - if(cmdline.isset("instrument-output")) - { - checker->instrument_and_output(goto_model); + if(cmdline.isset("instrument-output")) + { + checker->instrument_and_output(goto_model); + } } return retval; @@ -1766,6 +1788,7 @@ void twols_parse_optionst::help() " --octagons use octagon domain\n" " --heap-interval use heap domain with interval domain for values\n" // NOLINT(*) " --heap-zones use heap domain with zones domain for values\n" // NOLINT(*) + " --heap-zones use heap domain with dynamically incrementing stregth of value domain\n" // NOLINT(*) " --sympath compute invariant for each symbolic path (only usable with --heap-interval switch)" // NOLINT(*) " --enum-solver use solver based on model enumeration\n" " --binsearch-solver use solver based on binary search\n" diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index 771a6ac52..a62ba309e 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -38,7 +38,7 @@ class optionst; "(i386-linux)(i386-macos)(i386-win32)(win32)(winx64)(gcc)" \ "(ppc-macos)(unsigned-char)" \ "(havoc)(intervals)(zones)(octagons)(equalities)"\ - "(heap)(heap-interval)(heap-zones)"\ + "(heap)(heap-interval)(heap-zones)(heap-values-incremental)"\ "(sympath)" \ "(enum-solver)(binsearch-solver)(arrays)"\ "(string-abstraction)(no-arch)(arch):(floatbv)(fixedbv)" \ From 99d60038787d30e3f33d7fc476668a29e6eca398 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 10 Apr 2018 15:16:49 +0200 Subject: [PATCH 198/322] Update SAS;18 benchmark to use the new --heap-values-incremental switch --- regression/sas18/calendar/test.desc | 2 +- regression/sas18/cart/test.desc | 2 +- regression/sas18/hash_fun/test.desc | 2 +- regression/sas18/min_max/test.desc | 2 +- regression/sas18/packet_filter/test.desc | 2 +- regression/sas18/process_queue/test.desc | 2 +- regression/sas18/quick_sort_split/test.desc | 2 +- regression/sas18/running_example/test.desc | 2 +- regression/sas18/shared_mem1/test.desc | 2 +- regression/sas18/shared_mem2/test.desc | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/regression/sas18/calendar/test.desc b/regression/sas18/calendar/test.desc index 9fa90aa33..20acb756e 100644 --- a/regression/sas18/calendar/test.desc +++ b/regression/sas18/calendar/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-zones --sympath --inline +--heap-values-incremental --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/cart/test.desc b/regression/sas18/cart/test.desc index 9fa90aa33..20acb756e 100644 --- a/regression/sas18/cart/test.desc +++ b/regression/sas18/cart/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-zones --sympath --inline +--heap-values-incremental --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/hash_fun/test.desc b/regression/sas18/hash_fun/test.desc index 9fa90aa33..20acb756e 100644 --- a/regression/sas18/hash_fun/test.desc +++ b/regression/sas18/hash_fun/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-zones --sympath --inline +--heap-values-incremental --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/min_max/test.desc b/regression/sas18/min_max/test.desc index 9fa90aa33..20acb756e 100644 --- a/regression/sas18/min_max/test.desc +++ b/regression/sas18/min_max/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-zones --sympath --inline +--heap-values-incremental --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/packet_filter/test.desc b/regression/sas18/packet_filter/test.desc index c03cf0e85..20acb756e 100644 --- a/regression/sas18/packet_filter/test.desc +++ b/regression/sas18/packet_filter/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-interval --sympath --inline --no-propagation +--heap-values-incremental --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/process_queue/test.desc b/regression/sas18/process_queue/test.desc index c03cf0e85..20acb756e 100644 --- a/regression/sas18/process_queue/test.desc +++ b/regression/sas18/process_queue/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-interval --sympath --inline --no-propagation +--heap-values-incremental --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/quick_sort_split/test.desc b/regression/sas18/quick_sort_split/test.desc index c03cf0e85..20acb756e 100644 --- a/regression/sas18/quick_sort_split/test.desc +++ b/regression/sas18/quick_sort_split/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-interval --sympath --inline --no-propagation +--heap-values-incremental --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/running_example/test.desc b/regression/sas18/running_example/test.desc index c03cf0e85..20acb756e 100644 --- a/regression/sas18/running_example/test.desc +++ b/regression/sas18/running_example/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-interval --sympath --inline --no-propagation +--heap-values-incremental --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/shared_mem1/test.desc b/regression/sas18/shared_mem1/test.desc index c03cf0e85..20acb756e 100644 --- a/regression/sas18/shared_mem1/test.desc +++ b/regression/sas18/shared_mem1/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-interval --sympath --inline --no-propagation +--heap-values-incremental --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/shared_mem2/test.desc b/regression/sas18/shared_mem2/test.desc index c03cf0e85..20acb756e 100644 --- a/regression/sas18/shared_mem2/test.desc +++ b/regression/sas18/shared_mem2/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-interval --sympath --inline --no-propagation +--heap-values-incremental --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ From 0c8a3abdbd22f336b0da7b302d882eaef1063b28 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 15 May 2018 15:11:18 +0200 Subject: [PATCH 199/322] Analysis of the required number of dynamic object instances For some programs, we have to create multiple instances of dynamic objects in order to prevent unsoundness. This analysis should compute a number of such instances. Currently, it computes partitioning of all pointers based on must-alias relation for each abstract dynamic object. --- src/2ls/2ls_parse_options.cpp | 12 ++ src/ssa/Makefile | 3 +- src/ssa/dynobj_instance_analysis.cpp | 143 ++++++++++++++++++++++++ src/ssa/dynobj_instance_analysis.h | 160 +++++++++++++++++++++++++++ src/ssa/ssa_value_set.h | 1 + 5 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 src/ssa/dynobj_instance_analysis.cpp create mode 100644 src/ssa/dynobj_instance_analysis.h diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 0161289f9..ac680cb55 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -46,6 +46,7 @@ Author: Daniel Kroening, Peter Schrammel #include "graphml_witness_ext.h" #include +#include #include "2ls_parse_options.h" #include "summary_checker_ai.h" @@ -1285,6 +1286,17 @@ bool twols_parse_optionst::process_goto_program( inline_main(goto_model); } + forall_goto_functions(f_it, goto_model.goto_functions) + { + if (!f_it->second.body_available()) + continue; + namespacet ns(goto_model.symbol_table); + ssa_value_ait value_analysis(f_it->second, ns, ssa_heap_analysist(ns)); + value_analysis.output(ns, f_it->second, std::cerr); + dynobj_instance_analysist do_inst(f_it->second, ns, value_analysis); + do_inst.output(ns, f_it->second, std::cerr); + } + if(!cmdline.isset("independent-properties")) { add_assumptions_after_assertions(goto_model); diff --git a/src/ssa/Makefile b/src/ssa/Makefile index 81460b00c..55c63720d 100644 --- a/src/ssa/Makefile +++ b/src/ssa/Makefile @@ -5,7 +5,8 @@ SRC = local_ssa.cpp ssa_var_collector.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_pointed_objects.cpp ssa_heap_domain.cpp may_alias_analysis.cpp + ssa_pointed_objects.cpp ssa_heap_domain.cpp may_alias_analysis.cpp \ + dynobj_instance_analysis.cpp include ../config.inc include $(CBMC)/src/config.inc diff --git a/src/ssa/dynobj_instance_analysis.cpp b/src/ssa/dynobj_instance_analysis.cpp new file mode 100644 index 000000000..0800d5f15 --- /dev/null +++ b/src/ssa/dynobj_instance_analysis.cpp @@ -0,0 +1,143 @@ +// +// Created by vmalik on 5/14/18. +// + +#include +#include "dynobj_instance_analysis.h" +#include "ssa_dereference.h" + +bool has_deref_of(const exprt &expr, const exprt &pointer) +{ + if(expr.id()==ID_dereference && to_dereference_expr(expr).pointer()==pointer) + return true; + forall_operands(it, expr) + { + if(has_deref_of(*it, pointer)) + return true; + } + return false; +} + +void remove_dereferences(const exprt &pointer, must_alias_setst &instances) +{ + for (auto &i : instances) + { + if (has_deref_of(i, pointer)) + instances.isolate(i); + } +} + +void replace_pointer_in_deref(exprt &deref, const exprt &src, const exprt &dest) +{ + if (deref.id() == ID_dereference && to_dereference_expr(deref).pointer() == src) + deref = dereference_exprt(dest, deref.type()); + + Forall_operands(it, deref) + replace_pointer_in_deref(*it, src, dest); +} + +void add_aliased_dereferences(const exprt &pointer, must_alias_setst &instances) +{ + for (auto &i : instances) + { + if(i.id()==ID_symbol && pointer.id()==ID_symbol && i!=pointer && + instances.same_set(i, pointer)) + { + for (auto &deref_i : instances) + { + if (has_deref_of(deref_i, i)) + { + exprt deref_copy = deref_i; + replace_pointer_in_deref(deref_copy, i, pointer); + instances.make_union(deref_i, deref_copy); + } + } + } + } +} + +void dynobj_instance_domaint::transform( + ai_domain_baset::locationt from, + ai_domain_baset::locationt to, + ai_baset &ai, + const namespacet &ns) +{ + if (from->is_assign()) { + const code_assignt &assignment = to_code_assign(from->code); + const exprt lhs = symbolic_dereference(assignment.lhs(), ns); + + if(lhs.id()==ID_symbol && + id2string(to_symbol_expr(lhs).get_identifier()).find("__CPROVER")!= + std::string::npos) + return; + + if (assignment.rhs().get_bool("#malloc_result")) + { + const auto &values= + static_cast(ai).value_analysis[to]; + const auto lhs_deref = dereference(assignment.lhs(), values, "", ns); + auto value_set = values(lhs_deref, ns).value_set; + for (auto &v : value_set) + dynobj_instances[v.symbol_expr()].isolate(lhs); + } + else + { + exprt rhs = assignment.rhs(); + if (rhs.id() == ID_typecast) + rhs = to_typecast_expr(rhs).op(); + + const auto &values= + static_cast(ai).value_analysis[from]; + const auto rhs_deref = dereference(rhs, values, "", ns); + auto value_set = values(rhs_deref, ns).value_set; + for (auto &v : value_set) + { + auto &instances = dynobj_instances[v.symbol_expr()]; + instances.isolate(assignment.lhs()); + instances.make_union(assignment.lhs(), rhs); + + remove_dereferences(assignment.lhs(), instances); + add_aliased_dereferences(assignment.lhs(), instances); + } + } + } +} + +bool dynobj_instance_domaint::merge( + const dynobj_instance_domaint &other, + ai_domain_baset::locationt from, + ai_domain_baset::locationt to) +{ + bool result = false; + for (auto &obj : other.dynobj_instances) + { + if (dynobj_instances.find(obj.first) == dynobj_instances.end()) + { + dynobj_instances.insert(obj); + result = true; + } + else + { + if (dynobj_instances.at(obj.first).join(obj.second)) + result = true; + } + } + return result; +} + +void dynobj_instance_domaint::output( + std::ostream &out, + const ai_baset &ai, + const namespacet &ns) const +{ + for (const auto &o : dynobj_instances) + { + out << o.first.get_identifier() << ":\n"; + for (const exprt &p : o.second) + { + unsigned long n; + o.second.get_number(p, n); + out << " " << o.second.find_number(n) << ": " << from_expr(ns, "", p) << "\n"; + } + } +} diff --git a/src/ssa/dynobj_instance_analysis.h b/src/ssa/dynobj_instance_analysis.h new file mode 100644 index 000000000..2227ad9b6 --- /dev/null +++ b/src/ssa/dynobj_instance_analysis.h @@ -0,0 +1,160 @@ +// +// Created by vmalik on 5/14/18. +// + +#ifndef INC_2LS_DYNOBJ_INSTANCE_ANALYSIST_H +#define INC_2LS_DYNOBJ_INSTANCE_ANALYSIST_H + + +#include +#include +#include "ssa_object.h" +#include "ssa_value_set.h" + +class must_alias_setst : public union_find +{ +protected: + bool equal(const must_alias_setst &other) + { + if (size() != other.size()) + return false; + + for (auto &e1 : *this) + { + unsigned long n; + if (other.get_number(e1, n)) + return false; + for (auto &e2 : *this) + if (same_set(e1, e2) != other.same_set(e1, e2)) + return false; + } + return true; + } + + std::set sym_diff_elements(const must_alias_setst &other) + { + std::set result; + unsigned long n; + for (auto &e : *this) + if (get_number(e, n)) + result.insert(e); + for (auto &e : other) + if (get_number(e, n)) + result.insert(e); + return result; + } + +public: + bool join(const must_alias_setst &other) + { + if (!equal(other)) + { + // Find new elements (those that are unique to one of the sets + auto new_elements = sym_diff_elements(other); + // Copy *this + auto original = *this; + + // Make intersection (into *this) which contains all common elements + // (after retyping to vector) + clear(); + std::set common_elements; + for (auto &e1 : original) + { + if (new_elements.find(e1) != new_elements.end()) + continue; + + isolate(e1); + for (auto &e2 : common_elements) + if (original.same_set(e1, e2) && other.same_set(e1, e2)) + make_union(e1, e2); + common_elements.insert(e1); + } + + for (auto &e_new : new_elements) + { + bool added = false; + // First, try to find some new element that is already in *this and that + // is in the same class as e_new in one of the sets + for (auto &e : *this) + { + if(new_elements.find(e)!=new_elements.end() && + (original.same_set(e, e_new) || other.same_set(e, e_new))) + { + make_union(e, e_new); + added = true; + } + } + if (!added) + { + // Find all sets to which e_new should be added by comparing with + // common elements + // The map will contain: set_number(in *this) -> set_representative + std::map dest_sets; + for(auto &e: common_elements) + { + if(original.same_set(e_new, e) || other.same_set(e_new, e)) + { + unsigned long n; + get_number(e, n); + if(dest_sets.find(n)==dest_sets.end()) + dest_sets.emplace(n, e); + } + } + + // If there is just one set to add e_new to, add it there, otherwise + // isolate it + if(dest_sets.size()==1) + make_union(e_new, dest_sets.begin()->second); + else + isolate(e_new); + } + } + return true; + } + return false; + } +}; + +class dynobj_instance_domaint:public ai_domain_baset +{ + std::map dynobj_instances; + +public: + void transform( + locationt from, + locationt to, + ai_baset &ai, + const namespacet &ns) override; + void output( + std::ostream &out, + const ai_baset &ai, + const namespacet &ns) const override; + bool merge( + const dynobj_instance_domaint &other, + locationt from, + locationt to); + +protected: + +}; + +class dynobj_instance_analysist:public ait +{ +public: + dynobj_instance_analysist( + const goto_functionst::goto_functiont &goto_function, + const namespacet &ns, + ssa_value_ait &_value_ai): + value_analysis(_value_ai) + { + operator()(goto_function, ns); + } + +protected: + ssa_value_ait &value_analysis; + + friend class dynobj_instance_domaint; +}; + + +#endif //INC_2LS_DYNOBJ_INSTANCE_ANALYSIST_H diff --git a/src/ssa/ssa_value_set.h b/src/ssa/ssa_value_set.h index e2e79c791..a6dc3718c 100644 --- a/src/ssa/ssa_value_set.h +++ b/src/ssa/ssa_value_set.h @@ -10,6 +10,7 @@ Author: Daniel Kroening, kroening@kroening.com #define CPROVER_2LS_SSA_SSA_VALUE_SET_H #include +#include #include "ssa_object.h" #include "ssa_heap_domain.h" From 6b2d1545026919635461ce974ef686b3863ffcb5 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 15 May 2018 15:16:16 +0200 Subject: [PATCH 200/322] Add test that reveals an unsoundness in treating of dynamic objects --- regression/heap/dynobj_concret/main.c | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 regression/heap/dynobj_concret/main.c diff --git a/regression/heap/dynobj_concret/main.c b/regression/heap/dynobj_concret/main.c new file mode 100644 index 000000000..d59aae01b --- /dev/null +++ b/regression/heap/dynobj_concret/main.c @@ -0,0 +1,30 @@ +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +extern int __VERIFIER_nondet_int(); + +#include + +void exit(int s) { + _EXIT: goto _EXIT; +} + +typedef struct node { + struct node *n; +} *List; + +int main() { + /* Build a list of the form 1->...->1->0 */ + List t; + List p = NULL; + while (__VERIFIER_nondet_int()) { + t = (List) malloc(sizeof(struct node)); + t->n = p; + p = t; + } + + if (p && p->n) { + List n = p->n; + List nn = n->n; + assert(n==nn); + } +} From 4b20b5db10fdb8405446a59f486389d284168184 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Wed, 16 May 2018 09:40:20 +0200 Subject: [PATCH 201/322] Collect live pointers pointing to a dynamic object at the same time This information is used to determine a number of potentially distinct concrete objects represented by the same abstract object that are pointed at the same time. Next, we need to split abstract object to the corresponding number of objects to avoid unsoundness. --- src/2ls/2ls_parse_options.cpp | 3 +++ src/2ls/2ls_parse_options.h | 5 +++++ src/2ls/preprocessing_util.cpp | 33 ++++++++++++++++++++++++++++ src/ssa/dynobj_instance_analysis.cpp | 29 ++++++++++++++++++++++++ src/ssa/dynobj_instance_analysis.h | 3 ++- 5 files changed, 72 insertions(+), 1 deletion(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index ac680cb55..ecfa36588 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -1286,6 +1286,7 @@ bool twols_parse_optionst::process_goto_program( inline_main(goto_model); } + std::map dynobj_instances; forall_goto_functions(f_it, goto_model.goto_functions) { if (!f_it->second.body_available()) @@ -1295,6 +1296,8 @@ bool twols_parse_optionst::process_goto_program( value_analysis.output(ns, f_it->second, std::cerr); dynobj_instance_analysist do_inst(f_it->second, ns, value_analysis); do_inst.output(ns, f_it->second, std::cerr); + + compute_dynobj_instances(f_it->second.body, do_inst, dynobj_instances, ns); } if(!cmdline.isset("independent-properties")) diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index a62ba309e..46e9cebc7 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -186,6 +186,11 @@ class twols_parse_optionst: goto_modelt &goto_model); void split_same_symbolic_object_assignments(goto_modelt &goto_model); void remove_dead_goto(goto_modelt &goto_model); + void compute_dynobj_instances( + const goto_programt &goto_program, + const dynobj_instance_analysist &analysis, + std::map &instance_counts, + const namespacet &ns); }; #endif diff --git a/src/2ls/preprocessing_util.cpp b/src/2ls/preprocessing_util.cpp index 2e1c07b50..1ab37150a 100644 --- a/src/2ls/preprocessing_util.cpp +++ b/src/2ls/preprocessing_util.cpp @@ -12,6 +12,7 @@ Author: Peter Schrammel #include #include +#include #include "2ls_parse_options.h" @@ -701,3 +702,35 @@ void twols_parse_optionst::remove_dead_goto(goto_modelt &goto_model) } } } + +void twols_parse_optionst::compute_dynobj_instances( + const goto_programt &goto_program, + const dynobj_instance_analysist &analysis, + std::map &instance_counts, + const namespacet &ns) +{ + forall_goto_program_instructions(it, goto_program) + { + auto &analysis_value = analysis[it]; + for (auto &obj : analysis_value.live_pointers) + { + auto must_alias = analysis_value.dynobj_instances.find(obj.first); + if (must_alias == analysis_value.dynobj_instances.end()) + continue; + + std::set alias_classes; + for (auto &expr : obj.second) + { + unsigned long n; + must_alias->second.get_number(expr, n); + alias_classes.insert(must_alias->second.find_number(n)); + } + + if(instance_counts.find(obj.first)==instance_counts.end() || + instance_counts.at(obj.first)is_dead()) + { + const exprt &symbol = to_code_dead(from->code).symbol(); + const auto &values= + static_cast(ai).value_analysis[from]; + auto value_set = values(symbol, ns).value_set; + for (auto &v : value_set) + { + live_pointers[v.symbol_expr()].erase(symbol); + } + } } bool dynobj_instance_domaint::merge( @@ -121,6 +134,13 @@ bool dynobj_instance_domaint::merge( if (dynobj_instances.at(obj.first).join(obj.second)) result = true; } + + if (other.live_pointers.find(obj.first) != other.live_pointers.end()) + { + auto &other_pointers = other.live_pointers.at(obj.first); + live_pointers[obj.first].insert( + other_pointers.begin(), other_pointers.end()); + } } return result; } @@ -139,5 +159,14 @@ void dynobj_instance_domaint::output( o.second.get_number(p, n); out << " " << o.second.find_number(n) << ": " << from_expr(ns, "", p) << "\n"; } + + if (live_pointers.find(o.first) == live_pointers.end()) + continue; + out << "Live: "; + for (const auto &v : live_pointers.at(o.first)) + { + out << from_expr(ns, "", v) << " "; + } + out << "\n"; } } diff --git a/src/ssa/dynobj_instance_analysis.h b/src/ssa/dynobj_instance_analysis.h index 2227ad9b6..66aa5daeb 100644 --- a/src/ssa/dynobj_instance_analysis.h +++ b/src/ssa/dynobj_instance_analysis.h @@ -117,9 +117,10 @@ class must_alias_setst : public union_find class dynobj_instance_domaint:public ai_domain_baset { +public: std::map dynobj_instances; + std::map> live_pointers; -public: void transform( locationt from, locationt to, From 67bc0fcfe65002071e0eef03066aaff1ff076831 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 18 May 2018 07:52:47 +0200 Subject: [PATCH 202/322] Split dynamic objects into multiple instances based on results of the analysis The object instance is chosen non-deterministically. Also, update collection of allocation guards in the SSA form so that the analysis is done correctly. --- src/2ls/2ls_parse_options.cpp | 7 +++- src/2ls/2ls_parse_options.h | 5 +++ src/2ls/preprocessing_util.cpp | 70 ++++++++++++++++++++++++++++++++++ src/ssa/assignments.cpp | 44 ++++++++++----------- src/ssa/assignments.h | 6 +++ src/ssa/local_ssa.cpp | 51 ++++++++++++++++--------- src/ssa/local_ssa.h | 1 + 7 files changed, 140 insertions(+), 44 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index ecfa36588..a6ce6fc62 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -1287,7 +1287,7 @@ bool twols_parse_optionst::process_goto_program( } std::map dynobj_instances; - forall_goto_functions(f_it, goto_model.goto_functions) + Forall_goto_functions(f_it, goto_model.goto_functions) { if (!f_it->second.body_available()) continue; @@ -1297,7 +1297,10 @@ bool twols_parse_optionst::process_goto_program( dynobj_instance_analysist do_inst(f_it->second, ns, value_analysis); do_inst.output(ns, f_it->second, std::cerr); - compute_dynobj_instances(f_it->second.body, do_inst, dynobj_instances, ns); + compute_dynobj_instances( + f_it->second.body, do_inst, dynobj_instances, ns); + create_dynobj_instances( + f_it->second.body, dynobj_instances, goto_model.symbol_table); } if(!cmdline.isset("independent-properties")) diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index 46e9cebc7..c2ea47896 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -16,6 +16,7 @@ Author: Daniel Kroening, Peter Schrammel #include #include +#include class goto_modelt; class optionst; @@ -191,6 +192,10 @@ class twols_parse_optionst: const dynobj_instance_analysist &analysis, std::map &instance_counts, const namespacet &ns); + void create_dynobj_instances( + goto_programt &goto_program, + const std::map &instance_counts, + symbol_tablet &symbol_table); }; #endif diff --git a/src/2ls/preprocessing_util.cpp b/src/2ls/preprocessing_util.cpp index 1ab37150a..971c27a59 100644 --- a/src/2ls/preprocessing_util.cpp +++ b/src/2ls/preprocessing_util.cpp @@ -734,3 +734,73 @@ void twols_parse_optionst::compute_dynobj_instances( } } } + +void twols_parse_optionst::create_dynobj_instances( + goto_programt &goto_program, + const std::map &instance_counts, + symbol_tablet &symbol_table) +{ + Forall_goto_program_instructions(it, goto_program) + { + if (it->is_assign()) + { + auto &assign = to_code_assign(it->code); + if (assign.rhs().get_bool("#malloc_result")) + { + exprt &rhs = assign.rhs(); + exprt &address=rhs.id()==ID_typecast ? to_typecast_expr(rhs).op() : rhs; + assert(address.id() == ID_address_of); + exprt &obj = to_address_of_expr(address).object(); + assert(obj.id() == ID_symbol); + + if (instance_counts.find(to_symbol_expr(obj)) == instance_counts.end()) + continue; + + size_t count = instance_counts.at(to_symbol_expr(obj)); + if (count <= 1) + continue; + + symbolt obj_symbol= + symbol_table.lookup(to_symbol_expr(obj).get_identifier()); + + const std::string name = id2string(obj_symbol.name); + const std::string base_name = id2string(obj_symbol.base_name); + std::string suffix = "#" + std::to_string(0); + + obj_symbol.name = name + suffix; + obj_symbol.base_name = base_name + suffix; + symbol_table.add(obj_symbol); + + exprt new_rhs = address_of_exprt(obj_symbol.symbol_expr()); + if (rhs.id() == ID_typecast) + new_rhs = typecast_exprt(new_rhs, rhs.type()); + new_rhs.set("#malloc_result", true); + + for (size_t i = 1; i < count; ++i) + { + symbolt nondet; + nondet.type = bool_typet(); + nondet.name="$guard#os"+std::to_string(it->location_number)+"#"+ + std::to_string(i); + nondet.base_name = nondet.name; + nondet.pretty_name = nondet.name; + symbol_table.add(nondet); + + suffix = "#" + std::to_string(i); + obj_symbol.name = name + suffix; + obj_symbol.base_name = base_name + suffix; + + exprt new_obj = address_of_exprt(obj_symbol.symbol_expr()); + if (rhs.id() == ID_typecast) + new_obj = typecast_exprt(new_obj, rhs.type()); + new_rhs=if_exprt( + nondet.symbol_expr(), new_obj, new_rhs); + new_rhs.set("#malloc_result", true); + } + + rhs = new_rhs; + rhs.set("#malloc_result", true); + } + } + } +} diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index 06ea0673b..39b7c63fb 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -49,29 +49,7 @@ void assignmentst::build_assignment_map( // At allocations site, save newly allocated object(s) if (code_assign.rhs().get_bool("#malloc_result")) { - exprt alloc_res=code_assign.rhs(); - if(alloc_res.id()==ID_typecast) - alloc_res=to_typecast_expr(alloc_res).op(); - if(alloc_res.id()==ID_if) - { - exprt object=to_if_expr(alloc_res).false_case(); - if(object.id()==ID_address_of) - object=to_address_of_expr(object).object(); - - exprt concrete_object=to_if_expr(alloc_res).true_case(); - if(concrete_object.id()==ID_address_of) - concrete_object=to_address_of_expr(concrete_object).object(); - - allocation_map[it].insert(ssa_objectt(object, ns)); - allocation_map[it].insert(ssa_objectt(concrete_object, ns)); - } - else - { - exprt object=alloc_res; - if(object.id()==ID_address_of) - object=to_address_of_expr(object).object(); - allocation_map[it].insert(ssa_objectt(object, ns)); - } + allocate(code_assign.rhs(), it, ns); } } else if(it->is_assert()) @@ -335,3 +313,23 @@ void assignmentst::output( out << "\n"; } } + +void assignmentst::allocate( + const exprt &expr, + const assignmentst::locationt loc, + const namespacet &ns) +{ + if(expr.id()==ID_symbol && expr.type().get_bool("#dynamic")) + { + allocation_map[loc].insert(ssa_objectt(expr, ns)); + } + else if (expr.id() == ID_if) + { + allocate(to_if_expr(expr).true_case(), loc, ns); + allocate(to_if_expr(expr).false_case(), loc, ns); + } + else if (expr.id() == ID_address_of) + allocate(to_address_of_expr(expr).object(), loc, ns); + else if (expr.id() == ID_typecast) + allocate(to_typecast_expr(expr).op(), loc, ns); +} diff --git a/src/ssa/assignments.h b/src/ssa/assignments.h index 981355157..b0b054ce1 100644 --- a/src/ssa/assignments.h +++ b/src/ssa/assignments.h @@ -87,6 +87,12 @@ class assignmentst const exprt &expr, const locationt &loc, const namespacet &ns); + + void allocate( + const exprt &expr, + const locationt loc, + const namespacet &ns + ); }; #endif diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 6d685a639..1bf59743c 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -57,7 +57,7 @@ void local_SSAt::build_SSA() build_guard(i_it); build_assertions(i_it); build_function_call(i_it); - build_unknown_objs(i_it); +// build_unknown_objs(i_it); collect_record_frees(i_it); } @@ -1897,7 +1897,7 @@ void local_SSAt::build_unknown_objs(locationt loc) const exprt &malloc_res= rhs.id()==ID_typecast ? to_typecast_expr(rhs).op() : rhs; const exprt &addr_of_do= - malloc_res.id()==ID_if ? to_if_expr(malloc_res).false_case() + malloc_res.id()==ID_if ? to_if_expr(malloc_res).true_case() : malloc_res; const exprt &dyn_obj=to_address_of_expr(addr_of_do).object(); const typet &dyn_type=ns.follow(dyn_obj.type()); @@ -2146,23 +2146,10 @@ void local_SSAt::collect_allocation_guards( rhs=to_typecast_expr(rhs).op(); if(rhs.id()==ID_if) { - const if_exprt &malloc_res=to_if_expr(rhs); - assert(malloc_res.true_case().id()==ID_address_of); - assert(malloc_res.false_case().id()==ID_address_of); - - const exprt &object=to_address_of_expr(malloc_res.false_case()).object(); - const exprt &co_object=to_address_of_expr(malloc_res.true_case()).object(); - assert(object.id()==ID_symbol && co_object.id()==ID_symbol); - - std::string co_object_id=id2string( - to_symbol_expr(co_object).get_identifier()); - std::string object_id=id2string(to_symbol_expr(object).get_identifier()); - allocation_guards.emplace( - to_symbol_expr(co_object).get_identifier(), - read_rhs(malloc_res.cond(), loc)); - allocation_guards.emplace( - to_symbol_expr(object).get_identifier(), - read_rhs(not_exprt(malloc_res.cond()), loc)); + get_alloc_guard_rec( + to_if_expr(rhs).true_case(), to_if_expr(rhs).cond(), loc); + get_alloc_guard_rec( + to_if_expr(rhs).false_case(), not_exprt(to_if_expr(rhs).cond()), loc); } } @@ -2182,3 +2169,29 @@ void local_SSAt::collect_record_frees(local_SSAt::locationt loc) } } } + +void local_SSAt::get_alloc_guard_rec( + const exprt &expr, + exprt guard, + locationt loc) +{ + if (expr.id() == ID_symbol && expr.type().get_bool("#dynamic")) + { + allocation_guards.emplace(to_symbol_expr(expr).get_identifier(), guard); + } + else if(expr.id()==ID_if) + { + get_alloc_guard_rec( + to_if_expr(expr).true_case(), + and_exprt(guard, to_if_expr(expr).cond()), + loc); + get_alloc_guard_rec( + to_if_expr(expr).false_case(), + and_exprt(guard, not_exprt(to_if_expr(expr).cond())), + loc); + } + else if(expr.id()==ID_typecast) + get_alloc_guard_rec(to_typecast_expr(expr).op(), guard, loc); + else if (expr.id()==ID_address_of) + get_alloc_guard_rec(to_address_of_expr(expr).object(), guard, loc); +} diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 86eb4c087..23b578cb5 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -284,6 +284,7 @@ class local_SSAt void build_unknown_objs(locationt loc); void collect_allocation_guards(const code_assignt &assign, locationt loc); + void get_alloc_guard_rec(const exprt &expr, exprt old_guard, locationt loc); void collect_record_frees(locationt loc); // custom templates From 328499c94afe9b24e3ef8e052ff79b1a13f7cb82 Mon Sep 17 00:00:00 2001 From: Martin Hruska Date: Fri, 18 May 2018 09:51:34 +0200 Subject: [PATCH 203/322] rhs_concretisaztion --- src/ssa/dynobj_instance_analysis.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ssa/dynobj_instance_analysis.h b/src/ssa/dynobj_instance_analysis.h index 66aa5daeb..19b0dd39e 100644 --- a/src/ssa/dynobj_instance_analysis.h +++ b/src/ssa/dynobj_instance_analysis.h @@ -137,6 +137,12 @@ class dynobj_instance_domaint:public ai_domain_baset protected: +private: + void rhs_concretisation( + const exprt &guard, + ai_domain_baset::locationt loc, + ai_baset &ai, + const namespacet &ns); }; class dynobj_instance_analysist:public ait From df862c9b3a3958f034d74d7ac448b93a32fece5f Mon Sep 17 00:00:00 2001 From: Martin Hruska Date: Fri, 18 May 2018 09:51:36 +0200 Subject: [PATCH 204/322] rhs_concretisaztion --- src/ssa/dynobj_instance_analysis.cpp | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/ssa/dynobj_instance_analysis.cpp b/src/ssa/dynobj_instance_analysis.cpp index 86fb6494f..9358908cc 100644 --- a/src/ssa/dynobj_instance_analysis.cpp +++ b/src/ssa/dynobj_instance_analysis.cpp @@ -56,6 +56,44 @@ void add_aliased_dereferences(const exprt &pointer, must_alias_setst &instances) } } +void dynobj_instance_domaint::rhs_concretisation( + const exprt &guard, + ai_domain_baset::locationt loc, + ai_baset &ai, + const namespacet &ns) +{ + forall_operands(it, guard) + { + if(it->id() == ID_symbol || it->id() == ID_member) + { + bool found=false; + for(const auto &i:dynobj_instances) + { + unsigned long n; + found |= !i.second.get_number(*it, n); + } + if (!found) + { + // 1) now make derefence + const auto &values= + static_cast(ai).value_analysis[loc]; + const auto guard_deref = dereference(guard, values, "", ns); + auto value_set = values(guard_deref, ns).value_set; + // 2) then isolate for all values in vaulue set of dereferences + for (auto &v : value_set) + { + auto &instances = dynobj_instances[v.symbol_expr()]; + instances.isolate(*it); + } + } + } + else + { + rhs_concretisation(*it, loc, ai, ns); + } + } +} + void dynobj_instance_domaint::transform( ai_domain_baset::locationt from, ai_domain_baset::locationt to, @@ -103,6 +141,8 @@ void dynobj_instance_domaint::transform( } } } + else if (from->is_goto() || from->is_assume()) + rhs_concretisation(from->guard, from, ai, ns); else if (from->is_dead()) { const exprt &symbol = to_code_dead(from->code).symbol(); From 970b11b2cb2ecf31428d6ce0d3a8547fd3364f14 Mon Sep 17 00:00:00 2001 From: Martin Hruska Date: Fri, 18 May 2018 10:27:42 +0200 Subject: [PATCH 205/322] adding case for assert --- src/ssa/dynobj_instance_analysis.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ssa/dynobj_instance_analysis.cpp b/src/ssa/dynobj_instance_analysis.cpp index 9358908cc..a32d57f27 100644 --- a/src/ssa/dynobj_instance_analysis.cpp +++ b/src/ssa/dynobj_instance_analysis.cpp @@ -141,7 +141,7 @@ void dynobj_instance_domaint::transform( } } } - else if (from->is_goto() || from->is_assume()) + else if (from->is_goto() || from->is_assume() || from->is_assert()) rhs_concretisation(from->guard, from, ai, ns); else if (from->is_dead()) { From f665fb1db2433ac1d777f95cdf6b91e8aa28f921 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 21 May 2018 14:04:57 +0200 Subject: [PATCH 206/322] Template polyhedra domain: do not generate template rows with 'false' guard. This might occur when creating difference row for dynamic objects that cannot co-exist (i.e. instances of the same dynamic object). --- src/domains/tpolyhedra_domain.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/domains/tpolyhedra_domain.cpp b/src/domains/tpolyhedra_domain.cpp index 389bf2d57..8673ebec5 100644 --- a/src/domains/tpolyhedra_domain.cpp +++ b/src/domains/tpolyhedra_domain.cpp @@ -1069,6 +1069,8 @@ void tpolyhedra_domaint::add_difference_template( merge_and(pre_g, v1->pre_guard, v2->pre_guard, ns); merge_and(post_g, v1->post_guard, v2->post_guard, ns); merge_and(aux_expr, v1->aux_expr, v2->aux_expr, ns); + if (post_g.is_false()) + continue; // x1-x2 add_template_row( From c3ab3f3aa0729fbf649231cc90e7eca3607237a8 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 25 May 2018 10:00:10 +0200 Subject: [PATCH 207/322] Update running example in sas18 directory --- regression/sas18/running_example/main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/regression/sas18/running_example/main.c b/regression/sas18/running_example/main.c index eb49e6853..95b20d438 100644 --- a/regression/sas18/running_example/main.c +++ b/regression/sas18/running_example/main.c @@ -10,16 +10,17 @@ typedef struct node { int main() { Node *p, *list = malloc(sizeof(*list)); + Node *tail = list; list->next = NULL; list->val = 10; while (__VERIFIER_nondet_int()) { int x; __CPROVER_assume(x >= 10 && x <= 20); p = malloc(sizeof(*p)); - list->next = p; + tail->next = p; p->next = NULL; p->val = x; - list = p; + tail = p; } while (1) { From 7ae872736a981b448ce9c5eb88850685bf7c0930 Mon Sep 17 00:00:00 2001 From: Martin Hruska Date: Sun, 27 May 2018 19:41:18 +0200 Subject: [PATCH 208/322] updated running example to make it work --- regression/fmcad18/running_example/main.c | 35 +++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 regression/fmcad18/running_example/main.c diff --git a/regression/fmcad18/running_example/main.c b/regression/fmcad18/running_example/main.c new file mode 100644 index 000000000..34c4e6d1b --- /dev/null +++ b/regression/fmcad18/running_example/main.c @@ -0,0 +1,35 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +typedef struct node { + int val; + struct node *next; +} Node; + +int main() { + Node *p, *list = malloc(sizeof(*list)); + Node *tail = list; + list->next = NULL; + list->val = 10; + while (__VERIFIER_nondet_int()) { + int x; + if (x < 10 || x > 20) continue; + p = malloc(sizeof(*p)); + tail->next = p; + p->next = NULL; + p->val = x; + tail = p; + } + + while (1) { + for (p = list; p!= NULL; p = p->next) { + if (!(p->val <= 20 && p->val >= 10)) + __VERIFIER_error(); + if (p->val < 20) p->val++; + else p->val /= 2; + } + } + +} From 154bb4c3ba471ac1580a5990fe5ed40357d4d5f0 Mon Sep 17 00:00:00 2001 From: Martin Hruska Date: Sun, 27 May 2018 19:41:33 +0200 Subject: [PATCH 209/322] renamed directory to fmcad --- regression/fmcad18/Makefile | 20 +++++ regression/fmcad18/calendar/main.c | 40 +++++++++ regression/fmcad18/calendar/test.desc | 6 ++ regression/fmcad18/cart/main.c | 46 +++++++++++ regression/fmcad18/cart/test.desc | 6 ++ regression/fmcad18/hash_fun/main.c | 42 ++++++++++ regression/fmcad18/hash_fun/test.desc | 6 ++ regression/fmcad18/min_max/main.c | 40 +++++++++ regression/fmcad18/min_max/test.desc | 6 ++ regression/fmcad18/packet_filter/main.c | 81 +++++++++++++++++++ regression/fmcad18/packet_filter/test.desc | 6 ++ regression/fmcad18/process_queue/main.c | 69 ++++++++++++++++ regression/fmcad18/process_queue/test.desc | 6 ++ regression/fmcad18/quick_sort_split/main.c | 62 ++++++++++++++ regression/fmcad18/quick_sort_split/test.desc | 6 ++ regression/fmcad18/running_example/test.desc | 6 ++ regression/fmcad18/shared_mem1/main.c | 49 +++++++++++ regression/fmcad18/shared_mem1/test.desc | 6 ++ regression/fmcad18/shared_mem2/main.c | 45 +++++++++++ regression/fmcad18/shared_mem2/test.desc | 6 ++ 20 files changed, 554 insertions(+) create mode 100644 regression/fmcad18/Makefile create mode 100644 regression/fmcad18/calendar/main.c create mode 100644 regression/fmcad18/calendar/test.desc create mode 100644 regression/fmcad18/cart/main.c create mode 100644 regression/fmcad18/cart/test.desc create mode 100644 regression/fmcad18/hash_fun/main.c create mode 100644 regression/fmcad18/hash_fun/test.desc create mode 100644 regression/fmcad18/min_max/main.c create mode 100644 regression/fmcad18/min_max/test.desc create mode 100644 regression/fmcad18/packet_filter/main.c create mode 100644 regression/fmcad18/packet_filter/test.desc create mode 100644 regression/fmcad18/process_queue/main.c create mode 100644 regression/fmcad18/process_queue/test.desc create mode 100644 regression/fmcad18/quick_sort_split/main.c create mode 100644 regression/fmcad18/quick_sort_split/test.desc create mode 100644 regression/fmcad18/running_example/test.desc create mode 100644 regression/fmcad18/shared_mem1/main.c create mode 100644 regression/fmcad18/shared_mem1/test.desc create mode 100644 regression/fmcad18/shared_mem2/main.c create mode 100644 regression/fmcad18/shared_mem2/test.desc diff --git a/regression/fmcad18/Makefile b/regression/fmcad18/Makefile new file mode 100644 index 000000000..34cd734b9 --- /dev/null +++ b/regression/fmcad18/Makefile @@ -0,0 +1,20 @@ +default: tests.log + +FLAGS = --verbosity 10 + +test: + @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" + +tests.log: ../test.pl + @../test.pl -p -c "../../../src/2ls/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/fmcad18/calendar/main.c b/regression/fmcad18/calendar/main.c new file mode 100644 index 000000000..2ee9630e5 --- /dev/null +++ b/regression/fmcad18/calendar/main.c @@ -0,0 +1,40 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +#define APPEND(l,i) {i->next=l; l=i;} + +typedef struct node { + struct node *next; + int event1; + int event2; +} Node; + +int main() { + Node *l = NULL; + + while (__VERIFIER_nondet_int()) { + int ev1 = __VERIFIER_nondet_int(); + int ev2 = __VERIFIER_nondet_int(); + if (ev1 < 0 || ev1 > 3 || ev2 < 0 || ev2 > 3) + continue; + + if (((ev1 == 0) && (ev2 == 2)) || ((ev1 == 1) && (ev2 == 3)) || ((ev1 == 0) && (ev2 == 3))) + continue; + + Node *p = malloc(sizeof(*p)); + p->event1 = ev1; + p->event2 = ev2; + APPEND(l,p) + } + + Node *i = l; + + while (i != NULL) { + if (((i->event1 == 1) && (i->event2 == 3)) || ((i->event1 == 0) && (i->event2 == 2))) + __VERIFIER_error(); + i = i->next; + } +} + diff --git a/regression/fmcad18/calendar/test.desc b/regression/fmcad18/calendar/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/fmcad18/calendar/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/fmcad18/cart/main.c b/regression/fmcad18/cart/main.c new file mode 100644 index 000000000..3144e411e --- /dev/null +++ b/regression/fmcad18/cart/main.c @@ -0,0 +1,46 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +#define APPEND(l,i) {i->next=l; l=i;} + +typedef struct node { + struct node *next; + int stock; + int order; +} Node; + +int main() { + Node *l = NULL; + + while (__VERIFIER_nondet_int()) { + int stock = __VERIFIER_nondet_int(); + if (stock < 0) + continue; + + Node *p = malloc(sizeof(*p)); + p->stock = stock; + p->order = 0; + APPEND(l,p) + } + + Node *i = l; + while (i != NULL) { + int order = __VERIFIER_nondet_int(); + if (order < 0 || i->stock < order) + continue; + i->order = order; + i->stock = i->stock; + i = i->next; + } + + + i = l; + while (i != NULL) { + if (i->order > i->stock) + __VERIFIER_error(); + i = i->next; + } +} + diff --git a/regression/fmcad18/cart/test.desc b/regression/fmcad18/cart/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/fmcad18/cart/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/fmcad18/hash_fun/main.c b/regression/fmcad18/hash_fun/main.c new file mode 100644 index 000000000..08fd2104a --- /dev/null +++ b/regression/fmcad18/hash_fun/main.c @@ -0,0 +1,42 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +#define INTERVAL_SIZE 100 + +struct node { + int hash; + struct node *next; +}; + +int hash_fun(); + +void append_to_list(struct node **list, int hash) { + struct node *node = malloc(sizeof(*node)); + node->next = *list; + node->hash = hash; + *list = node; +} + +int main() { + struct node *list = NULL; + + int base = __VERIFIER_nondet_int(); + + while (__VERIFIER_nondet_int()) { + if (base >= 0 && base <= 1000000) { + base = base; + int hash = hash_fun(); + + if (hash > base && hash < base + INTERVAL_SIZE) + append_to_list(&list, hash); + } + } + + while (list) { + if (!(list->hash >= base && list->hash < base + INTERVAL_SIZE)) + __VERIFIER_error(); + list = list->next; + } +} diff --git a/regression/fmcad18/hash_fun/test.desc b/regression/fmcad18/hash_fun/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/fmcad18/hash_fun/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/fmcad18/min_max/main.c b/regression/fmcad18/min_max/main.c new file mode 100644 index 000000000..76b129535 --- /dev/null +++ b/regression/fmcad18/min_max/main.c @@ -0,0 +1,40 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include +#include + +#define APPEND(l,i) {i->next=l; l=i;} + +typedef struct node { + struct node *next; + int val; +} Node; + +int main() { + Node *l = NULL; + int min = INT_MAX, max = -INT_MAX; + + while (__VERIFIER_nondet_int()) { + Node *p = malloc(sizeof(*p)); + p->val = __VERIFIER_nondet_int(); + APPEND(l, p) + + if (min > p->val) { + min = p->val; + } + if (max < p->val) { + max = p->val; + } + + } + + Node *i = l; + while (i != NULL) { + if (i->val < min) + __VERIFIER_error(); + if (i->val > max) + __VERIFIER_error(); + i = i->next; + } +} diff --git a/regression/fmcad18/min_max/test.desc b/regression/fmcad18/min_max/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/fmcad18/min_max/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/fmcad18/packet_filter/main.c b/regression/fmcad18/packet_filter/main.c new file mode 100644 index 000000000..b2a16f4b4 --- /dev/null +++ b/regression/fmcad18/packet_filter/main.c @@ -0,0 +1,81 @@ +extern unsigned __VERIFIER_nondet_uint(); +extern int __VERIFIER_nondet_int(); +extern char *__VERIFIER_nondet_charp(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +#define LOW 0 +#define HIGH 1 + +typedef struct packet { + unsigned size; + unsigned prio; + char *payload; +} Packet; + +typedef struct packet_list_node { + struct packet packet; + struct packet_list_node *next; +} *Node; + +struct packet_queue { + struct packet_list_node *front; +}; + + +Packet receive() { + Packet packet; + packet.size = __VERIFIER_nondet_uint(); + packet.prio = __VERIFIER_nondet_int() ? LOW : HIGH; + packet.payload = __VERIFIER_nondet_charp(); + return packet; +} + +extern void send(struct packet p); + +void append_to_queue(Packet p, Node *q) { + Node node = malloc(sizeof(*node)); + node->packet = p; + node->next = *q; + *q = node; +} + +void process_prio_queue(Node q) { + for (Node node = q; node != NULL; node = node->next) { + if (!(node->packet.prio == HIGH || node->packet.size < 500)) + __VERIFIER_error(); + send(node->packet); + } +} + +void process_normal_queue(Node q) { + for (Node node = q; node != NULL; node = node->next) { + if (!(node->packet.prio == LOW && node->packet.size >= 500)) + __VERIFIER_error(); + send(node->packet); + } +} + +int main() { + Node prio_queue = NULL; + Node normal_queue = NULL; + + while (__VERIFIER_nondet_int()) { + Packet new_packet = receive(); + if (new_packet.size > 0) { + if (new_packet.prio == HIGH) { + append_to_queue(new_packet, &prio_queue); + } else if (new_packet.size < 500) { + append_to_queue(new_packet, &prio_queue); + } else { + append_to_queue(new_packet, &normal_queue); + } + } + } + + process_prio_queue(prio_queue); + process_normal_queue(normal_queue); + + return 0; +} diff --git a/regression/fmcad18/packet_filter/test.desc b/regression/fmcad18/packet_filter/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/fmcad18/packet_filter/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/fmcad18/process_queue/main.c b/regression/fmcad18/process_queue/main.c new file mode 100644 index 000000000..1299105de --- /dev/null +++ b/regression/fmcad18/process_queue/main.c @@ -0,0 +1,69 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +#define MAX_PROC 1000 + +struct process_node { + int process_id; + int time_to_wait; + + struct process_node *next; +}; + +extern void run_process(int id); + +void append_to_queue(struct process_node *n, struct process_node **q) { + n->next = *q; + *q = n; +} + +struct process_node *choose_next(struct process_node **q) { + struct process_node *node = *q; + struct process_node *prev = NULL; + struct process_node *result = NULL; + while (node != NULL) { + if (node->time_to_wait == 1) { + result = node; + if (prev == NULL) + *q = node->next; + else + prev->next = node->next; + } else { + node->time_to_wait--; + } + prev = node; + node = node->next; + } + return result; +} + +void check_queue(struct process_node *q) { + for (struct process_node *n = q; n != NULL; n = n->next) + if (!n->time_to_wait >= 1) + __VERIFIER_error(); +} + + +int main() { + struct process_node *queue = NULL; + int next_time = 1; + + while (__VERIFIER_nondet_int()) { + if (next_time < MAX_PROC && __VERIFIER_nondet_int()) { + int new_id = __VERIFIER_nondet_int(); + + struct process_node *new_process = malloc(sizeof(*new_process)); + new_process->process_id = __VERIFIER_nondet_int(); + new_process->time_to_wait = next_time++; + append_to_queue(new_process, &queue); + } else if (next_time > 1){ + struct process_node *p = choose_next(&queue); + next_time--; + run_process(p->process_id); + } + + check_queue(queue); + } +} diff --git a/regression/fmcad18/process_queue/test.desc b/regression/fmcad18/process_queue/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/fmcad18/process_queue/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/fmcad18/quick_sort_split/main.c b/regression/fmcad18/quick_sort_split/main.c new file mode 100644 index 000000000..c286aa4e8 --- /dev/null +++ b/regression/fmcad18/quick_sort_split/main.c @@ -0,0 +1,62 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +#define LOW -1 +#define HIGH 1 + +struct node { + int expected_list; + int value; + struct node *next; +}; + +void append_to_list(struct node **list, int val, int exp) { + struct node *node = malloc(sizeof(*node)); + node->next = *list; + node->value = val; + node->expected_list = exp; + *list = node; +} + +struct node *create_list() { + struct node *list = NULL; + while (__VERIFIER_nondet_int()) { + int v = __VERIFIER_nondet_int(); + if (v < 0) + append_to_list(&list, v, LOW); + else + append_to_list(&list, v, HIGH); + } + return list; +} + +int main() { + struct node *list = create_list(); + + struct node *low = NULL; + struct node *high = NULL; + + // Split list into low and high + struct node *p = list; + while (p) { + struct node *l = p->value >= 0 ? high : low; + struct node *next = p->next; + p->next = l; + l = p; + p = next; + } + + // Check that low and high contain expected elements + while (low) { + if (!low->expected_list == LOW) + __VERIFIER_error(); + low = low->next; + } + while (high) { + if (!high->expected_list == HIGH) + __VERIFIER_error(); + high = high->next; + } +} diff --git a/regression/fmcad18/quick_sort_split/test.desc b/regression/fmcad18/quick_sort_split/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/fmcad18/quick_sort_split/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/fmcad18/running_example/test.desc b/regression/fmcad18/running_example/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/fmcad18/running_example/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/fmcad18/shared_mem1/main.c b/regression/fmcad18/shared_mem1/main.c new file mode 100644 index 000000000..d80939e92 --- /dev/null +++ b/regression/fmcad18/shared_mem1/main.c @@ -0,0 +1,49 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +struct mem { + int val; +}; + +struct list_node { + int x; + struct mem *mem; + struct list_node *next; +}; + +int main() { + struct mem *m = malloc(sizeof(*m)); + m->val = 100; + + struct list_node *head = malloc(sizeof(*head)); + head->x = 1; + head->mem = m; + head->next = head; + + struct list_node *list = head; + + while (__VERIFIER_nondet_int()) { + int x; + if (x > 0 && x < 10) { + struct list_node *n = malloc(sizeof(*n)); + n->x = x; + n->mem = m; + n->next = head; + list->next = n; + } + } + + list = head; + while (list) { + if (list->mem->val <= 100) + list->mem->val += list->x; + else + list->mem->val -= list->x; + list = list->next; + + if (!(m->val > 90 && m->val < 110)) + __VERIFIER_error(); + } +} diff --git a/regression/fmcad18/shared_mem1/test.desc b/regression/fmcad18/shared_mem1/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/fmcad18/shared_mem1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/fmcad18/shared_mem2/main.c b/regression/fmcad18/shared_mem2/main.c new file mode 100644 index 000000000..dd4f6466d --- /dev/null +++ b/regression/fmcad18/shared_mem2/main.c @@ -0,0 +1,45 @@ +extern int __VERIFIER_nondet_int(); + +#include + +struct mem { + int val; +}; + +struct list_node { + int x; + struct mem *mem; + struct list_node *next; +}; + +int main() { + struct mem *m = malloc(sizeof(*m)); + m->val = 0; + + struct list_node *head = malloc(sizeof(*head)); + head->x = 1; + head->mem = m; + head->next = head; + + struct list_node *list = head; + + while (__VERIFIER_nondet_int()) { + int x; + if (x > 0 && x < 10) { + struct list_node *n = malloc(sizeof(*n)); + n->x = x; + n->mem = m; + n->next = head; + list->next = n; + } + } + + list = head; + while (m->val < 100) { + if (list->mem->val + list->x <= 100) + list->mem->val += list->x; + list = list->next; + } + if (!m->val == 100) + __VERIFIER_nondet_int(); +} diff --git a/regression/fmcad18/shared_mem2/test.desc b/regression/fmcad18/shared_mem2/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/fmcad18/shared_mem2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ From cf39cd2fff64e8754108e350c1daf77773e18dfd Mon Sep 17 00:00:00 2001 From: Martin Hruska Date: Sun, 27 May 2018 19:42:43 +0200 Subject: [PATCH 210/322] problematic version of running example --- regression/heap/running_example_assume/main.c | 35 +++++++++++++++++++ .../heap/running_example_assume/test.desc | 6 ++++ 2 files changed, 41 insertions(+) create mode 100644 regression/heap/running_example_assume/main.c create mode 100644 regression/heap/running_example_assume/test.desc diff --git a/regression/heap/running_example_assume/main.c b/regression/heap/running_example_assume/main.c new file mode 100644 index 000000000..95b20d438 --- /dev/null +++ b/regression/heap/running_example_assume/main.c @@ -0,0 +1,35 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +typedef struct node { + int val; + struct node *next; +} Node; + +int main() { + Node *p, *list = malloc(sizeof(*list)); + Node *tail = list; + list->next = NULL; + list->val = 10; + while (__VERIFIER_nondet_int()) { + int x; + __CPROVER_assume(x >= 10 && x <= 20); + p = malloc(sizeof(*p)); + tail->next = p; + p->next = NULL; + p->val = x; + tail = p; + } + + while (1) { + for (p = list; p!= NULL; p = p->next) { + if (!(p->val <= 20 && p->val >= 10)) + __VERIFIER_error(); + if (p->val < 20) p->val++; + else p->val /= 2; + } + } + +} diff --git a/regression/heap/running_example_assume/test.desc b/regression/heap/running_example_assume/test.desc new file mode 100644 index 000000000..bd68e9d2c --- /dev/null +++ b/regression/heap/running_example_assume/test.desc @@ -0,0 +1,6 @@ +KNOWNBUG +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ From 0cbf7de828406b21becb85dfd495df1fa2aa35ac Mon Sep 17 00:00:00 2001 From: Martin Hruska Date: Sun, 27 May 2018 19:43:44 +0200 Subject: [PATCH 211/322] sas18 to fmcad18 --- regression/sas18/Makefile | 20 ----- regression/sas18/calendar/main.c | 40 ---------- regression/sas18/calendar/test.desc | 6 -- regression/sas18/cart/main.c | 46 ------------ regression/sas18/cart/test.desc | 6 -- regression/sas18/hash_fun/main.c | 42 ----------- regression/sas18/hash_fun/test.desc | 6 -- regression/sas18/min_max/main.c | 40 ---------- regression/sas18/min_max/test.desc | 6 -- regression/sas18/packet_filter/main.c | 81 --------------------- regression/sas18/packet_filter/test.desc | 6 -- regression/sas18/process_queue/main.c | 69 ------------------ regression/sas18/process_queue/test.desc | 6 -- regression/sas18/quick_sort_split/main.c | 62 ---------------- regression/sas18/quick_sort_split/test.desc | 6 -- regression/sas18/running_example/main.c | 35 --------- regression/sas18/running_example/test.desc | 6 -- regression/sas18/shared_mem1/main.c | 49 ------------- regression/sas18/shared_mem1/test.desc | 6 -- regression/sas18/shared_mem2/main.c | 45 ------------ regression/sas18/shared_mem2/test.desc | 6 -- 21 files changed, 589 deletions(-) delete mode 100644 regression/sas18/Makefile delete mode 100644 regression/sas18/calendar/main.c delete mode 100644 regression/sas18/calendar/test.desc delete mode 100644 regression/sas18/cart/main.c delete mode 100644 regression/sas18/cart/test.desc delete mode 100644 regression/sas18/hash_fun/main.c delete mode 100644 regression/sas18/hash_fun/test.desc delete mode 100644 regression/sas18/min_max/main.c delete mode 100644 regression/sas18/min_max/test.desc delete mode 100644 regression/sas18/packet_filter/main.c delete mode 100644 regression/sas18/packet_filter/test.desc delete mode 100644 regression/sas18/process_queue/main.c delete mode 100644 regression/sas18/process_queue/test.desc delete mode 100644 regression/sas18/quick_sort_split/main.c delete mode 100644 regression/sas18/quick_sort_split/test.desc delete mode 100644 regression/sas18/running_example/main.c delete mode 100644 regression/sas18/running_example/test.desc delete mode 100644 regression/sas18/shared_mem1/main.c delete mode 100644 regression/sas18/shared_mem1/test.desc delete mode 100644 regression/sas18/shared_mem2/main.c delete mode 100644 regression/sas18/shared_mem2/test.desc diff --git a/regression/sas18/Makefile b/regression/sas18/Makefile deleted file mode 100644 index 34cd734b9..000000000 --- a/regression/sas18/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -default: tests.log - -FLAGS = --verbosity 10 - -test: - @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" - -tests.log: ../test.pl - @../test.pl -p -c "../../../src/2ls/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/sas18/calendar/main.c b/regression/sas18/calendar/main.c deleted file mode 100644 index 2ee9630e5..000000000 --- a/regression/sas18/calendar/main.c +++ /dev/null @@ -1,40 +0,0 @@ -extern int __VERIFIER_nondet_int(); -extern void __VERIFIER_error() __attribute__ ((__noreturn__)); - -#include - -#define APPEND(l,i) {i->next=l; l=i;} - -typedef struct node { - struct node *next; - int event1; - int event2; -} Node; - -int main() { - Node *l = NULL; - - while (__VERIFIER_nondet_int()) { - int ev1 = __VERIFIER_nondet_int(); - int ev2 = __VERIFIER_nondet_int(); - if (ev1 < 0 || ev1 > 3 || ev2 < 0 || ev2 > 3) - continue; - - if (((ev1 == 0) && (ev2 == 2)) || ((ev1 == 1) && (ev2 == 3)) || ((ev1 == 0) && (ev2 == 3))) - continue; - - Node *p = malloc(sizeof(*p)); - p->event1 = ev1; - p->event2 = ev2; - APPEND(l,p) - } - - Node *i = l; - - while (i != NULL) { - if (((i->event1 == 1) && (i->event2 == 3)) || ((i->event1 == 0) && (i->event2 == 2))) - __VERIFIER_error(); - i = i->next; - } -} - diff --git a/regression/sas18/calendar/test.desc b/regression/sas18/calendar/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/sas18/calendar/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/cart/main.c b/regression/sas18/cart/main.c deleted file mode 100644 index 3144e411e..000000000 --- a/regression/sas18/cart/main.c +++ /dev/null @@ -1,46 +0,0 @@ -extern int __VERIFIER_nondet_int(); -extern void __VERIFIER_error() __attribute__ ((__noreturn__)); - -#include - -#define APPEND(l,i) {i->next=l; l=i;} - -typedef struct node { - struct node *next; - int stock; - int order; -} Node; - -int main() { - Node *l = NULL; - - while (__VERIFIER_nondet_int()) { - int stock = __VERIFIER_nondet_int(); - if (stock < 0) - continue; - - Node *p = malloc(sizeof(*p)); - p->stock = stock; - p->order = 0; - APPEND(l,p) - } - - Node *i = l; - while (i != NULL) { - int order = __VERIFIER_nondet_int(); - if (order < 0 || i->stock < order) - continue; - i->order = order; - i->stock = i->stock; - i = i->next; - } - - - i = l; - while (i != NULL) { - if (i->order > i->stock) - __VERIFIER_error(); - i = i->next; - } -} - diff --git a/regression/sas18/cart/test.desc b/regression/sas18/cart/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/sas18/cart/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/hash_fun/main.c b/regression/sas18/hash_fun/main.c deleted file mode 100644 index 08fd2104a..000000000 --- a/regression/sas18/hash_fun/main.c +++ /dev/null @@ -1,42 +0,0 @@ -extern int __VERIFIER_nondet_int(); -extern void __VERIFIER_error() __attribute__ ((__noreturn__)); - -#include - -#define INTERVAL_SIZE 100 - -struct node { - int hash; - struct node *next; -}; - -int hash_fun(); - -void append_to_list(struct node **list, int hash) { - struct node *node = malloc(sizeof(*node)); - node->next = *list; - node->hash = hash; - *list = node; -} - -int main() { - struct node *list = NULL; - - int base = __VERIFIER_nondet_int(); - - while (__VERIFIER_nondet_int()) { - if (base >= 0 && base <= 1000000) { - base = base; - int hash = hash_fun(); - - if (hash > base && hash < base + INTERVAL_SIZE) - append_to_list(&list, hash); - } - } - - while (list) { - if (!(list->hash >= base && list->hash < base + INTERVAL_SIZE)) - __VERIFIER_error(); - list = list->next; - } -} diff --git a/regression/sas18/hash_fun/test.desc b/regression/sas18/hash_fun/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/sas18/hash_fun/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/min_max/main.c b/regression/sas18/min_max/main.c deleted file mode 100644 index 76b129535..000000000 --- a/regression/sas18/min_max/main.c +++ /dev/null @@ -1,40 +0,0 @@ -extern int __VERIFIER_nondet_int(); -extern void __VERIFIER_error() __attribute__ ((__noreturn__)); - -#include -#include - -#define APPEND(l,i) {i->next=l; l=i;} - -typedef struct node { - struct node *next; - int val; -} Node; - -int main() { - Node *l = NULL; - int min = INT_MAX, max = -INT_MAX; - - while (__VERIFIER_nondet_int()) { - Node *p = malloc(sizeof(*p)); - p->val = __VERIFIER_nondet_int(); - APPEND(l, p) - - if (min > p->val) { - min = p->val; - } - if (max < p->val) { - max = p->val; - } - - } - - Node *i = l; - while (i != NULL) { - if (i->val < min) - __VERIFIER_error(); - if (i->val > max) - __VERIFIER_error(); - i = i->next; - } -} diff --git a/regression/sas18/min_max/test.desc b/regression/sas18/min_max/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/sas18/min_max/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/packet_filter/main.c b/regression/sas18/packet_filter/main.c deleted file mode 100644 index b2a16f4b4..000000000 --- a/regression/sas18/packet_filter/main.c +++ /dev/null @@ -1,81 +0,0 @@ -extern unsigned __VERIFIER_nondet_uint(); -extern int __VERIFIER_nondet_int(); -extern char *__VERIFIER_nondet_charp(); -extern void __VERIFIER_error() __attribute__ ((__noreturn__)); - -#include - -#define LOW 0 -#define HIGH 1 - -typedef struct packet { - unsigned size; - unsigned prio; - char *payload; -} Packet; - -typedef struct packet_list_node { - struct packet packet; - struct packet_list_node *next; -} *Node; - -struct packet_queue { - struct packet_list_node *front; -}; - - -Packet receive() { - Packet packet; - packet.size = __VERIFIER_nondet_uint(); - packet.prio = __VERIFIER_nondet_int() ? LOW : HIGH; - packet.payload = __VERIFIER_nondet_charp(); - return packet; -} - -extern void send(struct packet p); - -void append_to_queue(Packet p, Node *q) { - Node node = malloc(sizeof(*node)); - node->packet = p; - node->next = *q; - *q = node; -} - -void process_prio_queue(Node q) { - for (Node node = q; node != NULL; node = node->next) { - if (!(node->packet.prio == HIGH || node->packet.size < 500)) - __VERIFIER_error(); - send(node->packet); - } -} - -void process_normal_queue(Node q) { - for (Node node = q; node != NULL; node = node->next) { - if (!(node->packet.prio == LOW && node->packet.size >= 500)) - __VERIFIER_error(); - send(node->packet); - } -} - -int main() { - Node prio_queue = NULL; - Node normal_queue = NULL; - - while (__VERIFIER_nondet_int()) { - Packet new_packet = receive(); - if (new_packet.size > 0) { - if (new_packet.prio == HIGH) { - append_to_queue(new_packet, &prio_queue); - } else if (new_packet.size < 500) { - append_to_queue(new_packet, &prio_queue); - } else { - append_to_queue(new_packet, &normal_queue); - } - } - } - - process_prio_queue(prio_queue); - process_normal_queue(normal_queue); - - return 0; -} diff --git a/regression/sas18/packet_filter/test.desc b/regression/sas18/packet_filter/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/sas18/packet_filter/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/process_queue/main.c b/regression/sas18/process_queue/main.c deleted file mode 100644 index 1299105de..000000000 --- a/regression/sas18/process_queue/main.c +++ /dev/null @@ -1,69 +0,0 @@ -extern int __VERIFIER_nondet_int(); -extern void __VERIFIER_error() __attribute__ ((__noreturn__)); - -#include - -#define MAX_PROC 1000 - -struct process_node { - int process_id; - int time_to_wait; - - struct process_node *next; -}; - -extern void run_process(int id); - -void append_to_queue(struct process_node *n, struct process_node **q) { - n->next = *q; - *q = n; -} - -struct process_node *choose_next(struct process_node **q) { - struct process_node *node = *q; - struct process_node *prev = NULL; - struct process_node *result = NULL; - while (node != NULL) { - if (node->time_to_wait == 1) { - result = node; - if (prev == NULL) - *q = node->next; - else - prev->next = node->next; - } else { - node->time_to_wait--; - } - prev = node; - node = node->next; - } - return result; -} - -void check_queue(struct process_node *q) { - for (struct process_node *n = q; n != NULL; n = n->next) - if (!n->time_to_wait >= 1) - __VERIFIER_error(); -} - - -int main() { - struct process_node *queue = NULL; - int next_time = 1; - - while (__VERIFIER_nondet_int()) { - if (next_time < MAX_PROC && __VERIFIER_nondet_int()) { - int new_id = __VERIFIER_nondet_int(); - - struct process_node *new_process = malloc(sizeof(*new_process)); - new_process->process_id = __VERIFIER_nondet_int(); - new_process->time_to_wait = next_time++; - append_to_queue(new_process, &queue); - } else if (next_time > 1){ - struct process_node *p = choose_next(&queue); - next_time--; - run_process(p->process_id); - } - - check_queue(queue); - } -} diff --git a/regression/sas18/process_queue/test.desc b/regression/sas18/process_queue/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/sas18/process_queue/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/quick_sort_split/main.c b/regression/sas18/quick_sort_split/main.c deleted file mode 100644 index c286aa4e8..000000000 --- a/regression/sas18/quick_sort_split/main.c +++ /dev/null @@ -1,62 +0,0 @@ -extern int __VERIFIER_nondet_int(); -extern void __VERIFIER_error() __attribute__ ((__noreturn__)); - -#include - -#define LOW -1 -#define HIGH 1 - -struct node { - int expected_list; - int value; - struct node *next; -}; - -void append_to_list(struct node **list, int val, int exp) { - struct node *node = malloc(sizeof(*node)); - node->next = *list; - node->value = val; - node->expected_list = exp; - *list = node; -} - -struct node *create_list() { - struct node *list = NULL; - while (__VERIFIER_nondet_int()) { - int v = __VERIFIER_nondet_int(); - if (v < 0) - append_to_list(&list, v, LOW); - else - append_to_list(&list, v, HIGH); - } - return list; -} - -int main() { - struct node *list = create_list(); - - struct node *low = NULL; - struct node *high = NULL; - - // Split list into low and high - struct node *p = list; - while (p) { - struct node *l = p->value >= 0 ? high : low; - struct node *next = p->next; - p->next = l; - l = p; - p = next; - } - - // Check that low and high contain expected elements - while (low) { - if (!low->expected_list == LOW) - __VERIFIER_error(); - low = low->next; - } - while (high) { - if (!high->expected_list == HIGH) - __VERIFIER_error(); - high = high->next; - } -} diff --git a/regression/sas18/quick_sort_split/test.desc b/regression/sas18/quick_sort_split/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/sas18/quick_sort_split/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/running_example/main.c b/regression/sas18/running_example/main.c deleted file mode 100644 index 95b20d438..000000000 --- a/regression/sas18/running_example/main.c +++ /dev/null @@ -1,35 +0,0 @@ -extern int __VERIFIER_nondet_int(); -extern void __VERIFIER_error() __attribute__ ((__noreturn__)); - -#include - -typedef struct node { - int val; - struct node *next; -} Node; - -int main() { - Node *p, *list = malloc(sizeof(*list)); - Node *tail = list; - list->next = NULL; - list->val = 10; - while (__VERIFIER_nondet_int()) { - int x; - __CPROVER_assume(x >= 10 && x <= 20); - p = malloc(sizeof(*p)); - tail->next = p; - p->next = NULL; - p->val = x; - tail = p; - } - - while (1) { - for (p = list; p!= NULL; p = p->next) { - if (!(p->val <= 20 && p->val >= 10)) - __VERIFIER_error(); - if (p->val < 20) p->val++; - else p->val /= 2; - } - } - -} diff --git a/regression/sas18/running_example/test.desc b/regression/sas18/running_example/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/sas18/running_example/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/shared_mem1/main.c b/regression/sas18/shared_mem1/main.c deleted file mode 100644 index d80939e92..000000000 --- a/regression/sas18/shared_mem1/main.c +++ /dev/null @@ -1,49 +0,0 @@ -extern int __VERIFIER_nondet_int(); -extern void __VERIFIER_error() __attribute__ ((__noreturn__)); - -#include - -struct mem { - int val; -}; - -struct list_node { - int x; - struct mem *mem; - struct list_node *next; -}; - -int main() { - struct mem *m = malloc(sizeof(*m)); - m->val = 100; - - struct list_node *head = malloc(sizeof(*head)); - head->x = 1; - head->mem = m; - head->next = head; - - struct list_node *list = head; - - while (__VERIFIER_nondet_int()) { - int x; - if (x > 0 && x < 10) { - struct list_node *n = malloc(sizeof(*n)); - n->x = x; - n->mem = m; - n->next = head; - list->next = n; - } - } - - list = head; - while (list) { - if (list->mem->val <= 100) - list->mem->val += list->x; - else - list->mem->val -= list->x; - list = list->next; - - if (!(m->val > 90 && m->val < 110)) - __VERIFIER_error(); - } -} diff --git a/regression/sas18/shared_mem1/test.desc b/regression/sas18/shared_mem1/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/sas18/shared_mem1/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/sas18/shared_mem2/main.c b/regression/sas18/shared_mem2/main.c deleted file mode 100644 index dd4f6466d..000000000 --- a/regression/sas18/shared_mem2/main.c +++ /dev/null @@ -1,45 +0,0 @@ -extern int __VERIFIER_nondet_int(); - -#include - -struct mem { - int val; -}; - -struct list_node { - int x; - struct mem *mem; - struct list_node *next; -}; - -int main() { - struct mem *m = malloc(sizeof(*m)); - m->val = 0; - - struct list_node *head = malloc(sizeof(*head)); - head->x = 1; - head->mem = m; - head->next = head; - - struct list_node *list = head; - - while (__VERIFIER_nondet_int()) { - int x; - if (x > 0 && x < 10) { - struct list_node *n = malloc(sizeof(*n)); - n->x = x; - n->mem = m; - n->next = head; - list->next = n; - } - } - - list = head; - while (m->val < 100) { - if (list->mem->val + list->x <= 100) - list->mem->val += list->x; - list = list->next; - } - if (!m->val == 100) - __VERIFIER_nondet_int(); -} diff --git a/regression/sas18/shared_mem2/test.desc b/regression/sas18/shared_mem2/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/sas18/shared_mem2/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ From 37d74d71ee04d155b66fe717bb6b424e98e7f86b Mon Sep 17 00:00:00 2001 From: Martin Hruska Date: Mon, 28 May 2018 21:56:31 +0200 Subject: [PATCH 212/322] fmcad18 to heap-data --- regression/heap-data/Makefile | 20 +++++ regression/heap-data/calendar/main.c | 40 +++++++++ regression/heap-data/calendar/test.desc | 6 ++ regression/heap-data/cart/main.c | 46 +++++++++++ regression/heap-data/cart/test.desc | 6 ++ regression/heap-data/hash_fun/main.c | 42 ++++++++++ regression/heap-data/hash_fun/test.desc | 6 ++ regression/heap-data/min_max/main.c | 40 +++++++++ regression/heap-data/min_max/test.desc | 6 ++ regression/heap-data/packet_filter/main.c | 81 +++++++++++++++++++ regression/heap-data/packet_filter/test.desc | 6 ++ regression/heap-data/process_queue/main.c | 69 ++++++++++++++++ regression/heap-data/process_queue/test.desc | 6 ++ regression/heap-data/quick_sort_split/main.c | 62 ++++++++++++++ .../heap-data/quick_sort_split/test.desc | 6 ++ regression/heap-data/running_example/main.c | 35 ++++++++ .../heap-data/running_example/test.desc | 6 ++ regression/heap-data/shared_mem1/main.c | 49 +++++++++++ regression/heap-data/shared_mem1/test.desc | 6 ++ regression/heap-data/shared_mem2/main.c | 45 +++++++++++ regression/heap-data/shared_mem2/test.desc | 6 ++ 21 files changed, 589 insertions(+) create mode 100644 regression/heap-data/Makefile create mode 100644 regression/heap-data/calendar/main.c create mode 100644 regression/heap-data/calendar/test.desc create mode 100644 regression/heap-data/cart/main.c create mode 100644 regression/heap-data/cart/test.desc create mode 100644 regression/heap-data/hash_fun/main.c create mode 100644 regression/heap-data/hash_fun/test.desc create mode 100644 regression/heap-data/min_max/main.c create mode 100644 regression/heap-data/min_max/test.desc create mode 100644 regression/heap-data/packet_filter/main.c create mode 100644 regression/heap-data/packet_filter/test.desc create mode 100644 regression/heap-data/process_queue/main.c create mode 100644 regression/heap-data/process_queue/test.desc create mode 100644 regression/heap-data/quick_sort_split/main.c create mode 100644 regression/heap-data/quick_sort_split/test.desc create mode 100644 regression/heap-data/running_example/main.c create mode 100644 regression/heap-data/running_example/test.desc create mode 100644 regression/heap-data/shared_mem1/main.c create mode 100644 regression/heap-data/shared_mem1/test.desc create mode 100644 regression/heap-data/shared_mem2/main.c create mode 100644 regression/heap-data/shared_mem2/test.desc diff --git a/regression/heap-data/Makefile b/regression/heap-data/Makefile new file mode 100644 index 000000000..34cd734b9 --- /dev/null +++ b/regression/heap-data/Makefile @@ -0,0 +1,20 @@ +default: tests.log + +FLAGS = --verbosity 10 + +test: + @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" + +tests.log: ../test.pl + @../test.pl -p -c "../../../src/2ls/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/heap-data/calendar/main.c b/regression/heap-data/calendar/main.c new file mode 100644 index 000000000..2ee9630e5 --- /dev/null +++ b/regression/heap-data/calendar/main.c @@ -0,0 +1,40 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +#define APPEND(l,i) {i->next=l; l=i;} + +typedef struct node { + struct node *next; + int event1; + int event2; +} Node; + +int main() { + Node *l = NULL; + + while (__VERIFIER_nondet_int()) { + int ev1 = __VERIFIER_nondet_int(); + int ev2 = __VERIFIER_nondet_int(); + if (ev1 < 0 || ev1 > 3 || ev2 < 0 || ev2 > 3) + continue; + + if (((ev1 == 0) && (ev2 == 2)) || ((ev1 == 1) && (ev2 == 3)) || ((ev1 == 0) && (ev2 == 3))) + continue; + + Node *p = malloc(sizeof(*p)); + p->event1 = ev1; + p->event2 = ev2; + APPEND(l,p) + } + + Node *i = l; + + while (i != NULL) { + if (((i->event1 == 1) && (i->event2 == 3)) || ((i->event1 == 0) && (i->event2 == 2))) + __VERIFIER_error(); + i = i->next; + } +} + diff --git a/regression/heap-data/calendar/test.desc b/regression/heap-data/calendar/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/heap-data/calendar/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap-data/cart/main.c b/regression/heap-data/cart/main.c new file mode 100644 index 000000000..3144e411e --- /dev/null +++ b/regression/heap-data/cart/main.c @@ -0,0 +1,46 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +#define APPEND(l,i) {i->next=l; l=i;} + +typedef struct node { + struct node *next; + int stock; + int order; +} Node; + +int main() { + Node *l = NULL; + + while (__VERIFIER_nondet_int()) { + int stock = __VERIFIER_nondet_int(); + if (stock < 0) + continue; + + Node *p = malloc(sizeof(*p)); + p->stock = stock; + p->order = 0; + APPEND(l,p) + } + + Node *i = l; + while (i != NULL) { + int order = __VERIFIER_nondet_int(); + if (order < 0 || i->stock < order) + continue; + i->order = order; + i->stock = i->stock; + i = i->next; + } + + + i = l; + while (i != NULL) { + if (i->order > i->stock) + __VERIFIER_error(); + i = i->next; + } +} + diff --git a/regression/heap-data/cart/test.desc b/regression/heap-data/cart/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/heap-data/cart/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap-data/hash_fun/main.c b/regression/heap-data/hash_fun/main.c new file mode 100644 index 000000000..08fd2104a --- /dev/null +++ b/regression/heap-data/hash_fun/main.c @@ -0,0 +1,42 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +#define INTERVAL_SIZE 100 + +struct node { + int hash; + struct node *next; +}; + +int hash_fun(); + +void append_to_list(struct node **list, int hash) { + struct node *node = malloc(sizeof(*node)); + node->next = *list; + node->hash = hash; + *list = node; +} + +int main() { + struct node *list = NULL; + + int base = __VERIFIER_nondet_int(); + + while (__VERIFIER_nondet_int()) { + if (base >= 0 && base <= 1000000) { + base = base; + int hash = hash_fun(); + + if (hash > base && hash < base + INTERVAL_SIZE) + append_to_list(&list, hash); + } + } + + while (list) { + if (!(list->hash >= base && list->hash < base + INTERVAL_SIZE)) + __VERIFIER_error(); + list = list->next; + } +} diff --git a/regression/heap-data/hash_fun/test.desc b/regression/heap-data/hash_fun/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/heap-data/hash_fun/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap-data/min_max/main.c b/regression/heap-data/min_max/main.c new file mode 100644 index 000000000..76b129535 --- /dev/null +++ b/regression/heap-data/min_max/main.c @@ -0,0 +1,40 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include +#include + +#define APPEND(l,i) {i->next=l; l=i;} + +typedef struct node { + struct node *next; + int val; +} Node; + +int main() { + Node *l = NULL; + int min = INT_MAX, max = -INT_MAX; + + while (__VERIFIER_nondet_int()) { + Node *p = malloc(sizeof(*p)); + p->val = __VERIFIER_nondet_int(); + APPEND(l, p) + + if (min > p->val) { + min = p->val; + } + if (max < p->val) { + max = p->val; + } + + } + + Node *i = l; + while (i != NULL) { + if (i->val < min) + __VERIFIER_error(); + if (i->val > max) + __VERIFIER_error(); + i = i->next; + } +} diff --git a/regression/heap-data/min_max/test.desc b/regression/heap-data/min_max/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/heap-data/min_max/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap-data/packet_filter/main.c b/regression/heap-data/packet_filter/main.c new file mode 100644 index 000000000..b2a16f4b4 --- /dev/null +++ b/regression/heap-data/packet_filter/main.c @@ -0,0 +1,81 @@ +extern unsigned __VERIFIER_nondet_uint(); +extern int __VERIFIER_nondet_int(); +extern char *__VERIFIER_nondet_charp(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +#define LOW 0 +#define HIGH 1 + +typedef struct packet { + unsigned size; + unsigned prio; + char *payload; +} Packet; + +typedef struct packet_list_node { + struct packet packet; + struct packet_list_node *next; +} *Node; + +struct packet_queue { + struct packet_list_node *front; +}; + + +Packet receive() { + Packet packet; + packet.size = __VERIFIER_nondet_uint(); + packet.prio = __VERIFIER_nondet_int() ? LOW : HIGH; + packet.payload = __VERIFIER_nondet_charp(); + return packet; +} + +extern void send(struct packet p); + +void append_to_queue(Packet p, Node *q) { + Node node = malloc(sizeof(*node)); + node->packet = p; + node->next = *q; + *q = node; +} + +void process_prio_queue(Node q) { + for (Node node = q; node != NULL; node = node->next) { + if (!(node->packet.prio == HIGH || node->packet.size < 500)) + __VERIFIER_error(); + send(node->packet); + } +} + +void process_normal_queue(Node q) { + for (Node node = q; node != NULL; node = node->next) { + if (!(node->packet.prio == LOW && node->packet.size >= 500)) + __VERIFIER_error(); + send(node->packet); + } +} + +int main() { + Node prio_queue = NULL; + Node normal_queue = NULL; + + while (__VERIFIER_nondet_int()) { + Packet new_packet = receive(); + if (new_packet.size > 0) { + if (new_packet.prio == HIGH) { + append_to_queue(new_packet, &prio_queue); + } else if (new_packet.size < 500) { + append_to_queue(new_packet, &prio_queue); + } else { + append_to_queue(new_packet, &normal_queue); + } + } + } + + process_prio_queue(prio_queue); + process_normal_queue(normal_queue); + + return 0; +} diff --git a/regression/heap-data/packet_filter/test.desc b/regression/heap-data/packet_filter/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/heap-data/packet_filter/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap-data/process_queue/main.c b/regression/heap-data/process_queue/main.c new file mode 100644 index 000000000..1299105de --- /dev/null +++ b/regression/heap-data/process_queue/main.c @@ -0,0 +1,69 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +#define MAX_PROC 1000 + +struct process_node { + int process_id; + int time_to_wait; + + struct process_node *next; +}; + +extern void run_process(int id); + +void append_to_queue(struct process_node *n, struct process_node **q) { + n->next = *q; + *q = n; +} + +struct process_node *choose_next(struct process_node **q) { + struct process_node *node = *q; + struct process_node *prev = NULL; + struct process_node *result = NULL; + while (node != NULL) { + if (node->time_to_wait == 1) { + result = node; + if (prev == NULL) + *q = node->next; + else + prev->next = node->next; + } else { + node->time_to_wait--; + } + prev = node; + node = node->next; + } + return result; +} + +void check_queue(struct process_node *q) { + for (struct process_node *n = q; n != NULL; n = n->next) + if (!n->time_to_wait >= 1) + __VERIFIER_error(); +} + + +int main() { + struct process_node *queue = NULL; + int next_time = 1; + + while (__VERIFIER_nondet_int()) { + if (next_time < MAX_PROC && __VERIFIER_nondet_int()) { + int new_id = __VERIFIER_nondet_int(); + + struct process_node *new_process = malloc(sizeof(*new_process)); + new_process->process_id = __VERIFIER_nondet_int(); + new_process->time_to_wait = next_time++; + append_to_queue(new_process, &queue); + } else if (next_time > 1){ + struct process_node *p = choose_next(&queue); + next_time--; + run_process(p->process_id); + } + + check_queue(queue); + } +} diff --git a/regression/heap-data/process_queue/test.desc b/regression/heap-data/process_queue/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/heap-data/process_queue/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap-data/quick_sort_split/main.c b/regression/heap-data/quick_sort_split/main.c new file mode 100644 index 000000000..c286aa4e8 --- /dev/null +++ b/regression/heap-data/quick_sort_split/main.c @@ -0,0 +1,62 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +#define LOW -1 +#define HIGH 1 + +struct node { + int expected_list; + int value; + struct node *next; +}; + +void append_to_list(struct node **list, int val, int exp) { + struct node *node = malloc(sizeof(*node)); + node->next = *list; + node->value = val; + node->expected_list = exp; + *list = node; +} + +struct node *create_list() { + struct node *list = NULL; + while (__VERIFIER_nondet_int()) { + int v = __VERIFIER_nondet_int(); + if (v < 0) + append_to_list(&list, v, LOW); + else + append_to_list(&list, v, HIGH); + } + return list; +} + +int main() { + struct node *list = create_list(); + + struct node *low = NULL; + struct node *high = NULL; + + // Split list into low and high + struct node *p = list; + while (p) { + struct node *l = p->value >= 0 ? high : low; + struct node *next = p->next; + p->next = l; + l = p; + p = next; + } + + // Check that low and high contain expected elements + while (low) { + if (!low->expected_list == LOW) + __VERIFIER_error(); + low = low->next; + } + while (high) { + if (!high->expected_list == HIGH) + __VERIFIER_error(); + high = high->next; + } +} diff --git a/regression/heap-data/quick_sort_split/test.desc b/regression/heap-data/quick_sort_split/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/heap-data/quick_sort_split/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap-data/running_example/main.c b/regression/heap-data/running_example/main.c new file mode 100644 index 000000000..34c4e6d1b --- /dev/null +++ b/regression/heap-data/running_example/main.c @@ -0,0 +1,35 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +typedef struct node { + int val; + struct node *next; +} Node; + +int main() { + Node *p, *list = malloc(sizeof(*list)); + Node *tail = list; + list->next = NULL; + list->val = 10; + while (__VERIFIER_nondet_int()) { + int x; + if (x < 10 || x > 20) continue; + p = malloc(sizeof(*p)); + tail->next = p; + p->next = NULL; + p->val = x; + tail = p; + } + + while (1) { + for (p = list; p!= NULL; p = p->next) { + if (!(p->val <= 20 && p->val >= 10)) + __VERIFIER_error(); + if (p->val < 20) p->val++; + else p->val /= 2; + } + } + +} diff --git a/regression/heap-data/running_example/test.desc b/regression/heap-data/running_example/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/heap-data/running_example/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap-data/shared_mem1/main.c b/regression/heap-data/shared_mem1/main.c new file mode 100644 index 000000000..d80939e92 --- /dev/null +++ b/regression/heap-data/shared_mem1/main.c @@ -0,0 +1,49 @@ +extern int __VERIFIER_nondet_int(); +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +#include + +struct mem { + int val; +}; + +struct list_node { + int x; + struct mem *mem; + struct list_node *next; +}; + +int main() { + struct mem *m = malloc(sizeof(*m)); + m->val = 100; + + struct list_node *head = malloc(sizeof(*head)); + head->x = 1; + head->mem = m; + head->next = head; + + struct list_node *list = head; + + while (__VERIFIER_nondet_int()) { + int x; + if (x > 0 && x < 10) { + struct list_node *n = malloc(sizeof(*n)); + n->x = x; + n->mem = m; + n->next = head; + list->next = n; + } + } + + list = head; + while (list) { + if (list->mem->val <= 100) + list->mem->val += list->x; + else + list->mem->val -= list->x; + list = list->next; + + if (!(m->val > 90 && m->val < 110)) + __VERIFIER_error(); + } +} diff --git a/regression/heap-data/shared_mem1/test.desc b/regression/heap-data/shared_mem1/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/heap-data/shared_mem1/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap-data/shared_mem2/main.c b/regression/heap-data/shared_mem2/main.c new file mode 100644 index 000000000..dd4f6466d --- /dev/null +++ b/regression/heap-data/shared_mem2/main.c @@ -0,0 +1,45 @@ +extern int __VERIFIER_nondet_int(); + +#include + +struct mem { + int val; +}; + +struct list_node { + int x; + struct mem *mem; + struct list_node *next; +}; + +int main() { + struct mem *m = malloc(sizeof(*m)); + m->val = 0; + + struct list_node *head = malloc(sizeof(*head)); + head->x = 1; + head->mem = m; + head->next = head; + + struct list_node *list = head; + + while (__VERIFIER_nondet_int()) { + int x; + if (x > 0 && x < 10) { + struct list_node *n = malloc(sizeof(*n)); + n->x = x; + n->mem = m; + n->next = head; + list->next = n; + } + } + + list = head; + while (m->val < 100) { + if (list->mem->val + list->x <= 100) + list->mem->val += list->x; + list = list->next; + } + if (!m->val == 100) + __VERIFIER_nondet_int(); +} diff --git a/regression/heap-data/shared_mem2/test.desc b/regression/heap-data/shared_mem2/test.desc new file mode 100644 index 000000000..20acb756e --- /dev/null +++ b/regression/heap-data/shared_mem2/test.desc @@ -0,0 +1,6 @@ +CORE +main.c +--heap-values-incremental --sympath --inline +^EXIT=0$ +^SIGNAL=0$ +^VERIFICATION SUCCESSFUL$ From 735e5c482f6a05203e1ae49f19e8211f3fcc130d Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 28 Jun 2018 14:21:14 +0200 Subject: [PATCH 213/322] Comments and refactoring of dynamic objects instances analysis. --- src/2ls/preprocessing_util.cpp | 41 ++++- src/ssa/dynobj_instance_analysis.cpp | 254 +++++++++++++++++++-------- src/ssa/dynobj_instance_analysis.h | 43 +++-- 3 files changed, 251 insertions(+), 87 deletions(-) diff --git a/src/2ls/preprocessing_util.cpp b/src/2ls/preprocessing_util.cpp index 971c27a59..b4e1fd400 100644 --- a/src/2ls/preprocessing_util.cpp +++ b/src/2ls/preprocessing_util.cpp @@ -688,6 +688,17 @@ void twols_parse_optionst::split_same_symbolic_object_assignments( } } +/*******************************************************************\ + +Function: twols_parse_optionst::remove_dead_goto + + Inputs: + + Outputs: + + Purpose: Remove dead backwards GOTO instructions (having false as guard) + +\*******************************************************************/ void twols_parse_optionst::remove_dead_goto(goto_modelt &goto_model) { Forall_goto_functions(f_it, goto_model.goto_functions) @@ -703,6 +714,19 @@ void twols_parse_optionst::remove_dead_goto(goto_modelt &goto_model) } } +/*******************************************************************\ + +Function: twols_parse_optionst::compute_dynobj_instances + + Inputs: + + Outputs: + + Purpose: For each allocation site, compute the number of objects + that must be used to soundly represent all objects allocated + at the given site. + +\*******************************************************************/ void twols_parse_optionst::compute_dynobj_instances( const goto_programt &goto_program, const dynobj_instance_analysist &analysis, @@ -714,8 +738,8 @@ void twols_parse_optionst::compute_dynobj_instances( auto &analysis_value = analysis[it]; for (auto &obj : analysis_value.live_pointers) { - auto must_alias = analysis_value.dynobj_instances.find(obj.first); - if (must_alias == analysis_value.dynobj_instances.end()) + auto must_alias = analysis_value.must_alias_relations.find(obj.first); + if (must_alias == analysis_value.must_alias_relations.end()) continue; std::set alias_classes; @@ -735,6 +759,19 @@ void twols_parse_optionst::compute_dynobj_instances( } } +/*******************************************************************\ + +Function: twols_parse_optionst::create_dynobj_instances + + Inputs: + + Outputs: + + Purpose: For each allocation site, split the allocated abstract + dynamic object into multiple in order to preserve soundness + of the analysis. + +\*******************************************************************/ void twols_parse_optionst::create_dynobj_instances( goto_programt &goto_program, const std::map &instance_counts, diff --git a/src/ssa/dynobj_instance_analysis.cpp b/src/ssa/dynobj_instance_analysis.cpp index a32d57f27..afa243e9c 100644 --- a/src/ssa/dynobj_instance_analysis.cpp +++ b/src/ssa/dynobj_instance_analysis.cpp @@ -1,53 +1,106 @@ -// -// Created by vmalik on 5/14/18. -// +/*******************************************************************\ + +Module: Analysis of a number of instances of abstract dynamic objects. + In some cases, multiple instances must be used so that the + analysis is sound. + +Author: Viktor Malik, viktor.malik@gmail.com + +\*******************************************************************/ #include #include "dynobj_instance_analysis.h" #include "ssa_dereference.h" +/*******************************************************************\ + +Function: has_deref_of + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ bool has_deref_of(const exprt &expr, const exprt &pointer) { if(expr.id()==ID_dereference && to_dereference_expr(expr).pointer()==pointer) return true; forall_operands(it, expr) - { - if(has_deref_of(*it, pointer)) - return true; - } + { + if(has_deref_of(*it, pointer)) + return true; + } return false; } +/*******************************************************************\ + +Function: remove_dereferences + + Inputs: + + Outputs: + + Purpose: Isolate all dereferences of some pointer in must-alias + paritioning. + +\*******************************************************************/ void remove_dereferences(const exprt &pointer, must_alias_setst &instances) { - for (auto &i : instances) + for(auto &i : instances) { - if (has_deref_of(i, pointer)) + if(has_deref_of(i, pointer)) instances.isolate(i); } } +/*******************************************************************\ + +Function: replace_pointer_in_deref + + Inputs: + + Outputs: + + Purpose: Replace pointer in derefence expression by another pointer. + +\*******************************************************************/ void replace_pointer_in_deref(exprt &deref, const exprt &src, const exprt &dest) { - if (deref.id() == ID_dereference && to_dereference_expr(deref).pointer() == src) - deref = dereference_exprt(dest, deref.type()); + if(deref.id()==ID_dereference && to_dereference_expr(deref).pointer()==src) + deref=dereference_exprt(dest, deref.type()); - Forall_operands(it, deref) - replace_pointer_in_deref(*it, src, dest); + Forall_operands(it, deref)replace_pointer_in_deref(*it, src, dest); } +/*******************************************************************\ + +Function: add_aliased_dereferences + + Inputs: + + Outputs: + + Purpose: Add dereferences of all aliased pointers to instances. + When dereference of a pointer is put to some must-alias + equivalence class, dereferences of aliased pointers must + be added to the same class as well. + +\*******************************************************************/ void add_aliased_dereferences(const exprt &pointer, must_alias_setst &instances) { - for (auto &i : instances) + for(auto &i : instances) { if(i.id()==ID_symbol && pointer.id()==ID_symbol && i!=pointer && instances.same_set(i, pointer)) { - for (auto &deref_i : instances) + for(auto &deref_i : instances) { - if (has_deref_of(deref_i, i)) + if(has_deref_of(deref_i, i)) { - exprt deref_copy = deref_i; + exprt deref_copy=deref_i; replace_pointer_in_deref(deref_copy, i, pointer); instances.make_union(deref_i, deref_copy); } @@ -56,81 +109,109 @@ void add_aliased_dereferences(const exprt &pointer, must_alias_setst &instances) } } +/*******************************************************************\ + +Function: dynobj_instance_domaint::rhs_concretisation + + Inputs: + + Outputs: + + Purpose: Concretise pointer expressions that occur at some RHS and + did not occur before (assume they do not alias with anything). + +\*******************************************************************/ void dynobj_instance_domaint::rhs_concretisation( const exprt &guard, ai_domain_baset::locationt loc, ai_baset &ai, const namespacet &ns) { - forall_operands(it, guard) + forall_operands(it, guard) + { + if(it->id()==ID_symbol || it->id()==ID_member) { - if(it->id() == ID_symbol || it->id() == ID_member) + bool found=false; + for(const auto &i:must_alias_relations) { - bool found=false; - for(const auto &i:dynobj_instances) - { - unsigned long n; - found |= !i.second.get_number(*it, n); - } - if (!found) - { - // 1) now make derefence - const auto &values= - static_cast(ai).value_analysis[loc]; - const auto guard_deref = dereference(guard, values, "", ns); - auto value_set = values(guard_deref, ns).value_set; - // 2) then isolate for all values in vaulue set of dereferences - for (auto &v : value_set) - { - auto &instances = dynobj_instances[v.symbol_expr()]; - instances.isolate(*it); - } - } + unsigned long n; + found|=!i.second.get_number(*it, n); } - else + if(!found) { - rhs_concretisation(*it, loc, ai, ns); + // 1) now make dereference + const auto &values= + static_cast(ai).value_analysis[loc]; + const auto guard_deref=dereference(guard, values, "", ns); + auto value_set=values(guard_deref, ns).value_set; + // 2) then isolate for all values in value set of dereferences + for(auto &v : value_set) + { + auto &instances=must_alias_relations[v.symbol_expr()]; + instances.isolate(*it); + } } } + else + { + rhs_concretisation(*it, loc, ai, ns); + } + } } +/*******************************************************************\ + +Function: dynobj_instance_domaint::transform + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ void dynobj_instance_domaint::transform( ai_domain_baset::locationt from, ai_domain_baset::locationt to, ai_baset &ai, const namespacet &ns) { - if (from->is_assign()) { - const code_assignt &assignment = to_code_assign(from->code); - const exprt lhs = symbolic_dereference(assignment.lhs(), ns); + if(from->is_assign()) + { + const code_assignt &assignment=to_code_assign(from->code); + const exprt lhs=symbolic_dereference(assignment.lhs(), ns); + // Do not include CPROVER symbols if(lhs.id()==ID_symbol && id2string(to_symbol_expr(lhs).get_identifier()).find("__CPROVER")!= std::string::npos) return; - if (assignment.rhs().get_bool("#malloc_result")) + if(assignment.rhs().get_bool("#malloc_result")) { + // For allocation site, the assigned pointer has no aliases const auto &values= static_cast(ai).value_analysis[to]; - const auto lhs_deref = dereference(assignment.lhs(), values, "", ns); - auto value_set = values(lhs_deref, ns).value_set; - for (auto &v : value_set) - dynobj_instances[v.symbol_expr()].isolate(lhs); + const auto lhs_deref=dereference(assignment.lhs(), values, "", ns); + auto value_set=values(lhs_deref, ns).value_set; + for(auto &v : value_set) + must_alias_relations[v.symbol_expr()].isolate(lhs); } else { - exprt rhs = assignment.rhs(); - if (rhs.id() == ID_typecast) - rhs = to_typecast_expr(rhs).op(); + // For other assignments, use value analysis to get all pointers pointing + // to a dynamic object and then update must-alias sets. + exprt rhs=assignment.rhs(); + if(rhs.id()==ID_typecast) + rhs=to_typecast_expr(rhs).op(); const auto &values= static_cast(ai).value_analysis[from]; - const auto rhs_deref = dereference(rhs, values, "", ns); - auto value_set = values(rhs_deref, ns).value_set; - for (auto &v : value_set) + const auto rhs_deref=dereference(rhs, values, "", ns); + auto value_set=values(rhs_deref, ns).value_set; + for(auto &v : value_set) { - auto &instances = dynobj_instances[v.symbol_expr()]; + auto &instances=must_alias_relations[v.symbol_expr()]; instances.isolate(assignment.lhs()); instances.make_union(assignment.lhs(), rhs); @@ -141,43 +222,54 @@ void dynobj_instance_domaint::transform( } } } - else if (from->is_goto() || from->is_assume() || from->is_assert()) + else if(from->is_goto() || from->is_assume() || from->is_assert()) rhs_concretisation(from->guard, from, ai, ns); - else if (from->is_dead()) + else if(from->is_dead()) { - const exprt &symbol = to_code_dead(from->code).symbol(); + const exprt &symbol=to_code_dead(from->code).symbol(); const auto &values= static_cast(ai).value_analysis[from]; - auto value_set = values(symbol, ns).value_set; - for (auto &v : value_set) + auto value_set=values(symbol, ns).value_set; + for(auto &v : value_set) { live_pointers[v.symbol_expr()].erase(symbol); } } } +/*******************************************************************\ + +Function: dynobj_instance_domaint::merge + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ bool dynobj_instance_domaint::merge( const dynobj_instance_domaint &other, ai_domain_baset::locationt from, ai_domain_baset::locationt to) { - bool result = false; - for (auto &obj : other.dynobj_instances) + bool result=false; + for(auto &obj : other.must_alias_relations) { - if (dynobj_instances.find(obj.first) == dynobj_instances.end()) + if(must_alias_relations.find(obj.first)==must_alias_relations.end()) { - dynobj_instances.insert(obj); - result = true; + must_alias_relations.insert(obj); + result=true; } else { - if (dynobj_instances.at(obj.first).join(obj.second)) - result = true; + if(must_alias_relations.at(obj.first).join(obj.second)) + result=true; } - if (other.live_pointers.find(obj.first) != other.live_pointers.end()) + if(other.live_pointers.find(obj.first)!=other.live_pointers.end()) { - auto &other_pointers = other.live_pointers.at(obj.first); + auto &other_pointers=other.live_pointers.at(obj.first); live_pointers[obj.first].insert( other_pointers.begin(), other_pointers.end()); } @@ -185,25 +277,37 @@ bool dynobj_instance_domaint::merge( return result; } +/*******************************************************************\ + +Function: dynobj_instance_domaint::output + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ void dynobj_instance_domaint::output( std::ostream &out, const ai_baset &ai, const namespacet &ns) const { - for (const auto &o : dynobj_instances) + for(const auto &o : must_alias_relations) { out << o.first.get_identifier() << ":\n"; - for (const exprt &p : o.second) + for(const exprt &p : o.second) { unsigned long n; o.second.get_number(p, n); - out << " " << o.second.find_number(n) << ": " << from_expr(ns, "", p) << "\n"; + out << " " << o.second.find_number(n) << ": " << from_expr(ns, "", p) + << "\n"; } - if (live_pointers.find(o.first) == live_pointers.end()) + if(live_pointers.find(o.first)==live_pointers.end()) continue; out << "Live: "; - for (const auto &v : live_pointers.at(o.first)) + for(const auto &v : live_pointers.at(o.first)) { out << from_expr(ns, "", v) << " "; } diff --git a/src/ssa/dynobj_instance_analysis.h b/src/ssa/dynobj_instance_analysis.h index 19b0dd39e..8df267fd7 100644 --- a/src/ssa/dynobj_instance_analysis.h +++ b/src/ssa/dynobj_instance_analysis.h @@ -1,9 +1,21 @@ -// -// Created by vmalik on 5/14/18. -// +/*******************************************************************\ -#ifndef INC_2LS_DYNOBJ_INSTANCE_ANALYSIST_H -#define INC_2LS_DYNOBJ_INSTANCE_ANALYSIST_H +Module: Analysis of a number of instances of abstract dynamic objects. + In some cases, multiple instances must be used so that the + analysis is sound. + The analysis computes for each allocation site 'a' and each + program location 'i' a set of pointer expressions that may + point to some object allocated at 'a' in the location 'i'. + Then, a must-alias relation is computed over these sets and + the maximum number of equivalence classes gives the number of + required objects for the given allocation site. + +Author: Viktor Malik, viktor.malik@gmail.com + +\*******************************************************************/ + +#ifndef CPROVER_2LS_SSA_DYNOBJ_INSTANCE_ANALYSIS_H +#define CPROVER_2LS_SSA_DYNOBJ_INSTANCE_ANALYSIS_H #include @@ -11,9 +23,18 @@ #include "ssa_object.h" #include "ssa_value_set.h" +/*******************************************************************\ + + Set partitioning by must-alias relation (it is an equivalence). + It extends the standard union find structure, particularly using + a custom join and equality. + +\*******************************************************************/ class must_alias_setst : public union_find { protected: + // Two partitionings are equal if they contain same elements partitioned + // in same sets (not necessarily having same numbers). bool equal(const must_alias_setst &other) { if (size() != other.size()) @@ -31,6 +52,7 @@ class must_alias_setst : public union_find return true; } + // Symmetric difference of elements std::set sym_diff_elements(const must_alias_setst &other) { std::set result; @@ -49,7 +71,7 @@ class must_alias_setst : public union_find { if (!equal(other)) { - // Find new elements (those that are unique to one of the sets + // Find new elements (those that are unique to one of the sets) auto new_elements = sym_diff_elements(other); // Copy *this auto original = *this; @@ -118,7 +140,10 @@ class must_alias_setst : public union_find class dynobj_instance_domaint:public ai_domain_baset { public: - std::map dynobj_instances; + // Must-alias relation for each dynamic object (corresponding to allocation + // site). + std::map must_alias_relations; + // Set of live pointers pointing to dynamic object. std::map> live_pointers; void transform( @@ -135,8 +160,6 @@ class dynobj_instance_domaint:public ai_domain_baset locationt from, locationt to); -protected: - private: void rhs_concretisation( const exprt &guard, @@ -164,4 +187,4 @@ class dynobj_instance_analysist:public ait }; -#endif //INC_2LS_DYNOBJ_INSTANCE_ANALYSIST_H +#endif // CPROVER_2LS_SSA_DYNOBJ_INSTANCE_ANALYSIS_H From 16ffaa11ab895ba45d6dac4b710b67a568baa3a9 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 28 Jun 2018 14:22:23 +0200 Subject: [PATCH 214/322] Add missing function comments. --- src/ssa/assignments.cpp | 11 +++++++++++ src/ssa/local_ssa.cpp | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index 39b7c63fb..ce00fc22b 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -314,6 +314,17 @@ void assignmentst::output( } } +/*******************************************************************\ + +Function: assignmentst::allocate + + Inputs: + + Outputs: + + Purpose: Record allocation + +\*******************************************************************/ void assignmentst::allocate( const exprt &expr, const assignmentst::locationt loc, diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 1bf59743c..eee5cea5a 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -2153,6 +2153,17 @@ void local_SSAt::collect_allocation_guards( } } +/********************************************************************\ + +Function: local_SSAt::collect_record_frees + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ void local_SSAt::collect_record_frees(local_SSAt::locationt loc) { if (loc->is_decl()) @@ -2170,6 +2181,17 @@ void local_SSAt::collect_record_frees(local_SSAt::locationt loc) } } +/********************************************************************\ + +Function: local_SSAt::get_alloc_guard_rec + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ void local_SSAt::get_alloc_guard_rec( const exprt &expr, exprt guard, From 6b67494d8e889de6fad75ac4974152b268711118 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 28 Jun 2018 14:39:16 +0200 Subject: [PATCH 215/322] Adjust coding style. --- src/2ls/2ls_parse_options.cpp | 8 +- src/2ls/preprocessing_util.cpp | 72 +++++++++--------- src/domains/heap_domain.cpp | 4 +- src/domains/heap_domain.h | 4 +- src/domains/heap_interval_domain.h | 8 +- src/domains/strategy_solver_heap.cpp | 4 +- .../strategy_solver_heap_interval_sympath.cpp | 2 +- src/domains/template_generator_base.cpp | 27 +++---- src/domains/tpolyhedra_domain.cpp | 9 ++- src/ssa/assignments.cpp | 8 +- src/ssa/assignments.h | 5 +- src/ssa/dynobj_instance_analysis.cpp | 46 ++++++------ src/ssa/dynobj_instance_analysis.h | 73 ++++++++++--------- src/ssa/local_ssa.cpp | 19 ++--- src/ssa/local_ssa.h | 2 +- src/ssa/malloc_ssa.cpp | 16 ++-- src/ssa/ssa_domain.cpp | 44 ++++++----- 17 files changed, 185 insertions(+), 166 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index a6ce6fc62..804bdf04c 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -657,7 +657,7 @@ int twols_parse_optionst::doit() if(cmdline.isset("graphml-witness")) output_graphml_proof(options, goto_model, *checker); retval=0; - finished = true; + finished=true; break; case property_checkert::FAIL: @@ -697,7 +697,7 @@ int twols_parse_optionst::doit() } report_failure(); retval=10; - finished = true; + finished=true; break; } case property_checkert::UNKNOWN: @@ -712,7 +712,7 @@ int twols_parse_optionst::doit() if(report_assertions) report_properties(options, goto_model, checker->property_map); retval=5; - finished = true; + finished=true; report_unknown(); } break; @@ -1289,7 +1289,7 @@ bool twols_parse_optionst::process_goto_program( std::map dynobj_instances; Forall_goto_functions(f_it, goto_model.goto_functions) { - if (!f_it->second.body_available()) + if(!f_it->second.body_available()) continue; namespacet ns(goto_model.symbol_table); ssa_value_ait value_analysis(f_it->second, ns, ssa_heap_analysist(ns)); diff --git a/src/2ls/preprocessing_util.cpp b/src/2ls/preprocessing_util.cpp index b4e1fd400..e635c54e9 100644 --- a/src/2ls/preprocessing_util.cpp +++ b/src/2ls/preprocessing_util.cpp @@ -705,9 +705,9 @@ void twols_parse_optionst::remove_dead_goto(goto_modelt &goto_model) { Forall_goto_program_instructions(i_it, f_it->second.body) { - if (i_it->is_backwards_goto()) + if(i_it->is_backwards_goto()) { - if (i_it->guard.is_false()) + if(i_it->guard.is_false()) i_it->make_skip(); } } @@ -735,15 +735,15 @@ void twols_parse_optionst::compute_dynobj_instances( { forall_goto_program_instructions(it, goto_program) { - auto &analysis_value = analysis[it]; - for (auto &obj : analysis_value.live_pointers) + auto &analysis_value=analysis[it]; + for(auto &obj : analysis_value.live_pointers) { - auto must_alias = analysis_value.must_alias_relations.find(obj.first); - if (must_alias == analysis_value.must_alias_relations.end()) + auto must_alias=analysis_value.must_alias_relations.find(obj.first); + if(must_alias==analysis_value.must_alias_relations.end()) continue; std::set alias_classes; - for (auto &expr : obj.second) + for(auto &expr : obj.second) { unsigned long n; must_alias->second.get_number(expr, n); @@ -779,63 +779,63 @@ void twols_parse_optionst::create_dynobj_instances( { Forall_goto_program_instructions(it, goto_program) { - if (it->is_assign()) + if(it->is_assign()) { - auto &assign = to_code_assign(it->code); - if (assign.rhs().get_bool("#malloc_result")) + auto &assign=to_code_assign(it->code); + if(assign.rhs().get_bool("#malloc_result")) { - exprt &rhs = assign.rhs(); + exprt &rhs=assign.rhs(); exprt &address=rhs.id()==ID_typecast ? to_typecast_expr(rhs).op() : rhs; - assert(address.id() == ID_address_of); - exprt &obj = to_address_of_expr(address).object(); - assert(obj.id() == ID_symbol); + assert(address.id()==ID_address_of); + exprt &obj=to_address_of_expr(address).object(); + assert(obj.id()==ID_symbol); - if (instance_counts.find(to_symbol_expr(obj)) == instance_counts.end()) + if(instance_counts.find(to_symbol_expr(obj))==instance_counts.end()) continue; - size_t count = instance_counts.at(to_symbol_expr(obj)); - if (count <= 1) + size_t count=instance_counts.at(to_symbol_expr(obj)); + if(count<=1) continue; symbolt obj_symbol= symbol_table.lookup(to_symbol_expr(obj).get_identifier()); - const std::string name = id2string(obj_symbol.name); - const std::string base_name = id2string(obj_symbol.base_name); - std::string suffix = "#" + std::to_string(0); + const std::string name=id2string(obj_symbol.name); + const std::string base_name=id2string(obj_symbol.base_name); + std::string suffix="#"+std::to_string(0); - obj_symbol.name = name + suffix; - obj_symbol.base_name = base_name + suffix; + obj_symbol.name=name+suffix; + obj_symbol.base_name=base_name+suffix; symbol_table.add(obj_symbol); - exprt new_rhs = address_of_exprt(obj_symbol.symbol_expr()); - if (rhs.id() == ID_typecast) - new_rhs = typecast_exprt(new_rhs, rhs.type()); + exprt new_rhs=address_of_exprt(obj_symbol.symbol_expr()); + if(rhs.id()==ID_typecast) + new_rhs=typecast_exprt(new_rhs, rhs.type()); new_rhs.set("#malloc_result", true); - for (size_t i = 1; i < count; ++i) + for(size_t i=1; ilocation_number)+"#"+ std::to_string(i); - nondet.base_name = nondet.name; - nondet.pretty_name = nondet.name; + nondet.base_name=nondet.name; + nondet.pretty_name=nondet.name; symbol_table.add(nondet); - suffix = "#" + std::to_string(i); - obj_symbol.name = name + suffix; - obj_symbol.base_name = base_name + suffix; + suffix="#"+std::to_string(i); + obj_symbol.name=name+suffix; + obj_symbol.base_name=base_name+suffix; - exprt new_obj = address_of_exprt(obj_symbol.symbol_expr()); - if (rhs.id() == ID_typecast) - new_obj = typecast_exprt(new_obj, rhs.type()); + exprt new_obj=address_of_exprt(obj_symbol.symbol_expr()); + if(rhs.id()==ID_typecast) + new_obj=typecast_exprt(new_obj, rhs.type()); new_rhs=if_exprt( nondet.symbol_expr(), new_obj, new_rhs); new_rhs.set("#malloc_result", true); } - rhs = new_rhs; + rhs=new_rhs; rhs.set("#malloc_result", true); } } diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index f2fc57af8..acf64fda5 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -890,10 +890,10 @@ bool heap_domaint::heap_row_valuet::add_all_paths( bool result=false; for(auto &path : other_val.paths) { - bool new_dest = (paths.find(path.destination) == paths.end()); + bool new_dest=(paths.find(path.destination)==paths.end()); if(add_path(path.destination, dyn_obj)) { - if (!new_dest) + if(!new_dest) paths.erase(dyn_obj.first); result=true; for(auto &o : path.dyn_objects) diff --git a/src/domains/heap_domain.h b/src/domains/heap_domain.h index e0c83cc01..72d0f3167 100644 --- a/src/domains/heap_domain.h +++ b/src/domains/heap_domain.h @@ -62,7 +62,7 @@ class heap_domaint:public domaint const namespacet &ns; - row_valuet(const namespacet &ns):ns(ns) {} + explicit row_valuet(const namespacet &ns):ns(ns) {} virtual exprt get_row_expr( const vart &templ_expr, @@ -86,7 +86,7 @@ class heap_domaint:public domaint // Set of objects (or NULL) the row variable can point to std::set points_to; - stack_row_valuet(const namespacet &ns):row_valuet(ns) {} + explicit stack_row_valuet(const namespacet &ns):row_valuet(ns) {} virtual exprt get_row_expr( const vart &templ_expr, diff --git a/src/domains/heap_interval_domain.h b/src/domains/heap_interval_domain.h index 485628b66..5db9bbab7 100644 --- a/src/domains/heap_interval_domain.h +++ b/src/domains/heap_interval_domain.h @@ -16,7 +16,8 @@ Author: Viktor Malik class heap_interval_domaint:public domaint { public: - enum polyhedra_kindt { + enum polyhedra_kindt + { INTERVAL, ZONES, OCTAGONS }; @@ -33,9 +34,10 @@ class heap_interval_domaint:public domaint heap_domain(_domain_number, _renaming_map, var_specs, ns), polyhedra_domain(_domain_number, _renaming_map, ns) { - if (polyhedra_kind == INTERVAL) + if(polyhedra_kind==INTERVAL) polyhedra_domain.add_interval_template(var_specs, ns); - else if (polyhedra_kind == ZONES) { + else if(polyhedra_kind==ZONES) + { polyhedra_domain.add_difference_template(var_specs, ns); polyhedra_domain.add_interval_template(var_specs, ns); } diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index 9b42527fe..8f408bcbf 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -432,14 +432,14 @@ void strategy_solver_heapt::clear_pointing_rows( std::vector to_remove; for(auto &ptr : row_value.pointed_by) { - if (ptr != row) + if(ptr!=row) { debug() << "Clearing row: " << ptr << eom; value[ptr].clear(); to_remove.push_back(ptr); } } - for (auto &r : to_remove) + for(auto &r : to_remove) row_value.pointed_by.erase(r); } diff --git a/src/domains/strategy_solver_heap_interval_sympath.cpp b/src/domains/strategy_solver_heap_interval_sympath.cpp index 4f05e0f04..6225d4ce4 100644 --- a/src/domains/strategy_solver_heap_interval_sympath.cpp +++ b/src/domains/strategy_solver_heap_interval_sympath.cpp @@ -6,7 +6,7 @@ Author: Viktor Malik \*******************************************************************/ - #define DEBUG +// #define DEBUG #include "strategy_solver_heap_interval_sympath.h" diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index 5a36d7b69..65ad50432 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -171,38 +171,39 @@ void template_generator_baset::collect_variables_loop( o_it!=SSA.ssa_objects.objects.end(); o_it++) { - const std::string id = id2string(o_it->get_identifier()); + const std::string id=id2string(o_it->get_identifier()); ssa_domaint::phi_nodest::const_iterator p_it=phi_nodes.find(id); if(p_it==phi_nodes.end()) // object not modified in this loop continue; - exprt obj_post_guard = post_guard; + exprt obj_post_guard=post_guard; // For dynamic objects allocated within the given loop, we need to add // guard of their allocation - if (id.find("ssa::dynamic_object$") != std::string::npos) + if(id.find("ssa::dynamic_object$")!=std::string::npos) { - std::string obj_id = id.substr(0, id.find_first_of(".")); - auto obj_def = SSA.ssa_analysis[n_it->location].def_map.find(obj_id); + std::string obj_id=id.substr(0, id.find_first_of(".")); + auto obj_def=SSA.ssa_analysis[n_it->location].def_map.find(obj_id); if(obj_def!=SSA.ssa_analysis[n_it->location].def_map.end() && obj_def->second.def.kind==ssa_domaint::deft::ALLOCATION) { - obj_post_guard=and_exprt(SSA.guard_symbol(obj_def->second.def.loc), - post_guard); + obj_post_guard=and_exprt( + SSA.guard_symbol(obj_def->second.def.loc), + post_guard); auto alloc_guard=SSA.allocation_guards.find(obj_id); if(alloc_guard!=SSA.allocation_guards.end()) obj_post_guard=and_exprt(obj_post_guard, alloc_guard->second); } } - if (id.find("__CPROVER_deallocated") != std::string::npos) + if(id.find("__CPROVER_deallocated")!=std::string::npos) { - auto record_frees = collect_record_frees(SSA, n_it->loophead, n_it); + auto record_frees=collect_record_frees(SSA, n_it->loophead, n_it); exprt::operandst d; - for (auto &r : record_frees) + for(auto &r : record_frees) d.push_back(equal_exprt(r, true_exprt())); - if (!d.empty()) - obj_post_guard = and_exprt(obj_post_guard, disjunction(d)); + if(!d.empty()) + obj_post_guard=and_exprt(obj_post_guard, disjunction(d)); } symbol_exprt pre_var; @@ -853,7 +854,7 @@ std::vector template_generator_baset::collect_record_frees( local_SSAt::nodest::const_iterator loop_end) { std::vector result; - for (auto &node : SSA.nodes) + for(auto &node : SSA.nodes) { if(node.location->location_number>loop_begin->location->location_number && node.location->location_numberlocation->location_number && diff --git a/src/domains/tpolyhedra_domain.cpp b/src/domains/tpolyhedra_domain.cpp index 8673ebec5..dbbecde6e 100644 --- a/src/domains/tpolyhedra_domain.cpp +++ b/src/domains/tpolyhedra_domain.cpp @@ -1052,9 +1052,10 @@ void tpolyhedra_domaint::add_difference_template( for(var_specst::const_iterator v1=var_specs.begin(); v1!=var_specs.end(); ++v1) { - if (v1->var.type().id() == ID_pointer) + if(v1->var.type().id()==ID_pointer) continue; - var_specst::const_iterator v2=v1; ++v2; + var_specst::const_iterator v2=v1; + ++v2; for(; v2!=var_specs.end(); ++v2) { kindt k=domaint::merge_kinds(v1->kind, v2->kind); @@ -1062,14 +1063,14 @@ void tpolyhedra_domaint::add_difference_template( continue; if(k==LOOP && v1->pre_guard!=v2->pre_guard) continue; // TEST: we need better heuristics - if (v2->var.type().id() == ID_pointer) + if(v2->var.type().id()==ID_pointer) continue; exprt pre_g, post_g, aux_expr; merge_and(pre_g, v1->pre_guard, v2->pre_guard, ns); merge_and(post_g, v1->post_guard, v2->post_guard, ns); merge_and(aux_expr, v1->aux_expr, v2->aux_expr, ns); - if (post_g.is_false()) + if(post_g.is_false()) continue; // x1-x2 diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index ce00fc22b..0820333ee 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -47,7 +47,7 @@ void assignmentst::build_assignment_map( assign_symbolic_rhs(code_assign.rhs(), it, ns); // At allocations site, save newly allocated object(s) - if (code_assign.rhs().get_bool("#malloc_result")) + if(code_assign.rhs().get_bool("#malloc_result")) { allocate(code_assign.rhs(), it, ns); } @@ -334,13 +334,13 @@ void assignmentst::allocate( { allocation_map[loc].insert(ssa_objectt(expr, ns)); } - else if (expr.id() == ID_if) + else if(expr.id()==ID_if) { allocate(to_if_expr(expr).true_case(), loc, ns); allocate(to_if_expr(expr).false_case(), loc, ns); } - else if (expr.id() == ID_address_of) + else if(expr.id()==ID_address_of) allocate(to_address_of_expr(expr).object(), loc, ns); - else if (expr.id() == ID_typecast) + else if(expr.id()==ID_typecast) allocate(to_typecast_expr(expr).op(), loc, ns); } diff --git a/src/ssa/assignments.h b/src/ssa/assignments.h index b0b054ce1..1e4807b33 100644 --- a/src/ssa/assignments.h +++ b/src/ssa/assignments.h @@ -47,7 +47,7 @@ class assignmentst inline const objectst &get_allocations(locationt loc) const { - auto it = allocation_map.find(loc); + auto it=allocation_map.find(loc); assert(it!=allocation_map.end()); return it->second; } @@ -91,8 +91,7 @@ class assignmentst void allocate( const exprt &expr, const locationt loc, - const namespacet &ns - ); + const namespacet &ns); }; #endif diff --git a/src/ssa/dynobj_instance_analysis.cpp b/src/ssa/dynobj_instance_analysis.cpp index afa243e9c..a76c53b80 100644 --- a/src/ssa/dynobj_instance_analysis.cpp +++ b/src/ssa/dynobj_instance_analysis.cpp @@ -128,35 +128,35 @@ void dynobj_instance_domaint::rhs_concretisation( const namespacet &ns) { forall_operands(it, guard) - { - if(it->id()==ID_symbol || it->id()==ID_member) { - bool found=false; - for(const auto &i:must_alias_relations) - { - unsigned long n; - found|=!i.second.get_number(*it, n); - } - if(!found) + if(it->id()==ID_symbol || it->id()==ID_member) { - // 1) now make dereference - const auto &values= - static_cast(ai).value_analysis[loc]; - const auto guard_deref=dereference(guard, values, "", ns); - auto value_set=values(guard_deref, ns).value_set; - // 2) then isolate for all values in value set of dereferences - for(auto &v : value_set) + bool found=false; + for(const auto &i : must_alias_relations) { - auto &instances=must_alias_relations[v.symbol_expr()]; - instances.isolate(*it); + unsigned long n; + found|=!i.second.get_number(*it, n); + } + if(!found) + { + // 1) now make dereference + const auto &values= + static_cast(ai).value_analysis[loc]; + const auto guard_deref=dereference(guard, values, "", ns); + auto value_set=values(guard_deref, ns).value_set; + // 2) then isolate for all values in value set of dereferences + for(auto &v : value_set) + { + auto &instances=must_alias_relations[v.symbol_expr()]; + instances.isolate(*it); + } } } + else + { + rhs_concretisation(*it, loc, ai, ns); + } } - else - { - rhs_concretisation(*it, loc, ai, ns); - } - } } /*******************************************************************\ diff --git a/src/ssa/dynobj_instance_analysis.h b/src/ssa/dynobj_instance_analysis.h index 8df267fd7..29d6e03e0 100644 --- a/src/ssa/dynobj_instance_analysis.h +++ b/src/ssa/dynobj_instance_analysis.h @@ -1,17 +1,18 @@ /*******************************************************************\ Module: Analysis of a number of instances of abstract dynamic objects. - In some cases, multiple instances must be used so that the - analysis is sound. - The analysis computes for each allocation site 'a' and each - program location 'i' a set of pointer expressions that may - point to some object allocated at 'a' in the location 'i'. - Then, a must-alias relation is computed over these sets and - the maximum number of equivalence classes gives the number of - required objects for the given allocation site. Author: Viktor Malik, viktor.malik@gmail.com +Description: In some cases, multiple instances must be used so that the + analysis is sound. The analysis computes for each allocation + site 'a' and each program location 'i' a set of pointer + expressions that may point to some object allocated at 'a' + in the location 'i'. Then, a must-alias relation is computed + over these sets and the maximum number of equivalence classes + gives the number of required objects for the given allocation + site. + \*******************************************************************/ #ifndef CPROVER_2LS_SSA_DYNOBJ_INSTANCE_ANALYSIS_H @@ -30,23 +31,23 @@ Author: Viktor Malik, viktor.malik@gmail.com a custom join and equality. \*******************************************************************/ -class must_alias_setst : public union_find +class must_alias_setst:public union_find { protected: // Two partitionings are equal if they contain same elements partitioned // in same sets (not necessarily having same numbers). bool equal(const must_alias_setst &other) { - if (size() != other.size()) + if(size()!=other.size()) return false; - for (auto &e1 : *this) + for(auto &e1 : *this) { unsigned long n; - if (other.get_number(e1, n)) + if(other.get_number(e1, n)) return false; - for (auto &e2 : *this) - if (same_set(e1, e2) != other.same_set(e1, e2)) + for(auto &e2 : *this) + if(same_set(e1, e2)!=other.same_set(e1, e2)) return false; } return true; @@ -57,11 +58,11 @@ class must_alias_setst : public union_find { std::set result; unsigned long n; - for (auto &e : *this) - if (get_number(e, n)) + for(auto &e : *this) + if(get_number(e, n)) result.insert(e); - for (auto &e : other) - if (get_number(e, n)) + for(auto &e : other) + if(get_number(e, n)) result.insert(e); return result; } @@ -69,50 +70,50 @@ class must_alias_setst : public union_find public: bool join(const must_alias_setst &other) { - if (!equal(other)) + if(!equal(other)) { // Find new elements (those that are unique to one of the sets) - auto new_elements = sym_diff_elements(other); + auto new_elements=sym_diff_elements(other); // Copy *this - auto original = *this; + auto original=*this; // Make intersection (into *this) which contains all common elements // (after retyping to vector) clear(); std::set common_elements; - for (auto &e1 : original) + for(auto &e1 : original) { - if (new_elements.find(e1) != new_elements.end()) + if(new_elements.find(e1)!=new_elements.end()) continue; isolate(e1); - for (auto &e2 : common_elements) - if (original.same_set(e1, e2) && other.same_set(e1, e2)) + for(auto &e2 : common_elements) + if(original.same_set(e1, e2) && other.same_set(e1, e2)) make_union(e1, e2); common_elements.insert(e1); } - for (auto &e_new : new_elements) + for(auto &e_new : new_elements) { - bool added = false; + bool added=false; // First, try to find some new element that is already in *this and that // is in the same class as e_new in one of the sets - for (auto &e : *this) + for(auto &e : *this) { if(new_elements.find(e)!=new_elements.end() && (original.same_set(e, e_new) || other.same_set(e, e_new))) { make_union(e, e_new); - added = true; + added=true; } } - if (!added) + if(!added) { // Find all sets to which e_new should be added by comparing with // common elements // The map will contain: set_number(in *this) -> set_representative std::map dest_sets; - for(auto &e: common_elements) + for(auto &e : common_elements) { if(original.same_set(e_new, e) || other.same_set(e_new, e)) { @@ -161,11 +162,11 @@ class dynobj_instance_domaint:public ai_domain_baset locationt to); private: - void rhs_concretisation( - const exprt &guard, - ai_domain_baset::locationt loc, - ai_baset &ai, - const namespacet &ns); + void rhs_concretisation( + const exprt &guard, + ai_domain_baset::locationt loc, + ai_baset &ai, + const namespacet &ns); }; class dynobj_instance_analysist:public ait diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index eee5cea5a..f063af185 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -736,7 +736,8 @@ void local_SSAt::build_assertions(locationt loc) { d.push_back( equal_exprt( - dealloc_symbol, typecast_exprt( + dealloc_symbol, + typecast_exprt( address_of_exprt(global.symbol_expr()), dealloc_symbol.type()))); } @@ -1472,7 +1473,7 @@ void local_SSAt::assign_rec( name(guard_symbol(), OBJECT_SELECT, loc)); cond=and_exprt(cond, other_cond); } - exprt orig_rhs = fresh_rhs ? name(ssa_objectt(rhs, ns), OUT, loc) : rhs; + exprt orig_rhs=fresh_rhs ? name(ssa_objectt(rhs, ns), OUT, loc) : rhs; exprt new_rhs=if_exprt(cond, orig_rhs, if_expr.true_case()); assign_rec( if_expr.true_case(), @@ -2166,17 +2167,17 @@ Function: local_SSAt::collect_record_frees \*******************************************************************/ void local_SSAt::collect_record_frees(local_SSAt::locationt loc) { - if (loc->is_decl()) + if(loc->is_decl()) { - const exprt &symbol = to_code_decl(loc->code).symbol(); - if (symbol.id() != ID_symbol) + const exprt &symbol=to_code_decl(loc->code).symbol(); + if(symbol.id()!=ID_symbol) return; - std::string id = id2string(to_symbol_expr(symbol).get_identifier()); + std::string id=id2string(to_symbol_expr(symbol).get_identifier()); if(id.find("free::")!=std::string::npos && id.find("::record")!=std::string::npos) { - (--nodes.end())->record_free = symbol; + (--nodes.end())->record_free=symbol; } } } @@ -2197,7 +2198,7 @@ void local_SSAt::get_alloc_guard_rec( exprt guard, locationt loc) { - if (expr.id() == ID_symbol && expr.type().get_bool("#dynamic")) + if(expr.id()==ID_symbol && expr.type().get_bool("#dynamic")) { allocation_guards.emplace(to_symbol_expr(expr).get_identifier(), guard); } @@ -2214,6 +2215,6 @@ void local_SSAt::get_alloc_guard_rec( } else if(expr.id()==ID_typecast) get_alloc_guard_rec(to_typecast_expr(expr).op(), guard, loc); - else if (expr.id()==ID_address_of) + else if(expr.id()==ID_address_of) get_alloc_guard_rec(to_address_of_expr(expr).object(), guard, loc); } diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 23b578cb5..436f54d6e 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -96,7 +96,7 @@ class local_SSAt std::list::iterator loophead; // link to loop head node // otherwise points to nodes.end() - exprt record_free = nil_exprt(); + exprt record_free=nil_exprt(); void output(std::ostream &, const namespacet &) const; diff --git a/src/ssa/malloc_ssa.cpp b/src/ssa/malloc_ssa.cpp index a9baa516c..035e85699 100644 --- a/src/ssa/malloc_ssa.cpp +++ b/src/ssa/malloc_ssa.cpp @@ -415,8 +415,9 @@ Function: set_var_always_to_true \*******************************************************************/ -void set_var_always_to_true(goto_modelt &goto_model, - bool (*name_cond)(std::string &)) +void set_var_always_to_true( + goto_modelt &goto_model, + bool (*name_cond)(std::string &)) { Forall_goto_functions(f_it, goto_model.goto_functions) { @@ -429,7 +430,7 @@ void set_var_always_to_true(goto_modelt &goto_model, { std::string decl_id= id2string(to_symbol_expr(code_decl.symbol()).get_identifier()); - if (name_cond(decl_id)) + if(name_cond(decl_id)) { auto assign=f_it->second.body.insert_after(i_it); assign->make_assignment(); @@ -459,7 +460,8 @@ Function: allow_record_malloc void allow_record_malloc(goto_modelt &goto_model) { set_var_always_to_true( - goto_model, [](std::string &name) + goto_model, + [](std::string &name) { return name.find("malloc::")!=std::string::npos && name.find("::record_malloc")!=std::string::npos; @@ -481,7 +483,8 @@ Function: allow_record_memleak void allow_record_memleak(goto_modelt &goto_model) { set_var_always_to_true( - goto_model, [](std::string &name) + goto_model, + [](std::string &name) { return name.find("malloc::")!=std::string::npos && name.find("::record_may_leak")!=std::string::npos; @@ -503,7 +506,8 @@ Function: allow_record_free void allow_record_free(goto_modelt &goto_model) { set_var_always_to_true( - goto_model, [](std::string &name) + goto_model, + [](std::string &name) { return name.find("free::")!=std::string::npos && name.find("::record")!=std::string::npos; diff --git a/src/ssa/ssa_domain.cpp b/src/ssa/ssa_domain.cpp index 005e8efe4..5a526aa46 100644 --- a/src/ssa/ssa_domain.cpp +++ b/src/ssa/ssa_domain.cpp @@ -13,7 +13,6 @@ Author: Daniel Kroening, kroening@kroening.com #endif #include -#include #include "ssa_domain.h" @@ -125,9 +124,9 @@ void ssa_domaint::transform( auto allocations= static_cast(ai).assignments.get_allocations(from); - for (auto &alloc : allocations) + for(auto &alloc : allocations) { - irep_idt identifier = alloc.get_identifier(); + irep_idt identifier=alloc.get_identifier(); def_entryt &def_entry=def_map[identifier]; def_entry.def.loc=from; def_entry.def.kind=deft::ALLOCATION; @@ -228,12 +227,12 @@ bool ssa_domaint::merge( continue; // Do not create PHIs for join of PHI and allocation with assignment - auto alloc_def = get_object_allocation_def(id, def_map); - if(alloc_def != def_map.end()) + auto alloc_def=get_object_allocation_def(id, def_map); + if(alloc_def!=def_map.end()) { - if(d_it_b->second.def.kind!=deft::ASSIGNMENT&& - to->location_number>alloc_def->second.def.loc->location_number&& - to->location_number>d_it_a->second.def.loc->location_number) + if(d_it_b->second.def.kind!=deft::ASSIGNMENT && + to->location_number>alloc_def->second.def.loc->location_number && + to->location_number>d_it_a->second.def.loc->location_number) { def_map[id]=d_it_a->second; def_map[id2string(id).substr(0, id2string(id).find_first_of("."))]= @@ -242,12 +241,12 @@ bool ssa_domaint::merge( continue; } } - alloc_def = get_object_allocation_def(id, b.def_map); - if(alloc_def != b.def_map.end()) + alloc_def=get_object_allocation_def(id, b.def_map); + if(alloc_def!=b.def_map.end()) { - if(d_it_a->second.def.kind!=deft::ASSIGNMENT&& + if(d_it_a->second.def.kind!=deft::ASSIGNMENT && to->location_number>alloc_def->second.def.loc->location_number && - to->location_number>d_it_b->second.def.loc->location_number) + to->location_number>d_it_b->second.def.loc->location_number) { def_map[id]=d_it_b->second; def_map[id2string(id).substr(0, id2string(id).find_first_of("."))]= @@ -280,19 +279,30 @@ bool ssa_domaint::merge( return result; } +/*******************************************************************\ + +Function: ssa_domaint::get_object_allocation_def + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ ssa_domaint::def_mapt::const_iterator ssa_domaint::get_object_allocation_def( const irep_idt &id, const ssa_domaint::def_mapt &def_map) { - auto def = def_map.find(id); - std::string id_str = id2string(id); + auto def=def_map.find(id); + std::string id_str=id2string(id); if(def!=def_map.end() && - def->second.def.kind == deft::ASSIGNMENT && + def->second.def.kind==deft::ASSIGNMENT && id_str.find("ssa::dynamic_object$")!=std::string::npos) { // Check if corresponding dynamic object has been allocated in that branch - std::string dyn_obj_id = id_str.substr(0, id_str.find_first_of(".")); - auto dyn_obj_def = def_map.find(dyn_obj_id); + std::string dyn_obj_id=id_str.substr(0, id_str.find_first_of(".")); + auto dyn_obj_def=def_map.find(dyn_obj_id); if(dyn_obj_def!=def_map.end() && dyn_obj_def->second.def.kind==deft::ALLOCATION) return dyn_obj_def; From b414e3c210f8d1d52173368281ee98148cc3ed39 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 28 Jun 2018 14:43:18 +0200 Subject: [PATCH 216/322] Heap-data tests: disable long test and move one from 'heap' directory Disabling 'packet_filter' since it takes more than 500 seconds. Moving failing version of running example from 'heap' to 'heap-data'. --- regression/heap-data/packet_filter/test.desc | 2 +- regression/{heap => heap-data}/running_example_assume/main.c | 0 regression/{heap => heap-data}/running_example_assume/test.desc | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename regression/{heap => heap-data}/running_example_assume/main.c (100%) rename regression/{heap => heap-data}/running_example_assume/test.desc (100%) diff --git a/regression/heap-data/packet_filter/test.desc b/regression/heap-data/packet_filter/test.desc index 20acb756e..35b8f2f24 100644 --- a/regression/heap-data/packet_filter/test.desc +++ b/regression/heap-data/packet_filter/test.desc @@ -1,4 +1,4 @@ -CORE +THOROUGH main.c --heap-values-incremental --sympath --inline ^EXIT=0$ diff --git a/regression/heap/running_example_assume/main.c b/regression/heap-data/running_example_assume/main.c similarity index 100% rename from regression/heap/running_example_assume/main.c rename to regression/heap-data/running_example_assume/main.c diff --git a/regression/heap/running_example_assume/test.desc b/regression/heap-data/running_example_assume/test.desc similarity index 100% rename from regression/heap/running_example_assume/test.desc rename to regression/heap-data/running_example_assume/test.desc From 14bad7b7f363de167a27eefab10af9b272b0d71c Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 28 Jun 2018 14:51:38 +0200 Subject: [PATCH 217/322] Remove debugging output --- src/2ls/2ls_parse_options.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 804bdf04c..592d4bb98 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -1295,7 +1295,6 @@ bool twols_parse_optionst::process_goto_program( ssa_value_ait value_analysis(f_it->second, ns, ssa_heap_analysist(ns)); value_analysis.output(ns, f_it->second, std::cerr); dynobj_instance_analysist do_inst(f_it->second, ns, value_analysis); - do_inst.output(ns, f_it->second, std::cerr); compute_dynobj_instances( f_it->second.body, do_inst, dynobj_instances, ns); From c75c8d471eb5ec4d772360578f6802e702af5b2b Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 29 Jun 2018 09:02:03 +0200 Subject: [PATCH 218/322] Adjust creation of multiple dynamic objects at one allocation site Now, the format is: malloc_value = cond1 ? (void *)&dyn_obj1 : (cond2 ? (void *)&dyn_obj2 ....) Also use read_rhs when collecting allocation guards to obtain correct versions of variables occuring in guards (this is needed when dealing with #co objects since their guards contain other pointers). --- src/2ls/preprocessing_util.cpp | 13 ++++++++----- src/ssa/local_ssa.cpp | 21 ++++++++------------- src/ssa/local_ssa.h | 2 +- src/ssa/malloc_ssa.cpp | 7 ++++--- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/2ls/preprocessing_util.cpp b/src/2ls/preprocessing_util.cpp index e635c54e9..744f9bf1e 100644 --- a/src/2ls/preprocessing_util.cpp +++ b/src/2ls/preprocessing_util.cpp @@ -785,7 +785,10 @@ void twols_parse_optionst::create_dynobj_instances( if(assign.rhs().get_bool("#malloc_result")) { exprt &rhs=assign.rhs(); - exprt &address=rhs.id()==ID_typecast ? to_typecast_expr(rhs).op() : rhs; + exprt &abstract_obj=rhs.id()==ID_if ? to_if_expr(rhs).false_case() + : rhs; + exprt &address=abstract_obj.id()==ID_typecast ? + to_typecast_expr(abstract_obj).op() : abstract_obj; assert(address.id()==ID_address_of); exprt &obj=to_address_of_expr(address).object(); assert(obj.id()==ID_symbol); @@ -809,7 +812,7 @@ void twols_parse_optionst::create_dynobj_instances( symbol_table.add(obj_symbol); exprt new_rhs=address_of_exprt(obj_symbol.symbol_expr()); - if(rhs.id()==ID_typecast) + if(abstract_obj.id()==ID_typecast) new_rhs=typecast_exprt(new_rhs, rhs.type()); new_rhs.set("#malloc_result", true); @@ -828,15 +831,15 @@ void twols_parse_optionst::create_dynobj_instances( obj_symbol.base_name=base_name+suffix; exprt new_obj=address_of_exprt(obj_symbol.symbol_expr()); - if(rhs.id()==ID_typecast) + if(abstract_obj.id()==ID_typecast) new_obj=typecast_exprt(new_obj, rhs.type()); new_rhs=if_exprt( nondet.symbol_expr(), new_obj, new_rhs); new_rhs.set("#malloc_result", true); } - rhs=new_rhs; - rhs.set("#malloc_result", true); + abstract_obj=new_rhs; + abstract_obj.set("#malloc_result", true); } } } diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index f063af185..6ca775df8 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -2148,9 +2148,10 @@ void local_SSAt::collect_allocation_guards( if(rhs.id()==ID_if) { get_alloc_guard_rec( - to_if_expr(rhs).true_case(), to_if_expr(rhs).cond(), loc); + to_if_expr(rhs).true_case(), read_rhs(to_if_expr(rhs).cond(), loc)); get_alloc_guard_rec( - to_if_expr(rhs).false_case(), not_exprt(to_if_expr(rhs).cond()), loc); + to_if_expr(rhs).false_case(), + read_rhs(not_exprt(to_if_expr(rhs).cond()), loc)); } } @@ -2193,10 +2194,7 @@ Function: local_SSAt::get_alloc_guard_rec Purpose: \*******************************************************************/ -void local_SSAt::get_alloc_guard_rec( - const exprt &expr, - exprt guard, - locationt loc) +void local_SSAt::get_alloc_guard_rec(const exprt &expr, exprt guard) { if(expr.id()==ID_symbol && expr.type().get_bool("#dynamic")) { @@ -2205,16 +2203,13 @@ void local_SSAt::get_alloc_guard_rec( else if(expr.id()==ID_if) { get_alloc_guard_rec( - to_if_expr(expr).true_case(), - and_exprt(guard, to_if_expr(expr).cond()), - loc); + to_if_expr(expr).true_case(), and_exprt(guard, to_if_expr(expr).cond())); get_alloc_guard_rec( to_if_expr(expr).false_case(), - and_exprt(guard, not_exprt(to_if_expr(expr).cond())), - loc); + and_exprt(guard, not_exprt(to_if_expr(expr).cond()))); } else if(expr.id()==ID_typecast) - get_alloc_guard_rec(to_typecast_expr(expr).op(), guard, loc); + get_alloc_guard_rec(to_typecast_expr(expr).op(), guard); else if(expr.id()==ID_address_of) - get_alloc_guard_rec(to_address_of_expr(expr).object(), guard, loc); + get_alloc_guard_rec(to_address_of_expr(expr).object(), guard); } diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 436f54d6e..0dbc6bdc0 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -284,7 +284,7 @@ class local_SSAt void build_unknown_objs(locationt loc); void collect_allocation_guards(const code_assignt &assign, locationt loc); - void get_alloc_guard_rec(const exprt &expr, exprt old_guard, locationt loc); + void get_alloc_guard_rec(const exprt &expr, exprt old_guard); void collect_record_frees(locationt loc); // custom templates diff --git a/src/ssa/malloc_ssa.cpp b/src/ssa/malloc_ssa.cpp index 035e85699..1f29988a3 100644 --- a/src/ssa/malloc_ssa.cpp +++ b/src/ssa/malloc_ssa.cpp @@ -236,6 +236,8 @@ exprt malloc_ssa( exprt object=create_dynamic_object( suffix, object_type, symbol_table, !alloc_concrete); + if(object.type()!=code.type()) + object=typecast_exprt(object, code.type()); exprt result; if(alloc_concrete) { @@ -260,14 +262,13 @@ exprt malloc_ssa( nondet_symbol.symbol_expr(), not_exprt(disjunction(pointer_equs))); + if(concrete_object.type()!=code.type()) + concrete_object=typecast_exprt(concrete_object, code.type()); result=if_exprt(cond, concrete_object, object); } else result=object; - if(result.type()!=code.type()) - result=typecast_exprt(result, code.type()); - result.set("#malloc_result", true); return result; From bc085cd7d738588b24cd53f6982697d7de334a5e Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 29 Jun 2018 09:07:58 +0200 Subject: [PATCH 219/322] Add one test to memsafety and disable failing tests. Multiple tests end inconclusive due to dynamic object splitting. --- regression/heap/dll1_simple/test.desc | 2 +- regression/heap/list_true/test.desc | 2 +- regression/heap/simple_true/test.desc | 2 +- .../memsafety/built_from_end_false/main.c | 38 +++++++++++++++++++ .../memsafety/built_from_end_false/test.desc | 7 ++++ regression/memsafety/simple_false/test.desc | 2 +- regression/memsafety/simple_true/test.desc | 2 +- 7 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 regression/memsafety/built_from_end_false/main.c create mode 100644 regression/memsafety/built_from_end_false/test.desc diff --git a/regression/heap/dll1_simple/test.desc b/regression/heap/dll1_simple/test.desc index ed14b476a..92784083a 100644 --- a/regression/heap/dll1_simple/test.desc +++ b/regression/heap/dll1_simple/test.desc @@ -1,4 +1,4 @@ -CORE +KNOWNBUG main.c --heap --inline --no-propagation ^EXIT=0$ diff --git a/regression/heap/list_true/test.desc b/regression/heap/list_true/test.desc index c03cf0e85..e2ef350dc 100644 --- a/regression/heap/list_true/test.desc +++ b/regression/heap/list_true/test.desc @@ -1,4 +1,4 @@ -CORE +KNOWNBUG main.c --heap-interval --sympath --inline --no-propagation ^EXIT=0$ diff --git a/regression/heap/simple_true/test.desc b/regression/heap/simple_true/test.desc index e086f8559..405084afc 100644 --- a/regression/heap/simple_true/test.desc +++ b/regression/heap/simple_true/test.desc @@ -1,4 +1,4 @@ -CORE +KNOWNBUG main.c --heap-interval --inline --no-propagation --sympath ^EXIT=0$ diff --git a/regression/memsafety/built_from_end_false/main.c b/regression/memsafety/built_from_end_false/main.c new file mode 100644 index 000000000..a56e5ab74 --- /dev/null +++ b/regression/memsafety/built_from_end_false/main.c @@ -0,0 +1,38 @@ +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +extern int __VERIFIER_nondet_int(); +/* + * Simple example: build a list with only 1s and finally a 0 (arbitrary length); + * afterwards, go through it and check if the list does have the correct form, and in particular + * finishes by a 0. + */ +#include + +void exit(int s) { + _EXIT: goto _EXIT; +} + +typedef struct node { + int h; + struct node *n; +} *List; + +int main() { + /* Build a list of the form 1->...->1->0 */ + List t; + List p = 0; + while (__VERIFIER_nondet_int()) { + t = (List) malloc(sizeof(struct node)); + if (t == 0) exit(1); + t->h = 1; + t->n = p ? p : t; + p = t; + } + while (p!=0) { + t = p->n; + free(p); + p = t; + } + +} + diff --git a/regression/memsafety/built_from_end_false/test.desc b/regression/memsafety/built_from_end_false/test.desc new file mode 100644 index 000000000..f93d3925c --- /dev/null +++ b/regression/memsafety/built_from_end_false/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--heap-interval --sympath --inline --pointer-check --no-assertions --k-induction +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +\[main.pointer_dereference.11\] dereference failure: deallocated dynamic object in \*p: FAILURE diff --git a/regression/memsafety/simple_false/test.desc b/regression/memsafety/simple_false/test.desc index 0812ec27e..fdea46680 100644 --- a/regression/memsafety/simple_false/test.desc +++ b/regression/memsafety/simple_false/test.desc @@ -1,4 +1,4 @@ -CORE +KNOWNBUG main.c --heap-interval --sympath --inline --pointer-check --k-induction ^EXIT=10$ diff --git a/regression/memsafety/simple_true/test.desc b/regression/memsafety/simple_true/test.desc index 02a269a04..3b416f2a8 100644 --- a/regression/memsafety/simple_true/test.desc +++ b/regression/memsafety/simple_true/test.desc @@ -1,4 +1,4 @@ -CORE +KNOWNBUG main.c --heap-interval --inline --sympath --pointer-check --no-assertions ^EXIT=0$ From 719684c720cb64b4ef674b8db2441fd5fc1efcad Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 29 Jun 2018 10:08:23 +0200 Subject: [PATCH 220/322] Splitting dynamic objects: do not fail on array-typed dynamic objects. --- src/2ls/preprocessing_util.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/2ls/preprocessing_util.cpp b/src/2ls/preprocessing_util.cpp index 744f9bf1e..0e5d36cb5 100644 --- a/src/2ls/preprocessing_util.cpp +++ b/src/2ls/preprocessing_util.cpp @@ -789,9 +789,11 @@ void twols_parse_optionst::create_dynobj_instances( : rhs; exprt &address=abstract_obj.id()==ID_typecast ? to_typecast_expr(abstract_obj).op() : abstract_obj; - assert(address.id()==ID_address_of); + if(address.id()!=ID_address_of) + continue; exprt &obj=to_address_of_expr(address).object(); - assert(obj.id()==ID_symbol); + if(obj.id()!=ID_symbol) + continue; if(instance_counts.find(to_symbol_expr(obj))==instance_counts.end()) continue; From 4fe510302c5314234f39f0c16c35fe67fa6a3c3c Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 29 Jun 2018 10:09:09 +0200 Subject: [PATCH 221/322] Add memsafety and heap-data to main regression Makefile --- regression/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/regression/Makefile b/regression/Makefile index 0b4d2b0bd..7b88bfe9c 100644 --- a/regression/Makefile +++ b/regression/Makefile @@ -1,5 +1,6 @@ -DIRS = heap nontermination termination kiki \ - preconditions interprocedural invariants +DIRS = nontermination termination kiki \ + preconditions interprocedural invariants \ + heap heap-data memsafety test: $(foreach var,$(DIRS), make -C $(var) test || exit 1;) From dd533c8b90bd885d61f4c4fc6ecac8c3746929aa Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 29 Jun 2018 12:15:07 +0200 Subject: [PATCH 222/322] Fix bug in creating PHI nodes for dynamic objects in some 'if' branches For more detail see 6f8efcacbc1408b79a91ccc22be99d4f55799141. This strenghtens the condition for not creating a PHI node for a dynamic object field when merging branches of a conditional in case the object was allocated in one branch only. --- src/ssa/ssa_domain.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ssa/ssa_domain.cpp b/src/ssa/ssa_domain.cpp index 5a526aa46..610f85be1 100644 --- a/src/ssa/ssa_domain.cpp +++ b/src/ssa/ssa_domain.cpp @@ -232,7 +232,8 @@ bool ssa_domaint::merge( { if(d_it_b->second.def.kind!=deft::ASSIGNMENT && to->location_number>alloc_def->second.def.loc->location_number && - to->location_number>d_it_a->second.def.loc->location_number) + to->location_number>d_it_a->second.def.loc->location_number && + to->location_number>d_it_b->second.def.loc->location_number) { def_map[id]=d_it_a->second; def_map[id2string(id).substr(0, id2string(id).find_first_of("."))]= @@ -246,7 +247,8 @@ bool ssa_domaint::merge( { if(d_it_a->second.def.kind!=deft::ASSIGNMENT && to->location_number>alloc_def->second.def.loc->location_number && - to->location_number>d_it_b->second.def.loc->location_number) + to->location_number>d_it_b->second.def.loc->location_number && + to->location_number>d_it_a->second.def.loc->location_number) { def_map[id]=d_it_b->second; def_map[id2string(id).substr(0, id2string(id).find_first_of("."))]= From 54c9a2ea1e9be60e1ed010b78762d32f0212146e Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 29 Jun 2018 12:23:35 +0200 Subject: [PATCH 223/322] Disable competition mode that kills programs with pointer arithmetic --- src/ssa/ssa_value_set.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ssa/ssa_value_set.cpp b/src/ssa/ssa_value_set.cpp index d8e6bffb0..20ba39d47 100644 --- a/src/ssa/ssa_value_set.cpp +++ b/src/ssa/ssa_value_set.cpp @@ -7,7 +7,7 @@ Author: Daniel Kroening, kroening@kroening.com \*******************************************************************/ // #define DEBUG -#define COMPETITION +// #define COMPETITION #ifdef DEBUG #include From d70047e15777e00d8d3030fb7d51c03bb1954a1c Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 20 Jul 2018 10:15:54 +0200 Subject: [PATCH 224/322] Fix bug in dynobj_instance_analysis. We cannot iterate container while changing it. --- src/ssa/dynobj_instance_analysis.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ssa/dynobj_instance_analysis.h b/src/ssa/dynobj_instance_analysis.h index 29d6e03e0..f9394d22c 100644 --- a/src/ssa/dynobj_instance_analysis.h +++ b/src/ssa/dynobj_instance_analysis.h @@ -98,7 +98,8 @@ class must_alias_setst:public union_find bool added=false; // First, try to find some new element that is already in *this and that // is in the same class as e_new in one of the sets - for(auto &e : *this) + auto this_copy(*this); + for(auto &e : this_copy) { if(new_elements.find(e)!=new_elements.end() && (original.same_set(e, e_new) || other.same_set(e, e_new))) From 40facd13cd542ebc722a93ac3e39e17455d04caa Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 20 Jul 2018 12:22:13 +0200 Subject: [PATCH 225/322] Fix bug in dynobj_instance_analysis. We cannot iterate container while changing it. --- src/ssa/dynobj_instance_analysis.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ssa/dynobj_instance_analysis.cpp b/src/ssa/dynobj_instance_analysis.cpp index a76c53b80..3094ce961 100644 --- a/src/ssa/dynobj_instance_analysis.cpp +++ b/src/ssa/dynobj_instance_analysis.cpp @@ -91,12 +91,14 @@ Function: add_aliased_dereferences \*******************************************************************/ void add_aliased_dereferences(const exprt &pointer, must_alias_setst &instances) { - for(auto &i : instances) + // We must copy instances so that we can alter them while iterating + auto inst_copy = instances; + for(auto &i : inst_copy) { if(i.id()==ID_symbol && pointer.id()==ID_symbol && i!=pointer && instances.same_set(i, pointer)) { - for(auto &deref_i : instances) + for(auto &deref_i : inst_copy) { if(has_deref_of(deref_i, i)) { From 9572ea272ffdd8c088c620c2b88b15258bd9f8e0 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 20 Jul 2018 13:03:45 +0200 Subject: [PATCH 226/322] Adjust code style for latest fix. --- src/ssa/dynobj_instance_analysis.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ssa/dynobj_instance_analysis.cpp b/src/ssa/dynobj_instance_analysis.cpp index 3094ce961..defe3554d 100644 --- a/src/ssa/dynobj_instance_analysis.cpp +++ b/src/ssa/dynobj_instance_analysis.cpp @@ -92,7 +92,7 @@ Function: add_aliased_dereferences void add_aliased_dereferences(const exprt &pointer, must_alias_setst &instances) { // We must copy instances so that we can alter them while iterating - auto inst_copy = instances; + auto inst_copy=instances; for(auto &i : inst_copy) { if(i.id()==ID_symbol && pointer.id()==ID_symbol && i!=pointer && From c9a7d893218d759d01845d794beac09fdea58dbe Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 20 Jul 2018 19:30:17 +0200 Subject: [PATCH 227/322] Remove fmcad18 directory, it has already been replaced by heap-data. The renaming commit probably forgot to delete the fmcad18 directory. --- regression/fmcad18/Makefile | 20 ----- regression/fmcad18/calendar/main.c | 40 --------- regression/fmcad18/calendar/test.desc | 6 -- regression/fmcad18/cart/main.c | 46 ----------- regression/fmcad18/cart/test.desc | 6 -- regression/fmcad18/hash_fun/main.c | 42 ---------- regression/fmcad18/hash_fun/test.desc | 6 -- regression/fmcad18/min_max/main.c | 40 --------- regression/fmcad18/min_max/test.desc | 6 -- regression/fmcad18/packet_filter/main.c | 81 ------------------- regression/fmcad18/packet_filter/test.desc | 6 -- regression/fmcad18/process_queue/main.c | 69 ---------------- regression/fmcad18/process_queue/test.desc | 6 -- regression/fmcad18/quick_sort_split/main.c | 62 -------------- regression/fmcad18/quick_sort_split/test.desc | 6 -- regression/fmcad18/running_example/main.c | 35 -------- regression/fmcad18/running_example/test.desc | 6 -- regression/fmcad18/shared_mem1/main.c | 49 ----------- regression/fmcad18/shared_mem1/test.desc | 6 -- regression/fmcad18/shared_mem2/main.c | 45 ----------- regression/fmcad18/shared_mem2/test.desc | 6 -- 21 files changed, 589 deletions(-) delete mode 100644 regression/fmcad18/Makefile delete mode 100644 regression/fmcad18/calendar/main.c delete mode 100644 regression/fmcad18/calendar/test.desc delete mode 100644 regression/fmcad18/cart/main.c delete mode 100644 regression/fmcad18/cart/test.desc delete mode 100644 regression/fmcad18/hash_fun/main.c delete mode 100644 regression/fmcad18/hash_fun/test.desc delete mode 100644 regression/fmcad18/min_max/main.c delete mode 100644 regression/fmcad18/min_max/test.desc delete mode 100644 regression/fmcad18/packet_filter/main.c delete mode 100644 regression/fmcad18/packet_filter/test.desc delete mode 100644 regression/fmcad18/process_queue/main.c delete mode 100644 regression/fmcad18/process_queue/test.desc delete mode 100644 regression/fmcad18/quick_sort_split/main.c delete mode 100644 regression/fmcad18/quick_sort_split/test.desc delete mode 100644 regression/fmcad18/running_example/main.c delete mode 100644 regression/fmcad18/running_example/test.desc delete mode 100644 regression/fmcad18/shared_mem1/main.c delete mode 100644 regression/fmcad18/shared_mem1/test.desc delete mode 100644 regression/fmcad18/shared_mem2/main.c delete mode 100644 regression/fmcad18/shared_mem2/test.desc diff --git a/regression/fmcad18/Makefile b/regression/fmcad18/Makefile deleted file mode 100644 index 34cd734b9..000000000 --- a/regression/fmcad18/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -default: tests.log - -FLAGS = --verbosity 10 - -test: - @../test.pl -p -c "../../../src/2ls/2ls $(FLAGS)" - -tests.log: ../test.pl - @../test.pl -p -c "../../../src/2ls/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/fmcad18/calendar/main.c b/regression/fmcad18/calendar/main.c deleted file mode 100644 index 2ee9630e5..000000000 --- a/regression/fmcad18/calendar/main.c +++ /dev/null @@ -1,40 +0,0 @@ -extern int __VERIFIER_nondet_int(); -extern void __VERIFIER_error() __attribute__ ((__noreturn__)); - -#include - -#define APPEND(l,i) {i->next=l; l=i;} - -typedef struct node { - struct node *next; - int event1; - int event2; -} Node; - -int main() { - Node *l = NULL; - - while (__VERIFIER_nondet_int()) { - int ev1 = __VERIFIER_nondet_int(); - int ev2 = __VERIFIER_nondet_int(); - if (ev1 < 0 || ev1 > 3 || ev2 < 0 || ev2 > 3) - continue; - - if (((ev1 == 0) && (ev2 == 2)) || ((ev1 == 1) && (ev2 == 3)) || ((ev1 == 0) && (ev2 == 3))) - continue; - - Node *p = malloc(sizeof(*p)); - p->event1 = ev1; - p->event2 = ev2; - APPEND(l,p) - } - - Node *i = l; - - while (i != NULL) { - if (((i->event1 == 1) && (i->event2 == 3)) || ((i->event1 == 0) && (i->event2 == 2))) - __VERIFIER_error(); - i = i->next; - } -} - diff --git a/regression/fmcad18/calendar/test.desc b/regression/fmcad18/calendar/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/fmcad18/calendar/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/fmcad18/cart/main.c b/regression/fmcad18/cart/main.c deleted file mode 100644 index 3144e411e..000000000 --- a/regression/fmcad18/cart/main.c +++ /dev/null @@ -1,46 +0,0 @@ -extern int __VERIFIER_nondet_int(); -extern void __VERIFIER_error() __attribute__ ((__noreturn__)); - -#include - -#define APPEND(l,i) {i->next=l; l=i;} - -typedef struct node { - struct node *next; - int stock; - int order; -} Node; - -int main() { - Node *l = NULL; - - while (__VERIFIER_nondet_int()) { - int stock = __VERIFIER_nondet_int(); - if (stock < 0) - continue; - - Node *p = malloc(sizeof(*p)); - p->stock = stock; - p->order = 0; - APPEND(l,p) - } - - Node *i = l; - while (i != NULL) { - int order = __VERIFIER_nondet_int(); - if (order < 0 || i->stock < order) - continue; - i->order = order; - i->stock = i->stock; - i = i->next; - } - - - i = l; - while (i != NULL) { - if (i->order > i->stock) - __VERIFIER_error(); - i = i->next; - } -} - diff --git a/regression/fmcad18/cart/test.desc b/regression/fmcad18/cart/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/fmcad18/cart/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/fmcad18/hash_fun/main.c b/regression/fmcad18/hash_fun/main.c deleted file mode 100644 index 08fd2104a..000000000 --- a/regression/fmcad18/hash_fun/main.c +++ /dev/null @@ -1,42 +0,0 @@ -extern int __VERIFIER_nondet_int(); -extern void __VERIFIER_error() __attribute__ ((__noreturn__)); - -#include - -#define INTERVAL_SIZE 100 - -struct node { - int hash; - struct node *next; -}; - -int hash_fun(); - -void append_to_list(struct node **list, int hash) { - struct node *node = malloc(sizeof(*node)); - node->next = *list; - node->hash = hash; - *list = node; -} - -int main() { - struct node *list = NULL; - - int base = __VERIFIER_nondet_int(); - - while (__VERIFIER_nondet_int()) { - if (base >= 0 && base <= 1000000) { - base = base; - int hash = hash_fun(); - - if (hash > base && hash < base + INTERVAL_SIZE) - append_to_list(&list, hash); - } - } - - while (list) { - if (!(list->hash >= base && list->hash < base + INTERVAL_SIZE)) - __VERIFIER_error(); - list = list->next; - } -} diff --git a/regression/fmcad18/hash_fun/test.desc b/regression/fmcad18/hash_fun/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/fmcad18/hash_fun/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/fmcad18/min_max/main.c b/regression/fmcad18/min_max/main.c deleted file mode 100644 index 76b129535..000000000 --- a/regression/fmcad18/min_max/main.c +++ /dev/null @@ -1,40 +0,0 @@ -extern int __VERIFIER_nondet_int(); -extern void __VERIFIER_error() __attribute__ ((__noreturn__)); - -#include -#include - -#define APPEND(l,i) {i->next=l; l=i;} - -typedef struct node { - struct node *next; - int val; -} Node; - -int main() { - Node *l = NULL; - int min = INT_MAX, max = -INT_MAX; - - while (__VERIFIER_nondet_int()) { - Node *p = malloc(sizeof(*p)); - p->val = __VERIFIER_nondet_int(); - APPEND(l, p) - - if (min > p->val) { - min = p->val; - } - if (max < p->val) { - max = p->val; - } - - } - - Node *i = l; - while (i != NULL) { - if (i->val < min) - __VERIFIER_error(); - if (i->val > max) - __VERIFIER_error(); - i = i->next; - } -} diff --git a/regression/fmcad18/min_max/test.desc b/regression/fmcad18/min_max/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/fmcad18/min_max/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/fmcad18/packet_filter/main.c b/regression/fmcad18/packet_filter/main.c deleted file mode 100644 index b2a16f4b4..000000000 --- a/regression/fmcad18/packet_filter/main.c +++ /dev/null @@ -1,81 +0,0 @@ -extern unsigned __VERIFIER_nondet_uint(); -extern int __VERIFIER_nondet_int(); -extern char *__VERIFIER_nondet_charp(); -extern void __VERIFIER_error() __attribute__ ((__noreturn__)); - -#include - -#define LOW 0 -#define HIGH 1 - -typedef struct packet { - unsigned size; - unsigned prio; - char *payload; -} Packet; - -typedef struct packet_list_node { - struct packet packet; - struct packet_list_node *next; -} *Node; - -struct packet_queue { - struct packet_list_node *front; -}; - - -Packet receive() { - Packet packet; - packet.size = __VERIFIER_nondet_uint(); - packet.prio = __VERIFIER_nondet_int() ? LOW : HIGH; - packet.payload = __VERIFIER_nondet_charp(); - return packet; -} - -extern void send(struct packet p); - -void append_to_queue(Packet p, Node *q) { - Node node = malloc(sizeof(*node)); - node->packet = p; - node->next = *q; - *q = node; -} - -void process_prio_queue(Node q) { - for (Node node = q; node != NULL; node = node->next) { - if (!(node->packet.prio == HIGH || node->packet.size < 500)) - __VERIFIER_error(); - send(node->packet); - } -} - -void process_normal_queue(Node q) { - for (Node node = q; node != NULL; node = node->next) { - if (!(node->packet.prio == LOW && node->packet.size >= 500)) - __VERIFIER_error(); - send(node->packet); - } -} - -int main() { - Node prio_queue = NULL; - Node normal_queue = NULL; - - while (__VERIFIER_nondet_int()) { - Packet new_packet = receive(); - if (new_packet.size > 0) { - if (new_packet.prio == HIGH) { - append_to_queue(new_packet, &prio_queue); - } else if (new_packet.size < 500) { - append_to_queue(new_packet, &prio_queue); - } else { - append_to_queue(new_packet, &normal_queue); - } - } - } - - process_prio_queue(prio_queue); - process_normal_queue(normal_queue); - - return 0; -} diff --git a/regression/fmcad18/packet_filter/test.desc b/regression/fmcad18/packet_filter/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/fmcad18/packet_filter/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/fmcad18/process_queue/main.c b/regression/fmcad18/process_queue/main.c deleted file mode 100644 index 1299105de..000000000 --- a/regression/fmcad18/process_queue/main.c +++ /dev/null @@ -1,69 +0,0 @@ -extern int __VERIFIER_nondet_int(); -extern void __VERIFIER_error() __attribute__ ((__noreturn__)); - -#include - -#define MAX_PROC 1000 - -struct process_node { - int process_id; - int time_to_wait; - - struct process_node *next; -}; - -extern void run_process(int id); - -void append_to_queue(struct process_node *n, struct process_node **q) { - n->next = *q; - *q = n; -} - -struct process_node *choose_next(struct process_node **q) { - struct process_node *node = *q; - struct process_node *prev = NULL; - struct process_node *result = NULL; - while (node != NULL) { - if (node->time_to_wait == 1) { - result = node; - if (prev == NULL) - *q = node->next; - else - prev->next = node->next; - } else { - node->time_to_wait--; - } - prev = node; - node = node->next; - } - return result; -} - -void check_queue(struct process_node *q) { - for (struct process_node *n = q; n != NULL; n = n->next) - if (!n->time_to_wait >= 1) - __VERIFIER_error(); -} - - -int main() { - struct process_node *queue = NULL; - int next_time = 1; - - while (__VERIFIER_nondet_int()) { - if (next_time < MAX_PROC && __VERIFIER_nondet_int()) { - int new_id = __VERIFIER_nondet_int(); - - struct process_node *new_process = malloc(sizeof(*new_process)); - new_process->process_id = __VERIFIER_nondet_int(); - new_process->time_to_wait = next_time++; - append_to_queue(new_process, &queue); - } else if (next_time > 1){ - struct process_node *p = choose_next(&queue); - next_time--; - run_process(p->process_id); - } - - check_queue(queue); - } -} diff --git a/regression/fmcad18/process_queue/test.desc b/regression/fmcad18/process_queue/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/fmcad18/process_queue/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/fmcad18/quick_sort_split/main.c b/regression/fmcad18/quick_sort_split/main.c deleted file mode 100644 index c286aa4e8..000000000 --- a/regression/fmcad18/quick_sort_split/main.c +++ /dev/null @@ -1,62 +0,0 @@ -extern int __VERIFIER_nondet_int(); -extern void __VERIFIER_error() __attribute__ ((__noreturn__)); - -#include - -#define LOW -1 -#define HIGH 1 - -struct node { - int expected_list; - int value; - struct node *next; -}; - -void append_to_list(struct node **list, int val, int exp) { - struct node *node = malloc(sizeof(*node)); - node->next = *list; - node->value = val; - node->expected_list = exp; - *list = node; -} - -struct node *create_list() { - struct node *list = NULL; - while (__VERIFIER_nondet_int()) { - int v = __VERIFIER_nondet_int(); - if (v < 0) - append_to_list(&list, v, LOW); - else - append_to_list(&list, v, HIGH); - } - return list; -} - -int main() { - struct node *list = create_list(); - - struct node *low = NULL; - struct node *high = NULL; - - // Split list into low and high - struct node *p = list; - while (p) { - struct node *l = p->value >= 0 ? high : low; - struct node *next = p->next; - p->next = l; - l = p; - p = next; - } - - // Check that low and high contain expected elements - while (low) { - if (!low->expected_list == LOW) - __VERIFIER_error(); - low = low->next; - } - while (high) { - if (!high->expected_list == HIGH) - __VERIFIER_error(); - high = high->next; - } -} diff --git a/regression/fmcad18/quick_sort_split/test.desc b/regression/fmcad18/quick_sort_split/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/fmcad18/quick_sort_split/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/fmcad18/running_example/main.c b/regression/fmcad18/running_example/main.c deleted file mode 100644 index 34c4e6d1b..000000000 --- a/regression/fmcad18/running_example/main.c +++ /dev/null @@ -1,35 +0,0 @@ -extern int __VERIFIER_nondet_int(); -extern void __VERIFIER_error() __attribute__ ((__noreturn__)); - -#include - -typedef struct node { - int val; - struct node *next; -} Node; - -int main() { - Node *p, *list = malloc(sizeof(*list)); - Node *tail = list; - list->next = NULL; - list->val = 10; - while (__VERIFIER_nondet_int()) { - int x; - if (x < 10 || x > 20) continue; - p = malloc(sizeof(*p)); - tail->next = p; - p->next = NULL; - p->val = x; - tail = p; - } - - while (1) { - for (p = list; p!= NULL; p = p->next) { - if (!(p->val <= 20 && p->val >= 10)) - __VERIFIER_error(); - if (p->val < 20) p->val++; - else p->val /= 2; - } - } - -} diff --git a/regression/fmcad18/running_example/test.desc b/regression/fmcad18/running_example/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/fmcad18/running_example/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/fmcad18/shared_mem1/main.c b/regression/fmcad18/shared_mem1/main.c deleted file mode 100644 index d80939e92..000000000 --- a/regression/fmcad18/shared_mem1/main.c +++ /dev/null @@ -1,49 +0,0 @@ -extern int __VERIFIER_nondet_int(); -extern void __VERIFIER_error() __attribute__ ((__noreturn__)); - -#include - -struct mem { - int val; -}; - -struct list_node { - int x; - struct mem *mem; - struct list_node *next; -}; - -int main() { - struct mem *m = malloc(sizeof(*m)); - m->val = 100; - - struct list_node *head = malloc(sizeof(*head)); - head->x = 1; - head->mem = m; - head->next = head; - - struct list_node *list = head; - - while (__VERIFIER_nondet_int()) { - int x; - if (x > 0 && x < 10) { - struct list_node *n = malloc(sizeof(*n)); - n->x = x; - n->mem = m; - n->next = head; - list->next = n; - } - } - - list = head; - while (list) { - if (list->mem->val <= 100) - list->mem->val += list->x; - else - list->mem->val -= list->x; - list = list->next; - - if (!(m->val > 90 && m->val < 110)) - __VERIFIER_error(); - } -} diff --git a/regression/fmcad18/shared_mem1/test.desc b/regression/fmcad18/shared_mem1/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/fmcad18/shared_mem1/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ diff --git a/regression/fmcad18/shared_mem2/main.c b/regression/fmcad18/shared_mem2/main.c deleted file mode 100644 index dd4f6466d..000000000 --- a/regression/fmcad18/shared_mem2/main.c +++ /dev/null @@ -1,45 +0,0 @@ -extern int __VERIFIER_nondet_int(); - -#include - -struct mem { - int val; -}; - -struct list_node { - int x; - struct mem *mem; - struct list_node *next; -}; - -int main() { - struct mem *m = malloc(sizeof(*m)); - m->val = 0; - - struct list_node *head = malloc(sizeof(*head)); - head->x = 1; - head->mem = m; - head->next = head; - - struct list_node *list = head; - - while (__VERIFIER_nondet_int()) { - int x; - if (x > 0 && x < 10) { - struct list_node *n = malloc(sizeof(*n)); - n->x = x; - n->mem = m; - n->next = head; - list->next = n; - } - } - - list = head; - while (m->val < 100) { - if (list->mem->val + list->x <= 100) - list->mem->val += list->x; - list = list->next; - } - if (!m->val == 100) - __VERIFIER_nondet_int(); -} diff --git a/regression/fmcad18/shared_mem2/test.desc b/regression/fmcad18/shared_mem2/test.desc deleted file mode 100644 index 20acb756e..000000000 --- a/regression/fmcad18/shared_mem2/test.desc +++ /dev/null @@ -1,6 +0,0 @@ -CORE -main.c ---heap-values-incremental --sympath --inline -^EXIT=0$ -^SIGNAL=0$ -^VERIFICATION SUCCESSFUL$ From c71334c4e9620cd1580791ce2d1568a38cdb22b4 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 23 Jul 2018 08:09:26 +0200 Subject: [PATCH 228/322] Remove spurious newlines from some tests in memory categories. --- regression/heap-data/running_example/main.c | 2 +- regression/heap-data/running_example_assume/main.c | 2 +- regression/heap/built_from_end/main.c | 1 - regression/memsafety/built_from_end/main.c | 1 - regression/memsafety/built_from_end_false/main.c | 1 - 5 files changed, 2 insertions(+), 5 deletions(-) diff --git a/regression/heap-data/running_example/main.c b/regression/heap-data/running_example/main.c index 34c4e6d1b..378fa8348 100644 --- a/regression/heap-data/running_example/main.c +++ b/regression/heap-data/running_example/main.c @@ -31,5 +31,5 @@ int main() { else p->val /= 2; } } - } + diff --git a/regression/heap-data/running_example_assume/main.c b/regression/heap-data/running_example_assume/main.c index 95b20d438..d64eed513 100644 --- a/regression/heap-data/running_example_assume/main.c +++ b/regression/heap-data/running_example_assume/main.c @@ -31,5 +31,5 @@ int main() { else p->val /= 2; } } - } + diff --git a/regression/heap/built_from_end/main.c b/regression/heap/built_from_end/main.c index a25f56363..47fe17aed 100644 --- a/regression/heap/built_from_end/main.c +++ b/regression/heap/built_from_end/main.c @@ -34,6 +34,5 @@ int main() { } p = p->n; } - } diff --git a/regression/memsafety/built_from_end/main.c b/regression/memsafety/built_from_end/main.c index f3e3fbf11..dcac19706 100644 --- a/regression/memsafety/built_from_end/main.c +++ b/regression/memsafety/built_from_end/main.c @@ -33,6 +33,5 @@ int main() { free(p); p = t; } - } diff --git a/regression/memsafety/built_from_end_false/main.c b/regression/memsafety/built_from_end_false/main.c index a56e5ab74..153ccea0e 100644 --- a/regression/memsafety/built_from_end_false/main.c +++ b/regression/memsafety/built_from_end_false/main.c @@ -33,6 +33,5 @@ int main() { free(p); p = t; } - } From d02289084f44739edcd568c13deb980ee3471c44 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 23 Jul 2018 08:10:30 +0200 Subject: [PATCH 229/322] Fix errors in command line options. --- src/2ls/2ls_parse_options.cpp | 2 +- src/2ls/2ls_parse_options.h | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 592d4bb98..f96700f28 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -1805,7 +1805,7 @@ void twols_parse_optionst::help() " --octagons use octagon domain\n" " --heap-interval use heap domain with interval domain for values\n" // NOLINT(*) " --heap-zones use heap domain with zones domain for values\n" // NOLINT(*) - " --heap-zones use heap domain with dynamically incrementing stregth of value domain\n" // NOLINT(*) + " --heap-incremental use heap domain with dynamically incrementing strength of value domain\n" // NOLINT(*) " --sympath compute invariant for each symbolic path (only usable with --heap-interval switch)" // NOLINT(*) " --enum-solver use solver based on model enumeration\n" " --binsearch-solver use solver based on binary search\n" diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index c2ea47896..d0dd45127 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -38,8 +38,15 @@ class optionst; "(version)" \ "(i386-linux)(i386-macos)(i386-win32)(win32)(winx64)(gcc)" \ "(ppc-macos)(unsigned-char)" \ - "(havoc)(intervals)(zones)(octagons)(equalities)"\ - "(heap)(heap-interval)(heap-zones)(heap-values-incremental)"\ + "(havoc)" \ + "(intervals)" \ + "(zones)" \ + "(octagons)" \ + "(equalities)" \ + "(heap)" \ + "(heap-interval)" \ + "(heap-zones)" \ + "(heap-values-incremental)" \ "(sympath)" \ "(enum-solver)(binsearch-solver)(arrays)"\ "(string-abstraction)(no-arch)(arch):(floatbv)(fixedbv)" \ From ed80b24a8237a0be59462c929de8648b6a7bf422 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 23 Jul 2018 08:11:23 +0200 Subject: [PATCH 230/322] Use has_prefix and CPROVER_PREFIX to check whether a symbol is CPROVER-specific. --- src/domains/strategy_solver_heap.cpp | 6 +++++- src/ssa/dynobj_instance_analysis.cpp | 9 ++++++--- src/ssa/dynobj_instance_analysis.h | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index 8f408bcbf..bd1b3b28a 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -10,6 +10,8 @@ Author: Viktor Malik #include #include +#include +#include #include "strategy_solver_heap.h" /*******************************************************************\ @@ -458,7 +460,9 @@ Function: strategy_solver_heapt::is_cprover_symbol bool strategy_solver_heapt::is_cprover_symbol(const exprt &expr) { return expr.id()==ID_symbol && - id2string(to_symbol_expr(expr).get_identifier()).find("__CPROVER_")==0; + has_prefix( + id2string(to_symbol_expr(expr).get_identifier()), + CPROVER_PREFIX); } /*******************************************************************\ diff --git a/src/ssa/dynobj_instance_analysis.cpp b/src/ssa/dynobj_instance_analysis.cpp index defe3554d..6d2b68b0e 100644 --- a/src/ssa/dynobj_instance_analysis.cpp +++ b/src/ssa/dynobj_instance_analysis.cpp @@ -1,6 +1,6 @@ /*******************************************************************\ -Module: Analysis of a number of instances of abstract dynamic objects. +Module: Analysis of the number of instances of abstract dynamic objects. In some cases, multiple instances must be used so that the analysis is sound. @@ -9,6 +9,8 @@ Author: Viktor Malik, viktor.malik@gmail.com \*******************************************************************/ #include +#include +#include #include "dynobj_instance_analysis.h" #include "ssa_dereference.h" @@ -185,8 +187,9 @@ void dynobj_instance_domaint::transform( // Do not include CPROVER symbols if(lhs.id()==ID_symbol && - id2string(to_symbol_expr(lhs).get_identifier()).find("__CPROVER")!= - std::string::npos) + has_prefix( + id2string(to_symbol_expr(lhs).get_identifier()), + CPROVER_PREFIX)) return; if(assignment.rhs().get_bool("#malloc_result")) diff --git a/src/ssa/dynobj_instance_analysis.h b/src/ssa/dynobj_instance_analysis.h index f9394d22c..14936c390 100644 --- a/src/ssa/dynobj_instance_analysis.h +++ b/src/ssa/dynobj_instance_analysis.h @@ -1,6 +1,6 @@ /*******************************************************************\ -Module: Analysis of a number of instances of abstract dynamic objects. +Module: Analysis of the number of instances of abstract dynamic objects. Author: Viktor Malik, viktor.malik@gmail.com From 556c9c782342fe2dc61af01f813ead14b4699fad Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 26 Jul 2018 10:09:47 +0200 Subject: [PATCH 231/322] Remove debugging output. --- src/2ls/2ls_parse_options.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index f96700f28..091bcc81f 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -1293,7 +1293,6 @@ bool twols_parse_optionst::process_goto_program( continue; namespacet ns(goto_model.symbol_table); ssa_value_ait value_analysis(f_it->second, ns, ssa_heap_analysist(ns)); - value_analysis.output(ns, f_it->second, std::cerr); dynobj_instance_analysist do_inst(f_it->second, ns, value_analysis); compute_dynobj_instances( From 9104bda3b3261e76142b571cdcca7560b56a06b4 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 3 Aug 2018 09:28:18 +0200 Subject: [PATCH 232/322] Rename heap-interval to heap-tpolyhedra including names of all related classes. --- src/2ls/summary_checker_kind.cpp | 2 +- src/domains/Makefile | 6 +- ..._domain.cpp => heap_tpolyhedra_domain.cpp} | 56 ++++++------ ...rval_domain.h => heap_tpolyhedra_domain.h} | 16 ++-- ...cpp => heap_tpolyhedra_sympath_domain.cpp} | 30 +++---- ...ain.h => heap_tpolyhedra_sympath_domain.h} | 28 +++--- src/domains/ssa_analyzer.cpp | 17 ++-- src/domains/strategy_solver_heap_interval.cpp | 83 ------------------ .../strategy_solver_heap_tpolyhedra.cpp | 86 +++++++++++++++++++ ...al.h => strategy_solver_heap_tpolyhedra.h} | 27 +++--- ...rategy_solver_heap_tpolyhedra_sympath.cpp} | 62 ++++++------- ...strategy_solver_heap_tpolyhedra_sympath.h} | 28 +++--- src/domains/template_generator_base.cpp | 12 +-- 13 files changed, 230 insertions(+), 223 deletions(-) rename src/domains/{heap_interval_domain.cpp => heap_tpolyhedra_domain.cpp} (65%) rename src/domains/{heap_interval_domain.h => heap_tpolyhedra_domain.h} (80%) rename src/domains/{heap_interval_sympath_domain.cpp => heap_tpolyhedra_sympath_domain.cpp} (60%) rename src/domains/{heap_interval_sympath_domain.h => heap_tpolyhedra_sympath_domain.h} (65%) delete mode 100644 src/domains/strategy_solver_heap_interval.cpp create mode 100644 src/domains/strategy_solver_heap_tpolyhedra.cpp rename src/domains/{strategy_solver_heap_interval.h => strategy_solver_heap_tpolyhedra.h} (53%) rename src/domains/{strategy_solver_heap_interval_sympath.cpp => strategy_solver_heap_tpolyhedra_sympath.cpp} (69%) rename src/domains/{strategy_solver_heap_interval_sympath.h => strategy_solver_heap_tpolyhedra_sympath.h} (59%) diff --git a/src/2ls/summary_checker_kind.cpp b/src/2ls/summary_checker_kind.cpp index 0fe1c9110..47092b8a7 100644 --- a/src/2ls/summary_checker_kind.cpp +++ b/src/2ls/summary_checker_kind.cpp @@ -6,7 +6,7 @@ Author: Peter Schrammel \*******************************************************************/ -#include +#include #include "summary_checker_kind.h" /*******************************************************************\ diff --git a/src/domains/Makefile b/src/domains/Makefile index 28f310666..e293aee2f 100644 --- a/src/domains/Makefile +++ b/src/domains/Makefile @@ -1,6 +1,7 @@ SRC = tpolyhedra_domain.cpp equality_domain.cpp domain.cpp \ predabs_domain.cpp heap_domain.cpp list_iterator.cpp \ - heap_interval_domain.cpp heap_interval_sympath_domain.cpp symbolic_path.cpp\ + heap_tpolyhedra_domain.cpp heap_tpolyhedra_sympath_domain.cpp \ + symbolic_path.cpp\ ssa_analyzer.cpp util.cpp incremental_solver.cpp \ strategy_solver_base.cpp strategy_solver_equality.cpp \ linrank_domain.cpp lexlinrank_domain.cpp\ @@ -10,7 +11,8 @@ SRC = tpolyhedra_domain.cpp equality_domain.cpp domain.cpp \ template_generator_callingcontext.cpp template_generator_ranking.cpp \ strategy_solver_binsearch2.cpp strategy_solver_binsearch3.cpp \ strategy_solver_predabs.cpp strategy_solver_heap.cpp \ - strategy_solver_heap_interval.cpp strategy_solver_heap_interval_sympath.cpp \ + strategy_solver_heap_tpolyhedra.cpp \ + strategy_solver_heap_tpolyhedra_sympath.cpp \ #solver_enumeration.cpp include ../config.inc diff --git a/src/domains/heap_interval_domain.cpp b/src/domains/heap_tpolyhedra_domain.cpp similarity index 65% rename from src/domains/heap_interval_domain.cpp rename to src/domains/heap_tpolyhedra_domain.cpp index 27edf9e06..c5bd4a636 100644 --- a/src/domains/heap_interval_domain.cpp +++ b/src/domains/heap_tpolyhedra_domain.cpp @@ -1,16 +1,16 @@ /*******************************************************************\ -Module: Combination of heap and interval abstract domains +Module: Combination of heap and template polyhedra abstract domains Author: Viktor Malik \*******************************************************************/ -#include "heap_interval_domain.h" +#include "heap_tpolyhedra_domain.h" /*******************************************************************\ -Function: heap_interval_domaint::initialize +Function: heap_tpolyhedra_domaint::initialize Inputs: @@ -20,17 +20,17 @@ Function: heap_interval_domaint::initialize \*******************************************************************/ -void heap_interval_domaint::initialize(domaint::valuet &value) +void heap_tpolyhedra_domaint::initialize(domaint::valuet &value) { - heap_interval_valuet &v=static_cast(value); + heap_tpolyhedra_valuet &v=static_cast(value); heap_domain.initialize(v.heap_value); - polyhedra_domain.initialize(v.interval_value); + polyhedra_domain.initialize(v.tpolyhedra_value); } /*******************************************************************\ -Function: heap_interval_domaint::output_value +Function: heap_tpolyhedra_domaint::output_value Inputs: @@ -40,21 +40,21 @@ Function: heap_interval_domaint::output_value \*******************************************************************/ -void heap_interval_domaint::output_value( +void heap_tpolyhedra_domaint::output_value( std::ostream &out, const domaint::valuet &value, const namespacet &ns) const { - const heap_interval_valuet &v= - static_cast(value); + const heap_tpolyhedra_valuet &v= + static_cast(value); heap_domain.output_value(out, v.heap_value, ns); - polyhedra_domain.output_value(out, v.interval_value, ns); + polyhedra_domain.output_value(out, v.tpolyhedra_value, ns); } /*******************************************************************\ -Function: heap_interval_domaint::output_domain +Function: heap_tpolyhedra_domaint::output_domain Inputs: @@ -64,7 +64,7 @@ Function: heap_interval_domaint::output_domain \*******************************************************************/ -void heap_interval_domaint::output_domain( +void heap_tpolyhedra_domaint::output_domain( std::ostream &out, const namespacet &ns) const { @@ -74,7 +74,7 @@ void heap_interval_domaint::output_domain( /*******************************************************************\ -Function: heap_interval_domaint::project_on_vars +Function: heap_tpolyhedra_domaint::project_on_vars Inputs: @@ -84,26 +84,26 @@ Function: heap_interval_domaint::project_on_vars \*******************************************************************/ -void heap_interval_domaint::project_on_vars( +void heap_tpolyhedra_domaint::project_on_vars( domaint::valuet &value, const domaint::var_sett &vars, exprt &result) { - heap_interval_valuet &v=static_cast(value); + heap_tpolyhedra_valuet &v=static_cast(value); exprt heap_result; heap_domain.project_on_vars(v.heap_value, vars, heap_result); - exprt interval_result; - polyhedra_domain.project_on_vars(v.interval_value, vars, interval_result); + exprt tpolyhedra_result; + polyhedra_domain.project_on_vars(v.tpolyhedra_value, vars, tpolyhedra_result); result=heap_result; - if(interval_result!=true_exprt()) - result=and_exprt(result, interval_result); + if(tpolyhedra_result!=true_exprt()) + result=and_exprt(result, tpolyhedra_result); } /*******************************************************************\ -Function: heap_interval_domaint::restrict_to_sympath +Function: heap_tpolyhedra_domaint::restrict_to_sympath Inputs: Symbolic path @@ -112,7 +112,7 @@ Function: heap_interval_domaint::restrict_to_sympath Purpose: Restrict template to a given symbolic path. \*******************************************************************/ -void heap_interval_domaint::restrict_to_sympath( +void heap_tpolyhedra_domaint::restrict_to_sympath( const symbolic_patht &sympath) { heap_domain.restrict_to_sympath(sympath); @@ -121,7 +121,7 @@ void heap_interval_domaint::restrict_to_sympath( /*******************************************************************\ -Function: heap_interval_domaint::clear_aux_symbols +Function: heap_tpolyhedra_domaint::clear_aux_symbols Inputs: @@ -130,7 +130,7 @@ Function: heap_interval_domaint::clear_aux_symbols Purpose: Reset aux symbols to true (remove all restricitions). \*******************************************************************/ -void heap_interval_domaint::clear_aux_symbols() +void heap_tpolyhedra_domaint::clear_aux_symbols() { heap_domain.clear_aux_symbols(); polyhedra_domain.clear_aux_symbols(); @@ -138,7 +138,7 @@ void heap_interval_domaint::clear_aux_symbols() /*******************************************************************\ -Function: heap_interval_domaint::eliminate_sympaths +Function: heap_tpolyhedra_domaint::eliminate_sympaths Inputs: Vector of symbolic paths @@ -147,7 +147,7 @@ Function: heap_interval_domaint::eliminate_sympaths Purpose: Restrict template to other paths than those specified. \*******************************************************************/ -void heap_interval_domaint::eliminate_sympaths( +void heap_tpolyhedra_domaint::eliminate_sympaths( const std::vector &sympaths) { heap_domain.eliminate_sympaths(sympaths); @@ -156,7 +156,7 @@ void heap_interval_domaint::eliminate_sympaths( /*******************************************************************\ -Function: heap_interval_domaint::undo_restriction +Function: heap_tpolyhedra_domaint::undo_restriction Inputs: @@ -165,7 +165,7 @@ Function: heap_interval_domaint::undo_restriction Purpose: Undo last restriction. \*******************************************************************/ -void heap_interval_domaint::undo_restriction() +void heap_tpolyhedra_domaint::undo_restriction() { heap_domain.undo_restriction(); polyhedra_domain.undo_restriction(); diff --git a/src/domains/heap_interval_domain.h b/src/domains/heap_tpolyhedra_domain.h similarity index 80% rename from src/domains/heap_interval_domain.h rename to src/domains/heap_tpolyhedra_domain.h index 5db9bbab7..5c2cb9d68 100644 --- a/src/domains/heap_interval_domain.h +++ b/src/domains/heap_tpolyhedra_domain.h @@ -1,19 +1,19 @@ /*******************************************************************\ -Module: Combination of heap and interval abstract domains +Module: Combination of heap and template polyhedra abstract domains Author: Viktor Malik \*******************************************************************/ -#ifndef CPROVER_2LS_DOMAINS_HEAP_INTERVAL_DOMAIN_H -#define CPROVER_2LS_DOMAINS_HEAP_INTERVAL_DOMAIN_H +#ifndef CPROVER_2LS_DOMAINS_HEAP_TPOLYHEDRA_DOMAIN_H +#define CPROVER_2LS_DOMAINS_HEAP_TPOLYHEDRA_DOMAIN_H #include "domain.h" #include "tpolyhedra_domain.h" #include "heap_domain.h" -class heap_interval_domaint:public domaint +class heap_tpolyhedra_domaint:public domaint { public: enum polyhedra_kindt @@ -24,7 +24,7 @@ class heap_interval_domaint:public domaint heap_domaint heap_domain; tpolyhedra_domaint polyhedra_domain; - heap_interval_domaint( + heap_tpolyhedra_domaint( unsigned int _domain_number, replace_mapt &_renaming_map, const var_specst &var_specs, @@ -43,11 +43,11 @@ class heap_interval_domaint:public domaint } } - class heap_interval_valuet:public valuet + class heap_tpolyhedra_valuet:public valuet { public: heap_domaint::heap_valuet heap_value; - tpolyhedra_domaint::templ_valuet interval_value; + tpolyhedra_domaint::templ_valuet tpolyhedra_value; }; virtual void initialize(valuet &value) override; @@ -73,4 +73,4 @@ class heap_interval_domaint:public domaint void clear_aux_symbols(); }; -#endif // CPROVER_2LS_DOMAINS_HEAP_INTERVAL_DOMAIN_H +#endif // CPROVER_2LS_DOMAINS_HEAP_TPOLYHEDRA_DOMAIN_H diff --git a/src/domains/heap_interval_sympath_domain.cpp b/src/domains/heap_tpolyhedra_sympath_domain.cpp similarity index 60% rename from src/domains/heap_interval_sympath_domain.cpp rename to src/domains/heap_tpolyhedra_sympath_domain.cpp index 8fc09f9c4..c13d3bb9c 100644 --- a/src/domains/heap_interval_sympath_domain.cpp +++ b/src/domains/heap_tpolyhedra_sympath_domain.cpp @@ -1,17 +1,17 @@ /*******************************************************************\ -Module: Abstract domain for computing invariants in heap-interval +Module: Abstract domain for computing invariants in heap-tpolyhedra domain for different symbolic paths in program. Author: Viktor Malik \*******************************************************************/ -#include "heap_interval_sympath_domain.h" +#include "heap_tpolyhedra_sympath_domain.h" /*******************************************************************\ -Function: heap_interval_sympath_domaint::output_value +Function: heap_tpolyhedra_sympath_domaint::output_value Inputs: @@ -20,23 +20,23 @@ Function: heap_interval_sympath_domaint::output_value Purpose: \*******************************************************************/ -void heap_interval_sympath_domaint::output_value( +void heap_tpolyhedra_sympath_domaint::output_value( std::ostream &out, const domaint::valuet &value, const namespacet &ns) const { - const heap_interval_sympath_valuet &v= - static_cast(value); + const heap_tpolyhedra_sympath_valuet &v= + static_cast(value); for(auto &config : v) { out << from_expr(ns, "", config.first) << "==>\n"; - heap_interval_domain.output_value(out, config.second, ns); + heap_tpolyhedra_domain.output_value(out, config.second, ns); } } /*******************************************************************\ -Function: heap_interval_sympath_domaint::output_domain +Function: heap_tpolyhedra_sympath_domaint::output_domain Inputs: @@ -45,16 +45,16 @@ Function: heap_interval_sympath_domaint::output_domain Purpose: \*******************************************************************/ -void heap_interval_sympath_domaint::output_domain( +void heap_tpolyhedra_sympath_domaint::output_domain( std::ostream &out, const namespacet &ns) const { - heap_interval_domain.output_domain(out, ns); + heap_tpolyhedra_domain.output_domain(out, ns); } /*******************************************************************\ -Function: heap_interval_sympath_domaint::project_on_vars +Function: heap_tpolyhedra_sympath_domaint::project_on_vars Inputs: @@ -63,18 +63,18 @@ Function: heap_interval_sympath_domaint::project_on_vars Purpose: \*******************************************************************/ -void heap_interval_sympath_domaint::project_on_vars( +void heap_tpolyhedra_sympath_domaint::project_on_vars( domaint::valuet &value, const domaint::var_sett &vars, exprt &result) { - heap_interval_sympath_valuet &v= - static_cast(value); + heap_tpolyhedra_sympath_valuet &v= + static_cast(value); exprt::operandst c; for(auto &config : v) { exprt config_result; - heap_interval_domain.project_on_vars(config.second, vars, config_result); + heap_tpolyhedra_domain.project_on_vars(config.second, vars, config_result); c.push_back(and_exprt(config.first, config_result)); } c.push_back(no_loops_path); diff --git a/src/domains/heap_interval_sympath_domain.h b/src/domains/heap_tpolyhedra_sympath_domain.h similarity index 65% rename from src/domains/heap_interval_sympath_domain.h rename to src/domains/heap_tpolyhedra_sympath_domain.h index e6ba7ec1a..3e2ddadb1 100644 --- a/src/domains/heap_interval_sympath_domain.h +++ b/src/domains/heap_tpolyhedra_sympath_domain.h @@ -1,32 +1,32 @@ /*******************************************************************\ -Module: Abstract domain for computing invariants in heap-interval +Module: Abstract domain for computing invariants in heap-tpolyhedra domain for different symbolic paths in program. Author: Viktor Malik \*******************************************************************/ -#ifndef CPROVER_2LS_DOMAINS_HEAP_INTERVAL_SYMPATH_DOMAIN_H -#define CPROVER_2LS_DOMAINS_HEAP_INTERVAL_SYMPATH_DOMAIN_H +#ifndef CPROVER_2LS_DOMAINS_HEAP_TPOLYHEDRA_SYMPATH_DOMAIN_H +#define CPROVER_2LS_DOMAINS_HEAP_TPOLYHEDRA_SYMPATH_DOMAIN_H #include "domain.h" -#include "heap_interval_domain.h" +#include "heap_tpolyhedra_domain.h" -class heap_interval_sympath_domaint:public domaint +class heap_tpolyhedra_sympath_domaint:public domaint { public: - heap_interval_domaint heap_interval_domain; + heap_tpolyhedra_domaint heap_tpolyhedra_domain; - heap_interval_sympath_domaint( + heap_tpolyhedra_sympath_domaint( unsigned int _domain_number, replace_mapt &_renaming_map, const var_specst &var_specs, const local_SSAt &SSA, - const heap_interval_domaint::polyhedra_kindt polyhedra_kind): + const heap_tpolyhedra_domaint::polyhedra_kindt polyhedra_kind): domaint(_domain_number, _renaming_map, SSA.ns), - heap_interval_domain( + heap_tpolyhedra_domain( _domain_number, _renaming_map, var_specs, SSA.ns, polyhedra_kind) { exprt::operandst false_loop_guards; @@ -36,10 +36,10 @@ class heap_interval_sympath_domaint:public domaint } // Value is a map from expression (symbolic path) to an invariant in heap - // interval domain - class heap_interval_sympath_valuet: + // tpolyhedra domain + class heap_tpolyhedra_sympath_valuet: public valuet, - public std::map + public std::map { }; @@ -63,8 +63,8 @@ class heap_interval_sympath_domaint:public domaint // path even though it can be feasible exprt no_loops_path; - friend class strategy_solver_heap_interval_sympatht; + friend class strategy_solver_heap_tpolyhedra_sympatht; }; -#endif // CPROVER_2LS_DOMAINS_HEAP_INTERVAL_SYMPATH_DOMAIN_H +#endif // CPROVER_2LS_DOMAINS_HEAP_TPOLYHEDRA_SYMPATH_DOMAIN_H diff --git a/src/domains/ssa_analyzer.cpp b/src/domains/ssa_analyzer.cpp index 352fe8a6d..72ad03b52 100644 --- a/src/domains/ssa_analyzer.cpp +++ b/src/domains/ssa_analyzer.cpp @@ -32,8 +32,8 @@ Author: Peter Schrammel #include "strategy_solver_predabs.h" #include "ssa_analyzer.h" #include "strategy_solver_heap.h" -#include "strategy_solver_heap_interval.h" -#include "strategy_solver_heap_interval_sympath.h" +#include "strategy_solver_heap_tpolyhedra.h" +#include "strategy_solver_heap_tpolyhedra_sympath.h" // NOLINTNEXTLINE(*) #define BINSEARCH_SOLVER strategy_solver_binsearcht(\ @@ -125,25 +125,26 @@ void ssa_analyzert::operator()( { if(template_generator.options.get_bool_option("sympath")) { - strategy_solver=new strategy_solver_heap_interval_sympatht( - *static_cast(domain), + strategy_solver=new strategy_solver_heap_tpolyhedra_sympatht( + *static_cast(domain), solver, SSA, precondition, get_message_handler(), template_generator); - result=new heap_interval_sympath_domaint::heap_interval_sympath_valuet(); + result= + new heap_tpolyhedra_sympath_domaint::heap_tpolyhedra_sympath_valuet(); } else { - strategy_solver=new strategy_solver_heap_intervalt( - *static_cast(domain), + strategy_solver=new strategy_solver_heap_tpolyhedrat( + *static_cast(domain), solver, SSA, precondition, get_message_handler(), template_generator); - result=new heap_interval_domaint::heap_interval_valuet(); + result=new heap_tpolyhedra_domaint::heap_tpolyhedra_valuet(); } } else diff --git a/src/domains/strategy_solver_heap_interval.cpp b/src/domains/strategy_solver_heap_interval.cpp deleted file mode 100644 index cf3112e93..000000000 --- a/src/domains/strategy_solver_heap_interval.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/*******************************************************************\ - -Module: Strategy solver for combination of shape and interval domains. - -Author: Viktor Malik - -\*******************************************************************/ - -#include "strategy_solver_heap_interval.h" - -/*******************************************************************\ - -Function: strategy_solver_heap_intervalt::iterate - - Inputs: - - Outputs: - - Purpose: Run iteration of each solver separately, but every time - in the context of the current invariant found by the other - solver. The interval solving is also restricted to - a symbolic path found by the heap solver. - -\*******************************************************************/ - -bool strategy_solver_heap_intervalt::iterate( - strategy_solver_baset::invariantt &_inv) -{ - heap_interval_domaint::heap_interval_valuet &inv= - static_cast(_inv); - - // Run one iteration of heap solver in the context of invariant from - // the interval solver - solver.new_context(); - solver << heap_interval_domain.polyhedra_domain.to_pre_constraints( - inv.interval_value); - bool heap_improved=heap_solver.iterate(inv.heap_value); - solver.pop_context(); - - if(heap_improved) - { - // If heap part was improved, restrict interval part to found symbolic path - symbolic_path=heap_solver.symbolic_path; - heap_interval_domain.polyhedra_domain.restrict_to_sympath(symbolic_path); - } - - // Run one interation of interval solver in the context of invariant from - // the heap solver - solver.new_context(); - solver << heap_interval_domain.heap_domain.to_pre_constraints(inv.heap_value); - bool interval_improved=interval_solver.iterate(inv.interval_value); - solver.pop_context(); - - if(heap_improved) - heap_interval_domain.polyhedra_domain.undo_restriction(); - - return heap_improved || interval_improved; -} - -/*******************************************************************\ - -Function: strategy_solver_heap_intervalt::set_message_handler - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -void strategy_solver_heap_intervalt::set_message_handler( - message_handlert &_message_handler) -{ - heap_solver.set_message_handler(_message_handler); - interval_solver.set_message_handler(_message_handler); -} - -void strategy_solver_heap_intervalt::clear_symbolic_path() -{ - heap_solver.symbolic_path.clear(); - interval_solver.symbolic_path.clear(); -} diff --git a/src/domains/strategy_solver_heap_tpolyhedra.cpp b/src/domains/strategy_solver_heap_tpolyhedra.cpp new file mode 100644 index 000000000..53625a76c --- /dev/null +++ b/src/domains/strategy_solver_heap_tpolyhedra.cpp @@ -0,0 +1,86 @@ +/*******************************************************************\ + +Module: Strategy solver for combination of shape and template + polyhedra domains. + +Author: Viktor Malik + +\*******************************************************************/ + +#include "strategy_solver_heap_tpolyhedra.h" + +/*******************************************************************\ + +Function: strategy_solver_heap_tpolyhedrat::iterate + + Inputs: + + Outputs: + + Purpose: Run iteration of each solver separately, but every time + in the context of the current invariant found by the other + solver. The template polyhedra solving is also restricted to + a symbolic path found by the heap solver. + +\*******************************************************************/ + +bool strategy_solver_heap_tpolyhedrat::iterate( + strategy_solver_baset::invariantt &_inv) +{ + heap_tpolyhedra_domaint::heap_tpolyhedra_valuet &inv= + static_cast(_inv); + + // Run one iteration of heap solver in the context of invariant from + // the template polyhedra solver + solver.new_context(); + solver << heap_tpolyhedra_domain.polyhedra_domain.to_pre_constraints( + inv.tpolyhedra_value); + bool heap_improved=heap_solver.iterate(inv.heap_value); + solver.pop_context(); + + if(heap_improved) + { + // If heap part was improved, restrict template polyhedra part to the found + // symbolic path + symbolic_path=heap_solver.symbolic_path; + heap_tpolyhedra_domain.polyhedra_domain.restrict_to_sympath(symbolic_path); + } + + // Run one interation of the template polyhedra solver in the context of + // invariant from the heap solver + solver.new_context(); + solver << heap_tpolyhedra_domain.heap_domain.to_pre_constraints( + inv.heap_value); + bool tpolyhedra_improved=tpolyhedra_solver.iterate(inv.tpolyhedra_value); + solver.pop_context(); + + if(heap_improved) + heap_tpolyhedra_domain.polyhedra_domain.undo_restriction(); + + return heap_improved || tpolyhedra_improved; +} + +/*******************************************************************\ + +Function: strategy_solver_heap_tpolyhedrat::set_message_handler + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void strategy_solver_heap_tpolyhedrat::set_message_handler( + message_handlert &_message_handler) +{ + heap_solver.set_message_handler(_message_handler); + tpolyhedra_solver.set_message_handler(_message_handler); +} + +void strategy_solver_heap_tpolyhedrat::clear_symbolic_path() +{ + heap_solver.symbolic_path.clear(); + tpolyhedra_solver.symbolic_path.clear(); +} diff --git a/src/domains/strategy_solver_heap_interval.h b/src/domains/strategy_solver_heap_tpolyhedra.h similarity index 53% rename from src/domains/strategy_solver_heap_interval.h rename to src/domains/strategy_solver_heap_tpolyhedra.h index 61b2b9cda..967f53aa8 100644 --- a/src/domains/strategy_solver_heap_interval.h +++ b/src/domains/strategy_solver_heap_tpolyhedra.h @@ -1,40 +1,41 @@ /*******************************************************************\ -Module: Strategy solver for combination of shape and interval domains. +Module: Strategy solver for combination of shape and template + polyhedra domains. Author: Viktor Malik \*******************************************************************/ -#ifndef CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_INTERVAL_H -#define CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_INTERVAL_H +#ifndef CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_TPOLYHEDRA_H +#define CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_TPOLYHEDRA_H #include "strategy_solver_base.h" -#include "heap_interval_domain.h" +#include "heap_tpolyhedra_domain.h" #include "strategy_solver_heap.h" #include "strategy_solver_binsearch.h" -class strategy_solver_heap_intervalt:public strategy_solver_baset +class strategy_solver_heap_tpolyhedrat:public strategy_solver_baset { public: - strategy_solver_heap_intervalt( - heap_interval_domaint &_heap_interval_domain, + strategy_solver_heap_tpolyhedrat( + heap_tpolyhedra_domaint &_heap_tpolyhedra_domain, incremental_solvert &_solver, const local_SSAt &SSA, const exprt &precondition, message_handlert &message_handler, template_generator_baset &template_generator): strategy_solver_baset(_solver, SSA.ns), - heap_interval_domain(_heap_interval_domain), + heap_tpolyhedra_domain(_heap_tpolyhedra_domain), heap_solver( - heap_interval_domain.heap_domain, + heap_tpolyhedra_domain.heap_domain, _solver, SSA, precondition, message_handler, template_generator), - interval_solver(heap_interval_domain.polyhedra_domain, _solver, SSA.ns) + tpolyhedra_solver(heap_tpolyhedra_domain.polyhedra_domain, _solver, SSA.ns) { } @@ -44,11 +45,11 @@ class strategy_solver_heap_intervalt:public strategy_solver_baset void clear_symbolic_path(); protected: - heap_interval_domaint &heap_interval_domain; + heap_tpolyhedra_domaint &heap_tpolyhedra_domain; strategy_solver_heapt heap_solver; - strategy_solver_binsearcht interval_solver; + strategy_solver_binsearcht tpolyhedra_solver; }; -#endif // CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_INTERVAL_H +#endif // CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_TPOLYHEDRA_H diff --git a/src/domains/strategy_solver_heap_interval_sympath.cpp b/src/domains/strategy_solver_heap_tpolyhedra_sympath.cpp similarity index 69% rename from src/domains/strategy_solver_heap_interval_sympath.cpp rename to src/domains/strategy_solver_heap_tpolyhedra_sympath.cpp index 6225d4ce4..53fcb1546 100644 --- a/src/domains/strategy_solver_heap_interval_sympath.cpp +++ b/src/domains/strategy_solver_heap_tpolyhedra_sympath.cpp @@ -1,6 +1,6 @@ /*******************************************************************\ -Module: Strategy solver for heap-interval domain using symbolic paths +Module: Strategy solver for heap-tpolyhedra domain using symbolic paths Author: Viktor Malik @@ -8,11 +8,11 @@ Author: Viktor Malik // #define DEBUG -#include "strategy_solver_heap_interval_sympath.h" +#include "strategy_solver_heap_tpolyhedra_sympath.h" /*******************************************************************\ -Function: strategy_solver_heap_interval_sympatht::set_message_handler +Function: strategy_solver_heap_tpolyhedra_sympatht::set_message_handler Inputs: @@ -21,7 +21,7 @@ Function: strategy_solver_heap_interval_sympatht::set_message_handler Purpose: \*******************************************************************/ -void strategy_solver_heap_interval_sympatht::set_message_handler( +void strategy_solver_heap_tpolyhedra_sympatht::set_message_handler( message_handlert &_message_handler) { solver.set_message_handler(_message_handler); @@ -29,7 +29,7 @@ void strategy_solver_heap_interval_sympatht::set_message_handler( /*******************************************************************\ -Function: strategy_solver_heap_interval_sympatht::iterate +Function: strategy_solver_heap_tpolyhedra_sympatht::iterate Inputs: @@ -38,12 +38,11 @@ Function: strategy_solver_heap_interval_sympatht::iterate Purpose: \*******************************************************************/ -bool strategy_solver_heap_interval_sympatht::iterate( +bool strategy_solver_heap_tpolyhedra_sympatht::iterate( strategy_solver_baset::invariantt &_inv) { - heap_interval_sympath_domaint::heap_interval_sympath_valuet &inv= - static_cast - (_inv); + auto &inv=static_cast + (_inv); bool improved; if(!new_path) @@ -58,8 +57,8 @@ bool strategy_solver_heap_interval_sympatht::iterate( const exprt sympath=symbolic_path.get_expr(); - domain.heap_interval_domain.restrict_to_sympath(symbolic_path); - improved=heap_interval_solver.iterate(inv.at(sympath)); + domain.heap_tpolyhedra_domain.restrict_to_sympath(symbolic_path); + improved=heap_tpolyhedra_solver.iterate(inv.at(sympath)); if(!improved) { // Invariant for the current symbolic path cannot be improved @@ -74,42 +73,42 @@ bool strategy_solver_heap_interval_sympatht::iterate( inv.erase(sympath); visited_paths.push_back(symbolic_path); - domain.heap_interval_domain.clear_aux_symbols(); - domain.heap_interval_domain.eliminate_sympaths(visited_paths); + domain.heap_tpolyhedra_domain.clear_aux_symbols(); + domain.heap_tpolyhedra_domain.eliminate_sympaths(visited_paths); clear_symbolic_path(); improved=true; new_path=true; } - else if(heap_interval_solver.symbolic_path.get_expr()!=sympath) + else if(heap_tpolyhedra_solver.symbolic_path.get_expr()!=sympath) { // The path has been altered during computation (solver has found another // loop-select guard that can be true - auto new_sympath=heap_interval_solver.symbolic_path.get_expr(); + auto new_sympath=heap_tpolyhedra_solver.symbolic_path.get_expr(); inv.emplace(new_sympath, std::move(inv.at(sympath))); inv.erase(sympath); - symbolic_path=heap_interval_solver.symbolic_path; + symbolic_path=heap_tpolyhedra_solver.symbolic_path; #ifdef DEBUG std::cerr << "Path altered\n"; std::cerr << from_expr(ns, "", symbolic_path.get_expr()) << "\n"; #endif } - domain.heap_interval_domain.undo_restriction(); + domain.heap_tpolyhedra_domain.undo_restriction(); } else { // Computing invariant for a new path - heap_interval_domaint::heap_interval_valuet new_value; - domain.heap_interval_domain.initialize(new_value); - improved=heap_interval_solver.iterate(new_value); + heap_tpolyhedra_domaint::heap_tpolyhedra_valuet new_value; + domain.heap_tpolyhedra_domain.initialize(new_value); + improved=heap_tpolyhedra_solver.iterate(new_value); if(improved) { - symbolic_path=heap_interval_solver.symbolic_path; + symbolic_path=heap_tpolyhedra_solver.symbolic_path; #ifdef DEBUG std::cerr << "Symbolic path:\n"; std::cerr << from_expr(ns, "", symbolic_path.get_expr()) << "\n"; #endif - const exprt sympath=heap_interval_solver.symbolic_path.get_expr(); + const exprt sympath=heap_tpolyhedra_solver.symbolic_path.get_expr(); inv.emplace(sympath, std::move(new_value)); new_path=false; } @@ -119,7 +118,7 @@ bool strategy_solver_heap_interval_sympatht::iterate( /*******************************************************************\ -Function: strategy_solver_heap_interval_sympatht::clear_symbolic_path +Function: strategy_solver_heap_tpolyhedra_sympatht::clear_symbolic_path Inputs: @@ -128,15 +127,15 @@ Function: strategy_solver_heap_interval_sympatht::clear_symbolic_path Purpose: \*******************************************************************/ -void strategy_solver_heap_interval_sympatht::clear_symbolic_path() +void strategy_solver_heap_tpolyhedra_sympatht::clear_symbolic_path() { symbolic_path.clear(); - heap_interval_solver.clear_symbolic_path(); + heap_tpolyhedra_solver.clear_symbolic_path(); } /*******************************************************************\ -Function: strategy_solver_heap_interval_sympatht::is_current_path_feasible +Function: strategy_solver_heap_tpolyhedra_sympatht::is_current_path_feasible Inputs: @@ -153,8 +152,8 @@ Function: strategy_solver_heap_interval_sympatht::is_current_path_feasible (g#lb => !g#le must be SAT) \*******************************************************************/ -bool strategy_solver_heap_interval_sympatht::is_current_path_feasible( - heap_interval_sympath_domaint::heap_interval_sympath_valuet &value) +bool strategy_solver_heap_tpolyhedra_sympatht::is_current_path_feasible( + heap_tpolyhedra_sympath_domaint::heap_tpolyhedra_sympath_valuet &value) { bool result=true; auto sympath=symbolic_path.get_expr(); @@ -162,7 +161,8 @@ bool strategy_solver_heap_interval_sympatht::is_current_path_feasible( // Path invariant exprt invariant; - domain.heap_interval_domain.project_on_vars(value.at(sympath), {}, invariant); + domain.heap_tpolyhedra_domain.project_on_vars( + value.at(sympath), {}, invariant); solver << invariant; for(auto &guard : symbolic_path.path_map) @@ -194,7 +194,7 @@ bool strategy_solver_heap_interval_sympatht::is_current_path_feasible( /*******************************************************************\ -Function: strategy_solver_heap_interval_sympatht::build_loop_conds_map +Function: strategy_solver_heap_tpolyhedra_sympatht::build_loop_conds_map Inputs: @@ -203,7 +203,7 @@ Function: strategy_solver_heap_interval_sympatht::build_loop_conds_map Purpose: \*******************************************************************/ -void strategy_solver_heap_interval_sympatht::build_loop_conds_map( +void strategy_solver_heap_tpolyhedra_sympatht::build_loop_conds_map( const local_SSAt &SSA) { for(auto &node : SSA.nodes) diff --git a/src/domains/strategy_solver_heap_interval_sympath.h b/src/domains/strategy_solver_heap_tpolyhedra_sympath.h similarity index 59% rename from src/domains/strategy_solver_heap_interval_sympath.h rename to src/domains/strategy_solver_heap_tpolyhedra_sympath.h index 6fb7fc17b..6bca710e3 100644 --- a/src/domains/strategy_solver_heap_interval_sympath.h +++ b/src/domains/strategy_solver_heap_tpolyhedra_sympath.h @@ -1,24 +1,24 @@ /*******************************************************************\ -Module: Strategy solver for heap-interval domain using symbolic paths +Module: Strategy solver for heap-tpolyhedra domain using symbolic paths Author: Viktor Malik \*******************************************************************/ -#ifndef CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_INTERVAL_SYMPATH_H -#define CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_INTERVAL_SYMPATH_H +#ifndef CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_TPOLYHEDRA_SYMPATH_H +#define CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_TPOLYHEDRA_SYMPATH_H #include "strategy_solver_base.h" -#include "heap_interval_sympath_domain.h" -#include "strategy_solver_heap_interval.h" +#include "heap_tpolyhedra_sympath_domain.h" +#include "strategy_solver_heap_tpolyhedra.h" -class strategy_solver_heap_interval_sympatht:public strategy_solver_baset +class strategy_solver_heap_tpolyhedra_sympatht:public strategy_solver_baset { public: - strategy_solver_heap_interval_sympatht( - heap_interval_sympath_domaint &_domain, + strategy_solver_heap_tpolyhedra_sympatht( + heap_tpolyhedra_sympath_domaint &_domain, incremental_solvert &_solver, const local_SSAt &SSA, const exprt &precondition, @@ -26,8 +26,8 @@ class strategy_solver_heap_interval_sympatht:public strategy_solver_baset template_generator_baset &template_generator): strategy_solver_baset(_solver, SSA.ns), domain(_domain), - heap_interval_solver( - domain.heap_interval_domain, + heap_tpolyhedra_solver( + domain.heap_tpolyhedra_domain, _solver, SSA, precondition, @@ -44,8 +44,8 @@ class strategy_solver_heap_interval_sympatht:public strategy_solver_baset void clear_symbolic_path(); protected: - heap_interval_sympath_domaint &domain; - strategy_solver_heap_intervalt heap_interval_solver; + heap_tpolyhedra_sympath_domaint &domain; + strategy_solver_heap_tpolyhedrat heap_tpolyhedra_solver; std::vector visited_paths; bool new_path=true; @@ -58,8 +58,8 @@ class strategy_solver_heap_interval_sympatht:public strategy_solver_baset void build_loop_conds_map(const local_SSAt &SSA); bool is_current_path_feasible( - heap_interval_sympath_domaint::heap_interval_sympath_valuet &value); + heap_tpolyhedra_sympath_domaint::heap_tpolyhedra_sympath_valuet &value); }; -#endif // CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_INTERVAL_SYMPATH_ +#endif // CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_HEAP_TPOLYHEDRA_SYMPATH_H diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index 65ad50432..f9a56e7bd 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -19,8 +19,8 @@ Author: Peter Schrammel #include "tpolyhedra_domain.h" #include "predabs_domain.h" #include "heap_domain.h" -#include "heap_interval_domain.h" -#include "heap_interval_sympath_domain.h" +#include "heap_tpolyhedra_domain.h" +#include "heap_tpolyhedra_sympath_domain.h" #ifdef DEBUG #include @@ -801,13 +801,13 @@ void template_generator_baset::instantiate_standard_domains( { filter_heap_interval_domain(); auto polyhedra_kind=options.get_bool_option("heap-interval") - ? heap_interval_domaint::INTERVAL - : heap_interval_domaint::ZONES; + ? heap_tpolyhedra_domaint::INTERVAL + : heap_tpolyhedra_domaint::ZONES; if(options.get_bool_option("sympath")) - domain_ptr=new heap_interval_sympath_domaint( + domain_ptr=new heap_tpolyhedra_sympath_domaint( domain_number, renaming_map, var_specs, SSA, polyhedra_kind); else - domain_ptr=new heap_interval_domaint( + domain_ptr=new heap_tpolyhedra_domaint( domain_number, renaming_map, var_specs, SSA.ns, polyhedra_kind); } } From cbb660c5e6e790f408cbf48cad6a2412183f2ee8 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 3 Aug 2018 09:32:04 +0200 Subject: [PATCH 233/322] Refactor combination of heap domain with increasing strength of value domains. Rename --heap-values-incremental to --heap-values-refine. Move refinement into summary_checker_ai. --- regression/heap-data/calendar/test.desc | 2 +- regression/heap-data/cart/test.desc | 2 +- regression/heap-data/hash_fun/test.desc | 2 +- regression/heap-data/min_max/test.desc | 2 +- regression/heap-data/packet_filter/test.desc | 2 +- regression/heap-data/process_queue/test.desc | 2 +- .../heap-data/quick_sort_split/test.desc | 2 +- .../heap-data/running_example/test.desc | 2 +- .../running_example_assume/test.desc | 2 +- regression/heap-data/shared_mem1/test.desc | 2 +- regression/heap-data/shared_mem2/test.desc | 2 +- src/2ls/2ls_parse_options.cpp | 243 +++++++++--------- src/2ls/2ls_parse_options.h | 2 +- src/2ls/summary_checker_ai.cpp | 72 ++++-- 14 files changed, 173 insertions(+), 166 deletions(-) diff --git a/regression/heap-data/calendar/test.desc b/regression/heap-data/calendar/test.desc index 20acb756e..b48b4027a 100644 --- a/regression/heap-data/calendar/test.desc +++ b/regression/heap-data/calendar/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-values-incremental --sympath --inline +--heap-values-refine --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap-data/cart/test.desc b/regression/heap-data/cart/test.desc index 20acb756e..b48b4027a 100644 --- a/regression/heap-data/cart/test.desc +++ b/regression/heap-data/cart/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-values-incremental --sympath --inline +--heap-values-refine --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap-data/hash_fun/test.desc b/regression/heap-data/hash_fun/test.desc index 20acb756e..b48b4027a 100644 --- a/regression/heap-data/hash_fun/test.desc +++ b/regression/heap-data/hash_fun/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-values-incremental --sympath --inline +--heap-values-refine --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap-data/min_max/test.desc b/regression/heap-data/min_max/test.desc index 20acb756e..b48b4027a 100644 --- a/regression/heap-data/min_max/test.desc +++ b/regression/heap-data/min_max/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-values-incremental --sympath --inline +--heap-values-refine --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap-data/packet_filter/test.desc b/regression/heap-data/packet_filter/test.desc index 35b8f2f24..2ed70fde0 100644 --- a/regression/heap-data/packet_filter/test.desc +++ b/regression/heap-data/packet_filter/test.desc @@ -1,6 +1,6 @@ THOROUGH main.c ---heap-values-incremental --sympath --inline +--heap-values-refine --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap-data/process_queue/test.desc b/regression/heap-data/process_queue/test.desc index 20acb756e..b48b4027a 100644 --- a/regression/heap-data/process_queue/test.desc +++ b/regression/heap-data/process_queue/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-values-incremental --sympath --inline +--heap-values-refine --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap-data/quick_sort_split/test.desc b/regression/heap-data/quick_sort_split/test.desc index 20acb756e..b48b4027a 100644 --- a/regression/heap-data/quick_sort_split/test.desc +++ b/regression/heap-data/quick_sort_split/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-values-incremental --sympath --inline +--heap-values-refine --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap-data/running_example/test.desc b/regression/heap-data/running_example/test.desc index 20acb756e..b48b4027a 100644 --- a/regression/heap-data/running_example/test.desc +++ b/regression/heap-data/running_example/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-values-incremental --sympath --inline +--heap-values-refine --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap-data/running_example_assume/test.desc b/regression/heap-data/running_example_assume/test.desc index bd68e9d2c..253d82f29 100644 --- a/regression/heap-data/running_example_assume/test.desc +++ b/regression/heap-data/running_example_assume/test.desc @@ -1,6 +1,6 @@ KNOWNBUG main.c ---heap-values-incremental --sympath --inline +--heap-values-refine --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap-data/shared_mem1/test.desc b/regression/heap-data/shared_mem1/test.desc index 20acb756e..b48b4027a 100644 --- a/regression/heap-data/shared_mem1/test.desc +++ b/regression/heap-data/shared_mem1/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-values-incremental --sympath --inline +--heap-values-refine --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/regression/heap-data/shared_mem2/test.desc b/regression/heap-data/shared_mem2/test.desc index 20acb756e..b48b4027a 100644 --- a/regression/heap-data/shared_mem2/test.desc +++ b/regression/heap-data/shared_mem2/test.desc @@ -1,6 +1,6 @@ CORE main.c ---heap-values-incremental --sympath --inline +--heap-values-refine --sympath --inline ^EXIT=0$ ^SIGNAL=0$ ^VERIFICATION SUCCESSFUL$ diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 091bcc81f..5ddf15306 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -216,8 +216,9 @@ void twols_parse_optionst::get_command_line_options(optionst &options) if(cmdline.isset("sympath")) options.set_option("sympath", true); } - else if(cmdline.isset("heap-values-incremental")) + else if(cmdline.isset("heap-values-refine")) { + options.set_option("heap-values-refine", true); options.set_option("heap-interval", true); if(cmdline.isset("sympath")) options.set_option("sympath", true); @@ -578,153 +579,137 @@ int twols_parse_optionst::doit() try { - bool finished=false; + std::unique_ptr checker; + if(!options.get_bool_option("k-induction") && + !options.get_bool_option("incremental-bmc")) + checker=std::unique_ptr( + new summary_checker_ait(options, heap_analysis)); + if(options.get_bool_option("k-induction") && + !options.get_bool_option("incremental-bmc")) + checker=std::unique_ptr( + new summary_checker_kindt(options, heap_analysis)); + if(!options.get_bool_option("k-induction") && + options.get_bool_option("incremental-bmc")) + checker=std::unique_ptr( + new summary_checker_bmct(options, heap_analysis)); + if(options.get_bool_option("nontermination")) + checker=std::unique_ptr( + new summary_checker_nontermt(options, heap_analysis)); + + checker->set_message_handler(get_message_handler()); + checker->simplify=!cmdline.isset("no-simplify"); + checker->fixed_point=!cmdline.isset("no-fixed-point"); + int retval; - while(!finished) + if(cmdline.isset("show-vcc")) { - std::unique_ptr checker; - if(!options.get_bool_option("k-induction") && - !options.get_bool_option("incremental-bmc")) - checker=std::unique_ptr( - new summary_checker_ait(options, heap_analysis)); - if(options.get_bool_option("k-induction") && - !options.get_bool_option("incremental-bmc")) - checker=std::unique_ptr( - new summary_checker_kindt(options, heap_analysis)); - if(!options.get_bool_option("k-induction") && - options.get_bool_option("incremental-bmc")) - checker=std::unique_ptr( - new summary_checker_bmct(options, heap_analysis)); - if(options.get_bool_option("nontermination")) - checker=std::unique_ptr( - new summary_checker_nontermt(options, heap_analysis)); - - checker->set_message_handler(get_message_handler()); - checker->simplify=!cmdline.isset("no-simplify"); - checker->fixed_point=!cmdline.isset("no-fixed-point"); - - if(cmdline.isset("show-vcc")) - { - std::cout << "VERIFICATION CONDITIONS:\n\n"; - checker->show_vcc=true; - (*checker)(goto_model); - return 0; - } + std::cout << "VERIFICATION CONDITIONS:\n\n"; + checker->show_vcc=true; + (*checker)(goto_model); + return 0; + } - if(cmdline.isset("horn-encoding")) - { - status() << "Horn-clause encoding" << eom; - namespacet ns(symbol_table); + if(cmdline.isset("horn-encoding")) + { + status() << "Horn-clause encoding" << eom; + namespacet ns(symbol_table); - std::string out_file=cmdline.get_value("horn-encoding"); + std::string out_file=cmdline.get_value("horn-encoding"); - if(out_file=="-") - { - horn_encoding(goto_model, std::cout); - } - else - { + if(out_file=="-") + { + horn_encoding(goto_model, std::cout); + } + else + { #ifdef _MSC_VER - std::ofstream out(widen(out_file).c_str()); + std::ofstream out(widen(out_file).c_str()); #else - std::ofstream out(out_file.c_str()); + std::ofstream out(out_file.c_str()); #endif - if(!out) - { - error() << "Failed to open output file " - << out_file << eom; - return 1; - } - - horn_encoding(goto_model, out); + if(!out) + { + error() << "Failed to open output file " + << out_file << eom; + return 1; } - return 0; + horn_encoding(goto_model, out); } - bool report_assertions= - !options.get_bool_option("preconditions") && - !options.get_bool_option("termination") && - !options.get_bool_option("nontermination"); - // do actual analysis - switch((*checker)(goto_model)) - { - case property_checkert::PASS: - if(report_assertions) - report_properties(options, goto_model, checker->property_map); - report_success(); - if(cmdline.isset("graphml-witness")) - output_graphml_proof(options, goto_model, *checker); - retval=0; - finished=true; - break; - - case property_checkert::FAIL: - { - if(report_assertions) - report_properties(options, goto_model, checker->property_map); + return 0; + } - // validate trace - bool trace_valid=false; - for(const auto &p : checker->property_map) - { - if(p.second.result!=property_checkert::FAIL) - continue; + bool report_assertions= + !options.get_bool_option("preconditions") && + !options.get_bool_option("termination") && + !options.get_bool_option("nontermination"); + // do actual analysis + switch((*checker)(goto_model)) + { + case property_checkert::PASS: + if(report_assertions) + report_properties(options, goto_model, checker->property_map); + report_success(); + if(cmdline.isset("graphml-witness")) + output_graphml_proof(options, goto_model, *checker); + retval=0; + break; + + case property_checkert::FAIL: + { + if(report_assertions) + report_properties(options, goto_model, checker->property_map); - if(options.get_bool_option("trace")) - show_counterexample(goto_model, p.second.error_trace); + // validate trace + bool trace_valid=false; + for(const auto &p : checker->property_map) + { + if(p.second.result!=property_checkert::FAIL) + continue; - trace_valid= - !p.second.error_trace.steps.empty() && - (options.get_bool_option("nontermination") || - p.second.error_trace.steps.back().is_assert()); - break; - } + if(options.get_bool_option("trace")) + show_counterexample(goto_model, p.second.error_trace); - if(cmdline.isset("graphml-witness")) - { -#if 1 - if(!trace_valid) - { - retval=5; - error() << "Internal witness validation failed" << eom; - report_unknown(); - break; - } -#endif - output_graphml_cex(options, goto_model, *checker); - } - report_failure(); - retval=10; - finished=true; + trace_valid= + !p.second.error_trace.steps.empty() && + (options.get_bool_option("nontermination") || + p.second.error_trace.steps.back().is_assert()); break; } - case property_checkert::UNKNOWN: - if(cmdline.isset("heap-values-incremental") && - options.get_bool_option("heap-interval")) - { - options.set_option("heap-interval", false); - options.set_option("heap-zones", true); - } - else + + if(cmdline.isset("graphml-witness")) + { +#if 1 + if(!trace_valid) { - if(report_assertions) - report_properties(options, goto_model, checker->property_map); retval=5; - finished=true; + error() << "Internal witness validation failed" << eom; report_unknown(); + break; } - break; - - default: - assert(false); +#endif + output_graphml_cex(options, goto_model, *checker); } + report_failure(); + retval=10; + break; + } + case property_checkert::UNKNOWN: + if(report_assertions) + report_properties(options, goto_model, checker->property_map); + retval=5; + report_unknown(); + break; - if(cmdline.isset("instrument-output")) - { - checker->instrument_and_output(goto_model); - } + default: + assert(false); + } + + if(cmdline.isset("instrument-output")) + { + checker->instrument_and_output(goto_model); } return retval; @@ -1802,10 +1787,14 @@ void twols_parse_optionst::help() " --heap use heap domain\n" " --zones use zone domain\n" " --octagons use octagon domain\n" - " --heap-interval use heap domain with interval domain for values\n" // NOLINT(*) - " --heap-zones use heap domain with zones domain for values\n" // NOLINT(*) - " --heap-incremental use heap domain with dynamically incrementing strength of value domain\n" // NOLINT(*) - " --sympath compute invariant for each symbolic path (only usable with --heap-interval switch)" // NOLINT(*) + " --heap-interval use heap domain with interval domain for" + "values\n" + " --heap-zones use heap domain with zones domain for values" + "\n" + " --heap-values-refine use heap domain with a dynamically" + "refinement of the strength of the value domain\n" + " --sympath compute invariant for each symbolic path" + "(only usable with --heap-interval switch)" " --enum-solver use solver based on model enumeration\n" " --binsearch-solver use solver based on binary search\n" " --arrays do not ignore array contents\n" diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index d0dd45127..9308fc9f3 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -46,7 +46,7 @@ class optionst; "(heap)" \ "(heap-interval)" \ "(heap-zones)" \ - "(heap-values-incremental)" \ + "(heap-values-refine)" \ "(sympath)" \ "(enum-solver)(binsearch-solver)(arrays)"\ "(string-abstraction)(no-arch)(arch):(floatbv)(fixedbv)" \ diff --git a/src/2ls/summary_checker_ai.cpp b/src/2ls/summary_checker_ai.cpp index 6f36857ab..8e60a8739 100644 --- a/src/2ls/summary_checker_ai.cpp +++ b/src/2ls/summary_checker_ai.cpp @@ -43,40 +43,58 @@ property_checkert::resultt summary_checker_ait::operator()( // properties initialize_property_map(goto_model.goto_functions); - bool preconditions=options.get_bool_option("preconditions"); - bool termination=options.get_bool_option("termination"); - bool trivial_domain=options.get_bool_option("havoc"); - if(!trivial_domain || termination) + property_checkert::resultt result=property_checkert::UNKNOWN; + bool finished=false; + while(!finished) { - // forward analysis - summarize(goto_model, true, termination); - } - if(!trivial_domain && preconditions) - { - // backward analysis - summarize(goto_model, false, termination); - } + bool preconditions=options.get_bool_option("preconditions"); + bool termination=options.get_bool_option("termination"); + bool trivial_domain=options.get_bool_option("havoc"); + if(!trivial_domain || termination) + { + // forward analysis + summarize(goto_model, true, termination); + } + if(!trivial_domain && preconditions) + { + // backward analysis + summarize(goto_model, false, termination); + } - if(preconditions) - { - report_statistics(); - report_preconditions(); - return property_checkert::UNKNOWN; - } + if(preconditions) + { + report_statistics(); + report_preconditions(); + return property_checkert::UNKNOWN; + } - if(termination) - { - report_statistics(); - return report_termination(); - } + if(termination) + { + report_statistics(); + return report_termination(); + } #ifdef SHOW_CALLINGCONTEXTS - if(options.get_bool_option("show-calling-contexts")) - return property_checkert::UNKNOWN; + if(options.get_bool_option("show-calling-contexts")) + return property_checkert::UNKNOWN; #endif - property_checkert::resultt result=check_properties(); - report_statistics(); + result=check_properties(); + report_statistics(); + + if(result==property_checkert::UNKNOWN && + options.get_bool_option("heap-values-refine") && + options.get_bool_option("heap-interval")) + { + summary_db.clear(); + options.set_option("heap-interval", false); + options.set_option("heap-zones", true); + } + else + { + finished=true; + } + } return result; } From d938e3eebd5dbcc270d68400c84e0ed2c08c70a5 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 3 Aug 2018 09:34:59 +0200 Subject: [PATCH 234/322] Code cleanup 1. Move long and utility functions into dedicated modules 2. Add braces for multi-line statements and multi-line conditionals 3. Remove commented code 4. Use better types (size_t instead of unsigned) 5. Replace function pointer by std::function --- regression/Makefile | 12 +++-- src/2ls/2ls_parse_options.cpp | 16 +----- src/2ls/2ls_parse_options.h | 1 + src/2ls/preprocessing_util.cpp | 24 ++++++++- src/domains/heap_domain.cpp | 13 ++++- src/domains/strategy_solver_heap.cpp | 22 --------- src/domains/strategy_solver_heap.h | 2 - src/domains/util.cpp | 22 +++++++++ src/domains/util.h | 2 + src/ssa/dynobj_instance_analysis.cpp | 4 +- src/ssa/dynobj_instance_analysis.h | 73 ++++++++++++++-------------- src/ssa/malloc_ssa.cpp | 27 ++-------- src/ssa/malloc_ssa.h | 1 - src/ssa/ssa_value_set.h | 1 - 14 files changed, 110 insertions(+), 110 deletions(-) diff --git a/regression/Makefile b/regression/Makefile index 7b88bfe9c..7143b0ad8 100644 --- a/regression/Makefile +++ b/regression/Makefile @@ -1,6 +1,12 @@ -DIRS = nontermination termination kiki \ - preconditions interprocedural invariants \ - heap heap-data memsafety +DIRS = nontermination \ + termination \ + kiki \ + preconditions \ + interprocedural \ + invariants \ + heap \ + heap-data \ + memsafety test: $(foreach var,$(DIRS), make -C $(var) test || exit 1;) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 5ddf15306..b9aba9452 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -1255,7 +1255,6 @@ bool twols_parse_optionst::process_goto_program( if(options.get_bool_option("pointer-check")) { allow_record_malloc(goto_model); -// allow_record_free(goto_model); } if(options.get_bool_option("memory-leak-check")) allow_record_memleak(goto_model); @@ -1271,20 +1270,7 @@ bool twols_parse_optionst::process_goto_program( inline_main(goto_model); } - std::map dynobj_instances; - Forall_goto_functions(f_it, goto_model.goto_functions) - { - if(!f_it->second.body_available()) - continue; - namespacet ns(goto_model.symbol_table); - ssa_value_ait value_analysis(f_it->second, ns, ssa_heap_analysist(ns)); - dynobj_instance_analysist do_inst(f_it->second, ns, value_analysis); - - compute_dynobj_instances( - f_it->second.body, do_inst, dynobj_instances, ns); - create_dynobj_instances( - f_it->second.body, dynobj_instances, goto_model.symbol_table); - } + auto dynobj_instances=split_dynamic_objects(goto_model); if(!cmdline.isset("independent-properties")) { diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index 9308fc9f3..2199b95d3 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -203,6 +203,7 @@ class twols_parse_optionst: goto_programt &goto_program, const std::map &instance_counts, symbol_tablet &symbol_table); + std::map split_dynamic_objects(goto_modelt &goto_model); }; #endif diff --git a/src/2ls/preprocessing_util.cpp b/src/2ls/preprocessing_util.cpp index 0e5d36cb5..f69cc78db 100644 --- a/src/2ls/preprocessing_util.cpp +++ b/src/2ls/preprocessing_util.cpp @@ -742,10 +742,10 @@ void twols_parse_optionst::compute_dynobj_instances( if(must_alias==analysis_value.must_alias_relations.end()) continue; - std::set alias_classes; + std::set alias_classes; for(auto &expr : obj.second) { - unsigned long n; + size_t n; must_alias->second.get_number(expr, n); alias_classes.insert(must_alias->second.find_number(n)); } @@ -846,3 +846,23 @@ void twols_parse_optionst::create_dynobj_instances( } } } + +std::map twols_parse_optionst::split_dynamic_objects( + goto_modelt &goto_model) +{ + std::map dynobj_instances; + Forall_goto_functions(f_it, goto_model.goto_functions) + { + if(!f_it->second.body_available()) + continue; + namespacet ns(goto_model.symbol_table); + ssa_value_ait value_analysis(f_it->second, ns, ssa_heap_analysist(ns)); + dynobj_instance_analysist do_inst(f_it->second, ns, value_analysis); + + compute_dynobj_instances( + f_it->second.body, do_inst, dynobj_instances, ns); + create_dynobj_instances( + f_it->second.body, dynobj_instances, goto_model.symbol_table); + } + return dynobj_instances; +} diff --git a/src/domains/heap_domain.cpp b/src/domains/heap_domain.cpp index acf64fda5..6c4576dea 100644 --- a/src/domains/heap_domain.cpp +++ b/src/domains/heap_domain.cpp @@ -85,12 +85,16 @@ void heap_domaint::make_template( { if(!(v_other.var.type().id()==ID_pointer && v_other.kind==LOOP && v_other.pre_guard==v.pre_guard)) + { continue; + } if(v_other.var.id()==ID_symbol && id2string(to_symbol_expr(v_other.var).get_identifier()).find( "__CPROVER_")!=std::string::npos) + { continue; + } add_template_row_pair(v, v_other, pointed_type); } @@ -136,7 +140,12 @@ void heap_domaint::add_template_row( if(identifier.find("."+id2string(component.get_name()))!= std::string::npos) { -// templ_row.mem_kind=HEAP; +#if 0 + // It has shown that using stack rows only is sufficient to prove all + // tested programs and it seems that pointer access paths are not + // necessary. Therefore, we currently disable this code. + templ_row.mem_kind=HEAP; +#endif templ_row.member=component.get_name(); std::string var_id=id2string(to_symbol_expr(var).get_identifier()); @@ -632,9 +641,11 @@ const exprt ptr_equality( else if(ns.follow(ptr_expr.type().subtype())==ns.follow(ptr_value.type())) value=address_of_exprt(ptr_value); else + { value=typecast_exprt( address_of_exprt(ptr_value), ns.follow(ptr_expr.type())); + } return equal_exprt(ptr_expr, value); } diff --git a/src/domains/strategy_solver_heap.cpp b/src/domains/strategy_solver_heap.cpp index bd1b3b28a..faf3c1a5f 100644 --- a/src/domains/strategy_solver_heap.cpp +++ b/src/domains/strategy_solver_heap.cpp @@ -10,8 +10,6 @@ Author: Viktor Malik #include #include -#include -#include #include "strategy_solver_heap.h" /*******************************************************************\ @@ -447,26 +445,6 @@ void strategy_solver_heapt::clear_pointing_rows( /*******************************************************************\ -Function: strategy_solver_heapt::is_cprover_symbol - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -bool strategy_solver_heapt::is_cprover_symbol(const exprt &expr) -{ - return expr.id()==ID_symbol && - has_prefix( - id2string(to_symbol_expr(expr).get_identifier()), - CPROVER_PREFIX); -} - -/*******************************************************************\ - Function: strategy_solver_heapt::get_points_to_dest Inputs: diff --git a/src/domains/strategy_solver_heap.h b/src/domains/strategy_solver_heap.h index 4007eded5..757da4d86 100644 --- a/src/domains/strategy_solver_heap.h +++ b/src/domains/strategy_solver_heap.h @@ -61,8 +61,6 @@ class strategy_solver_heapt:public strategy_solver_baset heap_domaint::heap_valuet &value); void print_solver_expr(const exprt &expr); - - bool is_cprover_symbol(const exprt &expr); }; diff --git a/src/domains/util.cpp b/src/domains/util.cpp index 4833531e6..826495123 100644 --- a/src/domains/util.cpp +++ b/src/domains/util.cpp @@ -7,6 +7,8 @@ Author: Peter Schrammel \*******************************************************************/ #include +#include +#include #include "util.h" @@ -688,3 +690,23 @@ void clean_expr(exprt &expr) } } } + +/*******************************************************************\ + +Function: is_cprover_symbol + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool is_cprover_symbol(const exprt &expr) +{ + return expr.id()==ID_symbol && + has_prefix( + id2string(to_symbol_expr(expr).get_identifier()), + CPROVER_PREFIX); +} diff --git a/src/domains/util.h b/src/domains/util.h index 790473db4..d21601a18 100644 --- a/src/domains/util.h +++ b/src/domains/util.h @@ -36,4 +36,6 @@ constant_exprt make_minusone(const typet &type); irep_idt get_original_name(const symbol_exprt &); void clean_expr(exprt &expr); +bool is_cprover_symbol(const exprt &expr); + #endif diff --git a/src/ssa/dynobj_instance_analysis.cpp b/src/ssa/dynobj_instance_analysis.cpp index 6d2b68b0e..32d1454ad 100644 --- a/src/ssa/dynobj_instance_analysis.cpp +++ b/src/ssa/dynobj_instance_analysis.cpp @@ -138,7 +138,7 @@ void dynobj_instance_domaint::rhs_concretisation( bool found=false; for(const auto &i : must_alias_relations) { - unsigned long n; + size_t n; found|=!i.second.get_number(*it, n); } if(!found) @@ -303,7 +303,7 @@ void dynobj_instance_domaint::output( out << o.first.get_identifier() << ":\n"; for(const exprt &p : o.second) { - unsigned long n; + size_t n; o.second.get_number(p, n); out << " " << o.second.find_number(n) << ": " << from_expr(ns, "", p) << "\n"; diff --git a/src/ssa/dynobj_instance_analysis.h b/src/ssa/dynobj_instance_analysis.h index 14936c390..2dd170a21 100644 --- a/src/ssa/dynobj_instance_analysis.h +++ b/src/ssa/dynobj_instance_analysis.h @@ -33,40 +33,6 @@ Description: In some cases, multiple instances must be used so that the \*******************************************************************/ class must_alias_setst:public union_find { -protected: - // Two partitionings are equal if they contain same elements partitioned - // in same sets (not necessarily having same numbers). - bool equal(const must_alias_setst &other) - { - if(size()!=other.size()) - return false; - - for(auto &e1 : *this) - { - unsigned long n; - if(other.get_number(e1, n)) - return false; - for(auto &e2 : *this) - if(same_set(e1, e2)!=other.same_set(e1, e2)) - return false; - } - return true; - } - - // Symmetric difference of elements - std::set sym_diff_elements(const must_alias_setst &other) - { - std::set result; - unsigned long n; - for(auto &e : *this) - if(get_number(e, n)) - result.insert(e); - for(auto &e : other) - if(get_number(e, n)) - result.insert(e); - return result; - } - public: bool join(const must_alias_setst &other) { @@ -113,12 +79,12 @@ class must_alias_setst:public union_find // Find all sets to which e_new should be added by comparing with // common elements // The map will contain: set_number(in *this) -> set_representative - std::map dest_sets; + std::map dest_sets; for(auto &e : common_elements) { if(original.same_set(e_new, e) || other.same_set(e_new, e)) { - unsigned long n; + size_t n; get_number(e, n); if(dest_sets.find(n)==dest_sets.end()) dest_sets.emplace(n, e); @@ -137,6 +103,40 @@ class must_alias_setst:public union_find } return false; } + +protected: + // Two partitionings are equal if they contain same elements partitioned + // in same sets (not necessarily having same numbers). + bool equal(const must_alias_setst &other) + { + if(size()!=other.size()) + return false; + + for(auto &e1 : *this) + { + size_t n; + if(other.get_number(e1, n)) + return false; + for(auto &e2 : *this) + if(same_set(e1, e2)!=other.same_set(e1, e2)) + return false; + } + return true; + } + + // Symmetric difference of elements + std::set sym_diff_elements(const must_alias_setst &other) + { + std::set result; + size_t n; + for(auto &e : *this) + if(get_number(e, n)) + result.insert(e); + for(auto &e : other) + if(get_number(e, n)) + result.insert(e); + return result; + } }; class dynobj_instance_domaint:public ai_domain_baset @@ -188,5 +188,4 @@ class dynobj_instance_analysist:public ait friend class dynobj_instance_domaint; }; - #endif // CPROVER_2LS_SSA_DYNOBJ_INSTANCE_ANALYSIS_H diff --git a/src/ssa/malloc_ssa.cpp b/src/ssa/malloc_ssa.cpp index 1f29988a3..b392faa98 100644 --- a/src/ssa/malloc_ssa.cpp +++ b/src/ssa/malloc_ssa.cpp @@ -17,6 +17,8 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include + #include "malloc_ssa.h" /*******************************************************************\ @@ -418,7 +420,7 @@ Function: set_var_always_to_true void set_var_always_to_true( goto_modelt &goto_model, - bool (*name_cond)(std::string &)) + std::functionname_cond) { Forall_goto_functions(f_it, goto_model.goto_functions) { @@ -491,26 +493,3 @@ void allow_record_memleak(goto_modelt &goto_model) name.find("::record_may_leak")!=std::string::npos; }); } - -/*******************************************************************\ - -Function: allow_record_free - - Inputs: - - Outputs: - - Purpose: - -\*******************************************************************/ - -void allow_record_free(goto_modelt &goto_model) -{ - set_var_always_to_true( - goto_model, - [](std::string &name) - { - return name.find("free::")!=std::string::npos && - name.find("::record")!=std::string::npos; - }); -} diff --git a/src/ssa/malloc_ssa.h b/src/ssa/malloc_ssa.h index 17df4bbb5..753dc6e57 100644 --- a/src/ssa/malloc_ssa.h +++ b/src/ssa/malloc_ssa.h @@ -25,6 +25,5 @@ bool replace_malloc( void allow_record_malloc(goto_modelt &goto_model); void allow_record_memleak(goto_modelt &goto_model); -void allow_record_free(goto_modelt &goto_model); #endif diff --git a/src/ssa/ssa_value_set.h b/src/ssa/ssa_value_set.h index a6dc3718c..e2e79c791 100644 --- a/src/ssa/ssa_value_set.h +++ b/src/ssa/ssa_value_set.h @@ -10,7 +10,6 @@ Author: Daniel Kroening, kroening@kroening.com #define CPROVER_2LS_SSA_SSA_VALUE_SET_H #include -#include #include "ssa_object.h" #include "ssa_heap_domain.h" From 215ab5dba6bec080cdec0a2ef30f470943515f26 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 13 Aug 2018 07:45:31 +0200 Subject: [PATCH 235/322] Help formatting. --- src/2ls/2ls_parse_options.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index b9aba9452..a9e8a3f76 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -1773,14 +1773,13 @@ void twols_parse_optionst::help() " --heap use heap domain\n" " --zones use zone domain\n" " --octagons use octagon domain\n" - " --heap-interval use heap domain with interval domain for" - "values\n" - " --heap-zones use heap domain with zones domain for values" - "\n" - " --heap-values-refine use heap domain with a dynamically" - "refinement of the strength of the value domain\n" - " --sympath compute invariant for each symbolic path" - "(only usable with --heap-interval switch)" + " --heap-interval use heap domain with interval domain for\n" + " values\n" + " --heap-zones use heap domain with zones domain for values\n" // NOLINT(*) + " --heap-values-refine use heap domain with a dynamic refinement\n" + " of strength of the value domain\n" + " --sympath compute invariant for each symbolic path\n" + " (only usable with --heap-* switches)\n" " --enum-solver use solver based on model enumeration\n" " --binsearch-solver use solver based on binary search\n" " --arrays do not ignore array contents\n" From e5ee8e742c59b2c97b7eeab2287e6f8f1c75a4de Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Mon, 13 Aug 2018 20:50:53 +0100 Subject: [PATCH 236/322] Update README --- README.md | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5b9e4c352..9a457586c 100644 --- a/README.md +++ b/README.md @@ -33,13 +33,17 @@ The current tool has following capabilities: * function-modular interprocedural analysis of C code based on summaries * summary and invariant inference using generic templates * combined k-induction and invariant inference +* incremental bounded model checking * function-modular termination analysis +* non-termination analysis Releases ======== Download using `git clone http://github.com/diffblue/2ls; cd 2ls; git checkout 2ls-x.y` +* [2LS 0.7](http://github.com/diffblue/2ls/releases/tag/2ls-0.7) (08/2018) +* [2LS 0.6](http://github.com/diffblue/2ls/releases/tag/2ls-0.6) (12/2017) * [2LS 0.5](http://github.com/diffblue/2ls/releases/tag/2ls-0.5) (01/2017) * [2LS 0.4](http://github.com/diffblue/2ls/releases/tag/2ls-0.4) (08/2016) * [2LS 0.3](http://svn.cprover.org/svn/deltacheck/releases/2ls-0.3) (08/2015) @@ -48,13 +52,14 @@ Download using `git clone http://github.com/diffblue/2ls; cd 2ls; git checkout 2 Software Verification Competition Contributions +* [SV-COMP 2018](http://github.com/diffblue/2ls/releases/tag/2ls-0.6) (12/2017) * [SV-COMP 2017](http://github.com/diffblue/2ls/releases/tag/2ls-0.5-sv-comp-2017) (01/2017) * [SV-COMP 2016](http://svn.cprover.org/svn/deltacheck/releases/2ls-0.3-sv-comp-2016) (11/2015) [Follow these instructions](http://www.cprover.org/2LS/2ls-sv-comp-2016.pdf) Installation ============ -`cd 2ls; ./install.h` +`cd 2ls; ./install.sh` Run `src/2ls/2ls` @@ -81,6 +86,15 @@ Currently the following abstract domains are available: * Equalities/disequalities: --equalities * The abstract domain consisting of the Top element: --havoc +Since release 0.6: + +* Heap abstract domain: --heap + +Since release 0.7: + +* Heap abstract domain with intervals or zones: --heap-[intervals|zones] +* Heap abstract domain with intervals or zones and loop paths: --heap-[intervals|zones] --sympath + Interprocedural Termination Analysis ==================================== @@ -90,12 +104,16 @@ Is supported by release 0.1 and >=0.3. * Context-sensitive universal termination: --termination --context-sensitive * Sufficient preconditions for termination --termination --context-sensitive --preconditions +Since release 0.6: + +* Nontermination analysis: --non-termination + Features in development ======================= * ACDL solver (ATVA'17 [Lifting CDCL to Template-Based Abstract Domains for Program Verification](https://doi.org/10.1007/978-3-319-68167-2_2)) -* abstract heap domain -* nontermination analysis +* array domain +* disjunctive domains * custom template specifications * modular refinement * template refinement @@ -104,6 +122,11 @@ Features in development Publications ============ +* FMCAD'18 Template-Based Verification of Heap-Manipulating Programs +* TACAS'18 [2LS: Memory Safety and Non-Termination](https://link.springer.com/chapter/10.1007%2F978-3-319-89963-3_24) +* TOPLAS 40(1) 2018 [Bit-Precise Procedure-Modular Termination Analysis](https://dl.acm.org/citation.cfm?doid=3121136) +* ATVA'17 [Compositional Refutation Techniques](https://link.springer.com/chapter/10.1007%2F978-3-319-68167-2_12) +* ATVA'17 [Lifting CDCL to Template-Based Abstract Domains for Program Verification](https://doi.org/10.1007/978-3-319-68167-2_2) * TACAS'16 [2LS for Program Analysis](http://dl.acm.org/citation.cfm?id=2945506) * SAS'15 [Safety Verification and Refutation by k-Invariants and k-Induction](http://link.springer.com/chapter/10.1007%2F978-3-662-48288-9_9) * ASE'15 [Synthesising Interprocedural Bit-Precise Termination Proofs](http://dl.acm.org/citation.cfm?id=2916211) [Experimental log](http://www.cs.ox.ac.uk/people/peter.schrammel/2ls/ase15-experimental_results_log.txt) [Additional material](http://www.cs.ox.ac.uk/people/peter.schrammel/2ls/ase15-additional-material.tgz) [Website](http://www.cprover.org/termination/modular) @@ -117,6 +140,7 @@ Contributors * Hongyi Chen * Madhukar Kumar * Martin Brain +* Martin Hruska * Peter Schrammel * Rajdeep Mukherjee * Samuel Bücheli From 40c0854f9e74ed771073a2e3594685b16a32d9c0 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Mon, 13 Aug 2018 20:51:30 +0100 Subject: [PATCH 237/322] Version 0.7 --- src/2ls/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/2ls/version.h b/src/2ls/version.h index fb5db29f8..ddd275a7c 100644 --- a/src/2ls/version.h +++ b/src/2ls/version.h @@ -9,6 +9,6 @@ Author: Peter Schrammel #ifndef CPROVER_2LS_2LS_VERSION_H #define CPROVER_2LS_2LS_VERSION_H -#define TWOLS_VERSION "0.6.0" +#define TWOLS_VERSION "0.7.0" #endif From 23c8d6e2220aeb4569a67a2712aaebd2d773cba8 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 7 Sep 2018 14:50:31 +0200 Subject: [PATCH 238/322] Travis CI: fetch master before running the linter. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 6f1e2bc14..73653de41 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,6 +36,7 @@ matrix: compiler: clang env: COMPILER=clang++ - env: NAME="CPP-LINT" + before_script: git fetch origin master:master script: scripts/run_lint.sh master HEAD script: From fdca1645e4c169b667890fe711cf0dc902107a9a Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 31 Aug 2018 09:55:05 +0200 Subject: [PATCH 239/322] Refactor tpolyhedra dmoain to use common function for creating row constraints. Made use of the get_row_constraint function that was present but not used. Now it is called by get_row_{pre|post}_constraints and project_on_vars. --- src/domains/tpolyhedra_domain.cpp | 42 +++++-------------------------- 1 file changed, 6 insertions(+), 36 deletions(-) diff --git a/src/domains/tpolyhedra_domain.cpp b/src/domains/tpolyhedra_domain.cpp index dbbecde6e..36c84bfbb 100644 --- a/src/domains/tpolyhedra_domain.cpp +++ b/src/domains/tpolyhedra_domain.cpp @@ -230,9 +230,6 @@ exprt tpolyhedra_domaint::get_row_constraint( const row_valuet &row_value) { assert(row Date: Fri, 31 Aug 2018 15:33:32 +0200 Subject: [PATCH 240/322] Do not split concrete dynamic objects. Detect if an object is allocated within a loop. In case it is not, do not split it into multiple instances (because it represents a single memory obejct). --- src/2ls/preprocessing_util.cpp | 3 +++ src/ssa/malloc_ssa.cpp | 38 ++++++++++++++++++++++++---------- src/ssa/malloc_ssa.h | 1 + 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/2ls/preprocessing_util.cpp b/src/2ls/preprocessing_util.cpp index f69cc78db..4bd55e6a8 100644 --- a/src/2ls/preprocessing_util.cpp +++ b/src/2ls/preprocessing_util.cpp @@ -795,6 +795,9 @@ void twols_parse_optionst::create_dynobj_instances( if(obj.id()!=ID_symbol) continue; + if(obj.get_bool("#concrete")) + continue; + if(instance_counts.find(to_symbol_expr(obj))==instance_counts.end()) continue; diff --git a/src/ssa/malloc_ssa.cpp b/src/ssa/malloc_ssa.cpp index b392faa98..7984fe768 100644 --- a/src/ssa/malloc_ssa.cpp +++ b/src/ssa/malloc_ssa.cpp @@ -71,7 +71,7 @@ exprt create_dynamic_object( const std::string &suffix, const typet &type, symbol_tablet &symbol_table, - bool concrete) + bool is_concrete) { symbolt value_symbol; @@ -96,7 +96,7 @@ exprt create_dynamic_object( else { address_of_object.op0()=value_symbol.symbol_expr(); - if(concrete) + if(is_concrete) address_of_object.op0().set("#concrete", true); address_of_object.type()=pointer_typet(value_symbol.type); } @@ -169,6 +169,7 @@ exprt malloc_ssa( const side_effect_exprt &code, const std::string &suffix, symbol_tablet &symbol_table, + bool is_concrete, bool alloc_concrete) { if(code.operands().size()!=1) @@ -237,11 +238,11 @@ exprt malloc_ssa( auto pointers=collect_pointer_vars(symbol_table, object_type); exprt object=create_dynamic_object( - suffix, object_type, symbol_table, !alloc_concrete); + suffix, object_type, symbol_table, is_concrete); if(object.type()!=code.type()) object=typecast_exprt(object, code.type()); exprt result; - if(alloc_concrete) + if(!is_concrete && alloc_concrete) { exprt concrete_object=create_dynamic_object( suffix+"$co", object_type, symbol_table, true); @@ -295,6 +296,7 @@ static bool replace_malloc_rec( symbol_tablet &symbol_table, const exprt &malloc_size, unsigned loc_number, + bool is_concrete, bool alloc_concrete) { if(expr.id()==ID_side_effect && @@ -304,8 +306,12 @@ static bool replace_malloc_rec( expr.op0()=malloc_size; expr=malloc_ssa( - to_side_effect_expr(expr), "$"+i2string(loc_number)+suffix, symbol_table, + to_side_effect_expr(expr), + "$"+i2string(loc_number)+suffix, + symbol_table, + is_concrete, alloc_concrete); + return true; } else @@ -313,9 +319,16 @@ static bool replace_malloc_rec( bool result=false; Forall_operands(it, expr) { - if(replace_malloc_rec( - *it, suffix, symbol_table, malloc_size, loc_number, alloc_concrete)) + if(replace_malloc_rec(*it, + suffix, + symbol_table, + malloc_size, + loc_number, + is_concrete, + alloc_concrete)) + { result=true; + } } return result; } @@ -388,10 +401,13 @@ bool replace_malloc( } } } - if(replace_malloc_rec( - code_assign.rhs(), suffix, goto_model.symbol_table, malloc_size, - i_it->location_number, - alloc_concrete && loop_end!=f_it->second.body.instructions.end())) + if(replace_malloc_rec(code_assign.rhs(), + suffix, + goto_model.symbol_table, + malloc_size, + i_it->location_number, + loop_end==f_it->second.body.instructions.end(), + alloc_concrete)) { result=(loop_end!=f_it->second.body.instructions.end()); } diff --git a/src/ssa/malloc_ssa.h b/src/ssa/malloc_ssa.h index 753dc6e57..5f3a9ed15 100644 --- a/src/ssa/malloc_ssa.h +++ b/src/ssa/malloc_ssa.h @@ -16,6 +16,7 @@ exprt malloc_ssa( const side_effect_exprt &, const std::string &suffix, symbol_tablet &, + bool is_concrete, bool alloc_concrete); bool replace_malloc( From c8c92fe88c79a1225f57ace6cb93dc45a8611df7 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 31 Aug 2018 16:11:59 +0200 Subject: [PATCH 241/322] memsatefy: add 2 more regression tests that now pass. --- regression/memsafety/simple_false/test.desc | 2 +- regression/memsafety/simple_true/test.desc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/regression/memsafety/simple_false/test.desc b/regression/memsafety/simple_false/test.desc index fdea46680..0812ec27e 100644 --- a/regression/memsafety/simple_false/test.desc +++ b/regression/memsafety/simple_false/test.desc @@ -1,4 +1,4 @@ -KNOWNBUG +CORE main.c --heap-interval --sympath --inline --pointer-check --k-induction ^EXIT=10$ diff --git a/regression/memsafety/simple_true/test.desc b/regression/memsafety/simple_true/test.desc index 3b416f2a8..02a269a04 100644 --- a/regression/memsafety/simple_true/test.desc +++ b/regression/memsafety/simple_true/test.desc @@ -1,4 +1,4 @@ -KNOWNBUG +CORE main.c --heap-interval --inline --sympath --pointer-check --no-assertions ^EXIT=0$ From 7a9ee8a20a1a5807fa08f8fab2145cc98ba890ab Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 7 Sep 2018 14:09:27 +0200 Subject: [PATCH 242/322] Dynamic object instances: do not include CPROVERsymbols to live variables. These are not variables of the original program so they are not needed to be included, which increases readability. --- src/ssa/dynobj_instance_analysis.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ssa/dynobj_instance_analysis.cpp b/src/ssa/dynobj_instance_analysis.cpp index 32d1454ad..a3ab284fe 100644 --- a/src/ssa/dynobj_instance_analysis.cpp +++ b/src/ssa/dynobj_instance_analysis.cpp @@ -223,7 +223,14 @@ void dynobj_instance_domaint::transform( remove_dereferences(assignment.lhs(), instances); add_aliased_dereferences(assignment.lhs(), instances); - live_pointers[v.symbol_expr()].insert(rhs); + // Do not include CPROVER objects + // TODO: do it better than check for "malloc" substring + if(!(rhs.id()==ID_symbol && + id2string(to_symbol_expr(rhs).get_identifier()).find( + "malloc")!=std::string::npos)) + { + live_pointers[v.symbol_expr()].insert(rhs); + } } } } From 4436b057b77729fa8db51d47f2ed0539d5bc46b6 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 7 Sep 2018 14:10:40 +0200 Subject: [PATCH 243/322] Dynamic objects: get rid of allocation guards in templates. Allocation guards of dynamic objects were a part of template row post guards in order to avoid a non-deterministic to get into the template value. We replace them by inequality saying that the given row expression (loop-back field of a dynamic object) does not equal the same field of the same dynamic object without suffix (representing the value of the field when the object is not allocated). This allows us to get rid of tracking assignments in the ssa_domain analysis. --- src/domains/template_generator_base.cpp | 32 ++++++++--------- src/ssa/assignments.cpp | 38 -------------------- src/ssa/assignments.h | 14 -------- src/ssa/ssa_domain.cpp | 48 ------------------------- 4 files changed, 15 insertions(+), 117 deletions(-) diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index f9a56e7bd..a40b16fe3 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -178,23 +178,6 @@ void template_generator_baset::collect_variables_loop( continue; exprt obj_post_guard=post_guard; - // For dynamic objects allocated within the given loop, we need to add - // guard of their allocation - if(id.find("ssa::dynamic_object$")!=std::string::npos) - { - std::string obj_id=id.substr(0, id.find_first_of(".")); - auto obj_def=SSA.ssa_analysis[n_it->location].def_map.find(obj_id); - if(obj_def!=SSA.ssa_analysis[n_it->location].def_map.end() && - obj_def->second.def.kind==ssa_domaint::deft::ALLOCATION) - { - obj_post_guard=and_exprt( - SSA.guard_symbol(obj_def->second.def.loc), - post_guard); - auto alloc_guard=SSA.allocation_guards.find(obj_id); - if(alloc_guard!=SSA.allocation_guards.end()) - obj_post_guard=and_exprt(obj_post_guard, alloc_guard->second); - } - } if(id.find("__CPROVER_deallocated")!=std::string::npos) { @@ -208,6 +191,21 @@ void template_generator_baset::collect_variables_loop( symbol_exprt pre_var; get_pre_var(SSA, o_it, n_it, pre_var); + + // For fields of dynamic objects, we add a guard that their value is not + // equal to the corresponding input SSA variable that represents a state + // when the object is not allocated. + // Example: dynamic_object$0.next#ls100 != dynamic_object$0.next + if(id.find("ssa::dynamic_object$")!=std::string::npos) + { + exprt &post_var=post_renaming_map[pre_var]; + assert(post_var.id()==ID_symbol); + const irep_idt orig_id=get_original_name(to_symbol_expr(post_var)); + symbol_exprt unallocated(orig_id, post_var.type()); + exprt guard=not_exprt(equal_exprt(post_var, unallocated)); + obj_post_guard=and_exprt(obj_post_guard, guard); + } + exprt init_expr; get_init_expr(SSA, o_it, n_it, init_expr); add_var(pre_var, pre_guard, obj_post_guard, domaint::LOOP, var_specs); diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index 0820333ee..556d0d037 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -33,7 +33,6 @@ void assignmentst::build_assignment_map( { // make sure we have the location in the map assignment_map[it]; - allocation_map[it]; // now fill it if(it->is_assign()) @@ -45,12 +44,6 @@ void assignmentst::build_assignment_map( assign(lhs_symbolic_deref, it, ns); assign_symbolic_rhs(code_assign.rhs(), it, ns); - - // At allocations site, save newly allocated object(s) - if(code_assign.rhs().get_bool("#malloc_result")) - { - allocate(code_assign.rhs(), it, ns); - } } else if(it->is_assert()) { @@ -313,34 +306,3 @@ void assignmentst::output( out << "\n"; } } - -/*******************************************************************\ - -Function: assignmentst::allocate - - Inputs: - - Outputs: - - Purpose: Record allocation - -\*******************************************************************/ -void assignmentst::allocate( - const exprt &expr, - const assignmentst::locationt loc, - const namespacet &ns) -{ - if(expr.id()==ID_symbol && expr.type().get_bool("#dynamic")) - { - allocation_map[loc].insert(ssa_objectt(expr, ns)); - } - else if(expr.id()==ID_if) - { - allocate(to_if_expr(expr).true_case(), loc, ns); - allocate(to_if_expr(expr).false_case(), loc, ns); - } - else if(expr.id()==ID_address_of) - allocate(to_address_of_expr(expr).object(), loc, ns); - else if(expr.id()==ID_typecast) - allocate(to_typecast_expr(expr).op(), loc, ns); -} diff --git a/src/ssa/assignments.h b/src/ssa/assignments.h index 1e4807b33..f316e158f 100644 --- a/src/ssa/assignments.h +++ b/src/ssa/assignments.h @@ -28,8 +28,6 @@ class assignmentst typedef std::map assignment_mapt; assignment_mapt assignment_map; - assignment_mapt allocation_map; - bool assigns(locationt loc, const ssa_objectt &object) const { assignment_mapt::const_iterator it=assignment_map.find(loc); @@ -45,13 +43,6 @@ class assignmentst return it->second; } - inline const objectst &get_allocations(locationt loc) const - { - auto it=allocation_map.find(loc); - assert(it!=allocation_map.end()); - return it->second; - } - assignmentst( const goto_programt &_goto_program, const namespacet &_ns, @@ -87,11 +78,6 @@ class assignmentst const exprt &expr, const locationt &loc, const namespacet &ns); - - void allocate( - const exprt &expr, - const locationt loc, - const namespacet &ns); }; #endif diff --git a/src/ssa/ssa_domain.cpp b/src/ssa/ssa_domain.cpp index 610f85be1..a657fad08 100644 --- a/src/ssa/ssa_domain.cpp +++ b/src/ssa/ssa_domain.cpp @@ -121,17 +121,6 @@ void ssa_domaint::transform( def_entry.def.kind=deft::ASSIGNMENT; def_entry.source=from; } - - auto allocations= - static_cast(ai).assignments.get_allocations(from); - for(auto &alloc : allocations) - { - irep_idt identifier=alloc.get_identifier(); - def_entryt &def_entry=def_map[identifier]; - def_entry.def.loc=from; - def_entry.def.kind=deft::ALLOCATION; - def_entry.source=from; - } } else if(from->is_dead()) { @@ -221,43 +210,6 @@ bool ssa_domaint::merge( } else { - // Do not create PHIs for allocations - if(d_it_a->second.def.kind==deft::ALLOCATION || - d_it_b->second.def.kind==deft::ALLOCATION) - continue; - - // Do not create PHIs for join of PHI and allocation with assignment - auto alloc_def=get_object_allocation_def(id, def_map); - if(alloc_def!=def_map.end()) - { - if(d_it_b->second.def.kind!=deft::ASSIGNMENT && - to->location_number>alloc_def->second.def.loc->location_number && - to->location_number>d_it_a->second.def.loc->location_number && - to->location_number>d_it_b->second.def.loc->location_number) - { - def_map[id]=d_it_a->second; - def_map[id2string(id).substr(0, id2string(id).find_first_of("."))]= - alloc_def->second; - result=true; - continue; - } - } - alloc_def=get_object_allocation_def(id, b.def_map); - if(alloc_def!=b.def_map.end()) - { - if(d_it_a->second.def.kind!=deft::ASSIGNMENT && - to->location_number>alloc_def->second.def.loc->location_number && - to->location_number>d_it_b->second.def.loc->location_number && - to->location_number>d_it_a->second.def.loc->location_number) - { - def_map[id]=d_it_b->second; - def_map[id2string(id).substr(0, id2string(id).find_first_of("."))]= - alloc_def->second; - result=true; - continue; - } - } - // Arg! Data coming from two sources from two different definitions! // We produce a new phi node. loc_def_mapt &phi_node=phi_nodes[id]; From 7fb5b483820d3034c33328528e6ee02dc9c64a71 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 14 Sep 2018 07:42:07 +0200 Subject: [PATCH 244/322] Regression: add 2 tests to heap running the false tests without k-induction The expected result is UNKNOWN. The tests are intended to check for soundness of the approach without k-induction (they must not end with OK). Tests reveal bug in the replacement of the allocation guards in heap template. --- regression/heap/list_false/test.desc | 8 ++-- regression/heap/list_false_kind/main.c | 53 +++++++++++++++++++++ regression/heap/list_false_kind/test.desc | 7 +++ regression/heap/simple_false/test.desc | 8 ++-- regression/heap/simple_false_kind/main.c | 45 +++++++++++++++++ regression/heap/simple_false_kind/test.desc | 7 +++ 6 files changed, 120 insertions(+), 8 deletions(-) create mode 100644 regression/heap/list_false_kind/main.c create mode 100644 regression/heap/list_false_kind/test.desc create mode 100644 regression/heap/simple_false_kind/main.c create mode 100644 regression/heap/simple_false_kind/test.desc diff --git a/regression/heap/list_false/test.desc b/regression/heap/list_false/test.desc index 93984c1aa..450b08c19 100644 --- a/regression/heap/list_false/test.desc +++ b/regression/heap/list_false/test.desc @@ -1,7 +1,7 @@ CORE main.c ---heap-interval --sympath --inline --no-propagation --k-induction -^EXIT=10$ +--heap-interval --sympath --inline --no-propagation +^EXIT=5$ ^SIGNAL=0$ -^VERIFICATION FAILED$ -^\[main.assertion.1\] : FAILURE +^VERIFICATION INCONCLUSIVE$ +^\[main.assertion.1\] : UNKNOWN diff --git a/regression/heap/list_false_kind/main.c b/regression/heap/list_false_kind/main.c new file mode 100644 index 000000000..386921ee1 --- /dev/null +++ b/regression/heap/list_false_kind/main.c @@ -0,0 +1,53 @@ +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +extern int __VERIFIER_nondet_int(); +/* + * Simple example: build a list with only 1s, then 2s and finally + * on 3 (arbitrary length); afterwards, go through it and check + * if the the list does have the correct form, and in particular + * finishes by a 3. + */ +#include + +void exit(int s) { + _EXIT: goto _EXIT; +} + +typedef struct node { + int h; + struct node *n; +} *List; + +int main() { + /* Build a list of the form 1->...->1->2->....->2->3 */ + List a = (List) malloc(sizeof(struct node)); + if (a == 0) exit(1); + List t; + List p = a; + while (__VERIFIER_nondet_int()) { + p->h = 1; + t = (List) malloc(sizeof(struct node)); + if (t == 0) exit(1); + p->n = t; + p = p->n; + } + while (__VERIFIER_nondet_int()) { + p->h = 2; + t = (List) malloc(sizeof(struct node)); + if (t == 0) exit(1); + p->n = t; + p = p->n; + } + p->h = 3; + + /* Check it */ + p = a; + while (p->h == 2) + p = p->n; + while (p->h == 1) + p = p->n; + if(p->h != 3) + ERROR: __VERIFIER_error(); + + return 0; +} diff --git a/regression/heap/list_false_kind/test.desc b/regression/heap/list_false_kind/test.desc new file mode 100644 index 000000000..93984c1aa --- /dev/null +++ b/regression/heap/list_false_kind/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--heap-interval --sympath --inline --no-propagation --k-induction +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +^\[main.assertion.1\] : FAILURE diff --git a/regression/heap/simple_false/test.desc b/regression/heap/simple_false/test.desc index 93984c1aa..450b08c19 100644 --- a/regression/heap/simple_false/test.desc +++ b/regression/heap/simple_false/test.desc @@ -1,7 +1,7 @@ CORE main.c ---heap-interval --sympath --inline --no-propagation --k-induction -^EXIT=10$ +--heap-interval --sympath --inline --no-propagation +^EXIT=5$ ^SIGNAL=0$ -^VERIFICATION FAILED$ -^\[main.assertion.1\] : FAILURE +^VERIFICATION INCONCLUSIVE$ +^\[main.assertion.1\] : UNKNOWN diff --git a/regression/heap/simple_false_kind/main.c b/regression/heap/simple_false_kind/main.c new file mode 100644 index 000000000..e3d4f0af8 --- /dev/null +++ b/regression/heap/simple_false_kind/main.c @@ -0,0 +1,45 @@ +extern void __VERIFIER_error() __attribute__ ((__noreturn__)); + +extern int __VERIFIER_nondet_int(); +/* + * Simple example: build a list with only 1s and finally a 0 (arbitrary length); + * afterwards, go through it and check if the list does have the correct form, and in particular + * finishes by a 0. + */ +#include + +void exit(int s) { + _EXIT: goto _EXIT; +} + +typedef struct node { + int h; + struct node *n; +} *List; + +int main() { + /* Build a list of the form 1->...->1->0 */ + List a = (List) malloc(sizeof(struct node)); + if (a == 0) exit(1); + List t; + List p = a; + a->h = 2; + while (__VERIFIER_nondet_int()) { + p->h = 1; + t = (List) malloc(sizeof(struct node)); + if (t == 0) exit(1); + p->n = t; + p = p->n; + } + p->h = 2; + p->n = 0; + p = a; + while (p!=0) { + if (p->h != 2) { + ERROR: __VERIFIER_error(); + } + p = p->n; + } + return 0; +} + diff --git a/regression/heap/simple_false_kind/test.desc b/regression/heap/simple_false_kind/test.desc new file mode 100644 index 000000000..93984c1aa --- /dev/null +++ b/regression/heap/simple_false_kind/test.desc @@ -0,0 +1,7 @@ +CORE +main.c +--heap-interval --sympath --inline --no-propagation --k-induction +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +^\[main.assertion.1\] : FAILURE From 515347a194ce6e645d3e7c305708fc427e8c62d2 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 14 Sep 2018 20:28:38 +0200 Subject: [PATCH 245/322] Create fresh symbols for dynamically allocated objects and their fields. For each object allocated at some location, create a fresh symbol (i.e. a declaration) for it or for all of its fields in case of a structured object. These fresh symbols can be used on rhs only if the object was allocated at the given run - for each RHS usage, add case split. If the allocation guard holds, use the fresh symbol, otherwise use the last definition of the object before the allocation. --- src/ssa/assignments.cpp | 70 +++++++++++++++++++++++++++++++++++++++++ src/ssa/assignments.h | 9 ++++++ src/ssa/local_ssa.cpp | 20 ++++++++++-- src/ssa/ssa_domain.cpp | 13 ++++++-- src/ssa/ssa_domain.h | 1 + 5 files changed, 108 insertions(+), 5 deletions(-) diff --git a/src/ssa/assignments.cpp b/src/ssa/assignments.cpp index 556d0d037..13586685d 100644 --- a/src/ssa/assignments.cpp +++ b/src/ssa/assignments.cpp @@ -44,6 +44,13 @@ void assignmentst::build_assignment_map( assign(lhs_symbolic_deref, it, ns); assign_symbolic_rhs(code_assign.rhs(), it, ns); + + if(code_assign.rhs().get_bool("#malloc_result")) + { + // Create empty assignment into the object (declaration) so that it + // gets non-deterministic value + create_alloc_decl(code_assign.rhs(), true_exprt(), it, ns); + } } else if(it->is_assert()) { @@ -306,3 +313,66 @@ void assignmentst::output( out << "\n"; } } + +/*******************************************************************\ + +Function: assignmentst::create_alloc_decl + + Inputs: + + Outputs: + + Purpose: Create new fresh symbol for each object (and for each its field) + dynamically allocated at the given location. + +\*******************************************************************/ +void assignmentst::create_alloc_decl( + const exprt &expr, + const exprt &guard, + const locationt loc, + const namespacet &ns) +{ + if(expr.id()==ID_symbol || expr.id()==ID_member) + { + const typet &type=ns.follow(expr.type()); + if(type.id()==ID_struct) + { + for(auto &c : to_struct_type(type).components()) + { + create_alloc_decl( + member_exprt(expr, c.get_name(), c.type()), guard, loc, ns); + } + } + else + { + ssa_objectt ssa_object(expr, ns); + if(ssa_object) + { + // Create declaration + assign(ssa_object, loc, ns); + // Store allocation guard + alloc_guards_map.emplace(std::make_pair(loc, ssa_object), guard); + } + } + } + else if(expr.id()==ID_if) + { + const if_exprt &if_expr=to_if_expr(expr); + create_alloc_decl( + if_expr.true_case(), + and_exprt(guard, if_expr.cond()), + loc, + ns); + create_alloc_decl( + if_expr.false_case(), + and_exprt(guard, not_exprt(if_expr.cond())), + loc, + ns); + } + else if(expr.id()==ID_address_of) + create_alloc_decl( + to_address_of_expr(expr).object(), guard, loc, ns); + else if(expr.id()==ID_typecast) + create_alloc_decl( + to_typecast_expr(expr).op(), guard, loc, ns); +} diff --git a/src/ssa/assignments.h b/src/ssa/assignments.h index f316e158f..e0184fbc6 100644 --- a/src/ssa/assignments.h +++ b/src/ssa/assignments.h @@ -28,6 +28,9 @@ class assignmentst typedef std::map assignment_mapt; assignment_mapt assignment_map; + typedef std::map, exprt> alloc_guards_mapt; + alloc_guards_mapt alloc_guards_map; + bool assigns(locationt loc, const ssa_objectt &object) const { assignment_mapt::const_iterator it=assignment_map.find(loc); @@ -78,6 +81,12 @@ class assignmentst const exprt &expr, const locationt &loc, const namespacet &ns); + + void create_alloc_decl( + const exprt &expr, + const exprt &guard, + const locationt loc, + const namespacet &ns); }; #endif diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 6ca775df8..0b8a478f0 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -162,7 +162,8 @@ void local_SSAt::get_globals( if(rhs_value) { - const exprt &expr=read_rhs(it->get_expr(), loc); + ssa_objectt object(it->get_expr(), ns); + const exprt &expr=read_rhs(object, loc); globals.insert(to_symbol_expr(expr)); } else @@ -1152,7 +1153,22 @@ exprt local_SSAt::read_rhs_rec(const exprt &expr, locationt loc) const if(ssa_objects.objects.find(object)!= ssa_objects.objects.end()) { - return read_rhs(object, loc); + // If the last definition of an object is at its allocation, we can only use + // the corresponding symbol if the object has truly been allocated + // (allocation guard holds). Otherwise we need to use the last definition + // before the allocation. + auto def_it=ssa_analysis[loc].def_map.find(object.get_identifier()); + if(def_it!=ssa_analysis[loc].def_map.end() && + def_it->second.def.kind==ssa_domaint::deft::ALLOCATION) + { + locationt alloc_loc=def_it->second.def.loc; + return if_exprt( + read_rhs(def_it->second.def.guard, alloc_loc), + read_rhs(object, loc), + read_rhs(object, alloc_loc)); + } + else + return read_rhs(object, loc); } else { diff --git a/src/ssa/ssa_domain.cpp b/src/ssa/ssa_domain.cpp index a657fad08..c70dec9a7 100644 --- a/src/ssa/ssa_domain.cpp +++ b/src/ssa/ssa_domain.cpp @@ -80,8 +80,8 @@ void ssa_domaint::transform( { if(from->is_assign() || from->is_decl() || from->is_function_call()) { - const std::set &assigns= - static_cast(ai).assignments.get(from); + const auto &assignments=static_cast(ai).assignments; + const std::set &assigns=assignments.get(from); for(std::set::const_iterator o_it=assigns.begin(); @@ -118,8 +118,15 @@ void ssa_domaint::transform( def_entryt &def_entry=def_map[identifier]; def_entry.def.loc=from; - def_entry.def.kind=deft::ASSIGNMENT; def_entry.source=from; + auto guard_it=assignments.alloc_guards_map.find({from, *o_it}); + if(guard_it!=assignments.alloc_guards_map.end()) + { + def_entry.def.kind=deft::ALLOCATION; + def_entry.def.guard=guard_it->second; + } + else + def_entry.def.kind=deft::ASSIGNMENT; } } else if(from->is_dead()) diff --git a/src/ssa/ssa_domain.h b/src/ssa/ssa_domain.h index c6767973b..91212247b 100644 --- a/src/ssa/ssa_domain.h +++ b/src/ssa/ssa_domain.h @@ -23,6 +23,7 @@ class ssa_domaint:public ai_domain_baset typedef enum { INPUT, ASSIGNMENT, PHI, ALLOCATION } kindt; kindt kind; locationt loc; + exprt guard=nil_exprt(); inline bool is_input() const { return kind==INPUT; } inline bool is_assignment() const { return kind==ASSIGNMENT; } From 2f72b879a9ffc1a301c53b438aef5e9914674cb4 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 14 Sep 2018 20:33:20 +0200 Subject: [PATCH 246/322] Add message handler to tpolyhedra solver to enable debugging outputs. --- src/domains/strategy_solver_heap_tpolyhedra.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/domains/strategy_solver_heap_tpolyhedra.h b/src/domains/strategy_solver_heap_tpolyhedra.h index 967f53aa8..edf7ce17c 100644 --- a/src/domains/strategy_solver_heap_tpolyhedra.h +++ b/src/domains/strategy_solver_heap_tpolyhedra.h @@ -37,6 +37,7 @@ class strategy_solver_heap_tpolyhedrat:public strategy_solver_baset template_generator), tpolyhedra_solver(heap_tpolyhedra_domain.polyhedra_domain, _solver, SSA.ns) { + tpolyhedra_solver.set_message_handler(message_handler); } virtual bool iterate(invariantt &_inv) override; From d88aef129d53d617a17078feafc1c4c37cc73f4b Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 14 Sep 2018 20:33:49 +0200 Subject: [PATCH 247/322] tpolyhedra: prevent using pre-value to update itself in symbolic value system. This causes a problem for dynamically allocated object, since the value of some x#lbN being constraint from one side (in intervals) can be used to compute the other side of the interval. This may happen if the updated row is the last not yet updated. In such situation, in the symbolic value system, there will be no g#lsX => FALSE (since the last FALSE is replaced by a symbolic value), hence x#lbN can be defined (by setting g#lsX to true) and since it is yet constraint from one side only, it may cause the other side of the interval to be set to a non-deterministic value. --- src/domains/tpolyhedra_domain.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/domains/tpolyhedra_domain.cpp b/src/domains/tpolyhedra_domain.cpp index 36c84bfbb..b61abca91 100644 --- a/src/domains/tpolyhedra_domain.cpp +++ b/src/domains/tpolyhedra_domain.cpp @@ -485,6 +485,8 @@ exprt tpolyhedra_domaint::get_row_symb_post_constraint(const rowt &row) templ_row.post_guard, binary_relation_exprt(templ_row.expr, ID_ge, get_row_symb_value(row))); rename(c); + c=and_exprt( + c, not_exprt(equal_exprt(get_row_symb_value(row), templ_row.expr))); return and_exprt(templ_row.aux_expr, c); } From bdf6b9178d7b1c3ca4c3521ab66cccec7933de60 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sat, 29 Sep 2018 11:44:15 +0100 Subject: [PATCH 248/322] Fix missing parentheses in test --- regression/heap-data/hash_fun/main.c | 2 +- regression/heap-data/process_queue/main.c | 2 +- regression/heap-data/quick_sort_split/main.c | 4 ++-- regression/heap-data/shared_mem1/main.c | 2 +- regression/heap-data/shared_mem2/main.c | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/regression/heap-data/hash_fun/main.c b/regression/heap-data/hash_fun/main.c index 08fd2104a..85448ca32 100644 --- a/regression/heap-data/hash_fun/main.c +++ b/regression/heap-data/hash_fun/main.c @@ -26,7 +26,7 @@ int main() { while (__VERIFIER_nondet_int()) { if (base >= 0 && base <= 1000000) { - base = base; + base = base + 0; int hash = hash_fun(); if (hash > base && hash < base + INTERVAL_SIZE) diff --git a/regression/heap-data/process_queue/main.c b/regression/heap-data/process_queue/main.c index 1299105de..8108ecfac 100644 --- a/regression/heap-data/process_queue/main.c +++ b/regression/heap-data/process_queue/main.c @@ -41,7 +41,7 @@ struct process_node *choose_next(struct process_node **q) { void check_queue(struct process_node *q) { for (struct process_node *n = q; n != NULL; n = n->next) - if (!n->time_to_wait >= 1) + if (!(n->time_to_wait >= 1)) __VERIFIER_error(); } diff --git a/regression/heap-data/quick_sort_split/main.c b/regression/heap-data/quick_sort_split/main.c index c286aa4e8..8b9ec9efb 100644 --- a/regression/heap-data/quick_sort_split/main.c +++ b/regression/heap-data/quick_sort_split/main.c @@ -50,12 +50,12 @@ int main() { // Check that low and high contain expected elements while (low) { - if (!low->expected_list == LOW) + if (!(low->expected_list == LOW)) __VERIFIER_error(); low = low->next; } while (high) { - if (!high->expected_list == HIGH) + if (!(high->expected_list == HIGH)) __VERIFIER_error(); high = high->next; } diff --git a/regression/heap-data/shared_mem1/main.c b/regression/heap-data/shared_mem1/main.c index d80939e92..2c0b16503 100644 --- a/regression/heap-data/shared_mem1/main.c +++ b/regression/heap-data/shared_mem1/main.c @@ -25,7 +25,7 @@ int main() { struct list_node *list = head; while (__VERIFIER_nondet_int()) { - int x; + int x = __VERIFIER_nondet_int(); if (x > 0 && x < 10) { struct list_node *n = malloc(sizeof(*n)); n->x = x; diff --git a/regression/heap-data/shared_mem2/main.c b/regression/heap-data/shared_mem2/main.c index dd4f6466d..40032f9b3 100644 --- a/regression/heap-data/shared_mem2/main.c +++ b/regression/heap-data/shared_mem2/main.c @@ -24,7 +24,7 @@ int main() { struct list_node *list = head; while (__VERIFIER_nondet_int()) { - int x; + int x = __VERIFIER_nondet_int(); if (x > 0 && x < 10) { struct list_node *n = malloc(sizeof(*n)); n->x = x; @@ -40,6 +40,6 @@ int main() { list->mem->val += list->x; list = list->next; } - if (!m->val == 100) + if (!(m->val == 100)) __VERIFIER_nondet_int(); } From 5dd95a91fc8b8636a11f517da507b36635a5948c Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sun, 30 Sep 2018 11:43:52 +0100 Subject: [PATCH 249/322] Test to expose regression on argument symbols Arguments used to be replaced by symbols in order to allow contexts to be computed more easily. --- regression/interprocedural/contextsensitive2/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/regression/interprocedural/contextsensitive2/main.c b/regression/interprocedural/contextsensitive2/main.c index 70fd27c8b..4a2ef0219 100644 --- a/regression/interprocedural/contextsensitive2/main.c +++ b/regression/interprocedural/contextsensitive2/main.c @@ -20,7 +20,6 @@ void main() int x = 1; int y = do1(x); assert(y==1); - x = -x; - int z = do2(x); + int z = do2(-x); assert(-1<=z && z<=1); } From df02991c2f2f5b4ecf26a3353613528f4e0f0753 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sun, 30 Sep 2018 11:50:59 +0100 Subject: [PATCH 250/322] Replace all args by symbols Amendment to aaaa132 which did it for constants --- src/ssa/local_ssa.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index 6ca775df8..e0d106440 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -578,16 +578,12 @@ void local_SSAt::build_function_call(locationt loc) unsigned i=0; for(exprt &a : f.arguments()) { - if(a.is_constant() || - (a.id()==ID_typecast && to_typecast_expr(a).op().is_constant())) - { - const std::string arg_name= - id2string(fname)+"#arg"+i2string(i)+"#"+ - i2string(loc->location_number); - symbol_exprt arg(arg_name, a.type()); - n_it->equalities.push_back(equal_exprt(a, arg)); - a=arg; - } + const std::string arg_name= + id2string(fname)+"#arg"+i2string(i)+"#"+ + i2string(loc->location_number); + symbol_exprt arg(arg_name, a.type()); + n_it->equalities.push_back(equal_exprt(a, arg)); + a=arg; ++i; } From 16496ff506ecc881f275aeab60539a1d21ce7cd3 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Thu, 4 Oct 2018 10:24:06 +0200 Subject: [PATCH 251/322] Dynobj instance analysis: improve detecting malloc-specific variables. These are variables containing "malloc::", "malloc#", or "malloc$". They are not inserted into the set of live variables to keep it more readable. --- src/ssa/dynobj_instance_analysis.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ssa/dynobj_instance_analysis.cpp b/src/ssa/dynobj_instance_analysis.cpp index a3ab284fe..78a1682aa 100644 --- a/src/ssa/dynobj_instance_analysis.cpp +++ b/src/ssa/dynobj_instance_analysis.cpp @@ -226,8 +226,12 @@ void dynobj_instance_domaint::transform( // Do not include CPROVER objects // TODO: do it better than check for "malloc" substring if(!(rhs.id()==ID_symbol && - id2string(to_symbol_expr(rhs).get_identifier()).find( - "malloc")!=std::string::npos)) + (id2string(to_symbol_expr(rhs).get_identifier()).find( + "malloc::")!=std::string::npos || + id2string(to_symbol_expr(rhs).get_identifier()).find( + "malloc#")!=std::string::npos || + id2string(to_symbol_expr(rhs).get_identifier()).find( + "malloc$")!=std::string::npos))) { live_pointers[v.symbol_expr()].insert(rhs); } From 10412b35a3c40d2684137396c8f48917a93e1893 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 5 Oct 2018 08:44:10 +0200 Subject: [PATCH 252/322] Symderef: do not reuse symbolic deref if some aliased object was assigned. Check all objects potentially pointed by the dereferenced pointer and if one of them is assigned after the last definition of the symbolic dereference, we need to redefine it. --- src/ssa/local_ssa.cpp | 97 +++++++++++++++++++++++++++++++++++-------- src/ssa/local_ssa.h | 5 +++ 2 files changed, 85 insertions(+), 17 deletions(-) diff --git a/src/ssa/local_ssa.cpp b/src/ssa/local_ssa.cpp index d6126a4e5..ca9a27db8 100644 --- a/src/ssa/local_ssa.cpp +++ b/src/ssa/local_ssa.cpp @@ -2097,27 +2097,14 @@ exprt local_SSAt::concretise_symbolic_deref_rhs( if(deref_rhs.get_bool("#heap_access") && rhs_object) { - const exprt pointer=get_pointer( - rhs_object.get_root_object(), - pointed_level(rhs_object.get_root_object())-1); - const auto pointer_id=ssa_objectt(pointer, ns).get_identifier(); - const auto pointer_def=ssa_analysis[loc].def_map.find( - pointer_id)->second.def; - const auto symbolic_id=ssa_objectt(symbolic_deref_rhs, ns).get_identifier(); - const auto symbolic_def=ssa_analysis[loc].def_map.find( - symbolic_id)->second.def; - - if(!symbolic_def.is_assignment() - || (pointer_def.is_assignment() - && pointer_def.loc->location_number> - symbolic_def.loc->location_number)) + if(can_reuse_symderef(rhs_object, ns, loc)) { - assign_rec(symbolic_deref_rhs, deref_rhs, true_exprt(), loc); - return name(ssa_objectt(symbolic_deref_rhs, ns), OUT, loc); + return symbolic_deref_rhs; } else { - return symbolic_deref_rhs; + assign_rec(symbolic_deref_rhs, deref_rhs, true_exprt(), loc); + return name(ssa_objectt(symbolic_deref_rhs, ns), OUT, loc); } } else @@ -2225,3 +2212,79 @@ void local_SSAt::get_alloc_guard_rec(const exprt &expr, exprt guard) else if(expr.id()==ID_address_of) get_alloc_guard_rec(to_address_of_expr(expr).object(), guard); } + +/********************************************************************\ + +Function: local_SSAt::can_reuse_symderef + + Inputs: Symbolic deference object, namespace, current location. + + Outputs: True if the symbolic dereference can be reused from the last location + that it was defined in (i.e. it does not have to be redefinef). + Otherwise false. + + Purpose: The symbolic dereference object can be reused if and only if + the pointer it dereferences was not overwritten and any potentially + aliased object (or field) was not overwritten. + +\*******************************************************************/ +bool local_SSAt::can_reuse_symderef( + ssa_objectt &symderef, + const namespacet &ns, + const local_SSAt::locationt loc) +{ + // Get a pointer that is dereferenced in the symbolic deref + const exprt pointer=get_pointer( + symderef.get_root_object(), + pointed_level(symderef.get_root_object())-1); + // Get the last definition of the pointer + const auto pointer_id=ssa_objectt(pointer, ns).get_identifier(); + const auto pointer_def=ssa_analysis[loc].def_map.find( + pointer_id)->second.def; + // Get the last definition of the symbolic dereference + const auto symbolic_id=symderef.get_identifier(); + const auto symbolic_def=ssa_analysis[loc].def_map.find( + symbolic_id)->second.def; + + // If symbolic deref was not created yet, it cannot be reused. + if(!symbolic_def.is_assignment()) + return false; + + // If the pointer that is dereferenced was overwritten, the symbolic deref + // is not valid. + if(pointer_def.is_assignment() && pointer_def.loc->location_number> + symbolic_def.loc->location_number) + return false; + + // Search all aliasing objects (objects potentially pointed by the pointer) + const auto &values=ssa_value_ai[loc](pointer, ns); + for(auto &obj : values.value_set) + { + irep_idt deref_id; + if(symderef.get_expr().id()==ID_member) + { + auto member=member_exprt( + obj.symbol_expr(), + to_member_expr(symderef.get_expr()).get_component_name(), + symderef.type()); + deref_id=ssa_objectt(member, ns).get_identifier(); + } + else + { + deref_id=obj.get_identifier(); + } + // If some potentially aliased object (or field) was overwritten, + // the symbolic dereference cannot be reused. + auto deref_def=ssa_analysis[loc].def_map.find(deref_id); + if(deref_def!=ssa_analysis[loc].def_map.end() && + (deref_def->second.def.is_assignment() || + deref_def->second.def.is_phi()) && + deref_def->second.def.loc->location_number> + symbolic_def.loc->location_number) + { + return false; + } + } + + return true; +} diff --git a/src/ssa/local_ssa.h b/src/ssa/local_ssa.h index 0dbc6bdc0..56a3dcc4c 100644 --- a/src/ssa/local_ssa.h +++ b/src/ssa/local_ssa.h @@ -229,6 +229,11 @@ class local_SSAt const namespacet &ns, const locationt loc); + bool can_reuse_symderef( + ssa_objectt &symderef, + const namespacet &ns, + const locationt loc); + const ssa_heap_analysist &heap_analysis; ssa_objectst ssa_objects; From ee865a2567300c1b263e491b212c0674045cd02c Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 13 Nov 2018 12:06:20 +0100 Subject: [PATCH 253/322] Fix detection of dynamic memory usage in loops. --- src/ssa/malloc_ssa.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ssa/malloc_ssa.cpp b/src/ssa/malloc_ssa.cpp index 7984fe768..5bc2e0f48 100644 --- a/src/ssa/malloc_ssa.cpp +++ b/src/ssa/malloc_ssa.cpp @@ -409,7 +409,7 @@ bool replace_malloc( loop_end==f_it->second.body.instructions.end(), alloc_concrete)) { - result=(loop_end!=f_it->second.body.instructions.end()); + result=result || (loop_end!=f_it->second.body.instructions.end()); } } } From 1d756359b541645693e95191389779a168c34591 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Fri, 16 Nov 2018 14:03:54 +0100 Subject: [PATCH 254/322] heap-zones: do not add difference rows for objects allocated by the same malloc We cannot add a difference template row for two fields of two dynamic objects allocated at the same allocation site. This is because the combined guard would never hold since only one of these objects is always allocated. --- src/domains/tpolyhedra_domain.cpp | 16 ++++++++++++++++ src/domains/util.cpp | 25 +++++++++++++++++++++++++ src/domains/util.h | 2 ++ 3 files changed, 43 insertions(+) diff --git a/src/domains/tpolyhedra_domain.cpp b/src/domains/tpolyhedra_domain.cpp index b61abca91..b8861e102 100644 --- a/src/domains/tpolyhedra_domain.cpp +++ b/src/domains/tpolyhedra_domain.cpp @@ -1026,10 +1026,26 @@ void tpolyhedra_domaint::add_difference_template( { if(v1->var.type().id()==ID_pointer) continue; + if(v1->var.id()==ID_and) + continue; var_specst::const_iterator v2=v1; ++v2; for(; v2!=var_specs.end(); ++v2) { + if (v2->var.id()==ID_and) + continue; + + // Check if both vars are dynamic objects allocated by the same malloc. + // In such case, do not add the template row, since only one of those is + // always allocated and the combined guard would never hold. + if(v1->var.id()==ID_symbol && v2->var.id()==ID_symbol) + { + int v1_index=get_dynobj_line(to_symbol_expr(v1->var).get_identifier()); + int v2_index=get_dynobj_line(to_symbol_expr(v2->var).get_identifier()); + if(v1_index>=0 && v2_index>=0 && v1_index==v2_index) + continue; + } + kindt k=domaint::merge_kinds(v1->kind, v2->kind); if(k==IN) continue; diff --git a/src/domains/util.cpp b/src/domains/util.cpp index 826495123..ade7c3231 100644 --- a/src/domains/util.cpp +++ b/src/domains/util.cpp @@ -710,3 +710,28 @@ bool is_cprover_symbol(const exprt &expr) id2string(to_symbol_expr(expr).get_identifier()), CPROVER_PREFIX); } + +/*******************************************************************\ + +Function: get_dynobj_line + + Inputs: Symbol identifier. + + Outputs: If the symbol is a dynamic object, then the location number of the + malloc call where the object was allocated, otherwise -1. + + Purpose: + +\*******************************************************************/ +int get_dynobj_line(const irep_idt &id) +{ + std::string name=id2string(id); + size_t pos=name.find("dynamic_object$"); + if(pos==std::string::npos) + return -1; + + size_t start=pos+15; + size_t end=name.find_first_not_of("0123456789", pos); + std::string number=name.substr(start, end-start); + return std::stoi(number); +} diff --git a/src/domains/util.h b/src/domains/util.h index d21601a18..251b18b89 100644 --- a/src/domains/util.h +++ b/src/domains/util.h @@ -38,4 +38,6 @@ void clean_expr(exprt &expr); bool is_cprover_symbol(const exprt &expr); +int get_dynobj_line(const irep_idt &id); + #endif From 9c34d2b2bea56376ccd0775fa865ef3e1d6308e3 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Mon, 19 Nov 2018 09:30:07 +0100 Subject: [PATCH 255/322] heap-zones: allow adding difference rows for different fields of dynobj Only difference of the same field of different instances of the same abstract dynamic object are now forbidden. --- src/domains/tpolyhedra_domain.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/domains/tpolyhedra_domain.cpp b/src/domains/tpolyhedra_domain.cpp index b8861e102..c7b12c810 100644 --- a/src/domains/tpolyhedra_domain.cpp +++ b/src/domains/tpolyhedra_domain.cpp @@ -1032,7 +1032,7 @@ void tpolyhedra_domaint::add_difference_template( ++v2; for(; v2!=var_specs.end(); ++v2) { - if (v2->var.id()==ID_and) + if(v2->var.id()==ID_and) continue; // Check if both vars are dynamic objects allocated by the same malloc. @@ -1043,7 +1043,23 @@ void tpolyhedra_domaint::add_difference_template( int v1_index=get_dynobj_line(to_symbol_expr(v1->var).get_identifier()); int v2_index=get_dynobj_line(to_symbol_expr(v2->var).get_identifier()); if(v1_index>=0 && v2_index>=0 && v1_index==v2_index) - continue; + { + const std::string v1_id=id2string( + to_symbol_expr(v1->var).get_identifier()); + const std::string v2_id=id2string( + to_symbol_expr(v2->var).get_identifier()); + // If the vars are fields of dynamic objects, do not add them if the + // fields are the same. + if(v1_id.find(".")!=std::string::npos && + v2_id.find(".")!=std::string::npos) + { + if(v1_id.substr(v1_id.find_first_of("."))== + v2_id.substr(v2_id.find_first_of("."))) + continue; + } + else + continue; + } } kindt k=domaint::merge_kinds(v1->kind, v2->kind); From 0af64ba076711836f0371af51e2db8d99dbb15e3 Mon Sep 17 00:00:00 2001 From: Peter Schrammel Date: Sun, 25 Nov 2018 22:18:11 +0530 Subject: [PATCH 256/322] Update to version 0.7.1 --- install.sh | 2 +- src/2ls/version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index 299186752..ecff84bae 100755 --- a/install.sh +++ b/install.sh @@ -1,7 +1,7 @@ #!/bin/bash CBMC_REPO=https://github.com/peterschrammel/cbmc -CBMC_VERSION=2ls-prerequisites-0.6 +CBMC_VERSION=2ls-prerequisites-0.7 if [ "$1" != "" ] then diff --git a/src/2ls/version.h b/src/2ls/version.h index ddd275a7c..5817d05a1 100644 --- a/src/2ls/version.h +++ b/src/2ls/version.h @@ -9,6 +9,6 @@ Author: Peter Schrammel #ifndef CPROVER_2LS_2LS_VERSION_H #define CPROVER_2LS_2LS_VERSION_H -#define TWOLS_VERSION "0.7.0" +#define TWOLS_VERSION "0.7.1" #endif From 85b17e55bc58981965f538f4cd5e1e25bcaa6cf3 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Wed, 20 Feb 2019 09:52:18 +0530 Subject: [PATCH 257/322] Added new files & class definition for disjunctive domain --- src/domains/disjunctive_domain.cpp | 24 ++++++++++++++++ src/domains/disjunctive_domain.h | 46 ++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 src/domains/disjunctive_domain.cpp create mode 100644 src/domains/disjunctive_domain.h diff --git a/src/domains/disjunctive_domain.cpp b/src/domains/disjunctive_domain.cpp new file mode 100644 index 000000000..c0e9257ce --- /dev/null +++ b/src/domains/disjunctive_domain.cpp @@ -0,0 +1,24 @@ +/*******************************************************************\ + +Module: Disjunctive domain + +Author: Johanan Wahlang + +\*******************************************************************/ + +#ifdef DEBUG +#include +#include +#endif + +#include +#include +#include + +#include "disjunctive_domain.h" +#include "util.h" +#include "domain.h" + +#define SYMB_BOUND_VAR "symb_bound#" + +#define ENABLE_HEURISTICS diff --git a/src/domains/disjunctive_domain.h b/src/domains/disjunctive_domain.h new file mode 100644 index 000000000..08d2d6775 --- /dev/null +++ b/src/domains/disjunctive_domain.h @@ -0,0 +1,46 @@ +/*******************************************************************\ + +Module: Disjunctive domain + +Author: Johanan Wahlang + +\*******************************************************************/ + +#ifndef CPROVER_2LS_DOMAINS_DISJUNCTIVE_DOMAIN_H +#define CPROVER_2LS_DOMAINS_DISJUNCTIVE_DOMAIN_H + +#include +#include + +#include +#include +#include +#include +#include + +#include "domain.h" +#include "symbolic_path.h" + +class disjunctive_domaint:public domaint +{ +public: + typedef unsigned disjunctt; + typedef std::vector templatet; + + class templ_valuet:public valuet, public std::vector + { + }; + + disjunctive_domaint( + unsigned _domain_number, + replace_mapt &_renaming_map, + const namespacet &_ns): + domaint(_domain_number, _renaming_map, _ns) + { + } + +protected: + templatet templ; +}; + +#endif // CPROVER_2LS_DOMAINS_DISJUNCTIVE_DOMAIN_H From ae7c3e04ad6f4d7a9a7a50e7d06de75b3d19ea9c Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Wed, 20 Feb 2019 09:53:37 +0530 Subject: [PATCH 258/322] Added intialize method --- src/domains/disjunctive_domain.cpp | 27 +++++++++++++++++++++++++++ src/domains/disjunctive_domain.h | 2 ++ 2 files changed, 29 insertions(+) diff --git a/src/domains/disjunctive_domain.cpp b/src/domains/disjunctive_domain.cpp index c0e9257ce..2da0787b2 100644 --- a/src/domains/disjunctive_domain.cpp +++ b/src/domains/disjunctive_domain.cpp @@ -22,3 +22,30 @@ Author: Johanan Wahlang #define SYMB_BOUND_VAR "symb_bound#" #define ENABLE_HEURISTICS + +/*******************************************************************\ + +Function: disjunctive_domaint::initialize + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void disjunctive_domaint::initialize(valuet &value) +{ +#if 0 + if(templ.size()==0) + return domaint::initialize(value); +#endif + + templ_valuet &v=static_cast(value); + v.resize(templ.size()); + for (std::size_t disjunct=0; disjunct Date: Wed, 20 Feb 2019 09:54:08 +0530 Subject: [PATCH 259/322] Added join method --- src/domains/disjunctive_domain.cpp | 30 ++++++++++++++++++++++++++++++ src/domains/disjunctive_domain.h | 2 ++ 2 files changed, 32 insertions(+) diff --git a/src/domains/disjunctive_domain.cpp b/src/domains/disjunctive_domain.cpp index 2da0787b2..c3f14dfae 100644 --- a/src/domains/disjunctive_domain.cpp +++ b/src/domains/disjunctive_domain.cpp @@ -49,3 +49,33 @@ void disjunctive_domaint::initialize(valuet &value) templ[disjunct].initialize(v[disjunct]); } } + +/*******************************************************************\ + +Function: tpolyhedra_domaint::join + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void disjunctive_domaint::join(valuet &value1, const valuet &value2) +{ +#if 0 + if(templ.size()==0) + return domaint::join(value1, value2); +#endif + + templ_valuet &v1=static_cast(value1); + const templ_valuet &v2=static_cast(value2); + v1.resize(v1.size() + v2.size()); + for(std::size_t disjunct=v1.size(); disjunct Date: Wed, 20 Mar 2019 14:24:13 +0530 Subject: [PATCH 260/322] Added printing to disjunctive domain class --- src/domains/disjunctive_domain.cpp | 47 ++++++++++++++++++++++++++++++ src/domains/disjunctive_domain.h | 10 +++++++ 2 files changed, 57 insertions(+) diff --git a/src/domains/disjunctive_domain.cpp b/src/domains/disjunctive_domain.cpp index c3f14dfae..407d30442 100644 --- a/src/domains/disjunctive_domain.cpp +++ b/src/domains/disjunctive_domain.cpp @@ -79,3 +79,50 @@ void disjunctive_domaint::join(valuet &value1, const valuet &value2) //TODO: merge heuristic for interval polyhedral domain } + +/*******************************************************************\ + +Function: disjunctive_domaint::output_value + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void disjunctive_domaint::output_value( + std::ostream &out, + const domaint::valuet &value, + const namespacet &ns) const +{ + const templ_valuet &v = static_cast(value); + + for (std::size_t d=0; d Date: Tue, 26 Mar 2019 09:57:45 +0530 Subject: [PATCH 261/322] Added project_on_vars --- src/domains/disjunctive_domain.cpp | 28 ++++++++++++++++++++++++++++ src/domains/disjunctive_domain.h | 5 +++++ 2 files changed, 33 insertions(+) diff --git a/src/domains/disjunctive_domain.cpp b/src/domains/disjunctive_domain.cpp index 407d30442..4be64e752 100644 --- a/src/domains/disjunctive_domain.cpp +++ b/src/domains/disjunctive_domain.cpp @@ -126,3 +126,31 @@ void disjunctive_domaint::output_domain( templ[d].output_domain(out,ns); } } + +/*******************************************************************\ + +Function: disjunctive_domaint::project_on_vars + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void disjunctive_domaint::project_on_vars( + domaint::valuet &value, + const domaint::var_sett &vars, + exprt &result) +{ + templ_valuet &v=static_cast(value); + + result = false_exprt(); + exprt disjunct_result; + for (std::size_t d=0; d Date: Sat, 11 May 2019 02:39:38 +0530 Subject: [PATCH 262/322] Added base domain pointer --- src/domains/disjunctive_domain.h | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/domains/disjunctive_domain.h b/src/domains/disjunctive_domain.h index ff4043988..6f822976c 100644 --- a/src/domains/disjunctive_domain.h +++ b/src/domains/disjunctive_domain.h @@ -32,13 +32,21 @@ class disjunctive_domaint:public domaint }; disjunctive_domaint( - unsigned _domain_number, + unsigned int _domain_number, replace_mapt &_renaming_map, + const var_specst &var_specs, const namespacet &_ns): - domaint(_domain_number, _renaming_map, _ns) + domaint(_domain_number, _renaming_map, _ns), + templ() { } + virtual ~disjunctive_domaint() + { + if (base_domain_ptr!=NULL) + delete base_domain_ptr; + } + virtual void initialize(valuet &value); virtual void join(valuet &value1, const valuet &value2); @@ -58,7 +66,13 @@ class disjunctive_domaint:public domaint const var_sett &vars, exprt &result) override; + domaint *base_domain() + { + return base_domain_ptr; + } + protected: + domaint *base_domain_ptr; templatet templ; }; From 2e2d68e7f388c38f94c9331b961f94e97323d1cb Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 11 May 2019 02:46:39 +0530 Subject: [PATCH 263/322] Added max no. of disjuncts --- src/domains/disjunctive_domain.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/domains/disjunctive_domain.h b/src/domains/disjunctive_domain.h index 6f822976c..43568bbcc 100644 --- a/src/domains/disjunctive_domain.h +++ b/src/domains/disjunctive_domain.h @@ -35,9 +35,11 @@ class disjunctive_domaint:public domaint unsigned int _domain_number, replace_mapt &_renaming_map, const var_specst &var_specs, - const namespacet &_ns): + const namespacet &_ns, + const disjunctt _max): domaint(_domain_number, _renaming_map, _ns), - templ() + templ(), + max(_max) { } @@ -73,6 +75,7 @@ class disjunctive_domaint:public domaint protected: domaint *base_domain_ptr; + disjunctt max; templatet templ; }; From 48f8d163603dcdc8ecd60fb89aab6a08bbc3d422 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 11 May 2019 03:20:13 +0530 Subject: [PATCH 264/322] Changed templatet and valuet defs --- src/domains/disjunctive_domain.cpp | 36 +++++++++++++++++++----------- src/domains/disjunctive_domain.h | 8 +++---- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/domains/disjunctive_domain.cpp b/src/domains/disjunctive_domain.cpp index 4be64e752..2235011a9 100644 --- a/src/domains/disjunctive_domain.cpp +++ b/src/domains/disjunctive_domain.cpp @@ -42,11 +42,14 @@ void disjunctive_domaint::initialize(valuet &value) return domaint::initialize(value); #endif - templ_valuet &v=static_cast(value); + disjunctive_valuet &v=static_cast(value); v.resize(templ.size()); - for (std::size_t disjunct=0; disjunct(value1); - const templ_valuet &v2=static_cast(value2); + disjunctive_valuet &v1=static_cast(value1); + const disjunctive_valuet &v2=static_cast(value2); v1.resize(v1.size() + v2.size()); for(std::size_t disjunct=v1.size(); disjunct(value); + const disjunctive_valuet &v = static_cast(value); - for (std::size_t d=0; d(value); + disjunctive_valuet &v=static_cast(value); result = false_exprt(); exprt disjunct_result; - for (std::size_t d=0; dsecond.project_on_vars(v[d.first], vars, disjunct_result); result = or_exprt(result, disjunct_result); } } diff --git a/src/domains/disjunctive_domain.h b/src/domains/disjunctive_domain.h index 43568bbcc..0be9e625f 100644 --- a/src/domains/disjunctive_domain.h +++ b/src/domains/disjunctive_domain.h @@ -25,9 +25,9 @@ class disjunctive_domaint:public domaint { public: typedef unsigned disjunctt; - typedef std::vector templatet; + typedef std::map> templatet; - class templ_valuet:public valuet, public std::vector + class disjunctive_valuet:public valuet, public std::vector { }; @@ -38,8 +38,8 @@ class disjunctive_domaint:public domaint const namespacet &_ns, const disjunctt _max): domaint(_domain_number, _renaming_map, _ns), - templ(), - max(_max) + max(_max), + templ() { } From 4cf5946b6a5888d55737bd4fd991d0be6ca0d95a Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 11 May 2019 03:42:21 +0530 Subject: [PATCH 265/322] Added template kind --- src/domains/disjunctive_domain.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/domains/disjunctive_domain.h b/src/domains/disjunctive_domain.h index 0be9e625f..cb46b765b 100644 --- a/src/domains/disjunctive_domain.h +++ b/src/domains/disjunctive_domain.h @@ -19,11 +19,16 @@ Author: Johanan Wahlang #include #include "domain.h" +#include "tpolyhedra_domain.h" #include "symbolic_path.h" class disjunctive_domaint:public domaint { public: + enum template_kindt + { + TPOLYHEDRA, HEAP + }; typedef unsigned disjunctt; typedef std::map> templatet; @@ -36,11 +41,17 @@ class disjunctive_domaint:public domaint replace_mapt &_renaming_map, const var_specst &var_specs, const namespacet &_ns, + const template_kindt _template_kind, const disjunctt _max): domaint(_domain_number, _renaming_map, _ns), + template_kind(_template_kind), max(_max), templ() { + if(template_kind==TPOLYHEDRA) + { + base_domain_ptr=new tpolyhedra_domaint(domain_number, renaming_map, ns); + } } virtual ~disjunctive_domaint() @@ -68,6 +79,10 @@ class disjunctive_domaint:public domaint const var_sett &vars, exprt &result) override; + template_kindt &get_template_kind() + { + return template_kind; + } domaint *base_domain() { return base_domain_ptr; @@ -75,6 +90,7 @@ class disjunctive_domaint:public domaint protected: domaint *base_domain_ptr; + template_kindt template_kind; disjunctt max; templatet templ; }; From cdae4b4299c2b8d9eebf2e655a26af8c96a13ce8 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 11 May 2019 03:46:00 +0530 Subject: [PATCH 266/322] Added guards and loophead location --- src/domains/disjunctive_domain.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/domains/disjunctive_domain.h b/src/domains/disjunctive_domain.h index cb46b765b..d546c60af 100644 --- a/src/domains/disjunctive_domain.h +++ b/src/domains/disjunctive_domain.h @@ -17,6 +17,7 @@ Author: Johanan Wahlang #include #include #include +#include #include "domain.h" #include "tpolyhedra_domain.h" @@ -31,6 +32,7 @@ class disjunctive_domaint:public domaint }; typedef unsigned disjunctt; typedef std::map> templatet; + typedef std::vector guardst; class disjunctive_valuet:public valuet, public std::vector { @@ -42,15 +44,19 @@ class disjunctive_domaint:public domaint const var_specst &var_specs, const namespacet &_ns, const template_kindt _template_kind, - const disjunctt _max): + const disjunctt _max, + const guardst _guards, + local_SSAt::locationt _location): domaint(_domain_number, _renaming_map, _ns), template_kind(_template_kind), max(_max), - templ() + templ(), + guards(_guards), + location(_location) { if(template_kind==TPOLYHEDRA) { - base_domain_ptr=new tpolyhedra_domaint(domain_number, renaming_map, ns); + base_domain_ptr=new tpolyhedra_domaint(domain_number, renaming_map, _ns); } } @@ -93,6 +99,8 @@ class disjunctive_domaint:public domaint template_kindt template_kind; disjunctt max; templatet templ; + guardst guards; + local_SSAt::locationt location; }; #endif // CPROVER_2LS_DOMAINS_DISJUNCTIVE_DOMAIN_H From d3a4a7549d1b82460641814395e9a9494e1ea44f Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 11 May 2019 03:48:18 +0530 Subject: [PATCH 267/322] Added lexigographic metric and tolerance --- src/domains/disjunctive_domain.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/domains/disjunctive_domain.h b/src/domains/disjunctive_domain.h index d546c60af..11f2226aa 100644 --- a/src/domains/disjunctive_domain.h +++ b/src/domains/disjunctive_domain.h @@ -38,6 +38,8 @@ class disjunctive_domaint:public domaint { }; + typedef std::pair lex_metrict; + disjunctive_domaint( unsigned int _domain_number, replace_mapt &_renaming_map, @@ -46,12 +48,14 @@ class disjunctive_domaint:public domaint const template_kindt _template_kind, const disjunctt _max, const guardst _guards, + const lex_metrict _tol, local_SSAt::locationt _location): domaint(_domain_number, _renaming_map, _ns), template_kind(_template_kind), max(_max), templ(), guards(_guards), + tol(_tol), location(_location) { if(template_kind==TPOLYHEDRA) @@ -100,6 +104,7 @@ class disjunctive_domaint:public domaint disjunctt max; templatet templ; guardst guards; + lex_metrict tol; local_SSAt::locationt location; }; From b5824190fc4d48120f7412419c3b68e774575dfc Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 11 May 2019 04:06:15 +0530 Subject: [PATCH 268/322] Added merge heuristic --- src/domains/disjunctive_domain.cpp | 178 +++++++++++++++++++++++++++++ src/domains/disjunctive_domain.h | 6 + 2 files changed, 184 insertions(+) diff --git a/src/domains/disjunctive_domain.cpp b/src/domains/disjunctive_domain.cpp index 2235011a9..8702bf254 100644 --- a/src/domains/disjunctive_domain.cpp +++ b/src/domains/disjunctive_domain.cpp @@ -164,3 +164,181 @@ void disjunctive_domaint::project_on_vars( result = or_exprt(result, disjunct_result); } } + +/*******************************************************************\ + +Function: disjunctive_domaint::merge_heuristic + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +int disjunctive_domaint::merge_heuristic(disjunctive_valuet &dv, valuet &value) +{ + if (template_kind==TPOLYHEDRA) + { + tpolyhedra_domaint::templ_valuet &v_new=static_cast(value); + ieee_floatt inf; + inf.make_plus_infinity(); + lex_metrict min_distance(dv.size(),inf); + disjunctt min_disjunct=0; + for (disjunctt d=0; d(dv[d]); + lex_metrict distance=hausdorff_distance(v, v_new); + if (distancetol) + { + return -1; + } + return min_disjunct; + } + else + { + //TODO: merge heuristic for other templates + } +} + +/*******************************************************************\ + +Function: disjunctive_domaint::hausdorff_distance + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +disjunctive_domaint::lex_metrict disjunctive_domaint::hausdorff_distance( + const tpolyhedra_domaint::templ_valuet &value1, + const tpolyhedra_domaint::templ_valuet &value2) +{ + assert(value1.size()==value2.size()); + ieee_floatt zero; + unsigned int incomparable=0; + ieee_floatt dist=zero; + for (int i=0; id2) + { + dist+=d1; + } + else + { + dist+=d2; + } + } + } + return lex_metrict(incomparable,dist); +} + +/*******************************************************************\ + +Function: disjunctive_domaint::distance + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +ieee_floatt disjunctive_domaint::distance(const constant_exprt &v1, const constant_exprt &v2) +{ + ieee_floatt diff; + if(v1.type()==v2.type() && + (v1.type().id()==ID_signedbv || v1.type().id()==ID_unsignedbv)) + { + mp_integer vv1, vv2; + to_integer(v1, vv1); + to_integer(v2, vv2); + diff.from_integer(vv1-vv2); + } + else if(v1.type().id()==ID_floatbv && v2.type().id()==ID_floatbv) + { + ieee_floatt vv1(to_constant_expr(v1)); + ieee_floatt vv2(to_constant_expr(v2)); + diff=ieee_floatt(vv1); + diff-=vv2; + } + else + { + assert(false); // types do not match or are not supported + } + diff.set_sign(false); + return diff; +} \ No newline at end of file diff --git a/src/domains/disjunctive_domain.h b/src/domains/disjunctive_domain.h index 11f2226aa..ea0c85347 100644 --- a/src/domains/disjunctive_domain.h +++ b/src/domains/disjunctive_domain.h @@ -98,6 +98,12 @@ class disjunctive_domaint:public domaint return base_domain_ptr; } + int merge_heuristic(disjunctive_valuet &dv,valuet &v); + lex_metrict hausdorff_distance( + const tpolyhedra_domaint::templ_valuet &value1, + const tpolyhedra_domaint::templ_valuet &value2); + ieee_floatt distance(const constant_exprt &v1, const constant_exprt &v2); + protected: domaint *base_domain_ptr; template_kindt template_kind; From 4ac01bdf61490e0c6f0a2026db75dc4767d30056 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 11 May 2019 04:37:00 +0530 Subject: [PATCH 269/322] Added unresolved and seen edges --- src/domains/disjunctive_domain.h | 39 +++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/domains/disjunctive_domain.h b/src/domains/disjunctive_domain.h index ea0c85347..38565ac6e 100644 --- a/src/domains/disjunctive_domain.h +++ b/src/domains/disjunctive_domain.h @@ -40,6 +40,39 @@ class disjunctive_domaint:public domaint typedef std::pair lex_metrict; + struct unresolved_edget + { + disjunctt disjunct; + symbolic_patht path; + + unresolved_edget( + disjunctt _disjunct, + symbolic_patht _path): + disjunct(_disjunct), + path(_path) + {} + }; + + typedef std::set unresolved_sett; + + struct seen_edget + { + disjunctt source; + symbolic_patht path; + disjunctt sink; + + seen_edget( + disjunctt _source, + symbolic_patht _path, + disjunctt _sink): + source(_source), + path(_path), + sink(_sink) + {} + }; + + typedef std::set seen_sett; + disjunctive_domaint( unsigned int _domain_number, replace_mapt &_renaming_map, @@ -56,7 +89,9 @@ class disjunctive_domaint:public domaint templ(), guards(_guards), tol(_tol), - location(_location) + location(_location), + unresolved_set(), + seen_set() { if(template_kind==TPOLYHEDRA) { @@ -112,6 +147,8 @@ class disjunctive_domaint:public domaint guardst guards; lex_metrict tol; local_SSAt::locationt location; + unresolved_sett unresolved_set; + seen_sett seen_set; }; #endif // CPROVER_2LS_DOMAINS_DISJUNCTIVE_DOMAIN_H From 50eecdbc65919c72d35a48999e7ce7d79588b4b4 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 11 May 2019 04:54:11 +0530 Subject: [PATCH 270/322] Minor fixes --- src/domains/disjunctive_domain.cpp | 2 +- src/domains/disjunctive_domain.h | 48 ++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/domains/disjunctive_domain.cpp b/src/domains/disjunctive_domain.cpp index 8702bf254..38e06b130 100644 --- a/src/domains/disjunctive_domain.cpp +++ b/src/domains/disjunctive_domain.cpp @@ -229,7 +229,7 @@ disjunctive_domaint::lex_metrict disjunctive_domaint::hausdorff_distance( ieee_floatt zero; unsigned int incomparable=0; ieee_floatt dist=zero; - for (int i=0; i { }; - - typedef std::pair lex_metrict; + + class lex_metrict + { + public: + unsigned int incomparable; + ieee_floatt distance; + + lex_metrict( + unsigned int _incomparable, + ieee_floatt _distance): + incomparable(_incomparable), + distance(_distance) + {} + friend bool operator< (const lex_metrict &m1, const lex_metrict &m2) + { + if (m1.incomparable (const lex_metrict &m1, const lex_metrict &m2) + { + if(m1.incomparable>m2.incomparable) + { + return true; + } + else if (m2.incomparable>m1.incomparable) + { + return false; + } + else + { + return (m1.distance>m2.distance); + } + + } + }; + struct unresolved_edget { From 5770ab50d7b1d7025a7b0ebd87f7640d275adce5 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 11 May 2019 04:55:52 +0530 Subject: [PATCH 271/322] Added compilation rule for disjunctive domain --- src/domains/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/domains/Makefile b/src/domains/Makefile index e293aee2f..40c65483e 100644 --- a/src/domains/Makefile +++ b/src/domains/Makefile @@ -1,7 +1,7 @@ SRC = tpolyhedra_domain.cpp equality_domain.cpp domain.cpp \ predabs_domain.cpp heap_domain.cpp list_iterator.cpp \ heap_tpolyhedra_domain.cpp heap_tpolyhedra_sympath_domain.cpp \ - symbolic_path.cpp\ + disjunctive_domain.cpp symbolic_path.cpp\ ssa_analyzer.cpp util.cpp incremental_solver.cpp \ strategy_solver_base.cpp strategy_solver_equality.cpp \ linrank_domain.cpp lexlinrank_domain.cpp\ From ee2df9f7b29fb398d52011e3b2b912451ade05a2 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 11 May 2019 05:08:53 +0530 Subject: [PATCH 272/322] Added strategy solver for disjunctive domain class --- src/domains/Makefile | 1 + src/domains/disjunctive_domain.h | 2 ++ src/domains/strategy_solver_disjunctive.cpp | 26 +++++++++++++++ src/domains/strategy_solver_disjunctive.h | 37 +++++++++++++++++++++ 4 files changed, 66 insertions(+) create mode 100644 src/domains/strategy_solver_disjunctive.cpp create mode 100644 src/domains/strategy_solver_disjunctive.h diff --git a/src/domains/Makefile b/src/domains/Makefile index 40c65483e..1561b946c 100644 --- a/src/domains/Makefile +++ b/src/domains/Makefile @@ -13,6 +13,7 @@ SRC = tpolyhedra_domain.cpp equality_domain.cpp domain.cpp \ strategy_solver_predabs.cpp strategy_solver_heap.cpp \ strategy_solver_heap_tpolyhedra.cpp \ strategy_solver_heap_tpolyhedra_sympath.cpp \ + strategy_solver_disjunctive.cpp \ #solver_enumeration.cpp include ../config.inc diff --git a/src/domains/disjunctive_domain.h b/src/domains/disjunctive_domain.h index ed1722fc9..5c2011a79 100644 --- a/src/domains/disjunctive_domain.h +++ b/src/domains/disjunctive_domain.h @@ -193,6 +193,8 @@ class disjunctive_domaint:public domaint local_SSAt::locationt location; unresolved_sett unresolved_set; seen_sett seen_set; + + friend class strategy_solver_disjunctivet; }; #endif // CPROVER_2LS_DOMAINS_DISJUNCTIVE_DOMAIN_H diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp new file mode 100644 index 000000000..2a9ec7760 --- /dev/null +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -0,0 +1,26 @@ +/*******************************************************************\ + +Module: Strategy solver for disjunctive domains + +Author: Johanan Wahlang + +\*******************************************************************/ + +#include "strategy_solver_disjunctive.h" + +/*******************************************************************\ + +Function: strategy_solver_disjunctivet::iterate + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool strategy_solver_disjunctivet::iterate( + strategy_solver_baset::invariantt &_inv) +{ +} diff --git a/src/domains/strategy_solver_disjunctive.h b/src/domains/strategy_solver_disjunctive.h new file mode 100644 index 000000000..416c29bd6 --- /dev/null +++ b/src/domains/strategy_solver_disjunctive.h @@ -0,0 +1,37 @@ +/*******************************************************************\ + +Module: Strategy solver for disjunctive domains + +Author: Johanan Wahlang + +\*******************************************************************/ + +#ifndef CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_DISJUNCTIVE_DOMAIN_H +#define CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_DISJUNCTIVE_DOMAIN_H + +#include +#include "strategy_solver_base.h" +#include "disjunctive_domain.h" + +class strategy_solver_disjunctivet:public strategy_solver_baset +{ +public: + strategy_solver_disjunctivet( + disjunctive_domaint &_disjunctive_domain, + incremental_solvert &_solver, + local_SSAt &_SSA, + const namespacet &_ns): + strategy_solver_baset(_solver, _ns), + disjunctive_domain(_disjunctive_domain), + SSA(_SSA) + { + } + + virtual bool iterate(invariantt &inv); + +protected: + disjunctive_domaint &disjunctive_domain; + local_SSAt &SSA; +}; + +#endif //CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_DISJUNCTIVE_DOMAIN_H \ No newline at end of file From f2f66aab5d26817ab2a06ed0cf40bbd771e967b8 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Wed, 15 May 2019 09:57:26 +0530 Subject: [PATCH 273/322] Added get_unresolved_edge --- src/domains/disjunctive_domain.h | 10 +++- src/domains/strategy_solver_disjunctive.cpp | 58 +++++++++++++++++++++ src/domains/strategy_solver_disjunctive.h | 3 ++ 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/domains/disjunctive_domain.h b/src/domains/disjunctive_domain.h index 5c2011a79..69a6c6320 100644 --- a/src/domains/disjunctive_domain.h +++ b/src/domains/disjunctive_domain.h @@ -84,12 +84,15 @@ class disjunctive_domaint:public domaint }; - struct unresolved_edget + class unresolved_edget { + public: disjunctt disjunct; symbolic_patht path; - unresolved_edget( + inline unresolved_edget() { } + + inline unresolved_edget( disjunctt _disjunct, symbolic_patht _path): disjunct(_disjunct), @@ -183,6 +186,9 @@ class disjunctive_domaint:public domaint const tpolyhedra_domaint::templ_valuet &value2); ieee_floatt distance(const constant_exprt &v1, const constant_exprt &v2); + + exprt get_disjunct_constraint(const disjunctt &d, const valuet &value); + protected: domaint *base_domain_ptr; template_kindt template_kind; diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 2a9ec7760..da62330d5 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -23,4 +23,62 @@ Function: strategy_solver_disjunctivet::iterate bool strategy_solver_disjunctivet::iterate( strategy_solver_baset::invariantt &_inv) { + disjunctive_domaint::disjunctive_valuet &inv= + static_cast(_inv); + + bool improved=false; + + disjunctive_domaint::unresolved_edget e=get_unresolved_edge(inv); + if (e.disjunct==0) + { + // no more unresolved edges + return improved; + } + + return improved; +} + +/*******************************************************************\ + +Function: strategy_solver_disjunctivet::get_unresolved_edge + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +disjunctive_domaint::unresolved_edget +strategy_solver_disjunctivet::get_unresolved_edge( + const disjunctive_domaint::disjunctive_valuet &value) +{ + disjunctive_domaint::unresolved_edget e; + for (auto it=disjunctive_domain.unresolved_set.begin(); + it!=disjunctive_domain.unresolved_set.end();) + { + solver.new_context(); + disjunctive_domaint::disjunctt d; + symbolic_patht p; + d = it->disjunct; + p = it->path; + + solver< Date: Wed, 15 May 2019 10:09:09 +0530 Subject: [PATCH 274/322] Disjunctive domain: compute post over an edge --- src/domains/strategy_solver_disjunctive.cpp | 36 +++++++++++++++++++++ src/domains/strategy_solver_disjunctive.h | 3 ++ 2 files changed, 39 insertions(+) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index da62330d5..b4bceb55f 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -7,6 +7,7 @@ Author: Johanan Wahlang \*******************************************************************/ #include "strategy_solver_disjunctive.h" +#include "strategy_solver_enumeration.h" /*******************************************************************\ @@ -35,6 +36,8 @@ bool strategy_solver_disjunctivet::iterate( return improved; } + invariantt post=get_post(e,inv); + return improved; } @@ -82,3 +85,36 @@ strategy_solver_disjunctivet::get_unresolved_edge( return disjunctive_domaint::unresolved_edget(0,symbolic_patht()); } + +/*******************************************************************\ + +Function: strategy_solver_disjunctivet::get_post + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +strategy_solver_disjunctivet::invariantt +strategy_solver_disjunctivet::get_post( + const disjunctive_domaint::unresolved_edget &e, + disjunctive_domaint::disjunctive_valuet &_inv) +{ + domaint *_domain=disjunctive_domain.base_domain(); + disjunctive_domaint::disjunctt d=e.disjunct; + symbolic_patht p=e.path; + strategy_solver_baset::invariantt inv=_inv[d]; + if (disjunctive_domain.get_template_kind()==disjunctive_domaint::TPOLYHEDRA) + { + tpolyhedra_domaint domain=*static_cast(_domain); + domain.restrict_to_sympath(p); + strategy_solver_enumerationt strategy_solver( + domain,solver,ns); + strategy_solver.iterate(inv); + domain.undo_restriction(); + } + return inv; +} diff --git a/src/domains/strategy_solver_disjunctive.h b/src/domains/strategy_solver_disjunctive.h index 10b01720d..c59ff3f3d 100644 --- a/src/domains/strategy_solver_disjunctive.h +++ b/src/domains/strategy_solver_disjunctive.h @@ -31,6 +31,9 @@ class strategy_solver_disjunctivet:public strategy_solver_baset disjunctive_domaint::unresolved_edget get_unresolved_edge( const disjunctive_domaint::disjunctive_valuet &value); + invariantt get_post( + const disjunctive_domaint::unresolved_edget &e, + disjunctive_domaint::disjunctive_valuet &inv); protected: disjunctive_domaint &disjunctive_domain; From 56c89e6cf50ff44a5f77187cece77dd2674091c8 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Wed, 15 May 2019 11:30:19 +0530 Subject: [PATCH 275/322] Disjunctive domain: fix zero indexing --- src/domains/disjunctive_domain.cpp | 11 ++++++++--- src/domains/disjunctive_domain.h | 2 +- src/domains/strategy_solver_disjunctive.cpp | 6 +++--- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/domains/disjunctive_domain.cpp b/src/domains/disjunctive_domain.cpp index 38e06b130..4d46fe48a 100644 --- a/src/domains/disjunctive_domain.cpp +++ b/src/domains/disjunctive_domain.cpp @@ -177,7 +177,7 @@ Function: disjunctive_domaint::merge_heuristic \*******************************************************************/ -int disjunctive_domaint::merge_heuristic(disjunctive_valuet &dv, valuet &value) +disjunctive_domaint::disjunctt disjunctive_domaint::merge_heuristic(disjunctive_valuet &dv, valuet &value) { if (template_kind==TPOLYHEDRA) { @@ -199,13 +199,18 @@ int disjunctive_domaint::merge_heuristic(disjunctive_valuet &dv, valuet &value) if (dv.size()tol) { - return -1; + return dv.size(); + } + else + { + return min_disjunct; } - return min_disjunct; } else { //TODO: merge heuristic for other templates + std::cout << "Merge heuristic template kind not yet implemented" << std::endl; + assert(false); } } diff --git a/src/domains/disjunctive_domain.h b/src/domains/disjunctive_domain.h index 69a6c6320..1da504f5a 100644 --- a/src/domains/disjunctive_domain.h +++ b/src/domains/disjunctive_domain.h @@ -180,7 +180,7 @@ class disjunctive_domaint:public domaint return base_domain_ptr; } - int merge_heuristic(disjunctive_valuet &dv,valuet &v); + disjunctt merge_heuristic(disjunctive_valuet &dv,valuet &v); lex_metrict hausdorff_distance( const tpolyhedra_domaint::templ_valuet &value1, const tpolyhedra_domaint::templ_valuet &value2); diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index b4bceb55f..1e7fcb0a8 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -30,7 +30,7 @@ bool strategy_solver_disjunctivet::iterate( bool improved=false; disjunctive_domaint::unresolved_edget e=get_unresolved_edge(inv); - if (e.disjunct==0) + if (e.disjunct==inv.size()) { // no more unresolved edges return improved; @@ -82,8 +82,8 @@ strategy_solver_disjunctivet::get_unresolved_edge( solver.pop_context(); return e; } - - return disjunctive_domaint::unresolved_edget(0,symbolic_patht()); + // couldn't find a feasible edge + return disjunctive_domaint::unresolved_edget(value.size(),symbolic_patht()); } /*******************************************************************\ From 59620e0573a50ed5e7fe9fe7b5ee5c508637c8b4 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 03:20:05 +0530 Subject: [PATCH 276/322] Use mp_integer instead of ieee_floatt for merge_heuristic --- src/domains/disjunctive_domain.cpp | 46 ++++++++++++++---------------- src/domains/disjunctive_domain.h | 9 +++--- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/src/domains/disjunctive_domain.cpp b/src/domains/disjunctive_domain.cpp index 4d46fe48a..654c6f17b 100644 --- a/src/domains/disjunctive_domain.cpp +++ b/src/domains/disjunctive_domain.cpp @@ -182,11 +182,12 @@ disjunctive_domaint::disjunctt disjunctive_domaint::merge_heuristic(disjunctive_ if (template_kind==TPOLYHEDRA) { tpolyhedra_domaint::templ_valuet &v_new=static_cast(value); - ieee_floatt inf; - inf.make_plus_infinity(); - lex_metrict min_distance(dv.size(),inf); - disjunctt min_disjunct=0; - for (disjunctt d=0; d(dv[d]); + lex_metrict distance=hausdorff_distance(v, v_new); + lex_metrict min_distance=distance; + disjunctt min_disjunct=d; + for (; d(dv[d]); lex_metrict distance=hausdorff_distance(v, v_new); @@ -231,9 +232,8 @@ disjunctive_domaint::lex_metrict disjunctive_domaint::hausdorff_distance( const tpolyhedra_domaint::templ_valuet &value2) { assert(value1.size()==value2.size()); - ieee_floatt zero; unsigned int incomparable=0; - ieee_floatt dist=zero; + mp_integer dist(0); for (std::size_t i=0; id2) { dist+=d1; @@ -322,28 +322,26 @@ Function: disjunctive_domaint::distance \*******************************************************************/ -ieee_floatt disjunctive_domaint::distance(const constant_exprt &v1, const constant_exprt &v2) +mp_integer disjunctive_domaint::distance(const constant_exprt &v1, const constant_exprt &v2) { - ieee_floatt diff; if(v1.type()==v2.type() && (v1.type().id()==ID_signedbv || v1.type().id()==ID_unsignedbv)) { - mp_integer vv1, vv2; - to_integer(v1, vv1); - to_integer(v2, vv2); - diff.from_integer(vv1-vv2); - } - else if(v1.type().id()==ID_floatbv && v2.type().id()==ID_floatbv) - { - ieee_floatt vv1(to_constant_expr(v1)); - ieee_floatt vv2(to_constant_expr(v2)); - diff=ieee_floatt(vv1); - diff-=vv2; + mp_integer vv1,vv2; + to_integer(v1,vv1); + to_integer(v2,vv2); + mp_integer diff(vv1-vv2); + if (diff.is_negative()) + { + return -diff; + } + else + { + return diff; + } } else { assert(false); // types do not match or are not supported } - diff.set_sign(false); - return diff; } \ No newline at end of file diff --git a/src/domains/disjunctive_domain.h b/src/domains/disjunctive_domain.h index 1da504f5a..dd29daff3 100644 --- a/src/domains/disjunctive_domain.h +++ b/src/domains/disjunctive_domain.h @@ -42,11 +42,11 @@ class disjunctive_domaint:public domaint { public: unsigned int incomparable; - ieee_floatt distance; + mp_integer distance; lex_metrict( - unsigned int _incomparable, - ieee_floatt _distance): + unsigned int _incomparable=0, + mp_integer _distance=0): incomparable(_incomparable), distance(_distance) {} @@ -184,8 +184,7 @@ class disjunctive_domaint:public domaint lex_metrict hausdorff_distance( const tpolyhedra_domaint::templ_valuet &value1, const tpolyhedra_domaint::templ_valuet &value2); - ieee_floatt distance(const constant_exprt &v1, const constant_exprt &v2); - + mp_integer distance(const constant_exprt &v1, const constant_exprt &v2); exprt get_disjunct_constraint(const disjunctt &d, const valuet &value); From ba9ae9f007c101a0817988e1362e0f798f649c1f Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 03:23:22 +0530 Subject: [PATCH 277/322] Use vector of pointers for values to avoid object splicing --- src/domains/disjunctive_domain.cpp | 14 +++++++------- src/domains/disjunctive_domain.h | 2 +- src/domains/strategy_solver_disjunctive.cpp | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/domains/disjunctive_domain.cpp b/src/domains/disjunctive_domain.cpp index 654c6f17b..d4d78d449 100644 --- a/src/domains/disjunctive_domain.cpp +++ b/src/domains/disjunctive_domain.cpp @@ -48,7 +48,7 @@ void disjunctive_domaint::initialize(valuet &value) { for (auto &t : d.second) { - t.second.initialize(v[d.first]); + t.second.initialize(*v[d.first]); } } } @@ -107,7 +107,7 @@ void disjunctive_domaint::output_value( auto t=d.second; for (auto &i : t) { - i.second.output_value(out,v[d.first],ns); + i.second.output_value(out,*v[d.first],ns); } } } @@ -160,7 +160,7 @@ void disjunctive_domaint::project_on_vars( exprt disjunct_result; for (auto &d : templ) { - d.second.begin()->second.project_on_vars(v[d.first], vars, disjunct_result); + d.second.begin()->second.project_on_vars(*v[d.first], vars, disjunct_result); result = or_exprt(result, disjunct_result); } } @@ -183,14 +183,14 @@ disjunctive_domaint::disjunctt disjunctive_domaint::merge_heuristic(disjunctive_ { tpolyhedra_domaint::templ_valuet &v_new=static_cast(value); disjunctt d=0; - tpolyhedra_domaint::templ_valuet &v=static_cast(dv[d]); - lex_metrict distance=hausdorff_distance(v, v_new); + tpolyhedra_domaint::templ_valuet *v=static_cast(dv[d]); + lex_metrict distance=hausdorff_distance(*v, v_new); lex_metrict min_distance=distance; disjunctt min_disjunct=d; for (; d(dv[d]); - lex_metrict distance=hausdorff_distance(v, v_new); + tpolyhedra_domaint::templ_valuet *v=static_cast(dv[d]); + lex_metrict distance=hausdorff_distance(*v, v_new); if (distance> templatet; typedef std::vector guardst; - class disjunctive_valuet:public valuet, public std::vector + class disjunctive_valuet:public valuet, public std::vector { }; diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 1e7fcb0a8..94c74c6f2 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -67,7 +67,7 @@ strategy_solver_disjunctivet::get_unresolved_edge( d = it->disjunct; p = it->path; - solver<(_domain); From 33f27b25b7d4683face7af514d2a045aa2afcbcd Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 03:34:57 +0530 Subject: [PATCH 278/322] Disjuntive domain: modified printing, initialization, and projection --- src/domains/disjunctive_domain.cpp | 66 +++++++++++++++++++----------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/src/domains/disjunctive_domain.cpp b/src/domains/disjunctive_domain.cpp index d4d78d449..20e46b247 100644 --- a/src/domains/disjunctive_domain.cpp +++ b/src/domains/disjunctive_domain.cpp @@ -37,20 +37,19 @@ Function: disjunctive_domaint::initialize void disjunctive_domaint::initialize(valuet &value) { -#if 0 - if(templ.size()==0) - return domaint::initialize(value); -#endif - - disjunctive_valuet &v=static_cast(value); - v.resize(templ.size()); - for (auto &d : templ) + disjunctive_valuet &dv=static_cast(value); + if (template_kind==TPOLYHEDRA) { - for (auto &t : d.second) + for (auto &v : dv) { - t.second.initialize(*v[d.first]); + tpolyhedra_domaint *domain=static_cast(base_domain_ptr); + domain->initialize(*v); } } + else + { + assert(false); + } } /*******************************************************************\ @@ -100,16 +99,21 @@ void disjunctive_domaint::output_value( const domaint::valuet &value, const namespacet &ns) const { - const disjunctive_valuet &v = static_cast(value); + const disjunctive_valuet &dv=static_cast(value); - for (auto &d : templ) + if (template_kind==TPOLYHEDRA) { - auto t=d.second; - for (auto &i : t) + tpolyhedra_domaint *domain=static_cast(base_domain_ptr); + for (auto &v : dv) { - i.second.output_value(out,*v[d.first],ns); + domain->output_value(out,*v,ns); + out << " || " << std::endl; } } + else + { + assert(false); + } } /*******************************************************************\ @@ -128,12 +132,13 @@ void disjunctive_domaint::output_domain( std::ostream &out, const namespacet &ns) const { - for (auto &d : templ) + switch (template_kind) { - for (auto &i : d.second) - { - i.second.output_domain(out,ns); - } + case TPOLYHEDRA: + static_cast(base_domain_ptr)->output_domain(out,ns); + break; + default: + assert(false); } } @@ -154,14 +159,27 @@ void disjunctive_domaint::project_on_vars( const domaint::var_sett &vars, exprt &result) { - disjunctive_valuet &v=static_cast(value); + disjunctive_valuet &dv=static_cast(value); + if (dv.size()==0) + { + result = true_exprt(); + return; + } result = false_exprt(); exprt disjunct_result; - for (auto &d : templ) + if (template_kind==TPOLYHEDRA) { - d.second.begin()->second.project_on_vars(*v[d.first], vars, disjunct_result); - result = or_exprt(result, disjunct_result); + tpolyhedra_domaint *domain=static_cast(base_domain_ptr); + for (auto &v : dv) + { + domain->project_on_vars(*v,vars,disjunct_result); + result = or_exprt(result,disjunct_result); + } + } + else + { + assert(false); } } From ac84b033eca294de688614677333424753b74f2c Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 03:36:31 +0530 Subject: [PATCH 279/322] Minor edit --- src/domains/disjunctive_domain.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/domains/disjunctive_domain.cpp b/src/domains/disjunctive_domain.cpp index 20e46b247..8c5ee03cd 100644 --- a/src/domains/disjunctive_domain.cpp +++ b/src/domains/disjunctive_domain.cpp @@ -19,8 +19,6 @@ Author: Johanan Wahlang #include "util.h" #include "domain.h" -#define SYMB_BOUND_VAR "symb_bound#" - #define ENABLE_HEURISTICS /*******************************************************************\ @@ -66,11 +64,6 @@ Function: tpolyhedra_domaint::join void disjunctive_domaint::join(valuet &value1, const valuet &value2) { -#if 0 - if(templ.size()==0) - return domaint::join(value1, value2); -#endif - disjunctive_valuet &v1=static_cast(value1); const disjunctive_valuet &v2=static_cast(value2); v1.resize(v1.size() + v2.size()); From 21cbf2420635c90c505fbf2074871c3cefc7170e Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 03:40:45 +0530 Subject: [PATCH 280/322] Disjunctive domain : use vector of pointer for template --- src/domains/disjunctive_domain.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/domains/disjunctive_domain.h b/src/domains/disjunctive_domain.h index c701641c9..66a3d4622 100644 --- a/src/domains/disjunctive_domain.h +++ b/src/domains/disjunctive_domain.h @@ -31,7 +31,7 @@ class disjunctive_domaint:public domaint TPOLYHEDRA, HEAP }; typedef unsigned disjunctt; - typedef std::map> templatet; + typedef std::map> templatet; typedef std::vector guardst; class disjunctive_valuet:public valuet, public std::vector From 55b380a314047ee5fd126c7698914ef97a7e59cc Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 03:43:53 +0530 Subject: [PATCH 281/322] Minor edits --- src/domains/disjunctive_domain.h | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/domains/disjunctive_domain.h b/src/domains/disjunctive_domain.h index 66a3d4622..4dd1e58b1 100644 --- a/src/domains/disjunctive_domain.h +++ b/src/domains/disjunctive_domain.h @@ -79,7 +79,6 @@ class disjunctive_domaint:public domaint { return (m1.distance>m2.distance); } - } }; @@ -100,7 +99,7 @@ class disjunctive_domaint:public domaint {} }; - typedef std::set unresolved_sett; + typedef std::vector unresolved_sett; struct seen_edget { @@ -118,7 +117,7 @@ class disjunctive_domaint:public domaint {} }; - typedef std::set seen_sett; + typedef std::vector seen_sett; disjunctive_domaint( unsigned int _domain_number, @@ -128,15 +127,13 @@ class disjunctive_domaint:public domaint const template_kindt _template_kind, const disjunctt _max, const guardst _guards, - const lex_metrict _tol, - local_SSAt::locationt _location): + const lex_metrict _tol): domaint(_domain_number, _renaming_map, _ns), template_kind(_template_kind), max(_max), templ(), guards(_guards), tol(_tol), - location(_location), unresolved_set(), seen_set() { @@ -171,11 +168,11 @@ class disjunctive_domaint:public domaint const var_sett &vars, exprt &result) override; - template_kindt &get_template_kind() + inline template_kindt &get_template_kind() { return template_kind; } - domaint *base_domain() + inline domaint *base_domain() { return base_domain_ptr; } @@ -195,7 +192,6 @@ class disjunctive_domaint:public domaint templatet templ; guardst guards; lex_metrict tol; - local_SSAt::locationt location; unresolved_sett unresolved_set; seen_sett seen_set; From 4a674af499935568171b1fb9b6a881cbd34e57ee Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 04:21:59 +0530 Subject: [PATCH 282/322] Added loop body guards for disjunctive domain --- src/domains/disjunctive_domain.h | 4 ---- src/domains/strategy_solver_disjunctive.h | 2 ++ src/domains/template_generator_base.h | 11 +++++++++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/domains/disjunctive_domain.h b/src/domains/disjunctive_domain.h index 4dd1e58b1..cf807220d 100644 --- a/src/domains/disjunctive_domain.h +++ b/src/domains/disjunctive_domain.h @@ -32,7 +32,6 @@ class disjunctive_domaint:public domaint }; typedef unsigned disjunctt; typedef std::map> templatet; - typedef std::vector guardst; class disjunctive_valuet:public valuet, public std::vector { @@ -126,13 +125,11 @@ class disjunctive_domaint:public domaint const namespacet &_ns, const template_kindt _template_kind, const disjunctt _max, - const guardst _guards, const lex_metrict _tol): domaint(_domain_number, _renaming_map, _ns), template_kind(_template_kind), max(_max), templ(), - guards(_guards), tol(_tol), unresolved_set(), seen_set() @@ -190,7 +187,6 @@ class disjunctive_domaint:public domaint template_kindt template_kind; disjunctt max; templatet templ; - guardst guards; lex_metrict tol; unresolved_sett unresolved_set; seen_sett seen_set; diff --git a/src/domains/strategy_solver_disjunctive.h b/src/domains/strategy_solver_disjunctive.h index c59ff3f3d..ee958b561 100644 --- a/src/domains/strategy_solver_disjunctive.h +++ b/src/domains/strategy_solver_disjunctive.h @@ -16,6 +16,7 @@ Author: Johanan Wahlang class strategy_solver_disjunctivet:public strategy_solver_baset { public: + typedef std::vector guardst; strategy_solver_disjunctivet( disjunctive_domaint &_disjunctive_domain, incremental_solvert &_solver, @@ -38,6 +39,7 @@ class strategy_solver_disjunctivet:public strategy_solver_baset protected: disjunctive_domaint &disjunctive_domain; local_SSAt &SSA; + guardst guards; }; #endif //CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_DISJUNCTIVE_DOMAIN_H \ No newline at end of file diff --git a/src/domains/template_generator_base.h b/src/domains/template_generator_base.h index 1c42a6c0c..e9010a12c 100644 --- a/src/domains/template_generator_base.h +++ b/src/domains/template_generator_base.h @@ -61,6 +61,10 @@ class template_generator_baset:public messaget optionst options; // copy: we may override options + local_SSAt::locationt loophead_loc; // for disjunctive domains + bool loop_present; + std::vector guards; + protected: const ssa_dbt &ssa_db; const ssa_local_unwindert &ssa_local_unwinder; @@ -76,6 +80,13 @@ class template_generator_baset:public messaget local_SSAt::nodest::const_iterator loop_begin, local_SSAt::nodest::const_iterator loop_end); + void collect_guards( + const local_SSAt &SSA, + local_SSAt::nodest::const_iterator loop_begin, + local_SSAt::nodest::const_iterator loop_end); + + void collect_guards(const exprt &expr); + void filter_template_domain(); void filter_equality_domain(); void filter_heap_domain(); From ccac6421bb4e3e7461fe0eeea8703148a7b0be70 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 04:29:24 +0530 Subject: [PATCH 283/322] Parse options for disjunctive domains --- src/2ls/2ls_parse_options.cpp | 25 +++++++++++++++++++++++++ src/2ls/2ls_parse_options.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index a9e8a3f76..4e1edf062 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -223,6 +223,25 @@ void twols_parse_optionst::get_command_line_options(optionst &options) if(cmdline.isset("sympath")) options.set_option("sympath", true); } + // disjunctive domains only work with inlined code for now + else if(cmdline.isset("disjunctive-intervals")) + { + options.set_option("disjunctive-intervals", true); + options.set_option("disjunctive_domains", true); + options.set_option("inline", true); + } + else if(cmdline.isset("disjunctive-zones")) + { + options.set_option("disjunctive-zones", true); + options.set_option("disjunctive_domains", true); + options.set_option("inline", true); + } + else if(cmdline.isset("disjunctive-octagons")) + { + options.set_option("disjunctive-octagons", true); + options.set_option("disjunctive_domains", true); + options.set_option("inline", true); + } else { if(cmdline.isset("zones")) @@ -534,6 +553,12 @@ int twols_parse_optionst::doit() status() << "Using heap domain with interval domain for values" << eom; else if(options.get_bool_option("heap-zones")) status() << "Using heap domain with zones domain for values" << eom; + else if(options.get_bool_option("disjunctive-intervals")) + status() << "Using disjunctive intervals domain" << eom; + else if(options.get_bool_option("disjunctive-zones")) + status() << "Using disjunctive zones domain" << eom; + else if(options.get_bool_option("disjunctive-octagons")) + status() << "Using disjunctive octagons domain" << eom; else { if(options.get_bool_option("intervals")) diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index 2199b95d3..5be2967d0 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -48,6 +48,9 @@ class optionst; "(heap-zones)" \ "(heap-values-refine)" \ "(sympath)" \ + "(disjunctive-intervals)" \ + "(disjunctive-zones)" \ + "(disjunctive-octagons)" \ "(enum-solver)(binsearch-solver)(arrays)"\ "(string-abstraction)(no-arch)(arch):(floatbv)(fixedbv)" \ "(round-to-nearest)(round-to-plus-inf)(round-to-minus-inf)(round-to-zero)" \ From fd7232c891c83d8220d636ed16e6f61420b34e43 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 04:52:45 +0530 Subject: [PATCH 284/322] Addded disjunct limit to parse options --- src/2ls/2ls_parse_options.cpp | 10 ++++++++++ src/2ls/2ls_parse_options.h | 1 + 2 files changed, 11 insertions(+) diff --git a/src/2ls/2ls_parse_options.cpp b/src/2ls/2ls_parse_options.cpp index 4e1edf062..b45bcfeb6 100644 --- a/src/2ls/2ls_parse_options.cpp +++ b/src/2ls/2ls_parse_options.cpp @@ -193,6 +193,10 @@ void twols_parse_optionst::get_command_line_options(optionst &options) if(cmdline.isset("error-label")) options.set_option("error-label", cmdline.get_value("error-label")); + // max disjunct + if (cmdline.isset("disjunct-limit")) + options.set_option("disjunct-limit", cmdline.get_value("disjunct-limit")); + if(cmdline.isset("havoc")) options.set_option("havoc", true); else if(cmdline.isset("equalities")) @@ -229,18 +233,24 @@ void twols_parse_optionst::get_command_line_options(optionst &options) options.set_option("disjunctive-intervals", true); options.set_option("disjunctive_domains", true); options.set_option("inline", true); + if (!cmdline.isset("disjunct-limit")) + options.set_option("disjunct-limit", 2); } else if(cmdline.isset("disjunctive-zones")) { options.set_option("disjunctive-zones", true); options.set_option("disjunctive_domains", true); options.set_option("inline", true); + if (!cmdline.isset("disjunct-limit")) + options.set_option("disjunct-limit", 2); } else if(cmdline.isset("disjunctive-octagons")) { options.set_option("disjunctive-octagons", true); options.set_option("disjunctive_domains", true); options.set_option("inline", true); + if (!cmdline.isset("disjunct-limit")) + options.set_option("disjunct-limit", 2); } else { diff --git a/src/2ls/2ls_parse_options.h b/src/2ls/2ls_parse_options.h index 5be2967d0..af55addab 100644 --- a/src/2ls/2ls_parse_options.h +++ b/src/2ls/2ls_parse_options.h @@ -51,6 +51,7 @@ class optionst; "(disjunctive-intervals)" \ "(disjunctive-zones)" \ "(disjunctive-octagons)" \ + "(disjunct-limit)" \ "(enum-solver)(binsearch-solver)(arrays)"\ "(string-abstraction)(no-arch)(arch):(floatbv)(fixedbv)" \ "(round-to-nearest)(round-to-plus-inf)(round-to-minus-inf)(round-to-zero)" \ From 0615727ec29dfb7f70f743dbd83737515f35f1fa Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 04:59:03 +0530 Subject: [PATCH 285/322] Guard collection & checks for disjunctive domains --- src/domains/template_generator_base.cpp | 97 +++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index a40b16fe3..944864272 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -21,6 +21,7 @@ Author: Peter Schrammel #include "heap_domain.h" #include "heap_tpolyhedra_domain.h" #include "heap_tpolyhedra_sympath_domain.h" +#include "disjunctive_domain.h" #ifdef DEBUG #include @@ -151,6 +152,7 @@ void template_generator_baset::collect_variables_loop( { // used for renaming map var_listt pre_state_vars, post_state_vars; + unsigned int loop_count=0; // add loop variables for(local_SSAt::nodest::const_iterator n_it=SSA.nodes.begin(); @@ -158,6 +160,18 @@ void template_generator_baset::collect_variables_loop( { if(n_it->loophead!=SSA.nodes.end()) // we've found a loop { + loop_present=true; + loop_count++; + if (options.get_bool_option("disjunctive_domains")) + { + assert(loop_count<=1); + } + + loophead_loc=n_it->loophead->location; + + //collect guards for paths + collect_guards(SSA,n_it->loophead,n_it); + exprt pre_guard, post_guard; get_pre_post_guards(SSA, n_it, pre_guard, post_guard); @@ -808,6 +822,45 @@ void template_generator_baset::instantiate_standard_domains( domain_ptr=new heap_tpolyhedra_domaint( domain_number, renaming_map, var_specs, SSA.ns, polyhedra_kind); } + else if (options.get_bool_option("disjunctive-intervals")) + { + filter_template_domain(); + disjunctive_domaint::template_kindt template_kind=disjunctive_domaint::TPOLYHEDRA; + disjunctive_domaint::lex_metrict tol(0,mp_integer(1)); + unsigned int max=options.get_unsigned_int_option("disjunct-limit"); + domain_ptr=new disjunctive_domaint( + domain_number,renaming_map,var_specs,SSA.ns,template_kind,max,tol); + + domaint *base_domain_ptr=static_cast(domain_ptr)->base_domain(); + static_cast(base_domain_ptr)->add_interval_template(var_specs,SSA.ns); + } + else if (options.get_bool_option("disjunctive-zones")) + { + filter_template_domain(); + disjunctive_domaint::template_kindt template_kind=disjunctive_domaint::TPOLYHEDRA; + disjunctive_domaint::lex_metrict tol(0,mp_integer(1)); + unsigned int max=options.get_unsigned_int_option("disjunct-limit"); + domain_ptr=new disjunctive_domaint( + domain_number,renaming_map,var_specs,SSA.ns,template_kind,max,tol); + + domaint *base_domain_ptr=static_cast(domain_ptr)->base_domain(); + static_cast(base_domain_ptr)->add_difference_template(var_specs,SSA.ns); + static_cast(base_domain_ptr)->add_interval_template(var_specs,SSA.ns); + } + else if (options.get_bool_option("disjunctive-octagons")) + { + filter_template_domain(); + disjunctive_domaint::template_kindt template_kind=disjunctive_domaint::TPOLYHEDRA; + disjunctive_domaint::lex_metrict tol(0,mp_integer(1)); + unsigned int max=options.get_unsigned_int_option("disjunct-limit"); + domain_ptr=new disjunctive_domaint( + domain_number,renaming_map,var_specs,SSA.ns,template_kind,max,tol); + + domaint *base_domain_ptr=static_cast(domain_ptr)->base_domain(); + static_cast(base_domain_ptr)->add_sum_template(var_specs,SSA.ns); + static_cast(base_domain_ptr)->add_difference_template(var_specs,SSA.ns); + static_cast(base_domain_ptr)->add_interval_template(var_specs,SSA.ns); + } } void template_generator_baset::filter_heap_interval_domain() @@ -863,3 +916,47 @@ std::vector template_generator_baset::collect_record_frees( } return result; } + +void template_generator_baset::collect_guards( + const local_SSAt &SSA, + local_SSAt::nodest::const_iterator loop_begin, + local_SSAt::nodest::const_iterator loop_end) +{ + auto n_it=loop_begin; + do + { + n_it++; + for (auto eq_it=n_it->equalities.begin();eq_it!=n_it->equalities.end();eq_it++) + { + std::string id=id2string(to_symbol_expr(eq_it->lhs()).get_identifier()); + if (id.find("phi")!=id.npos) + { + collect_guards(eq_it->rhs()); + } + } + } while (n_it!=loop_end); +} + +void template_generator_baset::collect_guards( + const exprt &expr) +{ + if(expr.id()==ID_if) + { + auto it=guards.begin(); + for (;it!=guards.end();it++) + { + if (*it==expr.op0()) + { + break; + } + } + if (it==guards.end()) + { + guards.push_back(expr.op0()); + } + } + forall_operands(it,expr) + { + collect_guards(*it); + } +} \ No newline at end of file From 6d50321963acb0476040c30f5b39cf9eeda43b7a Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 05:11:58 +0530 Subject: [PATCH 286/322] Added placeholder for get_disjunct_constraint --- src/domains/disjunctive_domain.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/domains/disjunctive_domain.cpp b/src/domains/disjunctive_domain.cpp index 8c5ee03cd..1f579b3a1 100644 --- a/src/domains/disjunctive_domain.cpp +++ b/src/domains/disjunctive_domain.cpp @@ -355,4 +355,10 @@ mp_integer disjunctive_domaint::distance(const constant_exprt &v1, const constan { assert(false); // types do not match or are not supported } -} \ No newline at end of file +} + +exprt disjunctive_domaint::get_disjunct_constraint(const disjunctt &d, const valuet &value) +{ + //TODO: implement actual disjunct constraint + return true_exprt(); +} From 618180d0884bd36345b8c390d87a756e531b4859 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 05:15:24 +0530 Subject: [PATCH 287/322] Disjunctive domain: added template generator to strategy solver --- src/domains/strategy_solver_disjunctive.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/domains/strategy_solver_disjunctive.h b/src/domains/strategy_solver_disjunctive.h index ee958b561..73a342212 100644 --- a/src/domains/strategy_solver_disjunctive.h +++ b/src/domains/strategy_solver_disjunctive.h @@ -12,6 +12,7 @@ Author: Johanan Wahlang #include #include "strategy_solver_base.h" #include "disjunctive_domain.h" +#include "template_generator_base.h" class strategy_solver_disjunctivet:public strategy_solver_baset { @@ -21,10 +22,12 @@ class strategy_solver_disjunctivet:public strategy_solver_baset disjunctive_domaint &_disjunctive_domain, incremental_solvert &_solver, local_SSAt &_SSA, - const namespacet &_ns): + const namespacet &_ns, + template_generator_baset &_template_generator): strategy_solver_baset(_solver, _ns), disjunctive_domain(_disjunctive_domain), - SSA(_SSA) + SSA(_SSA), + template_generator(_template_generator) { } @@ -40,6 +43,7 @@ class strategy_solver_disjunctivet:public strategy_solver_baset disjunctive_domaint &disjunctive_domain; local_SSAt &SSA; guardst guards; + template_generator_baset &template_generator; }; #endif //CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_DISJUNCTIVE_DOMAIN_H \ No newline at end of file From c84be79bd8229db4c7a64c48d6449ec7ad9aa944 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 05:18:55 +0530 Subject: [PATCH 288/322] Added disjunctive strategy solver to SSA analyzer --- src/domains/ssa_analyzer.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/domains/ssa_analyzer.cpp b/src/domains/ssa_analyzer.cpp index 72ad03b52..8a95f695d 100644 --- a/src/domains/ssa_analyzer.cpp +++ b/src/domains/ssa_analyzer.cpp @@ -34,6 +34,7 @@ Author: Peter Schrammel #include "strategy_solver_heap.h" #include "strategy_solver_heap_tpolyhedra.h" #include "strategy_solver_heap_tpolyhedra_sympath.h" +#include "strategy_solver_disjunctive.h" // NOLINTNEXTLINE(*) #define BINSEARCH_SOLVER strategy_solver_binsearcht(\ @@ -147,6 +148,13 @@ void ssa_analyzert::operator()( result=new heap_tpolyhedra_domaint::heap_tpolyhedra_valuet(); } } + else if(template_generator.options.get_bool_option("disjunctive-intervals") || + template_generator.options.get_bool_option("disjunctive-zones") || + template_generator.options.get_bool_option("disjunctive-octagons")) + { + strategy_solver=new strategy_solver_disjunctivet(*static_cast(domain),solver,SSA,SSA.ns,template_generator); + result=new disjunctive_domaint::disjunctive_valuet(); + } else { if(template_generator.options.get_bool_option("enum-solver")) From 22ded4202ff4133f067f0fce273c02500efcf9c1 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 05:32:35 +0530 Subject: [PATCH 289/322] Disjunctive domain: add check for presence of loop --- src/domains/strategy_solver_disjunctive.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 94c74c6f2..73c16c924 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -24,6 +24,9 @@ Function: strategy_solver_disjunctivet::iterate bool strategy_solver_disjunctivet::iterate( strategy_solver_baset::invariantt &_inv) { + // only iterate on loops for now + assert(template_generator.loop_present); + disjunctive_domaint::disjunctive_valuet &inv= static_cast(_inv); From 7c683a01af6cbe4a170761a5d0d7956935073cef Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 05:47:28 +0530 Subject: [PATCH 290/322] Disjunctive domain: enumerate all paths in the loop --- src/domains/strategy_solver_disjunctive.cpp | 42 +++++++++++++++++++++ src/domains/strategy_solver_disjunctive.h | 5 ++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 73c16c924..316a0b382 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -121,3 +121,45 @@ strategy_solver_disjunctivet::get_post( } return inv; } + +/*******************************************************************\ + +Function: strategy_solver_disjunctivet::enumerate_all_paths + + Inputs: + + Outputs: + + Purpose: Enumerate all paths inside the loop + +\*******************************************************************/ + +void strategy_solver_disjunctivet::enumerate_all_paths(guardst &guards) +{ + for (auto &guard : guards) + { + if (all_paths.empty()) + { + symbolic_patht p; + p.path_map[guard] = true; + all_paths.push_back(p); + p.path_map[guard] = false; + all_paths.push_back(p); + } + else + { + std::vector new_paths; + for (auto &path : all_paths) + { + symbolic_patht path_(path); + path.path_map[guard] = true; + path_.path_map[guard] = false; + new_paths.push_back(path_); + } + for (auto &path : new_paths) + { + all_paths.push_back(path); + } + } + } +} \ No newline at end of file diff --git a/src/domains/strategy_solver_disjunctive.h b/src/domains/strategy_solver_disjunctive.h index 73a342212..66d2c6d16 100644 --- a/src/domains/strategy_solver_disjunctive.h +++ b/src/domains/strategy_solver_disjunctive.h @@ -29,6 +29,7 @@ class strategy_solver_disjunctivet:public strategy_solver_baset SSA(_SSA), template_generator(_template_generator) { + enumerate_all_paths(template_generator.guards); } virtual bool iterate(invariantt &inv); @@ -42,8 +43,10 @@ class strategy_solver_disjunctivet:public strategy_solver_baset protected: disjunctive_domaint &disjunctive_domain; local_SSAt &SSA; - guardst guards; template_generator_baset &template_generator; + std::vector all_paths; + + void enumerate_all_paths(guardst &guards); }; #endif //CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_DISJUNCTIVE_DOMAIN_H \ No newline at end of file From 344a80fecfbe61a97c657488c2272363d042e288 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 05:50:34 +0530 Subject: [PATCH 291/322] Code refactoring --- src/domains/strategy_solver_disjunctive.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/domains/strategy_solver_disjunctive.h b/src/domains/strategy_solver_disjunctive.h index 66d2c6d16..425782f64 100644 --- a/src/domains/strategy_solver_disjunctive.h +++ b/src/domains/strategy_solver_disjunctive.h @@ -34,11 +34,6 @@ class strategy_solver_disjunctivet:public strategy_solver_baset virtual bool iterate(invariantt &inv); - disjunctive_domaint::unresolved_edget get_unresolved_edge( - const disjunctive_domaint::disjunctive_valuet &value); - invariantt get_post( - const disjunctive_domaint::unresolved_edget &e, - disjunctive_domaint::disjunctive_valuet &inv); protected: disjunctive_domaint &disjunctive_domain; @@ -47,6 +42,11 @@ class strategy_solver_disjunctivet:public strategy_solver_baset std::vector all_paths; void enumerate_all_paths(guardst &guards); + disjunctive_domaint::unresolved_edget get_unresolved_edge( + const disjunctive_domaint::disjunctive_valuet &value); + invariantt get_post( + const disjunctive_domaint::unresolved_edget &e, + disjunctive_domaint::disjunctive_valuet &inv); }; #endif //CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_DISJUNCTIVE_DOMAIN_H \ No newline at end of file From 013aaf781f342f432684cf6ed5d1d40e6719b150 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 05:57:33 +0530 Subject: [PATCH 292/322] Added initial strategy to disjunctive domain solver --- src/domains/strategy_solver_disjunctive.cpp | 25 +++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 316a0b382..107048077 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -32,6 +32,31 @@ bool strategy_solver_disjunctivet::iterate( bool improved=false; + // initial strategy + if (inv.size()==0) + { + if (disjunctive_domain.template_kind==disjunctive_domaint::TPOLYHEDRA) + { + auto result=tpolyhedra_domaint::templ_valuet(); + tpolyhedra_domaint *domain=static_cast(disjunctive_domain.base_domain()); + domain->initialize(result); + strategy_solver_enumerationt strategy_solver( + *domain,solver,ns); + strategy_solver.iterate(result); + inv.push_back(new tpolyhedra_domaint::templ_valuet(static_cast(result))); + + for (auto path : all_paths) + { + disjunctive_domaint::unresolved_edget e(0,path); + disjunctive_domain.unresolved_set.push_back(e); + } + } + else + { + assert(false); + } + } + disjunctive_domaint::unresolved_edget e=get_unresolved_edge(inv); if (e.disjunct==inv.size()) { From d86a34f3206c585b1514fc049160f410087040b6 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 06:09:31 +0530 Subject: [PATCH 293/322] Fixed get_unresolved_edge --- src/domains/strategy_solver_disjunctive.cpp | 30 +++++++++++++-------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 107048077..186e4d08f 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -85,33 +85,41 @@ disjunctive_domaint::unresolved_edget strategy_solver_disjunctivet::get_unresolved_edge( const disjunctive_domaint::disjunctive_valuet &value) { - disjunctive_domaint::unresolved_edget e; + disjunctive_domaint::unresolved_edget e(value.size(),symbolic_patht()); for (auto it=disjunctive_domain.unresolved_set.begin(); it!=disjunctive_domain.unresolved_set.end();) { solver.new_context(); - disjunctive_domaint::disjunctt d; - symbolic_patht p; - d = it->disjunct; - p = it->path; + disjunctive_domaint::disjunctt d=it->disjunct; + symbolic_patht p=it->path; - solver<(disjunctive_domain.base_domain()); + tpolyhedra_domaint::templ_valuet *v=static_cast(value[d]); + debug() << "Disjunct pre-constraint: " << eom; + debug() << from_expr(domain->to_pre_constraints(*v)) << eom << eom; + solver << domain->to_pre_constraints(*v); + } + debug() << "Path: " << from_expr(p.get_expr()) << eom; solver< Date: Fri, 17 May 2019 06:17:56 +0530 Subject: [PATCH 294/322] Fixed post computation --- src/domains/strategy_solver_disjunctive.cpp | 33 ++++++++++++++------- src/domains/strategy_solver_disjunctive.h | 7 +++-- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 186e4d08f..f4f4068c8 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -64,7 +64,12 @@ bool strategy_solver_disjunctivet::iterate( return improved; } - invariantt post=get_post(e,inv); + disjunctive_domaint::disjunctt d_src=e.disjunct; + disjunctive_domaint::disjunctt d_sink; + symbolic_patht p=e.path; + + invariantt *post=new tpolyhedra_domaint::templ_valuet(*static_cast(inv[d_src])); + get_post(p,inv, post); return improved; } @@ -134,25 +139,31 @@ Function: strategy_solver_disjunctivet::get_post \*******************************************************************/ -strategy_solver_disjunctivet::invariantt -strategy_solver_disjunctivet::get_post( - const disjunctive_domaint::unresolved_edget &e, - disjunctive_domaint::disjunctive_valuet &_inv) +void strategy_solver_disjunctivet::get_post( + const symbolic_patht &p, + const disjunctive_domaint::disjunctive_valuet &pre_inv, + invariantt *post_inv) { + debug() << "Computing post" << eom; domaint *_domain=disjunctive_domain.base_domain(); - disjunctive_domaint::disjunctt d=e.disjunct; - symbolic_patht p=e.path; - strategy_solver_baset::invariantt inv=*_inv[d]; + debug() << "--------------------------------------------------" << eom; if (disjunctive_domain.get_template_kind()==disjunctive_domaint::TPOLYHEDRA) { - tpolyhedra_domaint domain=*static_cast(_domain); + tpolyhedra_domaint domain(*static_cast(_domain)); domain.restrict_to_sympath(p); strategy_solver_enumerationt strategy_solver( domain,solver,ns); - strategy_solver.iterate(inv); + domain.output_value(debug(),*post_inv,ns); + debug() << "-------------------------------------------------" << eom; + strategy_solver.iterate(*post_inv); + domain.output_value(debug(),*post_inv,ns); + debug() << "--------------------------------------------------" << eom; domain.undo_restriction(); } - return inv; + else + { + assert(false); + } } /*******************************************************************\ diff --git a/src/domains/strategy_solver_disjunctive.h b/src/domains/strategy_solver_disjunctive.h index 425782f64..392c64467 100644 --- a/src/domains/strategy_solver_disjunctive.h +++ b/src/domains/strategy_solver_disjunctive.h @@ -44,9 +44,10 @@ class strategy_solver_disjunctivet:public strategy_solver_baset void enumerate_all_paths(guardst &guards); disjunctive_domaint::unresolved_edget get_unresolved_edge( const disjunctive_domaint::disjunctive_valuet &value); - invariantt get_post( - const disjunctive_domaint::unresolved_edget &e, - disjunctive_domaint::disjunctive_valuet &inv); + void get_post( + const symbolic_patht &p, + const disjunctive_domaint::disjunctive_valuet &pre_inv, + invariantt *post_inv); }; #endif //CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_DISJUNCTIVE_DOMAIN_H \ No newline at end of file From 5908939fa030285df1aa795ed13fb624f45772ae Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 07:02:50 +0530 Subject: [PATCH 295/322] Disjunctive domain: implemented merge --- src/domains/strategy_solver_disjunctive.cpp | 24 ++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index f4f4068c8..3a6b1de02 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -67,10 +67,32 @@ bool strategy_solver_disjunctivet::iterate( disjunctive_domaint::disjunctt d_src=e.disjunct; disjunctive_domaint::disjunctt d_sink; symbolic_patht p=e.path; - + invariantt *post=new tpolyhedra_domaint::templ_valuet(*static_cast(inv[d_src])); get_post(p,inv, post); + disjunctive_domaint::disjunctt d=disjunctive_domain.merge_heuristic(inv, *post); + + if (d==inv.size()) + { + if (disjunctive_domain.template_kind==disjunctive_domaint::TPOLYHEDRA) + { + inv.push_back(new tpolyhedra_domaint::templ_valuet(*static_cast(post))); + } + // TODO: add loop head + } + else + { + d_sink=d; + if (disjunctive_domain.template_kind==disjunctive_domaint::TPOLYHEDRA) + { + tpolyhedra_domaint *domain=static_cast(disjunctive_domain.base_domain_ptr); + domain->join(*inv[d_sink],*post); // join value + } + // TODO: add loop body + } + // TODO: create new template + return improved; } From adfcefd6047a8f6032ed80a5663e6215243e4c0a Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 07:20:32 +0530 Subject: [PATCH 296/322] Code refactoring --- src/domains/strategy_solver_disjunctive.cpp | 68 ++++++++++----------- src/domains/strategy_solver_disjunctive.h | 1 + 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 3a6b1de02..995f9fb23 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -32,18 +32,21 @@ bool strategy_solver_disjunctivet::iterate( bool improved=false; - // initial strategy - if (inv.size()==0) + if (disjunctive_domain.template_kind==disjunctive_domaint::TPOLYHEDRA) { - if (disjunctive_domain.template_kind==disjunctive_domaint::TPOLYHEDRA) + tpolyhedra_domaint *domain=static_cast(disjunctive_domain.base_domain()); + + // initial strategy + if (inv.size()==0) { auto result=tpolyhedra_domaint::templ_valuet(); - tpolyhedra_domaint *domain=static_cast(disjunctive_domain.base_domain()); domain->initialize(result); strategy_solver_enumerationt strategy_solver( *domain,solver,ns); strategy_solver.iterate(result); - inv.push_back(new tpolyhedra_domaint::templ_valuet(static_cast(result))); + inv.push_back( + new tpolyhedra_domaint::templ_valuet( + static_cast(result))); for (auto path : all_paths) { @@ -51,47 +54,44 @@ bool strategy_solver_disjunctivet::iterate( disjunctive_domain.unresolved_set.push_back(e); } } - else + + disjunctive_domaint::unresolved_edget e=get_unresolved_edge(inv); + if (e.disjunct==inv.size()) { - assert(false); + // no more unresolved edges + return improved; } - } - disjunctive_domaint::unresolved_edget e=get_unresolved_edge(inv); - if (e.disjunct==inv.size()) - { - // no more unresolved edges - return improved; - } + disjunctive_domaint::disjunctt d_src=e.disjunct; + disjunctive_domaint::disjunctt d_sink; + symbolic_patht p=e.path; - disjunctive_domaint::disjunctt d_src=e.disjunct; - disjunctive_domaint::disjunctt d_sink; - symbolic_patht p=e.path; + tpolyhedra_domaint::templ_valuet *post= + new tpolyhedra_domaint::templ_valuet( + *static_cast(inv[d_src])); + + get_post(p,inv, post); - invariantt *post=new tpolyhedra_domaint::templ_valuet(*static_cast(inv[d_src])); - get_post(p,inv, post); + d_sink=disjunctive_domain.merge_heuristic(inv, *post); - disjunctive_domaint::disjunctt d=disjunctive_domain.merge_heuristic(inv, *post); - - if (d==inv.size()) - { - if (disjunctive_domain.template_kind==disjunctive_domaint::TPOLYHEDRA) + if (d_sink==inv.size()) { - inv.push_back(new tpolyhedra_domaint::templ_valuet(*static_cast(post))); + inv.push_back( + new tpolyhedra_domaint::templ_valuet( + *static_cast(post))); } - // TODO: add loop head - } - else - { - d_sink=d; - if (disjunctive_domain.template_kind==disjunctive_domaint::TPOLYHEDRA) + else { - tpolyhedra_domaint *domain=static_cast(disjunctive_domain.base_domain_ptr); domain->join(*inv[d_sink],*post); // join value + // TODO: add loop body } - // TODO: add loop body + // TODO: create new template + } + else + { + // TODO: implement disjuntive strategy solver for other base domains + assert(false); } - // TODO: create new template return improved; } diff --git a/src/domains/strategy_solver_disjunctive.h b/src/domains/strategy_solver_disjunctive.h index 392c64467..77eabf582 100644 --- a/src/domains/strategy_solver_disjunctive.h +++ b/src/domains/strategy_solver_disjunctive.h @@ -18,6 +18,7 @@ class strategy_solver_disjunctivet:public strategy_solver_baset { public: typedef std::vector guardst; + strategy_solver_disjunctivet( disjunctive_domaint &_disjunctive_domain, incremental_solvert &_solver, From 0eb18fbe7396ec7fb46d467aeec4b12041a8e6b7 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 07:45:32 +0530 Subject: [PATCH 297/322] Disjunctive domain: added loop --- src/domains/strategy_solver_disjunctive.cpp | 86 ++++++++++++++++++++- src/domains/strategy_solver_disjunctive.h | 29 ++++++- 2 files changed, 113 insertions(+), 2 deletions(-) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 995f9fb23..fa553310d 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -228,4 +228,88 @@ void strategy_solver_disjunctivet::enumerate_all_paths(guardst &guards) } } } -} \ No newline at end of file +} + +/*******************************************************************\ + +Function: strategy_solver_disjunctivet::find_loop + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool strategy_solver_disjunctivet::find_loop( + local_SSAt::locationt &loophead_loc, loopt *loop) +{ + local_SSAt::nodest::iterator n_it=SSA.find_node(loophead_loc); + if (n_it==SSA.nodes.end()) + return false; + loop->body_nodes.push_back(*n_it); + auto &node=loop->body_nodes.back(); + for (local_SSAt::nodet::equalitiest::iterator eq_it=node.equalities.begin(); + eq_it!=node.equalities.end();eq_it++) + { + loop->add_loophead_objects(*eq_it); + } + + for (n_it++;n_it->loophead->location!=loophead_loc;n_it++) + { + loop->body_nodes.push_back(*n_it); + } + + return true; +} + +/*******************************************************************\ + +Function: strategy_solver_disjunctivet::loopt::add_loophead_object + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void strategy_solver_disjunctivet::loopt::add_loophead_objects(exprt expr) +{ + if(expr.id()==ID_symbol || + expr.id()==ID_nondet_symbol) + { + irep_idt id=expr.get(ID_identifier); + if (find_loophead_object(id)==loophead_objects.end()) + loophead_objects.push_back(id); + } + Forall_operands(it, expr) + add_loophead_objects(*it); +} + +/*******************************************************************\ + +Function: strategy_solver_disjunctivet::loopt::find_loophead_object + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +std::vector::iterator + strategy_solver_disjunctivet::loopt::find_loophead_object( + const irep_idt &id) +{ + std::vector::iterator it=loophead_objects.begin(); + for (;it!=loophead_objects.end();it++) + { + if (*it==id) + break; + } + return it; +} diff --git a/src/domains/strategy_solver_disjunctive.h b/src/domains/strategy_solver_disjunctive.h index 77eabf582..95f396a0d 100644 --- a/src/domains/strategy_solver_disjunctive.h +++ b/src/domains/strategy_solver_disjunctive.h @@ -17,6 +17,19 @@ Author: Johanan Wahlang class strategy_solver_disjunctivet:public strategy_solver_baset { public: + class loopt + { + public: + loopt(): + body_nodes() + { + } + local_SSAt::nodest body_nodes; + std::vector loophead_objects; + std::vector::iterator find_loophead_object(const irep_idt &id); + void add_loophead_objects(exprt expr); + }; + typedef std::vector guardst; strategy_solver_disjunctivet( @@ -28,9 +41,18 @@ class strategy_solver_disjunctivet:public strategy_solver_baset strategy_solver_baset(_solver, _ns), disjunctive_domain(_disjunctive_domain), SSA(_SSA), - template_generator(_template_generator) + template_generator(_template_generator), + current_count(0) { enumerate_all_paths(template_generator.guards); + + assert(template_generator.loop_present); + + loop=new loopt(); + assert(find_loop(template_generator.loophead_loc,loop)); + + loop_copies=new local_SSAt::nodest(); + loopheads=new local_SSAt::nodest(); } virtual bool iterate(invariantt &inv); @@ -41,6 +63,10 @@ class strategy_solver_disjunctivet:public strategy_solver_baset local_SSAt &SSA; template_generator_baset &template_generator; std::vector all_paths; + local_SSAt::nodest *loop_copies; + local_SSAt::nodest *loopheads; + loopt *loop; + unsigned int current_count; void enumerate_all_paths(guardst &guards); disjunctive_domaint::unresolved_edget get_unresolved_edge( @@ -49,6 +75,7 @@ class strategy_solver_disjunctivet:public strategy_solver_baset const symbolic_patht &p, const disjunctive_domaint::disjunctive_valuet &pre_inv, invariantt *post_inv); + bool find_loop(local_SSAt::locationt &loophead_loc, loopt *loop); }; #endif //CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_DISJUNCTIVE_DOMAIN_H \ No newline at end of file From a3f032b33bc4d6879dd326f0e25bc5dcc1b8e449 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 08:08:16 +0530 Subject: [PATCH 298/322] Renaming for loop copies --- src/domains/strategy_solver_disjunctive.cpp | 34 +++++++++++++++++++++ src/domains/strategy_solver_disjunctive.h | 1 + 2 files changed, 35 insertions(+) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index fa553310d..c612a7d1e 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -313,3 +313,37 @@ std::vector::iterator } return it; } + +/*******************************************************************\ + +Function: strategy_solver_disjunctivet::rename + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void strategy_solver_disjunctivet::rename( + exprt &expr, + const std::string &suffix, + disjunctive_domaint::disjunctt d_src) +{ + if(expr.id()==ID_symbol || + expr.id()==ID_nondet_symbol) + { + irep_idt id=expr.get(ID_identifier); + if (loop->find_loophead_object(id)!=loop->loophead_objects.end()) + { + expr.set(ID_identifier,id2string(id)+"_"+std::to_string(d_src)); + } + else + { + expr.set(ID_identifier,id2string(id)+suffix); + } + } + Forall_operands(it, expr) + rename(*it, suffix, d_src); +} diff --git a/src/domains/strategy_solver_disjunctive.h b/src/domains/strategy_solver_disjunctive.h index 95f396a0d..a72735523 100644 --- a/src/domains/strategy_solver_disjunctive.h +++ b/src/domains/strategy_solver_disjunctive.h @@ -76,6 +76,7 @@ class strategy_solver_disjunctivet:public strategy_solver_baset const disjunctive_domaint::disjunctive_valuet &pre_inv, invariantt *post_inv); bool find_loop(local_SSAt::locationt &loophead_loc, loopt *loop); + void rename(exprt &expr, const std::string &suffix, disjunctive_domaint::disjunctt d_src); }; #endif //CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_DISJUNCTIVE_DOMAIN_H \ No newline at end of file From 31c41f56021bfbe0780d2f076f7feb0d78f7634d Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 08:33:00 +0530 Subject: [PATCH 299/322] Disjunctive domain: add loophead SSA for new replications --- src/domains/strategy_solver_disjunctive.cpp | 27 +++++++++++++++++++++ src/domains/strategy_solver_disjunctive.h | 1 + 2 files changed, 28 insertions(+) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index c612a7d1e..40a0ffb12 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -47,6 +47,7 @@ bool strategy_solver_disjunctivet::iterate( inv.push_back( new tpolyhedra_domaint::templ_valuet( static_cast(result))); + add_loophead(0); // SSA loophead for first disjunct for (auto path : all_paths) { @@ -79,6 +80,7 @@ bool strategy_solver_disjunctivet::iterate( inv.push_back( new tpolyhedra_domaint::templ_valuet( *static_cast(post))); + add_loophead(d_sink); // SSA loophead for new disjunct } else { @@ -347,3 +349,28 @@ void strategy_solver_disjunctivet::rename( Forall_operands(it, expr) rename(*it, suffix, d_src); } + +/*******************************************************************\ + +Function: strategy_solver_disjunctivet::add_loophead + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void strategy_solver_disjunctivet::add_loophead( + disjunctive_domaint::disjunctt d) +{ + local_SSAt::nodest::iterator n_it=loop->body_nodes.begin(); + loopheads->push_back(*n_it); + local_SSAt::nodet &node=loopheads->back(); + for (auto eq:node.equalities) + { + rename(eq,"",d); + solver << eq; + } +} diff --git a/src/domains/strategy_solver_disjunctive.h b/src/domains/strategy_solver_disjunctive.h index a72735523..2aafab8ae 100644 --- a/src/domains/strategy_solver_disjunctive.h +++ b/src/domains/strategy_solver_disjunctive.h @@ -77,6 +77,7 @@ class strategy_solver_disjunctivet:public strategy_solver_baset invariantt *post_inv); bool find_loop(local_SSAt::locationt &loophead_loc, loopt *loop); void rename(exprt &expr, const std::string &suffix, disjunctive_domaint::disjunctt d_src); + void add_loophead(disjunctive_domaint::disjunctt d); }; #endif //CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_DISJUNCTIVE_DOMAIN_H \ No newline at end of file From 33a62ad4677ba3d46da147abf06f96a67f0daa0e Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 17:26:12 +0530 Subject: [PATCH 300/322] Disjunctive domain: add loop body after computing post --- src/domains/strategy_solver_disjunctive.cpp | 52 ++++++++++++++++++++- src/domains/strategy_solver_disjunctive.h | 4 ++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 40a0ffb12..3ad8664ac 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -85,8 +85,8 @@ bool strategy_solver_disjunctivet::iterate( else { domain->join(*inv[d_sink],*post); // join value - // TODO: add loop body } + add_edge(d_src,p,d_sink); // TODO: create new template } else @@ -374,3 +374,53 @@ void strategy_solver_disjunctivet::add_loophead( solver << eq; } } + +/*******************************************************************\ + +Function: strategy_solver_disjunctivet::add_edge + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void strategy_solver_disjunctivet::add_edge( + disjunctive_domaint::disjunctt d_src, + symbolic_patht &p, + disjunctive_domaint::disjunctt d_sink) +{ + debug() << "Adding new SSA nodes" << eom; + disjunctive_domaint::disjunctt _d_src,_d_sink; + symbolic_patht _p; + local_SSAt::nodest::iterator n_it=loop->body_nodes.begin(); + std::string suffix="_"+std::to_string(current_count); + for (n_it++;n_it!=loop->body_nodes.end();n_it++) + { + if (n_it->equalities.empty() && + n_it->constraints.empty() && + n_it->function_calls.empty()) + continue; + + loop_copies->push_back(*n_it); + auto &node=loop_copies->back(); + for (local_SSAt::nodet::equalitiest::iterator e_it=node.equalities.begin(); + e_it!=node.equalities.end();e_it++) + { + rename(*e_it,suffix,d_src); + } + for (local_SSAt::nodet::constraintst::iterator c_it=node.constraints.begin(); + c_it!=node.constraints.end();c_it++) + { + rename(*c_it,suffix,d_src); + } + for (local_SSAt::nodet::function_callst::iterator f_it=node.function_calls.begin(); + f_it!=node.function_calls.end();f_it) + { + rename(*f_it,suffix,d_src); + } + } + current_count++; +} diff --git a/src/domains/strategy_solver_disjunctive.h b/src/domains/strategy_solver_disjunctive.h index 2aafab8ae..8401f5e71 100644 --- a/src/domains/strategy_solver_disjunctive.h +++ b/src/domains/strategy_solver_disjunctive.h @@ -78,6 +78,10 @@ class strategy_solver_disjunctivet:public strategy_solver_baset bool find_loop(local_SSAt::locationt &loophead_loc, loopt *loop); void rename(exprt &expr, const std::string &suffix, disjunctive_domaint::disjunctt d_src); void add_loophead(disjunctive_domaint::disjunctt d); + void add_edge( + disjunctive_domaint::disjunctt d_src, + symbolic_patht &p, + disjunctive_domaint::disjunctt d_sink); }; #endif //CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_DISJUNCTIVE_DOMAIN_H \ No newline at end of file From b2d8301c5c3e05df67e1b6938995c52e466647de Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 17:27:45 +0530 Subject: [PATCH 301/322] printing --- src/domains/strategy_solver_disjunctive.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 3ad8664ac..19ca99577 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -178,10 +178,10 @@ void strategy_solver_disjunctivet::get_post( strategy_solver_enumerationt strategy_solver( domain,solver,ns); domain.output_value(debug(),*post_inv,ns); - debug() << "-------------------------------------------------" << eom; + debug() << "-------------------------------------------------" << eom << eom; strategy_solver.iterate(*post_inv); domain.output_value(debug(),*post_inv,ns); - debug() << "--------------------------------------------------" << eom; + debug() << "--------------------------------------------------" << eom << eom; domain.undo_restriction(); } else From c3811d275176e65fccc186f1c654835e0328b68f Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 17:29:06 +0530 Subject: [PATCH 302/322] Fixed improvement --- src/domains/strategy_solver_disjunctive.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 19ca99577..b4c9f2951 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -63,6 +63,8 @@ bool strategy_solver_disjunctivet::iterate( return improved; } + improved=true; // found an unresolved edge + disjunctive_domaint::disjunctt d_src=e.disjunct; disjunctive_domaint::disjunctt d_sink; symbolic_patht p=e.path; From db454a6ceb8ec3cf48d199521a28464ed18aed60 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 17:29:31 +0530 Subject: [PATCH 303/322] Fixed renaming for loopheads --- src/domains/strategy_solver_disjunctive.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index b4c9f2951..dc533a3da 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -370,7 +370,7 @@ void strategy_solver_disjunctivet::add_loophead( local_SSAt::nodest::iterator n_it=loop->body_nodes.begin(); loopheads->push_back(*n_it); local_SSAt::nodet &node=loopheads->back(); - for (auto eq:node.equalities) + for (auto &eq:node.equalities) { rename(eq,"",d); solver << eq; From 355054635b8d08cb9a48fa9de9d3d08d58a27a64 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 18:09:04 +0530 Subject: [PATCH 304/322] Add unresolved edges for new replications --- src/domains/strategy_solver_disjunctive.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index dc533a3da..453deeda3 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -83,6 +83,11 @@ bool strategy_solver_disjunctivet::iterate( new tpolyhedra_domaint::templ_valuet( *static_cast(post))); add_loophead(d_sink); // SSA loophead for new disjunct + for (auto path : all_paths) + { + disjunctive_domaint::unresolved_edget e(d_sink,path); + disjunctive_domain.unresolved_set.push_back(e); + } } else { From fa42b7c071ef07e13e5277c637e4bb4f671842c5 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 18:10:22 +0530 Subject: [PATCH 305/322] Code refactoring --- src/domains/strategy_solver_disjunctive.cpp | 60 ++++++++++++++------- src/domains/strategy_solver_disjunctive.h | 4 ++ 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 453deeda3..32986e908 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -39,21 +39,12 @@ bool strategy_solver_disjunctivet::iterate( // initial strategy if (inv.size()==0) { - auto result=tpolyhedra_domaint::templ_valuet(); + tpolyhedra_domaint::templ_valuet result; domain->initialize(result); strategy_solver_enumerationt strategy_solver( *domain,solver,ns); strategy_solver.iterate(result); - inv.push_back( - new tpolyhedra_domaint::templ_valuet( - static_cast(result))); - add_loophead(0); // SSA loophead for first disjunct - - for (auto path : all_paths) - { - disjunctive_domaint::unresolved_edget e(0,path); - disjunctive_domain.unresolved_set.push_back(e); - } + add_new_replication(inv,0,result); } disjunctive_domaint::unresolved_edget e=get_unresolved_edge(inv); @@ -79,15 +70,7 @@ bool strategy_solver_disjunctivet::iterate( if (d_sink==inv.size()) { - inv.push_back( - new tpolyhedra_domaint::templ_valuet( - *static_cast(post))); - add_loophead(d_sink); // SSA loophead for new disjunct - for (auto path : all_paths) - { - disjunctive_domaint::unresolved_edget e(d_sink,path); - disjunctive_domain.unresolved_set.push_back(e); - } + add_new_replication(inv,d_sink,*post); } else { @@ -107,6 +90,43 @@ bool strategy_solver_disjunctivet::iterate( /*******************************************************************\ +Function: strategy_solver_disjunctivet::add_new_replication + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void strategy_solver_disjunctivet::add_new_replication( + disjunctive_domaint::disjunctive_valuet &inv, + const disjunctive_domaint::disjunctt d, + const invariantt &value) +{ + if (disjunctive_domain.template_kind==disjunctive_domaint::TPOLYHEDRA) + { + inv.push_back( + new tpolyhedra_domaint::templ_valuet( + static_cast(value))); + + add_loophead(d); // SSA loophead for new disjunct + + for (auto path : all_paths) + { + disjunctive_domaint::unresolved_edget e(d,path); + disjunctive_domain.unresolved_set.push_back(e); + } + } + else + { + assert(false); + } +} + +/*******************************************************************\ + Function: strategy_solver_disjunctivet::get_unresolved_edge Inputs: diff --git a/src/domains/strategy_solver_disjunctive.h b/src/domains/strategy_solver_disjunctive.h index 8401f5e71..359a382e9 100644 --- a/src/domains/strategy_solver_disjunctive.h +++ b/src/domains/strategy_solver_disjunctive.h @@ -69,6 +69,10 @@ class strategy_solver_disjunctivet:public strategy_solver_baset unsigned int current_count; void enumerate_all_paths(guardst &guards); + void add_new_replication( + disjunctive_domaint::disjunctive_valuet &inv, + const disjunctive_domaint::disjunctt d, + const invariantt &value); disjunctive_domaint::unresolved_edget get_unresolved_edge( const disjunctive_domaint::disjunctive_valuet &value); void get_post( From 80a4ebb12e41ad15349c7efa90bb10d18d180ac3 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Fri, 17 May 2019 18:53:55 +0530 Subject: [PATCH 306/322] Destructor for disjunctive template --- src/domains/disjunctive_domain.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/domains/disjunctive_domain.h b/src/domains/disjunctive_domain.h index cf807220d..81a4ba812 100644 --- a/src/domains/disjunctive_domain.h +++ b/src/domains/disjunctive_domain.h @@ -144,6 +144,14 @@ class disjunctive_domaint:public domaint { if (base_domain_ptr!=NULL) delete base_domain_ptr; + for (auto &i:templ) + { + for (auto &j:i.second) + { + if (j.second!=NULL) + delete j.second; + } + } } virtual void initialize(valuet &value); From 7167440903720bd262d0dd9c6837c8390d207ccc Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 18 May 2019 03:07:30 +0530 Subject: [PATCH 307/322] Code refactoring for rename --- src/domains/strategy_solver_disjunctive.cpp | 21 +++++++++++---------- src/domains/strategy_solver_disjunctive.h | 4 +++- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 32986e908..643636805 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -357,8 +357,8 @@ Function: strategy_solver_disjunctivet::rename void strategy_solver_disjunctivet::rename( exprt &expr, - const std::string &suffix, - disjunctive_domaint::disjunctt d_src) + const std::string &src_suffix="", + const std::string &sink_suffix="") { if(expr.id()==ID_symbol || expr.id()==ID_nondet_symbol) @@ -366,15 +366,15 @@ void strategy_solver_disjunctivet::rename( irep_idt id=expr.get(ID_identifier); if (loop->find_loophead_object(id)!=loop->loophead_objects.end()) { - expr.set(ID_identifier,id2string(id)+"_"+std::to_string(d_src)); + expr.set(ID_identifier,id2string(id)+src_suffix); } else { - expr.set(ID_identifier,id2string(id)+suffix); + expr.set(ID_identifier,id2string(id)+sink_suffix); } } Forall_operands(it, expr) - rename(*it, suffix, d_src); + rename(*it,src_suffix,sink_suffix); } /*******************************************************************\ @@ -397,7 +397,7 @@ void strategy_solver_disjunctivet::add_loophead( local_SSAt::nodet &node=loopheads->back(); for (auto &eq:node.equalities) { - rename(eq,"",d); + rename(eq,"_"+std::to_string(d),""); solver << eq; } } @@ -423,7 +423,8 @@ void strategy_solver_disjunctivet::add_edge( disjunctive_domaint::disjunctt _d_src,_d_sink; symbolic_patht _p; local_SSAt::nodest::iterator n_it=loop->body_nodes.begin(); - std::string suffix="_"+std::to_string(current_count); + std::string sink_suffix="_"+std::to_string(current_count); + std::string src_suffix="_"+std::to_string(d_src); for (n_it++;n_it!=loop->body_nodes.end();n_it++) { if (n_it->equalities.empty() && @@ -436,17 +437,17 @@ void strategy_solver_disjunctivet::add_edge( for (local_SSAt::nodet::equalitiest::iterator e_it=node.equalities.begin(); e_it!=node.equalities.end();e_it++) { - rename(*e_it,suffix,d_src); + rename(*e_it,src_suffix,sink_suffix); } for (local_SSAt::nodet::constraintst::iterator c_it=node.constraints.begin(); c_it!=node.constraints.end();c_it++) { - rename(*c_it,suffix,d_src); + rename(*c_it,src_suffix,sink_suffix); } for (local_SSAt::nodet::function_callst::iterator f_it=node.function_calls.begin(); f_it!=node.function_calls.end();f_it) { - rename(*f_it,suffix,d_src); + rename(*f_it,src_suffix,sink_suffix); } } current_count++; diff --git a/src/domains/strategy_solver_disjunctive.h b/src/domains/strategy_solver_disjunctive.h index 359a382e9..eddce1a45 100644 --- a/src/domains/strategy_solver_disjunctive.h +++ b/src/domains/strategy_solver_disjunctive.h @@ -80,7 +80,9 @@ class strategy_solver_disjunctivet:public strategy_solver_baset const disjunctive_domaint::disjunctive_valuet &pre_inv, invariantt *post_inv); bool find_loop(local_SSAt::locationt &loophead_loc, loopt *loop); - void rename(exprt &expr, const std::string &suffix, disjunctive_domaint::disjunctt d_src); + void rename(exprt &expr, + const std::string &src_suffix, + const std::string &sink_suffix); void add_loophead(disjunctive_domaint::disjunctt d); void add_edge( disjunctive_domaint::disjunctt d_src, From 133a49a918763abea74f25706c587a0173932e8c Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 18 May 2019 03:08:23 +0530 Subject: [PATCH 308/322] Code refactoring and whitespace --- src/domains/strategy_solver_disjunctive.cpp | 2 +- src/domains/strategy_solver_disjunctive.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 643636805..1bfe5cb8e 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -416,7 +416,7 @@ Function: strategy_solver_disjunctivet::add_edge void strategy_solver_disjunctivet::add_edge( disjunctive_domaint::disjunctt d_src, - symbolic_patht &p, + const symbolic_patht &p, disjunctive_domaint::disjunctt d_sink) { debug() << "Adding new SSA nodes" << eom; diff --git a/src/domains/strategy_solver_disjunctive.h b/src/domains/strategy_solver_disjunctive.h index eddce1a45..1be2ba2de 100644 --- a/src/domains/strategy_solver_disjunctive.h +++ b/src/domains/strategy_solver_disjunctive.h @@ -57,7 +57,6 @@ class strategy_solver_disjunctivet:public strategy_solver_baset virtual bool iterate(invariantt &inv); - protected: disjunctive_domaint &disjunctive_domain; local_SSAt &SSA; @@ -86,7 +85,7 @@ class strategy_solver_disjunctivet:public strategy_solver_baset void add_loophead(disjunctive_domaint::disjunctt d); void add_edge( disjunctive_domaint::disjunctt d_src, - symbolic_patht &p, + const symbolic_patht &p, disjunctive_domaint::disjunctt d_sink); }; From df4aa6747a3ccfa5a01d3edd5c2e94a4123cdeb7 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 18 May 2019 04:42:07 +0530 Subject: [PATCH 309/322] Disjunctive domain solver: add new templates corresponding to each edge --- src/domains/strategy_solver_disjunctive.cpp | 63 +++++++++++++++++++++ src/domains/tpolyhedra_domain.h | 1 + 2 files changed, 64 insertions(+) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 1bfe5cb8e..691632143 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -450,5 +450,68 @@ void strategy_solver_disjunctivet::add_edge( rename(*f_it,src_suffix,sink_suffix); } } + + // add new edge to seen set + disjunctive_domaint::seen_edget new_edge(d_src,p,d_sink); + disjunctive_domain.seen_set.push_back(new_edge); + + // add new template corresponding to new edge + if (disjunctive_domain.template_kind==disjunctive_domaint::TPOLYHEDRA) + { + tpolyhedra_domaint *base_domain=static_cast(disjunctive_domain.base_domain()); + replace_mapt new_renaming_map; // renaming map for new domain + replace_mapt map; // map from base domain exprts to new domain exprts + for (auto &x:disjunctive_domain.renaming_map) + { + exprt pre_var=x.first; + exprt post_var=x.second; + new_renaming_map[pre_var]=post_var; // keep old renaming map for non-LOOP vars + rename(pre_var,src_suffix,sink_suffix); + rename(post_var,src_suffix,sink_suffix); + new_renaming_map[pre_var]=post_var; + map[x.first]=pre_var; + } + + tpolyhedra_domaint *new_domain=new tpolyhedra_domaint(disjunctive_domain.domain_number,new_renaming_map,ns); + + for (auto &row:base_domain->templ) + { + exprt pre_guard=row.pre_guard; + exprt aux_expr=row.aux_expr; + exprt post_guard=row.post_guard; + exprt expr=row.expr; + if (row.kind==tpolyhedra_domaint::kindt::LOOP) + { + if (map.find(row.pre_guard)==map.end()) + { + rename(pre_guard,src_suffix,sink_suffix); + map[row.pre_guard]=pre_guard; + } + if (map.find(row.aux_expr)==map.end()) + { + rename(aux_expr,src_suffix,sink_suffix); + map[row.aux_expr]=aux_expr; + } + if (map.find(row.post_guard)==map.end()) + { + rename(post_guard,src_suffix,sink_suffix); + map[row.post_guard]=post_guard; + } + replace_expr(map,expr); + pre_guard=map[row.pre_guard]; + post_guard=map[row.post_guard]; + aux_expr=map[row.aux_expr]; + } + new_domain->add_template_row(expr,pre_guard,post_guard,aux_expr,row.kind); + } + + // domains are sorted by sink, then source + disjunctive_domain.templ[d_sink][d_src]=new_domain; + } + else + { + assert(false); + } + current_count++; } diff --git a/src/domains/tpolyhedra_domain.h b/src/domains/tpolyhedra_domain.h index 42ca064c1..c51c1ddb8 100644 --- a/src/domains/tpolyhedra_domain.h +++ b/src/domains/tpolyhedra_domain.h @@ -147,6 +147,7 @@ class tpolyhedra_domaint:public domaint protected: friend class strategy_solver_binsearcht; friend class strategy_solver_enumerationt; + friend class strategy_solver_disjunctivet; templatet templ; }; From cda87693f4eb6632ed2d2d161962f5559ef642c8 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 18 May 2019 04:49:28 +0530 Subject: [PATCH 310/322] Code refactoring and printing --- src/domains/strategy_solver_disjunctive.cpp | 31 +++++++++++---------- src/domains/strategy_solver_disjunctive.h | 4 +-- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 691632143..fa18f898f 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -56,27 +56,27 @@ bool strategy_solver_disjunctivet::iterate( improved=true; // found an unresolved edge - disjunctive_domaint::disjunctt d_src=e.disjunct; - disjunctive_domaint::disjunctt d_sink; + disjunctive_domaint::disjunctt src=e.disjunct; + disjunctive_domaint::disjunctt sink; symbolic_patht p=e.path; tpolyhedra_domaint::templ_valuet *post= new tpolyhedra_domaint::templ_valuet( - *static_cast(inv[d_src])); + *static_cast(inv[src])); get_post(p,inv, post); - d_sink=disjunctive_domain.merge_heuristic(inv, *post); + sink=disjunctive_domain.merge_heuristic(inv, *post); - if (d_sink==inv.size()) + if (sink==inv.size()) { - add_new_replication(inv,d_sink,*post); + add_new_replication(inv,sink,*post); } else { - domain->join(*inv[d_sink],*post); // join value + domain->join(*inv[sink],*post); // join value } - add_edge(d_src,p,d_sink); + add_edge(src,p,sink); // TODO: create new template } else @@ -415,16 +415,15 @@ Function: strategy_solver_disjunctivet::add_edge \*******************************************************************/ void strategy_solver_disjunctivet::add_edge( - disjunctive_domaint::disjunctt d_src, + disjunctive_domaint::disjunctt src, const symbolic_patht &p, - disjunctive_domaint::disjunctt d_sink) + disjunctive_domaint::disjunctt sink) { debug() << "Adding new SSA nodes" << eom; - disjunctive_domaint::disjunctt _d_src,_d_sink; - symbolic_patht _p; + local_SSAt::nodest::iterator n_it=loop->body_nodes.begin(); std::string sink_suffix="_"+std::to_string(current_count); - std::string src_suffix="_"+std::to_string(d_src); + std::string src_suffix="_"+std::to_string(src); for (n_it++;n_it!=loop->body_nodes.end();n_it++) { if (n_it->equalities.empty() && @@ -452,10 +451,12 @@ void strategy_solver_disjunctivet::add_edge( } // add new edge to seen set - disjunctive_domaint::seen_edget new_edge(d_src,p,d_sink); + disjunctive_domaint::seen_edget new_edge(src,p,sink); disjunctive_domain.seen_set.push_back(new_edge); // add new template corresponding to new edge + debug() << "Adding new templates" << eom; + if (disjunctive_domain.template_kind==disjunctive_domaint::TPOLYHEDRA) { tpolyhedra_domaint *base_domain=static_cast(disjunctive_domain.base_domain()); @@ -506,7 +507,7 @@ void strategy_solver_disjunctivet::add_edge( } // domains are sorted by sink, then source - disjunctive_domain.templ[d_sink][d_src]=new_domain; + disjunctive_domain.templ[sink][src]=new_domain; } else { diff --git a/src/domains/strategy_solver_disjunctive.h b/src/domains/strategy_solver_disjunctive.h index 1be2ba2de..e5e0bb535 100644 --- a/src/domains/strategy_solver_disjunctive.h +++ b/src/domains/strategy_solver_disjunctive.h @@ -84,9 +84,9 @@ class strategy_solver_disjunctivet:public strategy_solver_baset const std::string &sink_suffix); void add_loophead(disjunctive_domaint::disjunctt d); void add_edge( - disjunctive_domaint::disjunctt d_src, + disjunctive_domaint::disjunctt src, const symbolic_patht &p, - disjunctive_domaint::disjunctt d_sink); + disjunctive_domaint::disjunctt sink); }; #endif //CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_DISJUNCTIVE_DOMAIN_H \ No newline at end of file From dd261326adef9c33e11a061597b18f2622c7d6d0 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 18 May 2019 04:49:42 +0530 Subject: [PATCH 311/322] Minor fix --- src/domains/strategy_solver_disjunctive.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index fa18f898f..01360c988 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -444,7 +444,7 @@ void strategy_solver_disjunctivet::add_edge( rename(*c_it,src_suffix,sink_suffix); } for (local_SSAt::nodet::function_callst::iterator f_it=node.function_calls.begin(); - f_it!=node.function_calls.end();f_it) + f_it!=node.function_calls.end();f_it++) { rename(*f_it,src_suffix,sink_suffix); } From 782944d8f48b578a02cc743e08ae5b86964de701 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 18 May 2019 05:06:30 +0530 Subject: [PATCH 312/322] Disjunctive domain solver: add symbolic path to new domain --- src/domains/strategy_solver_disjunctive.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 01360c988..621910b8f 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -416,7 +416,7 @@ Function: strategy_solver_disjunctivet::add_edge void strategy_solver_disjunctivet::add_edge( disjunctive_domaint::disjunctt src, - const symbolic_patht &p, + const symbolic_patht &path, disjunctive_domaint::disjunctt sink) { debug() << "Adding new SSA nodes" << eom; @@ -451,7 +451,7 @@ void strategy_solver_disjunctivet::add_edge( } // add new edge to seen set - disjunctive_domaint::seen_edget new_edge(src,p,sink); + disjunctive_domaint::seen_edget new_edge(src,path,sink); disjunctive_domain.seen_set.push_back(new_edge); // add new template corresponding to new edge @@ -505,7 +505,18 @@ void strategy_solver_disjunctivet::add_edge( } new_domain->add_template_row(expr,pre_guard,post_guard,aux_expr,row.kind); } - + + // restrict new domain to symbolic path + symbolic_patht path_; + for (auto p:path.path_map) + { + exprt guard=p.first; + rename(guard,src_suffix,sink_suffix); + std::cout << from_expr(guard) << std::endl; + path_.path_map[guard]=p.second; + } + new_domain->restrict_to_sympath(path_); + // domains are sorted by sink, then source disjunctive_domain.templ[sink][src]=new_domain; } @@ -513,6 +524,6 @@ void strategy_solver_disjunctivet::add_edge( { assert(false); } - + current_count++; } From bdca5909261589fc8c3d29230fad81a2b64fbdf2 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 18 May 2019 05:13:17 +0530 Subject: [PATCH 313/322] Variable naming & minor fixes --- src/domains/strategy_solver_disjunctive.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 621910b8f..10e6260b7 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -58,13 +58,13 @@ bool strategy_solver_disjunctivet::iterate( disjunctive_domaint::disjunctt src=e.disjunct; disjunctive_domaint::disjunctt sink; - symbolic_patht p=e.path; + symbolic_patht path=e.path; tpolyhedra_domaint::templ_valuet *post= new tpolyhedra_domaint::templ_valuet( *static_cast(inv[src])); - get_post(p,inv, post); + get_post(path,inv,post); sink=disjunctive_domain.merge_heuristic(inv, *post); @@ -76,8 +76,7 @@ bool strategy_solver_disjunctivet::iterate( { domain->join(*inv[sink],*post); // join value } - add_edge(src,p,sink); - // TODO: create new template + add_edge(src,path,sink); } else { @@ -512,7 +511,6 @@ void strategy_solver_disjunctivet::add_edge( { exprt guard=p.first; rename(guard,src_suffix,sink_suffix); - std::cout << from_expr(guard) << std::endl; path_.path_map[guard]=p.second; } new_domain->restrict_to_sympath(path_); From 76756b65ac235be849076e58e6b491f75a390e3d Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 18 May 2019 05:26:07 +0530 Subject: [PATCH 314/322] Added more printing --- src/domains/disjunctive_domain.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/domains/disjunctive_domain.cpp b/src/domains/disjunctive_domain.cpp index 1f579b3a1..2c0938326 100644 --- a/src/domains/disjunctive_domain.cpp +++ b/src/domains/disjunctive_domain.cpp @@ -128,7 +128,19 @@ void disjunctive_domaint::output_domain( switch (template_kind) { case TPOLYHEDRA: - static_cast(base_domain_ptr)->output_domain(out,ns); + if (templ.size()==0) + { + static_cast(base_domain_ptr)->output_domain(out,ns); + } + for (auto &x:templ) + { + for (auto &y:x.second) + { + out << "Template for edge from disjunct " << y.first << " to disjunct " << x.first << std::endl; + static_cast(y.second)->output_domain(out,ns); + out << std::endl; + } + } break; default: assert(false); From 1467cb0266ab7278b13d0427c79404deb6d06bee Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 18 May 2019 06:19:42 +0530 Subject: [PATCH 315/322] Remove loop select & init var --- src/domains/strategy_solver_disjunctive.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 10e6260b7..4d721d82a 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -281,6 +281,11 @@ bool strategy_solver_disjunctivet::find_loop( for (local_SSAt::nodet::equalitiest::iterator eq_it=node.equalities.begin(); eq_it!=node.equalities.end();eq_it++) { + std::string id=id2string(eq_it->lhs().get(ID_identifier)); + if (id.find("phi")!=id.npos) + { + eq_it->rhs()=eq_it->rhs().op1(); // remove loop select & init + } loop->add_loophead_objects(*eq_it); } From d68d5d146b76f77a037829360859b1d135f93f39 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 18 May 2019 06:32:47 +0530 Subject: [PATCH 316/322] Printing --- src/domains/strategy_solver_disjunctive.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 4d721d82a..9fe8c0d91 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -454,6 +454,24 @@ void strategy_solver_disjunctivet::add_edge( } } + for (auto &node:*loopheads) + { + for (auto &eq:node.equalities) + { + debug() << "(E) " << from_expr(eq) << eom; + } + debug() << eom; + } + + for (auto &node:*loop_copies) + { + for (auto &eq:node.equalities) + { + debug() << "(E) " << from_expr(eq) << eom; + } + debug() << eom; + } + // add new edge to seen set disjunctive_domaint::seen_edget new_edge(src,path,sink); disjunctive_domain.seen_set.push_back(new_edge); @@ -522,6 +540,9 @@ void strategy_solver_disjunctivet::add_edge( // domains are sorted by sink, then source disjunctive_domain.templ[sink][src]=new_domain; + + disjunctive_domain.output_domain(debug(),ns); + debug() << eom; } else { From d0a1dc0b4dfc8a1f876ccbd43bf1b8cfdb183628 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Sat, 18 May 2019 06:33:24 +0530 Subject: [PATCH 317/322] Disjunctive domain solver: send new SSA nodes to solver --- src/domains/strategy_solver_disjunctive.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 9fe8c0d91..d69f2d465 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -441,11 +441,13 @@ void strategy_solver_disjunctivet::add_edge( e_it!=node.equalities.end();e_it++) { rename(*e_it,src_suffix,sink_suffix); + solver << *e_it; } for (local_SSAt::nodet::constraintst::iterator c_it=node.constraints.begin(); c_it!=node.constraints.end();c_it++) { rename(*c_it,src_suffix,sink_suffix); + solver << *c_it; } for (local_SSAt::nodet::function_callst::iterator f_it=node.function_calls.begin(); f_it!=node.function_calls.end();f_it++) From ce10f945316fd7a42adfe60ae94c5ac1004eaf59 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Tue, 21 May 2019 08:38:15 +0530 Subject: [PATCH 318/322] Disjunctive strategy solver: make renaming_map have class wide scope --- src/domains/strategy_solver_disjunctive.cpp | 10 +++++----- src/domains/strategy_solver_disjunctive.h | 4 +++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index d69f2d465..77afa09ad 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -484,21 +484,21 @@ void strategy_solver_disjunctivet::add_edge( if (disjunctive_domain.template_kind==disjunctive_domaint::TPOLYHEDRA) { tpolyhedra_domaint *base_domain=static_cast(disjunctive_domain.base_domain()); - replace_mapt new_renaming_map; // renaming map for new domain + // replace_mapt new_renaming_map; // renaming map for new domain replace_mapt map; // map from base domain exprts to new domain exprts for (auto &x:disjunctive_domain.renaming_map) { exprt pre_var=x.first; exprt post_var=x.second; - new_renaming_map[pre_var]=post_var; // keep old renaming map for non-LOOP vars + renaming_map[pre_var]=post_var; // keep old renaming map for non-LOOP vars rename(pre_var,src_suffix,sink_suffix); rename(post_var,src_suffix,sink_suffix); - new_renaming_map[pre_var]=post_var; + renaming_map[pre_var]=post_var; map[x.first]=pre_var; } - tpolyhedra_domaint *new_domain=new tpolyhedra_domaint(disjunctive_domain.domain_number,new_renaming_map,ns); - + tpolyhedra_domaint *new_domain=new tpolyhedra_domaint(disjunctive_domain.domain_number,renaming_map,ns); + for (auto &row:base_domain->templ) { exprt pre_guard=row.pre_guard; diff --git a/src/domains/strategy_solver_disjunctive.h b/src/domains/strategy_solver_disjunctive.h index e5e0bb535..c608204a5 100644 --- a/src/domains/strategy_solver_disjunctive.h +++ b/src/domains/strategy_solver_disjunctive.h @@ -42,7 +42,8 @@ class strategy_solver_disjunctivet:public strategy_solver_baset disjunctive_domain(_disjunctive_domain), SSA(_SSA), template_generator(_template_generator), - current_count(0) + current_count(0), + renaming_map(disjunctive_domain.renaming_map) { enumerate_all_paths(template_generator.guards); @@ -66,6 +67,7 @@ class strategy_solver_disjunctivet:public strategy_solver_baset local_SSAt::nodest *loopheads; loopt *loop; unsigned int current_count; + replace_mapt renaming_map; // renaming map for new domains void enumerate_all_paths(guardst &guards); void add_new_replication( From 993ea7ee0a56c0e6cfd9ab011180a9c2effbd371 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Tue, 21 May 2019 08:51:47 +0530 Subject: [PATCH 319/322] Disjunctive domain: add pre constraint & post constraint methods --- src/domains/disjunctive_domain.cpp | 76 ++++++++++++++++++++++++++++-- src/domains/disjunctive_domain.h | 9 +++- 2 files changed, 81 insertions(+), 4 deletions(-) diff --git a/src/domains/disjunctive_domain.cpp b/src/domains/disjunctive_domain.cpp index 2c0938326..bfe864f9a 100644 --- a/src/domains/disjunctive_domain.cpp +++ b/src/domains/disjunctive_domain.cpp @@ -369,8 +369,78 @@ mp_integer disjunctive_domaint::distance(const constant_exprt &v1, const constan } } -exprt disjunctive_domaint::get_disjunct_constraint(const disjunctt &d, const valuet &value) +/*******************************************************************\ + +Function: disjunctive_domaint::to_pre_constraints + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +exprt disjunctive_domaint::to_pre_constraints( + const disjunctive_domaint::disjunctive_valuet &value) { - //TODO: implement actual disjunct constraint - return true_exprt(); + exprt::operandst c; + + for (auto &x:templ) + { + for (auto &y:x.second) + { + assert(value.size()>y.first); + if (template_kind==TPOLYHEDRA) + { + tpolyhedra_domaint::templ_valuet *v=static_cast(value[y.first]); + c.push_back(static_cast(y.second)->to_pre_constraints(*v)); + } + } + } + return conjunction(c); +} + +/*******************************************************************\ + +Function: disjunctive_domaint::make_not_post_constraints + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +exprt disjunctive_domaint::make_not_post_constraints( + const disjunctive_domaint::disjunctive_valuet &value, + disjunctive_domaint::disjunctive_exprst &disjunctive_cond_exprs, + disjunctive_domaint::disjunctive_exprst &disjunctive_value_exprs) +{ + exprt::operandst c; + + for (auto &x:templ) + { + assert(value.size()>x.first); + unsigned sink=x.first; + std::map value_exprs_map; + std::map cond_exprs_map; + for (auto &y:x.second) + { + unsigned src=y.first; + exprt::operandst cond_exprs; + exprt::operandst value_exprs; + if (template_kind==TPOLYHEDRA) + { + tpolyhedra_domaint::templ_valuet *v=static_cast(value[x.first]); + tpolyhedra_domaint *domain=static_cast(y.second); + domain->make_not_post_constraints(*v,cond_exprs,value_exprs); + value_exprs_map.insert(std::make_pair(src,value_exprs)); + cond_exprs_map.insert(std::make_pair(src,cond_exprs)); + } + } + disjunctive_cond_exprs.insert(std::make_pair(sink,cond_exprs_map)); + disjunctive_value_exprs.insert(std::make_pair(sink,value_exprs_map)); + } } diff --git a/src/domains/disjunctive_domain.h b/src/domains/disjunctive_domain.h index 81a4ba812..d4fec326d 100644 --- a/src/domains/disjunctive_domain.h +++ b/src/domains/disjunctive_domain.h @@ -33,6 +33,9 @@ class disjunctive_domaint:public domaint typedef unsigned disjunctt; typedef std::map> templatet; + typedef std::map> disjunctive_exprst; + typedef std::map> disjunctive_literalst; + class disjunctive_valuet:public valuet, public std::vector { }; @@ -188,7 +191,11 @@ class disjunctive_domaint:public domaint const tpolyhedra_domaint::templ_valuet &value2); mp_integer distance(const constant_exprt &v1, const constant_exprt &v2); - exprt get_disjunct_constraint(const disjunctt &d, const valuet &value); + exprt to_pre_constraints(const disjunctive_valuet &value); + exprt make_not_post_constraints( + const disjunctive_valuet &value, + disjunctive_exprst &cond_exprs, + disjunctive_exprst &value_exprs); protected: domaint *base_domain_ptr; From 3ef53539e2f41f704b59379a34c963785474af56 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Tue, 21 May 2019 08:54:13 +0530 Subject: [PATCH 320/322] Disjunctive strategy solver: add binary search iteration --- src/domains/strategy_solver_disjunctive.cpp | 85 ++++++++++++++++++++- src/domains/strategy_solver_disjunctive.h | 5 ++ 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index 77afa09ad..b8cddc3a5 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -76,7 +76,10 @@ bool strategy_solver_disjunctivet::iterate( { domain->join(*inv[sink],*post); // join value } - add_edge(src,path,sink); + + add_edge(src,path,sink); // add SSA nodes & new templates + + while (iterate_binsearch(inv)) { } } else { @@ -553,3 +556,83 @@ void strategy_solver_disjunctivet::add_edge( current_count++; } + +/*******************************************************************\ + +Function: strategy_solver_disjunctivet::iterate_binsearch + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +bool strategy_solver_disjunctivet::iterate_binsearch( + disjunctive_domaint::disjunctive_valuet &inv) +{ + // tpolyhedra_domaint::templ_valuet &inv= + // static_cast(_inv); + + bool improved=false; + + solver.new_context(); // for improvement check + + exprt inv_expr=disjunctive_domain.to_pre_constraints(inv); + +#if 1 + debug() << "improvement check: " << eom; + debug() << "pre-inv: " << from_expr(ns, "", inv_expr) << eom; +#endif + + solver << inv_expr; + + disjunctive_domaint::disjunctive_exprst disjunctive_strategy_cond_exprs; + disjunctive_domain.make_not_post_constraints( + inv, disjunctive_strategy_cond_exprs, disjunctive_strategy_value_exprs); + + // disjunctive_strategy_cond_literals.resize(disjunctive_strategy_cond_exprs.size()); +#if 1 + debug() << "post-inv: "; +#endif + exprt::operandst c; + for (auto &x:disjunctive_strategy_cond_exprs) + { + unsigned sink=x.first; + for (auto &y:x.second) + { + unsigned src=y.first; + + exprt::operandst &strategy_value_exprs=disjunctive_strategy_value_exprs[sink][src]; + exprt::operandst &strategy_cond_exprs=y.second; + disjunctive_strategy_cond_literals[sink][src].resize(strategy_cond_exprs.size()); + bvt &strategy_cond_literals=disjunctive_strategy_cond_literals[sink][src]; + for (std::size_t i=0;i0 ? " || " : "") << from_expr(ns, "", strategy_cond_exprs[i]); +#endif + strategy_cond_literals[i]=solver.convert(strategy_cond_exprs[i]); + strategy_cond_exprs[i]=literal_exprt(strategy_cond_literals[i]); + } + + c.push_back(disjunction(strategy_cond_exprs)); + } + } + solver << disjunction(c); +#if 1 + debug() << eom; +#endif + +#if 0 + debug() << "solve(): "; +#endif + + if(solver()==decision_proceduret::D_SATISFIABLE) // improvement check + {} + else + {} + + return improved; +} \ No newline at end of file diff --git a/src/domains/strategy_solver_disjunctive.h b/src/domains/strategy_solver_disjunctive.h index c608204a5..4b05c17d4 100644 --- a/src/domains/strategy_solver_disjunctive.h +++ b/src/domains/strategy_solver_disjunctive.h @@ -69,6 +69,10 @@ class strategy_solver_disjunctivet:public strategy_solver_baset unsigned int current_count; replace_mapt renaming_map; // renaming map for new domains + // handles on values to retrieve from model + disjunctive_domaint::disjunctive_literalst disjunctive_strategy_cond_literals; + disjunctive_domaint::disjunctive_exprst disjunctive_strategy_value_exprs; + void enumerate_all_paths(guardst &guards); void add_new_replication( disjunctive_domaint::disjunctive_valuet &inv, @@ -89,6 +93,7 @@ class strategy_solver_disjunctivet:public strategy_solver_baset disjunctive_domaint::disjunctt src, const symbolic_patht &p, disjunctive_domaint::disjunctt sink); + bool iterate_binsearch(disjunctive_domaint::disjunctive_valuet &inv); }; #endif //CPROVER_2LS_DOMAINS_STRATEGY_SOLVER_DISJUNCTIVE_DOMAIN_H \ No newline at end of file From 02b5eebb6e3a5ca7e53d49d99c1a1a26443e61e5 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Wed, 28 Aug 2019 23:03:23 +0530 Subject: [PATCH 321/322] Disjuntive domains: change default limits for testing --- src/domains/template_generator_base.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/domains/template_generator_base.cpp b/src/domains/template_generator_base.cpp index 944864272..e51083c93 100644 --- a/src/domains/template_generator_base.cpp +++ b/src/domains/template_generator_base.cpp @@ -826,8 +826,10 @@ void template_generator_baset::instantiate_standard_domains( { filter_template_domain(); disjunctive_domaint::template_kindt template_kind=disjunctive_domaint::TPOLYHEDRA; - disjunctive_domaint::lex_metrict tol(0,mp_integer(1)); + disjunctive_domaint::lex_metrict tol(0,mp_integer(0)); unsigned int max=options.get_unsigned_int_option("disjunct-limit"); + max = 51; + std::cout << "Using a maximum of " << max << " disjuncts" << std::endl; domain_ptr=new disjunctive_domaint( domain_number,renaming_map,var_specs,SSA.ns,template_kind,max,tol); @@ -840,6 +842,7 @@ void template_generator_baset::instantiate_standard_domains( disjunctive_domaint::template_kindt template_kind=disjunctive_domaint::TPOLYHEDRA; disjunctive_domaint::lex_metrict tol(0,mp_integer(1)); unsigned int max=options.get_unsigned_int_option("disjunct-limit"); + std::cout << "Using maximum of " << max << " disjuncts" << std::endl; domain_ptr=new disjunctive_domaint( domain_number,renaming_map,var_specs,SSA.ns,template_kind,max,tol); @@ -853,6 +856,7 @@ void template_generator_baset::instantiate_standard_domains( disjunctive_domaint::template_kindt template_kind=disjunctive_domaint::TPOLYHEDRA; disjunctive_domaint::lex_metrict tol(0,mp_integer(1)); unsigned int max=options.get_unsigned_int_option("disjunct-limit"); + std::cout << "Using maximum of " << max << "disjuncts" << std::endl; domain_ptr=new disjunctive_domaint( domain_number,renaming_map,var_specs,SSA.ns,template_kind,max,tol); From 727b2a555aef8c65905f8c081fd1c6b65b0d5f67 Mon Sep 17 00:00:00 2001 From: Johanan Wahlang Date: Wed, 28 Aug 2019 23:14:42 +0530 Subject: [PATCH 322/322] Modify post computation --- src/domains/strategy_solver_disjunctive.cpp | 168 ++++++++++++++++++-- src/domains/strategy_solver_disjunctive.h | 4 +- 2 files changed, 158 insertions(+), 14 deletions(-) diff --git a/src/domains/strategy_solver_disjunctive.cpp b/src/domains/strategy_solver_disjunctive.cpp index b8cddc3a5..88b07a1c0 100644 --- a/src/domains/strategy_solver_disjunctive.cpp +++ b/src/domains/strategy_solver_disjunctive.cpp @@ -60,11 +60,11 @@ bool strategy_solver_disjunctivet::iterate( disjunctive_domaint::disjunctt sink; symbolic_patht path=e.path; - tpolyhedra_domaint::templ_valuet *post= - new tpolyhedra_domaint::templ_valuet( - *static_cast(inv[src])); + tpolyhedra_domaint::templ_valuet pre=*static_cast(inv[src]); + tpolyhedra_domaint::templ_valuet *post=new tpolyhedra_domaint::templ_valuet(); + domain->initialize(*post); - get_post(path,inv,post); + get_post(path,pre,*post); sink=disjunctive_domain.merge_heuristic(inv, *post); @@ -79,7 +79,7 @@ bool strategy_solver_disjunctivet::iterate( add_edge(src,path,sink); // add SSA nodes & new templates - while (iterate_binsearch(inv)) { } + // while (iterate_binsearch(inv)) { } } else { @@ -194,8 +194,8 @@ Function: strategy_solver_disjunctivet::get_post void strategy_solver_disjunctivet::get_post( const symbolic_patht &p, - const disjunctive_domaint::disjunctive_valuet &pre_inv, - invariantt *post_inv) + invariantt &_pre_inv, + invariantt &_post_inv) { debug() << "Computing post" << eom; domaint *_domain=disjunctive_domain.base_domain(); @@ -203,13 +203,157 @@ void strategy_solver_disjunctivet::get_post( if (disjunctive_domain.get_template_kind()==disjunctive_domaint::TPOLYHEDRA) { tpolyhedra_domaint domain(*static_cast(_domain)); + tpolyhedra_domaint::templ_valuet &pre_inv= + static_cast(_pre_inv); + tpolyhedra_domaint::templ_valuet &post_inv= + static_cast(_post_inv); domain.restrict_to_sympath(p); - strategy_solver_enumerationt strategy_solver( - domain,solver,ns); - domain.output_value(debug(),*post_inv,ns); + + + domain.output_value(debug(),post_inv,ns); debug() << "-------------------------------------------------" << eom << eom; - strategy_solver.iterate(*post_inv); - domain.output_value(debug(),*post_inv,ns); + // strategy solver enumeration + solver.new_context(); + + std::cout << "Setting the loop select guard to true" << std::endl; + // std::cout << "pre guard: " << from_expr(domain.templ.begin()->pre_guard.op1()) << std::endl; + solver << domain.templ.begin()->pre_guard.op1(); + + exprt preinv_expr=domain.to_pre_constraints(pre_inv); + #ifdef DEBUG_OUTPUT + debug() << "pre-inv: " << from_expr(ns, "", preinv_expr) << eom; + #endif + + solver << preinv_expr; + + exprt::operandst strategy_cond_exprs; + domain.make_not_post_constraints( + post_inv, strategy_cond_exprs, strategy_value_exprs); + + strategy_cond_literals.resize(strategy_cond_exprs.size()); + + exprt postinv_expr=disjunction(strategy_cond_exprs); + + #ifdef DEBUG_OUTPUT + debug() << "post-inv: "; + #endif + for(std::size_t i=0; i0 ? " || " : "") << from_expr(ns, "", strategy_cond_exprs[i]); + #endif + + strategy_cond_literals[i]=solver.convert(strategy_cond_exprs[i]); + strategy_cond_exprs[i]=literal_exprt(strategy_cond_literals[i]); + } + #ifdef DEBUG_OUTPUT + debug() << eom; + #endif + + solver << disjunction(strategy_cond_exprs); + + #ifdef DEBUG_OUTPUT + debug() << "solve(): "; + #endif + + if(solver()==decision_proceduret::D_SATISFIABLE) + { + #ifdef DEBUG_OUTPUT + debug() << "SAT" << eom; + #endif + + #ifdef DEBUG_OUTPUT + for(std::size_t i=0; i vars; + find_symbols(preinv_expr, vars); + + for(const auto &var : vars) + { + debug() << "var: " << from_expr(ns, "", var) << "=" + << from_expr(ns, "", solver.get(var)) << eom; + } + } + for(std::size_t i=0; i vars; + find_symbols(strategy_value_exprs[i], vars); + + for(const auto &var : vars) + { + debug() << "var: " << from_expr(ns, "", var) << "=" + << from_expr(ns, "", solver.get(var)) << eom; + } + } + #endif + + for(std::size_t row=0; rowis_in_conflict(solver.formula[i])) + debug() << "is_in_conflict: " << solver.formula[i] << eom; + else + debug() << "not_in_conflict: " << solver.formula[i] << eom; + } + #endif + } + solver.pop_context(); + + + // strategy_solver_enumerationt strategy_solver( + // domain,solver,ns); + // strategy_solver.iterate(post_inv); + + + domain.output_value(debug(),post_inv,ns); debug() << "--------------------------------------------------" << eom << eom; domain.undo_restriction(); } diff --git a/src/domains/strategy_solver_disjunctive.h b/src/domains/strategy_solver_disjunctive.h index 4b05c17d4..a098e8dc2 100644 --- a/src/domains/strategy_solver_disjunctive.h +++ b/src/domains/strategy_solver_disjunctive.h @@ -82,8 +82,8 @@ class strategy_solver_disjunctivet:public strategy_solver_baset const disjunctive_domaint::disjunctive_valuet &value); void get_post( const symbolic_patht &p, - const disjunctive_domaint::disjunctive_valuet &pre_inv, - invariantt *post_inv); + invariantt &pre_inv, + invariantt &post_inv); bool find_loop(local_SSAt::locationt &loophead_loc, loopt *loop); void rename(exprt &expr, const std::string &src_suffix,