CBMC
value_set_dereference.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Symbolic Execution of ANSI-C
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
11 
12 #include "value_set_dereference.h"
13 
14 #ifdef DEBUG
15 #include <iostream>
16 #endif
17 
18 #include <util/arith_tools.h>
19 #include <util/byte_operators.h>
20 #include <util/c_types.h>
21 #include <util/config.h>
22 #include <util/cprover_prefix.h>
23 #include <util/expr_iterator.h>
24 #include <util/expr_util.h>
25 #include <util/format_expr.h>
26 #include <util/fresh_symbol.h>
27 #include <util/json.h>
28 #include <util/message.h>
29 #include <util/namespace.h>
30 #include <util/pointer_expr.h>
33 #include <util/range.h>
34 #include <util/simplify_expr.h>
35 #include <util/symbol.h>
36 
37 #include "dereference_callback.h"
38 
39 #include <deque>
40 
51 static bool should_use_local_definition_for(const exprt &expr)
52 {
53  bool seen_symbol = false;
54  for(auto it = expr.depth_begin(), itend = expr.depth_end(); it != itend; ++it)
55  {
56  if(it->id() == ID_symbol)
57  {
58  if(seen_symbol)
59  return true;
60  else
61  seen_symbol = true;
62  }
63  }
64 
65  return false;
66 }
67 
69  const exprt &pointer,
70  const std::vector<exprt> &points_to_set,
71  const std::vector<exprt> &retained_values,
72  const exprt &value)
73 {
74  json_objectt json_result;
75  json_result["Pointer"] = json_stringt{format_to_string(pointer)};
76  json_result["PointsToSetSize"] =
77  json_numbert{std::to_string(points_to_set.size())};
78 
79  json_arrayt points_to_set_json;
80  for(const auto &object : points_to_set)
81  {
82  points_to_set_json.push_back(json_stringt{format_to_string(object)});
83  }
84 
85  json_result["PointsToSet"] = points_to_set_json;
86 
87  json_result["RetainedValuesSetSize"] =
88  json_numbert{std::to_string(points_to_set.size())};
89 
90  json_arrayt retained_values_set_json;
91  for(auto &retained_value : retained_values)
92  {
93  retained_values_set_json.push_back(
94  json_stringt{format_to_string(retained_value)});
95  }
96 
97  json_result["RetainedValuesSet"] = retained_values_set_json;
98 
99  json_result["Value"] = json_stringt{format_to_string(value)};
100 
101  return json_result;
102 }
103 
107 static std::optional<exprt>
108 try_add_offset_to_indices(const exprt &expr, const exprt &offset_elements)
109 {
110  if(const auto *index_expr = expr_try_dynamic_cast<index_exprt>(expr))
111  {
112  return index_exprt{
113  index_expr->array(),
114  plus_exprt{index_expr->index(),
116  offset_elements, index_expr->index().type())}};
117  }
118  else if(const auto *if_expr = expr_try_dynamic_cast<if_exprt>(expr))
119  {
120  const auto true_case =
121  try_add_offset_to_indices(if_expr->true_case(), offset_elements);
122  if(!true_case)
123  return {};
124  const auto false_case =
125  try_add_offset_to_indices(if_expr->false_case(), offset_elements);
126  if(!false_case)
127  return {};
128  return if_exprt{if_expr->cond(), *true_case, *false_case};
129  }
130  else if(can_cast_expr<typecast_exprt>(expr))
131  {
132  // the case of a type cast is _not_ handled here, because that would require
133  // doing arithmetic on the offset, and may result in an offset into some
134  // sub-element
135  return {};
136  }
137  else
138  {
139  return {};
140  }
141 }
142 
144  const exprt &pointer,
145  bool display_points_to_sets)
146 {
148  pointer.type().id() == ID_pointer,
149  "dereference expected pointer type, but got " + pointer.type().pretty());
150 
151  // we may get ifs due to recursive calls
152  if(pointer.id()==ID_if)
153  {
154  const if_exprt &if_expr=to_if_expr(pointer);
155  exprt true_case = dereference(if_expr.true_case(), display_points_to_sets);
156  exprt false_case =
157  dereference(if_expr.false_case(), display_points_to_sets);
158  return if_exprt(if_expr.cond(), true_case, false_case);
159  }
160  else if(pointer.id() == ID_typecast)
161  {
162  const exprt *underlying = &pointer;
163  // Note this isn't quite the same as skip_typecast, which would also skip
164  // things such as int-to-ptr typecasts which we shouldn't ignore
165  while(underlying->id() == ID_typecast &&
166  underlying->type().id() == ID_pointer)
167  {
168  underlying = &to_typecast_expr(*underlying).op();
169  }
170 
171  if(underlying->id() == ID_if && underlying->type().id() == ID_pointer)
172  {
173  const auto &if_expr = to_if_expr(*underlying);
174  return if_exprt(
175  if_expr.cond(),
176  dereference(
177  typecast_exprt(if_expr.true_case(), pointer.type()),
178  display_points_to_sets),
179  dereference(
180  typecast_exprt(if_expr.false_case(), pointer.type()),
181  display_points_to_sets));
182  }
183  }
184  else if(pointer.id() == ID_plus && pointer.operands().size() == 2)
185  {
186  // Try to improve results for *(p + i) where p points to known offsets but
187  // i is non-constant-- if `p` points to known positions in arrays or array-members
188  // of structs then we can add the non-constant expression `i` to the index
189  // instead of using a byte-extract expression.
190 
191  exprt pointer_expr = to_plus_expr(pointer).op0();
192  exprt offset_expr = to_plus_expr(pointer).op1();
193 
194  if(can_cast_type<pointer_typet>(offset_expr.type()))
195  std::swap(pointer_expr, offset_expr);
196 
197  if(
198  can_cast_type<pointer_typet>(pointer_expr.type()) &&
199  !can_cast_type<pointer_typet>(offset_expr.type()) &&
200  !can_cast_expr<constant_exprt>(offset_expr))
201  {
202  exprt derefd_pointer = dereference(pointer_expr);
203  if(
204  auto derefd_with_offset =
205  try_add_offset_to_indices(derefd_pointer, offset_expr))
206  return *derefd_with_offset;
207 
208  // If any of this fails, fall through to use the normal byte-extract path.
209  }
210  }
211 
212  return handle_dereference_base_case(pointer, display_points_to_sets);
213 }
214 
216  const exprt &pointer,
217  bool display_points_to_sets)
218 { // type of the object
219  const typet &type = to_pointer_type(pointer.type()).base_type();
220 
221  // collect objects the pointer may point to
222  const std::vector<exprt> points_to_set =
224 
225  // get the values of these
226  const std::vector<exprt> retained_values =
227  make_range(points_to_set).filter([&](const exprt &value) {
229  });
230 
231  exprt compare_against_pointer = pointer;
232 
233  if(retained_values.size() >= 2 && should_use_local_definition_for(pointer))
234  {
235  symbolt fresh_binder = get_fresh_aux_symbol(
236  pointer.type(),
237  "derefd_pointer",
238  "derefd_pointer",
239  pointer.find_source_location(),
242 
243  compare_against_pointer = fresh_binder.symbol_expr();
244  }
245 
246  auto values =
247  make_range(retained_values)
248  .map([&](const exprt &value) {
249  return build_reference_to(value, compare_against_pointer, ns);
250  })
251  .collect<std::deque<valuet>>();
252 
253  const bool may_fail =
254  values.empty() ||
255  std::any_of(values.begin(), values.end(), [](const valuet &value) {
256  return value.value.is_nil();
257  });
258 
259  if(may_fail)
260  {
261  values.push_front(get_failure_value(pointer, type));
262  }
263 
264  // now build big case split, but we only do "good" objects
265 
266  exprt result_value = nil_exprt{};
267 
268  for(const auto &value : values)
269  {
270  if(value.value.is_not_nil())
271  {
272  if(result_value.is_nil()) // first?
273  result_value = value.value;
274  else
275  result_value = if_exprt(value.pointer_guard, value.value, result_value);
276  }
277  }
278 
279  if(compare_against_pointer != pointer)
280  result_value =
281  let_exprt(to_symbol_expr(compare_against_pointer), pointer, result_value);
282 
283  if(display_points_to_sets)
284  {
287  pointer, points_to_set, retained_values, result_value);
288  }
289 
290  return result_value;
291 }
292 
294  const exprt &pointer,
295  const typet &type)
296 {
297  // first see if we have a "failed object" for this pointer
298  exprt failure_value;
299 
300  if(
301  const symbolt *failed_symbol =
303  {
304  // yes!
305  failure_value = failed_symbol->symbol_expr();
306  failure_value.set(ID_C_invalid_object, true);
307  }
308  else
309  {
310  // else: produce new symbol
311  symbolt &symbol = get_fresh_aux_symbol(
312  type,
313  "symex",
314  "invalid_object",
315  pointer.source_location(),
318 
319  // make it a lvalue, so we can assign to it
320  symbol.is_lvalue = true;
321 
322  failure_value = symbol.symbol_expr();
323  failure_value.set(ID_C_invalid_object, true);
324  }
325 
326  valuet result{};
327  result.value = failure_value;
328  result.pointer_guard = true_exprt();
329  return result;
330 }
331 
341  const typet &object_type,
342  const typet &dereference_type,
343  const namespacet &ns)
344 {
345  const typet *object_unwrapped = &object_type;
346  const typet *dereference_unwrapped = &dereference_type;
347  while(object_unwrapped->id() == ID_pointer &&
348  dereference_unwrapped->id() == ID_pointer)
349  {
350  object_unwrapped = &to_pointer_type(*object_unwrapped).base_type();
351  dereference_unwrapped =
352  &to_pointer_type(*dereference_unwrapped).base_type();
353  }
354  if(dereference_unwrapped->id() == ID_empty)
355  {
356  return true;
357  }
358  else if(dereference_unwrapped->id() == ID_pointer &&
359  object_unwrapped->id() != ID_pointer)
360  {
361 #ifdef DEBUG
362  std::cout << "value_set_dereference: the dereference type has "
363  "too many ID_pointer levels"
364  << std::endl;
365  std::cout << " object_type: " << object_type.pretty() << std::endl;
366  std::cout << " dereference_type: " << dereference_type.pretty()
367  << std::endl;
368 #endif
369  }
370 
371  if(object_type == dereference_type)
372  return true; // ok, they just match
373 
374  // check for struct prefixes
375 
376  const typet ot_base=ns.follow(object_type),
377  dt_base=ns.follow(dereference_type);
378 
379  if(ot_base.id()==ID_struct &&
380  dt_base.id()==ID_struct)
381  {
382  if(to_struct_type(dt_base).is_prefix_of(
383  to_struct_type(ot_base)))
384  return true; // ok, dt is a prefix of ot
385  }
386 
387  // we are generous about code pointers
388  if(dereference_type.id()==ID_code &&
389  object_type.id()==ID_code)
390  return true;
391 
392  // bitvectors of same width are ok
393  if((dereference_type.id()==ID_signedbv ||
394  dereference_type.id()==ID_unsignedbv) &&
395  (object_type.id()==ID_signedbv ||
396  object_type.id()==ID_unsignedbv) &&
397  to_bitvector_type(dereference_type).get_width()==
398  to_bitvector_type(object_type).get_width())
399  return true;
400 
401  // really different
402 
403  return false;
404 }
405 
420  const exprt &what,
421  bool exclude_null_derefs,
422  const irep_idt &language_mode)
423 {
424  if(what.id() == ID_unknown || what.id() == ID_invalid)
425  {
426  return false;
427  }
428 
430 
431  const exprt &root_object = o.root_object();
432  if(root_object.id() == ID_null_object)
433  {
434  return exclude_null_derefs;
435  }
436  else if(root_object.id() == ID_integer_address)
437  {
438  return language_mode == ID_java;
439  }
440 
441  return false;
442 }
443 
457  const exprt &what,
458  const exprt &pointer_expr,
459  const namespacet &ns)
460 {
461  const pointer_typet &pointer_type =
462  type_checked_cast<pointer_typet>(pointer_expr.type());
463  const typet &dereference_type = pointer_type.base_type();
464 
465  if(what.id()==ID_unknown ||
466  what.id()==ID_invalid)
467  {
468  return valuet();
469  }
470 
472  what.id() == ID_object_descriptor,
473  "unknown points-to: " + what.id_string());
474 
476 
477  const exprt &root_object=o.root_object();
478  const exprt &object=o.object();
479 
480  #if 0
481  std::cout << "O: " << format(root_object) << '\n';
482  #endif
483 
484  if(root_object.id() == ID_null_object)
485  {
486  if(!o.offset().is_zero())
487  return {};
488 
489  valuet result;
491  return result;
492  }
493  else if(root_object.id()==ID_dynamic_object)
494  {
495  valuet result;
496 
497  // constraint that it actually is a dynamic object
498  // this is also our guard
499  result.pointer_guard = is_dynamic_object_exprt(pointer_expr);
500 
501  // can't remove here, turn into *p
502  result.value = dereference_exprt{pointer_expr};
503  result.pointer = pointer_expr;
504 
505  return result;
506  }
507  else if(root_object.id()==ID_integer_address)
508  {
509  // This is stuff like *((char *)5).
510  // This is turned into an access to __CPROVER_memory[...].
511 
512  const symbolt &memory_symbol=ns.lookup(CPROVER_PREFIX "memory");
513  const symbol_exprt symbol_expr(memory_symbol.name, memory_symbol.type);
514 
515  if(to_array_type(memory_symbol.type).element_type() == dereference_type)
516  {
517  // Types match already, what a coincidence!
518  // We can use an index expression.
519 
520  const index_exprt index_expr(
521  symbol_expr,
523  pointer_offset(pointer_expr),
524  to_array_type(memory_symbol.type).index_type()),
525  to_array_type(memory_symbol.type).element_type());
526 
527  valuet result;
528  result.value=index_expr;
529  result.pointer = address_of_exprt{index_expr};
530  return result;
531  }
532  else if(dereference_type_compare(
533  to_array_type(memory_symbol.type).element_type(),
534  dereference_type,
535  ns))
536  {
537  const index_exprt index_expr(
538  symbol_expr,
540  pointer_offset(pointer_expr),
541  to_array_type(memory_symbol.type).index_type()),
542  to_array_type(memory_symbol.type).element_type());
543 
544  valuet result;
545  result.value=typecast_exprt(index_expr, dereference_type);
546  result.pointer =
548  return result;
549  }
550  else
551  {
552  // We need to use byte_extract.
553  // Won't do this without a commitment to an endianness.
554 
556  return {};
557 
558  valuet result;
559  result.value = make_byte_extract(
560  symbol_expr, pointer_offset(pointer_expr), dereference_type);
561  result.pointer = address_of_exprt{result.value};
562  return result;
563  }
564  }
565  else
566  {
567  valuet result;
568 
569  // something generic -- really has to be a symbol
570  address_of_exprt object_pointer(object);
571 
572  if(o.offset().is_zero())
573  {
574  result.pointer_guard = equal_exprt(
575  typecast_exprt::conditional_cast(pointer_expr, object_pointer.type()),
576  object_pointer);
577  }
578  else
579  {
580  result.pointer_guard=same_object(pointer_expr, object_pointer);
581  }
582 
583  const typet &object_type = object.type();
584  const typet &root_object_type = root_object.type();
585 
586  if(
587  dereference_type_compare(object_type, dereference_type, ns) &&
588  o.offset().is_zero())
589  {
590  // The simplest case: types match, and offset is zero!
591  // This is great, we are almost done.
592 
593  result.value = typecast_exprt::conditional_cast(object, dereference_type);
594  result.pointer =
596 
597  return result;
598  }
599 
600  // this is relative to the root object
601  exprt offset;
602  if(o.offset().is_constant())
603  offset = o.offset();
604  else
605  offset = simplify_expr(pointer_offset(pointer_expr), ns);
606 
607  if(
608  root_object_type.id() == ID_array &&
610  to_array_type(root_object_type).element_type(), dereference_type, ns) &&
611  pointer_offset_bits(to_array_type(root_object_type).element_type(), ns) ==
612  pointer_offset_bits(dereference_type, ns) &&
613  offset.is_constant())
614  {
615  // We have an array with a subtype that matches
616  // the dereferencing type.
617 
618  // are we doing a byte?
619  auto element_size =
620  pointer_offset_size(to_array_type(root_object_type).element_type(), ns);
621  CHECK_RETURN(element_size.has_value());
622  CHECK_RETURN(*element_size > 0);
623 
624  const auto offset_int =
625  numeric_cast_v<mp_integer>(to_constant_expr(offset));
626 
627  if(offset_int % *element_size == 0)
628  {
629  index_exprt index_expr{
630  root_object,
631  from_integer(
632  offset_int / *element_size,
633  to_array_type(root_object_type).index_type())};
634  result.value =
635  typecast_exprt::conditional_cast(index_expr, dereference_type);
637  address_of_exprt{index_expr}, pointer_type);
638 
639  return result;
640  }
641  }
642 
643  // try to build a member/index expression - do not use byte_extract
644  auto subexpr = get_subexpression_at_offset(
645  root_object, o.offset(), dereference_type, ns);
646  if(subexpr.has_value())
647  simplify(subexpr.value(), ns);
648  if(
649  subexpr.has_value() &&
650  subexpr.value().id() != ID_byte_extract_little_endian &&
651  subexpr.value().id() != ID_byte_extract_big_endian)
652  {
653  // Successfully found a member, array index, or combination thereof
654  // that matches the desired type and offset:
655  result.value = subexpr.value();
657  address_of_exprt{skip_typecast(subexpr.value())}, pointer_type);
658  return result;
659  }
660 
661  // we extract something from the root object
662  result.value = o.root_object();
665 
666  if(memory_model(result.value, dereference_type, offset, ns))
667  {
668  // set pointer correctly
670  plus_exprt(
672  result.pointer,
674  offset),
675  pointer_type);
676  }
677  else
678  {
679  return {}; // give up, no way that this is ok
680  }
681 
682  return result;
683  }
684 }
685 
686 static bool is_a_bv_type(const typet &type)
687 {
688  return type.id()==ID_unsignedbv ||
689  type.id()==ID_signedbv ||
690  type.id()==ID_bv ||
691  type.id()==ID_fixedbv ||
692  type.id()==ID_floatbv ||
693  type.id()==ID_c_enum_tag;
694 }
695 
705  exprt &value,
706  const typet &to_type,
707  const exprt &offset,
708  const namespacet &ns)
709 {
710  // we will allow more or less arbitrary pointer type cast
711 
712  const typet from_type=value.type();
713 
714  // first, check if it's really just a type coercion,
715  // i.e., both have exactly the same (constant) size,
716  // for bit-vector types or pointers
717 
718  if(
719  (is_a_bv_type(from_type) && is_a_bv_type(to_type)) ||
720  (from_type.id() == ID_pointer && to_type.id() == ID_pointer))
721  {
723  {
724  // avoid semantic conversion in case of
725  // cast to float or fixed-point,
726  // or cast from float or fixed-point
727 
728  if(
729  to_type.id() != ID_fixedbv && to_type.id() != ID_floatbv &&
730  from_type.id() != ID_fixedbv && from_type.id() != ID_floatbv)
731  {
732  value = typecast_exprt::conditional_cast(value, to_type);
733  return true;
734  }
735  }
736  }
737 
738  // otherwise, we will stitch it together from bytes
739 
740  return memory_model_bytes(value, to_type, offset, ns);
741 }
742 
752  exprt &value,
753  const typet &to_type,
754  const exprt &offset,
755  const namespacet &ns)
756 {
757  const typet from_type=value.type();
758 
759  // We simply refuse to convert to/from code.
760  if(from_type.id()==ID_code || to_type.id()==ID_code)
761  return false;
762 
763  // We won't do this without a commitment to an endianness.
765  return false;
766 
767  // But everything else we will try!
768  // We just rely on byte_extract to do the job!
769 
770  exprt result;
771 
772  // See if we have an array of bytes already,
773  // and we want something byte-sized.
774  auto from_type_element_type_size =
775  from_type.id() == ID_array
776  ? pointer_offset_size(to_array_type(from_type).element_type(), ns)
777  : std::optional<mp_integer>{};
778 
779  auto to_type_size = pointer_offset_size(to_type, ns);
780 
781  if(
782  from_type.id() == ID_array && from_type_element_type_size.has_value() &&
783  *from_type_element_type_size == 1 && to_type_size.has_value() &&
784  *to_type_size == 1 &&
785  is_a_bv_type(to_array_type(from_type).element_type()) &&
786  is_a_bv_type(to_type))
787  {
788  // yes, can use 'index', but possibly need to convert
790  index_exprt(
791  value,
793  offset, to_array_type(from_type).index_type()),
794  to_array_type(from_type).element_type()),
795  to_type);
796  }
797  else
798  {
799  // no, use 'byte_extract'
800  result = make_byte_extract(value, offset, to_type);
801  }
802 
803  value=result;
804 
805  return true;
806 }
configt config
Definition: config.cpp:25
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
byte_extract_exprt make_byte_extract(const exprt &_op, const exprt &_offset, const typet &_type)
Construct a byte_extract_exprt with endianness and byte width matching the current configuration.
Expression classes for byte-level operators.
pointer_typet pointer_type(const typet &subtype)
Definition: c_types.cpp:235
bitvector_typet char_type()
Definition: c_types.cpp:106
Operator to return the address of an object.
Definition: pointer_expr.h:540
typet index_type() const
The type of the index expressions into any instance of this type.
Definition: std_types.cpp:33
const typet & element_type() const
The type of the elements of the array.
Definition: std_types.h:827
std::size_t get_width() const
Definition: std_types.h:920
struct configt::ansi_ct ansi_c
virtual const symbolt * get_or_create_failed_symbol(const exprt &expr)=0
virtual std::vector< exprt > get_value_set(const exprt &expr) const =0
Operator to dereference a pointer.
Definition: pointer_expr.h:834
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
Equality.
Definition: std_expr.h:1361
Base class for all expressions.
Definition: expr.h:56
const source_locationt & find_source_location() const
Get a source_locationt from the expression or from its operands (non-recursively).
Definition: expr.cpp:147
depth_iteratort depth_end()
Definition: expr.cpp:249
depth_iteratort depth_begin()
Definition: expr.cpp:247
const source_locationt & source_location() const
Definition: expr.h:231
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
The trinary if-then-else operator.
Definition: std_expr.h:2370
exprt & true_case()
Definition: std_expr.h:2397
exprt & false_case()
Definition: std_expr.h:2407
exprt & cond()
Definition: std_expr.h:2387
Array index operator.
Definition: std_expr.h:1465
exprt & array()
Definition: std_expr.h:1495
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
Definition: irep.cpp:482
const std::string & id_string() const
Definition: irep.h:387
void set(const irep_idt &name, const irep_idt &value)
Definition: irep.h:408
bool is_not_nil() const
Definition: irep.h:368
const irep_idt & id() const
Definition: irep.h:384
bool is_nil() const
Definition: irep.h:364
Evaluates to true if the operand is a pointer to a dynamic object.
Definition: pointer_expr.h:335
jsont & push_back(const jsont &json)
Definition: json.h:212
A let expression.
Definition: std_expr.h:3196
Class that provides messages with a built-in verbosity 'level'.
Definition: message.h:155
exprt & op1()
Definition: std_expr.h:938
exprt & op0()
Definition: std_expr.h:932
const typet & follow(const typet &) const
Resolve type symbol to the type it points to.
Definition: namespace.cpp:49
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Definition: namespace.cpp:148
The NIL expression.
Definition: std_expr.h:3073
The null pointer constant.
Definition: pointer_expr.h:909
Split an expression into a base object and a (byte) offset.
Definition: pointer_expr.h:181
static const exprt & root_object(const exprt &expr)
The plus expression Associativity is not specified.
Definition: std_expr.h:1002
The pointer type These are both 'bitvector_typet' (they have a width) and 'type_with_subtypet' (they ...
Definition: pointer_expr.h:24
const typet & base_type() const
The type of the data what we point to.
Definition: pointer_expr.h:35
Expression to hold a symbol (variable)
Definition: std_expr.h:131
Symbol table entry.
Definition: symbol.h:28
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
Definition: symbol.cpp:121
typet type
Type of symbol.
Definition: symbol.h:31
irep_idt name
The unique identifier.
Definition: symbol.h:40
bool is_lvalue
Definition: symbol.h:72
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
Return value for build_reference_to; see that method for documentation.
static bool memory_model_bytes(exprt &value, const typet &type, const exprt &offset, const namespacet &ns)
Replace value by an expression of type to_type corresponding to the value at memory address value + o...
valuet get_failure_value(const exprt &pointer, const typet &type)
exprt handle_dereference_base_case(const exprt &pointer, bool display_points_to_sets)
const bool exclude_null_derefs
Flag indicating whether value_set_dereferencet::dereference should disregard an apparent attempt to d...
symbol_table_baset & new_symbol_table
static bool dereference_type_compare(const typet &object_type, const typet &dereference_type, const namespacet &ns)
Check if the two types have matching number of ID_pointer levels, with the dereference type eventuall...
message_handlert & message_handler
dereference_callbackt & dereference_callback
exprt dereference(const exprt &pointer, bool display_points_to_sets=false)
Dereference the given pointer-expression.
const irep_idt language_mode
language_mode: ID_java, ID_C or another language identifier if we know the source language in use,...
static valuet build_reference_to(const exprt &what, const exprt &pointer, const namespacet &ns)
static bool should_ignore_value(const exprt &what, bool exclude_null_derefs, const irep_idt &language_mode)
Determine whether possible alias what should be ignored when replacing a pointer by its referees.
static bool memory_model(exprt &value, const typet &type, const exprt &offset, const namespacet &ns)
Replace value by an expression of type to_type corresponding to the value at memory address value + o...
#define CPROVER_PREFIX
Pointer Dereferencing.
Forward depth-first search iterators These iterators' copy operations are expensive,...
const exprt & skip_typecast(const exprt &expr)
find the expression nested inside typecasts, if any
Definition: expr_util.cpp:219
Deprecated expression utility functions.
std::string format_to_string(const T &o)
Definition: format.h:43
static format_containert< T > format(const T &o)
Definition: format.h:37
symbolt & get_fresh_aux_symbol(const typet &type, const std::string &name_prefix, const std::string &basename_prefix, const source_locationt &source_location, const irep_idt &symbol_mode, const namespacet &ns, symbol_table_baset &symbol_table)
Installs a fresh-named symbol with respect to the given namespace ns with the requested name pattern ...
Fresh auxiliary symbol creation.
std::string from_type(const namespacet &ns, const irep_idt &identifier, const typet &type)
double log(double x)
Definition: math.c:2776
API to expression classes for Pointers.
bool can_cast_type< pointer_typet >(const typet &type)
Check whether a reference to a typet is a pointer_typet.
Definition: pointer_expr.h:80
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:93
const object_descriptor_exprt & to_object_descriptor_expr(const exprt &expr)
Cast an exprt to an object_descriptor_exprt.
Definition: pointer_expr.h:252
std::optional< mp_integer > pointer_offset_bits(const typet &type, const namespacet &ns)
std::optional< exprt > get_subexpression_at_offset(const exprt &expr, const mp_integer &offset_bytes, const typet &target_type_raw, 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.
exprt pointer_offset(const exprt &pointer)
exprt same_object(const exprt &p1, const exprt &p2)
Various predicates over pointers in programs.
Ranges: pair of begin and end iterators, which can be initialized from containers,...
ranget< iteratort > make_range(iteratort begin, iteratort end)
Definition: range.h:522
bool simplify(exprt &expr, const namespacet &ns)
exprt simplify_expr(exprt src, const namespacet &ns)
#define PRECONDITION_WITH_DIAGNOSTICS(CONDITION,...)
Definition: invariant.h:464
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:495
bool can_cast_expr< typecast_exprt >(const exprt &base)
Definition: std_expr.h:2086
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition: std_expr.h:2450
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
bool can_cast_expr< constant_exprt >(const exprt &base)
Definition: std_expr.h:3021
const plus_exprt & to_plus_expr(const exprt &expr)
Cast an exprt to a plus_exprt.
Definition: std_expr.h:1041
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:888
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
endiannesst endianness
Definition: config.h:207
Symbol table entry.
static bool is_a_bv_type(const typet &type)
static json_objectt value_set_dereference_stats_to_json(const exprt &pointer, const std::vector< exprt > &points_to_set, const std::vector< exprt > &retained_values, const exprt &value)
static bool should_use_local_definition_for(const exprt &expr)
Returns true if expr is complicated enough that a local definition (using a let expression) is prefer...
static std::optional< exprt > try_add_offset_to_indices(const exprt &expr, const exprt &offset_elements)
If expr is of the form (c1 ? e1[o1] : c2 ? e2[o2] : c3 ? ...) then return c1 ? e1[o1 + offset] : e2[o...
Pointer Dereferencing.