CBMC
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
value_set.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Value Set
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
11
12#include "value_set.h"
13
14#include <util/arith_tools.h>
15#include <util/bitvector_expr.h>
16#include <util/byte_operators.h>
17#include <util/c_types.h>
18#include <util/format_expr.h>
19#include <util/format_type.h>
20#include <util/namespace.h>
21#include <util/pointer_expr.h>
23#include <util/prefix.h>
24#include <util/range.h>
25#include <util/simplify_expr.h>
26#include <util/std_code.h>
27#include <util/symbol.h>
28#include <util/xml.h>
29
30#ifdef DEBUG
31#include <iostream>
32#include <util/format_expr.h>
33#include <util/format_type.h>
34#endif
35
36#include "add_failed_symbols.h"
37
38// Due to a large number of functions defined inline, `value_sett` and
39// associated types are documented in its header file, `value_set.h`.
40
43
44bool value_sett::field_sensitive(const irep_idt &id, const typet &type)
45{
46 // we always track fields on these
47 if(
48 id.starts_with("value_set::dynamic_object") ||
49 id == "value_set::return_value" || id == "value_set::memory")
50 return true;
51
52 // otherwise it has to be a struct
53 return type.id() == ID_struct || type.id() == ID_struct_tag;
54}
55
57{
58 auto found = values.find(id);
59 return !found.has_value() ? nullptr : &(found->get());
60}
61
63 const entryt &e,
64 const typet &type,
66 bool add_to_sets)
67{
68 irep_idt index;
69
70 if(field_sensitive(e.identifier, type))
71 index=id2string(e.identifier)+e.suffix;
72 else
73 index=e.identifier;
74
75 auto existing_entry = values.find(index);
76 if(existing_entry.has_value())
77 {
78 if(add_to_sets)
79 {
81 {
82 values.update(index, [&new_values, this](entryt &entry) {
84 });
85 }
86 }
87 else
88 {
90 index, [&new_values](entryt &entry) { entry.object_map = new_values; });
91 }
92 }
93 else
94 {
95 entryt new_entry = e;
96 new_entry.object_map = new_values;
97 values.insert(index, std::move(new_entry));
98 }
99}
100
102 const object_mapt &dest,
104 const offsett &offset) const
105{
106 auto entry=dest.read().find(n);
107
108 if(entry==dest.read().end())
109 {
110 // new
112 }
113 else if(!entry->second)
115 else if(offset && *entry->second == *offset)
117 else
119}
120
122 object_mapt &dest,
124 const offsett &offset) const
125{
126 auto insert_action = get_insert_action(dest, n, offset);
128 return false;
129
130 auto &new_offset = dest.write()[n];
132 new_offset = offset;
133 else
134 new_offset.reset();
135
136 return true;
137}
138
139void value_sett::output(std::ostream &out, const std::string &indent) const
140{
141 values.iterate([&](const irep_idt &, const entryt &e) {
142 irep_idt identifier, display_name;
143
144 if(e.identifier.starts_with("value_set::dynamic_object"))
145 {
146 display_name = id2string(e.identifier) + e.suffix;
147 identifier.clear();
148 }
149 else if(e.identifier == "value_set::return_value")
150 {
151 display_name = "RETURN_VALUE" + e.suffix;
152 identifier.clear();
153 }
154 else
155 {
156#if 0
157 const symbolt &symbol=ns.lookup(e.identifier);
158 display_name=id2string(symbol.display_name())+e.suffix;
159 identifier=symbol.name;
160#else
161 identifier = id2string(e.identifier);
162 display_name = id2string(identifier) + e.suffix;
163#endif
164 }
165
166 out << indent << display_name << " = { ";
167
168 const object_map_dt &object_map = e.object_map.read();
169
170 std::size_t width = 0;
171
172 for(object_map_dt::const_iterator o_it = object_map.begin();
173 o_it != object_map.end();
174 o_it++)
175 {
176 const exprt &o = object_numbering[o_it->first];
177
178 std::ostringstream stream;
179
180 if(o.id() == ID_invalid || o.id() == ID_unknown)
181 stream << format(o);
182 else
183 {
184 stream << "<" << format(o) << ", ";
185
186 if(o_it->second)
187 stream << *o_it->second;
188 else
189 stream << '*';
190
191 if(o.type().is_nil())
192 stream << ", ?";
193 else
194 stream << ", " << format(o.type());
195
196 stream << '>';
197 }
198
199 const std::string result = stream.str();
200 out << result;
201 width += result.size();
202
203 object_map_dt::const_iterator next(o_it);
204 next++;
205
206 if(next != object_map.end())
207 {
208 out << ", ";
209 if(width >= 40)
210 out << "\n" << std::string(indent.size(), ' ') << " ";
211 }
212 }
213
214 out << " } \n";
215 });
216}
217
219{
220 xmlt output;
221
223 this->values.get_view(view);
224
225 for(const auto &values_entry : view)
226 {
227 xmlt &var = output.new_element("variable");
228 var.new_element("identifier").data = id2string(values_entry.first);
229
230#if 0
231 const value_sett::expr_sett &expr_set=
232 value_entries.expr_set();
233
234 for(value_sett::expr_sett::const_iterator
235 e_it=expr_set.begin();
236 e_it!=expr_set.end();
237 e_it++)
238 {
239 std::string value_str=
240 from_expr(ns, identifier, *e_it);
241
242 var.new_element("value").data=
244 }
245#endif
246 }
247
248 return output;
249}
250
251exprt value_sett::to_expr(const object_map_dt::value_type &it) const
252{
253 const exprt &object=object_numbering[it.first];
254
255 if(object.id()==ID_invalid ||
256 object.id()==ID_unknown)
257 return object;
258
260
261 od.object()=object;
262
263 if(it.second)
264 od.offset() = from_integer(*it.second, c_index_type());
265
266 od.type()=od.object().type();
267
268 return std::move(od);
269}
270
272{
273 bool result=false;
274
276
277 new_values.get_delta_view(values, delta_view, false);
278
279 for(const auto &delta_entry : delta_view)
280 {
281 if(delta_entry.is_in_both_maps())
282 {
284 delta_entry.get_other_map_value().object_map,
285 delta_entry.m.object_map))
286 {
288 make_union(existing_entry.object_map, delta_entry.m.object_map);
289 });
290 result = true;
291 }
292 }
293 else
294 {
296 result = true;
297 }
298 }
299
300 return result;
301}
302
304 const object_mapt &dest,
305 const object_mapt &src) const
306{
307 for(const auto &number_and_offset : src.read())
308 {
309 if(
311 dest, number_and_offset.first, number_and_offset.second) !=
313 {
314 return true;
315 }
316 }
317
318 return false;
319}
320
321bool value_sett::make_union(object_mapt &dest, const object_mapt &src) const
322{
323 bool result=false;
324
325 for(object_map_dt::const_iterator it=src.read().begin();
326 it!=src.read().end();
327 it++)
328 {
329 if(insert(dest, *it))
330 result=true;
331 }
332
333 return result;
334}
335
337 exprt &expr,
338 const namespacet &ns) const
339{
340 bool mod=false;
341
342 if(expr.id()==ID_pointer_offset)
343 {
345 get_value_set(to_pointer_offset_expr(expr).pointer(), ns, true);
346
349
350 const object_map_dt &object_map=reference_set.read();
351 for(object_map_dt::const_iterator
352 it=object_map.begin();
353 it!=object_map.end();
354 it++)
355 if(!it->second)
356 return false;
357 else
358 {
359 const exprt &object=object_numbering[it->first];
360 auto ptr_offset = compute_pointer_offset(object, ns);
361
362 if(!ptr_offset.has_value())
363 return false;
364
365 *ptr_offset += *it->second;
366
368 return false;
369
372 mod=true;
373 }
374
375 if(mod)
376 expr.swap(new_expr);
377 }
378 else
379 {
380 Forall_operands(it, expr)
381 mod=eval_pointer_offset(*it, ns) || mod;
382 }
383
384 return mod;
385}
386
387std::vector<exprt>
389{
390 const object_mapt object_map = get_value_set(std::move(expr), ns, false);
391 return make_range(object_map.read())
392 .map([&](const object_map_dt::value_type &pair) { return to_expr(pair); });
393}
394
396 exprt expr,
397 const namespacet &ns,
398 bool is_simplified) const
399{
400 if(!is_simplified)
401 simplify(expr, ns);
402
403 object_mapt dest;
404 bool includes_nondet_pointer = false;
405 get_value_set_rec(expr, dest, includes_nondet_pointer, "", expr.type(), ns);
406
407 if(includes_nondet_pointer && expr.type().id() == ID_pointer)
408 {
409 // we'll take the union of all objects we see, with unspecified offsets
410 values.iterate([this, &dest](const irep_idt &key, const entryt &value) {
411 for(const auto &object : value.object_map.read())
412 insert(dest, object.first, offsett());
413 });
414
415 // we'll add null, in case it's not there yet
416 insert(
417 dest,
418 exprt(ID_null_object, to_pointer_type(expr.type()).base_type()),
419 offsett());
420 }
421
422 return dest;
423}
424
429 const std::string &suffix, const std::string &field)
430{
431 return
432 !suffix.empty() &&
433 suffix[0] == '.' &&
434 suffix.compare(1, field.length(), field) == 0 &&
435 (suffix.length() == field.length() + 1 ||
436 suffix[field.length() + 1] == '.' ||
437 suffix[field.length() + 1] == '[');
438}
439
441 const std::string &suffix, const std::string &field)
442{
443 INVARIANT(
445 "suffix should start with " + field);
446 return suffix.substr(field.length() + 1);
447}
448
449std::optional<irep_idt> value_sett::get_index_of_symbol(
450 irep_idt identifier,
451 const typet &type,
452 const std::string &suffix,
453 const namespacet &ns) const
454{
455 if(
456 type.id() != ID_pointer && type.id() != ID_signedbv &&
457 type.id() != ID_unsignedbv && type.id() != ID_array &&
458 type.id() != ID_struct && type.id() != ID_struct_tag &&
459 type.id() != ID_union && type.id() != ID_union_tag)
460 {
461 return {};
462 }
463
464 // look it up
465 irep_idt index = id2string(identifier) + suffix;
466 auto *entry = find_entry(index);
467 if(entry)
468 return std::move(index);
469
470 const typet &followed_type = type.id() == ID_struct_tag
472 : type.id() == ID_union_tag
473 ? ns.follow_tag(to_union_tag_type(type))
474 : type;
475
476 // try first component name as suffix if not yet found
477 if(followed_type.id() == ID_struct || followed_type.id() == ID_union)
478 {
481
482 if(!struct_union_type.components().empty())
483 {
485 struct_union_type.components().front().get_name();
486
487 index =
488 id2string(identifier) + "." + id2string(first_component_name) + suffix;
489 entry = find_entry(index);
490 if(entry)
491 return std::move(index);
492 }
493 }
494
495 // not found? try without suffix
496 entry = find_entry(identifier);
497 if(entry)
498 return std::move(identifier);
499
500 return {};
501}
502
504 const exprt &expr,
505 object_mapt &dest,
507 const std::string &suffix,
508 const typet &original_type,
509 const namespacet &ns) const
510{
511#ifdef DEBUG
512 std::cout << "GET_VALUE_SET_REC EXPR: " << format(expr) << "\n";
513 std::cout << "GET_VALUE_SET_REC SUFFIX: " << suffix << '\n';
514#endif
515
516 if(expr.id()==ID_unknown || expr.id()==ID_invalid)
517 {
519 }
520 else if(expr.id()==ID_index)
521 {
522 const typet &type = to_index_expr(expr).array().type();
523
525 type.id() == ID_array, "operand 0 of index expression must be an array");
526
528 to_index_expr(expr).array(),
529 dest,
531 "[]" + suffix,
533 ns);
534 }
535 else if(expr.id()==ID_member)
536 {
537 const exprt &compound = to_member_expr(expr).compound();
538
540 compound.type().id() == ID_struct ||
541 compound.type().id() == ID_struct_tag ||
542 compound.type().id() == ID_union ||
543 compound.type().id() == ID_union_tag,
544 "compound of member expression must be struct or union");
545
546 const std::string &component_name=
548
550 compound,
551 dest,
553 "." + component_name + suffix,
555 ns);
556 }
557 else if(expr.id()==ID_symbol)
558 {
560 to_symbol_expr(expr).get_identifier(), expr.type(), suffix, ns);
561
562 if(entry_index.has_value())
563 make_union(dest, find_entry(*entry_index)->object_map);
564 else
566 }
567 else if(expr.id() == ID_nondet_symbol)
568 {
569 if(expr.type().id() == ID_pointer)
571 else
573 }
574 else if(expr.id()==ID_if)
575 {
577 to_if_expr(expr).true_case(),
578 dest,
580 suffix,
582 ns);
584 to_if_expr(expr).false_case(),
585 dest,
587 suffix,
589 ns);
590 }
591 else if(expr.id()==ID_address_of)
592 {
593 get_reference_set(to_address_of_expr(expr).object(), dest, ns);
594 }
595 else if(expr.id()==ID_dereference)
596 {
599 const object_map_dt &object_map=reference_set.read();
600
601 if(object_map.begin()==object_map.end())
603 else
604 {
605 for(object_map_dt::const_iterator
606 it1=object_map.begin();
607 it1!=object_map.end();
608 it1++)
609 {
612 const exprt object=object_numbering[it1->first];
614 object, dest, includes_nondet_pointer, suffix, original_type, ns);
615 }
616 }
617 }
618 else if(expr.is_constant())
619 {
620 // check if NULL
622 {
623 insert(
624 dest,
625 exprt(ID_null_object, to_pointer_type(expr.type()).base_type()),
626 mp_integer{0});
627 }
628 else if(
629 expr.type().id() == ID_unsignedbv || expr.type().id() == ID_signedbv)
630 {
631 // an integer constant got turned into a pointer
633 }
634 else
636 }
637 else if(expr.id()==ID_typecast)
638 {
639 // let's see what gets converted to what
640
641 const auto &op = to_typecast_expr(expr).op();
642 const typet &op_type = op.type();
643
644 if(op_type.id()==ID_pointer)
645 {
646 // pointer-to-something -- we just ignore the type cast
648 op, dest, includes_nondet_pointer, suffix, original_type, ns);
649 }
650 else if(
651 op_type.id() == ID_unsignedbv || op_type.id() == ID_signedbv ||
652 op_type.id() == ID_bv)
653 {
654 // integer-to-something
655
656 if(op.is_zero())
657 {
659 }
660 else
661 {
662 // see if we have something for the integer
664
666 op, tmp, includes_nondet_pointer, suffix, original_type, ns);
667
668 if(tmp.read().empty())
669 {
670 // if not, throw in integer
672 }
673 else if(tmp.read().size()==1 &&
674 object_numbering[tmp.read().begin()->first].id()==ID_unknown)
675 {
676 // if not, throw in integer
678 }
679 else
680 {
681 // use as is
682 dest.write().insert(tmp.read().begin(), tmp.read().end());
683 }
684 }
685 }
686 else
688 }
689 else if(
690 expr.id() == ID_plus || expr.id() == ID_minus || expr.id() == ID_bitor ||
691 expr.id() == ID_bitand || expr.id() == ID_bitxor ||
692 expr.id() == ID_bitnand || expr.id() == ID_bitnor ||
693 expr.id() == ID_bitxnor)
694 {
695 if(expr.operands().size()<2)
696 throw expr.id_string()+" expected to have at least two operands";
697
699 std::optional<mp_integer> i;
700
701 // special case for plus/minus and exactly one pointer
702 std::optional<exprt> ptr_operand;
703 if(
704 expr.type().id() == ID_pointer &&
705 (expr.id() == ID_plus || expr.id() == ID_minus))
706 {
707 bool non_const_offset = false;
708 for(const auto &op : expr.operands())
709 {
710 if(op.type().id() == ID_pointer)
711 {
712 if(ptr_operand.has_value())
713 {
714 ptr_operand.reset();
715 break;
716 }
717
718 ptr_operand = op;
719 }
720 else if(!non_const_offset)
721 {
722 auto offset = numeric_cast<mp_integer>(op);
723 if(!offset.has_value())
724 {
725 i.reset();
726 non_const_offset = true;
727 }
728 else
729 {
730 if(!i.has_value())
731 i = mp_integer{0};
732 i = *i + *offset;
733 }
734 }
735 }
736
737 if(ptr_operand.has_value() && i.has_value())
738 {
740 to_pointer_type(ptr_operand->type()).base_type();
741 if(pointer_base_type.id() == ID_empty)
743
744 auto size = pointer_offset_size(pointer_base_type, ns);
745
746 if(!size.has_value() || (*size) == 0)
747 {
748 i.reset();
749 }
750 else
751 {
752 *i *= *size;
753
754 if(expr.id()==ID_minus)
755 {
757 to_minus_expr(expr).lhs() == *ptr_operand,
758 "unexpected subtraction of pointer from integer");
759 i->negate();
760 }
761 }
762 }
763 }
764
765 if(ptr_operand.has_value())
766 {
771 "",
772 ptr_operand->type(),
773 ns);
774 }
775 else
776 {
777 // we get the points-to for all operands, even integers
778 for(const auto &op : expr.operands())
779 {
781 op, pointer_expr_set, includes_nondet_pointer, "", op.type(), ns);
782 }
783 }
784
785 for(object_map_dt::const_iterator
786 it=pointer_expr_set.read().begin();
787 it!=pointer_expr_set.read().end();
788 it++)
789 {
790 offsett offset = it->second;
791
792 // adjust by offset
793 if(offset && i.has_value())
794 *offset += *i;
795 else
796 offset.reset();
797
798 insert(dest, it->first, offset);
799 }
800 }
801 else if(expr.id()==ID_mult)
802 {
803 // this is to do stuff like
804 // (int*)((sel*(ulong)&a)+((sel^0x1)*(ulong)&b))
805
806 if(expr.operands().size()<2)
807 throw expr.id_string()+" expected to have at least two operands";
808
810
811 // we get the points-to for all operands, even integers
812 for(const auto &op : expr.operands())
813 {
815 op, pointer_expr_set, includes_nondet_pointer, "", op.type(), ns);
816 }
817
818 for(object_map_dt::const_iterator
819 it=pointer_expr_set.read().begin();
820 it!=pointer_expr_set.read().end();
821 it++)
822 {
823 offsett offset = it->second;
824
825 // kill any offset
826 offset.reset();
827
828 insert(dest, it->first, offset);
829 }
830 }
831 else if(expr.id() == ID_lshr || expr.id() == ID_ashr || expr.id() == ID_shl)
832 {
834
837 binary_expr.op0(),
840 "",
841 binary_expr.op0().type(),
842 ns);
843
844 for(const auto &object_map_entry : pointer_expr_set.read())
845 {
846 offsett offset = object_map_entry.second;
847
848 // kill any offset
849 offset.reset();
850
851 insert(dest, object_map_entry.first, offset);
852 }
853 }
854 else if(expr.id()==ID_side_effect)
855 {
856 const irep_idt &statement = to_side_effect_expr(expr).get_statement();
857
858 if(statement==ID_function_call)
859 {
860 // these should be gone
861 throw "unexpected function_call sideeffect";
862 }
863 else if(statement==ID_allocate)
864 {
865 PRECONDITION(suffix.empty());
866
867 const typet &dynamic_type=
868 static_cast<const typet &>(expr.find(ID_C_cxx_alloc_type));
869
871 dynamic_object.set_instance(location_number);
872 dynamic_object.valid()=true_exprt();
873
875 }
876 else if(statement==ID_cpp_new ||
877 statement==ID_cpp_new_array)
878 {
879 PRECONDITION(suffix.empty());
880 PRECONDITION(expr.type().id() == ID_pointer);
881
883 to_pointer_type(expr.type()).base_type());
884 dynamic_object.set_instance(location_number);
885 dynamic_object.valid()=true_exprt();
886
888 }
889 else
891 }
892 else if(expr.id()==ID_struct)
893 {
894 const auto &struct_components =
895 expr.type().id() == ID_struct_tag
896 ? ns.follow_tag(to_struct_tag_type(expr.type())).components()
897 : to_struct_type(expr.type()).components();
898 INVARIANT(
899 struct_components.size() == expr.operands().size(),
900 "struct expression should have an operand per component");
901 auto component_iter = struct_components.begin();
902 bool found_component = false;
903
904 // a struct constructor, which may contain addresses
905
906 for(const auto &op : expr.operands())
907 {
908 const std::string &component_name =
909 id2string(component_iter->get_name());
910 if(suffix_starts_with_field(suffix, component_name))
911 {
912 std::string remaining_suffix =
913 strip_first_field_from_suffix(suffix, component_name);
915 op,
916 dest,
920 ns);
921 found_component = true;
922 }
924 }
925
926 if(!found_component)
927 {
928 // Struct field doesn't appear as expected -- this has probably been
929 // cast from an incompatible type. Conservatively assume all fields may
930 // be of interest.
931 for(const auto &op : expr.operands())
932 {
934 op, dest, includes_nondet_pointer, suffix, original_type, ns);
935 }
936 }
937 }
938 else if(expr.id() == ID_union)
939 {
941 to_union_expr(expr).op(),
942 dest,
944 suffix,
946 ns);
947 }
948 else if(expr.id()==ID_with)
949 {
950 const with_exprt &with_expr = to_with_expr(expr);
951
952 // If the suffix is empty we're looking for the whole struct:
953 // default to combining both options as below.
954 if(
955 (expr.type().id() == ID_struct_tag || expr.type().id() == ID_struct) &&
956 !suffix.empty())
957 {
958 irep_idt component_name = with_expr.where().get(ID_component_name);
959 if(suffix_starts_with_field(suffix, id2string(component_name)))
960 {
961 // Looking for the member overwritten by this WITH expression
962 std::string remaining_suffix =
963 strip_first_field_from_suffix(suffix, id2string(component_name));
965 with_expr.new_value(),
966 dest,
970 ns);
971 }
972 else if(
973 (expr.type().id() == ID_struct &&
974 to_struct_type(expr.type()).has_component(component_name)) ||
975 (expr.type().id() == ID_struct_tag &&
977 .has_component(component_name)))
978 {
979 // Looking for a non-overwritten member, look through this expression
981 with_expr.old(),
982 dest,
984 suffix,
986 ns);
987 }
988 else
989 {
990 // Member we're looking for is not defined in this struct -- this
991 // must be a reinterpret cast of some sort. Default to conservatively
992 // assuming either operand might be involved.
994 with_expr.old(),
995 dest,
997 suffix,
999 ns);
1001 with_expr.new_value(),
1002 dest,
1004 "",
1006 ns);
1007 }
1008 }
1009 else if(expr.type().id() == ID_array && !suffix.empty())
1010 {
1011 std::string new_value_suffix;
1012 if(has_prefix(suffix, "[]"))
1013 new_value_suffix = suffix.substr(2);
1014
1015 // Otherwise use a blank suffix on the assumption anything involved with
1016 // the new value might be interesting.
1017
1019 with_expr.old(),
1020 dest,
1022 suffix,
1024 ns);
1026 with_expr.new_value(),
1027 dest,
1031 ns);
1032 }
1033 else
1034 {
1035 // Something else-- the suffixes used here are a rough guess at best,
1036 // so this is imprecise.
1038 with_expr.old(),
1039 dest,
1041 suffix,
1043 ns);
1045 with_expr.new_value(),
1046 dest,
1048 "",
1050 ns);
1051 }
1052 }
1053 else if(expr.id()==ID_array)
1054 {
1055 // an array constructor, possibly containing addresses
1056 std::string new_suffix = suffix;
1057 if(has_prefix(suffix, "[]"))
1058 new_suffix = suffix.substr(2);
1059 // Otherwise we're probably reinterpreting some other type -- try persisting
1060 // with the current suffix for want of a better idea.
1061
1062 for(const auto &op : expr.operands())
1063 {
1066 }
1067 }
1068 else if(expr.id()==ID_array_of)
1069 {
1070 // an array constructor, possibly containing an address
1071 std::string new_suffix = suffix;
1072 if(has_prefix(suffix, "[]"))
1073 new_suffix = suffix.substr(2);
1074 // Otherwise we're probably reinterpreting some other type -- try persisting
1075 // with the current suffix for want of a better idea.
1076
1078 to_array_of_expr(expr).what(),
1079 dest,
1081 new_suffix,
1083 ns);
1084 }
1085 else if(expr.id()==ID_dynamic_object)
1086 {
1089
1090 const std::string prefix=
1091 "value_set::dynamic_object"+
1092 std::to_string(dynamic_object.get_instance());
1093
1094 // first try with suffix
1095 const std::string full_name=prefix+suffix;
1096
1097 // look it up
1098 const entryt *entry = find_entry(full_name);
1099
1100 // not found? try without suffix
1101 if(!entry)
1102 entry = find_entry(prefix);
1103
1104 if(!entry)
1106 else
1107 make_union(dest, entry->object_map);
1108 }
1109 else if(expr.id()==ID_byte_extract_little_endian ||
1111 {
1112 const auto &byte_extract_expr = to_byte_extract_expr(expr);
1113
1114 bool found=false;
1115
1116 if(
1117 byte_extract_expr.op().type().id() == ID_struct ||
1118 byte_extract_expr.op().type().id() == ID_struct_tag)
1119 {
1120 exprt offset = byte_extract_expr.offset();
1121 if(eval_pointer_offset(offset, ns))
1122 simplify(offset, ns);
1123
1124 const auto offset_int = numeric_cast<mp_integer>(offset);
1125 const auto type_size = pointer_offset_size(expr.type(), ns);
1126
1127 const struct_typet &struct_type =
1128 byte_extract_expr.op().type().id() == ID_struct_tag
1130 : to_struct_type(byte_extract_expr.op().type());
1131
1132 for(const auto &c : struct_type.components())
1133 {
1134 const irep_idt &name = c.get_name();
1135
1136 if(offset_int.has_value())
1137 {
1138 auto comp_offset = member_offset(struct_type, name, ns);
1139 if(comp_offset.has_value())
1140 {
1141 if(
1142 type_size.has_value() && *offset_int + *type_size <= *comp_offset)
1143 {
1144 break;
1145 }
1146
1147 auto member_size = pointer_offset_size(c.type(), ns);
1148 if(
1149 member_size.has_value() &&
1151 {
1152 continue;
1153 }
1154 }
1155 }
1156
1157 found=true;
1158
1159 member_exprt member(byte_extract_expr.op(), c);
1161 member, dest, includes_nondet_pointer, suffix, original_type, ns);
1162 }
1163 }
1164
1165 if(
1166 byte_extract_expr.op().type().id() == ID_union ||
1167 byte_extract_expr.op().type().id() == ID_union_tag)
1168 {
1169 // just collect them all
1170 const auto &components =
1171 byte_extract_expr.op().type().id() == ID_union_tag
1173 .components()
1174 : to_union_type(byte_extract_expr.op().type()).components();
1175 for(const auto &c : components)
1176 {
1177 const irep_idt &name = c.get_name();
1178 member_exprt member(byte_extract_expr.op(), name, c.type());
1180 member, dest, includes_nondet_pointer, suffix, original_type, ns);
1181 }
1182 }
1183
1184 if(!found)
1185 // we just pass through
1187 byte_extract_expr.op(),
1188 dest,
1190 suffix,
1192 ns);
1193 }
1194 else if(expr.id()==ID_byte_update_little_endian ||
1196 {
1197 const auto &byte_update_expr = to_byte_update_expr(expr);
1198
1199 // we just pass through
1201 byte_update_expr.op(),
1202 dest,
1204 suffix,
1206 ns);
1208 byte_update_expr.value(),
1209 dest,
1211 suffix,
1213 ns);
1214
1215 // we could have checked object size to be more precise
1216 }
1217 else if(expr.id() == ID_let)
1218 {
1219 const auto &let_expr = to_let_expr(expr);
1220 // This depends on copying `value_sett` being cheap -- which it is, because
1221 // our backing store is sharing_mapt.
1224 let_expr.symbol(), let_expr.value(), ns, false, false);
1225
1226 value_set_with_local_definition.get_value_set_rec(
1227 let_expr.where(),
1228 dest,
1230 suffix,
1232 ns);
1233 }
1234 else if(auto eb = expr_try_dynamic_cast<extractbits_exprt>(expr))
1235 {
1238 eb->src(),
1241 "",
1242 eb->src().type(),
1243 ns);
1244
1245 for(const auto &object_map_entry : pointer_expr_set.read())
1246 {
1247 offsett offset = object_map_entry.second;
1248
1249 // kill any offset
1250 offset.reset();
1251
1252 insert(dest, object_map_entry.first, offset);
1253 }
1254 }
1255 else
1256 {
1258 for(const auto &op : expr.operands())
1259 {
1262 }
1263
1264 for(const auto &object_map_entry : pointer_expr_set.read())
1265 {
1266 offsett offset = object_map_entry.second;
1267
1268 // kill any offset
1269 offset.reset();
1270
1271 insert(dest, object_map_entry.first, offset);
1272 }
1273
1274 if(pointer_expr_set.read().empty())
1276 }
1277
1278 #ifdef DEBUG
1279 std::cout << "GET_VALUE_SET_REC RESULT:\n";
1280 for(const auto &obj : dest.read())
1281 {
1282 const exprt &e=to_expr(obj);
1283 std::cout << " " << format(e) << "\n";
1284 }
1285 std::cout << "\n";
1286 #endif
1287}
1288
1290 const exprt &src,
1291 exprt &dest) const
1292{
1293 // remove pointer typecasts
1294 if(src.id()==ID_typecast)
1295 {
1296 PRECONDITION(src.type().id() == ID_pointer);
1297
1298 dereference_rec(to_typecast_expr(src).op(), dest);
1299 }
1300 else
1301 dest=src;
1302}
1303
1305 const exprt &expr,
1307 const namespacet &ns) const
1308{
1309 object_mapt object_map;
1310 get_reference_set(expr, object_map, ns);
1311
1312 for(object_map_dt::const_iterator
1313 it=object_map.read().begin();
1314 it!=object_map.read().end();
1315 it++)
1316 dest.push_back(to_expr(*it));
1317}
1318
1320 const exprt &expr,
1321 object_mapt &dest,
1322 const namespacet &ns) const
1323{
1324#ifdef DEBUG
1325 std::cout << "GET_REFERENCE_SET_REC EXPR: " << format(expr)
1326 << '\n';
1327#endif
1328
1329 if(expr.id()==ID_symbol ||
1330 expr.id()==ID_dynamic_object ||
1331 expr.id()==ID_string_constant ||
1332 expr.id()==ID_array)
1333 {
1334 if(
1335 expr.type().id() == ID_array &&
1336 to_array_type(expr.type()).element_type().id() == ID_array)
1337 insert(dest, expr);
1338 else
1339 insert(dest, expr, mp_integer{0});
1340
1341 return;
1342 }
1343 else if(expr.id()==ID_dereference)
1344 {
1345 const auto &pointer = to_dereference_expr(expr).pointer();
1346
1347 bool includes_nondet_pointer = false;
1349 pointer, dest, includes_nondet_pointer, "", pointer.type(), ns);
1350
1351#ifdef DEBUG
1352 for(const auto &map_entry : dest.read())
1353 {
1354 std::cout << "VALUE_SET: " << format(object_numbering[map_entry.first])
1355 << '\n';
1356 }
1357#endif
1358
1359 return;
1360 }
1361 else if(expr.id()==ID_index)
1362 {
1363 if(expr.operands().size()!=2)
1364 throw "index expected to have two operands";
1365
1367 const exprt &array=index_expr.array();
1368 const exprt &offset=index_expr.index();
1369
1371 array.type().id() == ID_array, "index takes array-typed operand");
1372
1373 const auto &array_type = to_array_type(array.type());
1374
1377
1378 const object_map_dt &object_map=array_references.read();
1379
1380 for(object_map_dt::const_iterator
1381 a_it=object_map.begin();
1382 a_it!=object_map.end();
1383 a_it++)
1384 {
1385 const exprt &object=object_numbering[a_it->first];
1386
1387 if(object.id()==ID_unknown)
1388 insert(dest, exprt(ID_unknown, expr.type()));
1389 else
1390 {
1394
1395 offsett o = a_it->second;
1396 const auto i = numeric_cast<mp_integer>(offset);
1397
1398 if(offset.is_zero())
1399 {
1400 }
1401 else if(i.has_value() && o)
1402 {
1403 auto size = pointer_offset_size(array_type.element_type(), ns);
1404
1405 if(!size.has_value() || *size == 0)
1406 o.reset();
1407 else
1408 *o = *i * (*size);
1409 }
1410 else
1411 o.reset();
1412
1413 insert(dest, deref_index_expr, o);
1414 }
1415 }
1416
1417 return;
1418 }
1419 else if(expr.id()==ID_member)
1420 {
1421 const irep_idt &component_name=expr.get(ID_component_name);
1422
1423 const exprt &struct_op = to_member_expr(expr).compound();
1424
1426 get_reference_set(struct_op, struct_references, ns);
1427
1428 const object_map_dt &object_map=struct_references.read();
1429
1430 for(object_map_dt::const_iterator
1431 it=object_map.begin();
1432 it!=object_map.end();
1433 it++)
1434 {
1435 const exprt &object=object_numbering[it->first];
1436
1437 if(object.id()==ID_unknown)
1438 insert(dest, exprt(ID_unknown, expr.type()));
1439 else if(
1440 object.type().id() == ID_struct ||
1441 object.type().id() == ID_struct_tag || object.type().id() == ID_union ||
1442 object.type().id() == ID_union_tag)
1443 {
1444 offsett o = it->second;
1445
1446 member_exprt member_expr(object, component_name, expr.type());
1447
1448 // We cannot introduce a cast from scalar to non-scalar,
1449 // thus, we can only adjust the types of structs and unions.
1450
1451 if(
1452 object.type().id() == ID_struct ||
1453 object.type().id() == ID_struct_tag ||
1454 object.type().id() == ID_union || object.type().id() == ID_union_tag)
1455 {
1456 // adjust type?
1457 if(struct_op.type() != object.type())
1458 {
1459 member_expr.compound() =
1460 typecast_exprt(member_expr.compound(), struct_op.type());
1461 }
1462
1463 insert(dest, member_expr, o);
1464 }
1465 else
1466 insert(dest, exprt(ID_unknown, expr.type()));
1467 }
1468 else
1469 insert(dest, exprt(ID_unknown, expr.type()));
1470 }
1471
1472 return;
1473 }
1474 else if(expr.id()==ID_if)
1475 {
1476 get_reference_set_rec(to_if_expr(expr).true_case(), dest, ns);
1477 get_reference_set_rec(to_if_expr(expr).false_case(), dest, ns);
1478 return;
1479 }
1480
1481 insert(dest, exprt(ID_unknown, expr.type()));
1482}
1483
1485 const exprt &lhs,
1486 const exprt &rhs,
1487 const namespacet &ns,
1488 bool is_simplified,
1489 bool add_to_sets)
1490{
1491#ifdef DEBUG
1492 std::cout << "ASSIGN LHS: " << format(lhs) << " : "
1493 << format(lhs.type()) << '\n';
1494 std::cout << "ASSIGN RHS: " << format(rhs) << " : "
1495 << format(rhs.type()) << '\n';
1496 std::cout << "--------------------------------------------\n";
1497 output(std::cout);
1498#endif
1499
1500 if(lhs.type().id() == ID_struct || lhs.type().id() == ID_struct_tag)
1501 {
1502 const auto &components =
1503 lhs.type().id() == ID_struct_tag
1504 ? ns.follow_tag(to_struct_tag_type(lhs.type())).components()
1505 : to_struct_type(lhs.type()).components();
1506
1507 for(const auto &c : components)
1508 {
1509 const typet &subtype = c.type();
1510 const irep_idt &name = c.get_name();
1511
1512 // ignore padding
1514 subtype.id() != ID_code, "struct member must not be of code type");
1515 if(c.get_is_padding())
1516 continue;
1517
1518 member_exprt lhs_member(lhs, name, subtype);
1519
1521
1522 if(rhs.id()==ID_unknown ||
1523 rhs.id()==ID_invalid)
1524 {
1525 // this branch is deemed dead as otherwise we'd be missing assignments
1526 // that never happened in this branch
1528 rhs_member=exprt(rhs.id(), subtype);
1529 }
1530 else
1531 {
1533 rhs.type() == lhs.type(),
1534 "value_sett::assign types should match, got: "
1535 "rhs.type():\n" +
1536 rhs.type().pretty() + "\n" + "lhs.type():\n" + lhs.type().pretty());
1537
1538 if(rhs.type().id() == ID_struct_tag || rhs.type().id() == ID_union_tag)
1539 {
1542
1543 const typet &rhs_subtype = rhs_struct_union_type.component_type(name);
1545
1547 }
1548 else if(rhs.type().id() == ID_struct || rhs.type().id() == ID_union)
1549 {
1552
1553 const typet &rhs_subtype = rhs_struct_union_type.component_type(name);
1555
1557 }
1558 }
1559 }
1560 }
1561 else if(lhs.type().id() == ID_array)
1562 {
1563 const index_exprt lhs_index(
1564 lhs,
1566 to_array_type(lhs.type()).element_type());
1567
1568 if(rhs.id()==ID_unknown ||
1569 rhs.id()==ID_invalid)
1570 {
1571 assign(
1572 lhs_index,
1573 exprt(rhs.id(), to_array_type(lhs.type()).element_type()),
1574 ns,
1576 add_to_sets);
1577 }
1578 else
1579 {
1581 rhs.type() == lhs.type(),
1582 "value_sett::assign types should match, got: "
1583 "rhs.type():\n" +
1584 rhs.type().pretty() + "\n" + "type:\n" + lhs.type().pretty());
1585
1586 if(rhs.id()==ID_array_of)
1587 {
1588 assign(
1589 lhs_index,
1590 to_array_of_expr(rhs).what(),
1591 ns,
1593 add_to_sets);
1594 }
1595 else if(rhs.id() == ID_array || rhs.is_constant())
1596 {
1597 for(const auto &op : rhs.operands())
1598 {
1600 add_to_sets=true;
1601 }
1602 }
1603 else if(rhs.id()==ID_with)
1604 {
1605 const index_exprt op0_index(
1606 to_with_expr(rhs).old(),
1608 to_array_type(lhs.type()).element_type());
1609
1611 assign(
1612 lhs_index, to_with_expr(rhs).new_value(), ns, is_simplified, true);
1613 }
1614 else
1615 {
1616 const index_exprt rhs_index(
1617 rhs,
1619 to_array_type(lhs.type()).element_type());
1621 }
1622 }
1623 }
1624 else
1625 {
1626 // basic type or union
1628
1629 // Permit custom subclass to alter the read values prior to write:
1631
1632 // Permit custom subclass to perform global side-effects prior to write:
1633 apply_assign_side_effects(lhs, rhs, ns);
1634
1635 assign_rec(lhs, values_rhs, "", ns, add_to_sets);
1636 }
1637}
1638
1640 const exprt &lhs,
1641 const object_mapt &values_rhs,
1642 const std::string &suffix,
1643 const namespacet &ns,
1644 bool add_to_sets)
1645{
1646#ifdef DEBUG
1647 std::cout << "ASSIGN_REC LHS: " << format(lhs) << '\n';
1648 std::cout << "ASSIGN_REC LHS ID: " << lhs.id() << '\n';
1649 std::cout << "ASSIGN_REC SUFFIX: " << suffix << '\n';
1650
1651 for(object_map_dt::const_iterator it=values_rhs.read().begin();
1652 it!=values_rhs.read().end();
1653 it++)
1654 std::cout << "ASSIGN_REC RHS: " <<
1655 format(object_numbering[it->first]) << '\n';
1656 std::cout << '\n';
1657#endif
1658
1659 if(lhs.id()==ID_symbol)
1660 {
1661 const irep_idt &identifier=to_symbol_expr(lhs).get_identifier();
1662
1664 entryt{identifier, suffix}, lhs.type(), values_rhs, add_to_sets);
1665 }
1666 else if(lhs.id()==ID_dynamic_object)
1667 {
1670
1671 const std::string name=
1672 "value_set::dynamic_object"+
1673 std::to_string(dynamic_object.get_instance());
1674
1675 update_entry(entryt{name, suffix}, lhs.type(), values_rhs, true);
1676 }
1677 else if(lhs.id()==ID_dereference)
1678 {
1679 if(lhs.operands().size()!=1)
1680 throw lhs.id_string()+" expected to have one operand";
1681
1684
1685 if(reference_set.read().size()!=1)
1686 add_to_sets=true;
1687
1688 for(object_map_dt::const_iterator
1689 it=reference_set.read().begin();
1690 it!=reference_set.read().end();
1691 it++)
1692 {
1695 const exprt object=object_numbering[it->first];
1696
1697 if(object.id()!=ID_unknown)
1698 assign_rec(object, values_rhs, suffix, ns, add_to_sets);
1699 }
1700 }
1701 else if(lhs.id()==ID_index)
1702 {
1703 const auto &array = to_index_expr(lhs).array();
1704
1705 const typet &type = array.type();
1706
1708 type.id() == ID_array, "operand 0 of index expression must be an array");
1709
1710 assign_rec(array, values_rhs, "[]" + suffix, ns, true);
1711 }
1712 else if(lhs.id()==ID_member)
1713 {
1714 const auto &lhs_member_expr = to_member_expr(lhs);
1715 const auto &component_name = lhs_member_expr.get_component_name();
1716 const exprt &compound = lhs_member_expr.compound();
1717
1719 compound.type().id() == ID_struct ||
1720 compound.type().id() == ID_struct_tag ||
1721 compound.type().id() == ID_union ||
1722 compound.type().id() == ID_union_tag,
1723 "operand 0 of member expression must be struct or union");
1724
1725 assign_rec(
1726 compound,
1727 values_rhs,
1728 "." + id2string(component_name) + suffix,
1729 ns,
1730 add_to_sets);
1731 }
1732 else if(lhs.id()=="valid_object" ||
1733 lhs.id()=="dynamic_type" ||
1734 lhs.id()=="is_zero_string" ||
1735 lhs.id()=="zero_string" ||
1736 lhs.id()=="zero_string_length")
1737 {
1738 // we ignore this here
1739 }
1740 else if(lhs.id()==ID_string_constant)
1741 {
1742 // someone writes into a string-constant
1743 // evil guy
1744 }
1745 else if(lhs.id() == ID_null_object)
1746 {
1747 // evil as well
1748 }
1749 else if(lhs.id()==ID_typecast)
1750 {
1752
1753 assign_rec(typecast_expr.op(), values_rhs, suffix, ns, add_to_sets);
1754 }
1755 else if(lhs.id()==ID_byte_extract_little_endian ||
1757 {
1758 assign_rec(to_byte_extract_expr(lhs).op(), values_rhs, suffix, ns, true);
1759 }
1760 else if(lhs.id()==ID_integer_address)
1761 {
1762 // that's like assigning into __CPROVER_memory[...],
1763 // which we don't track
1764 }
1765 else
1766 throw "assign NYI: '" + lhs.id_string() + "'";
1767}
1768
1770 const irep_idt &function,
1771 const exprt::operandst &arguments,
1772 const namespacet &ns)
1773{
1774 const symbolt &symbol=ns.lookup(function);
1775
1776 const code_typet &type=to_code_type(symbol.type);
1778
1779 // these first need to be assigned to dummy, temporary arguments
1780 // and only thereafter to the actuals, in order
1781 // to avoid overwriting actuals that are needed for recursive
1782 // calls
1783
1784 for(std::size_t i=0; i<arguments.size(); i++)
1785 {
1786 const std::string identifier="value_set::dummy_arg_"+std::to_string(i);
1787 const symbol_exprt dummy_lhs(identifier, arguments[i].type());
1788 assign(dummy_lhs, arguments[i], ns, false, false);
1789 }
1790
1791 // now assign to 'actual actuals'
1792
1793 unsigned i=0;
1794
1795 for(code_typet::parameterst::const_iterator
1796 it=parameter_types.begin();
1797 it!=parameter_types.end();
1798 it++)
1799 {
1800 const irep_idt &identifier=it->get_identifier();
1801 if(identifier.empty())
1802 continue;
1803
1804 const exprt v_expr=
1805 symbol_exprt("value_set::dummy_arg_"+std::to_string(i), it->type());
1806
1807 const symbol_exprt actual_lhs(identifier, it->type());
1808 assign(actual_lhs, v_expr, ns, true, true);
1809 i++;
1810 }
1811
1812 // we could delete the dummy_arg_* now.
1813}
1814
1816 const exprt &lhs,
1817 const namespacet &ns)
1818{
1819 if(lhs.is_nil())
1820 return;
1821
1822 symbol_exprt rhs("value_set::return_value", lhs.type());
1823
1824 assign(lhs, rhs, ns, false, false);
1825}
1826
1828 const codet &code,
1829 const namespacet &ns)
1830{
1831 const irep_idt &statement=code.get_statement();
1832
1833 if(statement==ID_block)
1834 {
1835 for(const auto &op : code.operands())
1836 apply_code_rec(to_code(op), ns);
1837 }
1838 else if(statement==ID_function_call)
1839 {
1840 // shouldn't be here
1842 }
1843 else if(statement==ID_assign)
1844 {
1845 if(code.operands().size()!=2)
1846 throw "assignment expected to have two operands";
1847
1848 assign(code.op0(), code.op1(), ns, false, false);
1849 }
1850 else if(statement==ID_decl)
1851 {
1852 if(code.operands().size()!=1)
1853 throw "decl expected to have one operand";
1854
1855 const exprt &lhs=code.op0();
1856
1857 if(lhs.id()!=ID_symbol)
1858 throw "decl expected to have symbol on lhs";
1859
1860 const typet &lhs_type = lhs.type();
1861
1862 if(
1863 lhs_type.id() == ID_pointer ||
1864 (lhs_type.id() == ID_array &&
1865 to_array_type(lhs_type).element_type().id() == ID_pointer))
1866 {
1867 // assign the address of the failed object
1868 if(auto failed = get_failed_symbol(to_symbol_expr(lhs), ns))
1869 {
1871 assign(lhs, address_of_expr, ns, false, false);
1872 }
1873 else
1874 assign(lhs, exprt(ID_invalid), ns, false, false);
1875 }
1876 }
1877 else if(statement==ID_expression)
1878 {
1879 // can be ignored, we don't expect side effects here
1880 }
1881 else if(statement == ID_cpp_delete || statement == ID_cpp_delete_array)
1882 {
1883 // does nothing
1884 }
1885 else if(statement=="lock" || statement=="unlock")
1886 {
1887 // ignore for now
1888 }
1889 else if(statement==ID_asm)
1890 {
1891 // ignore for now, probably not safe
1892 }
1893 else if(statement==ID_nondet)
1894 {
1895 // doesn't do anything
1896 }
1897 else if(statement==ID_printf)
1898 {
1899 // doesn't do anything
1900 }
1901 else if(statement==ID_return)
1902 {
1904 // this is turned into an assignment
1905 symbol_exprt lhs(
1906 "value_set::return_value", code_return.return_value().type());
1907 assign(lhs, code_return.return_value(), ns, false, false);
1908 }
1909 else if(statement==ID_array_set)
1910 {
1911 }
1912 else if(statement==ID_array_copy)
1913 {
1914 }
1915 else if(statement==ID_array_replace)
1916 {
1917 }
1918 else if(statement == ID_array_equal)
1919 {
1920 }
1921 else if(statement==ID_assume)
1922 {
1923 guard(to_code_assume(code).assumption(), ns);
1924 }
1925 else if(statement==ID_user_specified_predicate ||
1928 {
1929 // doesn't do anything
1930 }
1931 else if(statement==ID_fence)
1932 {
1933 }
1935 {
1936 // doesn't do anything
1937 }
1938 else if(statement==ID_dead)
1939 {
1940 // Ignore by default; could prune the value set.
1941 }
1942 else if(statement == ID_havoc_object)
1943 {
1944 }
1945 else
1946 {
1947 // std::cerr << code.pretty() << '\n';
1948 throw "value_sett: unexpected statement: "+id2string(statement);
1949 }
1950}
1951
1953 const exprt &expr,
1954 const namespacet &ns)
1955{
1956 if(expr.id()==ID_and)
1957 {
1958 for(const auto &op : expr.operands())
1959 guard(op, ns);
1960 }
1961 else if(expr.id()==ID_equal)
1962 {
1963 }
1964 else if(expr.id()==ID_notequal)
1965 {
1966 }
1967 else if(expr.id()==ID_not)
1968 {
1969 }
1970 else if(expr.id()==ID_dynamic_object)
1971 {
1973 // dynamic_object.instance()=
1974 // from_integer(location_number, typet(ID_natural));
1975 dynamic_object.valid()=true_exprt();
1976
1978 address_of.type() = to_dynamic_object_expr(expr).op0().type();
1979
1980 assign(to_dynamic_object_expr(expr).op0(), address_of, ns, false, false);
1981 }
1982}
1983
1985 const irep_idt &index,
1986 const std::unordered_set<exprt, irep_hash> &values_to_erase)
1987{
1988 if(values_to_erase.empty())
1989 return;
1990
1991 auto entry = find_entry(index);
1992 if(!entry)
1993 return;
1994
1995 std::vector<object_map_dt::key_type> keys_to_erase;
1996
1997 for(auto &key_value : entry->object_map.read())
1998 {
1999 const auto &rhs_object = to_expr(key_value);
2000 if(values_to_erase.count(rhs_object))
2001 {
2002 keys_to_erase.emplace_back(key_value.first);
2003 }
2004 }
2005
2007 keys_to_erase.size() == values_to_erase.size(),
2008 "value_sett::erase_value_from_entry() should erase exactly one value for "
2009 "each element in the set it is given");
2010
2011 entryt replacement = *entry;
2012 for(const auto &key_to_erase : keys_to_erase)
2013 {
2014 replacement.object_map.write().erase(key_to_erase);
2015 }
2016 values.replace(index, std::move(replacement));
2017}
2018
2021 const std::string &erase_prefix,
2022 const namespacet &ns)
2023{
2024 for(const auto &c : struct_union_type.components())
2025 {
2026 const typet &subtype = c.type();
2027 const irep_idt &name = c.get_name();
2028
2029 // ignore padding
2031 subtype.id() != ID_code, "struct/union member must not be of code type");
2032 if(c.get_is_padding())
2033 continue;
2034
2035 erase_symbol_rec(subtype, erase_prefix + "." + id2string(name), ns);
2036 }
2037}
2038
2040 const typet &type,
2041 const std::string &erase_prefix,
2042 const namespacet &ns)
2043{
2044 if(type.id() == ID_struct_tag)
2047 else if(type.id() == ID_union_tag)
2050 else if(type.id() == ID_array)
2052 to_array_type(type).element_type(), erase_prefix + "[]", ns);
2053 else if(values.has_key(erase_prefix))
2055}
2056
2058 const symbol_exprt &symbol_expr,
2059 const namespacet &ns)
2060{
2062 symbol_expr.type(), id2string(symbol_expr.get_identifier()), ns);
2063}
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.
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
API to expression classes for bitvectors.
Expression classes for byte-level operators.
const byte_update_exprt & to_byte_update_expr(const exprt &expr)
const byte_extract_exprt & to_byte_extract_expr(const exprt &expr)
unsignedbv_typet unsigned_char_type()
Definition c_types.cpp:127
bitvector_typet char_type()
Definition c_types.cpp:106
bitvector_typet c_index_type()
Definition c_types.cpp:16
const union_typet & to_union_type(const typet &type)
Cast a typet to a union_typet.
Definition c_types.h:184
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
A base class for binary expressions.
Definition std_expr.h:638
goto_instruction_codet representation of a "return from a function" statement.
Base type of functions.
Definition std_types.h:583
std::vector< parametert > parameterst
Definition std_types.h:586
const parameterst & parameters() const
Definition std_types.h:699
Data structure for representing an arbitrary statement in a program.
exprt & op0()
Definition expr.h:133
exprt & op1()
Definition expr.h:136
const irep_idt & get_statement() const
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
bool starts_with(const char *s) const
equivalent of as_string().starts_with(s)
Definition dstring.h:95
bool empty() const
Definition dstring.h:89
Representation of heap-allocated objects.
The empty type.
Definition std_types.h:51
Base class for all expressions.
Definition expr.h:56
std::vector< exprt > operandst
Definition expr.h:58
bool is_zero() const
Return whether the expression is a constant representing 0.
Definition expr.cpp:47
bool is_constant() const
Return whether the expression is a constant.
Definition expr.h:212
typet & type()
Return the type of the expression.
Definition expr.h:84
operandst & operands()
Definition expr.h:94
Array index operator.
Definition std_expr.h:1470
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
Definition irep.cpp:482
const irept & find(const irep_idt &name) const
Definition irep.cpp:93
const irep_idt & get(const irep_idt &name) const
Definition irep.cpp:44
const std::string & id_string() const
Definition irep.h:391
void swap(irept &irep)
Definition irep.h:434
const irep_idt & id() const
Definition irep.h:388
bool is_nil() const
Definition irep.h:368
const std::string & get_string(const irep_idt &name) const
Definition irep.h:401
Extract member of struct or union.
Definition std_expr.h:2971
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().
Split an expression into a base object and a (byte) offset.
const T & read() const
std::vector< view_itemt > viewt
View of the key-value pairs in the map.
void insert(const key_type &k, valueU &&m)
Insert element, element must not exist in map.
void iterate(std::function< void(const key_type &k, const mapped_type &m)> f) const
Call a function for every key-value pair in the map.
void erase(const key_type &k)
Erase element, element must exist in map.
bool has_key(const key_type &k) const
Check if key is in map.
void replace(const key_type &k, valueU &&m)
Replace element, element must exist in map.
std::vector< delta_view_itemt > delta_viewt
Delta view of the key-value pairs in two maps.
std::optional< std::reference_wrapper< const mapped_type > > find(const key_type &k) const
Find element.
void get_view(V &view) const
Get a view of the elements in the map A view is a list of pairs with the components being const refer...
void update(const key_type &k, std::function< void(mapped_type &)> mutator)
Update an element in place; element must exist in map.
const irep_idt & get_statement() const
Definition std_code.h:1472
Structure type, corresponds to C style structs.
Definition std_types.h:231
Base type for structs and unions.
Definition std_types.h:62
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
The Boolean constant true.
Definition std_expr.h:3190
Semantic type conversion.
Definition std_expr.h:2073
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition std_expr.h:2081
The type of an expression, extends irept.
Definition type.h:29
std::list< exprt > valuest
Definition value_sets.h:28
State type in value_set_domaint, used in value-set analysis and goto-symex.
Definition value_set.h:44
virtual void apply_code_rec(const codet &code, const namespacet &ns)
Subclass customisation point for applying code to this domain:
bool eval_pointer_offset(exprt &expr, const namespacet &ns) const
Tries to resolve any pointer_offset_exprt expressions in expr to constant integers using this value-s...
const entryt * find_entry(const irep_idt &id) const
Finds an entry in this value-set.
Definition value_set.cpp:56
std::vector< exprt > get_value_set(exprt expr, const namespacet &ns) const
Gets values pointed to by expr, including following dereference operators (i.e.
virtual void get_value_set_rec(const exprt &expr, object_mapt &dest, bool &includes_nondet_pointer, const std::string &suffix, const typet &original_type, const namespacet &ns) const
Subclass customisation point for recursion over RHS expression.
xmlt output_xml(void) const
Output the value set formatted as XML.
void output(std::ostream &out, const std::string &indent="") const
Pretty-print this value-set.
void dereference_rec(const exprt &src, exprt &dest) const
Sets dest to src with any wrapping typecasts removed.
void erase_symbol(const symbol_exprt &symbol_expr, const namespacet &ns)
valuest values
Stores the LHS ID -> RHS expression set map.
Definition value_set.h:296
unsigned location_number
Matches the location_number field of the instruction that corresponds to this value_sett instance in ...
Definition value_set.h:73
static object_numberingt object_numbering
Global shared object numbering, used to abbreviate expressions stored in value sets.
Definition value_set.h:77
bool insert(object_mapt &dest, const object_map_dt::value_type &it) const
Merges an existing element into an object map.
Definition value_set.h:128
void erase_struct_union_symbol(const struct_union_typet &struct_union_type, const std::string &erase_prefix, const namespacet &ns)
std::optional< mp_integer > offsett
Represents the offset into an object: either a unique integer offset, or an unknown value,...
Definition value_set.h:81
void get_reference_set_rec(const exprt &expr, object_mapt &dest, const namespacet &ns) const
See get_reference_set.
exprt to_expr(const object_map_dt::value_type &it) const
Converts an object_map_dt element object_number -> offset into an object_descriptor_exprt with ....
void erase_values_from_entry(const irep_idt &index, const std::unordered_set< exprt, irep_hash > &values_to_erase)
Update the entry stored at index by erasing any values listed in values_to_erase.
void update_entry(const entryt &e, const typet &type, const object_mapt &new_values, bool add_to_sets)
Adds or replaces an entry in this value-set.
Definition value_set.cpp:62
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.
virtual void assign_rec(const exprt &lhs, const object_mapt &values_rhs, const std::string &suffix, const namespacet &ns, bool add_to_sets)
Subclass customisation point for recursion over LHS expression:
insert_actiont get_insert_action(const object_mapt &dest, object_numberingt::number_type n, const offsett &offset) const
Determines what would happen if object number n was inserted into map dest with offset offset – the p...
bool make_union(object_mapt &dest, const object_mapt &src) const
Merges two RHS expression sets.
virtual bool field_sensitive(const irep_idt &id, const typet &type)
Determines whether an identifier of a given type should have its fields distinguished.
Definition value_set.cpp:44
void guard(const exprt &expr, const namespacet &ns)
Transforms this value-set by assuming an expression holds.
bool make_union_would_change(const object_mapt &dest, const object_mapt &src) const
Determines whether merging two RHS expression sets would cause any change.
void do_end_function(const exprt &lhs, const namespacet &ns)
Transforms this value-set by assigning this function's return value to a given LHS expression.
static const object_map_dt empty_object_map
Definition value_set.h:41
void do_function_call(const irep_idt &function, const exprt::operandst &arguments, const namespacet &ns)
Transforms this value-set by executing the actual -> formal parameter assignments for a particular ca...
void get_reference_set(const exprt &expr, value_setst::valuest &dest, const namespacet &ns) const
Gets the set of expressions that expr may refer to, according to this value set.
virtual void apply_assign_side_effects(const exprt &lhs, const exprt &rhs, const namespacet &)
Subclass customisation point to apply global side-effects to this domain, after RHS values are read b...
Definition value_set.h:528
std::map< object_numberingt::number_type, offsett > object_map_dt
Represents a set of expressions (exprt instances) with corresponding offsets (offsett instances).
Definition value_set.h:88
virtual void adjust_assign_rhs_values(const exprt &rhs, const namespacet &, object_mapt &rhs_values) const
Subclass customisation point to filter or otherwise alter the value-set returned from get_value_set b...
Definition value_set.h:514
std::optional< irep_idt > get_index_of_symbol(irep_idt identifier, const typet &type, const std::string &suffix, const namespacet &ns) const
Get the index of the symbol and suffix.
void erase_symbol_rec(const typet &type, const std::string &erase_prefix, const namespacet &ns)
Operator to update elements in structs and arrays.
Definition std_expr.h:2598
Definition xml.h:21
xmlt & new_element(const std::string &key)
Definition xml.h:95
std::string data
Definition xml.h:39
static void escape(const std::string &s, std::ostream &out)
escaping for XML elements
Definition xml.cpp:79
bool has_prefix(const std::string &s, const std::string &prefix)
Definition converter.cpp:13
#define Forall_operands(it, expr)
Definition expr.h:27
bool is_null_pointer(const constant_exprt &expr)
Returns true if expr has a pointer type and a value NULL; it also returns true when expr has value ze...
static format_containert< T > format(const T &o)
Definition format.h:37
const code_returnt & to_code_return(const goto_instruction_codet &code)
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
std::string from_expr(const namespacet &ns, const irep_idt &identifier, const exprt &expr)
API to expression classes for Pointers.
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 pointer_offset_exprt & to_pointer_offset_expr(const exprt &expr)
Cast an exprt to a pointer_offset_exprt.
const dynamic_object_exprt & to_dynamic_object_expr(const exprt &expr)
Cast an exprt to a dynamic_object_exprt.
std::optional< mp_integer > pointer_offset_size(const typet &type, const namespacet &ns)
Compute the size of a type in bytes, rounding up to full bytes.
std::optional< mp_integer > compute_pointer_offset(const exprt &expr, const namespacet &ns)
std::optional< mp_integer > member_offset(const struct_typet &type, const irep_idt &member, const namespacet &ns)
Pointer Logic.
Ranges: pair of begin and end iterators, which can be initialized from containers,...
ranget< iteratort > make_range(iteratort begin, iteratort end)
Definition range.h:522
bool simplify(exprt &expr, const namespacet &ns)
exprt simplify_expr(exprt src, const namespacet &ns)
#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
side_effect_exprt & to_side_effect_expr(exprt &expr)
Definition std_code.h:1506
const code_assumet & to_code_assume(const codet &code)
Definition std_code.h:251
const codet & to_code(const exprt &expr)
const array_of_exprt & to_array_of_expr(const exprt &expr)
Cast an exprt to an array_of_exprt.
Definition std_expr.h:1603
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1538
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition std_expr.h:2107
const binary_exprt & to_binary_expr(const exprt &expr)
Cast an exprt to a binary_exprt.
Definition std_expr.h:715
const let_exprt & to_let_expr(const exprt &expr)
Cast an exprt to a let_exprt.
Definition std_expr.h:3455
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition std_expr.h:2577
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:3063
const minus_exprt & to_minus_expr(const exprt &expr)
Cast an exprt to a minus_exprt.
Definition std_expr.h:1086
const union_exprt & to_union_expr(const exprt &expr)
Cast an exprt to a union_exprt.
Definition std_expr.h:1816
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition std_expr.h:3172
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:2660
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition std_types.h:788
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition std_types.h:308
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 struct_or_union_tag_typet & to_struct_or_union_tag_type(const typet &type)
Cast a typet to a struct_or_union_tag_typet.
Definition std_types.h:478
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
Represents a row of a value_sett.
Definition value_set.h:203
irep_idt identifier
Definition value_set.h:205
std::string suffix
Definition value_set.h:206
object_mapt object_map
Definition value_set.h:204
Symbol table entry.
static bool failed(bool error_indicator)
static std::string strip_first_field_from_suffix(const std::string &suffix, const std::string &field)
static bool suffix_starts_with_field(const std::string &suffix, const std::string &field)
Check if 'suffix' starts with 'field'.
Value Set.