CBMC
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
simplify_expr_pointer.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module:
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
10
11#include "arith_tools.h"
12#include "c_types.h"
13#include "expr_util.h"
14#include "namespace.h"
15#include "pointer_expr.h"
16#include "pointer_offset_size.h"
17#include "pointer_predicates.h"
18#include "std_expr.h"
19#include "string_constant.h"
20
22 const exprt &expr,
23 mp_integer &address)
24{
25 if(expr.id() == ID_dereference)
26 {
27 const auto &pointer = to_dereference_expr(expr).pointer();
28
29 if(
30 pointer.id() == ID_typecast &&
31 to_typecast_expr(pointer).op().is_constant() &&
32 !to_integer(to_constant_expr(to_typecast_expr(pointer).op()), address))
33 {
34 return true;
35 }
36
37 if(pointer.is_constant())
38 {
39 const constant_exprt &constant = to_constant_expr(pointer);
40
41 if(constant.is_null_pointer())
42 {
43 address=0;
44 return true;
45 }
46 else if(!to_integer(constant, address))
47 return true;
48 }
49 }
50
51 return false;
52}
53
56 const unary_exprt &expr)
57{
58 const exprt &pointer = expr.op();
59 PRECONDITION(pointer.type().id() == ID_pointer);
60
61 if(pointer.id() == ID_if)
62 {
63 if_exprt if_expr = lift_if(expr, 0);
65 }
66 else
67 {
68 auto r_it = simplify_rec(pointer); // recursive call
69 if(r_it.has_changed())
70 {
71 auto tmp = expr;
72 tmp.op() = r_it.expr;
73 return tmp;
74 }
75 }
76
77 return unchanged(expr);
78}
79
82{
83 if(expr.id()==ID_index)
84 {
85 auto new_index_expr = to_index_expr(expr);
86
87 bool no_change = true;
88
90
91 if(array_result.has_changed())
92 {
93 no_change = false;
94 new_index_expr.array() = array_result.expr;
95 }
96
98
99 if(index_result.has_changed())
100 {
101 no_change = false;
102 new_index_expr.index() = index_result.expr;
103 }
104
105 // rewrite (*(type *)int) [index] by
106 // pushing the index inside
107
108 mp_integer address;
110 {
111 // push index into address
113
114 if(step_size.has_value())
115 {
116 const auto index = numeric_cast<mp_integer>(new_index_expr.index());
117
118 if(index.has_value())
119 {
121 to_dereference_expr(new_index_expr.array()).pointer().type());
123
125 from_integer((*step_size) * (*index) + address, c_index_type()),
127
129 }
130 }
131 }
132
133 if(!no_change)
134 return new_index_expr;
135 }
136 else if(expr.id()==ID_member)
137 {
138 auto new_member_expr = to_member_expr(expr);
139
140 bool no_change = true;
141
142 auto struct_op_result =
144
145 if(struct_op_result.has_changed())
146 {
147 new_member_expr.struct_op() = struct_op_result.expr;
148 no_change = false;
149 }
150
151 const typet &op_type = new_member_expr.struct_op().type();
152
153 if(op_type.id() == ID_struct || op_type.id() == ID_struct_tag)
154 {
155 // rewrite NULL -> member by
156 // pushing the member inside
157
158 mp_integer address;
159 if(is_dereference_integer_object(new_member_expr.struct_op(), address))
160 {
162 op_type.id() == ID_struct_tag
163 ? ns.follow_tag(to_struct_tag_type(op_type))
165 const irep_idt &member = to_member_expr(expr).get_component_name();
166 auto offset = member_offset(struct_type, member, ns);
167 if(offset.has_value())
168 {
170 to_dereference_expr(new_member_expr.struct_op()).pointer().type());
173 from_integer(address + *offset, c_index_type()), pointer_type);
175 }
176 }
177 }
178
179 if(!no_change)
180 return new_member_expr;
181 }
182 else if(expr.id()==ID_dereference)
183 {
184 auto new_expr = to_dereference_expr(expr);
185 auto r_pointer = simplify_rec(new_expr.pointer());
186 if(r_pointer.has_changed())
187 {
188 new_expr.pointer() = r_pointer.expr;
189 return std::move(new_expr);
190 }
191 }
192 else if(expr.id()==ID_if)
193 {
194 auto new_if_expr = to_if_expr(expr);
195
196 bool no_change = true;
197
198 auto r_cond = simplify_rec(new_if_expr.cond());
199 if(r_cond.has_changed())
200 {
201 new_if_expr.cond() = r_cond.expr;
202 no_change = false;
203 }
204
206 if(true_result.has_changed())
207 {
208 new_if_expr.true_case() = true_result.expr;
209 no_change = false;
210 }
211
213
214 if(false_result.has_changed())
215 {
216 new_if_expr.false_case() = false_result.expr;
217 no_change = false;
218 }
219
220 // condition is a constant?
221 if(new_if_expr.cond().is_true())
222 {
223 return new_if_expr.true_case();
224 }
225 else if(new_if_expr.cond().is_false())
226 {
227 return new_if_expr.false_case();
228 }
229
230 if(!no_change)
231 return new_if_expr;
232 }
233
234 return unchanged(expr);
235}
236
239{
240 if(expr.type().id() != ID_pointer)
241 return unchanged(expr);
242
244
245 if(new_object.expr.id() == ID_index)
246 {
248
249 if(!index_expr.index().is_zero())
250 {
251 // we normalize &a[i] to (&a[0])+i
252 exprt offset = index_expr.op1();
253 index_expr.op1()=from_integer(0, offset.type());
254 auto new_address_of_expr = expr;
255 new_address_of_expr.object() = std::move(index_expr);
256 return plus_exprt(std::move(new_address_of_expr), offset);
257 }
258 }
259 else if(new_object.expr.id() == ID_dereference)
260 {
261 // simplify &*p to p
262 return to_dereference_expr(new_object.expr).pointer();
263 }
264
265 if(new_object.has_changed())
266 {
267 auto new_expr = expr;
268 new_expr.object() = new_object;
269 return new_expr;
270 }
271 else
272 return unchanged(expr);
273}
274
277{
278 const exprt &ptr = expr.pointer();
279
280 if(ptr.type().id()!=ID_pointer)
281 return unchanged(expr);
282
283 if(ptr.id()==ID_address_of)
284 {
285 auto offset = compute_pointer_offset(to_address_of_expr(ptr).object(), ns);
286
287 if(offset.has_value())
288 return from_integer(*offset, expr.type());
289 }
290 else if(ptr.id()==ID_typecast) // pointer typecast
291 {
292 const auto &op = to_typecast_expr(ptr).op();
293 const typet &op_type = op.type();
294
295 if(op_type.id()==ID_pointer)
296 {
297 // Cast from pointer to pointer.
298 // This just passes through, remove typecast.
299 auto new_expr = expr;
300 new_expr.op() = op;
301
302 return changed(simplify_pointer_offset(new_expr)); // recursive call
303 }
304 else if(op_type.id()==ID_signedbv ||
306 {
307 // Cast from integer to pointer, say (int *)x.
308
309 if(op.is_constant())
310 {
311 // (T *)0x1234 -> 0x1234
312 return changed(simplify_typecast(typecast_exprt{op, expr.type()}));
313 }
314 else
315 {
316 // We do a bit of special treatment for (TYPE *)(a+(int)&o),
317 // which is re-written to 'a'.
318
319 typet type = expr.type();
320 exprt tmp = op;
321 if(tmp.id()==ID_plus && tmp.operands().size()==2)
322 {
323 const auto &plus_expr = to_plus_expr(tmp);
324
325 if(
326 plus_expr.op0().id() == ID_typecast &&
327 to_typecast_expr(plus_expr.op0()).op().id() == ID_address_of)
328 {
329 auto new_expr =
331
333 }
334 else if(
335 plus_expr.op1().id() == ID_typecast &&
336 to_typecast_expr(plus_expr.op1()).op().id() == ID_address_of)
337 {
338 auto new_expr =
340
342 }
343 }
344 }
345 }
346 }
347 else if(ptr.id()==ID_plus) // pointer arithmetic
348 {
351
352 for(const auto &op : ptr.operands())
353 {
354 if(op.type().id()==ID_pointer)
355 ptr_expr.push_back(op);
356 else if(!op.is_zero())
357 {
358 exprt tmp=op;
359 if(tmp.type()!=expr.type())
361
362 int_expr.push_back(tmp);
363 }
364 }
365
366 if(ptr_expr.size()!=1 || int_expr.empty())
367 return unchanged(expr);
368
370 to_pointer_type(ptr_expr.front().type()).base_type();
371 if(pointer_base_type.id() == ID_empty)
373
375
376 if(!element_size.has_value())
377 return unchanged(expr);
378
380 pointer_offset_exprt(ptr_expr.front(), expr.type()));
381
382 exprt sum;
383
384 if(int_expr.size()==1)
385 sum=int_expr.front();
386 else
388
390
392
394
396 }
397 else if(ptr.is_constant())
398 {
400
401 if(c_ptr.is_null_pointer())
402 {
403 return from_integer(0, expr.type());
404 }
405 }
406
407 return unchanged(expr);
408}
409
411 const binary_relation_exprt &expr)
412{
413 // the operands of the relation are both either one of
414 // a) an address_of_exprt
415 // b) a typecast_exprt with an address_of_exprt operand
416
417 PRECONDITION(expr.id() == ID_equal || expr.id() == ID_notequal);
418
419 // skip over the typecast
420 exprt tmp0 = skip_typecast(expr.op0());
422
424
425 if(
426 tmp0_address_of.object().id() == ID_index &&
427 to_index_expr(tmp0_address_of.object()).index().is_zero())
428 {
431 }
432
433 // skip over the typecast
434 exprt tmp1 = skip_typecast(expr.op1());
436
438
439 if(
440 tmp1_address_of.object().id() == ID_index &&
441 to_index_expr(tmp1_address_of.object()).index().is_zero())
442 {
444 }
445
446 const auto &tmp0_object = tmp0_address_of.object();
447 const auto &tmp1_object = tmp1_address_of.object();
448
449 if(tmp0_object.id() == ID_symbol && tmp1_object.id() == ID_symbol)
450 {
451 bool equal = to_symbol_expr(tmp0_object).get_identifier() ==
452 to_symbol_expr(tmp1_object).get_identifier();
453
454 return make_boolean_expr(expr.id() == ID_equal ? equal : !equal);
455 }
456 else if(
459 {
460 bool equal = to_dynamic_object_expr(tmp0_object).get_instance() ==
461 to_dynamic_object_expr(tmp1_object).get_instance();
462
463 return make_boolean_expr(expr.id() == ID_equal ? equal : !equal);
464 }
465 else if(
466 (tmp0_object.id() == ID_symbol && tmp1_object.id() == ID_dynamic_object) ||
468 {
469 return make_boolean_expr(expr.id() != ID_equal);
470 }
471 else if(
474 {
475 return make_boolean_expr(expr.id() == ID_equal);
476 }
477
478 return unchanged(expr);
479}
480
482 const binary_relation_exprt &expr)
483{
484 PRECONDITION(expr.id() == ID_equal || expr.id() == ID_notequal);
485 PRECONDITION(expr.is_boolean());
486
488 for(const auto &operand : expr.operands())
489 {
491 const exprt &op = to_pointer_object_expr(operand).pointer();
492
493 if(op.id()==ID_address_of)
494 {
495 const auto &op_object = to_address_of_expr(op).object();
496
497 if((op_object.id() != ID_symbol && op_object.id() != ID_dynamic_object &&
499 {
500 return unchanged(expr);
501 }
502 }
503 else if(!op.is_constant() || !op.is_zero())
504 {
505 return unchanged(expr);
506 }
507
508 if(new_inequality_ops.empty())
509 new_inequality_ops.push_back(op);
510 else
511 {
512 new_inequality_ops.push_back(
514 op, new_inequality_ops.front().type())));
515 }
516 }
517
518 auto new_expr = expr;
519
520 new_expr.operands() = std::move(new_inequality_ops);
521
523}
524
527{
528 const exprt &op = expr.pointer();
529
530 auto op_result = simplify_object(op);
531
532 if(op_result.expr.id() == ID_if)
533 {
534 const if_exprt &if_expr = to_if_expr(op_result.expr);
535 exprt cond=if_expr.cond();
536
537 auto p_o_false = expr;
538 p_o_false.op() = if_expr.false_case();
539
540 auto p_o_true = expr;
541 p_o_true.op() = if_expr.true_case();
542
543 auto new_expr = if_exprt(cond, p_o_true, p_o_false, expr.type());
545 }
546
547 if(op_result.has_changed())
548 {
549 auto new_expr = expr;
550 new_expr.op() = op_result;
551 return std::move(new_expr);
552 }
553 else
554 return unchanged(expr);
555}
556
559{
560 auto new_expr = expr;
561 exprt &op = new_expr.op();
562
563 bool no_change = true;
564
565 auto op_result = simplify_object(op);
566
567 if(op_result.has_changed())
568 {
569 op = op_result.expr;
570 no_change = false;
571 }
572
573 // NULL is not dynamic
575 return false_exprt();
576
577 // &something depends on the something
578 if(op.id() == ID_address_of)
579 {
580 const auto &op_object = to_address_of_expr(op).object();
581
582 if(op_object.id() == ID_symbol)
583 {
584 const irep_idt identifier = to_symbol_expr(op_object).get_identifier();
585
586 // this is for the benefit of symex
587 return make_boolean_expr(
588 identifier.starts_with(SYMEX_DYNAMIC_PREFIX "::"));
589 }
590 else if(op_object.id() == ID_string_constant)
591 {
592 return false_exprt();
593 }
594 else if(op_object.id() == ID_array)
595 {
596 return false_exprt();
597 }
598 }
599
600 if(no_change)
601 return unchanged(expr);
602 else
603 return std::move(new_expr);
604}
605
608{
609 auto new_expr = expr;
610 exprt &op = new_expr.op();
611 bool no_change = true;
612
613 auto op_result = simplify_object(op);
614
615 if(op_result.has_changed())
616 {
617 op = op_result.expr;
618 no_change = false;
619 }
620
621 // NULL is not invalid
623 {
624 return false_exprt();
625 }
626
627 // &anything is not invalid
628 if(op.id()==ID_address_of)
629 {
630 return false_exprt();
631 }
632
633 if(no_change)
634 return unchanged(expr);
635 else
636 return std::move(new_expr);
637}
638
641{
642 auto new_expr = expr;
643 bool no_change = true;
644 exprt &op = new_expr.pointer();
645 auto op_result = simplify_object(op);
646
647 if(op_result.has_changed())
648 {
649 op = op_result.expr;
650 no_change = false;
651 }
652
653 if(op.id() == ID_address_of)
654 {
655 const auto &op_object = to_address_of_expr(op).object();
656
657 if(op_object.id() == ID_symbol)
658 {
659 // just get the type
660 auto size_opt = size_of_expr(op_object.type(), ns);
661
662 if(size_opt.has_value())
663 {
664 const typet &expr_type = expr.type();
665 exprt size = size_opt.value();
666
667 if(size.type() != expr_type)
669
670 return size;
671 }
672 }
673 else if(op_object.id() == ID_string_constant)
674 {
675 typet type=expr.type();
676 return from_integer(
677 to_string_constant(op_object).value().size() + 1, type);
678 }
679 }
680
681 if(no_change)
682 return unchanged(expr);
683 else
684 return std::move(new_expr);
685}
686
688 const prophecy_r_or_w_ok_exprt &expr)
689{
691 if(!new_expr.is_constant())
692 return unchanged(expr);
693 else
694 return std::move(new_expr);
695}
696
699{
701 if(!new_expr.is_constant())
702 return unchanged(expr);
703 else
704 return std::move(new_expr);
705}
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
bool to_integer(const constant_exprt &expr, mp_integer &int_value)
Convert a constant expression expr to an arbitrary-precision integer.
pointer_typet pointer_type(const typet &subtype)
Definition c_types.cpp:235
bitvector_typet char_type()
Definition c_types.cpp:106
bitvector_typet c_index_type()
Definition c_types.cpp:16
Operator to return the address of an object.
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
exprt & op0()
Definition expr.h:133
exprt & op1()
Definition expr.h:136
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition std_expr.h:762
A constant literal expression.
Definition std_expr.h:3117
bool is_null_pointer() const
Returns true if expr has a pointer type and a value NULL; it also returns true when expr has value ze...
Definition std_expr.cpp:25
Operator to dereference a pointer.
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
bool starts_with(const char *s) const
equivalent of as_string().starts_with(s)
Definition dstring.h:95
Base class for all expressions.
Definition expr.h:56
std::vector< exprt > operandst
Definition expr.h:58
bool is_boolean() const
Return whether the expression represents a Boolean.
Definition expr.h:224
bool is_zero() const
Return whether the expression is a constant representing 0.
Definition expr.cpp:47
bool is_constant() const
Return whether the expression is a constant.
Definition expr.h:212
typet & type()
Return the type of the expression.
Definition expr.h:84
operandst & operands()
Definition expr.h:94
The Boolean constant false.
Definition std_expr.h:3199
The trinary if-then-else operator.
Definition std_expr.h:2497
const irep_idt & id() const
Definition irep.h:388
Binary multiplication Associativity is not specified.
Definition std_expr.h:1107
Expression for finding the size (in bytes) of the object a pointer points to.
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.
The pointer type These are both 'bitvector_typet' (they have a width) and 'type_with_subtypet' (they ...
const typet & base_type() const
The type of the data what we point to.
pointer_in_range (see pointer_in_range_exprt) with prophecy expressions to encode whether a pointer r...
exprt lower(const namespacet &ns) const
A base class for a predicate that indicates that an address range is ok to read or write or both.
exprt lower(const namespacet &ns) const
Lower an r_or_w_ok_exprt to arithmetic and logic expressions.
const namespacet & ns
resultt simplify_inequality_address_of(const binary_relation_exprt &)
resultt simplify_prophecy_r_or_w_ok(const prophecy_r_or_w_ok_exprt &)
Try to simplify prophecy_{r,w,rw}_ok to a constant expression.
static resultt changed(resultt<> result)
resultt simplify_unary_pointer_predicate_preorder(const unary_exprt &)
resultt simplify_address_of(const address_of_exprt &)
resultt simplify_node(const exprt &)
resultt simplify_prophecy_pointer_in_range(const prophecy_pointer_in_range_exprt &)
Try to simplify prophecy_pointer_in_range to a constant expression.
resultt simplify_rec(const exprt &)
resultt simplify_typecast(const typecast_exprt &)
resultt simplify_pointer_object(const pointer_object_exprt &)
resultt simplify_object(const exprt &)
resultt simplify_mult(const mult_exprt &)
resultt simplify_address_of_arg(const exprt &)
resultt simplify_inequality(const binary_relation_exprt &)
simplifies inequalities !=, <=, <, >=, >, and also ==
resultt simplify_inequality_pointer_object(const binary_relation_exprt &)
static resultt unchanged(exprt expr)
resultt simplify_is_invalid_pointer(const unary_exprt &)
resultt simplify_pointer_offset(const pointer_offset_exprt &)
resultt simplify_plus(const plus_exprt &)
resultt simplify_if_preorder(const if_exprt &expr)
resultt simplify_is_dynamic_object(const unary_exprt &)
resultt simplify_object_size(const object_size_exprt &)
Structure type, corresponds to C style structs.
Definition std_types.h:231
Semantic type conversion.
Definition std_expr.h:2073
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition std_expr.h:2081
The type of an expression, extends irept.
Definition type.h:29
Generic base class for unary expressions.
Definition std_expr.h:361
const exprt & op() const
Definition std_expr.h:391
constant_exprt make_boolean_expr(bool value)
returns true_exprt if given true and false_exprt otherwise
const exprt & skip_typecast(const exprt &expr)
find the expression nested inside typecasts, if any
if_exprt lift_if(const exprt &src, std::size_t operand_number)
lift up an if_exprt one level
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...
Deprecated expression utility functions.
API to expression classes for Pointers.
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
const pointer_object_exprt & to_pointer_object_expr(const exprt &expr)
Cast an exprt to a pointer_object_exprt.
const dynamic_object_exprt & to_dynamic_object_expr(const exprt &expr)
Cast an exprt to a dynamic_object_exprt.
std::optional< mp_integer > pointer_offset_size(const typet &type, const namespacet &ns)
Compute the size of a type in bytes, rounding up to full bytes.
std::optional< mp_integer > compute_pointer_offset(const exprt &expr, const namespacet &ns)
std::optional< exprt > size_of_expr(const typet &type, const namespacet &ns)
std::optional< mp_integer > member_offset(const struct_typet &type, const irep_idt &member, const namespacet &ns)
Pointer Logic.
Various predicates over pointers in programs.
#define SYMEX_DYNAMIC_PREFIX
static bool is_dereference_integer_object(const exprt &expr, mp_integer &address)
BigInt mp_integer
Definition smt_terms.h:17
#define PRECONDITION(CONDITION)
Definition invariant.h:463
API to expression classes.
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1538
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition std_expr.h:2107
const plus_exprt & to_plus_expr(const exprt &expr)
Cast an exprt to a plus_exprt.
Definition std_expr.h:1041
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition std_expr.h:2577
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:3063
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition std_expr.h:3172
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:272
bool is_constant(const typet &type)
This method tests, if the given typet is a constant.
Definition std_types.h:29
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition std_types.h:308
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition std_types.h:518
const string_constantt & to_string_constant(const exprt &expr)