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).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 == 0)
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).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).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(to_symbol_expr(index_expr.array()).identifier()))
152 else
154 }
155 else
156 return flagst::mk_unknown();
157 }
158 else
159 return flagst::mk_unknown();
160 }
161 else if(rhs.id()==ID_typecast)
162 {
163 return get_rec(to_typecast_expr(rhs).op(), loc_info_src);
164 }
165 else if(rhs.id()==ID_uninitialized)
166 {
168 }
169 else if(rhs.id()==ID_plus)
170 {
171 const auto &plus_expr = to_plus_expr(rhs);
172
173 if(plus_expr.operands().size() >= 3)
174 {
176 plus_expr.op0().type().id() == ID_pointer,
177 "pointer in pointer-typed sum must be op0");
179 }
180 else if(plus_expr.operands().size() == 2)
181 {
182 // one must be pointer, one an integer
183 if(plus_expr.op0().type().id() == ID_pointer)
184 {
185 return get_rec(plus_expr.op0(), loc_info_src) |
187 }
188 else if(plus_expr.op1().type().id() == ID_pointer)
189 {
190 return get_rec(plus_expr.op1(), loc_info_src) |
192 }
193 else
194 return flagst::mk_unknown();
195 }
196 else
197 return flagst::mk_unknown();
198 }
199 else if(rhs.id()==ID_minus)
200 {
201 const auto &op0 = to_minus_expr(rhs).op0();
202
203 if(op0.type().id() == ID_pointer)
204 {
206 }
207 else
208 return flagst::mk_unknown();
209 }
210 else if(rhs.id()==ID_member)
211 {
212 return flagst::mk_unknown();
213 }
214 else if(rhs.id()==ID_index)
215 {
216 return flagst::mk_unknown();
217 }
218 else if(rhs.id()==ID_dereference)
219 {
220 return flagst::mk_unknown();
221 }
222 else if(rhs.id()==ID_side_effect)
223 {
225 const irep_idt &statement=side_effect_expr.get_statement();
226
227 if(statement==ID_allocate)
229 else
230 return flagst::mk_unknown();
231 }
232 else
233 return flagst::mk_unknown();
234}
235
237{
238 if(cfg.nodes.empty())
239 return;
240
241 std::set<local_cfgt::node_nrt> work_queue;
242 work_queue.insert(0);
243
244 loc_infos.resize(cfg.nodes.size());
245
246 // Gather the objects we track, and
247 // feed in sufficiently bad defaults for their value
248 // in the entry location.
249 for(const auto &local : locals.locals)
250 {
251 if(is_tracked(local))
253 }
254
255 while(!work_queue.empty())
256 {
257 const auto loc_nr = *work_queue.begin();
258 const local_cfgt::nodet &node=cfg.nodes[loc_nr];
259 const goto_programt::instructiont &instruction=*node.t;
260 work_queue.erase(work_queue.begin());
261
264
265 switch(instruction.type())
266 {
267 case ASSIGN:
269 instruction.assign_lhs(),
270 instruction.assign_rhs(),
273 break;
274
275 case DECL:
277 instruction.decl_symbol(),
281 break;
282
283 case DEAD:
285 instruction.dead_symbol(),
289 break;
290
291 case FUNCTION_CALL:
292 {
293 const auto &lhs = instruction.call_lhs();
294 if(lhs.is_not_nil())
296 break;
297 }
298
299 case CATCH:
300 case THROW:
301#if 0
302 DATA_INVARIANT(false, "Exceptions must be removed before analysis");
303 break;
304#endif
305 case SET_RETURN_VALUE:
306#if 0
307 DATA_INVARIANT(false, "SET_RETURN_VALUE must be removed before analysis");
308 break;
309#endif
310 case ATOMIC_BEGIN: // Ignoring is a valid over-approximation
311 case ATOMIC_END: // Ignoring is a valid over-approximation
312 case LOCATION: // No action required
313 case START_THREAD: // Require a concurrent analysis at higher level
314 case END_THREAD: // Require a concurrent analysis at higher level
315 case SKIP: // No action required
316 case ASSERT: // No action required
317 case ASSUME: // Ignoring is a valid over-approximation
318 case GOTO: // Ignoring the guard is a valid over-approximation
319 case END_FUNCTION: // No action required
320 break;
321 case OTHER:
322#if 0
324 false, "Unclear what is a safe over-approximation of OTHER");
325#endif
326 break;
327 case INCOMPLETE_GOTO:
329 DATA_INVARIANT(false, "Only complete instructions can be analyzed");
330 break;
331 }
332
333 for(const auto &succ : node.successors)
334 {
335 INVARIANT(succ < loc_infos.size(), "successor outside function");
336 if(merge(loc_infos[succ], (loc_info_dest)))
337 work_queue.insert(succ);
338 }
339 }
340}
341
343 std::ostream &out,
344 const goto_functiont &goto_function,
345 const namespacet &ns) const
346{
347 std::size_t l = 0;
348
349 for(const auto &instruction : goto_function.body.instructions)
350 {
351 out << "**** " << instruction.source_location() << "\n";
352
353 const auto &loc_info=loc_infos[l];
354
356 p_it=loc_info.begin();
357 p_it!=loc_info.end();
358 p_it++)
359 {
360 out << " " << pointers[p_it-loc_info.begin()]
361 << ": "
362 << *p_it
363 << "\n";
364 }
365
366 out << "\n";
367 instruction.output(out);
368 out << "\n";
369
370 l++;
371 }
372}
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:566
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:57
bool is_constant() const
Return whether the expression is a constant.
Definition expr.h:213
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
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:3144
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: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
Symbol table entry.