CBMC
Loading...
Searching...
No Matches
contracts.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Verify and use annotated loop and function contracts
4
5Author: Michael Tautschnig
6
7Date: February 2016
8
9\*******************************************************************/
10
13
14#include "contracts.h"
15
16#include <util/c_types.h>
18#include <util/format_expr.h>
19#include <util/fresh_symbol.h>
21
25
29
30#include "cfg_info.h"
32#include "inlining_decorator.h"
34#include "memory_predicates.h"
35#include "utils.h"
36
37#include <algorithm>
38#include <map>
39
41 const irep_idt &function_name,
43 const local_may_aliast &local_may_alias,
46 const loopt &loop,
48 exprt invariant,
50 const irep_idt &mode)
51{
52 const auto loop_head_location = loop_head->source_location();
53 const auto loop_number = loop_end->loop_number;
54
55 // Vector representing a (possibly multidimensional) decreases clause
56 const auto &decreases_clause_exprs = decreases_clause.operands();
57
58 // Temporary variables for storing the multidimensional decreases clause
59 // at the start of and end of a loop body
60 std::vector<symbol_exprt> old_decreases_vars, new_decreases_vars;
61
62 // instrument
63 //
64 // ... preamble ...
65 // HEAD:
66 // ... eval guard ...
67 // if (!guard)
68 // goto EXIT;
69 // ... loop body ...
70 // goto HEAD;
71 // EXIT:
72 // ... postamble ...
73 //
74 // to
75 //
76 // ... preamble ...
77 // ,- initialize loop_entry history vars;
78 // | entered_loop = false
79 // loop assigns check | initial_invariant_val = invariant_expr;
80 // - unchecked, temps | in_base_case = true;
81 // func assigns check | snapshot (write_set);
82 // - disabled via pragma | goto HEAD;
83 // | STEP:
84 // --. | assert (initial_invariant_val);
85 // loop assigns check | | in_base_case = false;
86 // - not applicable >======= in_loop_havoc_block = true;
87 // func assigns check | | havoc (assigns_set);
88 // + deferred | | in_loop_havoc_block = false;
89 // --' | assume (invariant_expr);
90 // `- old_variant_val = decreases_clause_expr;
91 // * HEAD:
92 // loop assigns check ,- ... eval guard ...
93 // + assertions added | if (!guard)
94 // func assigns check | goto EXIT;
95 // - disabled via pragma `- ... loop body ...
96 // ,- entered_loop = true
97 // | if (in_base_case)
98 // | goto STEP;
99 // loop assigns check | assert (invariant_expr);
100 // - unchecked, temps | new_variant_val = decreases_clause_expr;
101 // func assigns check | assert (new_variant_val < old_variant_val);
102 // - disabled via pragma | dead old_variant_val, new_variant_val;
103 // | * assume (false);
104 // | * EXIT:
105 // To be inserted at ,~~~|~~~~ assert (entered_loop ==> !in_base_case);
106 // every unique EXIT | | dead loop_entry history vars, in_base_case;
107 // (break, goto etc.) `~~~`- ~~ dead initial_invariant_val, entered_loop;
108 // ... postamble ..
109 //
110 // Asterisks (*) denote anchor points (goto targets) for instrumentations.
111 // We insert generated code above and/below these targets.
112 //
113 // Assertions for assigns clause checking are inserted in the loop body.
114
115 // Process "loop_entry" history variables.
116 // We find and replace all "__CPROVER_loop_entry" subexpressions in invariant.
118 symbol_table, invariant, loop_head_location, mode);
119 invariant.swap(replace_history_result.expression_after_replacement);
120 const auto &history_var_map = replace_history_result.parameter_to_history;
121 // an intermediate goto_program to store generated instructions
122 // to be inserted before the loop head
124 replace_history_result.history_construction;
125
126 // Create a temporary to track if we entered the loop,
127 // i.e., the loop guard was satisfied.
128 const auto entered_loop =
130 bool_typet(),
131 id2string(loop_head_location.get_function()),
132 std::string(ENTERED_LOOP) + "__" + std::to_string(loop_number),
134 mode,
136 .symbol_expr();
141
142 // Create a snapshot of the invariant so that we can check the base case,
143 // if the loop is not vacuous and must be abstracted with contracts.
144 const auto initial_invariant_val =
146 bool_typet(),
147 id2string(loop_head_location.get_function()),
150 mode,
152 .symbol_expr();
155 {
156 // Although the invariant at this point will not have side effects,
157 // it is still a C expression, and needs to be "goto_convert"ed.
158 // Note that this conversion may emit many GOTO instructions.
160 initial_invariant_val, invariant};
161 initial_invariant_value_assignment.add_source_location() =
163
165 converter.goto_convert(
167 }
168
169 // Create a temporary variable to track base case vs inductive case
170 // instrumentation of the loop.
172 bool_typet(),
173 id2string(loop_head_location.get_function()),
174 "__in_base_case",
176 mode,
178 .symbol_expr();
183
184 // CAR snapshot instructions for checking assigns clause
186
187 loop_cfg_infot cfg_info(goto_function, loop);
188
189 // track static local symbols
191 function_name,
193 cfg_info,
196
197 instrument_spec_assigns.track_static_locals_between(
199
200 // set of targets to havoc
202
203 if(assigns_clause.is_nil())
204 {
205 // No assigns clause was specified for this loop.
206 // Infer memory locations assigned by the loop from the loop instructions
207 // and the inferred aliasing relation.
208 try
209 {
210 infer_loop_assigns(local_may_alias, loop, to_havoc);
211
212 // remove loop-local symbols from the inferred set
213 cfg_info.erase_locals(to_havoc);
214
215 // If the set contains pairs (i, a[i]),
216 // we widen them to (i, __CPROVER_POINTER_OBJECT(a))
218
219 log.debug() << "No loop assigns clause provided. Inferred targets: {";
220 // Add inferred targets to the loop assigns clause.
221 bool ran_once = false;
222 for(const auto &target : to_havoc)
223 {
224 if(ran_once)
225 log.debug() << ", ";
226 ran_once = true;
227 log.debug() << format(target);
228 instrument_spec_assigns.track_spec_target(
229 target, snapshot_instructions);
230 }
231 log.debug() << "}" << messaget::eom;
232
233 instrument_spec_assigns.get_static_locals(
234 std::inserter(to_havoc, to_havoc.end()));
235 }
236 catch(const analysis_exceptiont &exc)
237 {
238 log.error() << "Failed to infer variables being modified by the loop at "
240 << ".\nPlease specify an assigns clause.\nReason:"
241 << messaget::eom;
242 throw exc;
243 }
244 }
245 else
246 {
247 // An assigns clause was specified for this loop.
248 // Add the targets to the set of expressions to havoc.
249 for(const auto &target : assigns_clause.operands())
250 {
251 to_havoc.insert(target);
252 instrument_spec_assigns.track_spec_target(target, snapshot_instructions);
253 }
254 }
255
256 // Insert instrumentation
257 // This must be done before havocing the write set.
258 // FIXME: this is not true for write set targets that
259 // might depend on other write set targets.
261
262 // Insert a jump to the loop head
263 // (skipping over the step case initialization code below)
266
267 // The STEP case instructions follow.
268 // We skip past it initially, because of the unconditional jump above,
269 // but jump back here if we get past the loop guard while in_base_case.
270
271 const auto step_case_target =
274
275 // If we jump here, then the loop runs at least once,
276 // so add the base case assertion:
277 // assert(initial_invariant_val)
278 // We use a block scope for assertion, since it's immediately goto converted,
279 // and doesn't need to be kept around.
280 {
282 assertion.add_source_location() = loop_head_location;
283 assertion.add_source_location().set_comment(
284 "Check loop invariant before entry");
285
287 converter.goto_convert(assertion, pre_loop_head_instrs, mode);
288 }
289
290 // Insert the first block of pre_loop_head_instrs,
291 // with a pragma to disable assigns clause checking.
292 // All of the initialization code so far introduces local temporaries,
293 // which need not be checked against the enclosing scope's assigns clause.
294 goto_function.body.destructive_insert(
296
297 // Generate havocing code for assignment targets.
298 // ASSIGN in_loop_havoc_block = true;
299 // havoc (assigns_set);
300 // ASSIGN in_loop_havoc_block = false;
301 const auto in_loop_havoc_block =
303 bool_typet(),
304 id2string(loop_head_location.get_function()),
305 std::string(IN_LOOP_HAVOC_BLOCK) + +"__" + std::to_string(loop_number),
307 mode,
309 .symbol_expr();
316 havoc_gen.append_full_havoc_code(loop_head_location, pre_loop_head_instrs);
319
320 // Insert the second block of pre_loop_head_instrs: the havocing code.
321 // We do not `add_pragma_disable_assigns_check`,
322 // so that the enclosing scope's assigns clause instrumentation
323 // would pick these havocs up for inclusion (subset) checks.
324 goto_function.body.destructive_insert(loop_head, pre_loop_head_instrs);
325
326 // Generate: assume(invariant) just after havocing
327 // We use a block scope for assumption, since it's immediately goto converted,
328 // and doesn't need to be kept around.
329 {
330 code_assumet assumption{invariant};
332
334 converter.goto_convert(assumption, pre_loop_head_instrs, mode);
335 }
336
337 // Create fresh temporary variables that store the multidimensional
338 // decreases clause's value before and after the loop
339 for(const auto &clause : decreases_clause.operands())
340 {
341 const auto old_decreases_var =
343 clause.type(),
344 id2string(loop_head_location.get_function()),
345 "tmp_cc",
347 mode,
349 .symbol_expr();
353
354 const auto new_decreases_var =
356 clause.type(),
357 id2string(loop_head_location.get_function()),
358 "tmp_cc",
360 mode,
362 .symbol_expr();
366 }
367
368 // TODO: Fix loop contract handling for do/while loops.
369 if(loop_end->is_goto() && loop_end->condition() != true)
370 {
371 log.error() << "Loop contracts are unsupported on do/while loops: "
373 throw 0;
374
375 // non-deterministically skip the loop if it is a do-while loop.
376 // pre_loop_head_instrs.add(goto_programt::make_goto(
377 // loop_end, side_effect_expr_nondett(bool_typet(), loop_head_location)));
378 }
379
380 // Generate: assignments to store the multidimensional decreases clause's
381 // value just before the loop_head
382 if(!decreases_clause.is_nil())
383 {
384 for(size_t i = 0; i < old_decreases_vars.size(); i++)
385 {
388 old_decreases_assignment.add_source_location() = loop_head_location;
389
391 converter.goto_convert(
393 }
394
395 goto_function.body.destructive_insert(
397 }
398
399 // Insert the third and final block of pre_loop_head_instrs,
400 // with a pragma to disable assigns clause checking.
401 // The variables to store old variant value are local temporaries,
402 // which need not be checked against the enclosing scope's assigns clause.
403 goto_function.body.destructive_insert(
405
406 // Perform write set instrumentation on the entire loop.
407 instrument_spec_assigns.instrument_instructions(
408 goto_function.body,
409 loop_head,
410 loop_end,
411 [&loop](const goto_programt::targett &t) { return loop.contains(t); });
412
413 // Now we begin instrumenting at the loop_end.
414 // `pre_loop_end_instrs` are to be inserted before `loop_end`.
416
417 // Record that we entered the loop.
420
421 // Jump back to the step case to havoc the write set, assume the invariant,
422 // and execute an arbitrary iteration.
425
426 // The following code is only reachable in the step case,
427 // i.e., when in_base_case == false,
428 // because of the unconditional jump above.
429
430 // Generate the inductiveness check:
431 // assert(invariant)
432 // We use a block scope for assertion, since it's immediately goto converted,
433 // and doesn't need to be kept around.
434 {
435 code_assertt assertion{invariant};
437 assertion.add_source_location().set_comment(
438 "Check that loop invariant is preserved");
439
441 converter.goto_convert(assertion, pre_loop_end_instrs, mode);
442 }
443
444 // Generate: assignments to store the multidimensional decreases clause's
445 // value after one iteration of the loop
446 if(!decreases_clause.is_nil())
447 {
448 for(size_t i = 0; i < new_decreases_vars.size(); i++)
449 {
452 new_decreases_assignment.add_source_location() = loop_head_location;
453
455 converter.goto_convert(
457 }
458
459 // Generate: assertion that the multidimensional decreases clause's value
460 // after the loop is lexicographically smaller than its initial value.
465 monotonic_decreasing_assertion.add_source_location().set_comment(
466 "Check decreases clause on loop iteration");
467
469 converter.goto_convert(
471
472 // Discard the temporary variables that store decreases clause's value
473 for(size_t i = 0; i < old_decreases_vars.size(); i++)
474 {
479 }
480 }
481
483 goto_function.body,
484 loop_end,
486
487 // change the back edge into assume(false) or assume(guard)
488 loop_end->turn_into_assume();
489 loop_end->condition_nonconst() = boolean_negate(loop_end->condition());
490
491 std::set<goto_programt::targett, goto_programt::target_less_than>
493 // Find all exit points of the loop, make temporary variables `DEAD`,
494 // and check that step case was checked for non-vacuous loops.
495 for(const auto &t : loop)
496 {
497 if(!t->is_goto())
498 continue;
499
500 auto exit_target = t->get_target();
501 if(
502 loop.contains(exit_target) ||
504 continue;
505
507
509 // Assertion to check that step case was checked if we entered the loop.
511 annotated_location.set_comment(
512 "Check that loop instrumentation was not truncated");
516 // Instructions to make all the temporaries go dead.
521 for(const auto &v : history_var_map)
522 {
525 }
526 // Insert these instructions, preserving the loop end target.
528 goto_function.body, exit_target, pre_loop_exit_instrs);
529 }
530}
531
534static void throw_on_unsupported(const goto_programt &program)
535{
536 for(const auto &it : program.instructions)
537 {
538 if(
539 it.is_function_call() && it.call_function().id() == ID_symbol &&
540 to_symbol_expr(it.call_function()).get_identifier() == CPROVER_PREFIX
541 "obeys_contract")
542 {
544 CPROVER_PREFIX "obeys_contract is not supported in this version",
545 it.source_location());
546 }
547 }
548}
549
553 symbol_tablet &symbol_table,
554 goto_convertt &converter,
556 const irep_idt &mode,
557 const std::function<void(goto_programt &)> &is_fresh_update,
558 goto_programt &program,
559 const source_locationt &location)
560{
561 goto_programt constraint;
562 if(location.get_property_class() == ID_assume)
563 {
565 assumption.add_source_location() = location;
566 converter.goto_convert(assumption, constraint, mode);
567 }
568 else
569 {
571 assertion.add_source_location() = location;
572 converter.goto_convert(assertion, constraint, mode);
573 }
574 is_fresh_update(constraint);
575 throw_on_unsupported(constraint);
576 program.destructive_append(constraint);
577}
578
579static const code_with_contract_typet &
580get_contract(const irep_idt &function, const namespacet &ns)
581{
582 const std::string &function_str = id2string(function);
583 const auto &function_symbol = ns.lookup(function);
584
585 const symbolt *contract_sym;
586 if(ns.lookup("contract::" + function_str, contract_sym))
587 {
588 // no contract provided in the source or just an empty assigns clause
590 }
591
592 const auto &type = to_code_with_contract_type(contract_sym->type);
594 type == function_symbol.type,
595 "front-end should have rejected re-declarations with a different type");
596
597 return type;
598}
599
601 const irep_idt &function,
602 const source_locationt &location,
605{
606 const auto &const_target =
607 static_cast<const goto_programt::targett &>(target);
608 // Return if the function is not named in the call; currently we don't handle
609 // function pointers.
610 PRECONDITION(const_target->call_function().id() == ID_symbol);
611
612 const irep_idt &target_function =
613 to_symbol_expr(const_target->call_function()).get_identifier();
614 const symbolt &function_symbol = ns.lookup(target_function);
615 const code_typet &function_type = to_code_type(function_symbol.type);
616
617 // Check if the function actually has a contract before attempting to use it.
618 // If not, produce a hard error for soundness.
619 const symbolt *contract_sym;
620 if(ns.lookup("contract::" + id2string(target_function), contract_sym))
621 {
623 "Function '" + id2string(target_function) +
624 "' does not have a contract. " +
625 "A contract must be explicitly provided. If you need a trivial " +
626 "contract, please add explicit " +
627 CPROVER_PREFIX "requires and " CPROVER_PREFIX
628 "ensures clauses to the function.");
629 }
630
631 // Isolate each component of the contract.
632 const auto &type = get_contract(target_function, ns);
633
634 // Prepare to instantiate expressions in the callee
635 // with expressions from the call site (e.g. the return value).
637
638 // keep track of the call's return expression to make it nondet later
639 std::optional<exprt> call_ret_opt = {};
640
641 // if true, the call return variable variable was created during replacement
642 bool call_ret_is_fresh_var = false;
643
644 if(function_type.return_type() != empty_typet())
645 {
646 // Check whether the function's return value is not disregarded.
647 if(target->call_lhs().is_not_nil())
648 {
649 // If so, have it replaced appropriately.
650 // For example, if foo() ensures that its return value is > 5, then
651 // rewrite calls to foo as follows:
652 // x = foo() -> assume(__CPROVER_return_value > 5) -> assume(x > 5)
653 auto &lhs_expr = const_target->call_lhs();
656 }
657 else
658 {
659 // If the function does return a value, but the return value is
660 // disregarded, check if the postcondition includes the return value.
661 if(std::any_of(
662 type.c_ensures().begin(),
663 type.c_ensures().end(),
664 [](const exprt &e) {
665 return has_symbol_expr(
666 to_lambda_expr(e).where(), CPROVER_PREFIX "return_value", true);
667 }))
668 {
669 // The postcondition does mention __CPROVER_return_value, so mint a
670 // fresh variable to replace __CPROVER_return_value with.
673 function_type.return_type(),
674 id2string(target_function),
675 "ignored_return_value",
676 const_target->source_location(),
677 symbol_table.lookup_ref(target_function).mode,
678 ns,
680 auto fresh_sym_expr = fresh.symbol_expr();
683 }
684 else
685 {
686 // unused, add a dummy with the right type
687 instantiation_values.push_back(
688 exprt{ID_nil, function_type.return_type()});
689 }
690 }
691 }
692
693 // Replace formal parameters
694 const auto &arguments = const_target->call_arguments();
696 instantiation_values.end(), arguments.begin(), arguments.end());
697
698 const auto &mode = function_symbol.mode;
699
700 // new program where all contract-derived instructions are added
702
704 goto_model, log.get_message_handler(), target_function);
705 is_fresh.create_declarations();
706 is_fresh.add_memory_map_decl(new_program);
707
708 // Generate: assert(requires)
709 for(const auto &clause : type.c_requires())
710 {
712 to_lambda_expr(clause).application(instantiation_values);
713 source_locationt _location = clause.source_location();
714 _location.set_line(location.get_line());
715 _location.set_comment(std::string("Check requires clause of ")
716 .append(target_function.c_str())
717 .append(" in ")
718 .append(function.c_str()));
719 _location.set_property_class(ID_precondition);
723 converter,
725 mode,
726 [&is_fresh](goto_programt &c_requires) {
727 is_fresh.update_requires(c_requires);
728 },
730 _location);
731 }
732
733 // Generate all the instructions required to initialize history variables
735 for(auto clause : type.c_ensures())
736 {
738 to_lambda_expr(clause).application(instantiation_values);
739 instantiated_clause.add_source_location() = clause.source_location();
743 }
744
745 // ASSIGNS clause should not refer to any quantified variables,
746 // and only refer to the common symbols to be replaced.
747 exprt::operandst targets;
748 for(auto &target : type.c_assigns())
749 targets.push_back(to_lambda_expr(target).application(instantiation_values));
750
751 // Create a sequence of non-deterministic assignments ...
752
753 // ... for the assigns clause targets and static locals
755 function_cfg_infot cfg_info({});
757 target_function,
758 targets,
760 cfg_info,
761 location,
764
765 havocker.get_instructions(havoc_instructions);
766
767 // ... for the return value
768 if(call_ret_opt.has_value())
769 {
770 auto &call_ret = call_ret_opt.value();
771 auto &loc = call_ret.source_location();
772 auto &type = call_ret.type();
773
774 // Declare if fresh
778
779 side_effect_expr_nondett expr(type, location);
781 code_assignt{call_ret, std::move(expr), loc}, loc));
782 }
783
784 // Insert havoc instructions immediately before the call site.
785 new_program.destructive_append(havoc_instructions);
786
787 // Generate: assume(ensures)
788 for(auto &clause : instantiated_ensures_clauses)
789 {
790 if(clause == false)
791 {
793 std::string("Attempt to assume false at ")
794 .append(clause.source_location().as_string())
795 .append(".\nPlease update ensures clause to avoid vacuity."));
796 }
797 source_locationt _location = clause.source_location();
798 _location.set_comment("Assume ensures clause");
799 _location.set_property_class(ID_assume);
800
804 converter,
805 clause,
806 mode,
807 [&is_fresh](goto_programt &ensures) { is_fresh.update_ensures(ensures); },
809 _location);
810 }
811
812 // Kill return value variable if fresh
814 {
816 log.warning(), [&target](messaget::mstreamt &mstream) {
817 target->output(mstream);
818 mstream << messaget::eom;
819 });
820 auto dead_inst =
822 function_body.insert_before_swap(target, dead_inst);
823 ++target;
824 }
825
826 is_fresh.add_memory_map_dead(new_program);
827
828 // Erase original function call
829 *target = goto_programt::make_skip();
830
831 // insert contract replacement instructions
833
834 // Add this function to the set of replaced functions.
835 summarized.insert(target_function);
836
837 // restore global goto_program consistency
839}
840
842 const irep_idt &function_name,
843 goto_functionst::goto_functiont &goto_function)
844{
845 const bool may_have_loops = std::any_of(
846 goto_function.body.instructions.begin(),
847 goto_function.body.instructions.end(),
848 [](const goto_programt::instructiont &instruction) {
849 return instruction.is_backwards_goto();
850 });
851
852 if(!may_have_loops)
853 return;
854
857
858 decorated.throw_on_recursive_calls(log, 0);
859
860 // restore internal invariants
862
863 local_may_aliast local_may_alias(goto_function);
864 natural_loops_mutablet natural_loops(goto_function.body);
865
866 // A graph node type that stores information about a loop.
867 // We create a DAG representing nesting of various loops in goto_function,
868 // sort them topologically, and instrument them in the top-sorted order.
869 //
870 // The goal here is not avoid explicit "subset checks" on nested write sets.
871 // When instrumenting in a top-sorted order,
872 // the outer loop would no longer observe the inner loop's write set,
873 // but only corresponding `havoc` statements,
874 // which can be instrumented in the usual way to achieve a "subset check".
875
876 struct loop_graph_nodet : public graph_nodet<empty_edget>
877 {
878 const typename natural_loops_mutablet::loopt &content;
881
883 const typename natural_loops_mutablet::loopt &loop,
884 const goto_programt::targett head,
885 const goto_programt::targett end,
886 const exprt &assigns,
887 const exprt &inv,
888 const exprt &decreases)
889 : content(loop),
890 head_target(head),
891 end_target(end),
892 assigns_clause(assigns),
893 invariant(inv),
894 decreases_clause(decreases)
895 {
896 }
897 };
899
900 std::list<size_t> to_check_contracts_on_children;
901
902 std::map<
904 std::pair<goto_programt::targett, natural_loops_mutablet::loopt>,
907
908 for(const auto &loop_head_and_content : natural_loops.loop_map)
909 {
910 const auto &loop_body = loop_head_and_content.second;
911 // Skip empty loops and self-looped node.
912 if(loop_body.size() <= 1)
913 continue;
914
915 auto loop_head = loop_head_and_content.first;
916 auto loop_end = loop_head;
917
918 // Find the last back edge to `loop_head`
919 for(const auto &t : loop_body)
920 {
921 if(
922 t->is_goto() && t->get_target() == loop_head &&
923 t->location_number > loop_end->location_number)
924 loop_end = t;
925 }
926
927 if(loop_end == loop_head)
928 {
929 log.error() << "Could not find end of the loop starting at: "
930 << loop_head->source_location() << messaget::eom;
931 throw 0;
932 }
933
934 // By definition the `loop_body` is a set of instructions computed
935 // by `natural_loops` based on the CFG.
936 // Since we perform assigns clause instrumentation by sequentially
937 // traversing instructions from `loop_head` to `loop_end`,
938 // here we ensure that all instructions in `loop_body` belong within
939 // the [loop_head, loop_end] target range.
940
941 // Check 1. (i \in loop_body) ==> loop_head <= i <= loop_end
942 for(const auto &i : loop_body)
943 {
944 if(
945 loop_head->location_number > i->location_number ||
946 i->location_number > loop_end->location_number)
947 {
949 log.error(), [&i, &loop_head](messaget::mstreamt &mstream) {
950 mstream << "Computed loop at " << loop_head->source_location()
951 << "contains an instruction beyond [loop_head, loop_end]:"
952 << messaget::eom;
953 i->output(mstream);
954 mstream << messaget::eom;
955 });
956 throw 0;
957 }
958 }
959
960 if(!loop_head_ends.emplace(loop_head, std::make_pair(loop_end, loop_body))
961 .second)
963 }
964
965 for(auto &loop_head_end : loop_head_ends)
966 {
967 auto loop_head = loop_head_end.first;
968 auto loop_end = loop_head_end.second.first;
969 // After loop-contract instrumentation, jumps to the `loop_head` will skip
970 // some instrumented instructions. So we want to make sure that there is
971 // only one jump targeting `loop_head` from `loop_end` before loop-contract
972 // instrumentation.
973 // Add a skip before `loop_head` and let all jumps (except for the
974 // `loop_end`) that target to the `loop_head` target to the skip
975 // instead.
977 goto_function.body, loop_head, goto_programt::make_skip());
978 loop_end->set_target(loop_head);
979
981 exprt invariant =
985
986 if(invariant.is_nil())
987 {
988 if(decreases_clause.is_not_nil() || assigns_clause.is_not_nil())
989 {
990 invariant = true_exprt{};
991 // assigns clause is missing; we will try to automatic inference
992 log.warning()
993 << "The loop at " << loop_head->source_location().as_string()
994 << " does not have an invariant in its contract.\n"
995 << "Hence, a default invariant ('true') is being used.\n"
996 << "This choice is sound, but verification may fail"
997 << " if it is be too weak to prove the desired properties."
998 << messaget::eom;
999 }
1000 }
1001 else
1002 {
1003 invariant = conjunction(invariant.operands());
1004 if(decreases_clause.is_nil())
1005 {
1006 log.warning() << "The loop at "
1007 << loop_head->source_location().as_string()
1008 << " does not have a decreases clause in its contract.\n"
1009 << "Termination of this loop will not be verified."
1010 << messaget::eom;
1011 }
1012 }
1013
1014 const auto idx = loop_nesting_graph.add_node(
1015 loop_head_end.second.second,
1016 loop_head,
1017 loop_end,
1019 invariant,
1021
1022 if(
1023 assigns_clause.is_nil() && invariant.is_nil() &&
1024 decreases_clause.is_nil())
1025 continue;
1026
1027 to_check_contracts_on_children.push_back(idx);
1028 }
1029
1030 for(size_t outer = 0; outer < loop_nesting_graph.size(); ++outer)
1031 {
1032 for(size_t inner = 0; inner < loop_nesting_graph.size(); ++inner)
1033 {
1034 if(inner == outer)
1035 continue;
1036
1037 if(loop_nesting_graph[outer].content.contains(
1038 loop_nesting_graph[inner].head_target))
1039 {
1040 if(!loop_nesting_graph[outer].content.contains(
1041 loop_nesting_graph[inner].end_target))
1042 {
1043 log.error()
1044 << "Overlapping loops at:\n"
1045 << loop_nesting_graph[outer].head_target->source_location()
1046 << "\nand\n"
1047 << loop_nesting_graph[inner].head_target->source_location()
1048 << "\nLoops must be nested or sequential for contracts to be "
1049 "enforced."
1050 << messaget::eom;
1051 }
1052 loop_nesting_graph.add_edge(inner, outer);
1053 }
1054 }
1055 }
1056
1057 // make sure all children of a contractified loop also have contracts
1058 while(!to_check_contracts_on_children.empty())
1059 {
1060 const auto loop_idx = to_check_contracts_on_children.front();
1062
1063 const auto &loop_node = loop_nesting_graph[loop_idx];
1064 if(
1065 loop_node.assigns_clause.is_nil() && loop_node.invariant.is_nil() &&
1066 loop_node.decreases_clause.is_nil())
1067 {
1068 log.error()
1069 << "Inner loop at: " << loop_node.head_target->source_location()
1070 << " does not have contracts, but an enclosing loop does.\n"
1071 << "Please provide contracts for this loop, or unwind it first."
1072 << messaget::eom;
1073 throw 0;
1074 }
1075
1076 for(const auto child_idx : loop_nesting_graph.get_predecessors(loop_idx))
1078 }
1079
1080 // Iterate over the (natural) loops in the function, in topo-sorted order,
1081 // and apply any loop contracts that we find.
1082 for(const auto &idx : loop_nesting_graph.topsort())
1083 {
1084 const auto &loop_node = loop_nesting_graph[idx];
1085 if(
1086 loop_node.assigns_clause.is_nil() && loop_node.invariant.is_nil() &&
1087 loop_node.decreases_clause.is_nil())
1088 continue;
1089
1090 // Computed loop "contents" needs to be refreshed to include any newly
1091 // introduced instrumentation, e.g. havoc instructions for assigns clause,
1092 // on inner loops in to the outer loop's contents.
1093 // Else, during the outer loop instrumentation these instructions will be
1094 // "masked" just as any other instruction not within its "contents."
1095
1097 natural_loops_mutablet updated_loops(goto_function.body);
1098
1099 // We will unwind all transformed loops twice. Store the names of
1100 // to-unwind-loops here and perform the unwinding after transformation done.
1101 // As described in `check_apply_loop_contracts`, loops with loop contracts
1102 // will be transformed to a loop that execute exactly twice: one for base
1103 // case and one for step case. So we unwind them here to avoid users
1104 // incorrectly unwind them only once.
1105 std::string to_unwind = id2string(function_name) + "." +
1106 std::to_string(loop_node.end_target->loop_number) +
1107 ":2";
1108 loop_names.push_back(to_unwind);
1109
1111 function_name,
1112 goto_function,
1113 local_may_alias,
1114 loop_node.head_target,
1115 loop_node.end_target,
1116 updated_loops.loop_map[loop_node.head_target],
1117 loop_node.assigns_clause,
1118 loop_node.invariant,
1119 loop_node.decreases_clause,
1120 symbol_table.lookup_ref(function_name).mode);
1121 }
1122}
1123
1125{
1126 // Get the function object before instrumentation.
1127 auto function_obj = goto_functions.function_map.find(function);
1128
1129 INVARIANT(
1131 "Function '" + id2string(function) + "'must exist in the goto program");
1132
1133 const auto &goto_function = function_obj->second;
1134 auto &function_body = function_obj->second.body;
1135
1136 function_cfg_infot cfg_info(goto_function);
1137
1139 function,
1141 cfg_info,
1144
1145 // Detect and track static local variables before inlining
1148
1149 // Full inlining of the function body
1150 // Inlining is performed so that function calls to a same function
1151 // occurring under different write sets get instrumented specifically
1152 // for each write set
1155
1156 decorated.throw_on_recursive_calls(log, 0);
1157
1158 // Clean up possible fake loops that are due to `IF 0!=0 GOTO i` instructions
1160
1161 // Restore internal coherence in the programs
1163
1164 INVARIANT(
1166 "Loops remain in function '" + id2string(function) +
1167 "', assigns clause checking instrumentation cannot be applied.");
1168
1169 // Start instrumentation
1170 auto instruction_it = function_body.instructions.begin();
1171
1172 // Inject local static snapshots
1175
1176 // Track targets mentioned in the specification
1177 const symbolt &function_symbol = ns.lookup(function);
1178 const code_typet &function_type = to_code_type(function_symbol.type);
1180 // assigns clauses cannot refer to the return value, but we still need an
1181 // element in there to apply the lambda function consistently
1182 if(function_type.return_type() != empty_typet())
1183 instantiation_values.push_back(exprt{ID_nil, function_type.return_type()});
1184 for(const auto &param : function_type.parameters())
1185 {
1186 instantiation_values.push_back(
1187 ns.lookup(param.get_identifier()).symbol_expr());
1188 }
1189 for(auto &target : get_contract(function, ns).c_assigns())
1190 {
1192 instrument_spec_assigns.track_spec_target(
1193 to_lambda_expr(target).application(instantiation_values), payload);
1195 }
1196
1197 // Track formal parameters
1199 for(const auto &param : function_type.parameters())
1200 {
1202 instrument_spec_assigns.track_stack_allocated(
1203 ns.lookup(param.get_identifier()).symbol_expr(), payload);
1205 }
1206
1207 // Restore internal coherence in the programs
1209
1210 // Insert write set inclusion checks.
1211 instrument_spec_assigns.instrument_instructions(
1212 function_body, instruction_it, function_body.instructions.end());
1213}
1214
1216{
1217 // Add statements to the source function
1218 // to ensure assigns clause is respected.
1220
1221 // Rename source function
1222 std::stringstream ss;
1223 ss << CPROVER_PREFIX << "contracts_original_" << function;
1224 const irep_idt mangled(ss.str());
1225 const irep_idt original(function);
1226
1228 INVARIANT(
1230 "Function to replace must exist in the program.");
1231
1232 std::swap(goto_functions.function_map[mangled], old_function->second);
1234
1235 // Place a new symbol with the mangled name into the symbol table
1237 sl.set_file("instrumented for code contracts");
1238 sl.set_line("0");
1241 mangled_sym.name = mangled;
1242 mangled_sym.base_name = mangled;
1243 mangled_sym.location = sl;
1244 const auto mangled_found = symbol_table.insert(std::move(mangled_sym));
1245 INVARIANT(
1246 mangled_found.second,
1247 "There should be no existing function called " + ss.str() +
1248 " in the symbol table because that name is a mangled name");
1249
1250 // Insert wrapper function into goto_functions
1252 INVARIANT(
1254 "There should be no function called " + id2string(function) +
1255 " in the function map because that function should have had its"
1256 " name mangled");
1257
1259 INVARIANT(
1261 "There should be a function called " + ss.str() +
1262 " in the function map because we inserted a fresh goto-program"
1263 " with that mangled name");
1264
1266 wrapper.parameter_identifiers = mangled_fun->second.parameter_identifiers;
1269}
1270
1274 goto_programt &dest)
1275{
1276 PRECONDITION(!dest.instructions.empty());
1277
1278 // build:
1279 // decl ret
1280 // decl parameter1 ...
1281 // decl history_parameter1 ... [optional]
1282 // assume(requires) [optional]
1283 // ret=function(parameter1, ...)
1284 // assert(ensures)
1285
1286 const auto &code_type = get_contract(wrapper_function, ns);
1287 goto_programt check;
1288
1289 // prepare function call including all declarations
1290 const symbolt &function_symbol = ns.lookup(mangled_function);
1292
1293 // Prepare to instantiate expressions in the callee
1294 // with expressions from the call site (e.g. the return value).
1296
1297 source_locationt source_location = function_symbol.location;
1298 // Set function in source location to original function
1299 source_location.set_function(wrapper_function);
1300
1301 // decl ret
1302 std::optional<code_returnt> return_stmt;
1303 if(code_type.return_type() != empty_typet())
1304 {
1306 code_type.return_type(),
1307 id2string(source_location.get_function()),
1308 "tmp_cc",
1309 source_location,
1310 function_symbol.mode,
1312 .symbol_expr();
1313 check.add(goto_programt::make_decl(r, source_location));
1314
1315 call.lhs() = r;
1317
1318 instantiation_values.push_back(r);
1319 }
1320
1321 // decl parameter1 ...
1322 goto_functionst::function_mapt::iterator f_it =
1325
1326 const goto_functionst::goto_functiont &gf = f_it->second;
1327 for(const auto &parameter : gf.parameter_identifiers)
1328 {
1329 PRECONDITION(!parameter.empty());
1330 const symbolt &parameter_symbol = ns.lookup(parameter);
1332 parameter_symbol.type,
1333 id2string(source_location.get_function()),
1334 "tmp_cc",
1335 source_location,
1336 parameter_symbol.mode,
1338 .symbol_expr();
1339 check.add(goto_programt::make_decl(p, source_location));
1341 p, parameter_symbol.symbol_expr(), source_location));
1342
1343 call.arguments().push_back(p);
1344
1345 instantiation_values.push_back(p);
1346 }
1347
1350 visitor.create_declarations();
1351 visitor.add_memory_map_decl(check);
1352
1353 // Generate: assume(requires)
1354 for(const auto &clause : code_type.c_requires())
1355 {
1356 auto instantiated_clause =
1357 to_lambda_expr(clause).application(instantiation_values);
1358 if(instantiated_clause == false)
1359 {
1361 std::string("Attempt to assume false at ")
1362 .append(clause.source_location().as_string())
1363 .append(".\nPlease update requires clause to avoid vacuity."));
1364 }
1365 source_locationt _location = clause.source_location();
1366 _location.set_comment("Assume requires clause");
1367 _location.set_property_class(ID_assume);
1371 converter,
1373 function_symbol.mode,
1374 [&visitor](goto_programt &c_requires) {
1375 visitor.update_requires(c_requires);
1376 },
1377 check,
1378 _location);
1379 }
1380
1381 // Generate all the instructions required to initialize history variables
1383 for(auto clause : code_type.c_ensures())
1384 {
1385 auto instantiated_clause =
1386 to_lambda_expr(clause).application(instantiation_values);
1387 instantiated_clause.add_source_location() = clause.source_location();
1391 }
1392
1393 // ret=mangled_function(parameter1, ...)
1394 check.add(goto_programt::make_function_call(call, source_location));
1395
1396 // Generate: assert(ensures)
1397 for(auto &clause : instantiated_ensures_clauses)
1398 {
1399 source_locationt _location = clause.source_location();
1400 _location.set_comment("Check ensures clause");
1401 _location.set_property_class(ID_postcondition);
1405 converter,
1406 clause,
1407 function_symbol.mode,
1408 [&visitor](goto_programt &ensures) { visitor.update_ensures(ensures); },
1409 check,
1410 _location);
1411 }
1412
1413 if(code_type.return_type() != empty_typet())
1414 {
1416 return_stmt.value().return_value(), source_location));
1417 }
1418
1419 // kill the is_fresh memory map
1420 visitor.add_memory_map_dead(check);
1421
1422 // prepend the new code to dest
1423 dest.destructive_insert(dest.instructions.begin(), check);
1424
1425 // restore global goto_program consistency
1427}
1428
1430 const std::set<std::string> &functions) const
1431{
1432 for(const auto &function : functions)
1433 {
1434 if(
1435 goto_functions.function_map.find(function) ==
1437 {
1439 "Function '" + function + "' was not found in the GOTO program.");
1440 }
1441 }
1442}
1443
1444void code_contractst::replace_calls(const std::set<std::string> &to_replace)
1445{
1446 if(to_replace.empty())
1447 return;
1448
1449 log.status() << "Replacing function calls with contracts" << messaget::eom;
1450
1451 check_all_functions_found(to_replace);
1452
1453 for(auto &goto_function : goto_functions.function_map)
1454 {
1455 Forall_goto_program_instructions(ins, goto_function.second.body)
1456 {
1457 if(ins->is_function_call())
1458 {
1459 if(ins->call_function().id() != ID_symbol)
1460 continue;
1461
1462 const irep_idt &called_function =
1463 to_symbol_expr(ins->call_function()).get_identifier();
1464 auto found = std::find(
1465 to_replace.begin(), to_replace.end(), id2string(called_function));
1466 if(found == to_replace.end())
1467 continue;
1468
1470 goto_function.first,
1471 ins->source_location(),
1472 goto_function.second.body,
1473 ins);
1474 }
1475 }
1476 }
1477
1478 for(auto &goto_function : goto_functions.function_map)
1479 remove_skip(goto_function.second.body);
1480
1482}
1483
1485 const std::set<std::string> &to_exclude_from_nondet_init)
1486{
1487 for(auto &goto_function : goto_functions.function_map)
1488 apply_loop_contract(goto_function.first, goto_function.second);
1489
1490 log.status() << "Adding nondeterministic initialization "
1491 "of static/global variables."
1492 << messaget::eom;
1494
1495 // unwind all transformed loops twice.
1497 {
1498 unwindsett unwindset;
1499 unwindset.parse_unwindset(
1503 }
1504
1506
1507 // Record original loop number for some instrumented instructions.
1509 {
1510 auto &goto_function = goto_function_entry.second;
1511 bool is_in_loop_havoc_block = false;
1512
1513 unsigned loop_number_of_loop_havoc = 0;
1515 goto_function.body.instructions.begin();
1516 it_instr != goto_function.body.instructions.end();
1517 it_instr++)
1518 {
1519 // Don't override original loop numbers.
1520 if(original_loop_number_map.count(it_instr) != 0)
1521 continue;
1522
1523 // Store loop number for two type of instrumented instructions.
1524 // ASSIGN ENTERED_LOOP = false --- head of transformed loops.
1525 // ASSIGN ENTERED_LOOP = true --- end of transformed loops.
1526 if(
1528 {
1529 const auto &assign_lhs =
1532 id2string(assign_lhs->get_identifier()),
1533 std::string(ENTERED_LOOP) + "__");
1534 continue;
1535 }
1536
1537 // Loop havocs are assignments between
1538 // ASSIGN IN_LOOP_HAVOC_BLOCK = true
1539 // and
1540 // ASSIGN IN_LOOP_HAVOC_BLOCK = false
1541
1542 // Entering the loop-havoc block.
1544 {
1545 is_in_loop_havoc_block = it_instr->assign_rhs() == true_exprt();
1546 const auto &assign_lhs =
1549 id2string(assign_lhs->get_identifier()),
1550 std::string(IN_LOOP_HAVOC_BLOCK) + "__");
1551 continue;
1552 }
1553
1554 // Assignments in loop-havoc block are loop havocs.
1555 if(is_in_loop_havoc_block && it_instr->is_assign())
1556 {
1557 loop_havoc_set.emplace(it_instr);
1558
1559 // Store loop number for loop havoc.
1561 }
1562 }
1563 }
1564}
1565
1567 const std::set<std::string> &to_enforce,
1568 const std::set<std::string> &to_exclude_from_nondet_init)
1569{
1570 if(to_enforce.empty())
1571 return;
1572
1573 log.status() << "Enforcing contracts" << messaget ::eom;
1574
1576
1577 for(const auto &function : to_enforce)
1578 enforce_contract(function);
1579
1580 log.status() << "Adding nondeterministic initialization "
1581 "of static/global variables."
1582 << messaget::eom;
1584}
const code_with_contract_typet & to_code_with_contract_type(const typet &type)
Cast a typet to a code_with_contract_typet.
Definition c_types.h:467
Classes providing CFG-based information about symbols to guide simplifications in function and loop a...
virtual void output(const namespacet &ns, const irep_idt &function_id, const goto_programt &goto_program, std::ostream &out) const
Output the abstract states for a single function.
Definition ai.cpp:39
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:566
Thrown when an unexpected error occurs during the analysis (e.g., when the SAT solver returns an erro...
The Boolean type.
Definition std_types.h:36
A non-fatal assertion, which checks a condition then permits execution to continue.
Definition std_code.h:270
A goto_instruction_codet representing an assignment in the program.
An assumption, which must hold in subsequent code.
Definition std_code.h:217
void apply_function_contract(const irep_idt &function, const source_locationt &location, goto_programt &function_body, goto_programt::targett &target)
Replaces function calls with assertions based on requires clauses, non-deterministic assignments for ...
void enforce_contract(const irep_idt &function)
Enforce contract of a single function.
goto_modelt & goto_model
Definition contracts.h:153
void check_apply_loop_contracts(const irep_idt &function_name, goto_functionst::goto_functiont &goto_function, const local_may_aliast &local_may_alias, goto_programt::targett loop_head, goto_programt::targett loop_end, const loopt &loop, exprt assigns_clause, exprt invariant, exprt decreases_clause, const irep_idt &mode)
Definition contracts.cpp:40
void apply_loop_contract(const irep_idt &function, goto_functionst::goto_functiont &goto_function)
Apply loop contracts, whenever available, to all loops in function.
void check_all_functions_found(const std::set< std::string > &functions) const
Throws an exception if some function functions is found in the program.
void check_frame_conditions_function(const irep_idt &function)
Instrument functions to check frame conditions.
messaget & log
Definition contracts.h:157
void apply_loop_contracts(const std::set< std::string > &to_exclude_from_nondet_init={})
Applies loop contract transformations.
symbol_tablet & symbol_table
Definition contracts.h:154
void enforce_contracts(const std::set< std::string > &to_enforce, const std::set< std::string > &to_exclude_from_nondet_init={})
Turn requires & ensures into assumptions and assertions for each of the named functions.
void replace_calls(const std::set< std::string > &to_replace)
Replace all calls to each function in the to_replace set with that function's contract.
std::unordered_set< irep_idt > summarized
Definition contracts.h:159
const namespacet ns
Definition contracts.h:150
std::unordered_set< goto_programt::const_targett, const_target_hash > loop_havoc_set
Loop havoc instructions instrumented during applying loop contracts.
Definition contracts.h:173
loop_contract_configt loop_contract_config
Definition contracts.h:176
std::list< std::string > loop_names
Name of loops we are going to unwind.
Definition contracts.h:162
goto_functionst & goto_functions
Definition contracts.h:155
std::unordered_map< goto_programt::const_targett, unsigned, const_target_hash > original_loop_number_map
Store the map from instrumented instructions for loop contracts to their original loop numbers.
Definition contracts.h:169
void add_contract_check(const irep_idt &wrapper_function, const irep_idt &mangled_function, goto_programt &dest)
Instruments wrapper_function adding assumptions based on requires clauses and assertions based on ens...
goto_instruction_codet representation of a function call statement.
goto_instruction_codet representation of a "return from a function" statement.
Base type of functions.
Definition std_types.h:583
const parameterst & parameters() const
Definition std_types.h:699
const typet & return_type() const
Definition std_types.h:689
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
const char * c_str() const
Definition dstring.h:116
The empty type.
Definition std_types.h:51
Base class for all expressions.
Definition expr.h:57
std::vector< exprt > operandst
Definition expr.h:59
operandst & operands()
Definition expr.h:95
source_locationt & add_source_location()
Definition expr.h:241
The Boolean constant false.
Definition std_expr.h:3125
void goto_convert(const codet &code, goto_programt &dest, const irep_idt &mode)
function_mapt function_map
::goto_functiont goto_functiont
A goto function, consisting of function body (see body) and parameter identifiers (see parameter_iden...
This class represents an instruction in the GOTO intermediate representation.
A generic container class for the GOTO intermediate representation of one function.
instructionst instructions
The list of instructions in the goto program.
static instructiont make_set_return_value(exprt return_value, const source_locationt &l=source_locationt::nil())
static instructiont make_dead(const symbol_exprt &symbol, const source_locationt &l=source_locationt::nil())
void destructive_insert(const_targett target, goto_programt &p)
Inserts the given program p before target.
static instructiont make_end_function(const source_locationt &l=source_locationt::nil())
instructionst::iterator targett
instructionst::const_iterator const_targett
void destructive_append(goto_programt &p)
Appends the given program p to *this. p is destroyed.
static instructiont make_assignment(const code_assignt &_code, const source_locationt &l=source_locationt::nil())
Create an assignment instruction.
static instructiont make_skip(const source_locationt &l=source_locationt::nil())
static instructiont make_function_call(const code_function_callt &_code, const source_locationt &l=source_locationt::nil())
Create a function call instruction.
targett add(instructiont &&instruction)
Adds a given instruction at the end.
static instructiont make_goto(targett _target, const source_locationt &l=source_locationt::nil())
static instructiont make_decl(const symbol_exprt &symbol, const source_locationt &l=source_locationt::nil())
static instructiont make_assertion(const exprt &g, const source_locationt &l=source_locationt::nil())
This class represents a node in a directed graph.
Definition graph.h:35
Class to generate havocking instructions for target expressions of a function contract's assign claus...
A class that further overrides the "safe" havoc utilities, and adds support for havocing pointer_obje...
Definition utils.h:90
Decorator for a message_handlert used during function inlining that collect names of GOTO functions c...
A class that generates instrumentation for assigns clause checking.
Thrown when user-provided input cannot be processed.
Thrown when we can't handle something in an input source file.
void swap(irept &irep)
Definition irep.h:434
bool is_nil() const
Definition irep.h:368
loop_mapt loop_map
void erase_locals(std::set< exprt > &exprs)
Definition cfg_info.h:171
mstreamt & error() const
Definition message.h:391
mstreamt & debug() const
Definition message.h:421
message_handlert & get_message_handler()
Definition message.h:183
mstreamt & warning() const
Definition message.h:396
void conditional_output(mstreamt &mstream, const std::function< void(mstreamt &)> &output_generator) const
Generate output to message_stream using output_generator if the configured verbosity is at least as h...
Definition message.cpp:139
static eomt eom
Definition message.h:289
mstreamt & status() const
Definition message.h:406
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition namespace.h:91
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Boolean negation.
Definition std_expr.h:2378
Boolean OR All operands must be boolean, and the result is always boolean.
Definition std_expr.h:2183
A side_effect_exprt that returns a non-deterministically chosen value.
Definition std_code.h:1520
const irep_idt & get_function() const
const irep_idt & get_line() const
const irep_idt & get_property_class() const
void set_function(const irep_idt &function)
Expression to hold a symbol (variable)
Definition std_expr.h:132
const symbolt * lookup(const irep_idt &name) const
Find a symbol in the symbol table for read-only access.
const symbolt & lookup_ref(const irep_idt &name) const
Find a symbol in the symbol table for read-only access.
The symbol table.
virtual std::pair< symbolt &, bool > insert(symbolt symbol) override
Author: Diffblue Ltd.
Symbol table entry.
Definition symbol.h:28
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
Definition symbol.cpp:121
The Boolean constant true.
Definition std_expr.h:3116
void parse_unwindset(const std::list< std::string > &unwindset, abstract_goto_modelt &goto_model, message_handlert &message_handler)
static void generate_contract_constraints(symbol_tablet &symbol_table, goto_convertt &converter, exprt &instantiated_clause, const irep_idt &mode, const std::function< void(goto_programt &)> &is_fresh_update, goto_programt &program, const source_locationt &location)
This function generates instructions for all contract constraint, i.e., assumptions and assertions ba...
static const code_with_contract_typet & get_contract(const irep_idt &function, const namespacet &ns)
static void throw_on_unsupported(const goto_programt &program)
Throws an exception if a contract uses unsupported constructs like:
Verify and use annotated invariants and pre/post-conditions.
#define CPROVER_PREFIX
static const std::map< dfcc_funt, int > to_unwind
set of functions that need to be unwound to assigns clause size with corresponding loop identifiers.
exprt boolean_negate(const exprt &src)
negate a Boolean expression, possibly removing a not_exprt, and swapping false and true
Definition expr_util.cpp:98
static format_containert< T > format(const T &o)
Definition format.h:37
symbolt & get_fresh_aux_symbol(const typet &type, const std::string &name_prefix, const std::string &basename_prefix, const source_locationt &source_location, const irep_idt &symbol_mode, const namespacet &ns, symbol_table_baset &symbol_table)
Installs a fresh-named symbol with respect to the given namespace ns with the requested name pattern ...
Fresh auxiliary symbol creation.
void goto_function_inline(goto_modelt &goto_model, const irep_idt function, message_handlert &message_handler, bool adjust_function, bool caching)
Transitively inline all function calls made from a particular function.
Function Inlining This gives a number of different interfaces to the function inlining functionality ...
#define Forall_goto_program_instructions(it, program)
Havoc function assigns clauses.
std::set< exprt > assignst
Definition havoc_utils.h:24
std::optional< code_with_contract_typet > get_contract(const irep_idt &function_identifier, const namespacet &ns)
void add_pragma_disable_assigns_check(source_locationt &location)
Adds a pragma on a source_locationt to disable inclusion checking.
Specify write set in function contracts.
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
static int8_t r
Definition irep_hash.h:60
Field-insensitive, location-sensitive may-alias analysis.
natural_loops_mutablet::natural_loopt loopt
Definition loop_utils.h:20
API to expression classes for 'mathematical' expressions.
const lambda_exprt & to_lambda_expr(const exprt &expr)
Cast an exprt to a lambda_exprt.
Predicates to specify memory footprint in function contracts.
static void nondet_static(const namespacet &ns, goto_modelt &goto_model, const irep_idt &fct_name)
Nondeterministically initializes global scope variables in a goto-function.
Nondeterministically initializes global scope variables, except for constants (such as string literal...
void remove_skip(goto_programt &goto_program, goto_programt::targett begin, goto_programt::targett end)
remove unnecessary skip statements
Program Transformation.
#define UNREACHABLE
This should be used to mark dead code.
Definition invariant.h:525
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition invariant.h:534
#define PRECONDITION(CONDITION)
Definition invariant.h:463
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition invariant.h:423
exprt conjunction(exprt a, exprt b)
Conjunction of two expressions.
Definition std_expr.cpp:252
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:211
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition std_types.h:788
A total order over targett and const_targett.
Loop unwinding.
Loop unwinding.
void generate_history_variables_initialization(symbol_table_baset &symbol_table, exprt &clause, const irep_idt &mode, goto_programt &program)
This function generates all the instructions required to initialize history variables.
Definition utils.cpp:494
bool is_assignment_to_instrumented_variable(const goto_programt::const_targett &target, std::string var_name)
Return true if target is an assignment to an instrumented variable with name var_name.
Definition utils.cpp:524
void insert_before_and_update_jumps(goto_programt &destination, goto_programt::targett &target, const goto_programt::instructiont &i)
Insert a goto instruction before a target instruction iterator and update targets of all jumps that p...
Definition utils.cpp:247
void infer_loop_assigns(const local_may_aliast &local_may_alias, const loopt &loop, assignst &assigns)
Infer loop assigns using alias analysis result local_may_alias.
Definition utils.cpp:344
bool is_loop_free(const goto_programt &goto_program, const namespacet &ns, messaget &log)
Returns true iff the given program is loop-free, i.e.
Definition utils.cpp:271
exprt get_loop_assigns(const goto_programt::const_targett &loop_end)
Extract loop assigns from annotated loop end.
Definition utils.cpp:683
replace_history_parametert replace_history_loop_entry(symbol_table_baset &symbol_table, const exprt &expr, const source_locationt &location, const irep_idt &mode)
This function recursively identifies the "loop_entry" expressions within expr and replaces them with ...
Definition utils.cpp:475
bool is_transformed_loop_head(const goto_programt::const_targett &target)
Return true if target is the head of some transformed loop.
Definition utils.cpp:508
void insert_before_swap_and_advance(goto_programt &destination, goto_programt::targett &target, goto_programt &payload)
Insert a goto program before a target instruction iterator and advance the iterator.
Definition utils.cpp:237
void widen_assigns(assignst &assigns, const namespacet &ns)
Widen expressions in assigns with the following strategy.
Definition utils.cpp:360
void simplify_gotos(goto_programt &goto_program, const namespacet &ns)
Turns goto instructions IF cond GOTO label where the condition statically simplifies to false into SK...
Definition utils.cpp:260
exprt get_loop_invariants(const goto_programt::const_targett &loop_end, const bool check_side_effect)
Extract loop invariants from annotated loop end.
Definition utils.cpp:666
bool is_transformed_loop_end(const goto_programt::const_targett &target)
Return true if target is the end of some transformed loop.
Definition utils.cpp:516
exprt get_loop_decreases(const goto_programt::const_targett &loop_end, const bool check_side_effect)
Extract loop decreases from annotated loop end.
Definition utils.cpp:688
unsigned get_suffix_unsigned(const std::string &str, const std::string &prefix)
Convert the suffix digits right after prefix of str into unsigned.
Definition utils.cpp:546
exprt generate_lexicographic_less_than_check(const std::vector< symbol_exprt > &lhs, const std::vector< symbol_exprt > &rhs)
Generate a lexicographic less-than comparison over ordered tuples.
Definition utils.cpp:193
#define ENTERED_LOOP
Definition utils.h:24
#define INIT_INVARIANT
Definition utils.h:26
#define IN_LOOP_HAVOC_BLOCK
Definition utils.h:25