CBMC
full_struct_abstract_object.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Struct abstract object
4 
5 Author: Thomas Kiley, thomas.kiley@diffblue.com
6 
7 \*******************************************************************/
8 
9 #include <ostream>
10 
12 #include <util/std_expr.h>
13 
16 #include "map_visit.h"
17 
18 // #define DEBUG
19 
20 #ifdef DEBUG
21 # include <iostream>
22 #endif
23 
26  : abstract_aggregate_baset(ao), map(ao.map)
27 {
28 }
29 
32 {
33  PRECONDITION(t.id() == ID_struct);
34  DATA_INVARIANT(verify(), "Structural invariants maintained");
35 }
36 
38  const typet &t,
39  bool top,
40  bool bottom)
41  : abstract_aggregate_baset(t, top, bottom)
42 {
43  PRECONDITION(t.id() == ID_struct);
44  DATA_INVARIANT(verify(), "Structural invariants maintained");
45 }
46 
48  const exprt &e,
49  const abstract_environmentt &environment,
50  const namespacet &ns)
51  : abstract_aggregate_baset(e, environment, ns)
52 {
53  PRECONDITION(ns.follow(e.type()).id() == ID_struct);
54 
55  const struct_typet struct_type_def = to_struct_type(ns.follow(e.type()));
56 
57  bool did_initialize_values = false;
58  auto struct_type_it = struct_type_def.components().begin();
59  for(auto param_it = e.operands().begin(); param_it != e.operands().end();
60  ++param_it, ++struct_type_it)
61  {
63  struct_type_it->get_name(),
64  environment.abstract_object_factory(param_it->type(), *param_it, ns));
65  did_initialize_values = true;
66  }
67 
68  if(did_initialize_values)
69  {
70  set_not_top();
71  }
72 
73  DATA_INVARIANT(verify(), "Structural invariants maintained");
74 }
75 
77  const abstract_environmentt &environment,
78  const exprt &expr,
79  const namespacet &ns) const
80 {
81 #ifdef DEBUG
82  std::cout << "Reading component " << to_member_expr(expr).get_component_name()
83  << '\n';
84 #endif
85 
86  if(is_top())
87  {
88  return environment.abstract_object_factory(expr.type(), ns, true, false);
89  }
90  else
91  {
92  const member_exprt &member_expr = to_member_expr(expr);
94 
95  const irep_idt c = member_expr.get_component_name();
96 
97  auto const value = map.find(c);
98 
99  if(value.has_value())
100  {
101  return value.value();
102  }
103  else
104  {
105  return environment.abstract_object_factory(
106  member_expr.type(), ns, true, false);
107  }
108  }
109 }
110 
112  abstract_environmentt &environment,
113  const namespacet &ns,
114  const std::stack<exprt> &stack,
115  const exprt &expr,
116  const abstract_object_pointert &value,
117  bool merging_write) const
118 {
119  const member_exprt member_expr = to_member_expr(expr);
120 #ifdef DEBUG
121  std::cout << "Writing component " << member_expr.get_component_name() << '\n';
122 #endif
123 
124  if(is_bottom())
125  {
126  return std::make_shared<full_struct_abstract_objectt>(
127  member_expr.compound().type(), false, true);
128  }
129 
130  const auto &result =
131  std::dynamic_pointer_cast<full_struct_abstract_objectt>(mutable_clone());
132 
133  if(!stack.empty())
134  {
135  abstract_object_pointert starting_value;
136  const irep_idt c = member_expr.get_component_name();
137  auto const old_value = map.find(c);
138  if(!old_value.has_value())
139  {
140  starting_value = environment.abstract_object_factory(
141  member_expr.type(), ns, true, false);
142  result->map.insert(
143  c, environment.write(starting_value, value, stack, ns, merging_write));
144  }
145  else
146  {
147  result->map.replace(
148  c,
149  environment.write(old_value.value(), value, stack, ns, merging_write));
150  }
151 
152  result->set_not_top();
153  DATA_INVARIANT(result->verify(), "Structural invariants maintained");
154  return result;
155  }
156  else
157  {
158 #ifdef DEBUG
159  std::cout << "Setting component" << std::endl;
160 #endif
161 
162  const irep_idt c = member_expr.get_component_name();
163  auto const old_value = result->map.find(c);
164 
165  if(merging_write)
166  {
167  if(is_top()) // struct is top
168  {
169  DATA_INVARIANT(result->verify(), "Structural invariants maintained");
170  return result;
171  }
172 
173  INVARIANT(!result->map.empty(), "If not top, map cannot be empty");
174 
175  if(!old_value.has_value()) // component is top
176  {
177  DATA_INVARIANT(result->verify(), "Structural invariants maintained");
178  return result;
179  }
180 
181  result->map.replace(
182  c,
183  abstract_objectt::merge(old_value.value(), value, widen_modet::no)
184  .object);
185  }
186  else
187  {
188  if(old_value.has_value())
189  {
190  result->map.replace(c, value);
191  }
192  else
193  {
194  result->map.insert(c, value);
195  }
196  result->set_not_top();
197  INVARIANT(!result->is_bottom(), "top != bottom");
198  }
199 
200  DATA_INVARIANT(result->verify(), "Structural invariants maintained");
201 
202  return result;
203  }
204 }
205 
207  std::ostream &out,
208  const ai_baset &ai,
209  const namespacet &ns) const
210 {
211  // To ensure that a consistent ordering of fields is output, use
212  // the underlying type declaration for this struct to determine
213  // the ordering
215 
216  bool first = true;
217 
218  out << "{";
219  for(const auto &field : type_decl.components())
220  {
221  auto value = map.find(field.get_name());
222  if(value.has_value())
223  {
224  if(!first)
225  {
226  out << ", ";
227  }
228  out << '.' << field.get_name() << '=';
229  static_cast<const abstract_object_pointert &>(value.value())
230  ->output(out, ai, ns);
231  first = false;
232  }
233  }
234  out << "}";
235 }
236 
238 {
239  // Either the object is top or bottom (=> map empty)
240  // or the map is not empty => neither top nor bottom
241  return (is_top() || is_bottom()) == map.empty();
242 }
243 
245  const abstract_object_pointert &other,
246  const widen_modet &widen_mode) const
247 {
248  constant_struct_pointert cast_other =
249  std::dynamic_pointer_cast<const full_struct_abstract_objectt>(other);
250  if(cast_other)
251  return merge_constant_structs(cast_other, widen_mode);
252 
253  return abstract_aggregate_baset::merge(other, widen_mode);
254 }
255 
258  const widen_modet &widen_mode) const
259 {
260  if(is_bottom())
261  return std::make_shared<full_struct_abstract_objectt>(*other);
262 
263  const auto &result =
264  std::dynamic_pointer_cast<full_struct_abstract_objectt>(mutable_clone());
265 
266  bool modified = merge_shared_maps(map, other->map, result->map, widen_mode);
267 
268  if(!modified)
269  {
270  DATA_INVARIANT(verify(), "Structural invariants maintained");
271  return shared_from_this();
272  }
273  else
274  {
275  INVARIANT(!result->is_top(), "Merge of maps will not generate top");
276  INVARIANT(!result->is_bottom(), "Merge of maps will not generate bottom");
277  DATA_INVARIANT(result->verify(), "Structural invariants maintained");
278  return result;
279  }
280 }
281 
283  const locationt &location) const
284 {
286 }
287 
289  const locationt &location) const
290 {
292 }
293 
295  const abstract_object_visitort &visitor) const
296 {
297  const auto &result =
298  std::dynamic_pointer_cast<full_struct_abstract_objectt>(mutable_clone());
299 
300  bool is_modified = visit_map(result->map, visitor);
301 
302  return is_modified ? result : shared_from_this();
303 }
304 
306  const exprt &name) const
307 {
308  const auto &compound_type = to_struct_union_type(name.type());
309  auto all_predicates = exprt::operandst{};
310 
311  for(auto field : map.get_sorted_view())
312  {
313  auto field_name =
314  member_exprt(name, compound_type.get_component(field.first));
315  auto field_expr = field.second->to_predicate(field_name);
316 
317  if(!field_expr.is_true())
318  all_predicates.push_back(field_expr);
319  }
320 
321  if(all_predicates.empty())
322  return true_exprt();
323  if(all_predicates.size() == 1)
324  return all_predicates.front();
325  return and_exprt(all_predicates);
326 }
327 
329  abstract_object_statisticst &statistics,
330  abstract_object_visitedt &visited,
331  const abstract_environmentt &env,
332  const namespacet &ns) const
333 {
335  map.get_view(view);
336  for(auto const &object : view)
337  {
338  if(visited.find(object.second) == visited.end())
339  {
340  object.second->get_statistics(statistics, visited, env, ns);
341  }
342  }
343  statistics.objects_memory_usage += memory_sizet::from_bytes(sizeof(*this));
344 }
widen_modet
widen_modet
Definition: abstract_environment.h:32
struct_union_typet::components
const componentst & components() const
Definition: std_types.h:147
dstringt
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:36
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
full_struct_abstract_objectt::visit_sub_elements
abstract_object_pointert visit_sub_elements(const abstract_object_visitort &visitor) const override
Apply a visitor operation to all sub elements of this abstract_object.
Definition: full_struct_abstract_object.cpp:294
abstract_objectt::locationt
goto_programt::const_targett locationt
Definition: abstract_object.h:220
abstract_aggregate_objectt< full_struct_abstract_objectt, struct_aggregate_typet >::merge_shared_maps
static bool merge_shared_maps(const sharing_mapt< keyt, abstract_object_pointert, false, hash > &map1, const sharing_mapt< keyt, abstract_object_pointert, false, hash > &map2, sharing_mapt< keyt, abstract_object_pointert, false, hash > &out_map, const widen_modet &widen_mode)
Definition: abstract_aggregate_object.h:127
to_struct_type
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
visit_map
bool visit_map(mapt &map, const visitort &visitor)
Definition: map_visit.h:12
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
to_struct_union_type
const struct_union_typet & to_struct_union_type(const typet &type)
Cast a typet to a struct_union_typet.
Definition: std_types.h:214
widen_modet::no
@ no
full_struct_abstract_objectt::constant_struct_pointert
sharing_ptrt< full_struct_abstract_objectt > constant_struct_pointert
Definition: full_struct_abstract_object.h:23
typet
The type of an expression, extends irept.
Definition: type.h:28
sharing_mapt::get_view
void get_view(V &view) const
Get a view of the elements in the map A view is a list of pairs with the components being const refer...
full_struct_abstract_objectt::map
shared_struct_mapt map
Definition: full_struct_abstract_object.h:106
struct_union_typet
Base type for structs and unions.
Definition: std_types.h:61
full_struct_abstract_objectt::merge_constant_structs
abstract_object_pointert merge_constant_structs(constant_struct_pointert other, const widen_modet &widen_mode) const
Performs an element wise merge of the map for each struct.
Definition: full_struct_abstract_object.cpp:256
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
sharing_mapt::get_sorted_view
sorted_viewt get_sorted_view() const
Convenience function to get a sorted view of the map elements.
Definition: sharing_map.h:462
and_exprt
Boolean AND.
Definition: std_expr.h:2070
full_struct_abstract_objectt::read_component
abstract_object_pointert read_component(const abstract_environmentt &environment, const exprt &expr, const namespacet &ns) const override
A helper function to evaluate the abstract object contained within a struct.
Definition: full_struct_abstract_object.cpp:76
abstract_environmentt
Definition: abstract_environment.h:40
exprt
Base class for all expressions.
Definition: expr.h:55
sharing_mapt::map
nodet map
Definition: sharing_map.h:649
full_struct_abstract_objectt::write_location_context
abstract_object_pointert write_location_context(const locationt &location) const override
Update the location context for an abstract object.
Definition: full_struct_abstract_object.cpp:282
full_struct_abstract_objectt::full_struct_abstract_objectt
full_struct_abstract_objectt(const full_struct_abstract_objectt &ao)
Explicit copy-constructor to make it clear that the shared_map used to store the values of fields is ...
Definition: full_struct_abstract_object.cpp:24
full_struct_abstract_objectt
Definition: full_struct_abstract_object.h:18
namespacet
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:90
exprt::type
typet & type()
Return the type of the expression.
Definition: expr.h:84
full_struct_abstract_object.h
sharing_mapt< irep_idt, abstract_object_pointert, false, irep_id_hash >::viewt
std::vector< view_itemt > viewt
View of the key-value pairs in the map.
Definition: sharing_map.h:388
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
full_struct_abstract_objectt::statistics
void statistics(abstract_object_statisticst &statistics, abstract_object_visitedt &visited, const abstract_environmentt &env, const namespacet &ns) const override
Definition: full_struct_abstract_object.cpp:328
DATA_INVARIANT
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:510
abstract_object_statisticst
Definition: abstract_object_statistics.h:18
member_exprt::compound
const exprt & compound() const
Definition: std_expr.h:2843
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
full_struct_abstract_objectt::output
void output(std::ostream &out, const class ai_baset &ai, const class namespacet &ns) const override
To provide a human readable string to the out representing the current known value about this object.
Definition: full_struct_abstract_object.cpp:206
PRECONDITION
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
abstract_environment.h
map_visit.h
sharing_mapt::insert_or_replace
void insert_or_replace(const key_type &k, valueU &&m)
Definition: sharing_map.h:292
abstract_aggregate_objectt< full_struct_abstract_objectt, struct_aggregate_typet >
sharing_mapt::empty
bool empty() const
Check if map is empty.
Definition: sharing_map.h:360
full_struct_abstract_objectt::mutable_clone
internal_abstract_object_pointert mutable_clone() const override
Definition: full_struct_abstract_object.h:121
irept::id
const irep_idt & id() const
Definition: irep.h:396
exprt::operandst
std::vector< exprt > operandst
Definition: expr.h:58
full_struct_abstract_objectt::merge
abstract_object_pointert merge(const abstract_object_pointert &other, const widen_modet &widen_mode) const override
To merge an abstract object into this abstract object.
Definition: full_struct_abstract_object.cpp:244
abstract_object_visitedt
std::set< abstract_object_pointert > abstract_object_visitedt
Definition: abstract_object.h:70
abstract_objectt::abstract_object_visitort
Pure virtual interface required of a client that can apply a copy-on-write operation to a given abstr...
Definition: abstract_object.h:345
location_update_visitort
Definition: location_update_visitor.h:14
member_exprt
Extract member of struct or union.
Definition: std_expr.h:2793
struct_typet
Structure type, corresponds to C style structs.
Definition: std_types.h:230
namespace_baset::follow
const typet & follow(const typet &) const
Resolve type symbol to the type it points to.
Definition: namespace.cpp:49
full_struct_abstract_objectt::merge_location_context
abstract_object_pointert merge_location_context(const locationt &location) const override
Update the merge location context for an abstract object.
Definition: full_struct_abstract_object.cpp:288
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
full_struct_abstract_objectt::write_component
abstract_object_pointert write_component(abstract_environmentt &environment, const namespacet &ns, const std::stack< exprt > &stack, const exprt &expr, const abstract_object_pointert &value, bool merging_write) const override
A helper function to evaluate writing to a component of a struct.
Definition: full_struct_abstract_object.cpp:111
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
exprt::operands
operandst & operands()
Definition: expr.h:94
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
full_struct_abstract_objectt::to_predicate_internal
exprt to_predicate_internal(const exprt &name) const override
to_predicate implementation - derived classes will override
Definition: full_struct_abstract_object.cpp:305
true_exprt
The Boolean constant true.
Definition: std_expr.h:3007
full_struct_abstract_objectt::verify
bool verify() const override
Function: full_struct_abstract_objectt::verify.
Definition: full_struct_abstract_object.cpp:237
std_expr.h
location_update_visitor.h
memory_sizet::from_bytes
static memory_sizet from_bytes(std::size_t bytes)
Definition: memory_units.cpp:38
abstract_objectt::t
typet t
To enforce copy-on-write these are private and have read-only accessors.
Definition: abstract_object.h:385
validation_modet::INVARIANT
@ INVARIANT
sharing_mapt::find
optionalt< std::reference_wrapper< const mapped_type > > find(const key_type &k) const
Find element.
Definition: sharing_map.h:1451
merge_location_update_visitort
Definition: location_update_visitor.h:33