CBMC
Loading...
Searching...
No Matches
local_may_alias.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Field-insensitive, location-sensitive may-alias analysis
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
11
12#include "local_may_alias.h"
13
14#include <iterator>
15#include <algorithm>
16
17#include <util/arith_tools.h>
18#include <util/pointer_expr.h>
19#include <util/std_code.h>
20
21#include <util/c_types.h>
23
26{
27 bool changed=false;
28
29 // do union; this should be amortized linear
30 for(std::size_t i=0; i<src.aliases.size(); i++)
31 {
32 std::size_t root=src.aliases.find(i);
33
34 if(!aliases.same_set(i, root))
35 {
36 aliases.make_union(i, root);
37 changed=true;
38 }
39 }
40
41 return changed;
42}
43
45 const exprt &lhs,
46 const exprt &rhs,
49{
50 if(lhs.id()==ID_symbol)
51 {
52 if(lhs.type().id()==ID_pointer)
53 {
54 unsigned dest_pointer=objects.number(lhs);
55
56 // isolate the lhs pointer
57 loc_info_dest.aliases.isolate(dest_pointer);
58
61
62 // make these all aliases
63 for(object_sett::const_iterator
64 p_it=rhs_set.begin();
65 p_it!=rhs_set.end();
66 p_it++)
67 {
68 loc_info_dest.aliases.make_union(dest_pointer, *p_it);
69 }
70 }
71 }
72 else if(lhs.id()==ID_dereference)
73 {
74 // this might invalidate all pointers that are
75 // a) local and dirty
76 // b) global
77 if(lhs.type().id()==ID_pointer)
78 {
79 for(std::size_t i=0; i<objects.size(); i++)
80 {
81 if(objects[i].id()==ID_symbol)
82 {
83 const irep_idt &identifier = to_symbol_expr(objects[i]).identifier();
84
85 if(dirty(identifier) || !locals.is_local(identifier))
86 {
87 loc_info_dest.aliases.isolate(i);
88 loc_info_dest.aliases.make_union(i, unknown_object);
89 }
90 }
91 }
92 }
93 }
94 else if(lhs.id()==ID_index)
95 {
97 }
98 else if(lhs.id()==ID_member)
99 {
101 to_member_expr(lhs).struct_op(), rhs, loc_info_src, loc_info_dest);
102 }
103 else if(lhs.id()==ID_typecast)
104 {
106 }
107 else if(lhs.id()==ID_if)
108 {
109 assign_lhs(to_if_expr(lhs).true_case(), rhs, loc_info_src, loc_info_dest);
110 assign_lhs(to_if_expr(lhs).false_case(), rhs, loc_info_src, loc_info_dest);
111 }
112}
113
114std::set<exprt> local_may_aliast::get(
116 const exprt &rhs) const
117{
118 local_cfgt::loc_mapt::const_iterator loc_it=cfg.loc_map.find(t);
119 CHECK_RETURN(loc_it != cfg.loc_map.end());
120
121 const loc_infot &loc_info_src=loc_infos[loc_it->second];
122
125
126 std::set<exprt> result;
127
128 for(object_sett::const_iterator
129 it=result_tmp.begin();
130 it!=result_tmp.end();
131 it++)
132 {
133 result.insert(objects[*it]);
134 }
135
136 return result;
137}
138
141 const exprt &src1, const exprt &src2) const
142{
143 local_cfgt::loc_mapt::const_iterator loc_it=cfg.loc_map.find(t);
144 CHECK_RETURN(loc_it != cfg.loc_map.end());
145
146 const loc_infot &loc_info_src=loc_infos[loc_it->second];
147
151
152 if(tmp1.find(unknown_object)!=tmp1.end() ||
153 tmp2.find(unknown_object)!=tmp2.end())
154 return true;
155
156 std::list<unsigned> result;
157
158 std::set_intersection(
159 tmp1.begin(), tmp1.end(),
160 tmp2.begin(), tmp2.end(),
161 std::back_inserter(result));
162
163 return !result.empty();
164}
165
167 object_sett &dest,
168 const exprt &rhs,
169 const loc_infot &loc_info_src) const
170{
171 if(rhs.is_constant())
172 {
173 if(rhs == 0)
174 dest.insert(objects.number(exprt(ID_null_object)));
175 else
177 }
178 else if(rhs.id()==ID_symbol)
179 {
180 if(rhs.type().id()==ID_pointer)
181 {
182 unsigned src_pointer=objects.number(rhs);
183
184 dest.insert(src_pointer);
185
186 for(std::size_t i=0; i<loc_info_src.aliases.size(); i++)
187 if(loc_info_src.aliases.same_set(src_pointer, i))
188 dest.insert(i);
189 }
190 else
191 dest.insert(unknown_object);
192 }
193 else if(rhs.id()==ID_if)
194 {
195 get_rec(dest, to_if_expr(rhs).false_case(), loc_info_src);
196 get_rec(dest, to_if_expr(rhs).true_case(), loc_info_src);
197 }
198 else if(rhs.id()==ID_address_of)
199 {
200 const exprt &object=to_address_of_expr(rhs).object();
201
202 if(object.id()==ID_symbol)
203 {
204 unsigned object_nr=objects.number(rhs);
205 dest.insert(object_nr);
206
207 for(std::size_t i=0; i<loc_info_src.aliases.size(); i++)
208 if(loc_info_src.aliases.same_set(object_nr, i))
209 dest.insert(i);
210 }
211 else if(object.id()==ID_index)
212 {
213 const index_exprt &index_expr=to_index_expr(object);
214 if(index_expr.array().id()==ID_symbol)
215 {
217 tmp1.index() = from_integer(0, c_index_type());
219 unsigned object_nr=objects.number(tmp2);
220 dest.insert(object_nr);
221
222 for(std::size_t i=0; i<loc_info_src.aliases.size(); i++)
223 if(loc_info_src.aliases.same_set(object_nr, i))
224 dest.insert(i);
225 }
226 else if(index_expr.array().id()==ID_string_constant)
227 {
229 tmp1.index() = from_integer(0, c_index_type());
231 unsigned object_nr=objects.number(tmp2);
232 dest.insert(object_nr);
233
234 for(std::size_t i=0; i<loc_info_src.aliases.size(); i++)
235 if(loc_info_src.aliases.same_set(object_nr, i))
236 dest.insert(i);
237 }
238 else
239 dest.insert(unknown_object);
240 }
241 else
242 dest.insert(unknown_object);
243 }
244 else if(rhs.id()==ID_typecast)
245 {
246 get_rec(dest, to_typecast_expr(rhs).op(), loc_info_src);
247 }
248 else if(rhs.id()==ID_plus)
249 {
250 const auto &plus_expr = to_plus_expr(rhs);
251
252 if(plus_expr.operands().size() >= 3)
253 {
255 plus_expr.op0().type().id() == ID_pointer,
256 "pointer in pointer-typed sum must be op0");
257 get_rec(dest, plus_expr.op0(), loc_info_src);
258 }
259 else if(plus_expr.operands().size() == 2)
260 {
261 // one must be pointer, one an integer
262 if(plus_expr.op0().type().id() == ID_pointer)
263 {
264 get_rec(dest, plus_expr.op0(), loc_info_src);
265 }
266 else if(plus_expr.op1().type().id() == ID_pointer)
267 {
268 get_rec(dest, plus_expr.op1(), loc_info_src);
269 }
270 else
271 dest.insert(unknown_object);
272 }
273 else
274 dest.insert(unknown_object);
275 }
276 else if(rhs.id()==ID_minus)
277 {
278 const auto &op0 = to_minus_expr(rhs).op0();
279
280 if(op0.type().id() == ID_pointer)
281 {
282 get_rec(dest, op0, loc_info_src);
283 }
284 else
285 dest.insert(unknown_object);
286 }
287 else if(rhs.id()==ID_member)
288 {
289 dest.insert(unknown_object);
290 }
291 else if(rhs.id()==ID_index)
292 {
293 dest.insert(unknown_object);
294 }
295 else if(rhs.id()==ID_dereference)
296 {
297 dest.insert(unknown_object);
298 }
299 else if(rhs.id()==ID_side_effect)
300 {
302 const irep_idt &statement=side_effect_expr.get_statement();
303
304 if(statement==ID_allocate)
305 {
306 dest.insert(objects.number(exprt(ID_dynamic_object)));
307 }
308 else
309 dest.insert(unknown_object);
310 }
311 else if(rhs.is_nil())
312 {
313 // this means 'empty'
314 }
315 else
316 dest.insert(unknown_object);
317}
318
319void local_may_aliast::build(const goto_functiont &goto_function)
320{
321 if(cfg.nodes.empty())
322 return;
323
325
326 // put all nodes into work queue
327 for(local_cfgt::node_nrt n=0; n<cfg.nodes.size(); n++)
328 work_queue.push(n);
329
331
332 loc_infos.resize(cfg.nodes.size());
333
334 (void)goto_function; // unused parameter
335#if 0
336 // feed in sufficiently bad defaults
337 for(code_typet::parameterst::const_iterator
338 it=goto_function.type.parameters().begin();
339 it!=goto_function.type.parameters().end();
340 it++)
341 {
342 const irep_idt &identifier=it->get_identifier();
343 if(is_tracked(identifier))
344 loc_infos[0].points_to[objects.number(identifier)].objects.insert(
346 }
347#endif
348
349#if 0
350 for(localst::locals_mapt::const_iterator
351 l_it=locals.locals_map.begin();
352 l_it!=locals.locals_map.end();
353 l_it++)
354 {
355 if(is_tracked(l_it->first))
356 loc_infos[0].aliases.make_union(
358 }
359#endif
360
361 while(!work_queue.empty())
362 {
364 const local_cfgt::nodet &node=cfg.nodes[loc_nr];
365 const goto_programt::instructiont &instruction=*node.t;
366 work_queue.pop();
367
370
371 switch(instruction.type())
372 {
373 case ASSIGN:
374 {
376 instruction.assign_lhs(),
377 instruction.assign_rhs(),
380 break;
381 }
382
383 case DECL:
386 break;
387
388 case DEAD:
391 break;
392
393 case FUNCTION_CALL:
394 {
395 const auto &lhs = instruction.call_lhs();
396 if(lhs.is_not_nil())
398
399 // this might invalidate all pointers that are
400 // a) local and dirty
401 // b) global
402 for(std::size_t i = 0; i < objects.size(); i++)
403 {
404 if(objects[i].id() == ID_symbol)
405 {
406 const irep_idt &identifier = to_symbol_expr(objects[i]).identifier();
407
408 if(dirty(identifier) || !locals.is_local(identifier))
409 {
410 loc_info_dest.aliases.isolate(i);
411 loc_info_dest.aliases.make_union(i, unknown_object);
412 }
413 }
414 }
415 break;
416 }
417
418 case CATCH:
419 case THROW:
420 DATA_INVARIANT(false, "Exceptions must be removed before analysis");
421 break;
422 case SET_RETURN_VALUE:
423#if 0
424 DATA_INVARIANT(false, "SET_RETURN_VALUE must be removed before analysis");
425#endif
426 break;
427 case GOTO: // Ignoring the guard is a valid over-approximation
428 case START_THREAD: // Require a concurrent analysis at higher level
429 case END_THREAD: // Require a concurrent analysis at higher level
430 case ATOMIC_BEGIN: // Ignoring is a valid over-approximation
431 case ATOMIC_END: // Ignoring is a valid over-approximation
432 case LOCATION: // No action required
433 case SKIP: // No action required
434 case END_FUNCTION: // No action required
435 case ASSERT: // No action required
436 case ASSUME: // Ignoring is a valid over-approximation
437 break;
438 case OTHER:
439#if 0
441 false, "Unclear what is a safe over-approximation of OTHER");
442#endif
443 break;
444 case INCOMPLETE_GOTO:
446 DATA_INVARIANT(false, "Only complete instructions can be analyzed");
447 break;
448 }
449
450 for(local_cfgt::successorst::const_iterator
451 it=node.successors.begin();
452 it!=node.successors.end();
453 it++)
454 {
456 work_queue.push(*it);
457 }
458 }
459}
460
462 std::ostream &out,
463 const goto_functiont &goto_function,
464 const namespacet &ns) const
465{
466 unsigned l=0;
467
468 for(const auto &instruction : goto_function.body.instructions)
469 {
470 out << "**** " << instruction.source_location() << "\n";
471
472 const loc_infot &loc_info=loc_infos[l];
473
474 for(std::size_t i=0; i<loc_info.aliases.size(); i++)
475 {
476 if(loc_info.aliases.count(i)!=1 &&
477 loc_info.aliases.find(i)==i) // root?
478 {
479 out << '{';
480 for(std::size_t j=0; j<loc_info.aliases.size(); j++)
481 if(loc_info.aliases.find(j)==i)
482 {
483 INVARIANT(j < objects.size(), "invalid object index");
484 irep_idt identifier;
485 if(objects[j].id() == ID_symbol)
486 identifier = to_symbol_expr(objects[j]).identifier();
487 out << ' ' << from_expr(ns, identifier, objects[j]);
488 }
489
490 out << " }";
491 out << "\n";
492 }
493 }
494
495 out << "\n";
496 instruction.output(out);
497 out << "\n";
498
499 l++;
500 }
501}
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
bitvector_typet c_index_type()
Definition c_types.cpp:16
Operator to return the address of an object.
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:566
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:57
bool is_constant() const
Return whether the expression is a constant.
Definition expr.h:213
typet & type()
Return the type of the expression.
Definition expr.h:85
A goto function, consisting of function body (see body) and parameter identifiers (see parameter_iden...
goto_programt body
This class represents an instruction in the GOTO intermediate representation.
const symbol_exprt & dead_symbol() const
Get the symbol for DEAD.
const exprt & call_lhs() const
Get the lhs of a FUNCTION_CALL (may be nil)
const symbol_exprt & decl_symbol() const
Get the declared symbol for DECL.
const exprt & assign_lhs() const
Get the lhs of the assignment for ASSIGN.
const exprt & assign_rhs() const
Get the rhs of the assignment for ASSIGN.
goto_program_instruction_typet type() const
What kind of instruction?
instructionst instructions
The list of instructions in the goto program.
instructionst::const_iterator const_targett
Array index operator.
Definition std_expr.h:1431
const irep_idt & id() const
Definition irep.h:388
bool is_nil() const
Definition irep.h:368
goto_programt::const_targett t
Definition local_cfg.h:28
successorst successors
Definition local_cfg.h:29
nodest nodes
Definition local_cfg.h:38
std::size_t node_nrt
Definition local_cfg.h:22
loc_mapt loc_map
Definition local_cfg.h:35
bool merge(const loc_infot &src)
void output(std::ostream &out, const goto_functiont &goto_function, const namespacet &ns) const
void assign_lhs(const exprt &lhs, const exprt &rhs, const loc_infot &loc_info_src, loc_infot &loc_info_dest)
void build(const goto_functiont &goto_function)
numberingt< exprt, irep_hash > objects
std::set< exprt > get(const goto_programt::const_targett t, const exprt &src) const
void get_rec(object_sett &dest, const exprt &rhs, const loc_infot &loc_info_src) const
std::stack< local_cfgt::node_nrt > work_queuet
bool aliases(const goto_programt::const_targett t, const exprt &src1, const exprt &src2) const
std::set< unsigned > object_sett
bool is_local(const irep_idt &identifier) const
Definition locals.h:37
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition namespace.h:91
The NIL expression.
Definition std_expr.h:3144
number_type number(const key_type &a)
Definition numbering.h:37
size_type size() const
Definition numbering.h:66
An expression containing a side effect.
Definition std_code.h:1450
size_type size() const
Definition union_find.h:97
size_type find(size_type a) const
void make_union(size_type a, size_type b)
bool same_set(size_type a, size_type b) const
Definition union_find.h:91
@ FUNCTION_CALL
@ ATOMIC_END
@ DEAD
@ LOCATION
@ END_FUNCTION
@ ASSIGN
@ ASSERT
@ SET_RETURN_VALUE
@ ATOMIC_BEGIN
@ CATCH
@ END_THREAD
@ SKIP
@ NO_INSTRUCTION_TYPE
@ START_THREAD
@ THROW
@ DECL
@ OTHER
@ GOTO
@ INCOMPLETE_GOTO
@ ASSUME
std::string from_expr(const namespacet &ns, const irep_idt &identifier, const exprt &expr)
Field-insensitive, location-sensitive may-alias analysis.
API to expression classes for Pointers.
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
#define CHECK_RETURN(CONDITION)
Definition invariant.h:495
#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 INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition invariant.h:423
side_effect_exprt & to_side_effect_expr(exprt &expr)
Definition std_code.h:1506
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1494
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition std_expr.h:2024
const plus_exprt & to_plus_expr(const exprt &expr)
Cast an exprt to a plus_exprt.
Definition std_expr.h:1045
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition std_expr.h:2501
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:2953
const minus_exprt & to_minus_expr(const exprt &expr)
Cast an exprt to a minus_exprt.
Definition std_expr.h:1085
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:221
void merge(string_constraintst &result, string_constraintst other)
Merge two sets of constraints by appending to the first one.