@@ -23,6 +23,7 @@ Date: February 2016
23
23
#include < goto-instrument/havoc_utils.h>
24
24
25
25
#include < goto-programs/goto_inline.h>
26
+ #include < goto-programs/goto_program.h>
26
27
#include < goto-programs/remove_skip.h>
27
28
28
29
#include < langapi/language_util.h>
@@ -631,6 +632,10 @@ bool code_contractst::apply_function_contract(
631
632
// with expressions from the call site (e.g. the return value).
632
633
// This object tracks replacements that are common to ENSURES and REQUIRES.
633
634
replace_symbolt common_replace;
635
+
636
+ // keep track of the call's return expression to make it nondet later
637
+ optionalt<exprt> call_ret_opt = {};
638
+
634
639
if (type.return_type () != empty_typet ())
635
640
{
636
641
// Check whether the function's return value is not disregarded.
@@ -640,9 +645,10 @@ bool code_contractst::apply_function_contract(
640
645
// For example, if foo() ensures that its return value is > 5, then
641
646
// rewrite calls to foo as follows:
642
647
// x = foo() -> assume(__CPROVER_return_value > 5) -> assume(x > 5)
643
- symbol_exprt ret_val (
644
- CPROVER_PREFIX " return_value" , const_target->call_lhs ().type ());
645
- common_replace.insert (ret_val, const_target->call_lhs ());
648
+ auto &lhs_expr = const_target->call_lhs ();
649
+ call_ret_opt = lhs_expr;
650
+ symbol_exprt ret_val (CPROVER_PREFIX " return_value" , lhs_expr.type ());
651
+ common_replace.insert (ret_val, lhs_expr);
646
652
}
647
653
else
648
654
{
@@ -663,7 +669,9 @@ bool code_contractst::apply_function_contract(
663
669
ns,
664
670
symbol_table);
665
671
symbol_exprt ret_val (CPROVER_PREFIX " return_value" , type.return_type ());
666
- common_replace.insert (ret_val, fresh.symbol_expr ());
672
+ auto fresh_sym_expr = fresh.symbol_expr ();
673
+ common_replace.insert (ret_val, fresh_sym_expr);
674
+ call_ret_opt = fresh_sym_expr;
667
675
}
668
676
}
669
677
}
@@ -736,8 +744,10 @@ bool code_contractst::apply_function_contract(
736
744
targets.add_to_operands (std::move (target));
737
745
common_replace (targets);
738
746
739
- // Create a series of non-deterministic assignments to havoc the variables
740
- // in the assigns clause.
747
+ // Create a sequence of non-deterministic assignments...
748
+ goto_programt havoc_instructions;
749
+
750
+ // ...for assigns clause targets
741
751
if (!assigns.empty ())
742
752
{
743
753
assigns_clauset assigns_clause (
@@ -747,14 +757,25 @@ bool code_contractst::apply_function_contract(
747
757
modifiest modifies;
748
758
modifies.insert (targets.operands ().cbegin (), targets.operands ().cend ());
749
759
750
- goto_programt assigns_havoc;
751
760
havoc_assigns_targetst havoc_gen (modifies, ns);
752
- havoc_gen.append_full_havoc_code (location, assigns_havoc);
761
+ havoc_gen.append_full_havoc_code (location, havoc_instructions);
762
+ }
753
763
754
- // Insert the non-deterministic assignment immediately before the call site.
755
- insert_before_swap_and_advance (function_body, target, assigns_havoc);
764
+ // ...for the return value
765
+ if (call_ret_opt.has_value ())
766
+ {
767
+ auto &call_ret = call_ret_opt.value ();
768
+ auto &loc = call_ret.source_location ();
769
+ auto &type = call_ret.type ();
770
+ side_effect_expr_nondett expr (type, location);
771
+ auto target = havoc_instructions.add (
772
+ goto_programt::make_assignment (call_ret, expr, loc));
773
+ target->code_nonconst ().add_source_location () = loc;
756
774
}
757
775
776
+ // Insert havoc instructions immediately before the call site.
777
+ insert_before_swap_and_advance (function_body, target, havoc_instructions);
778
+
758
779
// To remove the function call, insert statements related to the assumption.
759
780
// Then, replace the function call with a SKIP statement.
760
781
if (!ensures.is_false ())
0 commit comments