CBMC
renaming_level.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Symbolic Execution
4 
5 Author: Romain Brenguier, romain.brenguier@diffblue.com
6 
7 \*******************************************************************/
8 
11 
12 #include "renaming_level.h"
13 
14 #include <util/namespace.h>
15 #include <util/pointer_expr.h>
16 #include <util/ssa_expr.h>
17 #include <util/symbol.h>
18 
19 #include "goto_symex_state.h"
20 
22 symex_level0(ssa_exprt ssa_expr, const namespacet &ns, std::size_t thread_nr)
23 {
24  // already renamed?
25  if(!ssa_expr.get_level_0().empty())
26  return renamedt<ssa_exprt, L0>{std::move(ssa_expr)};
27 
28  const irep_idt &obj_identifier = ssa_expr.get_object_name();
29 
30  // guards are not L0-renamed
31  if(obj_identifier == goto_symex_statet::guard_identifier())
32  return renamedt<ssa_exprt, L0>{std::move(ssa_expr)};
33 
34  const symbolt *s;
35  const bool found_l0 = !ns.lookup(obj_identifier, s);
36  INVARIANT(found_l0, "level0: failed to find " + id2string(obj_identifier));
37 
38  // don't rename shared variables or functions
39  if(s->type.id() == ID_code || s->is_shared())
40  return renamedt<ssa_exprt, L0>{std::move(ssa_expr)};
41 
42  // rename!
43  ssa_expr.set_level_0(thread_nr);
44  return renamedt<ssa_exprt, L0>{ssa_expr};
45 }
46 
48  const renamedt<ssa_exprt, L0> &ssa,
49  std::size_t index)
50 {
52  ssa.get().get_identifier(), std::make_pair(ssa.get(), index));
53 }
54 
55 std::optional<std::pair<ssa_exprt, std::size_t>>
57  const renamedt<ssa_exprt, L0> &ssa,
58  std::size_t index)
59 {
60  const irep_idt &identifier = ssa.get().get_identifier();
61  const auto old_value = current_names.find(identifier);
62  if(old_value)
63  {
64  std::pair<ssa_exprt, std::size_t> result = *old_value;
65  current_names.replace(identifier, std::make_pair(ssa.get(), index));
66  return result;
67  }
68  current_names.insert(identifier, std::make_pair(ssa.get(), index));
69  return {};
70 }
71 
73 {
74  return current_names.has_key(ssa.get().get_identifier());
75 }
76 
79 {
80  if(
81  !l0_expr.get().get_level_1().empty() ||
82  !l0_expr.get().get_level_2().empty())
83  {
84  return renamedt<ssa_exprt, L1>{std::move(l0_expr.value())};
85  }
86 
87  const irep_idt l0_name = l0_expr.get().get_l1_object_identifier();
88 
89  const auto r_opt = current_names.find(l0_name);
90 
91  if(!r_opt)
92  {
93  return renamedt<ssa_exprt, L1>{std::move(l0_expr.value())};
94  }
95 
96  // rename!
97  l0_expr.value().set_level_1(r_opt->get().second);
98  return renamedt<ssa_exprt, L1>{std::move(l0_expr.value())};
99 }
100 
102 operator()(renamedt<ssa_exprt, L1> l1_expr) const
103 {
104  if(!l1_expr.get().get_level_2().empty())
105  return renamedt<ssa_exprt, L2>{std::move(l1_expr.value())};
106  l1_expr.value().set_level_2(latest_index(l1_expr.get().get_identifier()));
107  return renamedt<ssa_exprt, L2>{std::move(l1_expr.value())};
108 }
109 
111 {
113  other.current_names.get_delta_view(current_names, delta_view, false);
114 
115  for(const auto &delta_item : delta_view)
116  {
117  if(!delta_item.is_in_both_maps())
118  {
119  current_names.insert(delta_item.k, delta_item.m);
120  }
121  else
122  {
123  if(delta_item.m != delta_item.get_other_map_value())
124  {
125  current_names.replace(delta_item.k, delta_item.m);
126  }
127  }
128  }
129 }
130 
131 unsigned symex_level2t::latest_index(const irep_idt &identifier) const
132 {
133  const auto r_opt = current_names.find(identifier);
134  return !r_opt ? 0 : r_opt->get().second;
135 }
136 
138  const irep_idt &l1_identifier,
139  const ssa_exprt &lhs,
140  std::function<std::size_t(const irep_idt &)> fresh_l2_name_provider)
141 {
142  const std::size_t n = fresh_l2_name_provider(l1_identifier);
143 
144  if(const auto r_opt = current_names.find(l1_identifier))
145  {
146  std::pair<ssa_exprt, std::size_t> copy = r_opt->get();
147  copy.second = n;
148  current_names.replace(l1_identifier, std::move(copy));
149  }
150  else
151  {
152  current_names.insert(l1_identifier, std::make_pair(lhs, n));
153  }
154 
155  return n;
156 }
157 
159 {
160  expr.type() = get_original_name(std::move(expr.type()));
161 
162  if(is_ssa_expr(expr))
163  return to_ssa_expr(expr).get_original_expr();
164  else
165  {
166  Forall_operands(it, expr)
167  *it = get_original_name(std::move(*it));
168  return expr;
169  }
170 }
171 
173 {
174  // rename all the symbols with their last known value
175 
176  if(type.id() == ID_array)
177  {
178  auto &array_type = to_array_type(type);
179  array_type.element_type() =
180  get_original_name(std::move(array_type.element_type()));
181  array_type.size() = get_original_name(std::move(array_type.size()));
182  }
183  else if(type.id() == ID_struct || type.id() == ID_union)
184  {
185  struct_union_typet &s_u_type = to_struct_union_type(type);
186  struct_union_typet::componentst &components = s_u_type.components();
187 
188  for(auto &component : components)
189  component.type() = get_original_name(std::move(component.type()));
190  }
191  else if(type.id() == ID_pointer)
192  {
193  to_pointer_type(type).base_type() =
194  get_original_name(std::move(to_pointer_type(type).base_type()));
195  }
196  return type;
197 }
198 
199 bool check_renaming(const typet &type)
200 {
201  if(type.id() == ID_array)
202  return check_renaming(to_array_type(type).size());
203  else if(type.id() == ID_struct || type.id() == ID_union)
204  {
205  for(const auto &c : to_struct_union_type(type).components())
206  if(check_renaming(c.type()))
207  return true;
208  }
209  else if(type.has_subtype())
210  return check_renaming(to_type_with_subtype(type).subtype());
211 
212  return false;
213 }
214 
215 bool check_renaming_l1(const exprt &expr)
216 {
217  if(check_renaming(expr.type()))
218  return true;
219 
220  if(expr.id() == ID_symbol)
221  {
222  const auto &type = expr.type();
223  if(!expr.get_bool(ID_C_SSA_symbol))
224  return type.id() != ID_code && type.id() != ID_mathematical_function;
225  if(!to_ssa_expr(expr).get_level_2().empty())
226  return true;
227  if(to_ssa_expr(expr).get_original_expr().type() != type)
228  return true;
229  }
230  else
231  {
232  for(const auto &op : expr.operands())
233  {
234  if(check_renaming_l1(op))
235  return true;
236  }
237  }
238 
239  return false;
240 }
241 
242 bool check_renaming(const exprt &expr)
243 {
244  if(check_renaming(expr.type()))
245  return true;
246 
247  if(
248  expr.id() == ID_address_of &&
249  to_address_of_expr(expr).object().id() == ID_symbol)
250  {
251  return check_renaming_l1(to_address_of_expr(expr).object());
252  }
253  else if(
254  expr.id() == ID_address_of &&
255  to_address_of_expr(expr).object().id() == ID_index)
256  {
257  const auto index_expr = to_index_expr(to_address_of_expr(expr).object());
258  return check_renaming_l1(index_expr.array()) ||
259  check_renaming(index_expr.index());
260  }
261  else if(expr.id() == ID_symbol)
262  {
263  const auto &type = expr.type();
264  if(!expr.get_bool(ID_C_SSA_symbol))
265  return type.id() != ID_code && type.id() != ID_mathematical_function;
266  if(to_ssa_expr(expr).get_level_2().empty())
267  return true;
268  if(to_ssa_expr(expr).get_original_expr().type() != type)
269  return true;
270  }
271  else if(expr.id() == ID_nil)
272  {
273  return expr != nil_exprt{};
274  }
275  else
276  {
277  for(const auto &op : expr.operands())
278  {
279  if(check_renaming(op))
280  return true;
281  }
282  }
283 
284  return false;
285 }
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
bool empty() const
Definition: dstring.h:89
Base class for all expressions.
Definition: expr.h:56
typet & type()
Return the type of the expression.
Definition: expr.h:84
operandst & operands()
Definition: expr.h:94
static irep_idt guard_identifier()
bool get_bool(const irep_idt &name) const
Definition: irep.cpp:57
const irep_idt & id() const
Definition: irep.h:384
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
const typet & base_type() const
The type of the data what we point to.
Definition: pointer_expr.h:35
Wrapper for expressions or types which have been renamed up to a given level.
Definition: renamed.h:33
const underlyingt & get() const
Definition: renamed.h:40
underlyingt & value()
Definition: renamed.h:54
void insert(const key_type &k, valueU &&m)
Insert element, element must not exist in map.
Definition: sharing_map.h:1348
bool has_key(const key_type &k) const
Check if key is in map.
Definition: sharing_map.h:377
void replace(const key_type &k, valueU &&m)
Replace element, element must exist in map.
Definition: sharing_map.h:1425
std::vector< delta_view_itemt > delta_viewt
Delta view of the key-value pairs in two maps.
Definition: sharing_map.h:439
std::optional< std::reference_wrapper< const mapped_type > > find(const key_type &k) const
Find element.
Definition: sharing_map.h:1451
void get_delta_view(const sharing_mapt &other, delta_viewt &delta_view, const bool only_common=true) const
Get a delta view of the elements in the map.
Definition: sharing_map.h:939
Expression providing an SSA-renamed symbol of expressions.
Definition: ssa_expr.h:17
const irep_idt get_level_0() const
Definition: ssa_expr.h:63
void set_level_0(std::size_t i)
const exprt & get_original_expr() const
Definition: ssa_expr.h:33
irep_idt get_object_name() const
Base type for structs and unions.
Definition: std_types.h:62
const componentst & components() const
Definition: std_types.h:147
std::vector< componentt > componentst
Definition: std_types.h:140
Symbol table entry.
Definition: symbol.h:28
typet type
Type of symbol.
Definition: symbol.h:31
bool is_shared() const
Definition: symbol.h:101
The type of an expression, extends irept.
Definition: type.h:29
bool has_subtype() const
Definition: type.h:64
#define Forall_operands(it, expr)
Definition: expr.h:27
Symbolic Execution.
const std::string & id2string(const irep_idt &d)
Definition: irep.h:40
API to expression classes for Pointers.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:93
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
Definition: pointer_expr.h:577
exprt get_original_name(exprt expr)
Undo all levels of renaming.
bool check_renaming(const typet &type)
Check that type is correctly renamed to level 2 and return true in case an error is detected.
renamedt< ssa_exprt, L0 > symex_level0(ssa_exprt ssa_expr, const namespacet &ns, std::size_t thread_nr)
Set the level 0 renaming of SSA expressions.
bool check_renaming_l1(const exprt &expr)
Check that expr is correctly renamed to level 1 and return true in case an error is detected.
Renaming levels.
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition: invariant.h:423
const ssa_exprt & to_ssa_expr(const exprt &expr)
Cast a generic exprt to an ssa_exprt.
Definition: ssa_expr.h:145
bool is_ssa_expr(const exprt &expr)
Definition: ssa_expr.h:125
auto component(T &struct_expr, const irep_idt &name, const namespacet &ns) -> decltype(struct_expr.op0())
Definition: std_expr.cpp:80
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1533
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:888
const struct_union_typet & to_struct_union_type(const typet &type)
Cast a typet to a struct_union_typet.
Definition: std_types.h:214
Functor to set the level 1 renaming of SSA expressions.
symex_renaming_levelt current_names
std::optional< std::pair< ssa_exprt, std::size_t > > insert_or_replace(const renamedt< ssa_exprt, L0 > &ssa, std::size_t index)
Set the index for ssa to index.
void restore_from(const symex_level1t &other)
Insert the content of other into this renaming.
renamedt< ssa_exprt, L1 > operator()(renamedt< ssa_exprt, L0 > l0_expr) const
bool has(const renamedt< ssa_exprt, L0 > &ssa) const
void insert(const renamedt< ssa_exprt, L0 > &ssa, std::size_t index)
Assume ssa is not already known.
unsigned latest_index(const irep_idt &identifier) const
Counter corresponding to an identifier.
renamedt< ssa_exprt, L2 > operator()(renamedt< ssa_exprt, L1 > l1_expr) const
Set L2 tag to correspond to the current count of the identifier of l1_expr's.
symex_renaming_levelt current_names
std::size_t increase_generation(const irep_idt &l1_identifier, const ssa_exprt &lhs, std::function< std::size_t(const irep_idt &)> fresh_l2_name_provider)
Allocates a fresh L2 name for the given L1 identifier, and makes it the latest generation on this pat...
Symbol table entry.
const type_with_subtypet & to_type_with_subtype(const typet &type)
Definition: type.h:208