@@ -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
3133enum 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
8486void 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
173204void 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
375420void 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
478538void 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
508570void 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 }
0 commit comments