CBMC
Loading...
Searching...
No Matches
local_bitvector_analysis.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
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
21void local_bitvector_analysist::flagst::print(std::ostream &out) const
22{
23 if(is_unknown())
24 out << "+unknown";
26 out << "+uninitialized";
27 if(is_uses_offset())
28 out << "+uses_offset";
30 out << "+dynamic_local";
31 if(is_dynamic_heap())
32 out << "+dynamic_heap";
33 if(is_null())
34 out << "+null";
36 out << "+static_lifetime";
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,
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);
77 }
78 }
79 else if(lhs.id()==ID_dereference)
80 {
81 }
82 else if(lhs.id()==ID_index)
83 {
85 }
86 else if(lhs.id()==ID_member)
87 {
89 to_member_expr(lhs).struct_op(), rhs, loc_info_src, loc_info_dest);
90 }
91 else if(lhs.id()==ID_typecast)
92 {
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,
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);
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()))
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 {
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");
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 {
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 {
226 const irep_idt &statement=side_effect_expr.get_statement();
227
228 if(statement==ID_allocate)
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
265
266 switch(instruction.type())
267 {
268 case ASSIGN:
270 instruction.assign_lhs(),
271 instruction.assign_rhs(),
274 break;
275
276 case DECL:
278 instruction.decl_symbol(),
282 break;
283
284 case DEAD:
286 instruction.dead_symbol(),
290 break;
291
292 case FUNCTION_CALL:
293 {
294 const auto &lhs = instruction.call_lhs();
295 if(lhs.is_not_nil())
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:
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}
virtual void output(const namespacet &ns, const irep_idt &function_id, const goto_programt &goto_program, std::ostream &out) const
Output the abstract states for a single function.
Definition ai.cpp:39
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
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...
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:1470
const irep_idt & id() const
Definition irep.h:388
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:91
The NIL expression.
Definition std_expr.h:3208
number_type number(const key_type &a)
Definition numbering.h:37
An expression containing a side effect.
Definition std_code.h:1450
@ 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
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.
#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:1538
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition std_expr.h:2107
const plus_exprt & to_plus_expr(const exprt &expr)
Cast an exprt to a plus_exprt.
Definition std_expr.h:1041
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition std_expr.h:2577
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:3063
const minus_exprt & to_minus_expr(const exprt &expr)
Cast an exprt to a minus_exprt.
Definition std_expr.h:1086
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:272
Symbol table entry.