@@ -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,27 @@ 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
+ }
128
141
}
129
- function_modifies (call.function (), modifies);
130
142
131
143
// build the havocking code
132
144
goto_programt havoc_code;
@@ -137,7 +149,9 @@ void code_contractst::apply_contract(
137
149
138
150
// TODO: return value could be nil
139
151
if (type.return_type ()!=empty_typet ())
152
+ {
140
153
replace.insert (" __CPROVER_return_value" , call.lhs ());
154
+ }
141
155
142
156
// formal parameters
143
157
code_function_callt::argumentst::const_iterator a_it=
@@ -153,6 +167,18 @@ void code_contractst::apply_contract(
153
167
replace (requires);
154
168
replace (ensures);
155
169
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
+
156
182
if (requires.is_not_nil ())
157
183
{
158
184
goto_programt::instructiont a (ASSERT);
@@ -164,15 +190,19 @@ void code_contractst::apply_contract(
164
190
++target;
165
191
}
166
192
167
- // TODO some sort of replacement on havoc code
168
193
goto_program.destructive_insert (target, havoc_code);
169
194
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
+ }
171
201
}
172
202
173
203
void code_contractst::apply_invariant (
174
204
goto_functionst::goto_functiont &goto_function,
175
- const local_may_aliast &local_may_alias ,
205
+ value_setst &value_sets ,
176
206
const goto_programt::targett loop_head,
177
207
const loopt &loop)
178
208
{
@@ -207,7 +237,20 @@ void code_contractst::apply_invariant(
207
237
208
238
// find out what can get changed in the loop
209
239
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
+ }
211
254
212
255
// build the havocking code
213
256
goto_programt havoc_code;
@@ -275,7 +318,8 @@ void code_contractst::check_contract(
275
318
static_cast <const exprt&>(goto_function.type .find (ID_C_spec_ensures));
276
319
277
320
// Nothing to check if ensures is nil.
278
- if (ensures.is_nil ()) {
321
+ if (ensures.is_nil ())
322
+ {
279
323
return ;
280
324
}
281
325
@@ -374,7 +418,7 @@ void code_contractst::check_contract(
374
418
375
419
void code_contractst::check_apply_invariant (
376
420
goto_functionst::goto_functiont &goto_function,
377
- const local_may_aliast &local_may_alias ,
421
+ value_setst &value_sets ,
378
422
const goto_programt::targett loop_head,
379
423
const loopt &loop)
380
424
{
@@ -393,7 +437,9 @@ void code_contractst::check_apply_invariant(
393
437
static_cast <const exprt&>(
394
438
loop_end->guard .find (ID_C_spec_loop_invariant));
395
439
if (invariant.is_nil ())
440
+ {
396
441
return ;
442
+ }
397
443
398
444
// change H: loop; E: ...
399
445
// to
@@ -408,7 +454,20 @@ void code_contractst::check_apply_invariant(
408
454
409
455
// find out what can get changed in the loop
410
456
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
+ }
412
471
413
472
// build the havocking code
414
473
goto_programt havoc_code;
@@ -477,18 +536,20 @@ const symbolt &code_contractst::new_tmp_symbol(
477
536
478
537
void code_contractst::apply_code_contracts ()
479
538
{
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
+
480
543
Forall_goto_functions (it, goto_functions)
481
544
{
482
545
goto_functionst::goto_functiont &goto_function = it->second ;
483
546
484
- // TODO: This aliasing check is insufficiently strong, in general.
485
- local_may_aliast local_may_alias (goto_function);
486
547
natural_loops_mutablet natural_loops (goto_function.body );
487
548
488
549
for (const auto &l_it : natural_loops.loop_map )
489
550
{
490
551
apply_invariant (goto_function,
491
- local_may_alias ,
552
+ *value_sets ,
492
553
l_it.first ,
493
554
l_it.second );
494
555
}
@@ -497,7 +558,7 @@ void code_contractst::apply_code_contracts()
497
558
{
498
559
if (it->is_function_call ())
499
560
{
500
- apply_contract (goto_function.body , local_may_alias , it);
561
+ apply_contract (goto_function.body , *value_sets , it);
501
562
}
502
563
}
503
564
}
@@ -507,6 +568,10 @@ void code_contractst::apply_code_contracts()
507
568
508
569
void code_contractst::check_code_contracts ()
509
570
{
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
+
510
575
goto_functionst::function_mapt::iterator i_it=
511
576
goto_functions.function_map .find (INITIALIZE_FUNCTION);
512
577
assert (i_it!=goto_functions.function_map .end ());
@@ -516,14 +581,12 @@ void code_contractst::check_code_contracts()
516
581
{
517
582
goto_functionst::goto_functiont &goto_function = it->second ;
518
583
519
- // TODO: This aliasing check is insufficiently strong, in general.
520
- local_may_aliast local_may_alias (goto_function);
521
584
natural_loops_mutablet natural_loops (goto_function.body );
522
585
523
586
for (const auto &l_it : natural_loops.loop_map )
524
587
{
525
588
check_apply_invariant (goto_function,
526
- local_may_alias ,
589
+ *value_sets ,
527
590
l_it.first ,
528
591
l_it.second );
529
592
}
@@ -532,7 +595,7 @@ void code_contractst::check_code_contracts()
532
595
{
533
596
if (it->is_function_call ())
534
597
{
535
- apply_contract (goto_function.body , local_may_alias , it);
598
+ apply_contract (goto_function.body , *value_sets , it);
536
599
}
537
600
}
538
601
}
0 commit comments