Skip to content

Commit c3fcb36

Browse files
author
klaas
committed
Makes code contracts use goto_rw for write sets
This change replaces the use of local_may_alias analysis in code contracts with the more accurate goto_rw analysis. These analyses are used to find the set of variables written to by a loop or function so that we know which variables to make nondeterministic when abstracting out those pieces of code.
1 parent 2ec8f88 commit c3fcb36

File tree

4 files changed

+94
-76
lines changed

4 files changed

+94
-76
lines changed
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
KNOWNBUG
1+
CORE
22
main.c
33
--check-code-contracts
44
^\[main.assertion.1\] assertion y == 0: FAILURE$
55
^\[main.assertion.2\] assertion z == 1: SUCCESS$
66
^\[foo.1\] : SUCCESS$
7-
^VERIFICATION SUCCESSFUL$
7+
^VERIFICATION FAILED$
88
--
99
--
10-
Contract checking does not properly havoc function calls.

src/goto-instrument/code_contracts.cpp

Lines changed: 92 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,18 @@ Date: February 2016
1717
#include <util/c_types.h>
1818
#include <util/expr_iterator.h>
1919
#include <util/fresh_symbol.h>
20+
#include <util/make_unique.h>
2021
#include <util/replace_symbol.h>
2122

2223
#include <goto-programs/remove_skip.h>
2324

24-
#include <analyses/local_may_alias.h>
25+
#include <analyses/goto_rw.h>
2526

2627
#include <linking/static_lifetime_init.h>
2728

29+
#include <pointer-analysis/value_set_analysis_fi.h>
30+
2831
#include "loop_utils.h"
29-
#include "function_modifies.h"
3032

3133
enum class contract_opst { APPLY, CHECK };
3234

@@ -56,12 +58,12 @@ class code_contractst
5658

5759
void apply_contract(
5860
goto_programt &goto_program,
59-
const local_may_aliast &local_may_alias,
61+
value_setst &value_sets,
6062
goto_programt::targett target);
6163

6264
void apply_invariant(
6365
goto_functionst::goto_functiont &goto_function,
64-
const local_may_aliast &local_may_alias,
66+
value_setst &value_sets,
6567
const goto_programt::targett loop_head,
6668
const loopt &loop);
6769

@@ -72,7 +74,7 @@ class code_contractst
7274

7375
void check_apply_invariant(
7476
goto_functionst::goto_functiont &goto_function,
75-
const local_may_aliast &local_may_alias,
77+
value_setst &value_sets,
7678
const goto_programt::targett loop_head,
7779
const loopt &loop);
7880

@@ -83,7 +85,7 @@ class code_contractst
8385

