CBMC
Loading...
Searching...
No Matches
goto_symex_state.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Symbolic Execution
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
11
12#include "goto_symex_state.h"
13
14#include <util/as_const.h>
15#include <util/base_exceptions.h> // IWYU pragma: keep
16#include <util/byte_operators.h>
17#include <util/c_types.h>
19#include <util/expr_iterator.h>
20#include <util/expr_util.h>
21#include <util/invariant.h>
22#include <util/std_expr.h>
23
24#include <analyses/dirty.h>
26
30
34 bool should_simplify,
35 const irep_idt &language_mode,
36 guard_managert &manager,
37 std::function<std::size_t(const irep_idt &)> fresh_l2_name_provider)
38 : goto_statet(manager),
39 source(_source),
40 guard_manager(manager),
41 symex_target(nullptr),
42 field_sensitivity(
44 should_simplify,
45 language_mode),
46 record_events({true}),
47 language_mode(language_mode),
48 fresh_l2_name_provider(fresh_l2_name_provider)
49{
50 threads.emplace_back(guard_manager);
51 call_stack().new_frame(source, guardt(true_exprt(), manager));
52}
53
55
56template <>
58goto_symex_statet::set_indices<L0>(ssa_exprt ssa_expr, const namespacet &ns)
59{
60 return symex_level0(std::move(ssa_expr), ns, source.thread_nr);
61}
62
63template <>
65goto_symex_statet::set_indices<L1>(ssa_exprt ssa_expr, const namespacet &ns)
66{
67 return level1(symex_level0(std::move(ssa_expr), ns, source.thread_nr));
68}
69
70template <>
72goto_symex_statet::set_indices<L2>(ssa_exprt ssa_expr, const namespacet &ns)
73{
74 return level2(
75 level1(symex_level0(std::move(ssa_expr), ns, source.thread_nr)));
76}
77
79 ssa_exprt lhs, // L0/L1
80 const exprt &rhs, // L2
81 const namespacet &ns,
83 bool record_value,
84 bool allow_pointer_unsoundness)
85{
86 // identifier should be l0 or l1, make sure it's l1
87 lhs = rename_ssa<L1>(std::move(lhs), ns).get();
89
90 // the type might need renaming
91 rename<L2>(lhs.type(), l1_identifier, ns);
94 lhs.update_type();
96 {
97 DATA_INVARIANT(!check_renaming_l1(lhs), "lhs renaming failed on l1");
98 }
99
100 // do the l2 renaming
102 renamedt<ssa_exprt, L2> l2_lhs = set_indices<L2>(std::move(lhs), ns);
103 lhs = l2_lhs.get();
104
105 // in case we happen to be multi-threaded, record the memory access
107
109 {
110 DATA_INVARIANT(!check_renaming(lhs), "lhs renaming failed on l2");
111 DATA_INVARIANT(!check_renaming(rhs), "rhs renaming failed on l2");
112 }
113
114 // see #305 on GitHub for a simple example and possible discussion
115 if(is_shared && lhs.type().id() == ID_pointer && !allow_pointer_unsoundness)
117 "pointer handling for concurrency is unsound");
118
119 // Update constant propagation map -- the RHS is L2
121 {
123 if(!propagation_entry.has_value())
124 propagation.insert(l1_identifier, rhs);
125 else if(propagation_entry->get() != rhs)
126 propagation.replace(l1_identifier, rhs);
127 }
128 else
129 propagation.erase_if_exists(l1_identifier);
130
132
133#ifdef DEBUG
134 std::cout << "Assigning " << l1_identifier << '\n';
135 value_set.output(std::cout);
136 std::cout << "**********************\n";
137#endif
138
139 return l2_lhs;
140}
141
142template <levelt level>
145{
146 static_assert(
147 level == L0 || level == L1,
148 "rename_ssa can only be used for levels L0 and L1");
149 ssa = set_indices<level>(std::move(ssa), ns).get();
150 rename<level>(ssa.type(), ssa.get_identifier(), ns);
151 ssa.update_type();
153}
154
157goto_symex_statet::rename_ssa<L0>(ssa_exprt ssa, const namespacet &ns);
159goto_symex_statet::rename_ssa<L1>(ssa_exprt ssa, const namespacet &ns);
160
161template <levelt level>
164{
165 // rename all the symbols with their last known value
166
167 static_assert(
168 level == L0 || level == L1 || level == L1_WITH_CONSTANT_PROPAGATION ||
169 level == L2,
170 "must handle all renaming levels");
171
172 if(is_ssa_expr(expr))
173 {
174 exprt original_expr = expr;
176
177 if(level == L0)
178 {
180 std::move(rename_ssa<L0>(std::move(ssa), ns).value())};
181 }
182 else if(level == L1)
183 {
185 std::move(rename_ssa<L1>(std::move(ssa), ns).value())};
186 }
187 else
188 {
189 ssa = set_indices<L1>(std::move(ssa), ns).get();
190 rename<level>(expr.type(), ssa.get_identifier(), ns);
191 ssa.update_type();
192
193 // renaming taken care of by l2_thread_encoding, or already at L2
194 if(l2_thread_read_encoding(ssa, ns) || !ssa.get_level_2().empty())
195 {
197 {
198 // Don't actually rename to L2 -- we just used `ssa` to check whether
199 // constant-propagation was applicable
200 return renamedt<exprt, level>(std::move(original_expr));
201 }
202 else
203 return renamedt<exprt, level>(std::move(ssa));
204 }
205 else
206 {
207 // We also consider propagation if we go up to L2.
208 // L1 identifiers are used for propagation!
209 auto p_it = propagation.find(ssa.get_identifier());
210
211 if(p_it.has_value())
212 {
213 return renamedt<exprt, level>(*p_it); // already L2
214 }
215 else
216 {
217 if(level == L2)
218 ssa = set_indices<L2>(std::move(ssa), ns).get();
219 return renamedt<exprt, level>(std::move(ssa));
220 }
221 }
222 }
223 }
224 else if(expr.id()==ID_symbol)
225 {
226 const auto &type = as_const(expr).type();
227
228 // we never rename function symbols
229 if(type.id() == ID_code || type.id() == ID_mathematical_function)
230 {
231 rename<level>(expr.type(), to_symbol_expr(expr).get_identifier(), ns);
232 return renamedt<exprt, level>{std::move(expr)};
233 }
234 else
235 return rename<level>(ssa_exprt{expr}, ns);
236 }
237 else if(expr.id()==ID_address_of)
238 {
241 to_pointer_type(expr.type()).base_type() =
242 as_const(address_of_expr).object().type();
243 return renamedt<exprt, level>{std::move(expr)};
244 }
245 else if(expr.is_nil())
246 {
247 return renamedt<exprt, level>{std::move(expr)};
248 }
249 else
250 {
251 rename<level>(expr.type(), irep_idt(), ns);
252
253 // do this recursively
254 Forall_operands(it, expr)
255 *it = rename<level>(std::move(*it), ns).get();
256
257 const exprt &c_expr = as_const(expr);
258
259 // It may happen that the `old` subexpression of a `with_exprt` expression
260 // is propagated with a value that has an array type with a size that is a
261 // symbol with an L2 index that is different. In this case the type of the
262 // `with_exprt` will not match with the type of the `old` subexpression
263 // anymore.
264 // To address this issue we re-canonicalize the `with_exprt` by propagating
265 // the type of the `old` subexpression to the type of the `with_exprt`.
267 if(
270 c_with_expr->type() != c_with_expr->old().type())
271 {
272 expr.type() = to_with_expr(expr).old().type();
273 }
275 expr.id() != ID_with ||
276 c_expr.type() == to_with_expr(c_expr).old().type(),
277 "Type of renamed expr should be the same as operands for with_exprt",
278 c_expr.type().pretty(),
279 to_with_expr(c_expr).old().type().pretty());
281 expr.id() != ID_if ||
282 c_expr.type() == to_if_expr(c_expr).true_case().type(),
283 "Type of renamed expr should be the same as operands for if_exprt",
284 c_expr.type().pretty(),
285 to_if_expr(c_expr).true_case().type().pretty());
287 expr.id() != ID_if ||
288 c_expr.type() == to_if_expr(c_expr).false_case().type(),
289 "Type of renamed expr should be the same as operands for if_exprt",
290 c_expr.type().pretty(),
291 to_if_expr(c_expr).false_case().type().pretty());
292
293 if(level == L2)
294 expr = field_sensitivity.apply(ns, *this, std::move(expr), false);
295
296 return renamedt<exprt, level>{std::move(expr)};
297 }
298}
299
300// Explicitly instantiate the one version of this function without an explicit
301// caller in this file:
304
306{
307 rename(lvalue.type(), irep_idt(), ns);
308
309 if(lvalue.id() == ID_symbol)
310 {
311 // Nothing to do
312 }
314 {
315 // Ignore apparent writes to 'NULL-object' and similar read-only objects
316 }
317 else if(lvalue.id() == ID_typecast)
318 {
321 }
322 else if(lvalue.id() == ID_member)
323 {
325 member_lvalue.compound() = l2_rename_rvalues(member_lvalue.compound(), ns);
326 }
327 else if(lvalue.id() == ID_index)
328 {
329 // The index is an rvalue:
331 index_lvalue.array() = l2_rename_rvalues(index_lvalue.array(), ns);
332 index_lvalue.index() = rename(index_lvalue.index(), ns).get();
333 }
334 else if(
337 {
338 // The offset is an rvalue:
341 byte_extract_lvalue.offset() = rename(byte_extract_lvalue.offset(), ns);
342 }
343 else if(lvalue.id() == ID_if)
344 {
345 // The condition is an rvalue:
346 auto &if_lvalue = to_if_expr(lvalue);
347 if_lvalue.cond() = rename(if_lvalue.cond(), ns);
348 if(if_lvalue.cond() != false)
349 if_lvalue.true_case() = l2_rename_rvalues(if_lvalue.true_case(), ns);
350 if(if_lvalue.cond() != true)
351 if_lvalue.false_case() = l2_rename_rvalues(if_lvalue.false_case(), ns);
352 }
353 else if(lvalue.id() == ID_complex_real)
354 {
357 }
358 else if(lvalue.id() == ID_complex_imag)
359 {
362 }
363 else
364 {
366 "l2_rename_rvalues case `" + lvalue.id_string() + "' not handled");
367 }
368
369 return lvalue;
370}
371
372template renamedt<exprt, L1>
373goto_symex_statet::rename<L1>(exprt expr, const namespacet &ns);
374
377 ssa_exprt &expr,
378 const namespacet &ns)
379{
380 // do we have threads?
381 if(threads.size()<=1)
382 return false;
383
384 // is it a shared object?
385 PRECONDITION(dirty != nullptr);
387 if(
389 (!ns.lookup(obj_identifier).is_shared() && !(*dirty)(obj_identifier)))
390 {
391 return false;
392 }
393
394 // only continue if an indivisible object is being accessed
395 if(field_sensitivity.is_divisible(expr, true))
396 return false;
397
398 const ssa_exprt ssa_l1 = remove_level_2(expr);
399 const irep_idt &l1_identifier=ssa_l1.get_identifier();
401
402 // see whether we are within an atomic section
403 if(atomic_section_id!=0)
404 {
406
409 {
410 for(const auto &guard_in_list : a_s_writes->second)
411 {
413 g-=guard;
414 if(g.is_true())
415 // There has already been a write to l1_identifier within this atomic
416 // section under the same guard, or a guard implied by the current
417 // one.
418 return false;
419
421 }
422 }
423
424 not_exprt no_write(write_guard.as_expr());
425
426 // we cannot determine for sure that there has been a write already
427 // so generate a read even if l1_identifier has been written on
428 // all branches flowing into this read
430
432 for(const auto &a_s_read_guard : a_s_read.second)
433 {
434 guardt g = a_s_read_guard; // copy
435 g-=guard;
436 if(g.is_true())
437 // There has already been a read of l1_identifier within this atomic
438 // section under the same guard, or a guard implied by the current one.
439 return false;
440
442 }
443
444 guardt cond = read_guard;
445 if(no_write.op() != false)
446 cond |= guardt{no_write.op(), guard_manager};
447
448 // It is safe to perform constant propagation in case we have read or
449 // written this object within the atomic section. We must actually do this,
450 // because goto_state::apply_condition may have placed the latest value in
451 // the propagation map without recording an assignment.
452 auto p_it = propagation.find(ssa_l1.get_identifier());
453 const exprt l2_true_case =
454 p_it.has_value() ? *p_it : set_indices<L2>(ssa_l1, ns).get();
455
456 if(!cond.is_true())
458
459 if(a_s_read.second.empty())
461
463
464 exprt tmp;
465 if(cond.is_false())
466 tmp = l2_false_case.get();
467 else if(cond.is_true())
469 else
471
472 record_events.push(false);
473 ssa_exprt ssa_l2 = assignment(std::move(ssa_l1), tmp, ns, true, true).get();
474 record_events.pop();
475
478 ssa_l2,
479 ssa_l2,
480 ssa_l2.get_original_expr(),
481 tmp,
482 source,
484
485 INVARIANT(!check_renaming(ssa_l2), "expr should be renamed to L2");
486 expr = std::move(ssa_l2);
487
488 a_s_read.second.push_back(guard);
489 if(no_write.op() != false)
490 a_s_read.second.back().add(no_write);
491
492 return true;
493 }
494
495 // No event and no fresh index, but avoid constant propagation
496 if(!record_events.top())
497 {
498 expr = set_indices<L2>(std::move(ssa_l1), ns).get();
499 return true;
500 }
501
502 // produce a fresh L2 name
504 expr = set_indices<L2>(std::move(ssa_l1), ns).get();
505
506 // and record that
508 symex_target!=nullptr, nullptr_exceptiont, "symex_target is null");
510
511 return true;
512}
513
515 const ssa_exprt &expr,
516 const namespacet &ns) const
517{
518 if(!record_events.top())
520
521 PRECONDITION(dirty != nullptr);
523 if(
525 (!ns.lookup(obj_identifier).is_shared() && !(*dirty)(obj_identifier)))
526 {
528 }
529
530 // only continue if an indivisible object is being accessed
531 if(field_sensitivity.is_divisible(expr, true))
533
534 if(atomic_section_id != 0)
536
538}
539
543 const ssa_exprt &expr,
544 const namespacet &ns)
545{
546 switch(write_is_shared(expr, ns))
547 {
549 return false;
551 {
553 return false;
554 }
556 break;
557 }
558
559 // record a shared write
561 guard.as_expr(),
562 expr,
564 source);
565
566 // do we have threads?
567 return threads.size() > 1;
568}
569
570template <levelt level>
572{
573 if(is_ssa_expr(expr))
574 {
576
577 // only do L1!
578 ssa = set_indices<L1>(std::move(ssa), ns).get();
579
580 rename<level>(expr.type(), ssa.get_identifier(), ns);
581 ssa.update_type();
582 }
583 else if(expr.id()==ID_symbol)
584 {
585 expr=ssa_exprt(expr);
586 rename_address<level>(expr, ns);
587 }
588 else
589 {
590 if(expr.id()==ID_index)
591 {
593
595 PRECONDITION(index_expr.array().type().id() == ID_array);
596 expr.type() = to_array_type(index_expr.array().type()).element_type();
597
598 // the index is not an address
599 index_expr.index() =
600 rename<level>(std::move(index_expr.index()), ns).get();
601 }
602 else if(expr.id()==ID_if)
603 {
604 // the condition is not an address
606 if_expr.cond() = rename<level>(std::move(if_expr.cond()), ns).get();
607 rename_address<level>(if_expr.true_case(), ns);
608 rename_address<level>(if_expr.false_case(), ns);
609
610 if_expr.type()=if_expr.true_case().type();
611 }
612 else if(expr.id()==ID_member)
613 {
615
616 rename_address<level>(member_expr.struct_op(), ns);
617
618 // type might not have been renamed in case of nesting of
619 // structs and pointers/arrays
620 if(
621 member_expr.struct_op().type().id() != ID_struct_tag &&
622 member_expr.struct_op().type().id() != ID_union_tag)
623 {
625 to_struct_union_type(member_expr.struct_op().type());
627 su_type.get_component(member_expr.get_component_name());
628 PRECONDITION(comp.is_not_nil());
629 expr.type()=comp.type();
630 }
631 else
632 rename<level>(expr.type(), irep_idt(), ns);
633 }
634 else
635 {
636 // this could go wrong, but we would have to re-typecheck ...
637 rename<level>(expr.type(), irep_idt(), ns);
638
639 // do this recursively; we assume here
640 // that all the operands are addresses
641 Forall_operands(it, expr)
642 rename_address<level>(*it, ns);
643 }
644 }
645}
646
650static bool requires_renaming(const typet &type, const namespacet &ns)
651{
652 if(type.id() == ID_array)
653 {
654 const auto &array_type = to_array_type(type);
655 return requires_renaming(array_type.element_type(), ns) ||
656 !array_type.size().is_constant();
657 }
658 else if(type.id() == ID_struct || type.id() == ID_union)
659 {
661 const struct_union_typet::componentst &components = s_u_type.components();
662
663 for(auto &component : components)
664 {
665 // be careful, or it might get cyclic
666 if(component.type().id() == ID_array)
667 {
668 if(!to_array_type(component.type()).size().is_constant())
669 return true;
670 }
671 else if(
672 component.type().id() != ID_pointer &&
673 requires_renaming(component.type(), ns))
674 {
675 return true;
676 }
677 }
678
679 return false;
680 }
681 else if(type.id() == ID_pointer)
682 {
683 return requires_renaming(to_pointer_type(type).base_type(), ns);
684 }
685 else if(type.id() == ID_union_tag)
686 {
687 const symbolt &symbol = ns.lookup(to_union_tag_type(type));
688 return requires_renaming(symbol.type, ns);
689 }
690 else if(type.id() == ID_struct_tag)
691 {
692 const symbolt &symbol = ns.lookup(to_struct_tag_type(type));
693 return requires_renaming(symbol.type, ns);
694 }
695
696 return false;
697}
698
699template <levelt level>
701 typet &type,
702 const irep_idt &l1_identifier,
703 const namespacet &ns)
704{
705 // check whether there are symbol expressions in the type; if not, there
706 // is no need to expand the struct/union tags in the type
707 if(!requires_renaming(type, ns))
708 return; // no action
709
710 // rename all the symbols with their last known value
711 // to the given level
712
713 std::pair<l1_typest::iterator, bool> l1_type_entry;
714 if(level==L2 &&
715 !l1_identifier.empty())
716 {
717 l1_type_entry=l1_types.insert(std::make_pair(l1_identifier, type));
718
719 if(!l1_type_entry.second) // was already in map
720 {
721 // do not change a complete array type to an incomplete one
722
723 const typet &type_prev=l1_type_entry.first->second;
724
725 if(type.id()!=ID_array ||
726 type_prev.id()!=ID_array ||
727 to_array_type(type).is_incomplete() ||
728 to_array_type(type_prev).is_complete())
729 {
730 type=l1_type_entry.first->second;
731 return;
732 }
733 }
734 }
735
736 if(type.id()==ID_array)
737 {
738 auto &array_type = to_array_type(type);
739 rename<level>(array_type.element_type(), irep_idt(), ns);
740 array_type.size() = rename<level>(std::move(array_type.size()), ns).get();
741 }
742 else if(
743 type.id() == ID_struct || type.id() == ID_union ||
744 type.id() == ID_struct_tag || type.id() == ID_union_tag)
745 {
746 // expand struct and union tag types
747 if(type.id() == ID_struct_tag)
748 type = ns.follow_tag(to_struct_tag_type(type));
749 else if(type.id() == ID_union_tag)
750 type = ns.follow_tag(to_union_tag_type(type));
751
753 struct_union_typet::componentst &components=s_u_type.components();
754
755 for(auto &component : components)
756 {
757 // be careful, or it might get cyclic
758 if(component.type().id() == ID_array)
759 {
760 auto &array_type = to_array_type(component.type());
761 array_type.size() =
762 rename<level>(std::move(array_type.size()), ns).get();
763 }
764 else if(component.type().id() != ID_pointer)
765 rename<level>(component.type(), irep_idt(), ns);
766 }
767 }
768 else if(type.id()==ID_pointer)
769 {
770 rename<level>(to_pointer_type(type).base_type(), irep_idt(), ns);
771 }
772
773 if(level==L2 &&
774 !l1_identifier.empty())
775 l1_type_entry.first->second=type;
776}
777
783void goto_symex_statet::print_backtrace(std::ostream &out) const
784{
785 if(threads[source.thread_nr].call_stack.empty())
786 {
787 out << "No stack!\n";
788 return;
789 }
790
791 out << source.function_id << " " << source.pc->location_number << "\n";
792
793 for(auto stackit = threads[source.thread_nr].call_stack.rbegin(),
794 stackend = threads[source.thread_nr].call_stack.rend();
795 stackit != stackend;
796 ++stackit)
797 {
798 const auto &frame = *stackit;
799 out << frame.calling_location.function_id << " "
800 << frame.calling_location.pc->location_number << "\n";
801 }
802}
803
805 const symbol_exprt &expr,
806 std::function<std::size_t(const irep_idt &)> index_generator,
807 const namespacet &ns)
808{
809 framet &frame = call_stack().top();
810
812 const irep_idt l0_name = renamed.get_identifier();
813 const std::size_t l1_index = index_generator(l0_name);
814
815 if(const auto old_value = level1.insert_or_replace(renamed, l1_index))
816 {
817 // save old L1 name
818 if(!frame.old_level1.has(renamed))
819 frame.old_level1.insert(renamed, old_value->second);
820 }
821
822 const ssa_exprt ssa = rename_ssa<L1>(renamed.get(), ns).get();
823 const bool inserted = frame.local_objects.insert(ssa.get_identifier()).second;
824 INVARIANT(inserted, "l1_name expected to be unique by construction");
825
826 return ssa;
827}
828
830{
831 const irep_idt &l1_identifier = ssa.get_identifier();
832
833 // rename type to L2
834 rename(ssa.type(), l1_identifier, ns);
835 ssa.update_type();
836
837 // in case of pointers, put something into the value set
838 if(ssa.type().id() == ID_pointer)
839 {
840 exprt rhs;
841 if(
842 auto failed =
843 get_failed_symbol(to_symbol_expr(ssa.get_original_expr()), ns))
845 else
846 rhs = exprt(ID_invalid);
847
848 exprt l1_rhs = rename<L1>(std::move(rhs), ns).get();
849 value_set.assign(ssa, l1_rhs, ns, true, false);
850 }
851
852 // L2 renaming
853 exprt fields = field_sensitivity.get_fields(ns, *this, ssa, false);
854
855 for(auto &e : pre_traversal(fields))
856 {
858 {
860 const std::size_t field_generation = level2.increase_generation(
861 l1_symbol->get_identifier(), field_ssa, fresh_l2_name_provider);
863 }
865 {
866 const ssa_exprt &ssa = fs_ssa->get_object_ssa();
867 const std::size_t field_generation = level2.increase_generation(
868 ssa.get_identifier(), ssa, fresh_l2_name_provider);
870 }
871 };
872
873 record_events.push(false);
874 exprt expr_l2 = rename(std::move(ssa), ns).get();
875 INVARIANT(
877 "symbol to declare should not be replaced by constant propagation");
879 record_events.pop();
880
881 return ssa;
882}
std::optional< symbol_exprt > get_failed_symbol(const symbol_exprt &expr, const namespacet &ns)
Get the failed-dereference symbol for the given symbol.
Pointer Dereferencing.
const T & as_const(T &value)
Return a reference to the same object but ensures the type is const.
Definition as_const.h:14
Generic exception types primarily designed for use with invariants.
Expression classes for byte-level operators.
const byte_extract_exprt & to_byte_extract_expr(const exprt &expr)
const union_tag_typet & to_union_tag_type(const typet &type)
Cast a typet to a union_tag_typet.
Definition c_types.h:224
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:562
framet & top()
Definition call_stack.h:17
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
Base class for all expressions.
Definition expr.h:57
typet & type()
Return the type of the expression.
Definition expr.h:85
The Boolean constant false.
Definition std_expr.h:3272
exprt get_fields(const namespacet &ns, goto_symex_statet &state, const ssa_exprt &ssa_expr, bool disjoined_fields_only) const
Compute an expression representing the individual components of a field-sensitive SSA representation ...
exprt apply(const namespacet &ns, goto_symex_statet &state, exprt expr, bool write) const
Turn an expression expr into a field-sensitive SSA expression.
bool is_divisible(const ssa_exprt &expr, bool disjoined_fields_only) const
Determine whether expr would translate to an atomic SSA expression (returns false) or a composite obj...
Stack frames – these are used for function calls and for exceptions.
symex_level1t old_level1
Definition frame.h:42
std::set< irep_idt > local_objects
Definition frame.h:44
Container for data that varies per program point, e.g.
Definition goto_state.h:32
symex_level2t level2
Definition goto_state.h:38
guardt guard
Definition goto_state.h:58
unsigned atomic_section_id
Threads.
Definition goto_state.h:76
sharing_mapt< irep_idt, exprt > propagation
Definition goto_state.h:71
value_sett value_set
Uses level 1 names, and is used to do dereferencing.
Definition goto_state.h:51
ssa_exprt declare(ssa_exprt ssa, const namespacet &ns)
Add invalid (or a failed symbol) to the value_set if ssa is a pointer, ensure that level2 index of sy...
ssa_exprt add_object(const symbol_exprt &expr, std::function< std::size_t(const irep_idt &)> index_generator, const namespacet &ns)
Instantiate the object expr.
call_stackt & call_stack()
std::pair< unsigned, std::list< guardt > > a_s_r_entryt
std::stack< bool > record_events
bool l2_thread_write_encoding(const ssa_exprt &expr, const namespacet &ns)
thread encoding
exprt l2_rename_rvalues(exprt lvalue, const namespacet &ns)
static irep_idt guard_identifier()
const incremental_dirtyt * dirty
std::unordered_map< ssa_exprt, a_s_r_entryt, irep_hash > read_in_atomic_section
std::unordered_map< ssa_exprt, a_s_w_entryt, irep_hash > written_in_atomic_section
symex_level1t level1
const irep_idt & language_mode
void rename_address(exprt &expr, const namespacet &ns)
renamedt< ssa_exprt, L2 > assignment(ssa_exprt lhs, const exprt &rhs, const namespacet &ns, bool rhs_is_simplified, bool record_value, bool allow_pointer_unsoundness=false)
guard_managert & guard_manager
bool l2_thread_read_encoding(ssa_exprt &expr, const namespacet &ns)
thread encoding
void print_backtrace(std::ostream &) const
Dumps the current state of symex, printing the function name and location number for each stack frame...
renamedt< exprt, level > rename(exprt expr, const namespacet &ns)
Rewrites symbol expressions in exprt, applying a suffix to each symbol reflecting its most recent ver...
symex_target_equationt * symex_target
goto_symex_statet(const symex_targett::sourcet &, std::size_t max_field_sensitive_array_size, bool should_simplify, const irep_idt &language_mode, guard_managert &manager, std::function< std::size_t(const irep_idt &)> fresh_l2_name_provider)
static bool is_read_only_object(const exprt &lvalue)
Returns true if lvalue is a read-only object, such as the null object.
field_sensitivityt field_sensitivity
write_is_shared_resultt write_is_shared(const ssa_exprt &expr, const namespacet &ns) const
symex_targett::sourcet source
renamedt< ssa_exprt, level > rename_ssa(ssa_exprt ssa, const namespacet &ns)
Version of rename which is specialized for SSA exprt.
bool run_validation_checks
Should the additional validation checks be run?
std::vector< threadt > threads
std::function< std::size_t(const irep_idt &)> fresh_l2_name_provider
bool is_true() const
Definition guard_expr.h:60
exprt as_expr() const
Definition guard_expr.h:46
bool is_false() const
Definition guard_expr.h:65
The trinary if-then-else operator.
Definition std_expr.h:2528
Array index operator.
Definition std_expr.h:1488
const irep_idt & id() const
Definition irep.h:388
bool is_nil() const
Definition irep.h:368
Extract member of struct or union.
Definition std_expr.h:2998
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().
Boolean negation.
Definition std_expr.h:2485
Expression providing an SSA-renamed symbol of expressions.
Definition ssa_expr.h:17
void update_type()
Definition ssa_expr.h:28
irep_idt get_object_name() const
Definition ssa_expr.cpp:145
Base type for structs and unions.
Definition std_types.h:62
std::vector< componentt > componentst
Definition std_types.h:140
Expression to hold a symbol (variable)
Definition std_expr.h:131
const irep_idt & get_identifier() const
Definition std_expr.h:160
Symbol table entry.
Definition symbol.h:28
typet type
Type of symbol.
Definition symbol.h:31
virtual void shared_read(const exprt &guard, const ssa_exprt &ssa_object, unsigned atomic_section_id, const sourcet &source)
Read from a shared variable ssa_object (which is both the left- and the right–hand side of assignment...
virtual void shared_write(const exprt &guard, const ssa_exprt &ssa_object, unsigned atomic_section_id, const sourcet &source)
Write to a shared variable ssa_object: we effectively assign a value from this thread to be visible b...
virtual void assignment(const exprt &guard, const ssa_exprt &ssa_lhs, const exprt &ssa_full_lhs, const exprt &original_full_lhs, const exprt &ssa_rhs, const sourcet &source, assignment_typet assignment_type)
Write to a local variable.
The Boolean constant true.
Definition std_expr.h:3263
The type of an expression, extends irept.
Definition type.h:29
Thrown when we encounter an instruction, parameters to an instruction etc.
void output(std::ostream &out, const std::string &indent="") const
Pretty-print this value-set.
void assign(const exprt &lhs, const exprt &rhs, const namespacet &ns, bool is_simplified, bool add_to_sets)
Transforms this value-set by executing executing the assignment lhs := rhs against it.
Variables whose address is taken.
#define Forall_operands(it, expr)
Definition expr.h:28
Forward depth-first search iterators These iterators' copy operations are expensive,...
static const_depth_iterator_range_adaptert pre_traversal(const exprt &root)
Deprecated expression utility functions.
GOTO Symex constant propagation.
static bool requires_renaming(const typet &type, const namespacet &ns)
Return true if, and only if, the type or one of its subtypes requires SSA renaming.
Symbolic Execution.
guard_exprt guardt
Definition guard.h:29
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.
static bool is_shared(const namespacet &ns, const symbol_exprt &symbol_expr)
@ L2
Definition renamed.h:26
@ L0
Definition renamed.h:23
@ L1_WITH_CONSTANT_PROPAGATION
Definition renamed.h:25
@ L1
Definition renamed.h:24
bool check_renaming(const typet &type)
Check that type is correctly renamed to level 2 and return true in case an error is detected.
renamedt< ssa_exprt, L0 > symex_level0(ssa_exprt ssa_expr, const namespacet &ns, std::size_t thread_nr)
Set the level 0 renaming of SSA expressions.
bool check_renaming_l1(const exprt &expr)
Check that expr is correctly renamed to level 1 and return true in case an error is detected.
#define INVARIANT_STRUCTURED(CONDITION, TYPENAME,...)
Definition invariant.h:407
#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
#define INVARIANT_WITH_DIAGNOSTICS(CONDITION, REASON,...)
Same as invariant, with one or more diagnostics attached Diagnostics can be of any type that has a sp...
Definition invariant.h:437
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition invariant.h:423
ssa_exprt remove_level_2(ssa_exprt ssa)
Definition ssa_expr.cpp:219
bool is_ssa_expr(const exprt &expr)
Definition ssa_expr.h:125
const ssa_exprt & to_ssa_expr(const exprt &expr)
Cast a generic exprt to an ssa_exprt.
Definition ssa_expr.h:145
auto component(T &struct_expr, const irep_idt &name, const namespacet &ns) -> decltype(struct_expr.op0())
Definition std_expr.cpp:291
API to expression classes.
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1556
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition std_expr.h:2125
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition std_expr.h:2608
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:3090
const complex_imag_exprt & to_complex_imag_expr(const exprt &expr)
Cast an exprt to a complex_imag_exprt.
Definition std_expr.h:2071
const complex_real_exprt & to_complex_real_expr(const exprt &expr)
Cast an exprt to a complex_real_exprt.
Definition std_expr.h:2028
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:272
const with_exprt & to_with_expr(const exprt &expr)
Cast an exprt to a with_exprt.
Definition std_expr.h:2687
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition std_types.h:518
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition std_types.h:888
const struct_union_typet & to_struct_union_type(const typet &type)
Cast a typet to a struct_union_typet.
Definition std_types.h:214
This is unused by this implementation of guards, but can be used by other implementations of the same...
Definition guard_expr.h:20
std::optional< std::pair< ssa_exprt, std::size_t > > insert_or_replace(const renamedt< ssa_exprt, L0 > &ssa, std::size_t index)
Set the index for ssa to index.
bool has(const renamedt< ssa_exprt, L0 > &ssa) const
void insert(const renamedt< ssa_exprt, L0 > &ssa, std::size_t index)
Assume ssa is not already known.
unsigned latest_index(const irep_idt &identifier) const
Counter corresponding to an identifier.
std::size_t increase_generation(const irep_idt &l1_identifier, const ssa_exprt &lhs, std::function< std::size_t(const irep_idt &)> fresh_l2_name_provider)
Allocates a fresh L2 name for the given L1 identifier, and makes it the latest generation on this pat...
Identifies source in the context of symbolic execution.
goto_programt::const_targett pc
Generate Equation using Symbolic Execution.
static bool failed(bool error_indicator)
dstringt irep_idt