@@ -21,6 +21,9 @@ Date: February 2016
21
21
22
22
#include < linking/static_lifetime_init.h>
23
23
24
+ #include < fstream>
25
+ #include < iostream>
26
+ #include < map>
24
27
#include < util/arith_tools.h>
25
28
#include < util/c_types.h>
26
29
#include < util/expr_util.h>
@@ -234,6 +237,121 @@ void code_contractst::add_quantified_variable(
234
237
}
235
238
}
236
239
240
+ optionalt<exprt> code_contractst::replace_old_parameter (
241
+ exprt expr,
242
+ std::map<exprt, exprt> ¶meter2ghost,
243
+ source_locationt location,
244
+ const irep_idt &function,
245
+ const irep_idt &mode,
246
+ std::list<goto_programt::instructiont> &instructions)
247
+ {
248
+ bool modified = false ;
249
+
250
+ for (auto &op : expr.operands ())
251
+ {
252
+ auto op_result = replace_old_parameter (
253
+ op, parameter2ghost, location, function, mode, instructions);
254
+ if (op_result.has_value ())
255
+ {
256
+ op = *op_result;
257
+ modified = true ;
258
+ }
259
+ }
260
+
261
+ if (expr.id () == ID_old)
262
+ {
263
+ DATA_INVARIANT (expr.operands ().size () == 1 , " old must have one operands" );
264
+
265
+ const auto ¶meter = to_old_expr (expr).variable ();
266
+
267
+ // TODO: generalize below
268
+ PRECONDITION (parameter.id () == ID_dereference);
269
+
270
+ exprt ret;
271
+ if (parameter.id () == ID_dereference)
272
+ {
273
+ const auto &dereference_expr = to_dereference_expr (parameter);
274
+ const auto &cur_pointer = dereference_expr.pointer ();
275
+
276
+ std::map<exprt, exprt>::iterator it = parameter2ghost.find (cur_pointer);
277
+
278
+ if (it == parameter2ghost.end ())
279
+ {
280
+ // 1. Create a temporary symbol expression that represents the
281
+ // history variable
282
+ symbol_exprt tmp_symbol =
283
+ new_tmp_symbol (cur_pointer.type (), location, function, mode)
284
+ .symbol_expr ();
285
+
286
+ // 2. Associate the above temporary variable to it's corresponding
287
+ // expression
288
+ parameter2ghost[cur_pointer] = tmp_symbol;
289
+
290
+ // 3. Add the required instructions to the instructions list
291
+ // 3.1 Declare the newly created temporary variable
292
+ instructions.push_back (goto_programt::make_decl (tmp_symbol, location));
293
+
294
+ // 3.2 Add an assignment such that the value pointed to by the new
295
+ // temporary variable is equal to the value of the corresponding parameter
296
+ instructions.push_back (goto_programt::make_assignment (
297
+ dereference_exprt (tmp_symbol),
298
+ dereference_exprt (cur_pointer),
299
+ location));
300
+ }
301
+
302
+ ret = dereference_exprt (parameter2ghost[cur_pointer]);
303
+ }
304
+
305
+ return ret;
306
+ }
307
+ else if (modified)
308
+ return std::move (expr);
309
+ else
310
+ return {};
311
+ }
312
+
313
+ std::pair<goto_programt::instructiont, std::list<goto_programt::instructiont>>
314
+ code_contractst::create_ensures_instruction (
315
+ exprt expression,
316
+ source_locationt location,
317
+ const irep_idt &function,
318
+ const irep_idt &mode,
319
+ bool isEnforces)
320
+ {
321
+ std::map<exprt, exprt> parameter2ghost;
322
+ std::list<goto_programt::instructiont> instructions;
323
+
324
+ // Create instruction corresponding to the ensures clause
325
+ goto_programt::instructiont instruction;
326
+ if (isEnforces)
327
+ instruction = goto_programt::make_assertion (expression, location);
328
+ else
329
+ instruction = goto_programt::make_assumption (expression, location);
330
+
331
+ // Find and replace "old" expression in the above instruction
332
+ if (has_subexpr (instruction.get_condition (), [](const exprt &expr) {
333
+ return expr.id () == ID_old;
334
+ }))
335
+ {
336
+ auto old_cond = replace_old_parameter (
337
+ instruction.get_condition (),
338
+ parameter2ghost,
339
+ location,
340
+ function,
341
+ mode,
342
+ instructions);
343
+ if (old_cond.has_value ())
344
+ {
345
+ instruction.set_condition (*old_cond);
346
+ }
347
+ }
348
+
349
+ // return a pair containing:
350
+ // 1. the instruction corresponding to the ensures clause
351
+ // 2. instructions related to initializing the history variables
352
+ return std::make_pair (instruction, instructions);
353
+ }
354
+
237
355
bool code_contractst::apply_function_contract (
238
356
const irep_idt &function_id,
239
357
goto_programt &goto_program,
@@ -301,7 +419,7 @@ bool code_contractst::apply_function_contract(
301
419
}
302
420
303
421
// Replace formal parameters
304
- code_function_callt::argumentst::const_iterator a_it=
422
+ code_function_callt::argumentst::const_iterator a_it =
305
423
call.arguments ().begin ();
306
424
for (code_typet::parameterst::const_iterator p_it = type.parameters ().begin ();
307
425
p_it != type.parameters ().end () && a_it != call.arguments ().end ();
@@ -353,7 +471,25 @@ bool code_contractst::apply_function_contract(
353
471
// function call with a SKIP statement.
354
472
if (ensures.is_not_nil ())
355
473
{
356
- *target = goto_programt::make_assumption (ensures, target->source_location );
474
+ // get all the relevant instructions related to history variables
475
+ std::
476
+ pair<goto_programt::instructiont, std::list<goto_programt::instructiont>>
477
+ ensures_pair = create_ensures_instruction (
478
+ ensures,
479
+ ensures.source_location (),
480
+ function,
481
+ function_symbol.mode ,
482
+ false );
483
+
484
+ // add all the history variable initializations
485
+ std::list<goto_programt::instructiont>::iterator it;
486
+ for (it = ensures_pair.second .begin (); it != ensures_pair.second .end (); ++it)
487
+ {
488
+ goto_program.insert_before (target, std::move (*it));
489
+ }
490
+
491
+ // add the ensures instructions
492
+ *target = std::move (ensures_pair.first );
357
493
}
358
494
else
359
495
{
@@ -793,6 +929,7 @@ void code_contractst::add_contract_check(
793
929
// if(nondet)
794
930
// decl ret
795
931
// decl parameter1 ...
932
+ // decl ghost_parameter1 ... [optional]
796
933
// assume(requires) [optional]
797
934
// ret=function(parameter1, ...)
798
935
// assert(ensures)
@@ -821,7 +958,7 @@ void code_contractst::add_contract_check(
821
958
.symbol_expr ();
822
959
check.add (goto_programt::make_decl (r, skip->source_location ));
823
960
824
- call.lhs ()= r;
961
+ call.lhs () = r;
825
962
return_stmt = code_returnt (r);
826
963
827
964
symbol_exprt ret_val (CPROVER_PREFIX " return_value" , call.lhs ().type ());
@@ -860,6 +997,32 @@ void code_contractst::add_contract_check(
860
997
code_contractst::add_quantified_variable (
861
998
requires , replace, function_symbol.mode );
862
999
1000
+ // rewrite any use of __CPROVER_return_value
1001
+ exprt ensures_cond = ensures;
1002
+ replace (ensures_cond);
1003
+
1004
+ // Prepare the history variables handling
1005
+ std::pair<goto_programt::instructiont, std::list<goto_programt::instructiont>>
1006
+ ensures_pair;
1007
+
1008
+ if (ensures.is_not_nil ())
1009
+ {
1010
+ // get all the relevant instructions related to history variables
1011
+ ensures_pair = create_ensures_instruction (
1012
+ ensures_cond,
1013
+ ensures.source_location (),
1014
+ wrapper_fun,
1015
+ function_symbol.mode ,
1016
+ true );
1017
+
1018
+ // add all the history variable initializations
1019
+ std::list<goto_programt::instructiont>::iterator it;
1020
+ for (it = ensures_pair.second .begin (); it != ensures_pair.second .end (); ++it)
1021
+ {
1022
+ check.add (std::move (*it));
1023
+ }
1024
+ }
1025
+
863
1026
// assume(requires)
864
1027
if (requires .is_not_nil ())
865
1028
{
@@ -874,15 +1037,10 @@ void code_contractst::add_contract_check(
874
1037
// ret=mangled_fun(parameter1, ...)
875
1038
check.add (goto_programt::make_function_call (call, skip->source_location ));
876
1039
877
- // rewrite any use of __CPROVER_return_value
878
- exprt ensures_cond = ensures;
879
- replace (ensures_cond);
880
-
881
1040
// assert(ensures)
882
1041
if (ensures.is_not_nil ())
883
1042
{
884
- check.add (
885
- goto_programt::make_assertion (ensures_cond, ensures.source_location ()));
1043
+ check.add (std::move (ensures_pair.first ));
886
1044
}
887
1045
888
1046
if (code_type.return_type () != empty_typet ())
0 commit comments