CBMC
local_bitvector_analysis.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 
13 
14 #include <util/namespace.h>
15 #include <util/pointer_expr.h>
16 #include <util/std_code.h>
17 #include <util/symbol.h>
18 
19 #include <algorithm>
20 
21 void local_bitvector_analysist::flagst::print(std::ostream &out) const
22 {
23  if(is_unknown())
24  out << "+unknown";
25  if(is_uninitialized())
26  out << "+uninitialized";
27  if(is_uses_offset())
28  out << "+uses_offset";
29  if(is_dynamic_local())
30  out << "+dynamic_local";
31  if(is_dynamic_heap())
32  out << "+dynamic_heap";
33  if(is_null())
34  out << "+null";
35  if(is_static_lifetime())
36  out << "+static_lifetime";
37  if(is_integer_address())
38  out << "+integer_address";
39 }
40 
42 {
43  bool result=false;
44 
45  std::size_t max_index=
46  std::max(a.size(), b.size());
47 
48  for(std::size_t i=0; i<max_index; i++)
49  result |= a[i].merge(b[i]);
50 
51  return result;
52 }
53 
56 {
57  localst::locals_sett::const_iterator it = locals.locals.find(identifier);
58  return it != locals.locals.end() && ns.lookup(*it).type.id() == ID_pointer &&
59  !dirty(identifier);
60 }
61 
63  const exprt &lhs,
64  const exprt &rhs,
65  points_tot &loc_info_src,
66  points_tot &loc_info_dest)
67 {
68  if(lhs.id()==ID_symbol)
69  {
70  const irep_idt &identifier=to_symbol_expr(lhs).get_identifier();
71 
72  if(is_tracked(identifier))
73  {
74  const auto dest_pointer = pointers.number(identifier);
75  flagst rhs_flags=get_rec(rhs, loc_info_src);
76  loc_info_dest[dest_pointer]=rhs_flags;
77  }
78  }
79  else if(lhs.id()==ID_dereference)
80  {
81  }
82  else if(lhs.id()==ID_index)
83  {
84  assign_lhs(to_index_expr(lhs).array(), rhs, loc_info_src, loc_info_dest);
85  }
86  else if(lhs.id()==ID_member)
87  {
88  assign_lhs(
89  to_member_expr(lhs).struct_op(), rhs, loc_info_src, loc_info_dest);
90  }
91  else if(lhs.id()==ID_typecast)
92  {
93  assign_lhs(to_typecast_expr(lhs).op(), rhs, loc_info_src, loc_info_dest);
94  }
95  else if(lhs.id()==ID_if)
96  {
97  assign_lhs(to_if_expr(lhs).true_case(), rhs, loc_info_src, loc_info_dest);
98  assign_lhs(to_if_expr(lhs).false_case(), rhs, loc_info_src, loc_info_dest);
99  }
100 }
101 
104  const exprt &rhs)
105 {
106  local_cfgt::loc_mapt::const_iterator loc_it=cfg.loc_map.find(t);
107  CHECK_RETURN(loc_it != cfg.loc_map.end());
108 
109  return get_rec(rhs, loc_infos[loc_it->second]);
110 }
111 
113  const exprt &rhs,
114  points_tot &loc_info_src)
115 {
116  if(rhs.is_constant())
117  {
118  if(rhs.is_zero())
119  return flagst::mk_null();
120  else
122  }
123  else if(rhs.id()==ID_symbol)
124  {
125  const irep_idt &identifier=to_symbol_expr(rhs).get_identifier();
126  if(is_tracked(identifier))
127  {
128  const auto src_pointer = pointers.number(identifier);
129  return loc_info_src[src_pointer];
130  }
131  else
132  return flagst::mk_unknown();
133  }
134  else if(rhs.id()==ID_address_of)
135  {
136  const exprt &object=to_address_of_expr(rhs).object();
137 
138  if(object.id()==ID_symbol)
139  {
140  if(locals.is_local(to_symbol_expr(object).get_identifier()))
141  return flagst::mk_dynamic_local();
142  else
144  }
145  else if(object.id()==ID_index)
146  {
147  const index_exprt &index_expr=to_index_expr(object);
148  if(index_expr.array().id()==ID_symbol)
149  {
150  if(locals.is_local(
151  to_symbol_expr(index_expr.array()).get_identifier()))
153  else
155  }
156  else
157  return flagst::mk_unknown();
158  }
159  else
160  return flagst::mk_unknown();
161  }
162  else if(rhs.id()==ID_typecast)
163  {
164  return get_rec(to_typecast_expr(rhs).op(), loc_info_src);
165  }
166  else if(rhs.id()==ID_uninitialized)
167  {
168  return flagst::mk_uninitialized();
169  }
170  else if(rhs.id()==ID_plus)
171  {
172  const auto &plus_expr = to_plus_expr(rhs);
173 
174  if(plus_expr.operands().size() >= 3)
175  {
177  plus_expr.op0().type().id() == ID_pointer,
178  "pointer in pointer-typed sum must be op0");
179  return get_rec(plus_expr.op0(), loc_info_src) | flagst::mk_uses_offset();
180  }
181  else if(plus_expr.operands().size() == 2)
182  {
183  // one must be pointer, one an integer
184  if(plus_expr.op0().type().id() == ID_pointer)
185  {
186  return get_rec(plus_expr.op0(), loc_info_src) |
188  }
189  else if(plus_expr.op1().type().id() == ID_pointer)
190  {
191  return get_rec(plus_expr.op1(), loc_info_src) |
193  }
194  else
195  return flagst::mk_unknown();
196  }
197  else
198  return flagst::mk_unknown();
199  }
200  else if(rhs.id()==ID_minus)
201  {
202  const auto &op0 = to_minus_expr(rhs).op0();
203 
204  if(op0.type().id() == ID_pointer)
205  {
206  return get_rec(op0, loc_info_src) | flagst::mk_uses_offset();
207  }
208  else
209  return flagst::mk_unknown();
210  }
211  else if(rhs.id()==ID_member)
212  {
213  return flagst::mk_unknown();
214  }
215  else if(rhs.id()==ID_index)
216  {
217  return flagst::mk_unknown();
218  }
219  else if(rhs.id()==ID_dereference)
220  {
221  return flagst::mk_unknown();
222  }
223  else if(rhs.id()==ID_side_effect)
224  {
225  const side_effect_exprt &side_effect_expr=to_side_effect_expr(rhs);
226  const irep_idt &statement=side_effect_expr.get_statement();
227 
228  if(statement==ID_allocate)
229  return flagst::mk_dynamic_heap();
230  else
231  return flagst::mk_unknown();
232  }
233  else
234  return flagst::mk_unknown();
235 }
236 
238 {
239  if(cfg.nodes.empty())
240  return;
241 
242  std::set<local_cfgt::node_nrt> work_queue;
243  work_queue.insert(0);
244 
245  loc_infos.resize(cfg.nodes.size());
246 
247  // Gather the objects we track, and
248  // feed in sufficiently bad defaults for their value
249  // in the entry location.
250  for(const auto &local : locals.locals)
251  {
252  if(is_tracked(local))
254  }
255 
256  while(!work_queue.empty())
257  {
258  const auto loc_nr = *work_queue.begin();
259  const local_cfgt::nodet &node=cfg.nodes[loc_nr];
260  const goto_programt::instructiont &instruction=*node.t;
261  work_queue.erase(work_queue.begin());
262 
263  auto &loc_info_src=loc_infos[loc_nr];
264  auto loc_info_dest=loc_infos[loc_nr];
265 
266  switch(instruction.type())
267  {
268  case ASSIGN:
269  assign_lhs(
270  instruction.assign_lhs(),
271  instruction.assign_rhs(),
272  loc_info_src,
273  loc_info_dest);
274  break;
275 
276  case DECL:
277  assign_lhs(
278  instruction.decl_symbol(),
279  exprt(ID_uninitialized),
280  loc_info_src,
281  loc_info_dest);
282  break;
283 
284  case DEAD:
285  assign_lhs(
286  instruction.dead_symbol(),
287  exprt(ID_uninitialized),
288  loc_info_src,
289  loc_info_dest);
290  break;
291 
292  case FUNCTION_CALL:
293  {
294  const auto &lhs = instruction.call_lhs();
295  if(lhs.is_not_nil())
296  assign_lhs(lhs, nil_exprt(), loc_info_src, loc_info_dest);
297  break;
298  }
299 
300  case CATCH:
301  case THROW:
302 #if 0
303  DATA_INVARIANT(false, "Exceptions must be removed before analysis");
304  break;
305 #endif
306  case SET_RETURN_VALUE:
307 #if 0
308  DATA_INVARIANT(false, "SET_RETURN_VALUE must be removed before analysis");
309  break;
310 #endif
311  case ATOMIC_BEGIN: // Ignoring is a valid over-approximation
312  case ATOMIC_END: // Ignoring is a valid over-approximation
313  case LOCATION: // No action required
314  case START_THREAD: // Require a concurrent analysis at higher level
315  case END_THREAD: // Require a concurrent analysis at higher level
316  case SKIP: // No action required
317  case ASSERT: // No action required
318  case ASSUME: // Ignoring is a valid over-approximation
319  case GOTO: // Ignoring the guard is a valid over-approximation
320  case END_FUNCTION: // No action required
321  break;
322  case OTHER:
323 #if 0
325  false, "Unclear what is a safe over-approximation of OTHER");
326 #endif
327  break;
328  case INCOMPLETE_GOTO:
329  case NO_INSTRUCTION_TYPE:
330  DATA_INVARIANT(false, "Only complete instructions can be analyzed");
331  break;
332  }
333 
334  for(const auto &succ : node.successors)
335  {
336  INVARIANT(succ < loc_infos.size(), "successor outside function");
337  if(merge(loc_infos[succ], (loc_info_dest)))
338  work_queue.insert(succ);
339  }
340  }
341 }
342 
344  std::ostream &out,
345  const goto_functiont &goto_function,
346  const namespacet &ns) const
347 {
348  std::size_t l = 0;
349 
350  for(const auto &instruction : goto_function.body.instructions)
351  {
352  out << "**** " << instruction.source_location() << "\n";
353 
354  const auto &loc_info=loc_infos[l];
355 
357  p_it=loc_info.begin();
358  p_it!=loc_info.end();
359  p_it++)
360  {
361  out << " " << pointers[p_it-loc_info.begin()]
362  << ": "
363  << *p_it
364  << "\n";
365  }
366 
367  out << "\n";
368  instruction.output(out);
369  out << "\n";
370 
371  l++;
372  }
373 }
exprt & object()
Definition: pointer_expr.h:549
exprt & op0()
Definition: expr.h:133
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
size_type size() const
data_typet::const_iterator const_iterator
Base class for all expressions.
Definition: expr.h:56
bool is_zero() const
Return whether the expression is a constant representing 0.
Definition: expr.cpp:47
bool is_constant() const
Return whether the expression is a constant.
Definition: expr.h:212
A goto function, consisting of function body (see body) and parameter identifiers (see parameter_iden...
Definition: goto_function.h:24
goto_programt body
Definition: goto_function.h:26
This class represents an instruction in the GOTO intermediate representation.
Definition: goto_program.h:181
const exprt & call_lhs() const
Get the lhs of a FUNCTION_CALL (may be nil)
Definition: goto_program.h:286
const exprt & assign_rhs() const
Get the rhs of the assignment for ASSIGN.
Definition: goto_program.h:214
const symbol_exprt & dead_symbol() const
Get the symbol for DEAD.
Definition: goto_program.h:244
const symbol_exprt & decl_symbol() const
Get the declared symbol for DECL.
Definition: goto_program.h:228
const exprt & assign_lhs() const
Get the lhs of the assignment for ASSIGN.
Definition: goto_program.h:200
goto_program_instruction_typet type() const
What kind of instruction?
Definition: goto_program.h:344
instructionst instructions
The list of instructions in the goto program.
Definition: goto_program.h:622
instructionst::const_iterator const_targett
Definition: goto_program.h:615
Array index operator.
Definition: std_expr.h:1465
exprt & array()
Definition: std_expr.h:1495
const irep_idt & id() const
Definition: irep.h:384
static bool merge(points_tot &a, points_tot &b)
flagst get(const goto_programt::const_targett t, const exprt &src)
void output(std::ostream &out, const goto_functiont &goto_function, const namespacet &ns) const
flagst get_rec(const exprt &rhs, points_tot &loc_info_src)
void assign_lhs(const exprt &lhs, const exprt &rhs, points_tot &loc_info_src, points_tot &loc_info_dest)
bool is_tracked(const irep_idt &identifier)
goto_programt::const_targett t
Definition: local_cfg.h:28
successorst successors
Definition: local_cfg.h:29
nodest nodes
Definition: local_cfg.h:38
loc_mapt loc_map
Definition: local_cfg.h:35
bool is_local(const irep_idt &identifier) const
Definition: locals.h:37
locals_sett locals
Definition: locals.h:43
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
Definition: namespace.cpp:148
The NIL expression.
Definition: std_expr.h:3073
number_type number(const key_type &a)
Definition: numbering.h:37
An expression containing a side effect.
Definition: std_code.h:1450
const irep_idt & get_statement() const
Definition: std_code.h:1472
const irep_idt & get_identifier() const
Definition: std_expr.h:160
@ FUNCTION_CALL
Definition: goto_program.h:49
@ ATOMIC_END
Definition: goto_program.h:44
@ DEAD
Definition: goto_program.h:48
@ END_FUNCTION
Definition: goto_program.h:42
@ ASSIGN
Definition: goto_program.h:46
@ ASSERT
Definition: goto_program.h:36
@ SET_RETURN_VALUE
Definition: goto_program.h:45
@ ATOMIC_BEGIN
Definition: goto_program.h:43
@ CATCH
Definition: goto_program.h:51
@ END_THREAD
Definition: goto_program.h:40
@ SKIP
Definition: goto_program.h:38
@ NO_INSTRUCTION_TYPE
Definition: goto_program.h:33
@ START_THREAD
Definition: goto_program.h:39
@ THROW
Definition: goto_program.h:50
@ DECL
Definition: goto_program.h:47
@ OTHER
Definition: goto_program.h:37
@ GOTO
Definition: goto_program.h:34
@ INCOMPLETE_GOTO
Definition: goto_program.h:52
Field-insensitive, location-sensitive bitvector 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.
Definition: pointer_expr.h:577
#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
side_effect_exprt & to_side_effect_expr(exprt &expr)
Definition: std_code.h:1506
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition: std_expr.h:2450
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition: std_expr.h:2102
const minus_exprt & to_minus_expr(const exprt &expr)
Cast an exprt to a minus_exprt.
Definition: std_expr.h:1086
const plus_exprt & to_plus_expr(const exprt &expr)
Cast an exprt to a plus_exprt.
Definition: std_expr.h:1041
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2933
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1533
Symbol table entry.