File tree Expand file tree Collapse file tree 12 files changed +290
-0
lines changed
local_control_flow_history_01
local_control_flow_history_02
local_control_flow_history_03
local_control_flow_history_04
local_control_flow_history_05
local_control_flow_history_06 Expand file tree Collapse file tree 12 files changed +290
-0
lines changed Original file line number Diff line number Diff line change
1
+ #include <assert.h>
2
+
3
+ int main (int argc , char * * argv )
4
+ {
5
+ int branch ;
6
+ int x = 0 ;
7
+
8
+ if (branch )
9
+ {
10
+ x = 1 ;
11
+ }
12
+ else
13
+ {
14
+ x = -1 ;
15
+ }
16
+
17
+ // Merging a constant domain here will make this unprovable
18
+ assert (x != 0 );
19
+
20
+ // Some subtle points here...
21
+ // The history tracks paths, it is up to the domain to track the
22
+ // path conditon / consequences of that path.
23
+ //
24
+ // We have two paths:
25
+ // branch == ?, x == 1
26
+ // branch == 0, x == -1
27
+ //
28
+ // As the domain in the first case can't express branch != 0
29
+ // we will wind up with three paths here, including a spurious
30
+ // one with branch == 0, x == 1.
31
+ if (branch )
32
+ {
33
+ assert (x == 1 );
34
+ }
35
+ else
36
+ {
37
+ assert (x == -1 );
38
+ }
39
+
40
+ // Working around the domain issues...
41
+ // (This doesn't increase the number of paths)
42
+ if (x == 1 )
43
+ {
44
+ x -- ;
45
+ }
46
+ else
47
+ {
48
+ x ++ ;
49
+ }
50
+
51
+ // Should be true in all 3 paths
52
+ assert (x == 0 );
53
+
54
+ return 0 ;
55
+ }
Original file line number Diff line number Diff line change
1
+ CORE
2
+ main.c
3
+ --verify --recursive-interprocedural --branching 0 --constants --one-domain-per-history
4
+ ^EXIT=0$
5
+ ^SIGNAL=0$
6
+ ^\[main.assertion.1\] .* assertion x != 0: SUCCESS$
7
+ ^\[main.assertion.2\] .* assertion x == 1: SUCCESS$
8
+ ^\[main.assertion.3\] .* assertion x == -1: FAILURE \(if reachable\)$
9
+ ^\[main.assertion.4\] .* assertion x == 0: SUCCESS$
10
+ --
11
+ ^warning: ignoring
12
+ --
13
+ This demonstrates the "lazy merging" that comes from tracking the history of branching
Original file line number Diff line number Diff line change
1
+ #include <assert.h>
2
+
3
+ int main (int argc , char * * argv )
4
+ {
5
+ int branching_array [5 ];
6
+ int x = 1 ;
7
+
8
+ if (branching_array [0 ])
9
+ {
10
+ ++ x ;
11
+ }
12
+ // Two paths...
13
+ assert (x > 0 );
14
+
15
+ if (branching_array [1 ])
16
+ {
17
+ ++ x ;
18
+ }
19
+ // Four paths...
20
+ assert (x > 0 );
21
+
22
+ if (branching_array [2 ])
23
+ {
24
+ ++ x ;
25
+ }
26
+ // Eight paths...
27
+ assert (x > 0 );
28
+
29
+ if (branching_array [3 ])
30
+ {
31
+ ++ x ;
32
+ }
33
+ // Paths merge so there will be some paths that will set x to \top
34
+ // and so this will be flagged as unknown
35
+ assert (x > 0 );
36
+ // In principle it would be possible to merge paths in such a way
37
+ // that the those with similar domains are merged and this would be
38
+ // able to be proved. The local_control_flow_history code doesn't
39
+ // do this though.
40
+
41
+ return 0 ;
42
+ }
Original file line number Diff line number Diff line change
1
+ CORE
2
+ main.c
3
+ --verify --recursive-interprocedural --branching 12 --constants --one-domain-per-history
4
+ ^EXIT=0$
5
+ ^SIGNAL=0$
6
+ ^\[main.assertion.1\] .* assertion x > 0: SUCCESS$
7
+ ^\[main.assertion.2\] .* assertion x > 0: SUCCESS$
8
+ ^\[main.assertion.3\] .* assertion x > 0: SUCCESS$
9
+ ^\[main.assertion.4\] .* assertion x > 0: UNKNOWN$
10
+ --
11
+ ^warning: ignoring
12
+ --
13
+ This demonstrates hitting the path limit and the merging of paths
Original file line number Diff line number Diff line change
1
+ #include <assert.h>
2
+
3
+ int main (int argc , char * * argv )
4
+ {
5
+ int total = 0 ;
6
+ int n = 50 ;
7
+ int i ;
8
+
9
+ for (i = 0 ; i < n ; ++ i )
10
+ {
11
+ total += i ;
12
+ }
13
+
14
+ assert (total == (n * (n - 1 ) / 2 ));
15
+
16
+ return 0 ;
17
+ }
Original file line number Diff line number Diff line change
1
+ CORE
2
+ main.c
3
+ --verify --recursive-interprocedural --loop-unwind 0 --constants --one-domain-per-history
4
+ ^EXIT=0$
5
+ ^SIGNAL=0$
6
+ ^\[main.assertion.1\] .* assertion total == \(n \* \(n - 1\) / 2\): SUCCESS$
7
+ --
8
+ ^warning: ignoring
9
+ --
10
+ A basic test of loop unwinding.
Original file line number Diff line number Diff line change
1
+ #include <assert.h>
2
+
3
+ int main (int argc , char * * argv )
4
+ {
5
+ int total ;
6
+ int n ;
7
+ int i ;
8
+
9
+ total = 0 ;
10
+ n = 8 ;
11
+ for (i = 0 ; i < n ; ++ i )
12
+ {
13
+ total += i ;
14
+ }
15
+
16
+ // Unknown due to the limit on unwindings
17
+ assert (total == (n * (n - 1 ) / 2 ));
18
+
19
+ // Condense down to one path...
20
+
21
+ total = 0 ;
22
+ n = 16 ;
23
+ for (i = 0 ; i < n ; ++ i )
24
+ {
25
+ total += i ;
26
+ }
27
+
28
+ // Creates a merge path but only one user of it
29
+ assert (total == (n * (n - 1 ) / 2 ));
30
+
31
+ total = 0 ;
32
+ n = 32 ;
33
+ for (i = 0 ; i < n ; ++ i )
34
+ {
35
+ total += i ;
36
+ }
37
+
38
+ // Provable
39
+ assert (total == (n * (n - 1 ) / 2 ));
40
+
41
+ return 0 ;
42
+ }
Original file line number Diff line number Diff line change
1
+ CORE
2
+ main.c
3
+ --verify --recursive-interprocedural --loop-unwind 17 --constants --one-domain-per-history
4
+ ^EXIT=0$
5
+ ^SIGNAL=0$
6
+ ^\[main.assertion.1\] .* assertion total == \(n \* \(n - 1\) / 2\): SUCCESS$
7
+ ^\[main.assertion.2\] .* assertion total == \(n \* \(n - 1\) / 2\): SUCCESS$
8
+ ^\[main.assertion.3\] .* assertion total == \(n \* \(n - 1\) / 2\): UNKNOWN$
9
+ --
10
+ ^warning: ignoring
11
+ --
12
+ A basic test of the loop unwinding limit.
13
+ You might think this has an off-by-one error but to process a loop 16 times
14
+ you have to visit the loop guard 17 times. Setting the loop limit to 16 will
15
+ cause the last two visits to merge loosing the precision needed to prove the
16
+ conjecture.
Original file line number Diff line number Diff line change
1
+ #include <assert.h>
2
+
3
+ int main (int argc , char * * argv )
4
+ {
5
+ int total ;
6
+ int n ;
7
+ int i ;
8
+ int branching [4 ];
9
+
10
+ total = 0 ;
11
+ n = 4 ;
12
+ for (i = 0 ; i < n ; ++ i )
13
+ {
14
+ if (branching [i ])
15
+ {
16
+ total += i ;
17
+ }
18
+ }
19
+
20
+ assert (total <= (n * (n - 1 ) / 2 ));
21
+
22
+ return 0 ;
23
+ }
Original file line number Diff line number Diff line change
1
+ CORE
2
+ main.c
3
+ --verify --recursive-interprocedural --loop-unwind-and-branching 32 --constants --one-domain-per-history
4
+ ^EXIT=0$
5
+ ^SIGNAL=0$
6
+ ^\[main.assertion.1\] .* assertion total <= \(n \* \(n - 1\) / 2\): SUCCESS$
7
+ --
8
+ ^warning: ignoring
9
+ --
10
+ Test tracking all local control-flow history.
11
+ Note the exponential rise in the number of paths!
Original file line number Diff line number Diff line change
1
+ #include <assert.h>
2
+
3
+ #define CODE_BLOCK \
4
+ int i; \
5
+ float flotal = 0; \
6
+ for(i = 0; i < n; ++i) \
7
+ { \
8
+ flotal += i; \
9
+ } \
10
+ assert(flotal == (n * (n - 1) / 2))
11
+
12
+ void do_the_loop (int n )
13
+ {
14
+ CODE_BLOCK ;
15
+ }
16
+
17
+ int main (int argc , char * * argv )
18
+ {
19
+ int j ;
20
+
21
+ // Will give unknown unless the bound is over 25
22
+ for (j = 0 ; j < 5 ; j ++ )
23
+ {
24
+ int n = 5 ;
25
+ CODE_BLOCK ;
26
+ }
27
+
28
+ // Paths in the loop will merge but that is OK
29
+ // because the value of n is the important bit
30
+ for (j = 0 ; j < 1000 ; j ++ )
31
+ {
32
+ int n = 10 ;
33
+ do_the_loop (n );
34
+ }
35
+
36
+ return 0 ;
37
+ }
Original file line number Diff line number Diff line change
1
+ CORE
2
+ main.c
3
+ --verify --recursive-interprocedural --loop-unwind-and-branching 12 --constants --one-domain-per-history
4
+ ^EXIT=0$
5
+ ^SIGNAL=0$
6
+ ^\[main.assertion.1\] .* assertion flotal == \(n \* \(n - 1\) / 2\): UNKNOWN$
7
+ ^\[do_the_loop.assertion.1\] .* assertion flotal == \(n \* \(n - 1\) / 2\): SUCCESS$
8
+ --
9
+ ^warning: ignoring
10
+ --
11
+ Demonstrate the function local behaviour of this history
You can’t perform that action at this time.
0 commit comments