CBMC
write_stack.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3  Module: Variable Sensitivity Domain
4 
5  Author: DiffBlue Limited.
6 
7 \*******************************************************************/
8 
12 
13 #include "write_stack.h"
14 
15 #include <util/arith_tools.h>
16 #include <util/c_types.h>
17 #include <util/pointer_expr.h>
18 #include <util/std_expr.h>
19 
20 #include "abstract_environment.h"
21 #include "write_stack_entry.h"
22 
23 #include <unordered_set>
24 
26 write_stackt::write_stackt() : stack(), top_stack(true)
27 {
28 }
29 
35  const exprt &expr,
36  const abstract_environmentt &environment,
37  const namespacet &ns)
38 {
39  top_stack = false;
40  if(expr.type().id() == ID_array)
41  {
42  // We are assigning an array to a pointer, which is equivalent to assigning
43  // the first element of that array
44  // &(expr)[0]
47  environment,
48  ns);
49  }
50  else
51  {
52  construct_stack_to_pointer(expr, environment, ns);
53  }
54 }
55 
61  const exprt &expr,
62  const abstract_environmentt &environment,
63  const namespacet &ns)
64 {
65  PRECONDITION(expr.type().id() == ID_pointer);
66 
67  if(expr.id() == ID_address_of)
68  {
69  // resovle reminder, can either be a symbol, member or index of
70  // otherwise unsupported
72  to_address_of_expr(expr).object(), environment, ns);
73  }
74  else if(expr.id() == ID_plus || expr.id() == ID_minus)
75  {
76  exprt base;
77  exprt offset;
78  const integral_resultt &which_side =
79  get_which_side_integral(expr, base, offset);
80  INVARIANT(
82  "An offset must be an integral amount");
83 
84  if(expr.id() == ID_minus)
85  {
86  // can't get a valid pointer by subtracting from a constant number
87  if(which_side == integral_resultt::LHS_INTEGRAL)
88  {
89  top_stack = true;
90  return;
91  }
92  offset = unary_minus_exprt(offset);
93  }
94 
95  abstract_object_pointert offset_value = environment.eval(offset, ns);
96 
98  std::make_shared<offset_entryt>(offset_value), environment, ns);
99 
100  // Build the pointer part
101  construct_stack_to_pointer(base, environment, ns);
102 
103  if(!top_stack)
104  {
105  // check the symbol at the bottom of the stack
106  const auto access = stack.front()->get_access_expr();
107  INVARIANT(
108  !access.second && access.first.id() == ID_symbol,
109  "The base should be an addressable location (i.e. symbol)");
110 
111  if(access.first.type().id() != ID_array)
112  {
113  top_stack = true;
114  }
115  }
116  }
117  else
118  {
119  // unknown expression type - play it safe and set to top
120  top_stack = true;
121  }
122 }
123 
130  const exprt &expr,
131  const abstract_environmentt &environment,
132  const namespacet &ns)
133 {
134  if(!top_stack)
135  {
136  if(expr.id() == ID_member)
137  {
138  add_to_stack(std::make_shared<simple_entryt>(expr), environment, ns);
140  to_member_expr(expr).struct_op(), environment, ns);
141  }
142  else if(expr.id() == ID_symbol || expr.id() == ID_dynamic_object)
143  {
144  add_to_stack(std::make_shared<simple_entryt>(expr), environment, ns);
145  }
146  else if(expr.id() == ID_index)
147  {
148  construct_stack_to_array_index(to_index_expr(expr), environment, ns);
149  }
150  else
151  {
152  top_stack = true;
153  }
154  }
155 }
156 
162  const index_exprt &index_expr,
163  const abstract_environmentt &environment,
164  const namespacet &ns)
165 {
166  abstract_object_pointert offset_value =
167  environment.eval(index_expr.index(), ns);
168 
169  add_to_stack(std::make_shared<offset_entryt>(offset_value), environment, ns);
170  construct_stack_to_lvalue(index_expr.array(), environment, ns);
171 }
172 
177 {
178  // A top stack is useless and its expression should not be evaluated
180  PRECONDITION(!stack.empty());
181  exprt access_expr = stack.front()->get_access_expr().first;
182  for(auto it = std::next(stack.begin()); it != stack.end(); ++it)
183  {
184  const auto access = (*it)->get_access_expr();
185  if(access.second)
186  access_expr = index_exprt{access_expr, access.first};
187  else
188  access_expr = access.first;
189  }
190  address_of_exprt top_expr(access_expr);
191  return std::move(top_expr);
192 }
193 
194 size_t write_stackt::depth() const
195 {
196  return stack.size();
197 }
198 
200 {
202  return stack[depth]->get_access_expr().first;
203 }
204 
206 {
208  auto const access = stack.back()->get_access_expr();
209 
210  if(access.second)
211  return access.first;
212 
213  if(access.first.id() == ID_member || access.first.id() == ID_symbol)
214  return access.first;
215 
216  if(access.first.id() == ID_index)
217  return to_index_expr(access.first).index();
218 
220 }
221 
226 {
227  return top_stack;
228 }
229 
236  std::shared_ptr<write_stack_entryt> entry_pointer,
237  const abstract_environmentt environment,
238  const namespacet &ns)
239 {
240  if(
241  stack.empty() ||
242  !stack.front()->try_squash_in(entry_pointer, environment, ns))
243  {
244  stack.insert(stack.begin(), entry_pointer);
245  }
246 }
247 
256  const exprt &expr,
257  exprt &out_base_expr,
258  exprt &out_integral_expr)
259 {
260  PRECONDITION(expr.operands().size() == 2);
261  const auto binary_e = to_binary_expr(expr);
262  static const std::unordered_set<irep_idt, irep_id_hash> integral_types = {
263  ID_signedbv, ID_unsignedbv, ID_integer};
264  if(integral_types.find(binary_e.lhs().type().id()) != integral_types.cend())
265  {
266  out_integral_expr = binary_e.lhs();
267  out_base_expr = binary_e.rhs();
269  }
270  else if(
271  integral_types.find(binary_e.rhs().type().id()) != integral_types.cend())
272  {
273  out_integral_expr = binary_e.rhs();
274  out_base_expr = binary_e.lhs();
276  }
277  else
278  {
279  out_integral_expr.make_nil();
280  out_base_expr.make_nil();
282  }
283 }
An abstract version of a program environment.
sharing_ptrt< class abstract_objectt > abstract_object_pointert
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
unsignedbv_typet unsigned_long_int_type()
Definition: c_types.cpp:86
signedbv_typet signed_size_type()
Definition: c_types.cpp:66
virtual abstract_object_pointert eval(const exprt &expr, const namespacet &ns) const
These three are really the heart of the method.
Operator to return the address of an object.
Definition: pointer_expr.h:540
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
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 & id() const
Definition: irep.h:384
void make_nil()
Definition: irep.h:442
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
The unary minus expression.
Definition: std_expr.h:484
bool top_stack
Definition: write_stack.h:79
void construct_stack_to_array_index(const index_exprt &expr, const abstract_environmentt &environment, const namespacet &ns)
Construct a stack for an array position l-value.
exprt target_expression(size_t depth) const
exprt offset_expression() const
static integral_resultt get_which_side_integral(const exprt &expr, exprt &out_base_expr, exprt &out_integral_expr)
Utility function to find out which side of a binary operation has an integral type,...
void construct_stack_to_lvalue(const exprt &expr, const abstract_environmentt &environment, const namespacet &ns)
Construct a stack up to a specific l-value (i.e.
write_stackt()
Build a topstack.
Definition: write_stack.cpp:26
bool is_top_value() const
Is the stack representing an unknown value and hence can't be written to or read from.
exprt to_expression() const
Convert the stack to an expression that can be used to write to.
void construct_stack_to_pointer(const exprt &expr, const abstract_environmentt &environment, const namespacet &ns)
Add to the stack the elements to get to a pointer.
Definition: write_stack.cpp:60
size_t depth() const
continuation_stack_storet stack
Definition: write_stack.h:78
void add_to_stack(std::shared_ptr< write_stack_entryt > entry_pointer, const abstract_environmentt environment, const namespacet &ns)
Add an element to the top of the stack.
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.
Definition: pointer_expr.h:577
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
API to expression classes.
const binary_exprt & to_binary_expr(const exprt &expr)
Cast an exprt to a binary_exprt.
Definition: std_expr.h:715
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2933
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1533
Represents a stack of write operations to an addressable memory location.
Represents an entry in the write_stackt.