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 
31  const typet &t,
32  bool top,
33  bool bottom)
34  : abstract_aggregate_baset(t, top, bottom)
35 {
36  PRECONDITION(t.id() == ID_struct || t.id() == ID_struct_tag);
37  DATA_INVARIANT(verify(), "Structural invariants maintained");
38 }
39 
41  const exprt &e,
42  const abstract_environmentt &environment,
43  const namespacet &ns)
44  : abstract_aggregate_baset(e, environment, ns)
45 {
46  PRECONDITION(e.type().id() == ID_struct || e.type().id() == ID_struct_tag);
47 
48  const struct_typet &struct_type_def =
49  e.type().id() == ID_struct ? to_struct_type(e.type())
51 
52  bool did_initialize_values = false;
53  auto struct_type_it = struct_type_def.components().begin();
54  for(auto param_it = e.operands().begin(); param_it != e.operands().end();
55  ++param_it, ++struct_type_it)
56  {
58  struct_type_it->get_name(),
59  environment.abstract_object_factory(param_it->type(), *param_it, ns));
60  did_initialize_values = true;
61  }
62 
63  if(did_initialize_values)
64  {
65  set_not_top();
66  }
67 
68  DATA_INVARIANT(verify(), "Structural invariants maintained");
69 }
70 
72  const abstract_environmentt &environment,
73  const exprt &expr,
74  const namespacet &ns) const
75 {
76 #ifdef DEBUG
77  std::cout << "Reading component " << to_member_expr(expr).get_component_name()
78  << '\n';
79 #endif
80 
81  if(is_top())
82  {
83  return environment.abstract_object_factory(expr.type(), ns, true, false);
84  }
85  else
86  {
87  const member_exprt &member_expr = to_member_expr(expr);
89 
90  const irep_idt c = member_expr.get_component_name();
91 
92  auto const value = map.find(c);
93 
94  if(value.has_value())
95  {
96  return value.value();
97  }
98  else
99  {
100  return environment.abstract_object_factory(
101  member_expr.type(), ns, true, false);
102  }
103  }
104 }
105 
107  abstract_environmentt &environment,
108  const namespacet &ns,
109  const std::stack<exprt> &stack,
110  const exprt &expr,
111  const abstract_object_pointert &value,
112  bool merging_write) const
113 {
114  const member_exprt member_expr = to_member_expr(expr);
115 #ifdef DEBUG
116  std::cout << "Writing component " << member_expr.get_component_name() << '\n';
117 #endif
118 
119  if(is_bottom())
120  {
121  return std::make_shared<full_struct_abstract_objectt>(
122  member_expr.compound().type(), false, true);
123  }
124 
125  const auto &result =
126  std::dynamic_pointer_cast<full_struct_abstract_objectt>(mutable_clone());
127 
128  if(!stack.empty())
129  {
130  abstract_object_pointert starting_value;
131  const irep_idt c = member_expr.get_component_name();
132  auto const old_value = map.find(c);
133  if(!old_value.has_value())
134  {
135  starting_value = environment.abstract_object_factory(
136  member_expr.type(), ns, true, false);
137  result->map.insert(
138  c, environment.write(starting_value, value, stack, ns, merging_write));
139  }
140  else
141  {
142  result->map.replace(
143  c,
144  environment.write(old_value.value(), value, stack, ns, merging_write));
145  }
146 
147  result->set_not_top();
148  DATA_INVARIANT(result->verify(), "Structural invariants maintained");
149  return result;
150  }
151  else
152  {
153 #ifdef DEBUG
154  std::cout << "Setting component" << std::endl;
155 #endif
156 
157  const irep_idt c = member_expr.get_component_name();
158  auto const old_value = result->map.find(c);
159 
160  if(merging_write)
161  {
162  if(is_top()) // struct is top
163  {
164  DATA_INVARIANT(result->verify(), "Structural invariants maintained");
165  return result;
166  }
167 
168  INVARIANT(!result->map.empty(), "If not top, map cannot be empty");
169 
170  if(!old_value.has_value()) // component is top
171  {
172  DATA_INVARIANT(result->verify(), "Structural invariants maintained");
173  return result;
174  }
175 
176  result->map.replace(
177  c,
178  abstract_objectt::merge(old_value.value(), value, widen_modet::no)
179  .object);
180  }
181  else
182  {
183  if(old_value.has_value())
184  {
185  result->map.replace(c, value);
186  }
187  else
188  {
189  result->map.insert(c, value);
190  }
191  result->set_not_top();
192  INVARIANT(!result->is_bottom(), "top != bottom");
193  }
194 
195  DATA_INVARIANT(result->verify(), "Structural invariants maintained");
196 
197  return result;
198  }
199 }
200 
202  std::ostream &out,
203  const ai_baset &ai,
204  const namespacet &ns) const
205 {
206  // To ensure that a consistent ordering of fields is output, use
207  // the underlying type declaration for this struct to determine
208  // the ordering
209  struct_union_typet type_decl =
210  (type().id() == ID_struct_tag || type().id() == ID_union_tag)
213 
214  bool first = true;
215 
216  out << "{";
217  for(const auto &field : type_decl.components())
218  {
219  auto value = map.find(field.get_name());
220  if(value.has_value())
221  {
222  if(!first)
223  {
224  out << ", ";
225  }
226  out << '.' << field.get_name() << '=';
227  static_cast<const abstract_object_pointert &>(value.value())
228  ->output(out, ai, ns);
229  first = false;
230  }
231  }
232  out << "}";
233 }
234 
236 {
237  // Either the object is top or bottom (=> map empty)
238  // or the map is not empty => neither top nor bottom
239  return (is_top() || is_bottom()) == map.empty();
240 }
241 
243  const abstract_object_pointert &other,
244  const widen_modet &widen_mode) const
245 {
246  constant_struct_pointert cast_other =
247  std::dynamic_pointer_cast<const full_struct_abstract_objectt>(other);
248  if(cast_other)
249  return merge_constant_structs(cast_other, widen_mode);
250 
251  return abstract_aggregate_baset::merge(other, widen_mode);
252 }
253 
256  const widen_modet &widen_mode) const
257 {
258  if(is_bottom())
259  return std::make_shared<full_struct_abstract_objectt>(*other);
260 
261  const auto &result =
262  std::dynamic_pointer_cast<full_struct_abstract_objectt>(mutable_clone());
263 
264  bool modified = merge_shared_maps(map, other->map, result->map, widen_mode);
265 
266  if(!modified)
267  {
268  DATA_INVARIANT(verify(), "Structural invariants maintained");
269  return shared_from_this();
270  }
271  else
272  {
273  INVARIANT(!result->is_top(), "Merge of maps will not generate top");
274  INVARIANT(!result->is_bottom(), "Merge of maps will not generate bottom");
275  DATA_INVARIANT(result->verify(), "Structural invariants maintained");
276  return result;
277  }
278 }
279 
281  const locationt &location) const
282 {
284 }
285 
287  const locationt &location) const
288 {
290 }
291 
293  const abstract_object_visitort &visitor) const
294 {
295  const auto &result =
296  std::dynamic_pointer_cast<full_struct_abstract_objectt>(mutable_clone());
297 
298  bool is_modified = visit_map(result->map, visitor);
299 
300  return is_modified ? result : shared_from_this();
301 }
302 
304  const exprt &name) const
305 {
306  const auto &compound_type = to_struct_union_type(name.type());
307  auto all_predicates = exprt::operandst{};
308 
309  for(auto field : map.get_sorted_view())
310  {
311  auto field_name =
312  member_exprt(name, compound_type.get_component(field.first));
313  auto field_expr = field.second->to_predicate(field_name);
314 
315  if(!field_expr.is_true())
316  all_predicates.push_back(field_expr);
317  }
318 
319  if(all_predicates.empty())
320  return true_exprt();
321  if(all_predicates.size() == 1)
322  return all_predicates.front();
323  return and_exprt(all_predicates);
324 }
325 
327  abstract_object_statisticst &statistics,
328  abstract_object_visitedt &visited,
329  const abstract_environmentt &env,
330  const namespacet &ns) const
331 {
333  map.get_view(view);
334  for(auto const &object : view)
335  {
336  if(visited.find(object.second) == visited.end())
337  {
338  object.second->get_statistics(statistics, visited, env, ns);
339  }
340  }
341  statistics.objects_memory_usage += memory_sizet::from_bytes(sizeof(*this));
342 }
An abstract version of a program environment.
std::set< abstract_object_pointert > abstract_object_visitedt
sharing_ptrt< class abstract_objectt > abstract_object_pointert
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)
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.
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.
virtual bool is_top() const
Find out if the abstract object is top.
virtual bool is_bottom() const
Find out if the abstract object is bottom.
goto_programt::const_targett locationt
static combine_result merge(const abstract_object_pointert &op1, const abstract_object_pointert &op2, const locationt &merge_location, const widen_modet &widen_mode)
typet t
To enforce copy-on-write these are private and have read-only accessors.
virtual const typet & type() const
Get the real type of the variable this abstract object is representing.
This is the basic interface of the abstract interpreter with default implementations of the core func...
Definition: ai.h:117
Boolean AND.
Definition: std_expr.h:2125
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
Base class for all expressions.
Definition: expr.h:56
std::vector< exprt > operandst
Definition: expr.h:58
typet & type()
Return the type of the expression.
Definition: expr.h:84
operandst & operands()
Definition: expr.h:94
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.
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.
internal_abstract_object_pointert mutable_clone() const override
bool verify() const override
Function: full_struct_abstract_objectt::verify.
void statistics(abstract_object_statisticst &statistics, abstract_object_visitedt &visited, const abstract_environmentt &env, const namespacet &ns) const override
abstract_object_pointert write_location_context(const locationt &location) const override
Update the location context for an abstract object.
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.
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.
abstract_object_pointert merge_location_context(const locationt &location) const override
Update the merge location context for an abstract object.
sharing_ptrt< full_struct_abstract_objectt > constant_struct_pointert
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.
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 ...
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.
exprt to_predicate_internal(const exprt &name) const override
to_predicate implementation - derived classes will override
const irep_idt & id() const
Definition: irep.h:388
Extract member of struct or union.
Definition: std_expr.h:2854
const exprt & compound() const
Definition: std_expr.h:2903
irep_idt get_component_name() const
Definition: std_expr.h:2876
static memory_sizet from_bytes(std::size_t bytes)
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
std::vector< view_itemt > viewt
View of the key-value pairs in the map.
Definition: sharing_map.h:388
bool empty() const
Check if map is empty.
Definition: sharing_map.h:360
sorted_viewt get_sorted_view() const
Convenience function to get a sorted view of the map elements.
Definition: sharing_map.h:462
std::optional< std::reference_wrapper< const mapped_type > > find(const key_type &k) const
Find element.
Definition: sharing_map.h:1451
void insert_or_replace(const key_type &k, valueU &&m)
Definition: sharing_map.h:292
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...
Structure type, corresponds to C style structs.
Definition: std_types.h:231
Base type for structs and unions.
Definition: std_types.h:62
const componentst & components() const
Definition: std_types.h:147
The Boolean constant true.
Definition: std_expr.h:3073
The type of an expression, extends irept.
Definition: type.h:29
An abstraction of a structure that stores one abstract object per field.
bool visit_map(mapt &map, const visitort &visitor)
Definition: map_visit.h:12
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:534
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
API to expression classes.
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2946
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
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
Pure virtual interface required of a client that can apply a copy-on-write operation to a given abstr...
abstract_object_pointert object