@@ -23,6 +23,7 @@ Date: February 2016
2323#include < goto-instrument/havoc_utils.h>
2424
2525#include < goto-programs/goto_inline.h>
26+ #include < goto-programs/goto_program.h>
2627#include < goto-programs/remove_skip.h>
2728
2829#include < langapi/language_util.h>
@@ -631,6 +632,10 @@ bool code_contractst::apply_function_contract(
631632 // with expressions from the call site (e.g. the return value).
632633 // This object tracks replacements that are common to ENSURES and REQUIRES.
633634 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+
634639 if (type.return_type () != empty_typet ())
635640 {
636641 // Check whether the function's return value is not disregarded.
@@ -640,9 +645,10 @@ bool code_contractst::apply_function_contract(
640645 // For example, if foo() ensures that its return value is > 5, then
641646 // rewrite calls to foo as follows:
642647 // 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);
646652 }
647653 else
648654 {
@@ -663,7 +669,9 @@ bool code_contractst::apply_function_contract(
663669 ns,
664670 symbol_table);
665671 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;
667675 }
668676 }
669677 }
@@ -736,8 +744,10 @@ bool code_contractst::apply_function_contract(
736744 targets.add_to_operands (std::move (target));
737745 common_replace (targets);
738746
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
741751 if (!assigns.empty ())
742752 {
743753 assigns_clauset assigns_clause (
@@ -747,14 +757,25 @@ bool code_contractst::apply_function_contract(
747757 modifiest modifies;
748758 modifies.insert (targets.operands ().cbegin (), targets.operands ().cend ());
749759
750- goto_programt assigns_havoc;
751760 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+ }
753763
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;
756774 }
757775
776+ // Insert havoc instructions immediately before the call site.
777+ insert_before_swap_and_advance (function_body, target, havoc_instructions);
778+
758779 // To remove the function call, insert statements related to the assumption.
759780 // Then, replace the function call with a SKIP statement.
760781 if (!ensures.is_false ())
0 commit comments