File tree Expand file tree Collapse file tree 15 files changed +278
-99
lines changed
assigns_enforce_detect_local_statics
function-calls-recursive-01
goto-instrument/contracts Expand file tree Collapse file tree 15 files changed +278
-99
lines changed Original file line number Diff line number Diff line change
1
+ #include <assert.h>
2
+ #include <stdlib.h>
3
+
4
+ static int x ;
5
+ static int xx ;
6
+
7
+ void foo ()
8
+ {
9
+ int * y = & x ;
10
+ int * yy = & xx ;
11
+
12
+ static int x ;
13
+ // must pass (modifies local static)
14
+ x ++ ;
15
+
16
+ // must pass (modifies assignable global static )
17
+ (* y )++ ;
18
+
19
+ // must fail (modifies non-assignable global static)
20
+ (* yy )++ ;
21
+ }
22
+
23
+ void bar () __CPROVER_assigns (x )
24
+ {
25
+ foo ();
26
+ }
27
+
28
+ int main ()
29
+ {
30
+ bar ();
31
+ }
Original file line number Diff line number Diff line change
1
+ CORE
2
+ main.c
3
+ --enforce-contract bar
4
+ ^EXIT=10$
5
+ ^SIGNAL=0$
6
+ ^\[foo.\d+\] line \d+ Check that y is assignable: SUCCESS$
7
+ ^\[foo.\d+\] line \d+ Check that foo\$\$1\$\$x is assignable: SUCCESS$
8
+ ^\[foo.\d+\] line \d+ Check that \*y is assignable: SUCCESS$
9
+ ^\[foo.\d+\] line \d+ Check that \*yy is assignable: FAILURE$
10
+ ^VERIFICATION FAILED$
11
+ --
12
+ --
13
+ Checks whether static local and global variables are correctly tracked
14
+ in assigns clause verification, accross subfunction calls.
Original file line number Diff line number Diff line change 1
- #include <assert.h>
2
- #include <stdlib.h>
3
-
4
- static int x ;
1
+ static int x = 0 ;
5
2
6
3
void foo () __CPROVER_assigns (x )
7
4
{
8
5
int * y = & x ;
9
6
10
- static int x ;
7
+ static int x = 0 ;
8
+
9
+ // should pass (assigns local x)
11
10
x ++ ;
12
11
12
+ // should fail (assigns global x)
13
13
(* y )++ ;
14
14
}
15
15
Original file line number Diff line number Diff line change 1
1
CORE
2
2
main.c
3
3
--enforce-contract f1 _ --unwind 20 --unwinding-assertions
4
- ^EXIT=10$
4
+ ^file main\.c line 13 function f2: recursion is ignored on call to 'f2'$
5
+ ^Invariant check failed$
6
+ ^Condition: decorated\.get_recursive_function_warnings_count\(\) == 0$
7
+ ^Reason: Recursive functions found during inlining$
8
+ ^EXIT=(127|134|137)$
5
9
^SIGNAL=0$
6
- ^file main.c line \d+ function f2: recursion is ignored on call to \'f2\'$
7
- ^\[postcondition.\d+\] file main.c line \d+ Check ensures clause: FAILURE$
8
- ^VERIFICATION FAILED$
9
10
--
10
11
--
11
- Verification:
12
- function | pre-cond | post-cond
13
- ---------|----------|----------
14
- f1 | assumed | asserted
15
-
16
- Test should fail:
17
- The postcondition of f2 is incorrect, considering the recursion particularity.
18
-
19
- Recursion:
20
- The base case for the recursive call to f2 provides different behavior than the common case (given the pre-conditions).
12
+ Test should fail because a recursive function is found during inlining.
Original file line number Diff line number Diff line change 1
1
CORE
2
2
main.c
3
3
--enforce-contract f2 _ --unwind 20 --unwinding-assertions
4
- ^EXIT=10$
4
+ ^file main\.c line 13 function f2: recursion is ignored on call to 'f2'$
5
+ ^Invariant check failed$
6
+ ^Condition: decorated\.get_recursive_function_warnings_count\(\) == 0$
7
+ ^Reason: Recursive functions found during inlining$
8
+ ^EXIT=(127|134|137)$
5
9
^SIGNAL=0$
6
- ^file main.c line \d+ function f2: recursion is ignored on call to \'f2\'$
7
- ^\[postcondition.\d+\] file main.c line \d+ Check ensures clause: FAILURE$
8
- ^\[f2.\d+\] line \d+ Check that loc is assignable: SUCCESS$
9
- ^VERIFICATION FAILED$
10
10
--
11
11
--
12
- Verification:
13
- function | pre-cond | post-cond
14
- ---------|----------|----------
15
- f2 | assumed | asserted
16
-
17
- Test should fail:
18
- The postcondition of f2 is incorrect, considering the recursion particularity.
19
-
20
- Recursion:
21
- The base case for the recursive call to f2 provides different behavior than the common case (given the pre-conditions).
12
+ Test should fail because a recursive function is found during inlining.
Original file line number Diff line number Diff line change 1
1
CORE
2
2
main.c
3
3
--enforce-contract f1 _ --unwind 20 --unwinding-assertions
4
- ^EXIT=10$
4
+ ^file main\.c line 19 function f2_in: recursion is ignored on call to 'f2_out'$
5
+ ^Invariant check failed$
6
+ ^Condition: decorated\.get_recursive_function_warnings_count\(\) == 0$
7
+ ^Reason: Recursive functions found during inlining$
8
+ ^EXIT=(127|134|137)$
5
9
^SIGNAL=0$
6
- ^file main.c line \d+ function f2\_in: recursion is ignored on call to \'f2\_out\'$
7
- ^\[postcondition.\d+\] file main.c line \d+ Check ensures clause: FAILURE$
8
- ^VERIFICATION FAILED$
9
10
--
10
11
--
11
- Verification:
12
- function | pre-cond | post-cond
13
- ---------|----------|----------
14
- f1 | assumed | asserted
15
-
16
- Test should fail:
17
- The postcondition of f2_out is incorrect, considering the recursion particularity.
18
-
19
- Recursion:
20
- The base case for the recursive call to f2_out provides different behavior
21
- than the general case (given the pre-conditions).
12
+ Test should fail because a recursive function is found during inlining.
Original file line number Diff line number Diff line change 1
1
CORE
2
2
main.c
3
3
--enforce-contract f2_in _ --unwind 20 --unwinding-assertions
4
- ^EXIT=10$
4
+ ^file main\.c line 13 function f2_out: recursion is ignored on call to 'f2_in'$
5
+ ^Invariant check failed$
6
+ ^Condition: decorated\.get_recursive_function_warnings_count\(\) == 0$
7
+ ^Reason: Recursive functions found during inlining$
8
+ ^EXIT=(127|134|137)$
5
9
^SIGNAL=0$
6
- ^file main.c line \d+ function f2\_out: recursion is ignored on call to \'f2\_in\'$
7
- ^\[postcondition.\d+\] file main.c line \d+ Check ensures clause: FAILURE$
8
- ^\[f2\_out.\d+\] line \d+ Check that loc2 is assignable: SUCCESS$
9
- ^VERIFICATION FAILED$
10
10
--
11
11
--
12
- Verification:
13
- function | pre-cond | post-cond
14
- ---------|----------|----------
15
- f2_in | assumed | asserted
16
-
17
- Test should fail:
18
- The postcondition of f2_out is incorrect, considering the recursion particularity.
19
-
20
- Recursion:
21
- The base case for the recursive call to f2_out provides different behavior
22
- than the general case (given the pre-conditions).
12
+ Test should fail because a recursive function is found during inlining.
Original file line number Diff line number Diff line change 1
1
CORE
2
2
main.c
3
3
--enforce-contract f2_out _ --unwind 20 --unwinding-assertions
4
- ^EXIT=10$
4
+ ^file main\.c line 19 function f2_in: recursion is ignored on call to 'f2_out'$
5
+ ^Invariant check failed$
6
+ ^Condition: decorated\.get_recursive_function_warnings_count\(\) == 0$
7
+ ^Reason: Recursive functions found during inlining$
8
+ ^EXIT=(127|134|137)$
5
9
^SIGNAL=0$
6
- ^file main.c line \d+ function f2\_in: recursion is ignored on call to \'f2\_out\'$
7
- ^\[postcondition.\d+\] file main.c line \d+ Check ensures clause: FAILURE$
8
- ^\[f2\_out.\d+\] line \d+ Check that loc2 is assignable: SUCCESS$
9
- ^VERIFICATION FAILED$
10
10
--
11
11
--
12
- Verification:
13
- function | pre-cond | post-cond
14
- ---------|----------|----------
15
- f2_out | assumed | asserted
16
-
17
- Test should fail:
18
- The postcondition of f2 is incorrect, considering the recursion particularity.
19
-
20
- Recursion:
21
- The base case for the recursive call to f2_out provides different behavior
22
- than the general case (given the pre-conditions).
12
+ Test should fail because a recursive function is found during inlining.
Original file line number Diff line number Diff line change
1
+ #include <stdlib.h>
2
+
3
+ int sum_rec (int i , int acc )
4
+ {
5
+ if (i >= 0 )
6
+ return sum_rec (i - 1 , acc + i );
7
+ return acc ;
8
+ }
9
+
10
+ int sum (int i ) __CPROVER_requires (0 <= i && i <= 50 )
11
+ __CPROVER_ensures (__CPROVER_return_value >= 0 ) __CPROVER_assigns ()
12
+ {
13
+ int j = i ;
14
+ int res = sum_rec (j , 0 );
15
+ return res ;
16
+ }
17
+
18
+ int main ()
19
+ {
20
+ int result = sum (10 );
21
+ __CPROVER_assert (result == 55 , "result == 55" );
22
+ return 0 ;
23
+ }
Original file line number Diff line number Diff line change
1
+ CORE
2
+ main.c
3
+ --enforce-contract sum _ --trace
4
+ ^file main\.c line 6 function sum_rec: recursion is ignored on call to 'sum_rec'$
5
+ ^Invariant check failed$
6
+ ^Condition: decorated\.get_recursive_function_warnings_count\(\) == 0$
7
+ ^Reason: Recursive functions found during inlining$
8
+ ^EXIT=(127|134|137)$
9
+ ^SIGNAL=0$
10
+ --
11
+ --
12
+ Test should fail because a recursive function is found during inlining.
Original file line number Diff line number Diff line change @@ -58,11 +58,11 @@ static void forall_callsites(
58
58
if (i_it->is_function_call ())
59
59
{
60
60
const exprt &function_expr = i_it->call_function ();
61
- if (function_expr. id ()==ID_symbol)
62
- {
63
- const irep_idt &callee= to_symbol_expr (function_expr). get_identifier ( );
64
- call_task (i_it, callee);
65
- }
61
+ PRECONDITION_WITH_DIAGNOSTICS (
62
+ function_expr. id () == ID_symbol,
63
+ " call graph computation requires function pointer removal " );
64
+ const irep_idt & callee = to_symbol_expr (function_expr). get_identifier ( );
65
+ call_task (i_it, callee);
66
66
}
67
67
}
68
68
}
Original file line number Diff line number Diff line change @@ -13,6 +13,8 @@ Date: July 2021
13
13
14
14
#include " assigns.h"
15
15
16
+ #include < analyses/call_graph.h>
17
+
16
18
#include < langapi/language_util.h>
17
19
18
20
#include < util/arith_tools.h>
@@ -196,3 +198,31 @@ void havoc_assigns_targetst::append_havoc_code_for_expr(
196
198
197
199
havoc_utilst::append_havoc_code_for_expr (location, expr, dest);
198
200
}
201
+
202
+ void assigns_clauset::add_static_locals_to_write_set (
203
+ const goto_functionst &functions,
204
+ const irep_idt &root_function)
205
+ {
206
+ auto call_graph =
207
+ call_grapht::create_from_root_function (functions, root_function, true )
208
+ .get_directed_graph ();
209
+
210
+ for (const auto &sym_pair : symbol_table)
211
+ {
212
+ const auto &sym = sym_pair.second ;
213
+ if (sym.is_static_lifetime )
214
+ {
215
+ auto fname = sym.location .get_function ();
216
+ if (
217
+ !fname.empty () && (fname == root_function ||
218
+ call_graph.get_node_index (fname).has_value ()))
219
+ {
220
+ // We found a symbol with
221
+ // - a static lifetime
222
+ // - non empty location function
223
+ // - this function appears in the call graph of the function
224
+ add_to_write_set (sym.symbol_expr ());
225
+ }
226
+ }
227
+ }
228
+ }
Original file line number Diff line number Diff line change @@ -87,6 +87,21 @@ class assigns_clauset
87
87
return write_set;
88
88
}
89
89
90
+ // / \brief Finds symbols declared with a static lifetime in the given
91
+ // / `root_function` or one of the functions it calls,
92
+ // / and adds them to the write set of this assigns clause.
93
+ // /
94
+ // / @param functions all functions of the goto_model
95
+ // / @param root_function the root function under which to search statics
96
+ // /
97
+ // / A symbol is considered a static local symbol iff:
98
+ // / - it has a static lifetime annotation
99
+ // / - its source location has a non-empty function attribute
100
+ // / - this function attribute is found in the call graph of the root_function
101
+ void add_static_locals_to_write_set (
102
+ const goto_functionst &functions,
103
+ const irep_idt &root_function);
104
+
90
105
const messaget &log;
91
106
const namespacet &ns;
92
107
const irep_idt &function_name;
You can’t perform that action at this time.
0 commit comments