CBMC
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
full_struct_abstract_object.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Struct abstract object
4
5Author: 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
29
31 const typet &t,
32 bool top,
33 bool bottom)
34 : abstract_aggregate_baset(t, top, bottom)
35{
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
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();
56 {
58 struct_type_it->get_name(),
59 environment.abstract_object_factory(param_it->type(), *param_it, ns));
61 }
62
64 {
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 {
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{
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 {
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 {
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
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{
247 std::dynamic_pointer_cast<const full_struct_abstract_objectt>(other);
248 if(cast_other)
250
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
285
291
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());
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();
324}
325
327 abstract_object_statisticst &statistics,
330 const namespacet &ns) const
331{
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
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
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:2971
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:49
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition namespace.h:91
std::vector< view_itemt > viewt
View of the key-value pairs in the map.
bool empty() const
Check if map is empty.
sorted_viewt get_sorted_view() const
Convenience function to get a sorted view of the map elements.
std::optional< std::reference_wrapper< const mapped_type > > find(const key_type &k) const
Find element.
void insert_or_replace(const key_type &k, valueU &&m)
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
The Boolean constant true.
Definition std_expr.h:3190
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
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition invariant.h:423
API to expression classes.
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:3063
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition std_types.h:308
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
const struct_union_typet & to_struct_union_type(const typet &type)
Cast a typet to a struct_union_typet.
Definition std_types.h:214
Pure virtual interface required of a client that can apply a copy-on-write operation to a given abstr...