Skip to content

Commit d9480d4

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 d9480d4

File tree

4 files changed

+93
-76
lines changed

4 files changed

+93
-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: 91 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,27 @@ 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+
}
128141
}
129-
function_modifies(call.function(), modifies);
130142

131143
// build the havocking code
132144
goto_programt havoc_code;
@@ -137,7 +149,9 @@ void code_contractst::apply_contract(
137149

138150
// TODO: return value could be nil
139151
if(type.return_type()!=empty_typet())
152+
{
140153
replace.insert("__CPROVER_return_value", call.lhs());
154+
}
141155

142156
// formal parameters
143157
code_function_callt::argumentst::const_iterator a_it=
@@ -153,6 +167,18 @@ void code_contractst::apply_contract(
153167
replace(requires);
154168
replace(ensures);
155169

170+
// Havoc the return value of the function call.
171+
if(type.return_type()!=empty_typet())
172+
{
173+
const exprt &lhs = call.lhs();
174+
const exprt &rhs = side_effect_expr_nondett(call.lhs().type());
175+
target->make_assignment(code_assignt(lhs, rhs));
176+
}
177+
else
178+
{
179+
target->make_skip();
180+
}
181+
156182
if(requires.is_not_nil())
157183
{
158184
goto_programt::instructiont a(ASSERT);
@@ -164,15 +190,19 @@ void code_contractst::apply_contract(
164190
++target;
165191
}
166192

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

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

173203
void code_contractst::apply_invariant(
174204
goto_functionst::goto_functiont &goto_function,
175-
const local_may_aliast &local_may_alias,
205+
value_setst &value_sets,
176206
const goto_programt::targett loop_head,
177207
const loopt &loop)
178208
{
@@ -207,7 +237,20 @@ void code_contractst::apply_invariant(
207237

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

212255
// build the havocking code
213256
goto_programt havoc_code;
@@ -275,7 +318,8 @@ void code_contractst::check_contract(
275318
static_cast<const exprt&>(goto_function.type.find(ID_C_spec_ensures));
276319

277320
// Nothing to check if ensures is nil.
278-
if(ensures.is_nil()) {
321+
if(ensures.is_nil())
322+
{
279323
return;
280324
}
281325

@@ -374,7 +418,7 @@ void code_contractst::check_contract(
374418

375419
void code_contractst::check_apply_invariant(
376420
goto_functionst::goto_functiont &goto_function,
377-
const local_may_aliast &local_may_alias,
421+
value_setst &value_sets,
378422
const goto_programt::targett loop_head,
379423
const loopt &loop)
380424
{
@@ -393,7 +437,9 @@ void code_contractst::check_apply_invariant(
393437
static_cast<const exprt&>(
394438
loop_end->guard.find(ID_C_spec_loop_invariant));
395439
if(invariant.is_nil())
440+
{
396441
return;
442+
}
397443

398444
// change H: loop; E: ...
399445
// to
@@ -408,7 +454,20 @@ void code_contractst::check_apply_invariant(
408454

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

413472
// build the havocking code
414473
goto_programt havoc_code;
@@ -477,18 +536,20 @@ const symbolt &code_contractst::new_tmp_symbol(
477536

478537
void code_contractst::apply_code_contracts()
479538
{
539+
auto vs = util_make_unique<value_set_analysis_fit>(ns);
540+
(*vs)(goto_functions);
541+
std::unique_ptr<value_setst> value_sets = std::move(vs);
542+
480543
Forall_goto_functions(it, goto_functions)
481544
{
482545
goto_functionst::goto_functiont &goto_function = it->second;
483546

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

488549
for(const auto &l_it : natural_loops.loop_map)
489550
{
490551
apply_invariant(goto_function,
491-
local_may_alias,
552+
*value_sets,
492553
l_it.first,
493554
l_it.second);
494555
}
@@ -497,7 +558,7 @@ void code_contractst::apply_code_contracts()
497558
{
498559
if(it->is_function_call())
499560
{
500-
apply_contract(goto_function.body, local_may_alias, it);
561+
apply_contract(goto_function.body, *value_sets, it);
501562
}
502563
}
503564
}
@@ -507,6 +568,10 @@ void code_contractst::apply_code_contracts()
507568

508569
void code_contractst::check_code_contracts()
509570
{
571+
auto vs = util_make_unique<value_set_analysis_fit>(ns);
572+
(*vs)(goto_functions);
573+
std::unique_ptr<value_setst> value_sets = std::move(vs);
574+
510575
goto_functionst::function_mapt::iterator i_it=
511576
goto_functions.function_map.find(INITIALIZE_FUNCTION);
512577
assert(i_it!=goto_functions.function_map.end());
@@ -516,14 +581,12 @@ void code_contractst::check_code_contracts()
516581
{
517582
goto_functionst::goto_functiont &goto_function = it->second;
518583

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

523586
for(const auto &l_it : natural_loops.loop_map)
524587
{
525588
check_apply_invariant(goto_function,
526-
local_may_alias,
589+
*value_sets,
527590
l_it.first,
528591
l_it.second);
529592
}
@@ -532,7 +595,7 @@ void code_contractst::check_code_contracts()
532595
{
533596
if(it->is_function_call())
534597
{
535-
apply_contract(goto_function.body, local_may_alias, it);
598+
apply_contract(goto_function.body, *value_sets, it);
536599
}
537600
}
538601
}

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, [email protected]
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, [email protected]
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)