cprover
local_may_alias.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Field-insensitive, location-sensitive may-alias analysis
4 
5 Author: 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/std_expr.h>
19 #include <util/std_code.h>
20 
21 #include <util/c_types.h>
22 #include <langapi/language_util.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,
47  const loc_infot &loc_info_src,
48  loc_infot &loc_info_dest)
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 
59  object_sett rhs_set;
60  get_rec(rhs_set, rhs, loc_info_src);
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=
85 
86  if(dirty(identifier) || !locals.is_local(identifier))
87  {
88  loc_info_dest.aliases.isolate(i);
89  loc_info_dest.aliases.make_union(i, unknown_object);
90  }
91  }
92  }
93  }
94  }
95  else if(lhs.id()==ID_index)
96  {
97  assign_lhs(to_index_expr(lhs).array(), rhs, loc_info_src, loc_info_dest);
98  }
99  else if(lhs.id()==ID_member)
100  {
101  assign_lhs(
102  to_member_expr(lhs).struct_op(), rhs, loc_info_src, loc_info_dest);
103  }
104  else if(lhs.id()==ID_typecast)
105  {
106  assign_lhs(to_typecast_expr(lhs).op(), rhs, loc_info_src, loc_info_dest);
107  }
108  else if(lhs.id()==ID_if)
109  {
110  assign_lhs(to_if_expr(lhs).true_case(), rhs, loc_info_src, loc_info_dest);
111  assign_lhs(to_if_expr(lhs).false_case(), rhs, loc_info_src, loc_info_dest);
112  }
113 }
114 
115 std::set<exprt> local_may_aliast::get(
117  const exprt &rhs) const
118 {
119  local_cfgt::loc_mapt::const_iterator loc_it=cfg.loc_map.find(t);
120 
121  assert(loc_it!=cfg.loc_map.end());
122 
123  const loc_infot &loc_info_src=loc_infos[loc_it->second];
124 
125  object_sett result_tmp;
126  get_rec(result_tmp, rhs, loc_info_src);
127 
128  std::set<exprt> result;
129 
130  for(object_sett::const_iterator
131  it=result_tmp.begin();
132  it!=result_tmp.end();
133  it++)
134  {
135  result.insert(objects[*it]);
136  }
137 
138  return result;
139 }
140 
143  const exprt &src1, const exprt &src2) const
144 {
145  local_cfgt::loc_mapt::const_iterator loc_it=cfg.loc_map.find(t);
146 
147  assert(loc_it!=cfg.loc_map.end());
148 
149  const loc_infot &loc_info_src=loc_infos[loc_it->second];
150 
151  object_sett tmp1, tmp2;
152  get_rec(tmp1, src1, loc_info_src);
153  get_rec(tmp2, src2, loc_info_src);
154 
155  if(tmp1.find(unknown_object)!=tmp1.end() ||
156  tmp2.find(unknown_object)!=tmp2.end())
157  return true;
158 
159  std::list<unsigned> result;
160 
161  std::set_intersection(
162  tmp1.begin(), tmp1.end(),
163  tmp2.begin(), tmp2.end(),
164  std::back_inserter(result));
165 
166  return !result.empty();
167 }
168 
170  object_sett &dest,
171  const exprt &rhs,
172  const loc_infot &loc_info_src) const
173 {
174  if(rhs.id()==ID_constant)
175  {
176  if(rhs.is_zero())
177  dest.insert(objects.number(exprt(ID_null_object)));
178  else
179  dest.insert(objects.number(exprt(ID_integer_address_object)));
180  }
181  else if(rhs.id()==ID_symbol)
182  {
183  if(rhs.type().id()==ID_pointer)
184  {
185  unsigned src_pointer=objects.number(rhs);
186 
187  dest.insert(src_pointer);
188 
189  for(std::size_t i=0; i<loc_info_src.aliases.size(); i++)
190  if(loc_info_src.aliases.same_set(src_pointer, i))
191  dest.insert(i);
192  }
193  else
194  dest.insert(unknown_object);
195  }
196  else if(rhs.id()==ID_if)
197  {
198  get_rec(dest, to_if_expr(rhs).false_case(), loc_info_src);
199  get_rec(dest, to_if_expr(rhs).true_case(), loc_info_src);
200  }
201  else if(rhs.id()==ID_address_of)
202  {
203  const exprt &object=to_address_of_expr(rhs).object();
204 
205  if(object.id()==ID_symbol)
206  {
207  unsigned object_nr=objects.number(rhs);
208  dest.insert(object_nr);
209 
210  for(std::size_t i=0; i<loc_info_src.aliases.size(); i++)
211  if(loc_info_src.aliases.same_set(object_nr, i))
212  dest.insert(i);
213  }
214  else if(object.id()==ID_index)
215  {
216  const index_exprt &index_expr=to_index_expr(object);
217  if(index_expr.array().id()==ID_symbol)
218  {
219  index_exprt tmp1=index_expr;
220  tmp1.index()=from_integer(0, index_type());
221  address_of_exprt tmp2(tmp1);
222  unsigned object_nr=objects.number(tmp2);
223  dest.insert(object_nr);
224 
225  for(std::size_t i=0; i<loc_info_src.aliases.size(); i++)
226  if(loc_info_src.aliases.same_set(object_nr, i))
227  dest.insert(i);
228  }
229  else if(index_expr.array().id()==ID_string_constant)
230  {
231  index_exprt tmp1=index_expr;
232  tmp1.index()=from_integer(0, index_type());
233  address_of_exprt tmp2(tmp1);
234  unsigned object_nr=objects.number(tmp2);
235  dest.insert(object_nr);
236 
237  for(std::size_t i=0; i<loc_info_src.aliases.size(); i++)
238  if(loc_info_src.aliases.same_set(object_nr, i))
239  dest.insert(i);
240  }
241  else
242  dest.insert(unknown_object);
243  }
244  else
245  dest.insert(unknown_object);
246  }
247  else if(rhs.id()==ID_typecast)
248  {
249  get_rec(dest, to_typecast_expr(rhs).op(), loc_info_src);
250  }
251  else if(rhs.id()==ID_plus)
252  {
253  if(rhs.operands().size()>=3)
254  {
255  assert(rhs.op0().type().id()==ID_pointer);
256  get_rec(dest, rhs.op0(), loc_info_src);
257  }
258  else if(rhs.operands().size()==2)
259  {
260  // one must be pointer, one an integer
261  if(rhs.op0().type().id()==ID_pointer)
262  {
263  get_rec(dest, rhs.op0(), loc_info_src);
264  }
265  else if(rhs.op1().type().id()==ID_pointer)
266  {
267  get_rec(dest, rhs.op1(), loc_info_src);
268  }
269  else
270  dest.insert(unknown_object);
271  }
272  else
273  dest.insert(unknown_object);
274  }
275  else if(rhs.id()==ID_minus)
276  {
277  if(rhs.op0().type().id()==ID_pointer)
278  {
279  get_rec(dest, rhs.op0(), loc_info_src);
280  }
281  else
282  dest.insert(unknown_object);
283  }
284  else if(rhs.id()==ID_member)
285  {
286  dest.insert(unknown_object);
287  }
288  else if(rhs.id()==ID_index)
289  {
290  dest.insert(unknown_object);
291  }
292  else if(rhs.id()==ID_dereference)
293  {
294  dest.insert(unknown_object);
295  }
296  else if(rhs.id()==ID_side_effect)
297  {
298  const side_effect_exprt &side_effect_expr=to_side_effect_expr(rhs);
299  const irep_idt &statement=side_effect_expr.get_statement();
300 
301  if(statement==ID_allocate)
302  {
303  dest.insert(objects.number(exprt(ID_dynamic_object)));
304  }
305  else
306  dest.insert(unknown_object);
307  }
308  else if(rhs.is_nil())
309  {
310  // this means 'empty'
311  }
312  else
313  dest.insert(unknown_object);
314 }
315 
316 void local_may_aliast::build(const goto_functiont &goto_function)
317 {
318  if(cfg.nodes.empty())
319  return;
320 
321  work_queuet work_queue;
322 
323  // put all nodes into work queue
324  for(local_cfgt::node_nrt n=0; n<cfg.nodes.size(); n++)
325  work_queue.push(n);
326 
327  unknown_object=objects.number(exprt(ID_unknown));
328 
329  loc_infos.resize(cfg.nodes.size());
330 
331  #if 0
332  // feed in sufficiently bad defaults
333  for(code_typet::parameterst::const_iterator
334  it=goto_function.type.parameters().begin();
335  it!=goto_function.type.parameters().end();
336  it++)
337  {
338  const irep_idt &identifier=it->get_identifier();
339  if(is_tracked(identifier))
340  loc_infos[0].points_to[objects.number(identifier)].objects.insert(
342  }
343  #endif
344 
345  #if 0
346  for(localst::locals_mapt::const_iterator
347  l_it=locals.locals_map.begin();
348  l_it!=locals.locals_map.end();
349  l_it++)
350  {
351  if(is_tracked(l_it->first))
352  loc_infos[0].aliases.make_union(
353  objects.number(l_it->second), unknown_object);
354  }
355  #endif
356 
357  while(!work_queue.empty())
358  {
359  local_cfgt::node_nrt loc_nr=work_queue.top();
360  const local_cfgt::nodet &node=cfg.nodes[loc_nr];
361  const goto_programt::instructiont &instruction=*node.t;
362  work_queue.pop();
363 
364  const loc_infot &loc_info_src=loc_infos[loc_nr];
365  loc_infot loc_info_dest=loc_infos[loc_nr];
366 
367  switch(instruction.type)
368  {
369  case ASSIGN:
370  {
371  const code_assignt &code_assign=to_code_assign(instruction.code);
372  assign_lhs(
373  code_assign.lhs(), code_assign.rhs(), loc_info_src, loc_info_dest);
374  }
375  break;
376 
377  case DECL:
378  {
379  const code_declt &code_decl=to_code_decl(instruction.code);
380  assign_lhs(
381  code_decl.symbol(), nil_exprt(), loc_info_src, loc_info_dest);
382  }
383  break;
384 
385  case DEAD:
386  {
387  const code_deadt &code_dead=to_code_dead(instruction.code);
388  assign_lhs(
389  code_dead.symbol(), nil_exprt(), loc_info_src, loc_info_dest);
390  }
391  break;
392 
393  case FUNCTION_CALL:
394  {
395  const code_function_callt &code_function_call=
396  to_code_function_call(instruction.code);
397  if(code_function_call.lhs().is_not_nil())
398  assign_lhs(
399  code_function_call.lhs(), nil_exprt(), loc_info_src, loc_info_dest);
400 
401  // this might invalidate all pointers that are
402  // a) local and dirty
403  // b) global
404  for(std::size_t i=0; i<objects.size(); i++)
405  {
406  if(objects[i].id()==ID_symbol)
407  {
408  const irep_idt &identifier=
410 
411  if(dirty(identifier) || !locals.is_local(identifier))
412  {
413  loc_info_dest.aliases.isolate(i);
414  loc_info_dest.aliases.make_union(i, unknown_object);
415  }
416  }
417  }
418  }
419  break;
420 
421  default:
422  {
423  }
424  }
425 
426  for(local_cfgt::successorst::const_iterator
427  it=node.successors.begin();
428  it!=node.successors.end();
429  it++)
430  {
431  if(loc_infos[*it].merge(loc_info_dest))
432  work_queue.push(*it);
433  }
434  }
435 }
436 
438  std::ostream &out,
439  const goto_functiont &goto_function,
440  const namespacet &ns) const
441 {
442  unsigned l=0;
443 
444  forall_goto_program_instructions(i_it, goto_function.body)
445  {
446  out << "**** " << i_it->source_location << "\n";
447 
448  const loc_infot &loc_info=loc_infos[l];
449 
450  for(std::size_t i=0; i<loc_info.aliases.size(); i++)
451  {
452  if(loc_info.aliases.count(i)!=1 &&
453  loc_info.aliases.find(i)==i) // root?
454  {
455  out << '{';
456  for(std::size_t j=0; j<loc_info.aliases.size(); j++)
457  if(loc_info.aliases.find(j)==i)
458  {
459  assert(j<objects.size());
460  irep_idt identifier = "";
461  if(objects[j].id() == ID_symbol)
462  identifier = to_symbol_expr(objects[j]).get_identifier();
463  out << ' ' << from_expr(ns, identifier, objects[j]);
464  }
465 
466  out << " }";
467  out << "\n";
468  }
469  }
470 
471  out << "\n";
472  goto_function.body.output_instruction(ns, "", out, *i_it);
473  out << "\n";
474 
475  l++;
476  }
477 }
const if_exprt & to_if_expr(const exprt &expr)
Cast a generic exprt to an if_exprt.
Definition: std_expr.h:3426
const code_declt & to_code_decl(const codet &code)
Definition: std_code.h:289
bool is_nil() const
Definition: irep.h:102
bool is_not_nil() const
Definition: irep.h:103
loc_mapt loc_map
Definition: local_cfg.h:33
exprt & object()
Definition: std_expr.h:3180
exprt & op0()
Definition: expr.h:72
const code_deadt & to_code_dead(const codet &code)
Definition: std_code.h:341
goto_program_instruction_typet type
What kind of instruction?
Definition: goto_program.h:185
exprt & symbol()
Definition: std_code.h:266
locals_mapt locals_map
Definition: locals.h:38
std::set< unsigned > object_sett
const irep_idt & get_identifier() const
Definition: std_expr.h:128
goto_programt body
Definition: goto_function.h:23
std::string from_expr(const namespacet &ns, const irep_idt &identifier, const exprt &expr)
std::stack< local_cfgt::node_nrt > work_queuet
typet & type()
Definition: expr.h:56
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast a generic exprt to an address_of_exprt.
Definition: std_expr.h:3201
size_type size() const
Definition: union_find.h:94
bool merge(const loc_infot &src)
std::size_t node_nrt
Definition: local_cfg.h:22
side_effect_exprt & to_side_effect_expr(exprt &expr)
Definition: std_code.h:1287
This class represents an instruction in the GOTO intermediate representation.
Definition: goto_program.h:173
void make_union(size_type a, size_type b)
Definition: union_find.cpp:13
nodest nodes
Definition: local_cfg.h:36
bool is_local(const irep_idt &identifier) const
Definition: locals.h:32
const code_assignt & to_code_assign(const codet &code)
Definition: std_code.h:239
void build(const goto_functiont &goto_function)
size_type find(size_type a) const
Definition: union_find.cpp:145
const irep_idt & id() const
Definition: irep.h:189
exprt & lhs()
Definition: std_code.h:208
A declaration of a local variable.
Definition: std_code.h:253
loc_infost loc_infos
The NIL expression.
Definition: std_expr.h:4510
exprt & rhs()
Definition: std_code.h:213
API to expression classes.
size_type count(size_type a) const
Definition: union_find.h:100
exprt & op1()
Definition: expr.h:75
instructionst::const_iterator const_targett
Definition: goto_program.h:398
TO_BE_DOCUMENTED.
Definition: namespace.h:74
const member_exprt & to_member_expr(const exprt &expr)
Cast a generic exprt to a member_exprt.
Definition: std_expr.h:3955
A function call.
Definition: std_code.h:828
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast a generic exprt to a symbol_exprt.
Definition: std_expr.h:210
code_typet type
Definition: goto_function.h:24
bitvector_typet index_type()
Definition: c_types.cpp:16
Operator to return the address of an object.
Definition: std_expr.h:3170
exprt & symbol()
Definition: std_code.h:318
void isolate(size_type a)
Definition: union_find.cpp:41
unsigned unknown_object
goto_programt::const_targett t
Definition: local_cfg.h:28
std::ostream & output_instruction(const namespacet &ns, const irep_idt &identifier, std::ostream &out, const instructionst::value_type &it) const
Output a single instruction.
exprt & index()
Definition: std_expr.h:1496
Base class for all expressions.
Definition: expr.h:42
const parameterst & parameters() const
Definition: std_types.h:905
void assign_lhs(const exprt &lhs, const exprt &rhs, const loc_infot &loc_info_src, loc_infot &loc_info_dest)
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast a generic exprt to a typecast_exprt.
Definition: std_expr.h:2143
A removal of a local variable.
Definition: std_code.h:305
bool is_zero() const
Definition: expr.cpp:161
numbering< exprt > objects
bool aliases(const goto_programt::const_targett t, const exprt &src1, const exprt &src2) const
void output(std::ostream &out, const goto_functiont &goto_function, const namespacet &ns) const
An expression containing a side effect.
Definition: std_code.h:1238
operandst & operands()
Definition: expr.h:66
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
#define forall_goto_program_instructions(it, program)
Definition: goto_program.h:735
bool same_set(size_type a, size_type b) const
Definition: union_find.h:88
exprt & array()
Definition: std_expr.h:1486
const index_exprt & to_index_expr(const exprt &expr)
Cast a generic exprt to an index_exprt.
Definition: std_expr.h:1517
Assignment.
Definition: std_code.h:195
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
const irep_idt & get_statement() const
Definition: std_code.h:1253
Field-insensitive, location-sensitive may-alias analysis.
successorst successors
Definition: local_cfg.h:29
const code_function_callt & to_code_function_call(const codet &code)
Definition: std_code.h:879
array index operator
Definition: std_expr.h:1462