CBMC
Loading...
Searching...
No Matches
may_alias.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Solver
4
5Author: Daniel Kroening, dkr@amazon.com
6
7\*******************************************************************/
8
11
12#include "may_alias.h"
13
14#include <util/c_types.h>
15#include <util/namespace.h>
16#include <util/pointer_expr.h>
17#include <util/std_expr.h>
18#include <util/symbol.h>
19
21{
22 // C99; ISO/IEC 9899:1999 6.5/7
23 if(a == b)
24 return true;
25 else if(a == signed_char_type() || a == unsigned_char_type())
26 return true; // char * can alias anyting
27 else if(b == signed_char_type() || b == unsigned_char_type())
28 return true; // char * can alias anyting
29 else if(
30 (a.id() == ID_unsignedbv || a.id() == ID_signedbv) &&
31 (b.id() == ID_unsignedbv || b.id() == ID_signedbv))
32 {
33 // signed/unsigned of same width can alias
34 return to_bitvector_type(a).get_width() == to_bitvector_type(b).get_width();
35 }
36 else if(a.id() == ID_empty)
37 return true; // void * can alias any pointer
38 else if(b.id() == ID_empty)
39 return true; // void * can alias any pointer
40 else if(
41 a.id() == ID_pointer && to_pointer_type(a).base_type().id() == ID_empty)
42 return true; // void * can alias any pointer
43 else if(
44 b.id() == ID_pointer && to_pointer_type(b).base_type().id() == ID_empty)
45 return true; // void * can alias any pointer
46 else if(
47 a.id() == ID_pointer && to_pointer_type(a).base_type().id() == ID_pointer &&
48 to_pointer_type(to_pointer_type(a).base_type()).base_type().id() ==
50 return true; // void * can alias any pointer
51 else if(
52 b.id() == ID_pointer && to_pointer_type(b).base_type().id() == ID_pointer &&
53 to_pointer_type(to_pointer_type(b).base_type()).base_type().id() ==
55 return true; // void * can alias any pointer
56 else
57 {
58 return false;
59 }
60}
61
63{
64 if(expr.id() == ID_object_address)
65 return true;
66 else if(expr.id() == ID_element_address)
68 else if(expr.id() == ID_field_address)
70 else
71 return false;
72}
73
74bool prefix_of(const typet &a, const typet &b, const namespacet &ns)
75{
76 if(a == b)
77 return true;
78
79 if(a.id() == ID_struct_tag)
80 return prefix_of(ns.follow_tag(to_struct_tag_type(a)), b, ns);
81
82 if(b.id() == ID_struct_tag)
83 return prefix_of(a, ns.follow_tag(to_struct_tag_type(b)), ns);
84
85 if(a.id() != ID_struct || b.id() != ID_struct)
86 return false;
87
88 const auto &a_struct = to_struct_type(a);
89 const auto &b_struct = to_struct_type(b);
90
91 return a_struct.is_prefix_of(b_struct) || b_struct.is_prefix_of(a_struct);
92}
93
94static std::optional<object_address_exprt> find_object(const exprt &expr)
95{
96 if(expr.id() == ID_object_address)
97 return to_object_address_expr(expr);
98 else if(expr.id() == ID_field_address)
99 return find_object(to_field_address_expr(expr).base());
100 else if(expr.id() == ID_element_address)
101 return find_object(to_element_address_expr(expr).base());
102 else
103 return {};
104}
105
106// Is 'expr' on the stack and it's address is not taken?
108 const exprt &expr,
109 const std::unordered_set<symbol_exprt, irep_hash> &address_taken,
110 const namespacet &ns)
111{
112 auto object = find_object(expr);
113 if(object.has_value())
114 {
115 auto symbol_expr = object->object_expr();
116 auto identifier = symbol_expr.get_identifier();
117 if(identifier.starts_with("va_arg::"))
118 return true; // on the stack, and might alias
119 else if(identifier.starts_with("var_args::"))
120 return false; // on the stack -- can take address?
121 else if(identifier.starts_with("va_args::"))
122 return false; // on the stack -- can take address?
123 else if(identifier.starts_with("va_arg_array::"))
124 return false; // on the stack -- can take address?
125 else if(identifier.starts_with("old::"))
126 return true; // on the stack, but can't take address
127 else if(identifier == "return_value")
128 return true; // on the stack, but can't take address
129 const auto &symbol = ns.lookup(symbol_expr);
130 return !symbol.is_static_lifetime &&
131 address_taken.find(symbol_expr) == address_taken.end();
132 }
133 else
134 return false;
135}
136
138{
139 if(
140 src.id() == ID_typecast &&
141 to_typecast_expr(src).op().type().id() == ID_pointer)
143 else
144 return src;
145}
146
147std::optional<exprt>
148same_address(const exprt &a, const exprt &b, const namespacet &ns)
149{
150 static const auto true_expr = true_exprt();
151 static const auto false_expr = false_exprt();
152
153 // syntactically the same?
155 return true_expr;
156
157 // a and b are both object/field/element?
159 {
160 if(a.id() == ID_object_address && b.id() == ID_object_address)
161 {
162 if(
163 to_object_address_expr(a).object_identifier() ==
164 to_object_address_expr(b).object_identifier())
165 {
166 return true_expr; // the same
167 }
168 else
169 return false_expr; // different
170 }
171 else if(a.id() == ID_element_address && b.id() == ID_element_address)
172 {
175
176 // rec. call
177 auto base_same_address =
179
180 CHECK_RETURN(base_same_address.has_value());
181
182 if(base_same_address->is_false())
183 return false_expr;
184 else
185 {
186 return and_exprt(
189 }
190 }
191 else if(a.id() == ID_field_address && b.id() == ID_field_address)
192 {
195
196 // structs can't alias unless one is a prefix of the other
197 if(!prefix_of(
198 a_field_address.type().base_type(),
199 b_field_address.type().base_type(),
200 ns))
201 {
202 return false_expr;
203 }
204
205 if(a_field_address.component_name() == b_field_address.component_name())
206 {
207 // rec. call
208 return same_address(a_field_address.base(), b_field_address.base(), ns);
209 }
210 else
211 return false_expr;
212 }
213 else
214 return false_expr;
215 }
216
217 // don't know
218 return {};
219}
220
221std::optional<exprt> may_alias(
222 const exprt &a,
223 const exprt &b,
224 const std::unordered_set<symbol_exprt, irep_hash> &address_taken,
225 const namespacet &ns)
226{
227 PRECONDITION(a.type().id() == ID_pointer);
228 PRECONDITION(b.type().id() == ID_pointer);
229
230 static const auto true_expr = true_exprt();
231 static const auto false_expr = false_exprt();
232
233 // syntactically the same?
235 return true_expr;
236
237 // consider the strict aliasing rule
238 const auto &a_base = to_pointer_type(a.type()).base_type();
239 const auto &b_base = to_pointer_type(b.type()).base_type();
240
242 {
243 // The object is known to be different, because of strict aliasing.
244 return false_expr;
245 }
246
247 // a and b the same addresses?
248 auto same_address_opt = same_address(a, b, ns);
249 if(same_address_opt.has_value())
250 return same_address_opt;
251
252 // is one of them stack-allocated and it's address is not taken?
254 return false_expr; // can't alias
255
257 return false_expr; // can't alias
258
259 // we don't know
260 return {};
261}
std::unordered_set< symbol_exprt, irep_hash > address_taken(const std::vector< exprt > &src)
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
signedbv_typet signed_char_type()
Definition c_types.cpp:134
unsignedbv_typet unsigned_char_type()
Definition c_types.cpp:127
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
Equality.
Definition std_expr.h:1366
Base class for all expressions.
Definition expr.h:56
The Boolean constant false.
Definition std_expr.h:3199
const irep_idt & id() const
Definition irep.h:388
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
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
The Boolean constant true.
Definition std_expr.h:3190
The type of an expression, extends irept.
Definition type.h:29
std::optional< exprt > same_address(const exprt &a, const exprt &b, const namespacet &ns)
static std::optional< object_address_exprt > find_object(const exprt &expr)
Definition may_alias.cpp:94
bool permitted_by_strict_aliasing(const typet &a, const typet &b)
Definition may_alias.cpp:20
bool prefix_of(const typet &a, const typet &b, const namespacet &ns)
Definition may_alias.cpp:74
std::optional< exprt > may_alias(const exprt &a, const exprt &b, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
static exprt drop_pointer_typecasts(exprt src)
bool is_object_field_element(const exprt &expr)
Definition may_alias.cpp:62
bool stack_and_not_dirty(const exprt &expr, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const namespacet &ns)
May Alias.
API to expression classes for Pointers.
const element_address_exprt & to_element_address_expr(const exprt &expr)
Cast an exprt to an element_address_exprt.
const object_address_exprt & to_object_address_expr(const exprt &expr)
Cast an exprt to an object_address_exprt.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
const field_address_exprt & to_field_address_expr(const exprt &expr)
Cast an exprt to an field_address_exprt.
#define CHECK_RETURN(CONDITION)
Definition invariant.h:495
#define PRECONDITION(CONDITION)
Definition invariant.h:463
API to expression classes.
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition std_expr.h:2107
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
Symbol table entry.