CBMC
field_sensitivity.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Field-sensitive SSA
4 
5 Author: Michael Tautschnig
6 
7 \*******************************************************************/
8 
9 #include "field_sensitivity.h"
10 
11 #include <util/arith_tools.h>
12 #include <util/byte_operators.h>
13 #include <util/c_types.h>
15 #include <util/simplify_expr.h>
16 
17 #include "goto_symex_state.h"
18 #include "symex_target.h"
19 
20 #define ENABLE_ARRAY_FIELD_SENSITIVITY
21 
23  const namespacet &ns,
24  goto_symex_statet &state,
25  ssa_exprt ssa_expr,
26  bool write) const
27 {
28  if(write)
29  return std::move(ssa_expr);
30  else
31  return get_fields(ns, state, ssa_expr, true);
32 }
33 
35  const namespacet &ns,
36  goto_symex_statet &state,
37  exprt expr,
38  bool write) const
39 {
40  if(expr.id() != ID_address_of)
41  {
42  Forall_operands(it, expr)
43  *it = apply(ns, state, std::move(*it), write);
44  }
45 
46  if(!write && is_ssa_expr(expr))
47  {
48  return get_fields(ns, state, to_ssa_expr(expr), true);
49  }
50  else if(
51  !write && expr.id() == ID_member &&
52  to_member_expr(expr).struct_op().id() == ID_struct)
53  {
54  return simplify_opt(std::move(expr), ns);
55  }
56 #ifdef ENABLE_ARRAY_FIELD_SENSITIVITY
57  else if(
58  !write && expr.id() == ID_index &&
59  to_index_expr(expr).array().id() == ID_array)
60  {
61  return simplify_opt(std::move(expr), ns);
62  }
63 #endif // ENABLE_ARRAY_FIELD_SENSITIVITY
64  else if(expr.id() == ID_member)
65  {
66  // turn a member-of-an-SSA-expression into a single SSA expression, thus
67  // encoding the member as an individual symbol rather than only the full
68  // struct
69  member_exprt &member = to_member_expr(expr);
70 
71  if(
72  is_ssa_expr(member.struct_op()) &&
73  (member.struct_op().type().id() == ID_struct ||
74  member.struct_op().type().id() == ID_struct_tag ||
75  member.struct_op().type().id() == ID_union ||
76  member.struct_op().type().id() == ID_union_tag))
77  {
78  // place the entire member expression, not just the struct operand, in an
79  // SSA expression
80  ssa_exprt tmp = to_ssa_expr(member.struct_op());
81  bool was_l2 = !tmp.get_level_2().empty();
82 
83  tmp.remove_level_2();
84  member.struct_op() = tmp.get_original_expr();
85  tmp.set_expression(member);
86  if(was_l2)
87  return apply(ns, state, state.rename(std::move(tmp), ns).get(), write);
88  else
89  return apply(ns, state, std::move(tmp), write);
90  }
91  }
92  else if(
93  !write && (expr.id() == ID_byte_extract_little_endian ||
94  expr.id() == ID_byte_extract_big_endian))
95  {
96  const byte_extract_exprt &be = to_byte_extract_expr(expr);
97  if(
98  (be.op().type().id() == ID_union ||
99  be.op().type().id() == ID_union_tag) &&
100  is_ssa_expr(be.op()) && be.offset().is_constant())
101  {
102  const union_typet &type =
103  be.op().type().id() == ID_union_tag
104  ? ns.follow_tag(to_union_tag_type(be.op().type()))
105  : to_union_type(be.op().type());
106  for(const auto &comp : type.components())
107  {
108  ssa_exprt tmp = to_ssa_expr(be.op());
109  bool was_l2 = !tmp.get_level_2().empty();
110  tmp.remove_level_2();
111  const member_exprt member{tmp.get_original_expr(), comp};
112  auto recursive_member =
113  get_subexpression_at_offset(member, be.offset(), be.type(), ns);
114  if(
115  recursive_member.has_value() &&
116  (recursive_member->id() == ID_member ||
117  recursive_member->id() == ID_index))
118  {
119  tmp.type() = be.type();
120  tmp.set_expression(*recursive_member);
121  if(was_l2)
122  {
123  return apply(
124  ns, state, state.rename(std::move(tmp), ns).get(), write);
125  }
126  else
127  return apply(ns, state, std::move(tmp), write);
128  }
129  else if(
130  recursive_member.has_value() && recursive_member->id() == ID_typecast)
131  {
132  if(was_l2)
133  {
134  return apply(
135  ns,
136  state,
137  state.rename(std::move(*recursive_member), ns).get(),
138  write);
139  }
140  else
141  return apply(ns, state, std::move(*recursive_member), write);
142  }
143  }
144  }
145  }
146 #ifdef ENABLE_ARRAY_FIELD_SENSITIVITY
147  else if(expr.id() == ID_index)
148  {
149  // turn a index-of-an-SSA-expression into a single SSA expression, thus
150  // encoding the index access into an array as an individual symbol rather
151  // than only the full array
152  index_exprt &index = to_index_expr(expr);
153  if(should_simplify)
154  simplify(index.index(), ns);
155 
156  if(
157  is_ssa_expr(index.array()) && index.array().type().id() == ID_array &&
158  index.index().is_constant())
159  {
160  // place the entire index expression, not just the array operand, in an
161  // SSA expression
162  ssa_exprt tmp = to_ssa_expr(index.array());
163  auto l2_index = state.rename(index.index(), ns);
164  if(should_simplify)
165  l2_index.simplify(ns);
166  bool was_l2 = !tmp.get_level_2().empty();
167  exprt l2_size =
168  state.rename(to_array_type(index.array().type()).size(), ns).get();
169  if(l2_size.is_nil() && index.array().id() == ID_symbol)
170  {
171  // In case the array type was incomplete, attempt to retrieve it from
172  // the symbol table.
173  const symbolt *array_from_symbol_table = ns.get_symbol_table().lookup(
174  to_symbol_expr(index.array()).get_identifier());
175  if(array_from_symbol_table != nullptr)
176  l2_size = to_array_type(array_from_symbol_table->type).size();
177  }
178 
179  if(
180  l2_size.is_constant() &&
181  numeric_cast_v<mp_integer>(to_constant_expr(l2_size)) <=
183  {
184  if(l2_index.get().is_constant())
185  {
186  // place the entire index expression, not just the array operand,
187  // in an SSA expression
188  ssa_exprt ssa_array = to_ssa_expr(index.array());
189  ssa_array.remove_level_2();
190  index.array() = ssa_array.get_original_expr();
191  index.index() = l2_index.get();
192  tmp.set_expression(index);
193  if(was_l2)
194  {
195  return apply(
196  ns, state, state.rename(std::move(tmp), ns).get(), write);
197  }
198  else
199  return apply(ns, state, std::move(tmp), write);
200  }
201  else if(!write)
202  {
203  // Expand the array and return `{array[0]; array[1]; ...}[index]`
204  exprt expanded_array =
205  get_fields(ns, state, to_ssa_expr(index.array()), true);
206  return index_exprt{std::move(expanded_array), index.index()};
207  }
208  }
209  }
210  }
211 #endif // ENABLE_ARRAY_FIELD_SENSITIVITY
212  return expr;
213 }
214 
216  const namespacet &ns,
217  goto_symex_statet &state,
218  const ssa_exprt &ssa_expr,
219  bool disjoined_fields_only) const
220 {
221  if(
222  ssa_expr.type().id() == ID_struct ||
223  ssa_expr.type().id() == ID_struct_tag ||
224  (!disjoined_fields_only && (ssa_expr.type().id() == ID_union ||
225  ssa_expr.type().id() == ID_union_tag)))
226  {
227  const struct_union_typet::componentst &components =
228  (ssa_expr.type().id() == ID_struct_tag ||
229  ssa_expr.type().id() == ID_union_tag)
231  .components()
232  : to_struct_union_type(ssa_expr.type()).components();
233 
234  exprt::operandst fields;
235  fields.reserve(components.size());
236 
237  const exprt &compound_op = ssa_expr.get_original_expr();
238 
239  for(const auto &comp : components)
240  {
241  ssa_exprt tmp = ssa_expr;
242  bool was_l2 = !tmp.get_level_2().empty();
243  tmp.remove_level_2();
244  tmp.set_expression(
245  member_exprt{compound_op, comp.get_name(), comp.type()});
246  exprt field = get_fields(ns, state, tmp, disjoined_fields_only);
247  if(was_l2)
248  {
249  fields.emplace_back(state.rename(std::move(field), ns).get());
250  }
251  else
252  fields.emplace_back(std::move(field));
253  }
254 
255  if(
256  disjoined_fields_only && (ssa_expr.type().id() == ID_struct ||
257  ssa_expr.type().id() == ID_struct_tag))
258  {
259  return struct_exprt{std::move(fields), ssa_expr.type()};
260  }
261  else
262  return field_sensitive_ssa_exprt{ssa_expr, std::move(fields)};
263  }
264 #ifdef ENABLE_ARRAY_FIELD_SENSITIVITY
265  else if(
266  ssa_expr.type().id() == ID_array &&
267  to_array_type(ssa_expr.type()).size().is_constant())
268  {
269  const mp_integer mp_array_size = numeric_cast_v<mp_integer>(
270  to_constant_expr(to_array_type(ssa_expr.type()).size()));
271  if(mp_array_size < 0 || mp_array_size > max_field_sensitivity_array_size)
272  return ssa_expr;
273 
274  const array_typet &type = to_array_type(ssa_expr.type());
275  const std::size_t array_size = numeric_cast_v<std::size_t>(mp_array_size);
276 
277  array_exprt::operandst elements;
278  elements.reserve(array_size);
279 
280  const exprt &array = ssa_expr.get_original_expr();
281 
282  for(std::size_t i = 0; i < array_size; ++i)
283  {
284  const index_exprt index(array, from_integer(i, type.index_type()));
285  ssa_exprt tmp = ssa_expr;
286  bool was_l2 = !tmp.get_level_2().empty();
287  tmp.remove_level_2();
288  tmp.set_expression(index);
289  exprt element = get_fields(ns, state, tmp, disjoined_fields_only);
290  if(was_l2)
291  {
292  elements.emplace_back(state.rename(std::move(element), ns).get());
293  }
294  else
295  elements.emplace_back(std::move(element));
296  }
297 
298  if(disjoined_fields_only)
299  return array_exprt(std::move(elements), type);
300  else
301  return field_sensitive_ssa_exprt{ssa_expr, std::move(elements)};
302  }
303 #endif // ENABLE_ARRAY_FIELD_SENSITIVITY
304  else
305  return ssa_expr;
306 }
307 
309  const namespacet &ns,
310  goto_symex_statet &state,
311  const ssa_exprt &lhs,
312  const exprt &rhs,
313  symex_targett &target,
314  bool allow_pointer_unsoundness) const
315 {
316  const exprt lhs_fs = get_fields(ns, state, lhs, false);
317 
318  if(lhs != lhs_fs)
319  {
321  ns, state, lhs_fs, rhs, target, allow_pointer_unsoundness);
322  // Erase the composite symbol from our working state. Note that we need to
323  // have it in the propagation table and the value set while doing the field
324  // assignments, thus we cannot skip putting it in there above.
325  if(is_divisible(lhs, true))
326  {
327  state.propagation.erase_if_exists(lhs.get_identifier());
328  state.value_set.erase_symbol(lhs, ns);
329  }
330  }
331 }
332 
344  const namespacet &ns,
345  goto_symex_statet &state,
346  const exprt &lhs_fs,
347  const exprt &ssa_rhs,
348  symex_targett &target,
349  bool allow_pointer_unsoundness) const
350 {
351  if(is_ssa_expr(lhs_fs))
352  {
353  const ssa_exprt &l1_lhs = to_ssa_expr(lhs_fs);
354  const ssa_exprt ssa_lhs =
355  state
356  .assignment(l1_lhs, ssa_rhs, ns, true, true, allow_pointer_unsoundness)
357  .get();
358 
359  // do the assignment
360  target.assignment(
361  state.guard.as_expr(),
362  ssa_lhs,
363  ssa_lhs,
364  ssa_lhs.get_original_expr(),
365  ssa_rhs,
366  state.source,
368  // Erase the composite symbol from our working state. Note that we need to
369  // have it in the propagation table and the value set while doing the field
370  // assignments, thus we cannot skip putting it in there above.
371  if(is_divisible(l1_lhs, true))
372  {
373  state.propagation.erase_if_exists(l1_lhs.get_identifier());
374  state.value_set.erase_symbol(l1_lhs, ns);
375  }
376  }
377  else if(
378  ssa_rhs.type().id() == ID_struct || ssa_rhs.type().id() == ID_struct_tag)
379  {
380  const struct_typet &type =
381  ssa_rhs.type().id() == ID_struct_tag
382  ? ns.follow_tag(to_struct_tag_type(ssa_rhs.type()))
383  : to_struct_type(ssa_rhs.type());
384  const struct_union_typet::componentst &components = type.components();
385 
386  PRECONDITION(
387  components.empty() ||
388  (lhs_fs.has_operands() && lhs_fs.operands().size() == components.size()));
389 
390  exprt::operandst::const_iterator fs_it = lhs_fs.operands().begin();
391  for(const auto &comp : components)
392  {
393  const exprt member_rhs = apply(
394  ns,
395  state,
396  simplify_opt(member_exprt{ssa_rhs, comp.get_name(), comp.type()}, ns),
397  false);
398 
399  const exprt &member_lhs = *fs_it;
400  if(
401  auto fs_ssa =
402  expr_try_dynamic_cast<field_sensitive_ssa_exprt>(member_lhs))
403  {
405  ns,
406  state,
407  fs_ssa->get_object_ssa(),
408  member_rhs,
409  target,
410  allow_pointer_unsoundness);
411  }
412 
414  ns, state, member_lhs, member_rhs, target, allow_pointer_unsoundness);
415  ++fs_it;
416  }
417  }
418  else if(
419  ssa_rhs.type().id() == ID_union || ssa_rhs.type().id() == ID_union_tag)
420  {
421  const union_typet &type =
422  ssa_rhs.type().id() == ID_union_tag
423  ? ns.follow_tag(to_union_tag_type(ssa_rhs.type()))
424  : to_union_type(ssa_rhs.type());
425  const struct_union_typet::componentst &components = type.components();
426 
427  PRECONDITION(
428  components.empty() ||
429  (lhs_fs.has_operands() && lhs_fs.operands().size() == components.size()));
430 
431  exprt::operandst::const_iterator fs_it = lhs_fs.operands().begin();
432  for(const auto &comp : components)
433  {
434  const exprt member_rhs = apply(
435  ns,
436  state,
437  simplify_opt(
439  ssa_rhs, from_integer(0, c_index_type()), comp.type()),
440  ns),
441  false);
442 
443  const exprt &member_lhs = *fs_it;
444  if(
445  auto fs_ssa =
446  expr_try_dynamic_cast<field_sensitive_ssa_exprt>(member_lhs))
447  {
449  ns,
450  state,
451  fs_ssa->get_object_ssa(),
452  member_rhs,
453  target,
454  allow_pointer_unsoundness);
455  }
456 
458  ns, state, member_lhs, member_rhs, target, allow_pointer_unsoundness);
459  ++fs_it;
460  }
461  }
462 #ifdef ENABLE_ARRAY_FIELD_SENSITIVITY
463  else if(const auto &type = type_try_dynamic_cast<array_typet>(ssa_rhs.type()))
464  {
465  const std::size_t array_size =
466  numeric_cast_v<std::size_t>(to_constant_expr(type->size()));
467  PRECONDITION(lhs_fs.operands().size() == array_size);
468 
469  if(array_size > max_field_sensitivity_array_size)
470  return;
471 
472  exprt::operandst::const_iterator fs_it = lhs_fs.operands().begin();
473  for(std::size_t i = 0; i < array_size; ++i)
474  {
475  const exprt index_rhs = apply(
476  ns,
477  state,
478  simplify_opt(
479  index_exprt{ssa_rhs, from_integer(i, type->index_type())}, ns),
480  false);
481 
482  const exprt &index_lhs = *fs_it;
483  if(
484  auto fs_ssa =
485  expr_try_dynamic_cast<field_sensitive_ssa_exprt>(index_lhs))
486  {
488  ns,
489  state,
490  fs_ssa->get_object_ssa(),
491  index_rhs,
492  target,
493  allow_pointer_unsoundness);
494  }
495 
497  ns, state, index_lhs, index_rhs, target, allow_pointer_unsoundness);
498  ++fs_it;
499  }
500  }
501 #endif // ENABLE_ARRAY_FIELD_SENSITIVITY
502  else if(lhs_fs.has_operands())
503  {
504  PRECONDITION(
505  ssa_rhs.has_operands() &&
506  lhs_fs.operands().size() == ssa_rhs.operands().size());
507 
508  exprt::operandst::const_iterator fs_it = lhs_fs.operands().begin();
509  for(const exprt &op : ssa_rhs.operands())
510  {
511  if(auto fs_ssa = expr_try_dynamic_cast<field_sensitive_ssa_exprt>(*fs_it))
512  {
514  ns,
515  state,
516  fs_ssa->get_object_ssa(),
517  op,
518  target,
519  allow_pointer_unsoundness);
520  }
521 
523  ns, state, *fs_it, op, target, allow_pointer_unsoundness);
524  ++fs_it;
525  }
526  }
527  else
528  {
529  UNREACHABLE;
530  }
531 }
532 
534  const ssa_exprt &expr,
535  bool disjoined_fields_only) const
536 {
537  if(expr.type().id() == ID_struct || expr.type().id() == ID_struct_tag)
538  return true;
539 
540 #ifdef ENABLE_ARRAY_FIELD_SENSITIVITY
541  if(
542  expr.type().id() == ID_array &&
543  to_array_type(expr.type()).size().is_constant() &&
544  numeric_cast_v<mp_integer>(to_constant_expr(
546  {
547  return true;
548  }
549 #endif
550 
551  if(
552  !disjoined_fields_only &&
553  (expr.type().id() == ID_union || expr.type().id() == ID_union_tag))
554  {
555  return true;
556  }
557 
558  return false;
559 }
560 
562 {
563  if(!should_simplify)
564  return e;
565 
566  return simplify_expr(std::move(e), ns);
567 }
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
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
Array constructor from list of elements.
Definition: std_expr.h:1616
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:34
const exprt & size() const
Definition: std_types.h:840
Expression of type type extracted from some object op starting at position offset (given in number of...
bool empty() const
Definition: dstring.h:89
Base class for all expressions.
Definition: expr.h:56
std::vector< exprt > operandst
Definition: expr.h:58
bool has_operands() const
Return true if there is at least one operand.
Definition: expr.h:91
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
exprt simplify_opt(exprt e, const namespacet &ns) const
const std::size_t max_field_sensitivity_array_size
exprt get_fields(const namespacet &ns, goto_symex_statet &state, const ssa_exprt &ssa_expr, bool disjoined_fields_only) const
Compute an expression representing the individual components of a field-sensitive SSA representation ...
void field_assignments_rec(const namespacet &ns, goto_symex_statet &state, const exprt &lhs_fs, const exprt &ssa_rhs, symex_targett &target, bool allow_pointer_unsoundness) const
Assign to the individual fields lhs_fs of a non-expanded symbol lhs.
exprt apply(const namespacet &ns, goto_symex_statet &state, exprt expr, bool write) const
Turn an expression expr into a field-sensitive SSA expression.
void field_assignments(const namespacet &ns, goto_symex_statet &state, const ssa_exprt &lhs, const exprt &rhs, symex_targett &target, bool allow_pointer_unsoundness) const
Assign to the individual fields of a non-expanded symbol lhs.
bool is_divisible(const ssa_exprt &expr, bool disjoined_fields_only) const
Determine whether expr would translate to an atomic SSA expression (returns false) or a composite obj...
guardt guard
Definition: goto_state.h:58
sharing_mapt< irep_idt, exprt > propagation
Definition: goto_state.h:71
value_sett value_set
Uses level 1 names, and is used to do dereferencing.
Definition: goto_state.h:51
Central data structure: state.
renamedt< ssa_exprt, L2 > assignment(ssa_exprt lhs, const exprt &rhs, const namespacet &ns, bool rhs_is_simplified, bool record_value, bool allow_pointer_unsoundness=false)
renamedt< exprt, level > rename(exprt expr, const namespacet &ns)
Rewrites symbol expressions in exprt, applying a suffix to each symbol reflecting its most recent ver...
symex_targett::sourcet source
exprt as_expr() const
Definition: guard_expr.h:46
Array index operator.
Definition: std_expr.h:1465
exprt & array()
Definition: std_expr.h:1495
exprt & index()
Definition: std_expr.h:1505
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:44
const irep_idt & id() const
Definition: irep.h:388
bool is_nil() const
Definition: irep.h:368
Extract member of struct or union.
Definition: std_expr.h:2844
const exprt & struct_op() const
Definition: std_expr.h:2882
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
const symbol_table_baset & get_symbol_table() const
Return first symbol table registered with the namespace.
Definition: namespace.h:126
Expression providing an SSA-renamed symbol of expressions.
Definition: ssa_expr.h:17
void remove_level_2()
void set_expression(exprt expr)
Replace the underlying, original expression by expr while maintaining SSA indices.
const irep_idt get_level_2() const
Definition: ssa_expr.h:73
const exprt & get_original_expr() const
Definition: ssa_expr.h:33
Struct constructor from list of elements.
Definition: std_expr.h:1872
Structure type, corresponds to C style structs.
Definition: std_types.h:231
const componentst & components() const
Definition: std_types.h:147
std::vector< componentt > componentst
Definition: std_types.h:140
const irep_idt & get_identifier() const
Definition: std_expr.h:160
const symbolt * lookup(const irep_idt &name) const
Find a symbol in the symbol table for read-only access.
Symbol table entry.
Definition: symbol.h:28
typet type
Type of symbol.
Definition: symbol.h:31
The interface of the target container for symbolic execution to record its symbolic steps into.
Definition: symex_target.h:25
virtual void assignment(const exprt &guard, const ssa_exprt &ssa_lhs, const exprt &ssa_full_lhs, const exprt &original_full_lhs, const exprt &ssa_rhs, const sourcet &source, assignment_typet assignment_type)=0
Write to a local variable.
The union type.
Definition: c_types.h:147
void erase_symbol(const symbol_exprt &symbol_expr, const namespacet &ns)
Definition: value_set.cpp:2059
#define Forall_operands(it, expr)
Definition: expr.h:27
Symbolic Execution.
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.
bool simplify(exprt &expr, const namespacet &ns)
exprt simplify_expr(exprt src, const namespacet &ns)
BigInt mp_integer
Definition: smt_terms.h:17
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
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
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:3045
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2936
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1533
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
const struct_union_typet & to_struct_union_type(const typet &type)
Cast a typet to a struct_union_typet.
Definition: std_types.h:214
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 struct_or_union_tag_typet & to_struct_or_union_tag_type(const typet &type)
Cast a typet to a struct_or_union_tag_typet.
Definition: std_types.h:478
Generate Equation using Symbolic Execution.
ssize_t write(int fildes, const void *buf, size_t nbyte)
Definition: unistd.c:195