CBMC
constant_pointer_abstract_object.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3  Module: analyses variable-sensitivity
4 
5  Author: Thomas Kiley, thomas.kiley@diffblue.com
6 
7 \*******************************************************************/
8 
10 
12 #include <util/arith_tools.h>
13 #include <util/c_types.h>
14 #include <util/pointer_expr.h>
15 #include <util/std_expr.h>
16 
17 #include <ostream>
18 
20 
22  const typet &type)
24 {
25  PRECONDITION(type.id() == ID_pointer);
26 }
27 
29  const typet &type,
30  bool top,
31  bool bottom)
32  : abstract_pointer_objectt(type, top, bottom)
33 {
34  PRECONDITION(type.id() == ID_pointer);
35 }
36 
38  const typet &new_type,
40  : abstract_pointer_objectt(new_type, old.is_top(), old.is_bottom()),
41  value_stack(old.value_stack)
42 {
43 }
44 
46  const exprt &expr,
47  const abstract_environmentt &environment,
48  const namespacet &ns)
49  : abstract_pointer_objectt(expr, environment, ns),
50  value_stack(expr, environment, ns)
51 {
52  PRECONDITION(expr.type().id() == ID_pointer);
54  {
55  set_top();
56  }
57  else
58  {
59  set_not_top();
60  }
61 }
62 
64  const abstract_object_pointert &other,
65  const widen_modet &widen_mode) const
66 {
67  auto cast_other =
68  std::dynamic_pointer_cast<const constant_pointer_abstract_objectt>(other);
69  if(cast_other)
70  return merge_constant_pointers(cast_other, widen_mode);
71 
72  return abstract_pointer_objectt::merge(other, widen_mode);
73 }
74 
76  abstract_object_pointert other) const
77 {
78  auto cast_other =
79  std::dynamic_pointer_cast<const constant_pointer_abstract_objectt>(other);
80 
81  if(value_stack.is_top_value() || cast_other->value_stack.is_top_value())
82  return false;
83 
84  if(value_stack.depth() != cast_other->value_stack.depth())
85  return false;
86 
87  for(size_t d = 0; d != value_stack.depth() - 1; ++d)
88  if(
90  cast_other->value_stack.target_expression(d))
91  return false;
92 
93  return true;
94 }
95 
97 {
99  return nil_exprt();
101 }
102 
104  abstract_object_pointert other) const
105 {
106  auto cast_other =
107  std::dynamic_pointer_cast<const constant_pointer_abstract_objectt>(other);
108 
109  if(value_stack.is_top_value() || cast_other->value_stack.is_top_value())
110  return nil_exprt();
111 
112  return minus_exprt(
114  cast_other->value_stack.offset_expression());
115 }
116 
120  const widen_modet &widen_mode) const
121 {
122  if(is_bottom())
123  return std::make_shared<constant_pointer_abstract_objectt>(*other);
124 
125  bool matching_pointers =
126  value_stack.to_expression() == other->value_stack.to_expression();
127 
128  if(matching_pointers)
129  return shared_from_this();
130 
131  return abstract_pointer_objectt::merge(other, widen_mode);
132 }
133 
135 {
136  if(is_top() || is_bottom())
137  {
139  }
140  else
141  {
142  // TODO(tkiley): I think we would like to eval this before using it
143  // in the to_constant.
144  return value_stack.to_expression();
145  }
146 }
147 
149  std::ostream &out,
150  const ai_baset &ai,
151  const namespacet &ns) const
152 {
153  if(is_top() || is_bottom() || value_stack.is_top_value())
154  {
156  }
157  else
158  {
159  out << "ptr ->(";
160  const exprt &value = value_stack.to_expression();
161  if(value.id() == ID_address_of)
162  {
163  const auto &addressee = to_address_of_expr(value).object();
164  if(addressee.id() == ID_symbol)
165  {
166  const symbol_exprt &symbol_pointed_to(to_symbol_expr(addressee));
167 
168  out << symbol_pointed_to.get_identifier();
169  }
170  else if(addressee.id() == ID_dynamic_object)
171  {
172  out << addressee.get(ID_identifier);
173  }
174  else if(addressee.id() == ID_index)
175  {
176  auto const &array_index = to_index_expr(addressee);
177  auto const &array = array_index.array();
178  if(array.id() == ID_symbol)
179  {
180  auto const &array_symbol = to_symbol_expr(array);
181  out << array_symbol.get_identifier() << "[";
182  if(array_index.index().id() == ID_constant)
183  out << to_constant_expr(array_index.index()).get_value();
184  else
185  out << "?";
186  out << "]";
187  }
188  }
189  }
190 
191  out << ")";
192  }
193 }
194 
196  const abstract_environmentt &env,
197  const namespacet &ns) const
198 {
199  if(is_top() || is_bottom() || value_stack.is_top_value())
200  {
201  // Return top if dereferencing a null pointer or we are top
202  bool is_value_top = is_top() || value_stack.is_top_value();
203  return env.abstract_object_factory(
204  to_pointer_type(type()).base_type(), ns, is_value_top, !is_value_top);
205  }
206  else
207  {
208  return env.eval(
210  }
211 }
212 
214  abstract_environmentt &environment,
215  const namespacet &ns,
216  const std::stack<exprt> &stack,
217  const abstract_object_pointert &new_value,
218  bool merging_write) const
219 {
220  if(is_top() || is_bottom())
221  {
222  environment.havoc("Writing to a 2value pointer");
223  return shared_from_this();
224  }
225 
227  return std::make_shared<constant_pointer_abstract_objectt>(
228  type(), true, false);
229 
230  if(stack.empty())
231  {
232  // We should not be changing the type of an abstract object
233  PRECONDITION(
234  new_value->type() == ns.follow(to_pointer_type(type()).base_type()));
235 
236  // Get an expression that we can assign to
238  if(merging_write)
239  {
240  abstract_object_pointert pointed_value = environment.eval(value, ns);
241  abstract_object_pointert merged_value =
242  abstract_objectt::merge(pointed_value, new_value, widen_modet::no)
243  .object;
244  environment.assign(value, merged_value, ns);
245  }
246  else
247  {
248  environment.assign(value, new_value, ns);
249  }
250  }
251  else
252  {
254  abstract_object_pointert pointed_value = environment.eval(value, ns);
255  abstract_object_pointert modified_value =
256  environment.write(pointed_value, new_value, stack, ns, merging_write);
257  environment.assign(value, modified_value, ns);
258  // but the pointer itself does not change!
259  }
260 
261  return shared_from_this();
262 }
263 
265  const typet &new_type,
266  const abstract_environmentt &environment,
267  const namespacet &ns) const
268 {
269  INVARIANT(is_void_pointer(type()), "Only allow pointer casting from void*");
270 
271  // Get an expression that we can assign to
273  if(value.id() == ID_dynamic_object)
274  {
275  auto &env = const_cast<abstract_environmentt &>(environment);
276 
277  auto heap_array_type =
278  array_typet(to_pointer_type(new_type).base_type(), nil_exprt());
279  auto array_object =
280  environment.abstract_object_factory(heap_array_type, ns, true, false);
281  auto heap_symbol = symbol_exprt(value.get(ID_identifier), heap_array_type);
282  env.assign(heap_symbol, array_object, ns);
283  auto heap_address = address_of_exprt(
284  index_exprt(heap_symbol, from_integer(0, signed_size_type())));
285  auto new_pointer = std::make_shared<constant_pointer_abstract_objectt>(
286  heap_address, env, ns);
287  return new_pointer;
288  }
289 
290  return std::make_shared<constant_pointer_abstract_objectt>(new_type, *this);
291 }
292 
294  abstract_object_statisticst &statistics,
295  abstract_object_visitedt &visited,
296  const abstract_environmentt &env,
297  const namespacet &ns) const
298 {
299  abstract_pointer_objectt::get_statistics(statistics, visited, env, ns);
300  // don't bother following nullptr
301  if(!is_top() && !is_bottom() && !value_stack.is_top_value())
302  {
303  read_dereference(env, ns)->get_statistics(statistics, visited, env, ns);
304  }
305  statistics.objects_memory_usage += memory_sizet::from_bytes(sizeof(*this));
306 }
307 
309  const exprt &expr,
310  const std::vector<abstract_object_pointert> &operands,
311  const abstract_environmentt &environment,
312  const namespacet &ns) const
313 {
314  auto &rhs = operands.back();
315 
316  if(same_target(rhs))
317  return environment.eval(offset_from(rhs), ns);
318 
320  expr, operands, environment, ns);
321 }
322 
323 static exprt to_bool_expr(bool v)
324 {
325  if(v)
326  return true_exprt();
327  return false_exprt();
328 }
329 
331  irep_idt const &id,
332  exprt const &lhs,
333  exprt const &rhs)
334 {
335  auto const &lhs_member = to_member_expr(lhs).get_component_name();
336  auto const &rhs_member = to_member_expr(rhs).get_component_name();
337 
338  if(id == ID_equal)
339  return to_bool_expr(lhs_member == rhs_member);
340  if(id == ID_notequal)
341  return to_bool_expr(lhs_member != rhs_member);
342  return nil_exprt();
343 }
344 
346  irep_idt const &id,
347  exprt const &lhs,
348  exprt const &rhs)
349 {
350  auto const &lhs_identifier = to_symbol_expr(lhs).get_identifier();
351  auto const &rhs_identifier = to_symbol_expr(rhs).get_identifier();
352 
353  if(id == ID_equal)
354  return to_bool_expr(lhs_identifier == rhs_identifier);
355  if(id == ID_notequal)
356  return to_bool_expr(lhs_identifier != rhs_identifier);
357  return nil_exprt();
358 }
359 
361  const exprt &expr,
362  const std::vector<abstract_object_pointert> &operands,
363  const abstract_environmentt &environment,
364  const namespacet &ns) const
365 {
366  auto rhs = std::dynamic_pointer_cast<const constant_pointer_abstract_objectt>(
367  operands.back());
368 
369  if(is_top() || rhs->is_top())
370  return nil_exprt();
371 
372  if(same_target(rhs)) // rewrite in terms of pointer offset
373  {
374  auto lhs_offset = offset();
375  auto rhs_offset = rhs->offset();
376 
377  if(lhs_offset.id() == ID_member)
379  expr.id(), lhs_offset, rhs_offset);
380  if(lhs_offset.id() == ID_symbol)
381  return symbol_ptr_comparison_expr(expr.id(), lhs_offset, rhs_offset);
382 
383  return binary_relation_exprt(lhs_offset, expr.id(), rhs_offset);
384  }
385 
386  // not same target, can only eval == and !=
387  if(expr.id() == ID_equal)
388  return false_exprt();
389  if(expr.id() == ID_notequal)
390  return true_exprt();
391  return nil_exprt();
392 }
393 
395  const exprt &name) const
396 {
397  return equal_exprt(name, value_stack.to_expression());
398 }
widen_modet
widen_modet
Definition: abstract_environment.h:32
dstringt
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:36
constant_pointer_abstract_objectt::output
void output(std::ostream &out, const ai_baset &ai, const namespacet &ns) const override
Print the value of the pointer.
Definition: constant_pointer_abstract_object.cpp:148
write_stackt::is_top_value
bool is_top_value() const
Is the stack representing an unknown value and hence can't be written to or read from.
Definition: write_stack.cpp:224
abstract_object_pointert
sharing_ptrt< class abstract_objectt > abstract_object_pointert
Definition: abstract_object.h:69
abstract_objectt::is_top
virtual bool is_top() const
Find out if the abstract object is top.
Definition: abstract_object.cpp:155
abstract_objectt::output
virtual void output(std::ostream &out, const class ai_baset &ai, const namespacet &ns) const
Print the value of the abstract object.
Definition: abstract_object.cpp:190
arith_tools.h
address_of_exprt::object
exprt & object()
Definition: pointer_expr.h:380
abstract_environmentt::write
virtual abstract_object_pointert write(const abstract_object_pointert &lhs, const abstract_object_pointert &rhs, std::stack< exprt > remaining_stack, const namespacet &ns, bool merge_write)
Used within assign to do the actual dispatch.
Definition: abstract_environment.cpp:237
write_stackt::depth
size_t depth() const
Definition: write_stack.cpp:193
widen_modet::no
@ no
typet
The type of an expression, extends irept.
Definition: type.h:28
constant_pointer_abstract_objectt::ptr_diff
abstract_object_pointert ptr_diff(const exprt &expr, const std::vector< abstract_object_pointert > &operands, const abstract_environmentt &environment, const namespacet &ns) const override
Definition: constant_pointer_abstract_object.cpp:308
to_index_expr
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1478
abstract_objectt::type
virtual const typet & type() const
Get the real type of the variable this abstract object is representing.
Definition: abstract_object.cpp:47
constant_pointer_abstract_objectt::write_dereference
abstract_object_pointert write_dereference(abstract_environmentt &environment, const namespacet &ns, const std::stack< exprt > &stack, const abstract_object_pointert &value, bool merging_write) const override
A helper function to evaluate writing to a pointers value.
Definition: constant_pointer_abstract_object.cpp:213
constant_pointer_abstract_objectt::value_stack
write_stackt value_stack
Definition: constant_pointer_abstract_object.h:168
abstract_environmentt::assign
virtual bool assign(const exprt &expr, const abstract_object_pointert &value, const namespacet &ns)
Assign a value to an expression.
Definition: abstract_environment.cpp:147
abstract_pointer_objectt
Definition: abstract_pointer_object.h:20
abstract_objectt::set_top
void set_top()
Definition: abstract_object.h:476
abstract_environmentt
Definition: abstract_environment.h:40
exprt
Base class for all expressions.
Definition: expr.h:55
symbol_ptr_comparison_expr
exprt symbol_ptr_comparison_expr(irep_idt const &id, exprt const &lhs, exprt const &rhs)
Definition: constant_pointer_abstract_object.cpp:345
abstract_environmentt::havoc
virtual void havoc(const std::string &havoc_string)
This should be used as a default case / everything else has failed The string is so that I can easily...
Definition: abstract_environment.cpp:379
constant_pointer_abstract_objectt::merge_constant_pointers
abstract_object_pointert merge_constant_pointers(const constant_pointer_abstract_pointert &other, const widen_modet &widen_mode) const
Merges two constant pointers.
Definition: constant_pointer_abstract_object.cpp:118
symbol_exprt
Expression to hold a symbol (variable)
Definition: std_expr.h:112
equal_exprt
Equality.
Definition: std_expr.h:1305
constant_pointer_abstract_objectt::offset
exprt offset() const
Definition: constant_pointer_abstract_object.cpp:96
struct_member_ptr_comparison_expr
exprt struct_member_ptr_comparison_expr(irep_idt const &id, exprt const &lhs, exprt const &rhs)
Definition: constant_pointer_abstract_object.cpp:330
irept::get
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:45
abstract_pointer_objectt::get_statistics
void get_statistics(abstract_object_statisticst &statistics, abstract_object_visitedt &visited, const abstract_environmentt &env, const namespacet &ns) const override
Definition: abstract_pointer_object.cpp:76
namespacet
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:90
constant_pointer_abstract_objectt::constant_pointer_abstract_pointert
sharing_ptrt< constant_pointer_abstract_objectt > constant_pointer_abstract_pointert
Definition: constant_pointer_abstract_object.h:23
constant_pointer_abstract_objectt::same_target
bool same_target(abstract_object_pointert other) const
Definition: constant_pointer_abstract_object.cpp:75
exprt::type
typet & type()
Return the type of the expression.
Definition: expr.h:84
constant_pointer_abstract_objectt::typecast
abstract_object_pointert typecast(const typet &new_type, const abstract_environmentt &environment, const namespacet &ns) const override
Definition: constant_pointer_abstract_object.cpp:264
abstract_objectt::merge
static combine_result merge(const abstract_object_pointert &op1, const abstract_object_pointert &op2, const locationt &merge_location, const widen_modet &widen_mode)
Definition: abstract_object.cpp:209
constant_pointer_abstract_objectt::read_dereference
abstract_object_pointert read_dereference(const abstract_environmentt &env, const namespacet &ns) const override
A helper function to dereference a value from a pointer.
Definition: constant_pointer_abstract_object.cpp:195
constant_pointer_abstract_objectt::merge
abstract_object_pointert merge(const abstract_object_pointert &op1, const widen_modet &widen_mode) const override
Set this abstract object to be the result of merging this abstract object.
Definition: constant_pointer_abstract_object.cpp:63
abstract_object_statisticst
Definition: abstract_object_statistics.h:18
write_stackt::target_expression
exprt target_expression(size_t depth) const
Definition: write_stack.cpp:198
abstract_environmentt::abstract_object_factory
virtual abstract_object_pointert abstract_object_factory(const typet &type, const namespacet &ns, bool top, bool bottom) const
Look at the configuration for the sensitivity and create an appropriate abstract_object.
Definition: abstract_environment.cpp:312
to_bool_expr
static exprt to_bool_expr(bool v)
Definition: constant_pointer_abstract_object.cpp:323
PRECONDITION
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
symbol_exprt::get_identifier
const irep_idt & get_identifier() const
Definition: std_expr.h:142
nil_exprt
The NIL expression.
Definition: std_expr.h:3025
constant_pointer_abstract_objectt
Definition: constant_pointer_abstract_object.h:19
constant_pointer_abstract_object.h
pointer_expr.h
abstract_environment.h
signed_size_type
signedbv_typet signed_size_type()
Definition: c_types.cpp:84
abstract_objectt::to_constant
virtual exprt to_constant() const
Converts to a constant expression if possible.
Definition: abstract_object.cpp:170
to_pointer_type
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:79
to_symbol_expr
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:222
constant_pointer_abstract_objectt::to_constant
exprt to_constant() const override
To try and find a constant expression for this abstract object.
Definition: constant_pointer_abstract_object.cpp:134
abstract_environmentt::eval
virtual abstract_object_pointert eval(const exprt &expr, const namespacet &ns) const
These three are really the heart of the method.
Definition: abstract_environment.cpp:94
irept::id
const irep_idt & id() const
Definition: irep.h:396
false_exprt
The Boolean constant false.
Definition: std_expr.h:3016
abstract_object_visitedt
std::set< abstract_object_pointert > abstract_object_visitedt
Definition: abstract_object.h:70
minus_exprt
Binary minus.
Definition: std_expr.h:1005
constant_pointer_abstract_objectt::constant_pointer_abstract_objectt
constant_pointer_abstract_objectt(const typet &type)
Definition: constant_pointer_abstract_object.cpp:21
write_stackt::offset_expression
exprt offset_expression() const
Definition: write_stack.cpp:204
array_typet
Arrays with given size.
Definition: std_types.h:762
constant_pointer_abstract_objectt::offset_from
exprt offset_from(abstract_object_pointert other) const
Definition: constant_pointer_abstract_object.cpp:103
namespace_baset::follow
const typet & follow(const typet &) const
Resolve type symbol to the type it points to.
Definition: namespace.cpp:49
constant_pointer_abstract_objectt::to_predicate_internal
exprt to_predicate_internal(const exprt &name) const override
to_predicate implementation - derived classes will override
Definition: constant_pointer_abstract_object.cpp:394
abstract_object_statistics.h
from_integer
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Definition: arith_tools.cpp:100
binary_relation_exprt
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition: std_expr.h:706
abstract_object_statisticst::objects_memory_usage
memory_sizet objects_memory_usage
An underestimation of the memory usage of the abstract objects.
Definition: abstract_object_statistics.h:28
ai_baset
This is the basic interface of the abstract interpreter with default implementations of the core func...
Definition: ai.h:118
abstract_objectt::set_not_top
void set_not_top()
Definition: abstract_object.h:481
constant_pointer_abstract_objectt::get_statistics
void get_statistics(abstract_object_statisticst &statistics, abstract_object_visitedt &visited, const abstract_environmentt &env, const namespacet &ns) const override
Definition: constant_pointer_abstract_object.cpp:293
to_member_expr
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2886
member_exprt::get_component_name
irep_idt get_component_name() const
Definition: std_expr.h:2816
to_address_of_expr
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
Definition: pointer_expr.h:408
index_exprt
Array index operator.
Definition: std_expr.h:1409
is_void_pointer
bool is_void_pointer(const typet &type)
This method tests, if the given typet is a pointer of type void.
Definition: pointer_expr.h:96
address_of_exprt
Operator to return the address of an object.
Definition: pointer_expr.h:370
abstract_objectt::is_bottom
virtual bool is_bottom() const
Find out if the abstract object is bottom.
Definition: abstract_object.cpp:160
abstract_objectt::combine_result::object
abstract_object_pointert object
Definition: abstract_object.h:264
true_exprt
The Boolean constant true.
Definition: std_expr.h:3007
write_stackt::to_expression
exprt to_expression() const
Convert the stack to an expression that can be used to write to.
Definition: write_stack.cpp:175
std_expr.h
constant_exprt::get_value
const irep_idt & get_value() const
Definition: std_expr.h:2950
memory_sizet::from_bytes
static memory_sizet from_bytes(std::size_t bytes)
Definition: memory_units.cpp:38
c_types.h
constant_pointer_abstract_objectt::ptr_comparison_expr
exprt ptr_comparison_expr(const exprt &expr, const std::vector< abstract_object_pointert > &operands, const abstract_environmentt &environment, const namespacet &ns) const override
Definition: constant_pointer_abstract_object.cpp:360
abstract_objectt::expression_transform
virtual abstract_object_pointert expression_transform(const exprt &expr, const std::vector< abstract_object_pointert > &operands, const abstract_environmentt &environment, const namespacet &ns) const
Interface for transforms.
Definition: abstract_object.cpp:112
validation_modet::INVARIANT
@ INVARIANT
to_constant_expr
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:2992