CBMC
rewrite_union.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 "rewrite_union.h"
13 
14 #include <util/arith_tools.h>
15 #include <util/byte_operators.h>
16 #include <util/c_types.h>
17 #include <util/pointer_expr.h>
19 #include <util/std_code.h>
20 
22 
23 static bool have_to_rewrite_union(const exprt &expr)
24 {
25  if(expr.id()==ID_member)
26  {
27  const exprt &op=to_member_expr(expr).struct_op();
28 
29  if(op.type().id() == ID_union_tag || op.type().id() == ID_union)
30  return true;
31  }
32  else if(expr.id()==ID_union)
33  return true;
34 
35  for(const auto &op : expr.operands())
36  {
37  if(have_to_rewrite_union(op))
38  return true;
39  }
40 
41  return false;
42 }
43 
44 // inside an address of (&x), unions can simply
45 // be type casts and don't have to be re-written!
47 {
48  if(!have_to_rewrite_union(expr))
49  return;
50 
51  if(expr.id()==ID_index)
52  {
54  rewrite_union(to_index_expr(expr).index());
55  }
56  else if(expr.id()==ID_member)
57  rewrite_union_address_of(to_member_expr(expr).struct_op());
58  else if(expr.id()==ID_symbol)
59  {
60  // done!
61  }
62  else if(expr.id()==ID_dereference)
63  rewrite_union(to_dereference_expr(expr).pointer());
64 }
65 
68 void rewrite_union(exprt &expr)
69 {
70  if(expr.id()==ID_address_of)
71  {
73  return;
74  }
75 
76  if(!have_to_rewrite_union(expr))
77  return;
78 
79  Forall_operands(it, expr)
80  rewrite_union(*it);
81 
82  if(expr.id()==ID_member)
83  {
84  const exprt &op=to_member_expr(expr).struct_op();
85 
86  if(op.type().id() == ID_union_tag || op.type().id() == ID_union)
87  {
88  exprt offset = from_integer(0, c_index_type());
89  expr = make_byte_extract(op, offset, expr.type());
90  }
91  }
92  else if(expr.id()==ID_union)
93  {
94  const union_exprt &union_expr=to_union_expr(expr);
95  exprt offset = from_integer(0, c_index_type());
96  side_effect_expr_nondett nondet(expr.type(), expr.source_location());
97  expr = make_byte_update(nondet, offset, union_expr.op());
98  }
99 }
100 
102 {
103  for(auto &instruction : goto_function.body.instructions)
104  {
105  rewrite_union(instruction.code_nonconst());
106 
107  if(instruction.has_condition())
108  rewrite_union(instruction.condition_nonconst());
109  }
110 }
111 
112 void rewrite_union(goto_functionst &goto_functions)
113 {
114  for(auto &gf_entry : goto_functions.function_map)
115  rewrite_union(gf_entry.second);
116 }
117 
118 void rewrite_union(goto_modelt &goto_model)
119 {
120  rewrite_union(goto_model.goto_functions);
121 }
122 
128 static bool restore_union_rec(exprt &expr, const namespacet &ns)
129 {
130  bool unmodified = true;
131 
132  Forall_operands(it, expr)
133  unmodified &= restore_union_rec(*it, ns);
134 
135  if(
136  expr.id() == ID_byte_extract_little_endian ||
137  expr.id() == ID_byte_extract_big_endian)
138  {
140  if(be.op().type().id() == ID_union || be.op().type().id() == ID_union_tag)
141  {
142  const union_typet &union_type =
143  be.op().type().id() == ID_union_tag
144  ? ns.follow_tag(to_union_tag_type(be.op().type()))
145  : to_union_type(be.op().type());
146 
147  for(const auto &comp : union_type.components())
148  {
149  if(be.offset().is_zero() && be.type() == comp.type())
150  {
151  expr = member_exprt{be.op(), comp.get_name(), be.type()};
152  return false;
153  }
154  else if(
155  comp.type().id() == ID_array || comp.type().id() == ID_struct ||
156  comp.type().id() == ID_struct_tag)
157  {
158  std::optional<exprt> result = get_subexpression_at_offset(
159  member_exprt{be.op(), comp.get_name(), comp.type()},
160  be.offset(),
161  be.type(),
162  ns);
163  if(result.has_value())
164  {
165  expr = *result;
166  return false;
167  }
168  }
169  }
170  }
171  }
172 
173  return unmodified;
174 }
175 
180 void restore_union(exprt &expr, const namespacet &ns)
181 {
182  exprt tmp = expr;
183 
184  if(!restore_union_rec(tmp, ns))
185  expr.swap(tmp);
186 }
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
byte_update_exprt make_byte_update(const exprt &_op, const exprt &_offset, const exprt &_value)
Construct a byte_update_exprt with endianness and byte width matching the current configuration.
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.
const byte_extract_exprt & to_byte_extract_expr(const exprt &expr)
bitvector_typet c_index_type()
Definition: c_types.cpp:16
const union_tag_typet & to_union_tag_type(const typet &type)
Cast a typet to a union_tag_typet.
Definition: c_types.h:224
const union_typet & to_union_type(const typet &type)
Cast a typet to a union_typet.
Definition: c_types.h:184
Expression of type type extracted from some object op starting at position offset (given in number of...
Base class for all expressions.
Definition: expr.h:56
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
operandst & operands()
Definition: expr.h:94
A collection of goto functions.
function_mapt function_map
::goto_functiont goto_functiont
goto_functionst goto_functions
GOTO functions.
Definition: goto_model.h:34
const irep_idt & id() const
Definition: irep.h:388
void swap(irept &irep)
Definition: irep.h:434
Extract member of struct or union.
Definition: std_expr.h:2849
const exprt & struct_op() const
Definition: std_expr.h:2887
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition: namespace.cpp:63
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
A side_effect_exprt that returns a non-deterministically chosen value.
Definition: std_code.h:1520
const componentst & components() const
Definition: std_types.h:147
const exprt & op() const
Definition: std_expr.h:391
Union constructor from single element.
Definition: std_expr.h:1770
The union type.
Definition: c_types.h:147
#define Forall_operands(it, expr)
Definition: expr.h:27
Symbol Table + CFG.
API to expression classes for Pointers.
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
Definition: pointer_expr.h:890
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
Definition: pointer_expr.h:577
std::optional< exprt > get_subexpression_at_offset(const exprt &expr, const mp_integer &offset_bytes, const typet &target_type_raw, const namespacet &ns)
Pointer Logic.
void restore_union(exprt &expr, const namespacet &ns)
Undo the union access -> byte_extract replacement that rewrite_union did for the purpose of displayin...
static bool have_to_rewrite_union(const exprt &expr)
void rewrite_union_address_of(exprt &expr)
void rewrite_union(exprt &expr)
We rewrite u.c for unions u into byte_extract(u, 0), and { .c = v } into byte_update(NIL,...
static bool restore_union_rec(exprt &expr, const namespacet &ns)
Undo the union access -> byte_extract replacement that rewrite_union did for the purpose of displayin...
Symbolic Execution.
const union_exprt & to_union_expr(const exprt &expr)
Cast an exprt to a union_exprt.
Definition: std_expr.h:1816
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2941
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1538