CBMC
Loading...
Searching...
No Matches
state_encoding.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: State Encoding
4
5Author: Daniel Kroening, dkr@amazon.com
6
7\*******************************************************************/
8
9#include "state_encoding.h"
10
11#include <util/arith_tools.h>
12#include <util/c_types.h>
14#include <util/pointer_expr.h>
15#include <util/prefix.h>
16#include <util/simplify_expr.h>
17#include <util/std_code.h>
18
20
23#include "sentinel_dll.h"
24#include "solver.h"
25#include "state.h"
27#include "variable_encoding.h"
28
29#include <algorithm>
30#include <iostream>
31
33{
34public:
39
40 void operator()(
41 const goto_functionst::function_mapt::const_iterator,
43
44 void encode(
45 const goto_functiont &,
47 const std::string &state_prefix,
48 const std::vector<irep_idt> &call_stack,
49 const std::string &annotation,
51 const exprt &return_lhs,
53
54protected:
57
59 symbol_exprt state_expr_with_suffix(loct, const std::string &suffix) const;
62 std::vector<symbol_exprt> incoming_symbols(loct) const;
63 exprt evaluate_expr(loct, const exprt &, const exprt &) const;
65 loct,
66 const exprt &,
67 const exprt &,
68 const std::unordered_set<symbol_exprt, irep_hash> &) const;
70 loct,
71 const exprt &,
72 std::vector<symbol_exprt> &nondet_symbols) const;
73 exprt evaluate_expr(loct, const exprt &) const;
74 exprt address_rec(loct, const exprt &, exprt) const;
78 void setup_incoming(const goto_functiont &);
81 loct,
82 exprt state,
83 exprt lhs,
84 exprt rhs,
85 std::vector<symbol_exprt> &nondet_symbols) const;
88
90 std::string state_prefix;
91 std::string annotation;
92 std::vector<irep_idt> call_stack;
96 using incomingt =
97 std::map<loct, std::vector<loct>, goto_programt::target_less_than>;
99
100 static symbol_exprt va_args(irep_idt function);
101};
102
107
109 loct loc,
110 const std::string &suffix) const
111{
112 irep_idt identifier =
113 state_prefix + std::to_string(loc->location_number) + suffix;
114 return symbol_exprt(identifier, state_predicate_type());
115}
116
118{
119 return state_expr_with_suffix(loc, taken ? "T" : "");
120}
121
122std::vector<symbol_exprt> state_encodingt::incoming_symbols(loct loc) const
123{
124 auto incoming_it = incoming.find(loc);
125
126 DATA_INVARIANT(incoming_it != incoming.end(), "incoming is complete");
127
128 std::vector<symbol_exprt> symbols;
129 symbols.reserve(incoming_it->second.size());
130
131 for(auto &loc_in : incoming_it->second)
132 {
133 std::string suffix;
134
135 // conditional jump from loc_in to loc?
136 if(
137 loc_in->is_goto() && loc_in->condition() != true &&
138 loc != std::next(loc_in))
139 {
140 suffix = "T";
141 }
142
143 symbols.push_back(state_expr_with_suffix(loc_in, suffix));
144 }
145
146 return symbols;
147}
148
150{
151 if(loc == first_loc)
152 return entry_state;
153
154 auto incoming_symbols = this->incoming_symbols(loc);
155
156 if(incoming_symbols.size() == 1)
157 return incoming_symbols.front();
158 else
159 return state_expr_with_suffix(loc, "in");
160}
161
163 loct loc,
164 const exprt &state,
165 const exprt &what) const
166{
167 return evaluate_expr_rec(loc, state, what, {});
168}
169
171 loct loc,
172 const exprt &what,
173 std::vector<symbol_exprt> &nondet_symbols) const
174{
175 if(what.id() == ID_side_effect)
176 {
177 auto &side_effect = to_side_effect_expr(what);
178 auto statement = side_effect.get_statement();
179 if(statement == ID_nondet)
180 {
181 irep_idt identifier = "nondet::" + state_prefix +
182 std::to_string(loc->location_number) + "-" +
183 std::to_string(nondet_symbols.size());
184 auto symbol = symbol_exprt(identifier, side_effect.type());
185 nondet_symbols.push_back(symbol);
186 return std::move(symbol);
187 }
188 else if(statement == ID_va_start)
189 {
190 // return address of va_args array
193 what.type());
194 }
195 else
196 return what; // leave it
197 }
198 else
199 {
200 exprt tmp = what;
201 for(auto &op : tmp.operands())
202 op = replace_nondet_rec(loc, op, nondet_symbols);
203 return tmp;
204 }
205}
206
208 loct loc,
209 const exprt &state,
210 const exprt &what,
211 const std::unordered_set<symbol_exprt, irep_hash> &bound_symbols) const
212{
213 PRECONDITION(state.type().id() == ID_state);
214
215 if(what.id() == ID_symbol)
216 {
217 const auto &symbol_expr = to_symbol_expr(what);
218
219 if(symbol_expr.identifier() == CPROVER_PREFIX "return_value")
220 {
221 auto new_symbol = symbol_exprt("return_value", what.type());
222 return evaluate_exprt(
223 state, address_rec(loc, state, new_symbol), what.type());
224 }
225 else if(bound_symbols.find(symbol_expr) == bound_symbols.end())
226 {
227 return evaluate_exprt(state, address_rec(loc, state, what), what.type());
228 }
229 else
230 return what; // leave as is
231 }
232 else if(
233 what.id() == ID_dereference || what.id() == ID_member ||
234 what.id() == ID_index)
235 {
236 return evaluate_exprt(state, address_rec(loc, state, what), what.type());
237 }
238 else if(what.id() == ID_forall || what.id() == ID_exists)
239 {
240 auto new_quantifier_expr = to_quantifier_expr(what); // copy
241 auto new_bound_symbols = bound_symbols; // copy
242
243 for(const auto &v : new_quantifier_expr.variables())
244 new_bound_symbols.insert(v);
245
247 loc, state, new_quantifier_expr.where(), new_bound_symbols);
248
249 return std::move(new_quantifier_expr);
250 }
251 else if(what.id() == ID_address_of)
252 {
253 const auto &object = to_address_of_expr(what).object();
254 return address_rec(loc, state, object);
255 }
256 else if(what.id() == ID_live_object)
257 {
258 const auto &live_object_expr = to_live_object_expr(what);
259 auto pointer =
260 evaluate_expr_rec(loc, state, live_object_expr.pointer(), bound_symbols);
261 return state_live_object_exprt(state, pointer);
262 }
263 else if(what.id() == ID_writeable_object)
264 {
266 auto pointer = evaluate_expr_rec(
267 loc, state, writeable_object_expr.pointer(), bound_symbols);
268 return state_writeable_object_exprt(state, pointer);
269 }
270 else if(what.id() == ID_is_dynamic_object)
271 {
273 auto pointer = evaluate_expr_rec(
274 loc, state, is_dynamic_object_expr.address(), bound_symbols);
275 return state_is_dynamic_object_exprt(state, pointer);
276 }
277 else if(what.id() == ID_object_size)
278 {
279 const auto &object_size_expr = to_object_size_expr(what);
280 auto pointer =
281 evaluate_expr_rec(loc, state, object_size_expr.pointer(), bound_symbols);
282 return state_object_size_exprt(state, pointer, what.type());
283 }
284 else if(what.id() == ID_r_ok || what.id() == ID_w_ok || what.id() == ID_rw_ok)
285 {
286 // we need to add the state
287 const auto &r_or_w_ok_expr = to_r_or_w_ok_expr(what);
288 auto pointer =
289 evaluate_expr_rec(loc, state, r_or_w_ok_expr.pointer(), bound_symbols);
290 auto size =
292 auto new_id = what.id() == ID_r_ok ? ID_state_r_ok
293 : what.id() == ID_w_ok ? ID_state_w_ok
295 return ternary_exprt(new_id, state, pointer, size, what.type());
296 }
297 else if(what.id() == ID_is_cstring)
298 {
299 // we need to add the state
300 const auto &is_cstring_expr = to_unary_expr(what);
301 auto pointer =
303 return binary_predicate_exprt(state, ID_state_is_cstring, pointer);
304 }
305 else if(what.id() == ID_cstrlen)
306 {
307 // we need to add the state
308 const auto &cstrlen_expr = to_cstrlen_expr(what);
309 auto address =
311 return state_cstrlen_exprt(state, address, cstrlen_expr.type());
312 }
313 else if(what.id() == ID_is_sentinel_dll)
314 {
315 // we need to add the state
316 if(what.operands().size() == 2)
317 {
318 const auto &is_sentinel_dll_expr = to_binary_expr(what);
319 auto head = evaluate_expr_rec(
320 loc, state, is_sentinel_dll_expr.op0(), bound_symbols);
321 auto tail = evaluate_expr_rec(
322 loc, state, is_sentinel_dll_expr.op1(), bound_symbols);
323 return state_is_sentinel_dll_exprt(state, head, tail);
324 }
325 else if(what.operands().size() == 3)
326 {
327 const auto &is_sentinel_dll_expr = to_ternary_expr(what);
328 auto head = evaluate_expr_rec(
329 loc, state, is_sentinel_dll_expr.op0(), bound_symbols);
330 auto tail = evaluate_expr_rec(
331 loc, state, is_sentinel_dll_expr.op1(), bound_symbols);
332 auto node = evaluate_expr_rec(
333 loc, state, is_sentinel_dll_expr.op2(), bound_symbols);
334 return state_is_sentinel_dll_exprt(state, head, tail, node);
335 }
336 else
337 DATA_INVARIANT(false, "is_sentinel_dll expressions have 2 or 3 operands");
338 }
339 else if(what.id() == ID_side_effect)
340 {
341 const auto &side_effect = to_side_effect_expr(what);
342 if(
343 side_effect.get_statement() == ID_allocate &&
344 side_effect.operands().size() == 2 &&
345 side_effect.type().id() == ID_pointer)
346 {
347 // __CPROVER_allocate is handled like the malloc call (see the malloc
348 // handling in function_call_symbol below): tie the allocation to the
349 // current state so that the live_object, writeable_object and
350 // object_size axioms apply to the result. Without this, the generic
351 // allocate side effect is left uninterpreted, and "pointer safe"
352 // properties over the allocated object are spuriously refuted.
353 // c_typecheck_expr rejects an ID_allocate without exactly two
354 // operands (size, zero-init flag), so the size() == 2 check documents
355 // that invariant rather than building an allocation from a partial
356 // operand list; the side effect's type is always void *, so the
357 // ID_pointer conjunct is defensive only.
358 //
359 // NOTE: operands()[1] is the zero-initialisation flag (calloc lowers to
360 // __CPROVER_allocate(size, 1)); like the malloc/posix_memalign/realloc
361 // cases this backend does not model zeroing, so the allocated contents
362 // are left nondeterministic. TODO: model zeroing.
364 loc, state, side_effect.operands().front(), bound_symbols);
365 return allocate_exprt{
367 }
368 // leave as is
369 return what;
370 }
371 else if(
372 (what.id() == ID_equal || what.id() == ID_notequal) &&
373 to_binary_relation_expr(what).lhs().type().id() == ID_struct_tag)
374 {
375 const auto &lhs = to_binary_relation_expr(what).lhs();
376 const auto &rhs = to_binary_relation_expr(what).rhs();
377
378 const auto &type = to_struct_tag_type(lhs.type());
379 const namespacet ns(goto_model.symbol_table);
380 const auto &struct_type = ns.follow_tag(type);
381
383
384 for(auto &field : struct_type.components())
385 {
386 exprt lhs_member = member_exprt(lhs, field.get_name(), field.type());
387 exprt rhs_member = member_exprt(rhs, field.get_name(), field.type());
388 auto equality = equal_exprt(lhs_member, rhs_member);
389 auto equality_evaluated =
390 evaluate_expr_rec(loc, state, equality, bound_symbols);
391 conjuncts.push_back(std::move(equality_evaluated));
392 }
393
394 if(what.id() == ID_equal)
395 return conjunction(conjuncts);
396 else
398 }
399 else
400 {
401 exprt tmp = what;
402 for(auto &op : tmp.operands())
403 op = evaluate_expr_rec(loc, state, op, bound_symbols);
404 return tmp;
405 }
406}
407
409{
410 return evaluate_expr(loc, in_state_expr(loc), what);
411}
412
414{
415 return lambda_exprt({state_expr()}, std::move(what));
416}
417
419{
420 return forall_exprt(
421 {state_expr()},
424 std::move(what)));
425}
426
428 const
429{
430 return forall_exprt(
431 {state_expr()},
433 and_exprt(
435 std::move(condition)),
436 std::move(what)));
437}
438
440 const
441{
442 if(expr.id() == ID_symbol)
443 {
445 }
446 else if(expr.id() == ID_member)
447 {
448 auto compound = to_member_expr(expr).struct_op();
449 auto compound_address = address_rec(loc, state, std::move(compound));
450 auto component_name = to_member_expr(expr).get_component_name();
451
453
454 if(expr.type().id() == ID_array)
455 {
456 const auto &element_type = to_array_type(expr.type()).element_type();
457 return field_address_exprt(
458 std::move(compound_address),
459 component_name,
460 pointer_type(element_type));
461 }
462 else
463 {
464 return field_address_exprt(
465 std::move(compound_address), component_name, pointer_type(expr.type()));
466 }
467 }
468 else if(expr.id() == ID_index)
469 {
470 auto array = to_index_expr(expr).array();
471 auto index_evaluated =
472 evaluate_expr(loc, state, to_index_expr(expr).index());
473 auto array_address = address_rec(loc, state, std::move(array));
474 // The type of the element pointer may not be the type
475 // of the base pointer, which may be a pointer to an array.
477 std::move(array_address),
478 std::move(index_evaluated),
479 pointer_type(expr.type()));
480 }
481 else if(expr.id() == ID_dereference)
482 return evaluate_expr(loc, state, to_dereference_expr(expr).pointer());
483 else if(expr.id() == ID_string_constant)
484 {
485 // we'll stick to 'address_of' here.
486 return address_of_exprt(
487 expr, pointer_type(to_array_type(expr.type()).element_type()));
488 }
489 else if(expr.id() == ID_array)
490 {
491 // TBD.
493 "can't do array literals", expr.source_location());
494 }
495 else if(expr.id() == ID_struct)
496 {
497 // TBD.
499 "can't do struct literals", expr.source_location());
500 }
501 else if(expr.id() == ID_union)
502 {
503 // TBD.
505 "can't do union literals", expr.source_location());
506 }
507 else if(expr.id() == ID_side_effect)
508 {
509 // Should have been removed elsewhere.
511 "address of side effect " +
512 id2string(to_side_effect_expr(expr).get_statement()),
513 expr.source_location());
514 }
515 else if(expr.id() == ID_typecast)
516 {
517 // TBD.
519 "can't do assignments to typecasts", expr.source_location());
520 }
521 else
522 {
523 // address of something we don't know
525 "address of unknown object " + expr.id_string(), expr.source_location());
526 }
527}
528
530 loct loc,
531 exprt state,
532 exprt lhs,
533 exprt rhs,
534 std::vector<symbol_exprt> &nondet_symbols) const
535{
536 if(lhs.type().id() == ID_struct_tag)
537 {
538 // split up into fields, recursively
539 const namespacet ns(goto_model.symbol_table);
540 const auto &struct_type = ns.follow_tag(to_struct_tag_type(lhs.type()));
541 exprt new_state = state;
542 for(auto &field : struct_type.components())
543 {
544 exprt lhs_member = member_exprt(lhs, field.get_name(), field.type());
545 exprt rhs_member = member_exprt(rhs, field.get_name(), field.type());
546
547 if(rhs.id() == ID_struct)
549 else if(
550 rhs.id() == ID_side_effect &&
551 to_side_effect_expr(rhs).get_statement() == ID_nondet)
552 {
553 rhs_member =
555 }
556
559 }
560
561 return new_state;
562 }
563 else if(lhs.type().id() == ID_array)
564 {
565 // split up into elements, recursively
566 const namespacet ns(goto_model.symbol_table);
567 auto &array_type = to_array_type(lhs.type());
568 if(array_type.size().is_constant())
569 {
570 auto size_int =
572 exprt new_state = state;
573
574 for(mp_integer i = 0; i < size_int; ++i)
575 {
576 auto i_expr = from_integer(i, array_type.index_type());
579
580 if(rhs.id() == ID_array)
582 else if(
583 rhs.id() == ID_side_effect &&
584 to_side_effect_expr(rhs).get_statement() == ID_nondet)
585 {
586 rhs_index =
588 }
589
592 }
593
594 return new_state;
595 }
596 else
597 {
598 // TODO: quantifier?
599 return state;
600 }
601 }
602 else
603 {
604 auto s = state_expr();
605 auto address = address_rec(loc, s, lhs);
606
607 exprt rhs_evaluated = evaluate_expr(loc, s, rhs);
608
610
611 return update_state_exprt(state, address, new_value);
612 }
613}
614
616 const
617{
618 std::vector<symbol_exprt> nondet_symbols;
619
620 auto new_state =
622
624 binding.insert(binding.end(), nondet_symbols.begin(), nondet_symbols.end());
625
626 return forall_exprt(
627 std::move(binding),
631}
632
634{
635 forall_goto_program_instructions(it, goto_function.body)
636 incoming[it];
637
638 forall_goto_program_instructions(it, goto_function.body)
639 {
640 if(it->is_goto())
641 incoming[it->get_target()].push_back(it);
642 }
643
644 forall_goto_program_instructions(it, goto_function.body)
645 {
646 auto next = std::next(it);
647 if(it->is_goto() && it->condition() == true)
648 {
649 }
650 else if(next != goto_function.body.instructions.end())
651 {
652 incoming[next].push_back(it);
653 }
654 }
655}
656
658{
659 if(src.id() == ID_not)
660 return to_not_expr(src).op();
661 else
662 return not_exprt(src);
663}
664
666{
667 return symbol_exprt(
668 "va_args::" + id2string(function),
670}
671
672std::set<irep_idt> no_body_warnings;
673
676 encoding_targett &dest)
677{
678 const auto &function = to_symbol_expr(loc->call_function());
679 const auto &type = to_code_type(function.type());
680 auto identifier = function.identifier();
681
682 auto new_annotation = annotation + u8" \u2192 " + id2string(identifier);
684
685 // malloc is special-cased
686 if(identifier == "malloc")
687 {
688 auto state = state_expr();
689 PRECONDITION(loc->call_arguments().size() == 1);
690 auto size_evaluated = evaluate_expr(loc, state, loc->call_arguments()[0]);
691
692 auto lhs_address = address_rec(loc, state, loc->call_lhs());
693 auto lhs_type = to_pointer_type(loc->call_lhs().type());
696 dest << forall_states_expr(
698 return;
699 }
700
701 // malloc is special-cased
702 if(identifier == "posix_memalign")
703 {
704 // int posix_memalign(void **memptr, size_t alignment, size_t size);
705 auto state = state_expr();
706 PRECONDITION(loc->call_arguments().size() == 3);
707 auto memptr_evaluated = evaluate_expr(loc, state, loc->call_arguments()[0]);
708 auto size_evaluated = evaluate_expr(loc, state, loc->call_arguments()[2]);
709 auto lhs_type =
713 dest << forall_states_expr(
715 return;
716 }
717
718 // realloc is special-cased
719 if(identifier == "realloc")
720 {
721 auto state = state_expr();
722 PRECONDITION(loc->call_arguments().size() == 2);
723 auto pointer_evaluated =
724 evaluate_expr(loc, state, loc->call_arguments()[0]);
725 auto size_evaluated = evaluate_expr(loc, state, loc->call_arguments()[1]);
726
727 auto lhs_address = address_rec(loc, state, loc->call_lhs());
728 auto lhs_type = to_pointer_type(loc->call_lhs().type());
730 state,
733 dest << forall_states_expr(
735 return;
736 }
737
738 // free is special-cased
739 if(identifier == "free")
740 {
741 auto state = state_expr();
742 PRECONDITION(loc->call_arguments().size() == 1);
743 auto address_evaluated =
744 evaluate_expr(loc, state, loc->call_arguments()[0]);
745
747 dest << forall_states_expr(
749 return;
750 }
751
752 // Find the function
753 auto f = goto_model.goto_functions.function_map.find(identifier);
754 if(f == goto_model.goto_functions.function_map.end())
755 DATA_INVARIANT(false, "failed find function in function_map");
756
757 // Do we have a function body?
758 if(!f->second.body_available())
759 {
760 // no function body -- do LHS assignment nondeterministically, if any
761 if(loc->call_lhs().is_not_nil())
762 {
763 auto rhs = side_effect_expr_nondett(
764 loc->call_lhs().type(), loc->source_location());
765 dest << assignment_constraint(loc, loc->call_lhs(), std::move(rhs));
766 }
767 else
768 {
769 // This is a SKIP.
770 dest << equal_exprt(out_state_expr(loc), in_state_expr(loc));
771 }
772
773 // issue a warning, but only once
774 if(no_body_warnings.insert(identifier).second)
775 std::cout << "**** WARNING: no body for function " << identifier << '\n';
776 }
777 else
778 {
779 // Yes, we've got a body. Check whether this is recursive.
780 if(
781 std::find(call_stack.begin(), call_stack.end(), identifier) !=
782 call_stack.end())
783 {
784 // ignore
785 dest << equal_exprt(out_state_expr(loc), in_state_expr(loc));
786 return;
787 }
788
789 // Evaluate the arguments of the call in the 'in state'
791 const auto &arguments = loc->call_arguments();
792
793 // regular parameters
794 for(std::size_t i = 0; i < type.parameters().size(); i++)
795 {
796 auto address = object_address_exprt(symbol_exprt(
797 f->second.parameter_identifiers[i], type.parameters()[i].type()));
798 auto value = evaluate_expr(loc, state_expr(), arguments[i]);
800 }
801
802 // extra arguments, i.e., va_arg
803 if(arguments.size() > type.parameters().size())
804 {
805 std::vector<exprt> va_args_elements;
807
808 for(std::size_t i = type.parameters().size(); i < arguments.size(); i++)
809 {
810 auto index = i - type.parameters().size();
811 auto id = "va_arg::" + state_prefix +
812 std::to_string(loc->location_number) +
813 "::" + std::to_string(index);
814 auto address =
815 object_address_exprt(symbol_exprt(id, arguments[i].type()));
816 auto value = evaluate_expr(loc, state_expr(), arguments[i]);
817 va_args_elements.push_back(
820 }
821
822 // assign these to an array
823 auto va_count = va_args_elements.size();
824 auto array_type = array_typet(
826 auto array_identifier =
827 "va_arg_array::" + state_prefix + std::to_string(loc->location_number);
828 auto array_symbol = symbol_exprt(array_identifier, array_type);
829
830 for(std::size_t i = 0; i < va_count; i++)
831 {
832 auto address = element_address_exprt(
833 object_address_exprt(array_symbol),
834 from_integer(i, array_type.index_type()),
836 auto value = va_args_elements[i];
838 }
839
840 // now make va_args point to the beginning of that array
841 auto address = object_address_exprt(va_args(identifier));
842 auto value = element_address_exprt(
843 object_address_exprt(array_symbol),
844 from_integer(0, array_type.index_type()),
847 }
848
849 // Now assign all the arguments to the parameters
850 auto function_entry_state = state_expr_with_suffix(loc, "Entry");
851 dest << forall_states_expr(
853
854 // now do the body, recursively
856 auto new_state_prefix =
857 state_prefix + std::to_string(loc->location_number) + ".";
860 body_state_encoding.encode(
861 f->second,
862 identifier,
867 nil_exprt(),
868 dest);
869
870 // exit state of called function
871 auto exit_loc = std::prev(f->second.body.instructions.end());
873 new_state_prefix + std::to_string(exit_loc->location_number);
874 auto exit_state =
876
877 // done with function, reset source location to call site
878 dest.set_source_location(loc->source_location());
879
880 // now assign the return value, if any
881 if(loc->call_lhs().is_not_nil())
882 {
883 auto rhs = symbol_exprt("return_value", loc->call_lhs().type());
884 auto state = state_expr();
885 auto address = address_rec(exit_loc, state, loc->call_lhs());
886 auto rhs_evaluated = evaluate_expr(exit_loc, state, rhs);
888 dest << forall_exprt(
889 {state_expr()},
893 }
894 else
895 {
896 // link up return state to exit state
897 dest << equal_exprt(out_state_expr(loc), std::move(exit_state));
898 }
899 }
900}
901
904 encoding_targett &dest)
905{
906 // Function pointer?
907 const auto &function = loc->call_function();
908 if(function.id() == ID_dereference)
909 {
910 // TBD.
912 "can't do function pointers", loc->source_location());
913 }
914 else if(function.id() == ID_symbol)
915 {
916 function_call_symbol(loc, dest);
917 }
918 else
919 {
921 false, "got function that's neither a symbol nor a function pointer");
922 }
923}
924
926 goto_functionst::function_mapt::const_iterator f_entry,
927 encoding_targett &dest)
928{
929 const auto &goto_function = f_entry->second;
930
931 if(goto_function.body.instructions.empty())
932 return;
933
934 // initial state
935 auto in_state = symbol_exprt("SInitial", state_predicate_type());
936
937 dest << forall_exprt(
938 {state_expr()},
942
943 auto annotation = id2string(f_entry->first);
944
945 encode(
946 goto_function,
947 f_entry->first,
948 "S",
949 {},
951 in_state,
952 nil_exprt(),
953 dest);
954}
955
957 const goto_functiont &goto_function,
958 const irep_idt function_identifier,
959 const std::string &state_prefix,
960 const std::vector<irep_idt> &call_stack,
961 const std::string &annotation,
962 const symbol_exprt &entry_state,
963 const exprt &return_lhs,
964 encoding_targett &dest)
965{
966 first_loc = goto_function.body.instructions.begin();
967 this->function_identifier = function_identifier;
968 this->state_prefix = state_prefix;
969 this->call_stack = call_stack;
970 this->annotation = annotation;
971 this->entry_state = entry_state;
972 this->return_lhs = return_lhs;
973
974 setup_incoming(goto_function);
975
976 // constraints for each instruction
977 forall_goto_program_instructions(loc, goto_function.body)
978 {
979 // pass on the source code location
980 dest.set_source_location(loc->source_location());
981
982 // constraints on the incoming state
983 {
984 auto incoming_symbols = this->incoming_symbols(loc);
985
986 if(incoming_symbols.size() >= 2)
987 {
988 auto s = state_expr();
990 {
991 dest << forall_exprt(
992 {s},
996 }
997 }
998 }
999
1000 if(loc->is_assign())
1001 {
1002 auto &lhs = loc->assign_lhs();
1003 auto &rhs = loc->assign_rhs();
1004
1005 DATA_INVARIANT(lhs.type() == rhs.type(), "assignment type consistency");
1006
1007 if(
1008 lhs.id() == ID_symbol &&
1009 has_prefix(
1010 id2string(to_symbol_expr(lhs).identifier()), CPROVER_PREFIX) &&
1011 to_symbol_expr(lhs).identifier() != CPROVER_PREFIX "rounding_mode")
1012 {
1013 // skip for now
1014 dest << equal_exprt(out_state_expr(loc), in_state_expr(loc));
1015 }
1016 else if(
1017 lhs.id() == ID_symbol &&
1018 to_symbol_expr(lhs).identifier() == "_DefaultRuneLocale")
1019 {
1020 // /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/runetype.h
1021 // skip for now
1022 dest << equal_exprt(out_state_expr(loc), in_state_expr(loc));
1023 }
1024 else
1025 dest << assignment_constraint(loc, lhs, rhs);
1026 }
1027 else if(loc->is_assume())
1028 {
1029 // we produce ∅ when the assumption is false
1030 auto state = state_expr();
1031 auto condition_evaluated = evaluate_expr(loc, state, loc->condition());
1032
1033 dest << forall_states_expr(
1034 loc,
1037 }
1038 else if(loc->is_goto())
1039 {
1040 // We produce ∅ when the 'other' branch is taken. Get the condition.
1041 const auto &condition = loc->condition();
1042
1043 if(condition == true)
1044 {
1045 dest << equal_exprt(out_state_expr(loc), in_state_expr(loc));
1046 }
1047 else
1048 {
1049 auto state = state_expr();
1050 auto condition_evaluated = evaluate_expr(loc, state, condition);
1051
1052 dest << forall_states_expr(
1053 loc,
1055 function_application_exprt(out_state_expr(loc, true), {state}));
1056
1057 dest << forall_states_expr(
1058 loc,
1060 function_application_exprt(out_state_expr(loc, false), {state}));
1061 }
1062 }
1063 else if(loc->is_assert())
1064 {
1065 // all assertions need to hold
1066 dest << forall_states_expr(
1067 loc, evaluate_expr(loc, state_expr(), loc->condition()));
1068
1069 dest << equal_exprt(out_state_expr(loc), in_state_expr(loc));
1070 }
1071 else if(
1072 loc->is_skip() || loc->is_assert() || loc->is_location() ||
1073 loc->is_end_function())
1074 {
1075 // these do not change the state
1076 dest << equal_exprt(out_state_expr(loc), in_state_expr(loc));
1077 }
1078 else if(loc->is_atomic_begin() || loc->is_atomic_end())
1079 {
1080 // no concurrency yet
1081 dest << equal_exprt(out_state_expr(loc), in_state_expr(loc));
1082 }
1083 else if(loc->is_other())
1084 {
1085 auto &code = loc->code();
1086 auto &statement = code.get_statement();
1087 if(statement == ID_array_set)
1088 {
1090 code.operands().size() == 2, "array_set has two operands");
1091 // op0 must be an array
1092 dest << equal_exprt(out_state_expr(loc), in_state_expr(loc));
1093 }
1094 else
1095 {
1096 // ought to print a warning
1097 dest << equal_exprt(out_state_expr(loc), in_state_expr(loc));
1098 }
1099 }
1100 else if(loc->is_decl())
1101 {
1102 auto s_in = state_expr();
1104 s_in, address_rec(loc, s_in, loc->decl_symbol()));
1105 dest << forall_states_expr(
1107 }
1108 else if(loc->is_dead())
1109 {
1110 auto s = state_expr();
1111 auto s_in = state_expr();
1113 s_in, address_rec(loc, s_in, loc->dead_symbol()));
1114 dest << forall_states_expr(
1116 }
1117 else if(loc->is_function_call())
1118 {
1119 function_call(loc, dest);
1120 }
1121 else if(loc->is_set_return_value())
1122 {
1123 const auto &rhs = loc->return_value();
1124
1125 if(return_lhs.is_nil())
1126 {
1127 // treat these as assignments to a special symbol named 'return_value'
1128 auto lhs = symbol_exprt("return_value", rhs.type());
1129 dest << assignment_constraint(loc, std::move(lhs), std::move(rhs));
1130 }
1131 else
1132 {
1133 }
1134 }
1135 else
1136 {
1137 std::cout << "X: " << loc->type() << '\n';
1138 DATA_INVARIANT(false, "unexpected GOTO instruction");
1139 }
1140 }
1141}
1142
1144 const goto_modelt &goto_model,
1145 bool program_is_inlined,
1146 std::optional<irep_idt> contract,
1147 encoding_targett &dest)
1148{
1150 {
1151 auto f_entry = goto_model.goto_functions.function_map.find(
1153
1154 if(f_entry == goto_model.goto_functions.function_map.end())
1155 throw incorrect_goto_program_exceptiont("The program has no entry point");
1156
1157 dest.annotation("function " + id2string(f_entry->first));
1158
1159 state_encodingt{goto_model}(f_entry, dest);
1160 }
1161 else if(contract.has_value())
1162 {
1163 // check given contract
1164 const namespacet ns(goto_model.symbol_table);
1165 const symbolt *symbol;
1166 if(ns.lookup(*contract, symbol))
1168 "The given function was not found", "contract");
1169
1170 if(!get_contract(*contract, ns).has_value())
1172 "The given function has no contract", "contract");
1173
1174 const auto f = goto_model.goto_functions.function_map.find(symbol->name);
1175 CHECK_RETURN(f != goto_model.goto_functions.function_map.end());
1176
1177 dest.annotation("");
1178 dest.annotation("function " + id2string(symbol->name));
1179 state_encodingt{goto_model}(f, dest);
1180 }
1181 else
1182 {
1183 // sort alphabetically
1184 const auto sorted = goto_model.goto_functions.sorted();
1185 const namespacet ns(goto_model.symbol_table);
1186 bool found = false;
1187 for(auto &f : sorted)
1188 {
1189 if(
1190 f->first == goto_functionst::entry_point() ||
1191 get_contract(f->first, ns).has_value())
1192 {
1193 dest.annotation("");
1194 dest.annotation("function " + id2string(f->first));
1195 state_encodingt{goto_model}(f, dest);
1196 found = true;
1197 }
1198 }
1199
1200 if(!found)
1201 throw incorrect_goto_program_exceptiont("The program has no entry point");
1202 }
1203}
1204
1206 const goto_modelt &goto_model,
1208 bool program_is_inlined,
1209 std::optional<irep_idt> contract,
1210 std::ostream &out)
1211{
1212 switch(state_encoding_format)
1213 {
1215 {
1216 ascii_encoding_targett dest(out);
1217 state_encoding(goto_model, program_is_inlined, contract, dest);
1218 }
1219 break;
1220
1222 {
1223 const namespacet ns(goto_model.symbol_table);
1224 smt2_encoding_targett dest(ns, out);
1225 state_encoding(goto_model, program_is_inlined, contract, dest);
1226 }
1227 break;
1228 }
1229}
1230
1232 const goto_modelt &goto_model,
1234 std::ostream &out)
1235{
1236 const namespacet ns(goto_model.symbol_table);
1237
1239 state_encoding(goto_model, true, {}, container);
1240
1242
1243 variable_encoding(container.constraints);
1244
1245 switch(state_encoding_format)
1246 {
1248 {
1249 ascii_encoding_targett dest(out);
1250 dest << container;
1251 }
1252 break;
1253
1255 {
1256 smt2_encoding_targett dest(ns, out);
1257 dest << container;
1258 }
1259 break;
1260 }
1261}
1262
1264 const goto_modelt &goto_model,
1265 bool program_is_inlined,
1266 std::optional<irep_idt> contract,
1268{
1269 const namespacet ns(goto_model.symbol_table);
1270
1272 state_encoding(goto_model, program_is_inlined, contract, container);
1273
1275
1276#if 0
1277 if(solver_options.verbose)
1278 {
1279 ascii_encoding_targett dest(std::cout);
1280 dest << container;
1281 }
1282#endif
1283
1284 return solver(container.constraints, solver_options, ns);
1285}
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
pointer_typet pointer_type(const typet &subtype)
Definition c_types.cpp:235
Operator to return the address of an object.
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:566
Boolean AND All operands must be boolean, and the result is always boolean.
Definition std_expr.h:2043
Arrays with given size.
Definition std_types.h:806
A base class for expressions that are predicates, i.e., Boolean-typed, and that take exactly two argu...
Definition std_expr.h:737
std::vector< symbol_exprt > variablest
Definition std_expr.h:3172
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
Operator to return the address of an array element relative to a base address.
The empty type.
Definition std_types.h:50
virtual void annotation(const std::string &)
void set_source_location(source_locationt __source_location)
Equality.
Definition std_expr.h:1339
Base class for all expressions.
Definition expr.h:57
std::vector< exprt > operandst
Definition expr.h:59
typet & type()
Return the type of the expression.
Definition expr.h:85
operandst & operands()
Definition expr.h:95
const source_locationt & source_location() const
Definition expr.h:236
Operator to return the address of a field relative to a base address.
A forall expression.
Application of (mathematical) function.
function_mapt function_map
std::vector< function_mapt::const_iterator > sorted() const
returns a vector of the iterators in alphabetical order
static irep_idt entry_point()
Get the identifier of the entry point to a goto model.
A goto function, consisting of function body (see body) and parameter identifiers (see parameter_iden...
goto_programt body
symbol_tablet symbol_table
Symbol table.
Definition goto_model.h:31
goto_functionst goto_functions
GOTO functions.
Definition goto_model.h:34
instructionst instructions
The list of instructions in the goto program.
instructionst::const_iterator const_targett
Boolean implication.
Definition std_expr.h:2154
Thrown when a goto program that's being processed is in an invalid format, for example passing the wr...
Array index operator.
Definition std_expr.h:1431
Thrown when users pass incorrect command line arguments, for example passing no files to analysis or ...
const std::string & id_string() const
Definition irep.h:391
const irep_idt & id() const
Definition irep.h:388
bool is_nil() const
Definition irep.h:368
A (mathematical) lambda expression.
Extract member of struct or union.
Definition std_expr.h:2866
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition namespace.cpp:49
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().
The NIL expression.
Definition std_expr.h:3144
Boolean negation.
Definition std_expr.h:2388
Operator to return the address of an object.
A side_effect_exprt that returns a non-deterministically chosen value.
Definition std_code.h:1520
state_encodingt(const goto_modelt &__goto_model)
exprt evaluate_expr_rec(loct, const exprt &, const exprt &, const std::unordered_set< symbol_exprt, irep_hash > &) const
void setup_incoming(const goto_functiont &)
symbol_exprt in_state_expr(loct) const
void function_call(goto_programt::const_targett, encoding_targett &)
const goto_modelt & goto_model
exprt address_rec(loct, const exprt &, exprt) const
goto_programt::const_targett loct
void encode(const goto_functiont &, const irep_idt function_identifier, const std::string &state_prefix, const std::vector< irep_idt > &call_stack, const std::string &annotation, const symbol_exprt &entry_state, const exprt &return_lhs, encoding_targett &)
std::string annotation
symbol_exprt out_state_expr(loct) const
static symbol_exprt va_args(irep_idt function)
exprt assignment_constraint_rec(loct, exprt state, exprt lhs, exprt rhs, std::vector< symbol_exprt > &nondet_symbols) const
std::map< loct, std::vector< loct >, goto_programt::target_less_than > incomingt
exprt replace_nondet_rec(loct, const exprt &, std::vector< symbol_exprt > &nondet_symbols) const
void function_call_symbol(goto_programt::const_targett, encoding_targett &)
symbol_exprt entry_state
exprt evaluate_expr(loct, const exprt &, const exprt &) const
irep_idt function_identifier
symbol_exprt state_expr_with_suffix(loct, const std::string &suffix) const
std::vector< irep_idt > call_stack
exprt assignment_constraint(loct, exprt lhs, exprt rhs) const
std::string state_prefix
std::vector< symbol_exprt > incoming_symbols(loct) const
void operator()(const goto_functionst::function_mapt::const_iterator, encoding_targett &)
static exprt state_lambda_expr(exprt)
exprt forall_states_expr(loct, exprt) const
Expression to hold a symbol (variable)
Definition std_expr.h:132
Symbol table entry.
Definition symbol.h:28
irep_idt name
The unique identifier.
Definition symbol.h:40
An expression with three operands.
Definition std_expr.h:68
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition std_expr.h:2003
The type of an expression, extends irept.
Definition type.h:29
bool has_prefix(const std::string &s, const std::string &prefix)
Definition converter.cpp:13
#define CPROVER_PREFIX
void equality_propagation(std::vector< exprt > &constraints)
Equality Propagation.
Symbol Table + CFG.
#define forall_goto_program_instructions(it, program)
static symbol_exprt state_expr()
static exprt simplifying_not(exprt src)
static mathematical_function_typet state_predicate_type()
std::optional< code_with_contract_typet > get_contract(const irep_idt &function_identifier, const namespacet &ns)
Instrument Given Invariants.
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
API to expression classes for 'mathematical' expressions.
const quantifier_exprt & to_quantifier_expr(const exprt &expr)
Cast an exprt to a quantifier_exprt.
API to expression classes for Pointers.
const live_object_exprt & to_live_object_expr(const exprt &expr)
Cast an exprt to a live_object_exprt.
const r_or_w_ok_exprt & to_r_or_w_ok_expr(const exprt &expr)
const cstrlen_exprt & to_cstrlen_expr(const exprt &expr)
Cast an exprt to a cstrlen_exprt.
const writeable_object_exprt & to_writeable_object_expr(const exprt &expr)
Cast an exprt to a writeable_object_exprt.
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
const object_size_exprt & to_object_size_expr(const exprt &expr)
Cast an exprt to a object_size_exprt.
const is_dynamic_object_exprt & to_is_dynamic_object_expr(const exprt &expr)
exprt simplify_expr(exprt src, const namespacet &ns)
void solver(std::vector< framet > &frames, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const solver_optionst &solver_options, const namespacet &ns, std::vector< propertyt > &properties, std::size_t property_index)
Definition solver.cpp:44
Equality Propagation.
solver_resultt
Definition solver.h:21
#define CHECK_RETURN(CONDITION)
Definition invariant.h:495
#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
solver_resultt state_encoding_solver(const goto_modelt &goto_model, bool program_is_inlined, std::optional< irep_idt > contract, const solver_optionst &solver_options)
void state_encoding(const goto_modelt &goto_model, bool program_is_inlined, std::optional< irep_idt > contract, encoding_targett &dest)
void variable_encoding(const goto_modelt &goto_model, state_encoding_formatt state_encoding_format, std::ostream &out)
std::set< irep_idt > no_body_warnings
static exprt simplifying_not(exprt src)
State Encoding.
state_encoding_formatt
side_effect_exprt & to_side_effect_expr(exprt &expr)
Definition std_code.h:1506
exprt conjunction(exprt a, exprt b)
Conjunction of two expressions.
Definition std_expr.cpp:252
const binary_relation_exprt & to_binary_relation_expr(const exprt &expr)
Cast an exprt to a binary_relation_exprt.
Definition std_expr.h:828
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1494
const ternary_exprt & to_ternary_expr(const exprt &expr)
Cast an exprt to a ternary_exprt.
Definition std_expr.h:117
const binary_exprt & to_binary_expr(const exprt &expr)
Cast an exprt to a binary_exprt.
Definition std_expr.h:721
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
Definition std_expr.h:424
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:2953
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition std_expr.h:3078
const not_exprt & to_not_expr(const exprt &expr)
Cast an exprt to an not_exprt.
Definition std_expr.h:2408
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:221
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition std_types.h:787
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition std_types.h:517
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition std_types.h:887
A total order over targett and const_targett.
#define size_type
Definition unistd.c:186
Variable Encoding.
dstringt irep_idt