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