CBMC
simplify_state_expr.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Simplify State Expressions
4 
5 Author: Daniel Kroening, dkr@amazon.com
6 
7 \*******************************************************************/
8 
11 
12 #include "simplify_state_expr.h"
13 
14 #include <util/arith_tools.h>
15 #include <util/c_types.h>
16 #include <util/expr_util.h>
17 #include <util/namespace.h>
20 #include <util/simplify_expr.h>
21 #include <util/std_expr.h>
22 #include <util/symbol.h>
23 
24 #include "may_alias.h"
25 #include "may_be_same_object.h"
26 #include "sentinel_dll.h"
27 #include "state.h"
28 
29 std::size_t allocate_counter = 0;
30 
32  exprt,
33  const std::unordered_set<symbol_exprt, irep_hash> &address_taken,
34  const namespacet &);
35 
36 static bool types_are_compatible(const typet &a, const typet &b)
37 {
38  if(a == b)
39  return true;
40  else if(a.id() == ID_pointer && b.id() == ID_pointer)
41  return true;
42  else
43  return false;
44 }
45 
47  evaluate_exprt evaluate_expr,
48  const std::unordered_set<symbol_exprt, irep_hash> &address_taken,
49  const namespacet &ns)
50 {
51  PRECONDITION(evaluate_expr.state().id() == ID_update_state);
52 
53  const auto &update_state_expr = to_update_state_expr(evaluate_expr.state());
54 
55 #if 0
56  std::cout << "U: " << format(update_state_expr) << "\n";
57  std::cout << "u: " << format(update_state_expr.address()) << "\n";
58  std::cout << "T: " << format(update_state_expr.address().type()) << "\n";
59  std::cout << "E: " << format(evaluate_expr.address()) << "\n";
60  std::cout << "T: " << format(evaluate_expr.address().type()) << "\n";
61 #endif
62 
63  auto may_alias = ::may_alias(
64  evaluate_expr.address(), update_state_expr.address(), address_taken, ns);
65 
66 #if 0
67  if(may_alias.has_value())
68  std::cout << "M: " << format(*may_alias) << "\n";
69  else
70  std::cout << "M: ?\n";
71 #endif
72 
73  if(may_alias.has_value())
74  {
75  // 'simple' case
76  if(may_alias->is_true())
77  {
78  // The object is known to be the same.
79  // (ς[A:=V])(A) --> V
82  update_state_expr.new_value(), evaluate_expr.type()),
84  ns);
85  }
86  else if(may_alias->is_false())
87  {
88  // The object is known to be different.
89  // (ς[❝x❞:=V])(❝y❞) --> ς(❝y❞)
90  // It might be possible to further simplify ς(❝y❞).
92  evaluate_expr.with_state(update_state_expr.state()), address_taken, ns);
93  }
94  else
95  {
96  // The object may or may not be the same.
97  // (ς[A:=V])(B) --> if cond then V else ς(B) endif
98  auto simplified_cond = simplify_state_expr(*may_alias, address_taken, ns);
99  auto new_evaluate_expr =
100  evaluate_expr.with_state(update_state_expr.state());
101  auto simplified_new_evaluate_expr = simplify_state_expr_node(
102  new_evaluate_expr, address_taken, ns); // rec. call
103  auto if_expr = if_exprt(
104  std::move(simplified_cond),
107  update_state_expr.new_value(), evaluate_expr.type()),
109  ns),
110  std::move(simplified_new_evaluate_expr));
111  return simplify_expr(if_expr, ns);
112  }
113  }
114 
115  auto new_evaluate_expr = evaluate_expr.with_state(update_state_expr.state());
116  auto simplified_new_evaluate_expr =
117  simplify_state_expr(new_evaluate_expr, address_taken, ns); // rec. call
118 
119  // Types are compatible?
121  update_state_expr.new_value().type(), evaluate_expr.type()))
122  {
123  // Disregard case where the two memory regions overlap.
124  //
125  // (ς[w:=v])(r) -->
126  // IF same_object(w, r) ∧ offset(w) = offset(r) THEN
127  // v
128  // ELSE
129  // ς(r)
130  // ENDIF
131  auto same_object =
132  ::same_object(evaluate_expr.address(), update_state_expr.address());
133 
134  auto simplified_same_object =
136 
137  auto offset_w = simplify_state_expr(
138  pointer_offset(evaluate_expr.address()), address_taken, ns);
139 
140  auto offset_r = simplify_state_expr(
141  pointer_offset(update_state_expr.address()), address_taken, ns);
142 
143  auto same_offset = equal_exprt(offset_w, offset_r);
144 
145  auto same = and_exprt(simplified_same_object, same_offset);
146 
147  auto simplified_same =
149 
150  auto new_value = typecast_exprt::conditional_cast(
151  update_state_expr.new_value(), evaluate_expr.type());
152 
153  auto if_expr =
154  if_exprt(simplified_same, new_value, simplified_new_evaluate_expr);
155 
156  return simplify_expr(if_expr, ns);
157  }
158  else
159  {
160  // Complex case. Types don't match.
161  return simplified_new_evaluate_expr;
162 
163 #if 0
164  auto object = update_state_expr.new_value();
165 
166  auto offset = simplify_state_expr_node(
167  pointer_offset(evaluate_expr.address()), address_taken, ns);
168 
169  auto byte_extract = make_byte_extract(object, offset, evaluate_expr.type());
170 
171  return if_exprt(
172  std::move(simplified_same_object),
173  std::move(byte_extract),
174  std::move(simplified_new_evaluate_expr));
175 #endif
176  }
177 }
178 
180 {
181  // A store does not affect the result.
182  // allocate(ς[A:=V]), size) --> allocate(ς, size)
183  if(src.state().id() == ID_update_state)
184  {
185  // rec. call
186  return simplify_allocate(
188  }
189  else if(src.state().id() == ID_enter_scope_state)
190  {
191  // rec. call
192  return simplify_allocate(
194  }
195  else if(src.state().id() == ID_exit_scope_state)
196  {
197  // rec. call
198  return simplify_allocate(
200  }
201 
202  return std::move(src);
203 }
204 
206  evaluate_exprt evaluate_expr,
207  const namespacet &ns)
208 {
209  PRECONDITION(evaluate_expr.state().id() == ID_allocate_state);
210 
211  // const auto &allocate_expr = to_allocate_expr(evaluate_expr.state());
212 
213 #if 0
214  // Same address?
215  if(evaluate_expr.address() == allocate_expr.address())
216  {
217 # if 0
218  irep_idt identifier = "allocate-" + std::to_string(++allocate_counter);
219  auto object_size = allocate_expr.size();
220  auto object_type = array_typet(char_type(), object_size);
221  auto symbol_expr = symbol_exprt(identifier, object_type);
222  return object_address_exprt(symbol_expr);
223 # endif
224  return std::move(evaluate_expr);
225  }
226  else // different
227  {
228  auto new_evaluate_expr = evaluate_expr;
229  new_evaluate_expr.state() = allocate_expr.state();
230  return std::move(new_evaluate_expr);
231  }
232 #endif
233  return std::move(evaluate_expr);
234 }
235 
237  evaluate_exprt evaluate_expr,
238  const namespacet &ns)
239 {
240  PRECONDITION(evaluate_expr.state().id() == ID_deallocate_state);
241 
242  // deallocate isn't visible to 'evaluate'
243  const auto &deallocate_state_expr =
244  to_deallocate_state_expr(evaluate_expr.state());
245  auto new_evaluate_expr =
246  evaluate_expr.with_state(deallocate_state_expr.state());
247  return std::move(new_evaluate_expr);
248 }
249 
251  evaluate_exprt evaluate_expr,
252  const namespacet &ns)
253 {
254  PRECONDITION(evaluate_expr.state().id() == ID_enter_scope_state);
255 
256  const auto &enter_scope_state_expr =
257  to_enter_scope_state_expr(evaluate_expr.state());
258  auto new_evaluate_expr =
259  evaluate_expr.with_state(enter_scope_state_expr.state());
260  return std::move(new_evaluate_expr);
261 }
262 
264  evaluate_exprt evaluate_expr,
265  const namespacet &ns)
266 {
267  PRECONDITION(evaluate_expr.state().id() == ID_exit_scope_state);
268 
269  const auto &exit_scope_state_expr =
270  to_exit_scope_state_expr(evaluate_expr.state());
271  auto new_evaluate_expr =
272  evaluate_expr.with_state(exit_scope_state_expr.state());
273  return std::move(new_evaluate_expr);
274 }
275 
277 {
278  if(src.id() == ID_object_address)
279  return src;
280  else if(src.id() == ID_element_address)
282  else if(src.id() == ID_field_address)
284  else if(src.id() == ID_plus)
285  {
286  const auto &plus_expr = to_plus_expr(src);
287  for(auto &op : plus_expr.operands())
288  if(op.type().id() == ID_pointer)
290  return src; // no change
291  }
292  else if(src.id() == ID_typecast)
293  {
294  const auto &op = to_typecast_expr(src).op();
295  if(op.type().id() == ID_pointer)
297  else
298  return src; // no change
299  }
300  else
301  return src;
302 }
303 
305 {
306  return simplify_object_expression_rec(src);
307 }
308 
311  const std::unordered_set<symbol_exprt, irep_hash> &address_taken,
312  const namespacet &ns)
313 {
314  const auto &pointer = src.address();
315 
316  auto object = simplify_object_expression(pointer);
317 
318  if(object.id() == ID_object_address)
319  {
320  auto identifier = to_object_address_expr(object).object_identifier();
321 
322  if(identifier.starts_with("allocate-"))
323  {
324  }
325  else if(identifier == "return_value")
326  {
327  return true_exprt(); // never dies
328  }
329  else if(identifier.starts_with("va_args::"))
330  {
331  return true_exprt(); // might be 'dead'
332  }
333  else
334  {
335  const auto &symbol = ns.lookup(identifier);
336  if(symbol.is_static_lifetime)
337  {
338  return true_exprt(); // always live
339  }
340  }
341  }
342 
343  // A store does not affect the result.
344  // live_object(ς[A:=V]), p) --> live_object(ς, p)
345  if(src.state().id() == ID_update_state)
346  {
347  src.state() = to_update_state_expr(src.state()).state();
348 
349  // rec. call
350  return simplify_live_object_expr(std::move(src), address_taken, ns);
351  }
352  else if(src.state().id() == ID_deallocate_state)
353  {
354  const auto &deallocate_state_expr = to_deallocate_state_expr(src.state());
355  // live_object(deallocate_state(ς, p), q) -->
356  // IF same_object(p, q) THEN false ELSE live_object(ς, q) ENDIF
357  auto same_object = ::same_object(object, deallocate_state_expr.address());
358  auto simplified_same_object =
360  auto new_live_object_expr = simplify_live_object_expr(
361  src.with_state(deallocate_state_expr.state()), address_taken, ns);
362  return if_exprt(
363  simplified_same_object, false_exprt(), new_live_object_expr);
364  }
365  else if(src.state().id() == ID_enter_scope_state)
366  {
367  // This begins the life of a local-scoped variable.
368  const auto &enter_scope_state_expr = to_enter_scope_state_expr(src.state());
369  if(
370  address_taken.find(enter_scope_state_expr.symbol()) !=
371  address_taken.end())
372  {
373  // live_object(enter_scope_state(ς, p), q) -->
374  // IF same_object(p, q) THEN true ELSE live_object(ς, q) ENDIF
375  auto same_object =
376  ::same_object(object, enter_scope_state_expr.address());
377  auto simplified_same_object =
379  auto new_live_object_expr = simplify_live_object_expr( // rec. call
380  src.with_state(enter_scope_state_expr.state()),
382  ns);
383  return if_exprt(
384  simplified_same_object, true_exprt(), new_live_object_expr);
385  }
386  else
387  {
388  return simplify_live_object_expr( // rec. call
389  src.with_state(enter_scope_state_expr.state()),
391  ns);
392  }
393  }
394  else if(src.state().id() == ID_exit_scope_state)
395  {
396  // This ends the life of a local-scoped variable.
397  const auto &exit_scope_state_expr = to_exit_scope_state_expr(src.state());
398  if(
399  address_taken.find(exit_scope_state_expr.symbol()) != address_taken.end())
400  {
401  // live_object(exit_scope_state(ς, p), q) -->
402  // IF same_object(p, q) THEN false ELSE live_object(ς, q) ENDIF
403  auto same_object = ::same_object(object, exit_scope_state_expr.address());
404  auto simplified_same_object =
406  auto new_live_object_expr = simplify_live_object_expr( // rec. call
407  src.with_state(exit_scope_state_expr.state()),
409  ns);
410  return if_exprt(
411  simplified_same_object, false_exprt(), new_live_object_expr);
412  }
413  else
414  {
415  return simplify_live_object_expr( // rec. call
416  src.with_state(exit_scope_state_expr.state()),
418  ns);
419  }
420  }
421 
422  return std::move(src);
423 }
424 
427  const namespacet &ns)
428 {
429  const auto &pointer = src.address();
430 
431  auto object = simplify_object_expression(pointer);
432 
433  if(object.id() == ID_object_address)
434  {
435  auto identifier = to_object_address_expr(object).object_identifier();
436 
437  if(identifier.starts_with("allocate-"))
438  {
439  }
440  else if(identifier.starts_with("va_args::"))
441  {
442  return true_exprt(); // always writeable
443  }
444  else
445  {
446  const auto &symbol = ns.lookup(identifier);
447  return make_boolean_expr(!symbol.type.get_bool(ID_C_constant));
448  }
449  }
450 
451  // A store does not affect the result.
452  // writeable_object(ς[A:=V]), p) --> writeable_object(ς, p)
453  if(src.state().id() == ID_update_state)
454  {
455  src.state() = to_update_state_expr(src.state()).state();
456  return std::move(src);
457  }
458 
459  return std::move(src);
460 }
461 
463 {
464  const auto &pointer = src.address();
465 
466  auto object = simplify_object_expression(pointer);
467 
468  if(object.id() == ID_object_address)
469  {
470  // these are not dynamic
471  return false_exprt();
472  }
473 
474  // A store does not affect the result.
475  // is_dynamic_object(ς[A:=V]), p) --> is_dynamic_object(ς, p)
476  if(src.state().id() == ID_update_state)
477  {
478  src.state() = to_update_state_expr(src.state()).state();
479  // rec. call
480  return simplify_is_dynamic_object_expr(std::move(src));
481  }
482  else if(src.state().id() == ID_enter_scope_state)
483  {
486  }
487  else if(src.state().id() == ID_exit_scope_state)
488  {
491  }
492 
493  return std::move(src);
494 }
495 
498  const namespacet &ns)
499 {
500  const auto &pointer = src.address();
501 
502  auto object = simplify_object_expression(pointer);
503 
504  if(object.id() == ID_object_address)
505  {
506  const auto &object_address_expr = to_object_address_expr(object);
507  auto size_opt = size_of_expr(object_address_expr.object_type(), ns);
508  if(size_opt.has_value())
509  return typecast_exprt::conditional_cast(*size_opt, src.type());
510  else
511  return std::move(src); // no change
512  }
513 
514  // A store does not affect the result.
515  // object_size(ς[A:=V]), p) --> object_size(ς, p)
516  if(src.state().id() == ID_update_state)
517  {
518  return src.with_state(to_update_state_expr(src.state()).state());
519  }
520 
521  return std::move(src);
522 }
523 
525  state_ok_exprt src,
526  const std::unordered_set<symbol_exprt, irep_hash> &address_taken,
527  const namespacet &ns)
528 {
529  auto &state = src.state();
530  auto &pointer = src.address();
531  auto &size = src.size();
532 
533  if(state.id() == ID_update_state)
534  {
535  // A store does not affect the result.
536  // X_ok(ς[A:=V]), A, S) --> X_ok(ς, A, S)
537  state = to_update_state_expr(state).state();
538 
539  // rec. call
540  return simplify_state_expr_node(std::move(src), address_taken, ns);
541  }
542  else if(state.id() == ID_enter_scope_state)
543  {
544  const auto &enter_scope_state_expr = to_enter_scope_state_expr(state);
545 
546  // rec. call
547  auto rec_result = simplify_state_expr_node(
548  src.with_state(enter_scope_state_expr.state()), address_taken, ns);
549 
550 #if 0
551  // replace array by array[0]
552  auto enter_scope_address =
553  enter_scope_state_expr.object_type().id() == ID_array ?
554  element_address_exprt(enter_scope_state_expr.address(), from_integer(0, to_array_type(enter_scope_state_expr.object_type()).index_type())) :
555  enter_scope_state_expr.address();
556 
557  auto may_alias =
558  ::may_alias(enter_scope_address, pointer, address_taken, ns);
559 
560  if(may_alias.has_value() && *may_alias == false_exprt())
561  return rec_result;
562 
563  auto same_object = ::same_object(pointer, enter_scope_state_expr.address());
564 #else
566  pointer, enter_scope_state_expr.address(), address_taken, ns);
567 #endif
568 
569  auto simplified_same_object =
571 
572  // Known to be live, only need to check upper bound.
573  // Extend one bit, to cover overflow case.
574  auto size_type = ::size_type();
575  auto size_type_ext = unsignedbv_typet(size_type.get_width() + 1);
576  auto offset = pointer_offset_exprt(pointer, size_type_ext);
577  auto size_casted = typecast_exprt(size, size_type_ext);
578  auto object_size_opt =
579  size_of_expr(enter_scope_state_expr.object_type(), ns);
580  if(!object_size_opt.has_value())
581  return std::move(src);
582 
583  auto upper = binary_relation_exprt(
584  plus_exprt(offset, size_casted),
585  ID_le,
586  typecast_exprt(*object_size_opt, size_type_ext));
587 
588  auto simplified_upper = simplify_state_expr(upper, address_taken, ns);
589 
590  auto implication =
591  if_exprt(simplified_same_object, simplified_upper, rec_result);
592 
593  return std::move(implication);
594  }
595  else if(state.id() == ID_exit_scope_state)
596  {
597 #if 0
598  const auto &exit_scope_state_expr = to_exit_scope_state_expr(state);
599 
600  // rec. call
601  auto rec_result = simplify_state_expr_node(
602  src.with_state(exit_scope_state_expr.state()), address_taken, ns);
603 
604  auto same_object = ::same_object(pointer, exit_scope_state_expr.address());
605 
606  auto simplified_same_object =
608 
609  // Known to be dead if it's the same object.
610  auto implication =
611  if_exprt(simplified_same_object, false_exprt(), rec_result);
612 
613  return implication;
614 #else
616  src.with_state(to_exit_scope_state_expr(state).state()),
618  ns);
619 #endif
620  }
621 
622  return std::move(src);
623 }
624 
625 #if 0
626 static bool is_one(const exprt &src)
627 {
628  if(src.id() == ID_typecast)
629  return is_one(to_typecast_expr(src).op());
630  else if(src.is_constant())
631  {
632  auto value_opt = numeric_cast<mp_integer>(src);
633  return value_opt.has_value() && *value_opt == 1;
634  }
635  else
636  return false;
637 }
638 #endif
639 
640 static bool is_a_char_type(const typet &type)
641 {
642  return (type.id() == ID_signedbv || type.id() == ID_unsignedbv) &&
644 }
645 
646 static bool is_zero_char(const exprt &src, const namespacet &ns)
647 {
648  if(!is_a_char_type(src.type()))
649  return false;
650 
651  auto src_simplified = simplify_expr(src, ns);
652 
653  auto integer_opt = numeric_cast<mp_integer>(src);
654 
655  return integer_opt.has_value() && *integer_opt == 0;
656 }
657 
660  const std::unordered_set<symbol_exprt, irep_hash> &address_taken,
661  const namespacet &ns)
662 {
663  PRECONDITION(src.type().id() == ID_bool);
664  const auto &state = src.state();
665  const auto &pointer = src.address();
666 
667  if(state.id() == ID_update_state)
668  {
669  const auto &update_state_expr = to_update_state_expr(state);
670 
671  auto cstring_in_old_state = src;
672  cstring_in_old_state.op0() = update_state_expr.state();
673  auto simplified_cstring_in_old_state =
674  simplify_state_expr_node(cstring_in_old_state, address_taken, ns);
675 
676  auto may_alias =
677  ::may_alias(pointer, update_state_expr.address(), address_taken, ns);
678 
679  if(may_alias.has_value() && may_alias->is_false())
680  {
681  // different objects
682  // cstring(s[x:=v], p) --> cstring(s, p)
683  return simplified_cstring_in_old_state;
684  }
685 
686  // maybe the same
687 
688  // Are we writing zero?
689  if(update_state_expr.new_value().is_zero())
690  {
691  // cstring(s[p:=0], q) --> if p alias q then true else cstring(s, q)
692  auto same_object = ::same_object(pointer, update_state_expr.address());
693 
694  auto simplified_same_object =
696 
697  return if_exprt(
698  simplified_same_object, true_exprt(), simplified_cstring_in_old_state);
699  }
700  }
701  else if(state.id() == ID_enter_scope_state)
702  {
703  // rec. call
705  src.with_state(to_enter_scope_state_expr(state).state()),
707  ns);
708  }
709  else if(state.id() == ID_exit_scope_state)
710  {
711  // rec. call
713  src.with_state(to_exit_scope_state_expr(state).state()),
715  ns);
716  }
717 
718  if(pointer.id() == ID_plus)
719  {
720 #if 0
721  auto &plus_expr = to_plus_expr(pointer);
722  if(plus_expr.operands().size() == 2 && is_one(plus_expr.op1()))
723  {
724  // is_cstring(ς, p + 1)) --> is_cstring(ς, p) ∨ ς(p)=0
725  auto new_is_cstring = src;
726  new_is_cstring.op1() = plus_expr.op0();
727  auto type = to_pointer_type(pointer.type()).base_type();
728  auto zero = from_integer(0, type);
729  auto is_zero =
730  equal_exprt(evaluate_exprt(state, plus_expr.op0(), type), zero);
731  return or_exprt(new_is_cstring, is_zero);
732  }
733 #endif
734  }
735  else if(
736  pointer.id() == ID_address_of &&
737  to_address_of_expr(pointer).object().id() == ID_string_constant)
738  {
739  // is_cstring(ς, &"...")) --> true
740  return true_exprt();
741  }
742  else if(
743  pointer.id() == ID_element_address &&
744  to_element_address_expr(pointer).base().id() == ID_address_of &&
745  to_address_of_expr(to_element_address_expr(pointer).base()).object().id() ==
746  ID_string_constant)
747  {
748  // TODO: compare offset to length
749  // is_cstring(ς, element_address(&"...", 0))) --> true
750  return true_exprt();
751  }
752 
753  return std::move(src);
754 }
755 
758  const std::unordered_set<symbol_exprt, irep_hash> &address_taken,
759  const namespacet &ns)
760 {
761  const auto &state = src.state();
762  const auto &pointer = src.address();
763 
764  if(state.id() == ID_update_state)
765  {
766  const auto &update_state_expr = to_update_state_expr(state);
767 
768  auto cstrlen_in_old_state = src.with_state(update_state_expr.state());
769  auto simplified_cstrlen_in_old_state =
770  simplify_state_expr_node(cstrlen_in_old_state, address_taken, ns);
771 
773  pointer, update_state_expr.address(), address_taken, ns);
774 
776  {
777  // different objects
778  // cstrlen(s[x:=v], p) --> cstrlen(s, p)
779  return simplified_cstrlen_in_old_state;
780  }
781 
782  // maybe the same
783 
784  // Are we writing zero?
785  if(is_zero_char(update_state_expr.new_value(), ns))
786  {
787  // cstrlen(s[p:=0], p) --> 0
788  if(pointer == update_state_expr.address())
789  return from_integer(0, src.type());
790  }
791  }
792 
793  if(pointer.id() == ID_plus)
794  {
795 #if 0
796  auto &plus_expr = to_plus_expr(pointer);
797  if(plus_expr.operands().size() == 2 && is_one(plus_expr.op1()))
798  {
799  // is_cstring(ς, p + 1)) --> is_cstring(ς, p) ∨ ς(p)=0
800  auto new_is_cstring = src;
801  new_is_cstring.op1() = plus_expr.op0();
802  auto type = to_pointer_type(pointer.type()).base_type();
803  auto zero = from_integer(0, type);
804  auto is_zero =
805  equal_exprt(evaluate_exprt(state, plus_expr.op0(), type), zero);
806  return or_exprt(new_is_cstring, is_zero);
807  }
808 #endif
809  }
810  else if(
811  pointer.id() == ID_address_of &&
812  to_address_of_expr(pointer).object().id() == ID_string_constant)
813  {
814 #if 0
815  // is_cstring(ς, &"...")) --> true
816  return true_exprt();
817 #endif
818  }
819  else if(
820  pointer.id() == ID_element_address &&
821  to_element_address_expr(pointer).base().id() == ID_address_of &&
822  to_address_of_expr(to_element_address_expr(pointer).base()).object().id() ==
823  ID_string_constant)
824  {
825 #if 0
826  // TODO: compare offset to length
827  // is_cstring(ς, element_address(&"...", 0))) --> true
828  return true_exprt();
829 #endif
830  }
831 
832  return std::move(src);
833 }
834 
837  const std::unordered_set<symbol_exprt, irep_hash> &address_taken,
838  const namespacet &ns)
839 {
840  PRECONDITION(src.type().id() == ID_bool);
841  const auto &state = src.state();
842  const auto &head = src.head();
843  const auto &tail = src.tail();
844 
845  {
846  // ς(h.❝n❞) = t ∧ ς(t.❝p❞) = h --> is_sentinel_dll(ς, h, t)
847  auto head_next = sentinel_dll_next(state, head, ns);
848  auto tail_prev = sentinel_dll_prev(state, tail, ns);
849 
850  if(head_next.has_value() && tail_prev.has_value())
851  {
852  // rec. calls
853  auto head_next_simplified =
854  simplify_state_expr(*head_next, address_taken, ns);
855  auto tail_prev_simplified =
856  simplify_state_expr(*tail_prev, address_taken, ns);
857  if(head_next_simplified == tail && tail_prev_simplified == head)
858  return true_exprt();
859  }
860  }
861 
862  if(state.id() == ID_update_state)
863  {
864  const auto &update_state_expr = to_update_state_expr(state);
865 
866  // are we writing to something that might be a node pointer?
867  const auto &update_type = update_state_expr.new_value().type();
868  if(update_type != src.head().type())
869  {
870  // update is irrelevant, drop update
871  auto without_update = src.with_state(update_state_expr.state());
872  return simplify_is_sentinel_dll_expr(without_update, address_taken, ns);
873  }
874  }
875  else if(state.id() == ID_enter_scope_state)
876  {
878  src.with_state(to_enter_scope_state_expr(state).state()),
880  ns);
881  }
882  else if(state.id() == ID_exit_scope_state)
883  {
885  src.with_state(to_exit_scope_state_expr(state).state()),
887  ns);
888  }
889 
890  return std::move(src);
891 }
892 
895  const std::unordered_set<symbol_exprt, irep_hash> &address_taken,
896  const namespacet &ns)
897 {
898  if(src.pointer().id() == ID_object_address)
899  {
900  // pointer_offset(❝x❞) -> 0
901  return from_integer(0, src.type());
902  }
903  else if(src.pointer().id() == ID_element_address)
904  {
905  const auto &element_address_expr = to_element_address_expr(src.pointer());
906  // pointer_offset(element_address(Z, y)) -->
907  // pointer_offset(Z) + y*sizeof(x)
908  auto size_opt = size_of_expr(element_address_expr.element_type(), ns);
909  if(size_opt.has_value())
910  {
911  auto product = mult_exprt(
913  element_address_expr.index(), src.type()),
914  typecast_exprt::conditional_cast(*size_opt, src.type()));
916  pointer_offset_exprt(element_address_expr.base(), src.type()),
918  ns);
919  auto sum = plus_exprt(pointer_offset, std::move(product));
920  return std::move(sum);
921  }
922  }
923  else if(src.pointer().id() == ID_address_of)
924  {
925  const auto &address_of_expr = to_address_of_expr(src.pointer());
926  if(address_of_expr.object().id() == ID_string_constant)
927  return from_integer(0, src.type());
928  }
929  else if(src.pointer().id() == ID_typecast)
930  {
931  if(to_typecast_expr(src.pointer()).op().type().id() == ID_pointer)
932  {
933  // remove the typecast
937  ns);
938  }
939  }
940 
941  return std::move(src);
942 }
943 
946  const std::unordered_set<symbol_exprt, irep_hash> &address_taken,
947  const namespacet &ns)
948 {
949  auto simplified_pointer = simplify_object_expression_rec(src.pointer());
950 
951  if(src.pointer() != simplified_pointer)
952  return pointer_object_exprt(simplified_pointer, src.type());
953 
954  return std::move(src);
955 }
956 
958  exprt src,
959  const std::unordered_set<symbol_exprt, irep_hash> &address_taken,
960  const namespacet &ns)
961 {
962  if(src.id() == ID_allocate)
963  {
964  return simplify_allocate(to_allocate_expr(src));
965  }
966  else if(src.id() == ID_evaluate)
967  {
968  auto &evaluate_expr = to_evaluate_expr(src);
969 
970  if(evaluate_expr.state().id() == ID_update_state)
971  {
972  return simplify_evaluate_update(evaluate_expr, address_taken, ns);
973  }
974  else if(evaluate_expr.state().id() == ID_allocate_state)
975  {
976  return simplify_evaluate_allocate_state(evaluate_expr, ns);
977  }
978  else if(evaluate_expr.state().id() == ID_deallocate_state)
979  {
980  return simplify_evaluate_deallocate_state(evaluate_expr, ns);
981  }
982  else if(evaluate_expr.state().id() == ID_enter_scope_state)
983  {
984  return simplify_evaluate_enter_scope_state(evaluate_expr, ns);
985  }
986  else if(evaluate_expr.state().id() == ID_exit_scope_state)
987  {
988  return simplify_evaluate_exit_scope_state(evaluate_expr, ns);
989  }
990  }
991  else if(
992  src.id() == ID_state_r_ok || src.id() == ID_state_w_ok ||
993  src.id() == ID_state_rw_ok)
994  {
996  }
997  else if(src.id() == ID_state_live_object)
998  {
1001  }
1002  else if(src.id() == ID_state_writeable_object)
1003  {
1006  }
1007  else if(src.id() == ID_state_is_cstring)
1008  {
1009  return simplify_is_cstring_expr(
1011  }
1012  else if(src.id() == ID_state_cstrlen)
1013  {
1015  }
1016  else if(src.id() == ID_state_is_sentinel_dll)
1017  {
1020  }
1021  else if(src.id() == ID_state_is_dynamic_object)
1022  {
1025  }
1026  else if(src.id() == ID_plus)
1027  {
1028  auto &plus_expr = to_plus_expr(src);
1029  if(
1030  src.type().id() == ID_pointer &&
1031  plus_expr.op0().id() == ID_element_address)
1032  {
1033  // element_address(X, Y) + Z --> element_address(X, Y + Z)
1034  auto new_element_address_expr = to_element_address_expr(plus_expr.op0());
1035  new_element_address_expr.index() = plus_exprt(
1036  new_element_address_expr.index(),
1038  plus_expr.op1(), new_element_address_expr.index().type()));
1039  new_element_address_expr.index() =
1040  simplify_expr(new_element_address_expr.index(), ns);
1041  return simplify_state_expr_node(
1042  new_element_address_expr, address_taken, ns);
1043  }
1044  }
1045  else if(src.id() == ID_pointer_offset)
1046  {
1049  }
1050  else if(src.id() == ID_pointer_object)
1051  {
1054  }
1055  else if(src.id() == ID_state_object_size)
1056  {
1058  }
1059  else if(src.id() == ID_equal)
1060  {
1061  const auto &equal_expr = to_equal_expr(src);
1062  if(
1063  equal_expr.lhs().id() == ID_pointer_object &&
1064  equal_expr.rhs().id() == ID_pointer_object)
1065  {
1066  const auto &lhs_p = to_pointer_object_expr(equal_expr.lhs()).pointer();
1067  const auto &rhs_p = to_pointer_object_expr(equal_expr.rhs()).pointer();
1068  if(lhs_p.id() == ID_object_address && rhs_p.id() == ID_object_address)
1069  {
1070  if(
1071  to_object_address_expr(lhs_p).object_identifier() ==
1072  to_object_address_expr(rhs_p).object_identifier())
1073  return true_exprt();
1074  else
1075  return false_exprt();
1076  }
1077  }
1078  }
1079 
1080  return src;
1081 }
1082 
1084  exprt src,
1085  const std::unordered_set<symbol_exprt, irep_hash> &address_taken,
1086  const namespacet &ns)
1087 {
1088  // operands first, recursively
1089  for(auto &op : src.operands())
1090  op = simplify_state_expr(op, address_taken, ns);
1091 
1092  // now the node itself
1093  src = simplify_state_expr_node(src, address_taken, ns);
1094 
1095  return src;
1096 }
std::unordered_set< symbol_exprt, irep_hash > address_taken(const std::vector< exprt > &src)
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.
bitvector_typet char_type()
Definition: c_types.cpp:106
allocate_exprt with_state(exprt state) const
Definition: state.h:246
const exprt & state() const
Definition: state.h:230
Boolean AND.
Definition: std_expr.h:2120
Arrays with given size.
Definition: std_types.h:807
typet index_type() const
The type of the index expressions into any instance of this type.
Definition: std_types.cpp:33
exprt & op1()
Definition: expr.h:136
exprt & op0()
Definition: expr.h:133
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition: std_expr.h:762
std::size_t get_width() const
Definition: std_types.h:920
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
Operator to return the address of an array element relative to a base address.
Definition: pointer_expr.h:748
const exprt & state() const
Definition: state.h:991
Equality.
Definition: std_expr.h:1361
const exprt & state() const
Definition: state.h:100
evaluate_exprt with_state(exprt state) const
Definition: state.h:116
const exprt & address() const
Definition: state.h:110
const exprt & state() const
Definition: state.h:1074
Base class for all expressions.
Definition: expr.h:56
bool is_false() const
Return whether the expression is a constant representing false.
Definition: expr.cpp:34
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
exprt & op0()
Definition: expr.h:133
operandst & operands()
Definition: expr.h:94
The Boolean constant false.
Definition: std_expr.h:3064
The trinary if-then-else operator.
Definition: std_expr.h:2370
const irep_idt & id() const
Definition: irep.h:384
Binary multiplication Associativity is not specified.
Definition: std_expr.h:1107
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
Operator to return the address of an object.
Definition: pointer_expr.h:596
irep_idt object_identifier() const
Definition: pointer_expr.h:602
Boolean OR.
Definition: std_expr.h:2228
The plus expression Associativity is not specified.
Definition: std_expr.h:1002
A numerical identifier for the object a pointer points to.
The offset (in bytes) of a pointer relative to the object.
const typet & base_type() const
The type of the data what we point to.
Definition: pointer_expr.h:35
const exprt & address() const
Definition: state.h:657
const exprt & state() const
Definition: state.h:647
state_cstrlen_exprt with_state(exprt state) const
Definition: state.h:663
const exprt & address() const
Definition: state.h:595
const exprt & state() const
Definition: state.h:585
state_is_cstring_exprt with_state(exprt state) const
Definition: state.h:601
const exprt & address() const
Definition: state.h:718
state_is_dynamic_object_exprt with_state(exprt state) const
Definition: state.h:724
const exprt & state() const
Definition: state.h:708
const exprt & head() const
Definition: sentinel_dll.h:49
state_is_sentinel_dll_exprt with_state(exprt state) const
Definition: sentinel_dll.h:70
const exprt & tail() const
Definition: sentinel_dll.h:59
const exprt & state() const
Definition: sentinel_dll.h:39
const exprt & state() const
Definition: state.h:468
const exprt & address() const
Definition: state.h:478
state_live_object_exprt with_state(exprt state) const
Definition: state.h:484
const exprt & address() const
Definition: state.h:783
state_object_size_exprt with_state(exprt state) const
Definition: state.h:789
const exprt & state() const
Definition: state.h:773
const exprt & address() const
Definition: state.h:847
state_ok_exprt with_state(exprt state) const
Definition: state.h:868
const exprt & state() const
Definition: state.h:837
const exprt & size() const
Definition: state.h:857
const exprt & state() const
Definition: state.h:530
const exprt & address() const
Definition: state.h:540
Expression to hold a symbol (variable)
Definition: std_expr.h:131
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
Fixed-width bit-vector with unsigned binary interpretation.
const exprt & state() const
Definition: state.h:165
constant_exprt make_boolean_expr(bool value)
returns true_exprt if given true and false_exprt otherwise
Definition: expr_util.cpp:339
Deprecated expression utility functions.
static format_containert< T > format(const T &o)
Definition: format.h:37
static exprt implication(exprt lhs, exprt rhs)
std::optional< exprt > may_alias(const exprt &a, const exprt &b, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
Definition: may_alias.cpp:221
May Alias.
exprt may_be_same_object(const exprt &a, const exprt &b, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
May Be Same Object.
const pointer_offset_exprt & to_pointer_offset_expr(const exprt &expr)
Cast an exprt to a pointer_offset_exprt.
const field_address_exprt & to_field_address_expr(const exprt &expr)
Cast an exprt to an field_address_exprt.
Definition: pointer_expr.h:727
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:93
const pointer_object_exprt & to_pointer_object_expr(const exprt &expr)
Cast an exprt to a pointer_object_exprt.
const object_address_exprt & to_object_address_expr(const exprt &expr)
Cast an exprt to an object_address_exprt.
Definition: pointer_expr.h:643
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
Definition: pointer_expr.h:577
const element_address_exprt & to_element_address_expr(const exprt &expr)
Cast an exprt to an element_address_exprt.
Definition: pointer_expr.h:814
std::optional< exprt > size_of_expr(const typet &type, const namespacet &ns)
Pointer Logic.
exprt pointer_offset(const exprt &pointer)
exprt object_size(const exprt &pointer)
exprt same_object(const exprt &p1, const exprt &p2)
Various predicates over pointers in programs.
std::optional< exprt > sentinel_dll_next(const exprt &state, const exprt &node, const namespacet &ns)
std::optional< exprt > sentinel_dll_prev(const exprt &state, const exprt &node, const namespacet &ns)
const state_is_sentinel_dll_exprt & to_state_is_sentinel_dll_expr(const exprt &expr)
Cast an exprt to a state_is_sentinel_dll_exprt.
Definition: sentinel_dll.h:85
exprt simplify_expr(exprt src, const namespacet &ns)
exprt simplify_evaluate_enter_scope_state(evaluate_exprt evaluate_expr, const namespacet &ns)
exprt simplify_allocate(allocate_exprt src)
exprt simplify_is_dynamic_object_expr(state_is_dynamic_object_exprt src)
exprt simplify_object_expression_rec(exprt src)
static bool is_zero_char(const exprt &src, const namespacet &ns)
exprt simplify_live_object_expr(state_live_object_exprt src, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
exprt simplify_is_sentinel_dll_expr(state_is_sentinel_dll_exprt src, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
exprt simplify_evaluate_exit_scope_state(evaluate_exprt evaluate_expr, const namespacet &ns)
exprt simplify_ok_expr(state_ok_exprt src, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
exprt simplify_state_expr_node(exprt, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &)
exprt simplify_is_cstring_expr(state_is_cstring_exprt src, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
exprt simplify_evaluate_update(evaluate_exprt evaluate_expr, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
exprt simplify_cstrlen_expr(state_cstrlen_exprt src, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
std::size_t allocate_counter
exprt simplify_pointer_offset_expr(pointer_offset_exprt src, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
static bool is_a_char_type(const typet &type)
exprt simplify_evaluate_deallocate_state(evaluate_exprt evaluate_expr, const namespacet &ns)
exprt simplify_object_expression(exprt src)
exprt simplify_object_size_expr(state_object_size_exprt src, const namespacet &ns)
exprt simplify_state_expr(exprt src, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
exprt simplify_writeable_object_expr(state_writeable_object_exprt src, const namespacet &ns)
exprt simplify_pointer_object_expr(pointer_object_exprt src, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
exprt simplify_evaluate_allocate_state(evaluate_exprt evaluate_expr, const namespacet &ns)
static bool types_are_compatible(const typet &a, const typet &b)
Simplify State Expression.
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
const deallocate_state_exprt & to_deallocate_state_expr(const exprt &expr)
Cast an exprt to a deallocate_state_exprt.
Definition: state.h:446
const state_cstrlen_exprt & to_state_cstrlen_expr(const exprt &expr)
Cast an exprt to a state_cstrlen_exprt.
Definition: state.h:677
const update_state_exprt & to_update_state_expr(const exprt &expr)
Cast an exprt to a update_state_exprt.
Definition: state.h:200
const state_is_dynamic_object_exprt & to_state_is_dynamic_object_expr(const exprt &expr)
Cast an exprt to a state_is_dynamic_object_exprt.
Definition: state.h:739
const evaluate_exprt & to_evaluate_expr(const exprt &expr)
Cast an exprt to a evaluate_exprt.
Definition: state.h:130
const state_object_size_exprt & to_state_object_size_expr(const exprt &expr)
Cast an exprt to a state_object_size_exprt.
Definition: state.h:804
const allocate_exprt & to_allocate_expr(const exprt &expr)
Cast an exprt to a allocate_exprt.
Definition: state.h:260
const state_live_object_exprt & to_state_live_object_expr(const exprt &expr)
Cast an exprt to a state_live_object_exprt.
Definition: state.h:499
const state_writeable_object_exprt & to_state_writeable_object_expr(const exprt &expr)
Cast an exprt to a state_writeable_object_exprt.
Definition: state.h:553
const state_is_cstring_exprt & to_state_is_cstring_expr(const exprt &expr)
Cast an exprt to a state_is_cstring_exprt.
Definition: state.h:615
const exit_scope_state_exprt & to_exit_scope_state_expr(const exprt &expr)
Cast an exprt to a exit_scope_state_exprt.
Definition: state.h:1119
const enter_scope_state_exprt & to_enter_scope_state_expr(const exprt &expr)
Cast an exprt to a enter_scope_state_exprt.
Definition: state.h:1042
const state_ok_exprt & to_state_ok_expr(const exprt &expr)
Cast an exprt to a state_ok_exprt.
Definition: state.h:882
API to expression classes.
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition: std_expr.h:2102
const equal_exprt & to_equal_expr(const exprt &expr)
Cast an exprt to an equal_exprt.
Definition: std_expr.h:1402
const plus_exprt & to_plus_expr(const exprt &expr)
Cast an exprt to a plus_exprt.
Definition: std_expr.h:1041
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.
Symbol table entry.
#define size_type
Definition: unistd.c:347