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/byte_operators.h>
16 #include <util/c_types.h>
17 #include <util/expr_util.h>
18 #include <util/format_expr.h>
19 #include <util/format_type.h>
20 #include <util/pointer_expr.h>
22 #include <util/prefix.h>
23 #include <util/range.h>
24 #include <util/simplify_expr.h>
25 #include <util/std_code.h>
26 #include <util/symbol_table.h>
27 
28 #include <ostream>
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 
44 bool value_sett::field_sensitive(const irep_idt &id, const typet &type)
45 {
46  // we always track fields on these
47  if(has_prefix(id2string(id), "value_set::dynamic_object") ||
48  id=="value_set::return_value" ||
49  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,
65  const object_mapt &new_values,
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  {
80  if(make_union_would_change(existing_entry->get().object_map, new_values))
81  {
82  values.update(index, [&new_values, this](entryt &entry) {
83  make_union(entry.object_map, new_values);
84  });
85  }
86  }
87  else
88  {
89  values.update(
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
111  return insert_actiont::INSERT;
112  }
113  else if(!entry->second)
114  return insert_actiont::NONE;
115  else if(offset && *entry->second == *offset)
116  return insert_actiont::NONE;
117  else
119 }
120 
122  object_mapt &dest,
124  const offsett &offset) const
125 {
126  auto insert_action = get_insert_action(dest, n, offset);
127  if(insert_action == insert_actiont::NONE)
128  return false;
129 
130  auto &new_offset = dest.write()[n];
131  if(insert_action == insert_actiont::INSERT)
132  new_offset = offset;
133  else
134  new_offset.reset();
135 
136  return true;
137 }
138 
139 void 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(has_prefix(id2string(e.identifier), "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 
218 exprt value_sett::to_expr(const object_map_dt::value_type &it) const
219 {
220  const exprt &object=object_numbering[it.first];
221 
222  if(object.id()==ID_invalid ||
223  object.id()==ID_unknown)
224  return object;
225 
227 
228  od.object()=object;
229 
230  if(it.second)
231  od.offset() = from_integer(*it.second, c_index_type());
232 
233  od.type()=od.object().type();
234 
235  return std::move(od);
236 }
237 
239 {
240  bool result=false;
241 
243 
244  new_values.get_delta_view(values, delta_view, false);
245 
246  for(const auto &delta_entry : delta_view)
247  {
248  if(delta_entry.is_in_both_maps())
249  {
251  delta_entry.get_other_map_value().object_map,
252  delta_entry.m.object_map))
253  {
254  values.update(delta_entry.k, [&](entryt &existing_entry) {
255  make_union(existing_entry.object_map, delta_entry.m.object_map);
256  });
257  result = true;
258  }
259  }
260  else
261  {
262  values.insert(delta_entry.k, delta_entry.m);
263  result = true;
264  }
265  }
266 
267  return result;
268 }
269 
271  const object_mapt &dest,
272  const object_mapt &src) const
273 {
274  for(const auto &number_and_offset : src.read())
275  {
276  if(
278  dest, number_and_offset.first, number_and_offset.second) !=
280  {
281  return true;
282  }
283  }
284 
285  return false;
286 }
287 
288 bool value_sett::make_union(object_mapt &dest, const object_mapt &src) const
289 {
290  bool result=false;
291 
292  for(object_map_dt::const_iterator it=src.read().begin();
293  it!=src.read().end();
294  it++)
295  {
296  if(insert(dest, *it))
297  result=true;
298  }
299 
300  return result;
301 }
302 
304  exprt &expr,
305  const namespacet &ns) const
306 {
307  bool mod=false;
308 
309  if(expr.id()==ID_pointer_offset)
310  {
311  const object_mapt reference_set =
312  get_value_set(to_pointer_offset_expr(expr).pointer(), ns, true);
313 
314  exprt new_expr;
315  mp_integer previous_offset=0;
316 
317  const object_map_dt &object_map=reference_set.read();
318  for(object_map_dt::const_iterator
319  it=object_map.begin();
320  it!=object_map.end();
321  it++)
322  if(!it->second)
323  return false;
324  else
325  {
326  const exprt &object=object_numbering[it->first];
327  auto ptr_offset = compute_pointer_offset(object, ns);
328 
329  if(!ptr_offset.has_value())
330  return false;
331 
332  *ptr_offset += *it->second;
333 
334  if(mod && *ptr_offset != previous_offset)
335  return false;
336 
337  new_expr = from_integer(*ptr_offset, expr.type());
338  previous_offset = *ptr_offset;
339  mod=true;
340  }
341 
342  if(mod)
343  expr.swap(new_expr);
344  }
345  else
346  {
347  Forall_operands(it, expr)
348  mod=eval_pointer_offset(*it, ns) || mod;
349  }
350 
351  return mod;
352 }
353 
354 std::vector<exprt>
356 {
357  const object_mapt object_map = get_value_set(std::move(expr), ns, false);
358  return make_range(object_map.read())
359  .map([&](const object_map_dt::value_type &pair) { return to_expr(pair); });
360 }
361 
363  exprt expr,
364  const namespacet &ns,
365  bool is_simplified) const
366 {
367  if(!is_simplified)
368  simplify(expr, ns);
369 
370  object_mapt dest;
371  get_value_set_rec(expr, dest, "", expr.type(), ns);
372  return dest;
373 }
374 
379  const std::string &suffix, const std::string &field)
380 {
381  return
382  !suffix.empty() &&
383  suffix[0] == '.' &&
384  suffix.compare(1, field.length(), field) == 0 &&
385  (suffix.length() == field.length() + 1 ||
386  suffix[field.length() + 1] == '.' ||
387  suffix[field.length() + 1] == '[');
388 }
389 
390 static std::string strip_first_field_from_suffix(
391  const std::string &suffix, const std::string &field)
392 {
393  INVARIANT(
394  suffix_starts_with_field(suffix, field),
395  "suffix should start with " + field);
396  return suffix.substr(field.length() + 1);
397 }
398 
400  irep_idt identifier,
401  const typet &type,
402  const std::string &suffix,
403  const namespacet &ns) const
404 {
405  if(
406  type.id() != ID_pointer && type.id() != ID_signedbv &&
407  type.id() != ID_unsignedbv && type.id() != ID_array &&
408  type.id() != ID_struct && type.id() != ID_struct_tag &&
409  type.id() != ID_union && type.id() != ID_union_tag)
410  {
411  return {};
412  }
413 
414  // look it up
415  irep_idt index = id2string(identifier) + suffix;
416  auto *entry = find_entry(index);
417  if(entry)
418  return std::move(index);
419 
420  const typet &followed_type = type.id() == ID_struct_tag
421  ? ns.follow_tag(to_struct_tag_type(type))
422  : type.id() == ID_union_tag
423  ? ns.follow_tag(to_union_tag_type(type))
424  : type;
425 
426  // try first component name as suffix if not yet found
427  if(followed_type.id() == ID_struct || followed_type.id() == ID_union)
428  {
429  const struct_union_typet &struct_union_type =
430  to_struct_union_type(followed_type);
431 
432  if(!struct_union_type.components().empty())
433  {
434  const irep_idt &first_component_name =
435  struct_union_type.components().front().get_name();
436 
437  index =
438  id2string(identifier) + "." + id2string(first_component_name) + suffix;
439  entry = find_entry(index);
440  if(entry)
441  return std::move(index);
442  }
443  }
444 
445  // not found? try without suffix
446  entry = find_entry(identifier);
447  if(entry)
448  return std::move(identifier);
449 
450  return {};
451 }
452 
454  const exprt &expr,
455  object_mapt &dest,
456  const std::string &suffix,
457  const typet &original_type,
458  const namespacet &ns) const
459 {
460 #ifdef DEBUG
461  std::cout << "GET_VALUE_SET_REC EXPR: " << format(expr) << "\n";
462  std::cout << "GET_VALUE_SET_REC SUFFIX: " << suffix << '\n';
463 #endif
464 
465  const typet &expr_type=ns.follow(expr.type());
466 
467  if(expr.id()==ID_unknown || expr.id()==ID_invalid)
468  {
469  insert(dest, exprt(ID_unknown, original_type));
470  }
471  else if(expr.id()==ID_index)
472  {
473  const typet &type = to_index_expr(expr).array().type();
474 
476  type.id() == ID_array, "operand 0 of index expression must be an array");
477 
479  to_index_expr(expr).array(), dest, "[]" + suffix, original_type, ns);
480  }
481  else if(expr.id()==ID_member)
482  {
483  const typet &type = ns.follow(to_member_expr(expr).compound().type());
484 
486  type.id() == ID_struct || type.id() == ID_union,
487  "compound of member expression must be struct or union");
488 
489  const std::string &component_name=
490  expr.get_string(ID_component_name);
491 
493  to_member_expr(expr).compound(),
494  dest,
495  "." + component_name + suffix,
496  original_type,
497  ns);
498  }
499  else if(expr.id()==ID_symbol)
500  {
501  auto entry_index = get_index_of_symbol(
502  to_symbol_expr(expr).get_identifier(), expr_type, suffix, ns);
503 
504  if(entry_index.has_value())
505  make_union(dest, find_entry(*entry_index)->object_map);
506  else
507  insert(dest, exprt(ID_unknown, original_type));
508  }
509  else if(expr.id() == ID_nondet_symbol)
510  {
511  if(expr.type().id() == ID_pointer)
512  {
513  // we'll take the union of all objects we see, with unspecified offsets
514  values.iterate([this, &dest](const irep_idt &key, const entryt &value) {
515  for(const auto &object : value.object_map.read())
516  insert(dest, object.first, offsett());
517  });
518 
519  // we'll add null, in case it's not there yet
520  insert(
521  dest,
522  exprt(ID_null_object, to_pointer_type(expr_type).base_type()),
523  offsett());
524  }
525  else
526  insert(dest, exprt(ID_unknown, original_type));
527  }
528  else if(expr.id()==ID_if)
529  {
531  to_if_expr(expr).true_case(), dest, suffix, original_type, ns);
533  to_if_expr(expr).false_case(), dest, suffix, original_type, ns);
534  }
535  else if(expr.id()==ID_address_of)
536  {
537  get_reference_set(to_address_of_expr(expr).object(), dest, ns);
538  }
539  else if(expr.id()==ID_dereference)
540  {
541  object_mapt reference_set;
542  get_reference_set(expr, reference_set, ns);
543  const object_map_dt &object_map=reference_set.read();
544 
545  if(object_map.begin()==object_map.end())
546  insert(dest, exprt(ID_unknown, original_type));
547  else
548  {
549  for(object_map_dt::const_iterator
550  it1=object_map.begin();
551  it1!=object_map.end();
552  it1++)
553  {
556  const exprt object=object_numbering[it1->first];
557  get_value_set_rec(object, dest, suffix, original_type, ns);
558  }
559  }
560  }
561  else if(expr.is_constant())
562  {
563  // check if NULL
565  {
566  insert(
567  dest,
568  exprt(ID_null_object, to_pointer_type(expr_type).base_type()),
569  mp_integer{0});
570  }
571  else if(expr_type.id()==ID_unsignedbv ||
572  expr_type.id()==ID_signedbv)
573  {
574  // an integer constant got turned into a pointer
575  insert(dest, exprt(ID_integer_address, unsigned_char_type()));
576  }
577  else
578  insert(dest, exprt(ID_unknown, original_type));
579  }
580  else if(expr.id()==ID_typecast)
581  {
582  // let's see what gets converted to what
583 
584  const auto &op = to_typecast_expr(expr).op();
585  const typet &op_type = op.type();
586 
587  if(op_type.id()==ID_pointer)
588  {
589  // pointer-to-pointer -- we just ignore these
590  get_value_set_rec(op, dest, suffix, original_type, ns);
591  }
592  else if(op_type.id()==ID_unsignedbv ||
593  op_type.id()==ID_signedbv)
594  {
595  // integer-to-pointer
596 
597  if(op.is_zero())
598  {
599  insert(
600  dest,
601  exprt(ID_null_object, to_type_with_subtype(expr_type).subtype()),
602  mp_integer{0});
603  }
604  else
605  {
606  // see if we have something for the integer
607  object_mapt tmp;
608 
609  get_value_set_rec(op, tmp, suffix, original_type, ns);
610 
611  if(tmp.read().empty())
612  {
613  // if not, throw in integer
614  insert(dest, exprt(ID_integer_address, unsigned_char_type()));
615  }
616  else if(tmp.read().size()==1 &&
617  object_numbering[tmp.read().begin()->first].id()==ID_unknown)
618  {
619  // if not, throw in integer
620  insert(dest, exprt(ID_integer_address, unsigned_char_type()));
621  }
622  else
623  {
624  // use as is
625  dest.write().insert(tmp.read().begin(), tmp.read().end());
626  }
627  }
628  }
629  else
630  insert(dest, exprt(ID_unknown, original_type));
631  }
632  else if(
633  expr.id() == ID_plus || expr.id() == ID_minus || expr.id() == ID_bitor ||
634  expr.id() == ID_bitand || expr.id() == ID_bitxor ||
635  expr.id() == ID_bitnand || expr.id() == ID_bitnor ||
636  expr.id() == ID_bitxnor)
637  {
638  if(expr.operands().size()<2)
639  throw expr.id_string()+" expected to have at least two operands";
640 
641  object_mapt pointer_expr_set;
643 
644  // special case for plus/minus and exactly one pointer
645  optionalt<exprt> ptr_operand;
646  if(
647  expr_type.id() == ID_pointer &&
648  (expr.id() == ID_plus || expr.id() == ID_minus))
649  {
650  bool non_const_offset = false;
651  for(const auto &op : expr.operands())
652  {
653  if(op.type().id() == ID_pointer)
654  {
655  if(ptr_operand.has_value())
656  {
657  ptr_operand.reset();
658  break;
659  }
660 
661  ptr_operand = op;
662  }
663  else if(!non_const_offset)
664  {
665  auto offset = numeric_cast<mp_integer>(op);
666  if(!offset.has_value())
667  {
668  i.reset();
669  non_const_offset = true;
670  }
671  else
672  {
673  if(!i.has_value())
674  i = mp_integer{0};
675  i = *i + *offset;
676  }
677  }
678  }
679 
680  if(ptr_operand.has_value() && i.has_value())
681  {
682  typet pointer_base_type =
683  to_pointer_type(ptr_operand->type()).base_type();
684  if(pointer_base_type.id() == ID_empty)
685  pointer_base_type = char_type();
686 
687  auto size = pointer_offset_size(pointer_base_type, ns);
688 
689  if(!size.has_value() || (*size) == 0)
690  {
691  i.reset();
692  }
693  else
694  {
695  *i *= *size;
696 
697  if(expr.id()==ID_minus)
698  {
700  to_minus_expr(expr).lhs() == *ptr_operand,
701  "unexpected subtraction of pointer from integer");
702  i->negate();
703  }
704  }
705  }
706  }
707 
708  if(ptr_operand.has_value())
709  {
711  *ptr_operand, pointer_expr_set, "", ptr_operand->type(), ns);
712  }
713  else
714  {
715  // we get the points-to for all operands, even integers
716  forall_operands(it, expr)
717  {
719  *it, pointer_expr_set, "", it->type(), ns);
720  }
721  }
722 
723  for(object_map_dt::const_iterator
724  it=pointer_expr_set.read().begin();
725  it!=pointer_expr_set.read().end();
726  it++)
727  {
728  offsett offset = it->second;
729 
730  // adjust by offset
731  if(offset && i.has_value())
732  *offset += *i;
733  else
734  offset.reset();
735 
736  insert(dest, it->first, offset);
737  }
738  }
739  else if(expr.id()==ID_mult)
740  {
741  // this is to do stuff like
742  // (int*)((sel*(ulong)&a)+((sel^0x1)*(ulong)&b))
743 
744  if(expr.operands().size()<2)
745  throw expr.id_string()+" expected to have at least two operands";
746 
747  object_mapt pointer_expr_set;
748 
749  // we get the points-to for all operands, even integers
750  forall_operands(it, expr)
751  {
753  *it, pointer_expr_set, "", it->type(), ns);
754  }
755 
756  for(object_map_dt::const_iterator
757  it=pointer_expr_set.read().begin();
758  it!=pointer_expr_set.read().end();
759  it++)
760  {
761  offsett offset = it->second;
762 
763  // kill any offset
764  offset.reset();
765 
766  insert(dest, it->first, offset);
767  }
768  }
769  else if(expr.id() == ID_lshr || expr.id() == ID_ashr || expr.id() == ID_shl)
770  {
771  const binary_exprt &binary_expr = to_binary_expr(expr);
772 
773  object_mapt pointer_expr_set;
775  binary_expr.op0(), pointer_expr_set, "", binary_expr.op0().type(), ns);
776 
777  for(const auto &object_map_entry : pointer_expr_set.read())
778  {
779  offsett offset = object_map_entry.second;
780 
781  // kill any offset
782  offset.reset();
783 
784  insert(dest, object_map_entry.first, offset);
785  }
786  }
787  else if(expr.id()==ID_side_effect)
788  {
789  const irep_idt &statement = to_side_effect_expr(expr).get_statement();
790 
791  if(statement==ID_function_call)
792  {
793  // these should be gone
794  throw "unexpected function_call sideeffect";
795  }
796  else if(statement==ID_allocate)
797  {
798  PRECONDITION(suffix.empty());
799 
800  const typet &dynamic_type=
801  static_cast<const typet &>(expr.find(ID_C_cxx_alloc_type));
802 
803  dynamic_object_exprt dynamic_object(dynamic_type);
804  dynamic_object.set_instance(location_number);
805  dynamic_object.valid()=true_exprt();
806 
807  insert(dest, dynamic_object, mp_integer{0});
808  }
809  else if(statement==ID_cpp_new ||
810  statement==ID_cpp_new_array)
811  {
812  PRECONDITION(suffix.empty());
813  assert(expr_type.id()==ID_pointer);
814 
815  dynamic_object_exprt dynamic_object(
816  to_pointer_type(expr_type).base_type());
817  dynamic_object.set_instance(location_number);
818  dynamic_object.valid()=true_exprt();
819 
820  insert(dest, dynamic_object, mp_integer{0});
821  }
822  else
823  insert(dest, exprt(ID_unknown, original_type));
824  }
825  else if(expr.id()==ID_struct)
826  {
827  const auto &struct_components = to_struct_type(expr_type).components();
828  INVARIANT(
829  struct_components.size() == expr.operands().size(),
830  "struct expression should have an operand per component");
831  auto component_iter = struct_components.begin();
832  bool found_component = false;
833 
834  // a struct constructor, which may contain addresses
835 
836  forall_operands(it, expr)
837  {
838  const std::string &component_name =
839  id2string(component_iter->get_name());
840  if(suffix_starts_with_field(suffix, component_name))
841  {
842  std::string remaining_suffix =
843  strip_first_field_from_suffix(suffix, component_name);
844  get_value_set_rec(*it, dest, remaining_suffix, original_type, ns);
845  found_component = true;
846  }
847  ++component_iter;
848  }
849 
850  if(!found_component)
851  {
852  // Struct field doesn't appear as expected -- this has probably been
853  // cast from an incompatible type. Conservatively assume all fields may
854  // be of interest.
855  forall_operands(it, expr)
856  get_value_set_rec(*it, dest, suffix, original_type, ns);
857  }
858  }
859  else if(expr.id() == ID_union)
860  {
862  to_union_expr(expr).op(), dest, suffix, original_type, ns);
863  }
864  else if(expr.id()==ID_with)
865  {
866  const with_exprt &with_expr = to_with_expr(expr);
867 
868  // If the suffix is empty we're looking for the whole struct:
869  // default to combining both options as below.
870  if(expr_type.id() == ID_struct && !suffix.empty())
871  {
872  irep_idt component_name = with_expr.where().get(ID_component_name);
873  if(suffix_starts_with_field(suffix, id2string(component_name)))
874  {
875  // Looking for the member overwritten by this WITH expression
876  std::string remaining_suffix =
877  strip_first_field_from_suffix(suffix, id2string(component_name));
879  with_expr.new_value(), dest, remaining_suffix, original_type, ns);
880  }
881  else if(to_struct_type(expr_type).has_component(component_name))
882  {
883  // Looking for a non-overwritten member, look through this expression
884  get_value_set_rec(with_expr.old(), dest, suffix, original_type, ns);
885  }
886  else
887  {
888  // Member we're looking for is not defined in this struct -- this
889  // must be a reinterpret cast of some sort. Default to conservatively
890  // assuming either operand might be involved.
891  get_value_set_rec(with_expr.old(), dest, suffix, original_type, ns);
892  get_value_set_rec(with_expr.new_value(), dest, "", original_type, ns);
893  }
894  }
895  else if(expr_type.id() == ID_array && !suffix.empty())
896  {
897  std::string new_value_suffix;
898  if(has_prefix(suffix, "[]"))
899  new_value_suffix = suffix.substr(2);
900 
901  // Otherwise use a blank suffix on the assumption anything involved with
902  // the new value might be interesting.
903 
904  get_value_set_rec(with_expr.old(), dest, suffix, original_type, ns);
906  with_expr.new_value(), dest, new_value_suffix, original_type, ns);
907  }
908  else
909  {
910  // Something else-- the suffixes used here are a rough guess at best,
911  // so this is imprecise.
912  get_value_set_rec(with_expr.old(), dest, suffix, original_type, ns);
913  get_value_set_rec(with_expr.new_value(), dest, "", original_type, ns);
914  }
915  }
916  else if(expr.id()==ID_array)
917  {
918  // an array constructor, possibly containing addresses
919  std::string new_suffix = suffix;
920  if(has_prefix(suffix, "[]"))
921  new_suffix = suffix.substr(2);
922  // Otherwise we're probably reinterpreting some other type -- try persisting
923  // with the current suffix for want of a better idea.
924 
925  forall_operands(it, expr)
926  get_value_set_rec(*it, dest, new_suffix, original_type, ns);
927  }
928  else if(expr.id()==ID_array_of)
929  {
930  // an array constructor, possibly containing an address
931  std::string new_suffix = suffix;
932  if(has_prefix(suffix, "[]"))
933  new_suffix = suffix.substr(2);
934  // Otherwise we're probably reinterpreting some other type -- try persisting
935  // with the current suffix for want of a better idea.
936 
938  to_array_of_expr(expr).what(), dest, new_suffix, original_type, ns);
939  }
940  else if(expr.id()==ID_dynamic_object)
941  {
942  const dynamic_object_exprt &dynamic_object=
944 
945  const std::string prefix=
946  "value_set::dynamic_object"+
947  std::to_string(dynamic_object.get_instance());
948 
949  // first try with suffix
950  const std::string full_name=prefix+suffix;
951 
952  // look it up
953  const entryt *entry = find_entry(full_name);
954 
955  // not found? try without suffix
956  if(!entry)
957  entry = find_entry(prefix);
958 
959  if(!entry)
960  insert(dest, exprt(ID_unknown, original_type));
961  else
962  make_union(dest, entry->object_map);
963  }
964  else if(expr.id()==ID_byte_extract_little_endian ||
965  expr.id()==ID_byte_extract_big_endian)
966  {
967  const auto &byte_extract_expr = to_byte_extract_expr(expr);
968 
969  bool found=false;
970 
971  const typet &op_type = ns.follow(byte_extract_expr.op().type());
972  if(op_type.id() == ID_struct)
973  {
974  exprt offset = byte_extract_expr.offset();
975  if(eval_pointer_offset(offset, ns))
976  simplify(offset, ns);
977 
978  const auto offset_int = numeric_cast<mp_integer>(offset);
979  const auto type_size = pointer_offset_size(expr.type(), ns);
980 
981  const struct_typet &struct_type = to_struct_type(op_type);
982 
983  for(const auto &c : struct_type.components())
984  {
985  const irep_idt &name = c.get_name();
986 
987  if(offset_int.has_value())
988  {
989  auto comp_offset = member_offset(struct_type, name, ns);
990  if(comp_offset.has_value())
991  {
992  if(
993  type_size.has_value() && *offset_int + *type_size <= *comp_offset)
994  {
995  break;
996  }
997 
998  auto member_size = pointer_offset_size(c.type(), ns);
999  if(
1000  member_size.has_value() &&
1001  *offset_int >= *comp_offset + *member_size)
1002  {
1003  continue;
1004  }
1005  }
1006  }
1007 
1008  found=true;
1009 
1010  member_exprt member(byte_extract_expr.op(), c);
1011  get_value_set_rec(member, dest, suffix, original_type, ns);
1012  }
1013  }
1014 
1015  if(op_type.id() == ID_union)
1016  {
1017  // just collect them all
1018  for(const auto &c : to_union_type(op_type).components())
1019  {
1020  const irep_idt &name = c.get_name();
1021  member_exprt member(byte_extract_expr.op(), name, c.type());
1022  get_value_set_rec(member, dest, suffix, original_type, ns);
1023  }
1024  }
1025 
1026  if(!found)
1027  // we just pass through
1029  byte_extract_expr.op(), dest, suffix, original_type, ns);
1030  }
1031  else if(expr.id()==ID_byte_update_little_endian ||
1032  expr.id()==ID_byte_update_big_endian)
1033  {
1034  const auto &byte_update_expr = to_byte_update_expr(expr);
1035 
1036  // we just pass through
1037  get_value_set_rec(byte_update_expr.op(), dest, suffix, original_type, ns);
1039  byte_update_expr.value(), dest, suffix, original_type, ns);
1040 
1041  // we could have checked object size to be more precise
1042  }
1043  else if(expr.id() == ID_let)
1044  {
1045  const auto &let_expr = to_let_expr(expr);
1046  // This depends on copying `value_sett` being cheap -- which it is, because
1047  // our backing store is sharing_mapt.
1048  value_sett value_set_with_local_definition = *this;
1049  value_set_with_local_definition.assign(
1050  let_expr.symbol(), let_expr.value(), ns, false, false);
1051 
1052  value_set_with_local_definition.get_value_set_rec(
1053  let_expr.where(), dest, suffix, original_type, ns);
1054  }
1055  else
1056  {
1057  insert(dest, exprt(ID_unknown, original_type));
1058  }
1059 
1060  #ifdef DEBUG
1061  std::cout << "GET_VALUE_SET_REC RESULT:\n";
1062  for(const auto &obj : dest.read())
1063  {
1064  const exprt &e=to_expr(obj);
1065  std::cout << " " << format(e) << "\n";
1066  }
1067  std::cout << "\n";
1068  #endif
1069 }
1070 
1072  const exprt &src,
1073  exprt &dest) const
1074 {
1075  // remove pointer typecasts
1076  if(src.id()==ID_typecast)
1077  {
1078  assert(src.type().id()==ID_pointer);
1079 
1080  dereference_rec(to_typecast_expr(src).op(), dest);
1081  }
1082  else
1083  dest=src;
1084 }
1085 
1087  const exprt &expr,
1088  value_setst::valuest &dest,
1089  const namespacet &ns) const
1090 {
1091  object_mapt object_map;
1092  get_reference_set(expr, object_map, ns);
1093 
1094  for(object_map_dt::const_iterator
1095  it=object_map.read().begin();
1096  it!=object_map.read().end();
1097  it++)
1098  dest.push_back(to_expr(*it));
1099 }
1100 
1102  const exprt &expr,
1103  object_mapt &dest,
1104  const namespacet &ns) const
1105 {
1106 #ifdef DEBUG
1107  std::cout << "GET_REFERENCE_SET_REC EXPR: " << format(expr)
1108  << '\n';
1109 #endif
1110 
1111  if(expr.id()==ID_symbol ||
1112  expr.id()==ID_dynamic_object ||
1113  expr.id()==ID_string_constant ||
1114  expr.id()==ID_array)
1115  {
1116  if(
1117  expr.type().id() == ID_array &&
1118  to_array_type(expr.type()).element_type().id() == ID_array)
1119  insert(dest, expr);
1120  else
1121  insert(dest, expr, mp_integer{0});
1122 
1123  return;
1124  }
1125  else if(expr.id()==ID_dereference)
1126  {
1127  const auto &pointer = to_dereference_expr(expr).pointer();
1128 
1129  get_value_set_rec(pointer, dest, "", pointer.type(), ns);
1130 
1131 #ifdef DEBUG
1132  for(const auto &map_entry : dest.read())
1133  {
1134  std::cout << "VALUE_SET: " << format(object_numbering[map_entry.first])
1135  << '\n';
1136  }
1137 #endif
1138 
1139  return;
1140  }
1141  else if(expr.id()==ID_index)
1142  {
1143  if(expr.operands().size()!=2)
1144  throw "index expected to have two operands";
1145 
1146  const index_exprt &index_expr=to_index_expr(expr);
1147  const exprt &array=index_expr.array();
1148  const exprt &offset=index_expr.index();
1149 
1151  array.type().id() == ID_array, "index takes array-typed operand");
1152 
1153  const auto &array_type = to_array_type(array.type());
1154 
1155  object_mapt array_references;
1156  get_reference_set(array, array_references, ns);
1157 
1158  const object_map_dt &object_map=array_references.read();
1159 
1160  for(object_map_dt::const_iterator
1161  a_it=object_map.begin();
1162  a_it!=object_map.end();
1163  a_it++)
1164  {
1165  const exprt &object=object_numbering[a_it->first];
1166 
1167  if(object.id()==ID_unknown)
1168  insert(dest, exprt(ID_unknown, expr.type()));
1169  else
1170  {
1171  const index_exprt deref_index_expr(
1172  typecast_exprt::conditional_cast(object, array_type),
1173  from_integer(0, c_index_type()));
1174 
1175  offsett o = a_it->second;
1176  const auto i = numeric_cast<mp_integer>(offset);
1177 
1178  if(offset.is_zero())
1179  {
1180  }
1181  else if(i.has_value() && o)
1182  {
1183  auto size = pointer_offset_size(array_type.element_type(), ns);
1184 
1185  if(!size.has_value() || *size == 0)
1186  o.reset();
1187  else
1188  *o = *i * (*size);
1189  }
1190  else
1191  o.reset();
1192 
1193  insert(dest, deref_index_expr, o);
1194  }
1195  }
1196 
1197  return;
1198  }
1199  else if(expr.id()==ID_member)
1200  {
1201  const irep_idt &component_name=expr.get(ID_component_name);
1202 
1203  const exprt &struct_op = to_member_expr(expr).compound();
1204 
1205  object_mapt struct_references;
1206  get_reference_set(struct_op, struct_references, ns);
1207 
1208  const object_map_dt &object_map=struct_references.read();
1209 
1210  for(object_map_dt::const_iterator
1211  it=object_map.begin();
1212  it!=object_map.end();
1213  it++)
1214  {
1215  const exprt &object=object_numbering[it->first];
1216 
1217  if(object.id()==ID_unknown)
1218  insert(dest, exprt(ID_unknown, expr.type()));
1219  else if(
1220  object.type().id() == ID_struct ||
1221  object.type().id() == ID_struct_tag || object.type().id() == ID_union ||
1222  object.type().id() == ID_union_tag)
1223  {
1224  offsett o = it->second;
1225 
1226  member_exprt member_expr(object, component_name, expr.type());
1227 
1228  // We cannot introduce a cast from scalar to non-scalar,
1229  // thus, we can only adjust the types of structs and unions.
1230 
1231  const typet &final_object_type = ns.follow(object.type());
1232 
1233  if(final_object_type.id()==ID_struct ||
1234  final_object_type.id()==ID_union)
1235  {
1236  // adjust type?
1237  if(ns.follow(struct_op.type())!=final_object_type)
1238  {
1239  member_expr.compound() =
1240  typecast_exprt(member_expr.compound(), struct_op.type());
1241  }
1242 
1243  insert(dest, member_expr, o);
1244  }
1245  else
1246  insert(dest, exprt(ID_unknown, expr.type()));
1247  }
1248  else
1249  insert(dest, exprt(ID_unknown, expr.type()));
1250  }
1251 
1252  return;
1253  }
1254  else if(expr.id()==ID_if)
1255  {
1256  get_reference_set_rec(to_if_expr(expr).true_case(), dest, ns);
1257  get_reference_set_rec(to_if_expr(expr).false_case(), dest, ns);
1258  return;
1259  }
1260 
1261  insert(dest, exprt(ID_unknown, expr.type()));
1262 }
1263 
1265  const exprt &lhs,
1266  const exprt &rhs,
1267  const namespacet &ns,
1268  bool is_simplified,
1269  bool add_to_sets)
1270 {
1271 #ifdef DEBUG
1272  std::cout << "ASSIGN LHS: " << format(lhs) << " : "
1273  << format(lhs.type()) << '\n';
1274  std::cout << "ASSIGN RHS: " << format(rhs) << " : "
1275  << format(rhs.type()) << '\n';
1276  std::cout << "--------------------------------------------\n";
1277  output(std::cout);
1278 #endif
1279 
1280  const typet &type=ns.follow(lhs.type());
1281 
1282  if(type.id() == ID_struct)
1283  {
1284  for(const auto &c : to_struct_type(type).components())
1285  {
1286  const typet &subtype = c.type();
1287  const irep_idt &name = c.get_name();
1288 
1289  // ignore methods and padding
1290  if(subtype.id() == ID_code || c.get_is_padding())
1291  continue;
1292 
1293  member_exprt lhs_member(lhs, name, subtype);
1294 
1295  exprt rhs_member;
1296 
1297  if(rhs.id()==ID_unknown ||
1298  rhs.id()==ID_invalid)
1299  {
1300  // this branch is deemed dead as otherwise we'd be missing assignments
1301  // that never happened in this branch
1302  UNREACHABLE;
1303  rhs_member=exprt(rhs.id(), subtype);
1304  }
1305  else
1306  {
1308  rhs.type() == lhs.type(),
1309  "value_sett::assign types should match, got: "
1310  "rhs.type():\n" +
1311  rhs.type().pretty() + "\n" + "lhs.type():\n" + lhs.type().pretty());
1312 
1313  const typet &followed = ns.follow(rhs.type());
1314 
1315  if(followed.id() == ID_struct || followed.id() == ID_union)
1316  {
1317  const struct_union_typet &rhs_struct_union_type =
1318  to_struct_union_type(followed);
1319 
1320  const typet &rhs_subtype = rhs_struct_union_type.component_type(name);
1321  rhs_member = simplify_expr(member_exprt{rhs, name, rhs_subtype}, ns);
1322 
1323  assign(lhs_member, rhs_member, ns, true, add_to_sets);
1324  }
1325  }
1326  }
1327  }
1328  else if(type.id()==ID_array)
1329  {
1330  const index_exprt lhs_index(
1331  lhs,
1332  exprt(ID_unknown, c_index_type()),
1333  to_array_type(type).element_type());
1334 
1335  if(rhs.id()==ID_unknown ||
1336  rhs.id()==ID_invalid)
1337  {
1338  assign(
1339  lhs_index,
1340  exprt(rhs.id(), to_array_type(type).element_type()),
1341  ns,
1342  is_simplified,
1343  add_to_sets);
1344  }
1345  else
1346  {
1348  rhs.type() == type,
1349  "value_sett::assign types should match, got: "
1350  "rhs.type():\n" +
1351  rhs.type().pretty() + "\n" + "type:\n" + type.pretty());
1352 
1353  if(rhs.id()==ID_array_of)
1354  {
1355  assign(
1356  lhs_index,
1357  to_array_of_expr(rhs).what(),
1358  ns,
1359  is_simplified,
1360  add_to_sets);
1361  }
1362  else if(rhs.id()==ID_array ||
1363  rhs.id()==ID_constant)
1364  {
1365  forall_operands(o_it, rhs)
1366  {
1367  assign(lhs_index, *o_it, ns, is_simplified, add_to_sets);
1368  add_to_sets=true;
1369  }
1370  }
1371  else if(rhs.id()==ID_with)
1372  {
1373  const index_exprt op0_index(
1374  to_with_expr(rhs).old(),
1375  exprt(ID_unknown, c_index_type()),
1376  to_array_type(type).element_type());
1377 
1378  assign(lhs_index, op0_index, ns, is_simplified, add_to_sets);
1379  assign(
1380  lhs_index, to_with_expr(rhs).new_value(), ns, is_simplified, true);
1381  }
1382  else
1383  {
1384  const index_exprt rhs_index(
1385  rhs,
1386  exprt(ID_unknown, c_index_type()),
1387  to_array_type(type).element_type());
1388  assign(lhs_index, rhs_index, ns, is_simplified, true);
1389  }
1390  }
1391  }
1392  else
1393  {
1394  // basic type or union
1395  object_mapt values_rhs = get_value_set(rhs, ns, is_simplified);
1396 
1397  // Permit custom subclass to alter the read values prior to write:
1398  adjust_assign_rhs_values(rhs, ns, values_rhs);
1399 
1400  // Permit custom subclass to perform global side-effects prior to write:
1401  apply_assign_side_effects(lhs, rhs, ns);
1402 
1403  assign_rec(lhs, values_rhs, "", ns, add_to_sets);
1404  }
1405 }
1406 
1408  const exprt &lhs,
1409  const object_mapt &values_rhs,
1410  const std::string &suffix,
1411  const namespacet &ns,
1412  bool add_to_sets)
1413 {
1414 #ifdef DEBUG
1415  std::cout << "ASSIGN_REC LHS: " << format(lhs) << '\n';
1416  std::cout << "ASSIGN_REC LHS ID: " << lhs.id() << '\n';
1417  std::cout << "ASSIGN_REC SUFFIX: " << suffix << '\n';
1418 
1419  for(object_map_dt::const_iterator it=values_rhs.read().begin();
1420  it!=values_rhs.read().end();
1421  it++)
1422  std::cout << "ASSIGN_REC RHS: " <<
1423  format(object_numbering[it->first]) << '\n';
1424  std::cout << '\n';
1425 #endif
1426 
1427  if(lhs.id()==ID_symbol)
1428  {
1429  const irep_idt &identifier=to_symbol_expr(lhs).get_identifier();
1430 
1431  update_entry(
1432  entryt{identifier, suffix}, lhs.type(), values_rhs, add_to_sets);
1433  }
1434  else if(lhs.id()==ID_dynamic_object)
1435  {
1436  const dynamic_object_exprt &dynamic_object=
1438 
1439  const std::string name=
1440  "value_set::dynamic_object"+
1441  std::to_string(dynamic_object.get_instance());
1442 
1443  update_entry(entryt{name, suffix}, lhs.type(), values_rhs, true);
1444  }
1445  else if(lhs.id()==ID_dereference)
1446  {
1447  if(lhs.operands().size()!=1)
1448  throw lhs.id_string()+" expected to have one operand";
1449 
1450  object_mapt reference_set;
1451  get_reference_set(lhs, reference_set, ns);
1452 
1453  if(reference_set.read().size()!=1)
1454  add_to_sets=true;
1455 
1456  for(object_map_dt::const_iterator
1457  it=reference_set.read().begin();
1458  it!=reference_set.read().end();
1459  it++)
1460  {
1463  const exprt object=object_numbering[it->first];
1464 
1465  if(object.id()!=ID_unknown)
1466  assign_rec(object, values_rhs, suffix, ns, add_to_sets);
1467  }
1468  }
1469  else if(lhs.id()==ID_index)
1470  {
1471  const auto &array = to_index_expr(lhs).array();
1472 
1473  const typet &type = array.type();
1474 
1476  type.id() == ID_array, "operand 0 of index expression must be an array");
1477 
1478  assign_rec(array, values_rhs, "[]" + suffix, ns, true);
1479  }
1480  else if(lhs.id()==ID_member)
1481  {
1482  const auto &lhs_member_expr = to_member_expr(lhs);
1483  const auto &component_name = lhs_member_expr.get_component_name();
1484 
1485  const typet &type = ns.follow(lhs_member_expr.compound().type());
1486 
1488  type.id() == ID_struct || type.id() == ID_union,
1489  "operand 0 of member expression must be struct or union");
1490 
1491  assign_rec(
1492  lhs_member_expr.compound(),
1493  values_rhs,
1494  "." + id2string(component_name) + suffix,
1495  ns,
1496  add_to_sets);
1497  }
1498  else if(lhs.id()=="valid_object" ||
1499  lhs.id()=="dynamic_type" ||
1500  lhs.id()=="is_zero_string" ||
1501  lhs.id()=="zero_string" ||
1502  lhs.id()=="zero_string_length")
1503  {
1504  // we ignore this here
1505  }
1506  else if(lhs.id()==ID_string_constant)
1507  {
1508  // someone writes into a string-constant
1509  // evil guy
1510  }
1511  else if(lhs.id() == ID_null_object)
1512  {
1513  // evil as well
1514  }
1515  else if(lhs.id()==ID_typecast)
1516  {
1517  const typecast_exprt &typecast_expr=to_typecast_expr(lhs);
1518 
1519  assign_rec(typecast_expr.op(), values_rhs, suffix, ns, add_to_sets);
1520  }
1521  else if(lhs.id()==ID_byte_extract_little_endian ||
1522  lhs.id()==ID_byte_extract_big_endian)
1523  {
1524  assign_rec(to_byte_extract_expr(lhs).op(), values_rhs, suffix, ns, true);
1525  }
1526  else if(lhs.id()==ID_integer_address)
1527  {
1528  // that's like assigning into __CPROVER_memory[...],
1529  // which we don't track
1530  }
1531  else
1532  throw "assign NYI: '" + lhs.id_string() + "'";
1533 }
1534 
1536  const irep_idt &function,
1537  const exprt::operandst &arguments,
1538  const namespacet &ns)
1539 {
1540  const symbolt &symbol=ns.lookup(function);
1541 
1542  const code_typet &type=to_code_type(symbol.type);
1543  const code_typet::parameterst &parameter_types=type.parameters();
1544 
1545  // these first need to be assigned to dummy, temporary arguments
1546  // and only thereafter to the actuals, in order
1547  // to avoid overwriting actuals that are needed for recursive
1548  // calls
1549 
1550  for(std::size_t i=0; i<arguments.size(); i++)
1551  {
1552  const std::string identifier="value_set::dummy_arg_"+std::to_string(i);
1553  const symbol_exprt dummy_lhs(identifier, arguments[i].type());
1554  assign(dummy_lhs, arguments[i], ns, false, false);
1555  }
1556 
1557  // now assign to 'actual actuals'
1558 
1559  unsigned i=0;
1560 
1561  for(code_typet::parameterst::const_iterator
1562  it=parameter_types.begin();
1563  it!=parameter_types.end();
1564  it++)
1565  {
1566  const irep_idt &identifier=it->get_identifier();
1567  if(identifier.empty())
1568  continue;
1569 
1570  const exprt v_expr=
1571  symbol_exprt("value_set::dummy_arg_"+std::to_string(i), it->type());
1572 
1573  const symbol_exprt actual_lhs(identifier, it->type());
1574  assign(actual_lhs, v_expr, ns, true, true);
1575  i++;
1576  }
1577 
1578  // we could delete the dummy_arg_* now.
1579 }
1580 
1582  const exprt &lhs,
1583  const namespacet &ns)
1584 {
1585  if(lhs.is_nil())
1586  return;
1587 
1588  symbol_exprt rhs("value_set::return_value", lhs.type());
1589 
1590  assign(lhs, rhs, ns, false, false);
1591 }
1592 
1594  const codet &code,
1595  const namespacet &ns)
1596 {
1597  const irep_idt &statement=code.get_statement();
1598 
1599  if(statement==ID_block)
1600  {
1601  forall_operands(it, code)
1602  apply_code_rec(to_code(*it), ns);
1603  }
1604  else if(statement==ID_function_call)
1605  {
1606  // shouldn't be here
1607  UNREACHABLE;
1608  }
1609  else if(statement==ID_assign)
1610  {
1611  if(code.operands().size()!=2)
1612  throw "assignment expected to have two operands";
1613 
1614  assign(code.op0(), code.op1(), ns, false, false);
1615  }
1616  else if(statement==ID_decl)
1617  {
1618  if(code.operands().size()!=1)
1619  throw "decl expected to have one operand";
1620 
1621  const exprt &lhs=code.op0();
1622 
1623  if(lhs.id()!=ID_symbol)
1624  throw "decl expected to have symbol on lhs";
1625 
1626  const typet &lhs_type = lhs.type();
1627 
1628  if(
1629  lhs_type.id() == ID_pointer ||
1630  (lhs_type.id() == ID_array &&
1631  to_array_type(lhs_type).element_type().id() == ID_pointer))
1632  {
1633  // assign the address of the failed object
1634  if(auto failed = get_failed_symbol(to_symbol_expr(lhs), ns))
1635  {
1636  address_of_exprt address_of_expr(*failed, to_pointer_type(lhs.type()));
1637  assign(lhs, address_of_expr, ns, false, false);
1638  }
1639  else
1640  assign(lhs, exprt(ID_invalid), ns, false, false);
1641  }
1642  }
1643  else if(statement==ID_expression)
1644  {
1645  // can be ignored, we don't expect side effects here
1646  }
1647  else if(statement == ID_cpp_delete || statement == ID_cpp_delete_array)
1648  {
1649  // does nothing
1650  }
1651  else if(statement=="lock" || statement=="unlock")
1652  {
1653  // ignore for now
1654  }
1655  else if(statement==ID_asm)
1656  {
1657  // ignore for now, probably not safe
1658  }
1659  else if(statement==ID_nondet)
1660  {
1661  // doesn't do anything
1662  }
1663  else if(statement==ID_printf)
1664  {
1665  // doesn't do anything
1666  }
1667  else if(statement==ID_return)
1668  {
1669  const code_returnt &code_return = to_code_return(code);
1670  // this is turned into an assignment
1671  symbol_exprt lhs(
1672  "value_set::return_value", code_return.return_value().type());
1673  assign(lhs, code_return.return_value(), ns, false, false);
1674  }
1675  else if(statement==ID_array_set)
1676  {
1677  }
1678  else if(statement==ID_array_copy)
1679  {
1680  }
1681  else if(statement==ID_array_replace)
1682  {
1683  }
1684  else if(statement == ID_array_equal)
1685  {
1686  }
1687  else if(statement==ID_assume)
1688  {
1689  guard(to_code_assume(code).assumption(), ns);
1690  }
1691  else if(statement==ID_user_specified_predicate ||
1692  statement==ID_user_specified_parameter_predicates ||
1693  statement==ID_user_specified_return_predicates)
1694  {
1695  // doesn't do anything
1696  }
1697  else if(statement==ID_fence)
1698  {
1699  }
1701  {
1702  // doesn't do anything
1703  }
1704  else if(statement==ID_dead)
1705  {
1706  // Ignore by default; could prune the value set.
1707  }
1708  else if(statement == ID_havoc_object)
1709  {
1710  }
1711  else
1712  {
1713  // std::cerr << code.pretty() << '\n';
1714  throw "value_sett: unexpected statement: "+id2string(statement);
1715  }
1716 }
1717 
1719  const exprt &expr,
1720  const namespacet &ns)
1721 {
1722  if(expr.id()==ID_and)
1723  {
1724  forall_operands(it, expr)
1725  guard(*it, ns);
1726  }
1727  else if(expr.id()==ID_equal)
1728  {
1729  }
1730  else if(expr.id()==ID_notequal)
1731  {
1732  }
1733  else if(expr.id()==ID_not)
1734  {
1735  }
1736  else if(expr.id()==ID_dynamic_object)
1737  {
1738  dynamic_object_exprt dynamic_object(unsigned_char_type());
1739  // dynamic_object.instance()=
1740  // from_integer(location_number, typet(ID_natural));
1741  dynamic_object.valid()=true_exprt();
1742 
1743  address_of_exprt address_of(dynamic_object);
1744  address_of.type() = to_dynamic_object_expr(expr).op0().type();
1745 
1746  assign(to_dynamic_object_expr(expr).op0(), address_of, ns, false, false);
1747  }
1748 }
1749 
1751  const irep_idt &index,
1752  const std::unordered_set<exprt, irep_hash> &values_to_erase)
1753 {
1754  if(values_to_erase.empty())
1755  return;
1756 
1757  auto entry = find_entry(index);
1758  if(!entry)
1759  return;
1760 
1761  std::vector<object_map_dt::key_type> keys_to_erase;
1762 
1763  for(auto &key_value : entry->object_map.read())
1764  {
1765  const auto &rhs_object = to_expr(key_value);
1766  if(values_to_erase.count(rhs_object))
1767  {
1768  keys_to_erase.emplace_back(key_value.first);
1769  }
1770  }
1771 
1773  keys_to_erase.size() == values_to_erase.size(),
1774  "value_sett::erase_value_from_entry() should erase exactly one value for "
1775  "each element in the set it is given");
1776 
1777  entryt replacement = *entry;
1778  for(const auto &key_to_erase : keys_to_erase)
1779  {
1780  replacement.object_map.write().erase(key_to_erase);
1781  }
1782  values.replace(index, std::move(replacement));
1783 }
1784 
1786  const struct_union_typet &struct_union_type,
1787  const std::string &erase_prefix,
1788  const namespacet &ns)
1789 {
1790  for(const auto &c : struct_union_type.components())
1791  {
1792  const typet &subtype = c.type();
1793  const irep_idt &name = c.get_name();
1794 
1795  // ignore methods and padding
1796  if(subtype.id() == ID_code || c.get_is_padding())
1797  continue;
1798 
1799  erase_symbol_rec(subtype, erase_prefix + "." + id2string(name), ns);
1800  }
1801 }
1802 
1804  const typet &type,
1805  const std::string &erase_prefix,
1806  const namespacet &ns)
1807 {
1808  if(type.id() == ID_struct_tag)
1810  ns.follow_tag(to_struct_tag_type(type)), erase_prefix, ns);
1811  else if(type.id() == ID_union_tag)
1813  ns.follow_tag(to_union_tag_type(type)), erase_prefix, ns);
1814  else if(type.id() == ID_array)
1816  to_array_type(type).element_type(), erase_prefix + "[]", ns);
1817  else if(values.has_key(erase_prefix))
1818  values.erase(erase_prefix);
1819 }
1820 
1822  const symbol_exprt &symbol_expr,
1823  const namespacet &ns)
1824 {
1826  symbol_expr.type(), id2string(symbol_expr.get_identifier()), ns);
1827 }
with_exprt
Operator to update elements in structs and arrays.
Definition: std_expr.h:2423
to_union_tag_type
const union_tag_typet & to_union_tag_type(const typet &type)
Cast a typet to a union_tag_typet.
Definition: c_types.h:202
sharing_mapt< irep_idt, entryt >::delta_viewt
std::vector< delta_view_itemt > delta_viewt
Delta view of the key-value pairs in two maps.
Definition: sharing_map.h:439
UNREACHABLE
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:503
struct_union_typet::components
const componentst & components() const
Definition: std_types.h:147
dstringt
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:36
value_sett::erase_symbol
void erase_symbol(const symbol_exprt &symbol_expr, const namespacet &ns)
Definition: value_set.cpp:1821
pointer_offset_size.h
to_union_type
const union_typet & to_union_type(const typet &type)
Cast a typet to a union_typet.
Definition: c_types.h:162
value_sett::make_union_would_change
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:270
format
static format_containert< T > format(const T &o)
Definition: format.h:37
typecast_exprt::conditional_cast
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition: std_expr.h:2025
value_sett::apply_code_rec
virtual void apply_code_rec(const codet &code, const namespacet &ns)
Subclass customisation point for applying code to this domain:
Definition: value_set.cpp:1593
value_sett::location_number
unsigned location_number
Matches the location_number field of the instruction that corresponds to this value_sett instance in ...
Definition: value_set.h:72
get_failed_symbol
optionalt< symbol_exprt > get_failed_symbol(const symbol_exprt &expr, const namespacet &ns)
Get the failed-dereference symbol for the given symbol.
Definition: add_failed_symbols.cpp:92
sharing_mapt::get_delta_view
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
mp_integer
BigInt mp_integer
Definition: smt_terms.h:17
Forall_operands
#define Forall_operands(it, expr)
Definition: expr.h:27
arith_tools.h
codet::op0
exprt & op0()
Definition: expr.h:125
to_struct_type
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
value_sett::dereference_rec
void dereference_rec(const exprt &src, exprt &dest) const
Sets dest to src with any wrapping typecasts removed.
Definition: value_set.cpp:1071
sharing_mapt< irep_idt, entryt >
to_struct_union_type
const struct_union_typet & to_struct_union_type(const typet &type)
Cast a typet to a struct_union_typet.
Definition: std_types.h:214
to_dereference_expr
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
Definition: pointer_expr.h:716
value_sett::get_insert_action
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:101
value_sett::entryt::identifier
irep_idt identifier
Definition: value_set.h:204
value_sett::assign
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:1264
typet
The type of an expression, extends irept.
Definition: type.h:28
code_typet::parameterst
std::vector< parametert > parameterst
Definition: std_types.h:541
irept::pretty
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
Definition: irep.cpp:495
to_byte_extract_expr
const byte_extract_exprt & to_byte_extract_expr(const exprt &expr)
Definition: byte_operators.h:57
to_index_expr
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1478
to_if_expr
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition: std_expr.h:2403
irept::find
const irept & find(const irep_idt &name) const
Definition: irep.cpp:106
sharing_mapt::update
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
struct_union_typet
Base type for structs and unions.
Definition: std_types.h:61
symbolt::type
typet type
Type of symbol.
Definition: symbol.h:31
dynamic_object_exprt
Representation of heap-allocated objects.
Definition: pointer_expr.h:257
numberingt< exprt, irep_hash >
value_sett::find_entry
const entryt * find_entry(const irep_idt &id) const
Finds an entry in this value-set.
Definition: value_set.cpp:56
value_sett::erase_struct_union_symbol
void erase_struct_union_symbol(const struct_union_typet &struct_union_type, const std::string &erase_prefix, const namespacet &ns)
Definition: value_set.cpp:1785
object_descriptor_exprt
Split an expression into a base object and a (byte) offset.
Definition: pointer_expr.h:166
prefix.h
with_exprt::new_value
exprt & new_value()
Definition: std_expr.h:2454
value_sett::object_numbering
static object_numberingt object_numbering
Global shared object numbering, used to abbreviate expressions stored in value sets.
Definition: value_set.h:76
to_array_of_expr
const array_of_exprt & to_array_of_expr(const exprt &expr)
Cast an exprt to an array_of_exprt.
Definition: std_expr.h:1543
suffix_starts_with_field
static bool suffix_starts_with_field(const std::string &suffix, const std::string &field)
Check if 'suffix' starts with 'field'.
Definition: value_set.cpp:378
to_type_with_subtype
const type_with_subtypet & to_type_with_subtype(const typet &type)
Definition: type.h:193
value_sett::assign_rec
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:1407
value_sett
State type in value_set_domaint, used in value-set analysis and goto-symex.
Definition: value_set.h:42
struct_union_typet::component_type
const typet & component_type(const irep_idt &component_name) const
Definition: std_types.cpp:76
exprt
Base class for all expressions.
Definition: expr.h:55
binary_exprt
A base class for binary expressions.
Definition: std_expr.h:582
to_union_expr
const union_exprt & to_union_expr(const exprt &expr)
Cast an exprt to a union_exprt.
Definition: std_expr.h:1754
namespace_baset::follow_tag
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition: namespace.cpp:63
value_sett::eval_pointer_offset
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:303
value_sett::insert_actiont::RESET_OFFSET
@ RESET_OFFSET
to_string
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
Definition: string_constraint.cpp:58
unsigned_char_type
unsignedbv_typet unsigned_char_type()
Definition: c_types.cpp:145
to_side_effect_expr
side_effect_exprt & to_side_effect_expr(exprt &expr)
Definition: std_code.h:1506
value_sett::entryt::object_map
object_mapt object_map
Definition: value_set.h:203
symbol_exprt
Expression to hold a symbol (variable)
Definition: std_expr.h:112
value_sett::adjust_assign_rhs_values
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:502
to_minus_expr
const minus_exprt & to_minus_expr(const exprt &expr)
Cast an exprt to a minus_exprt.
Definition: std_expr.h:1031
value_sett::make_union
bool make_union(object_mapt &dest, const object_mapt &src) const
Merges two RHS expression sets.
Definition: value_set.cpp:288
value_sett::get_reference_set_rec
void get_reference_set_rec(const exprt &expr, object_mapt &dest, const namespacet &ns) const
See get_reference_set.
Definition: value_set.cpp:1101
irept::get
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:45
to_binary_expr
const binary_exprt & to_binary_expr(const exprt &expr)
Cast an exprt to a binary_exprt.
Definition: std_expr.h:660
strip_first_field_from_suffix
static std::string strip_first_field_from_suffix(const std::string &suffix, const std::string &field)
Definition: value_set.cpp:390
namespacet
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:90
to_code
const codet & to_code(const exprt &expr)
Definition: std_code_base.h:104
compute_pointer_offset
optionalt< mp_integer > compute_pointer_offset(const exprt &expr, const namespacet &ns)
Definition: pointer_offset_size.cpp:507
value_sett::insert_actiont
insert_actiont
Definition: value_set.h:168
exprt::type
typet & type()
Return the type of the expression.
Definition: expr.h:84
to_code_assume
const code_assumet & to_code_assume(const codet &code)
Definition: std_code.h:251
namespacet::lookup
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Definition: namespace.cpp:138
value_set.h
with_exprt::old
exprt & old()
Definition: std_expr.h:2434
dynamic_object_exprt::get_instance
unsigned int get_instance() const
Definition: pointer_expr.cpp:23
byte_operators.h
Expression classes for byte-level operators.
to_code_type
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition: std_types.h:744
value_sett::empty_object_map
static const object_map_dt empty_object_map
Definition: value_set.h:89
has_prefix
bool has_prefix(const std::string &s, const std::string &prefix)
Definition: converter.cpp:13
DATA_INVARIANT
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:510
value_setst::valuest
std::list< exprt > valuest
Definition: value_sets.h:28
id2string
const std::string & id2string(const irep_idt &d)
Definition: irep.h:47
value_sett::output
void output(std::ostream &out, const std::string &indent="") const
Pretty-print this value-set.
Definition: value_set.cpp:139
member_exprt::compound
const exprt & compound() const
Definition: std_expr.h:2843
failed
static bool failed(bool error_indicator)
Definition: symtab2gb_parse_options.cpp:39
value_sett::get_value_set
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:355
get_identifier
static optionalt< smt_termt > get_identifier(const exprt &expr, const std::unordered_map< exprt, smt_identifier_termt, irep_hash > &expression_handle_identifiers, const std::unordered_map< exprt, smt_identifier_termt, irep_hash > &expression_identifiers)
Definition: smt2_incremental_decision_procedure.cpp:328
forall_operands
#define forall_operands(it, expr)
Definition: expr.h:20
to_byte_update_expr
const byte_update_exprt & to_byte_update_expr(const exprt &expr)
Definition: byte_operators.h:117
PRECONDITION
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
symbol_exprt::get_identifier
const irep_idt & get_identifier() const
Definition: std_expr.h:142
dereference_exprt::pointer
exprt & pointer()
Definition: pointer_expr.h:673
to_let_expr
const let_exprt & to_let_expr(const exprt &expr)
Cast an exprt to a let_exprt.
Definition: std_expr.h:3266
pointer_expr.h
value_sett::erase_symbol_rec
void erase_symbol_rec(const typet &type, const std::string &erase_prefix, const namespacet &ns)
Definition: value_set.cpp:1803
irept::id_string
const std::string & id_string() const
Definition: irep.h:399
simplify
bool simplify(exprt &expr, const namespacet &ns)
Definition: simplify_expr.cpp:2926
to_pointer_type
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:79
simplify_expr
exprt simplify_expr(exprt src, const namespacet &ns)
Definition: simplify_expr.cpp:2931
value_sett::do_function_call
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:1535
index_exprt::index
exprt & index()
Definition: std_expr.h:1450
irept::get_string
const std::string & get_string(const irep_idt &name) const
Definition: irep.h:409
value_sett::object_map_dt
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:87
index_exprt::array
exprt & array()
Definition: std_expr.h:1440
irept::swap
void swap(irept &irep)
Definition: irep.h:442
to_symbol_expr
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:222
code_typet
Base type of functions.
Definition: std_types.h:538
irept::is_nil
bool is_nil() const
Definition: irep.h:376
irept::id
const irep_idt & id() const
Definition: irep.h:396
to_struct_tag_type
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition: std_types.h:474
range.h
exprt::operandst
std::vector< exprt > operandst
Definition: expr.h:58
dstringt::empty
bool empty() const
Definition: dstring.h:88
unary_exprt::op
const exprt & op() const
Definition: std_expr.h:326
code_typet::parameters
const parameterst & parameters() const
Definition: std_types.h:655
to_dynamic_object_expr
const dynamic_object_exprt & to_dynamic_object_expr(const exprt &expr)
Cast an exprt to a dynamic_object_exprt.
Definition: pointer_expr.h:301
reference_counting< object_map_dt, empty_object_map >
std_code.h
optionalt
nonstd::optional< T > optionalt
Definition: optional.h:35
sharing_mapt::has_key
bool has_key(const key_type &k) const
Check if key is in map.
Definition: sharing_map.h:377
sharing_mapt::insert
void insert(const key_type &k, valueU &&m)
Insert element, element must not exist in map.
Definition: sharing_map.h:1348
to_with_expr
const with_exprt & to_with_expr(const exprt &expr)
Cast an exprt to a with_exprt.
Definition: std_expr.h:2486
side_effect_exprt::get_statement
const irep_idt & get_statement() const
Definition: std_code.h:1472
char_type
bitvector_typet char_type()
Definition: c_types.cpp:124
simplify_expr.h
can_cast_expr< code_outputt >
bool can_cast_expr< code_outputt >(const exprt &base)
Definition: goto_instruction_code.h:482
value_sett::offsett
optionalt< mp_integer > offsett
Represents the offset into an object: either a unique integer offset, or an unknown value,...
Definition: value_set.h:80
value_sett::get_value_set_rec
virtual void get_value_set_rec(const exprt &expr, object_mapt &dest, const std::string &suffix, const typet &original_type, const namespacet &ns) const
Subclass customisation point for recursion over RHS expression:
Definition: value_set.cpp:453
value_sett::entryt::suffix
std::string suffix
Definition: value_set.h:205
exprt::is_zero
bool is_zero() const
Return whether the expression is a constant representing 0.
Definition: expr.cpp:65
member_exprt
Extract member of struct or union.
Definition: std_expr.h:2793
expr_util.h
Deprecated expression utility functions.
dynamic_object_exprt::set_instance
void set_instance(unsigned int instance)
Definition: pointer_expr.cpp:18
format_expr.h
sharing_mapt::replace
void replace(const key_type &k, valueU &&m)
Replace element, element must exist in map.
Definition: sharing_map.h:1425
struct_typet
Structure type, corresponds to C style structs.
Definition: std_types.h:230
value_sett::insert
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:127
pointer_offset_size
optionalt< mp_integer > pointer_offset_size(const typet &type, const namespacet &ns)
Compute the size of a type in bytes, rounding up to full bytes.
Definition: pointer_offset_size.cpp:90
dynamic_object_exprt::valid
exprt & valid()
Definition: pointer_expr.h:273
code_returnt
goto_instruction_codet representation of a "return from a function" statement.
Definition: goto_instruction_code.h:494
value_sett::insert_actiont::INSERT
@ INSERT
value_sett::do_end_function
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:1581
namespace_baset::follow
const typet & follow(const typet &) const
Resolve type symbol to the type it points to.
Definition: namespace.cpp:49
value_sett::insert_actiont::NONE
@ NONE
symbolt
Symbol table entry.
Definition: symbol.h:27
from_integer
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Definition: arith_tools.cpp:100
to_typecast_expr
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition: std_expr.h:2051
value_sett::get_index_of_symbol
optionalt< 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:399
exprt::is_constant
bool is_constant() const
Return whether the expression is a constant.
Definition: expr.cpp:27
value_sett::update_entry
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
reference_counting::read
const T & read() const
Definition: reference_counting.h:69
pointer_typet::base_type
const typet & base_type() const
The type of the data what we point to.
Definition: pointer_expr.h:35
value_sett::get_reference_set
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:1086
to_array_type
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:844
reference_counting::write
T & write()
Definition: reference_counting.h:76
can_cast_expr< code_inputt >
bool can_cast_expr< code_inputt >(const exprt &base)
Definition: goto_instruction_code.h:436
value_sett::field_sensitive
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
to_pointer_offset_expr
const pointer_offset_exprt & to_pointer_offset_expr(const exprt &expr)
Cast an exprt to a pointer_offset_exprt.
Definition: pointer_expr.h:928
to_member_expr
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2886
sharing_mapt::iterate
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
to_address_of_expr
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
Definition: pointer_expr.h:408
exprt::operands
operandst & operands()
Definition: expr.h:94
add_failed_symbols.h
codet::op1
exprt & op1()
Definition: expr.h:128
is_null_pointer
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:315
index_exprt
Array index operator.
Definition: std_expr.h:1409
address_of_exprt
Operator to return the address of an object.
Definition: pointer_expr.h:370
symbol_table.h
Author: Diffblue Ltd.
typecast_exprt
Semantic type conversion.
Definition: std_expr.h:2016
code_returnt::return_value
const exprt & return_value() const
Definition: goto_instruction_code.h:502
object_descriptor_exprt::object
exprt & object()
Definition: pointer_expr.h:193
true_exprt
The Boolean constant true.
Definition: std_expr.h:3007
codet::get_statement
const irep_idt & get_statement() const
Definition: std_code_base.h:65
c_index_type
bitvector_typet c_index_type()
Definition: c_types.cpp:16
sharing_mapt::erase
void erase(const key_type &k)
Erase element, element must exist in map.
Definition: sharing_map.h:1203
value_sett::entryt
Represents a row of a value_sett.
Definition: value_set.h:201
value_sett::erase_values_from_entry
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:1750
with_exprt::where
exprt & where()
Definition: std_expr.h:2444
member_offset
optionalt< mp_integer > member_offset(const struct_typet &type, const irep_idt &member, const namespacet &ns)
Definition: pointer_offset_size.cpp:24
value_sett::to_expr
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:218
to_code_return
const code_returnt & to_code_return(const goto_instruction_codet &code)
Definition: goto_instruction_code.h:537
make_range
ranget< iteratort > make_range(iteratort begin, iteratort end)
Definition: range.h:524
c_types.h
format_type.h
value_sett::apply_assign_side_effects
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:516
value_sett::guard
void guard(const exprt &expr, const namespacet &ns)
Transforms this value-set by assuming an expression holds.
Definition: value_set.cpp:1718
binary_exprt::op0
exprt & op0()
Definition: expr.h:125
validation_modet::INVARIANT
@ INVARIANT
sharing_mapt::find
optionalt< std::reference_wrapper< const mapped_type > > find(const key_type &k) const
Find element.
Definition: sharing_map.h:1451
numberingt< exprt, irep_hash >::number_type
std::size_t number_type
Definition: numbering.h:24
array_typet::element_type
const typet & element_type() const
The type of the elements of the array.
Definition: std_types.h:785
codet
Data structure for representing an arbitrary statement in a program.
Definition: std_code_base.h:28
to_constant_expr
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:2992
object_descriptor_exprt::offset
exprt & offset()
Definition: pointer_expr.h:209
value_sett::values
valuest values
Stores the LHS ID -> RHS expression set map.
Definition: value_set.h:292