@@ -17,16 +17,18 @@ Date: February 2016
17
17
#include < util/c_types.h>
18
18
#include < util/expr_iterator.h>
19
19
#include < util/fresh_symbol.h>
20
+ #include < util/make_unique.h>
20
21
#include < util/replace_symbol.h>
21
22
22
23
#include < goto-programs/remove_skip.h>
23
24
24
- #include < analyses/local_may_alias .h>
25
+ #include < analyses/goto_rw .h>
25
26
26
27
#include < linking/static_lifetime_init.h>
27
28
29
+ #include < pointer-analysis/value_set_analysis_fi.h>
30
+
28
31
#include " loop_utils.h"
29
- #include " function_modifies.h"
30
32
31
33
enum class contract_opst { APPLY, CHECK };
32
34
@@ -56,12 +58,12 @@ class code_contractst
56
58
57
59
void apply_contract (
58
60
goto_programt &goto_program,
59
- const local_may_aliast &local_may_alias ,
61
+ value_setst &value_sets ,
60
62
goto_programt::targett target);
61
63
62
64
void apply_invariant (
63
65
goto_functionst::goto_functiont &goto_function,
64
- const local_may_aliast &local_may_alias ,
66
+ value_setst &value_sets ,
65
67
const goto_programt::targett loop_head,
66
68
const loopt &loop);
67
69
@@ -72,7 +74,7 @@ class code_contractst
72
74
73
75
void check_apply_invariant (
74
76
goto_functionst::goto_functiont &goto_function,
75
- const local_may_aliast &local_may_alias ,
77
+ value_setst &value_sets ,
76
78
const goto_programt::targett loop_head,
77
79
const loopt &loop);
78
80
@@ -83,7 +85,7 @@ class code_contractst
83
85
84
86
void code_contractst::apply_contract (
85
87
goto_programt &goto_program,
86
- const local_may_aliast &local_may_alias ,
88
+ value_setst &value_sets ,
87
89
goto_programt::targett target)
88
90
{
89
91
const code_function_callt &call=to_code_function_call (target->code );
@@ -116,17 +118,28 @@ void code_contractst::apply_contract(
116
118
}
117
119
118
120
// find out what can be written by the function
119
- // TODO Use a better write-set analysis.
120
121
modifiest modifies;
121
- function_modifiest function_modifies (goto_functions);
122
122
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)
125
126
{
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 ());
128
142
}
129
- function_modifies (call.function (), modifies);
130
143
131
144
// build the havocking code
132
145
goto_programt havoc_code;
@@ -137,7 +150,9 @@ void code_contractst::apply_contract(
137
150
138
151
// TODO: return value could be nil
139
152
if (type.return_type ()!=empty_typet ())
153
+ {
140
154
replace.insert (" __CPROVER_return_value" , call.lhs ());
155
+ }
141
156
142
157
// formal parameters
143
158
code_function_callt::argumentst::const_iterator a_it=
@@ -153,6 +168,18 @@ void code_contractst::apply_contract(
153
168
replace (requires );
154
169
replace (ensures);
155
170
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
+
156
183
if (requires .is_not_nil ())
157
184
{
158
185
goto_programt::instructiont a (ASSERT);
@@ -164,15 +191,19 @@ void code_contractst::apply_contract(
164
191
++target;
165
192
}
166
193
167
- // TODO some sort of replacement on havoc code
168
194
goto_program.destructive_insert (target, havoc_code);
169
195
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
+ }
171
202
}
172
203
173
204
void code_contractst::apply_invariant (
174
205
goto_functionst::goto_functiont &goto_function,
175
- const local_may_aliast &local_may_alias ,
206
+ value_setst &value_sets ,
176
207
const goto_programt::targett loop_head,
177
208
const loopt &loop)
178
209
{
@@ -207,7 +238,20 @@ void code_contractst::apply_invariant(
207
238
208
239
// find out what can get changed in the loop
209
240
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
+ }
211
255
212
256
// build the havocking code
213
257
goto_programt havoc_code;
@@ -275,7 +319,8 @@ void code_contractst::check_contract(
275
319
static_cast <const exprt&>(goto_function.type .find (ID_C_spec_ensures));
276
320
277
321
// Nothing to check if ensures is nil.
278
- if (ensures.is_nil ()) {
322
+ if (ensures.is_nil ())
323
+ {
279
324
return ;
280
325
}
281
326
@@ -374,7 +419,7 @@ void code_contractst::check_contract(
374
419
375
420
void code_contractst::check_apply_invariant (
376
421
goto_functionst::goto_functiont &goto_function,
377
- const local_may_aliast &local_may_alias ,
422
+ value_setst &value_sets ,
378
423
const goto_programt::targett loop_head,
379
424
const loopt &loop)
380
425
{
@@ -393,7 +438,9 @@ void code_contractst::check_apply_invariant(
393
438
static_cast <const exprt&>(
394
439
loop_end->guard .find (ID_C_spec_loop_invariant));
395
440
if (invariant.is_nil ())
441
+ {
396
442
return ;
443
+ }
397
444
398
445
// change H: loop; E: ...
399
446
// to
@@ -408,7 +455,20 @@ void code_contractst::check_apply_invariant(
408
455
409
456
// find out what can get changed in the loop
410
457
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
+ }
412
472
413
473
// build the havocking code
414
474
goto_programt havoc_code;
@@ -477,18 +537,20 @@ const symbolt &code_contractst::new_tmp_symbol(
477
537
478
538
void code_contractst::apply_code_contracts ()
479
539
{
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
+
480
544
Forall_goto_functions (it, goto_functions)
481
545
{
482
546
goto_functionst::goto_functiont &goto_function = it->second ;
483
547
484
- // TODO: This aliasing check is insufficiently strong, in general.
485
- local_may_aliast local_may_alias (goto_function);
486
548
natural_loops_mutablet natural_loops (goto_function.body );
487
549
488
550
for (const auto &l_it : natural_loops.loop_map )
489
551
{
490
552
apply_invariant (goto_function,
491
- local_may_alias ,
553
+ *value_sets ,
492
554
l_it.first ,
493
555
l_it.second );
494
556
}
@@ -497,7 +559,7 @@ void code_contractst::apply_code_contracts()
497
559
{
498
560
if (it->is_function_call ())
499
561
{
500
- apply_contract (goto_function.body , local_may_alias , it);
562
+ apply_contract (goto_function.body , *value_sets , it);
501
563
}
502
564
}
503
565
}
@@ -507,6 +569,10 @@ void code_contractst::apply_code_contracts()
507
569
508
570
void code_contractst::check_code_contracts ()
509
571
{
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
+
510
576
goto_functionst::function_mapt::iterator i_it=
511
577
goto_functions.function_map .find (INITIALIZE_FUNCTION);
512
578
assert (i_it!=goto_functions.function_map .end ());
@@ -516,14 +582,12 @@ void code_contractst::check_code_contracts()
516
582
{
517
583
goto_functionst::goto_functiont &goto_function = it->second ;
518
584
519
- // TODO: This aliasing check is insufficiently strong, in general.
520
- local_may_aliast local_may_alias (goto_function);
521
585
natural_loops_mutablet natural_loops (goto_function.body );
522
586
523
587
for (const auto &l_it : natural_loops.loop_map )
524
588
{
525
589
check_apply_invariant (goto_function,
526
- local_may_alias ,
590
+ *value_sets ,
527
591
l_it.first ,
528
592
l_it.second );
529
593
}
@@ -532,7 +596,7 @@ void code_contractst::check_code_contracts()
532
596
{
533
597
if (it->is_function_call ())
534
598
{
535
- apply_contract (goto_function.body , local_may_alias , it);
599
+ apply_contract (goto_function.body , *value_sets , it);
536
600
}
537
601
}
538
602
}
0 commit comments