8486
void code_contractst::apply_contract(
8587
goto_programt &goto_program,
86-
const local_may_aliast &local_may_alias,
88+
value_setst &value_sets,
8789
goto_programt::targett target)
8890
{
8991
const code_function_callt &call=to_code_function_call(target->code);
@@ -116,17 +118,28 @@ void code_contractst::apply_contract(
116118
}
117119

118120
// find out what can be written by the function
119-
// TODO Use a better write-set analysis.
120121
modifiest modifies;
121-
function_modifiest function_modifies(goto_functions);
122122

123-
// Handle return value of the function
124-
if(call.lhs().is_not_nil())
123+
rw_range_set_value_sett rw_set(ns, value_sets);
124+
goto_rw(goto_functions, function, rw_set);
125+
forall_rw_range_set_w_objects(it, rw_set)
125126
{
126-
function_modifies.get_modifies_lhs(local_may_alias, target,
127-
call.lhs(), modifies);
127+
// Skip over local variables of the function being called, as well as
128+
// variables not in the namespace (e.g. symex::invalid_object)
129+
const symbolt *symbol_ptr;
130+
if(!ns.lookup(it->first, symbol_ptr))
131+
{
132+
const std::string &name_string = id2string(symbol_ptr->name);
133+
std::string scope_prefix(id2string(ns.lookup(function).name));
134+
scope_prefix += "::";
135+
136+
if(name_string.find(scope_prefix) == std::string::npos)
137+
{
138+
modifies.insert(ns.lookup(it->first).symbol_expr());
139+
}
140+
}
141+
modifies.insert(ns.lookup(it->first).symbol_expr());
128142
}
129-
function_modifies(call.function(), modifies);
130143

131144
// build the havocking code
132145
goto_programt havoc_code;
@@ -137,7 +150,9 @@ void code_contractst::apply_contract(
137150

138151
// TODO: return value could be nil
139152
if(type.return_type()!=empty_typet())
153+
{
140154
replace.insert("__CPROVER_return_value", call.lhs());
155+
}
141156

142157
// formal parameters
143158
code_function_callt::argumentst::const_iterator a_it=
@@ -153,6 +168,18 @@ void code_contractst::apply_contract(
153168
replace(requires);
154169
replace(ensures);
155170

171+
// Havoc the return value of the function call.
172+
if(type.return_type()!=empty_typet())
173+
{
174+
const exprt &lhs = call.lhs();
175+
const exprt &rhs = side_effect_expr_nondett(call.lhs().type());
176+
target->make_assignment(code_assignt(lhs, rhs));
177+
}
178+
else
179+
{
180+
target->make_skip();
181+
}
182+
156183
if(requires.is_not_nil())
157184
{
158185
goto_programt::instructiont a(ASSERT);
@@ -164,15 +191,19 @@ void code_contractst::apply_contract(
164191
++target;
165192
}
166193

167-
// TODO some sort of replacement on havoc code
168194
goto_program.destructive_insert(target, havoc_code);
169195

170-
target->make_assumption(ensures);
196+
{
197+
goto_programt::targett a=goto_program.insert_after(target);
198+
a->make_assumption(ensures);
199+
a->function=target->function;
200+
a->source_location=target->source_location;
201+
}
171202
}
172203

173204
void code_contractst::apply_invariant(
174205
goto_functionst::goto_functiont &goto_function,
175-
const local_may_aliast &local_may_alias,
206+
value_setst &value_sets,
176207
const goto_programt::targett loop_head,
177208
const loopt &loop)
178209
{
@@ -207,7 +238,20 @@ void code_contractst::apply_invariant(
207238

208239
// find out what can get changed in the loop
209240
modifiest modifies;
210-
get_modifies(local_may_alias, loop, modifies);
241+
242+
rw_range_set_value_sett rw_set(ns, value_sets);
243+
for(const goto_programt::targett &inst : loop)
244+
{
245+
goto_rw(inst, rw_set);
246+
}
247+
forall_rw_range_set_w_objects(it, rw_set)
248+
{
249+
const symbolt *symbol_ptr;
250+
if(!ns.lookup(it->first, symbol_ptr))
251+
{
252+
modifies.insert(ns.lookup(it->first).symbol_expr());
253+
}
254+
}
211255

212256
// build the havocking code
213257
goto_programt havoc_code;
@@ -275,7 +319,8 @@ void code_contractst::check_contract(
275319
static_cast<const exprt&>(goto_function.type.find(ID_C_spec_ensures));
276320

277321
// Nothing to check if ensures is nil.
278-
if(ensures.is_nil()) {
322+
if(ensures.is_nil())
323+
{
279324
return;
280325
}
281326

@@ -374,7 +419,7 @@ void code_contractst::check_contract(
374419

375420
void code_contractst::check_apply_invariant(
376421
goto_functionst::goto_functiont &goto_function,
377-
const local_may_aliast &local_may_alias,
422+
value_setst &value_sets,
378423
const goto_programt::targett loop_head,
379424
const loopt &loop)
380425
{
@@ -393,7 +438,9 @@ void code_contractst::check_apply_invariant(
393438
static_cast<const exprt&>(
394439
loop_end->guard.find(ID_C_spec_loop_invariant));
395440
if(invariant.is_nil())
441+
{
396442
return;
443+
}
397444

398445
// change H: loop; E: ...
399446
// to
@@ -408,7 +455,20 @@ void code_contractst::check_apply_invariant(
408455

409456
// find out what can get changed in the loop
410457
modifiest modifies;
411-
get_modifies(local_may_alias, loop, modifies);
458+
459+
rw_range_set_value_sett rw_set(ns, value_sets);
460+
for(const goto_programt::targett &inst : loop)
461+
{
462+
goto_rw(inst, rw_set);
463+
}
464+
forall_rw_range_set_w_objects(it, rw_set)
465+
{
466+
const symbolt *symbol_ptr;
467+
if(!ns.lookup(it->first, symbol_ptr))
468+
{
469+
modifies.insert(ns.lookup(it->first).symbol_expr());
470+
}
471+
}
412472

413473
// build the havocking code
414474
goto_programt havoc_code;
@@ -477,18 +537,20 @@ const symbolt &code_contractst::new_tmp_symbol(
477537

478538
void code_contractst::apply_code_contracts()
479539
{
540+
auto vs = util_make_unique<value_set_analysis_fit>(ns);
541+
(*vs)(goto_functions);
542+
std::unique_ptr<value_setst> value_sets = std::move(vs);
543+
480544
Forall_goto_functions(it, goto_functions)
481545
{
482546
goto_functionst::goto_functiont &goto_function = it->second;
483547

484-
// TODO: This aliasing check is insufficiently strong, in general.
485-
local_may_aliast local_may_alias(goto_function);
486548
natural_loops_mutablet natural_loops(goto_function.body);
487549

488550
for(const auto &l_it : natural_loops.loop_map)
489551
{
490552
apply_invariant(goto_function,
491-
local_may_alias,
553+
*value_sets,
492554
l_it.first,
493555
l_it.second);
494556
}
@@ -497,7 +559,7 @@ void code_contractst::apply_code_contracts()
497559
{
498560
if(it->is_function_call())
499561
{
500-
apply_contract(goto_function.body, local_may_alias, it);
562+
apply_contract(goto_function.body, *value_sets, it);
501563
}
502564
}
503565
}
@@ -507,6 +569,10 @@ void code_contractst::apply_code_contracts()
507569

508570
void code_contractst::check_code_contracts()
509571
{
572+
auto vs = util_make_unique<value_set_analysis_fit>(ns);
573+
(*vs)(goto_functions);
574+
std::unique_ptr<value_setst> value_sets = std::move(vs);
575+
510576
goto_functionst::function_mapt::iterator i_it=
511577
goto_functions.function_map.find(INITIALIZE_FUNCTION);
512578
assert(i_it!=goto_functions.function_map.end());
@@ -516,14 +582,12 @@ void code_contractst::check_code_contracts()
516582
{
517583
goto_functionst::goto_functiont &goto_function = it->second;
518584

519-
// TODO: This aliasing check is insufficiently strong, in general.
520-
local_may_aliast local_may_alias(goto_function);
521585
natural_loops_mutablet natural_loops(goto_function.body);
522586

523587
for(const auto &l_it : natural_loops.loop_map)
524588
{
525589
check_apply_invariant(goto_function,
526-
local_may_alias,
590+
*value_sets,
527591
l_it.first,
528592
l_it.second);
529593
}
@@ -532,7 +596,7 @@ void code_contractst::check_code_contracts()
532596
{
533597
if(it->is_function_call())
534598
{
535-
apply_contract(goto_function.body, local_may_alias, it);
599+
apply_contract(goto_function.body, *value_sets, it);
536600
}
537601
}
538602
}

src/goto-instrument/loop_utils.cpp

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ Author: Daniel Kroening, kroening@kroening.com
1212
#include "loop_utils.h"
1313

1414
#include <util/std_expr.h>
15-
#include <util/expr_iterator.h>
1615

1716
#include <analyses/natural_loops.h>
1817
#include <analyses/local_may_alias.h>
@@ -108,41 +107,3 @@ void get_modifies(
108107
}
109108
}
110109
}
111-
112-
// TODO handle aliasing at all
113-
void get_uses(
114-
const local_may_aliast &local_may_alias,
115-
const loopt &loop,
116-
usest &uses)
117-
{
118-
for(loopt::const_iterator
119-
i_it=loop.begin(); i_it!=loop.end(); i_it++)
120-
{
121-
const goto_programt::instructiont &instruction=**i_it;
122-
if(instruction.code.is_not_nil())
123-
{
124-
for(const_depth_iteratort it=instruction.code.depth_begin();
125-
it!=instruction.code.depth_end();
126-
++it)
127-
{
128-
if((*it).id()==ID_symbol)
129-
{
130-
uses.insert(*it);
131-
}
132-
}
133-
}
134-
135-
if(instruction.guard.is_not_nil())
136-
{
137-
for(const_depth_iteratort it=instruction.guard.depth_begin();
138-
it!=instruction.guard.depth_end();
139-
++it)
140-
{
141-
if((*it).id()==ID_symbol)
142-
{
143-
uses.insert(*it);
144-
}
145-
}
146-
}
147-
}
148-
}

src/goto-instrument/loop_utils.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,13 @@ Author: Daniel Kroening, kroening@kroening.com
1717
class local_may_aliast;
1818

1919
typedef std::set<exprt> modifiest;
20-
typedef std::set<exprt> usest;
2120
typedef const natural_loops_mutablet::natural_loopt loopt;
2221

2322
void get_modifies(
2423
const local_may_aliast &local_may_alias,
2524
const loopt &loop,
2625
modifiest &modifies);
2726

28-
void get_uses(
29-
const local_may_aliast &local_may_alias,
30-
const loopt &loop,
31-
usest &uses);
32-
3327
void build_havoc_code(
3428
const goto_programt::targett loop_head,
3529
const modifiest &modifies,

0 commit comments

Comments
 (0)