CBMC
Loading...
Searching...
No Matches
flow_insensitive_analysis.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Flow Insensitive Static Analysis
4
5Author: Daniel Kroening, kroening@kroening.com
6 CM Wintersteiger
7
8\*******************************************************************/
9
12
14
15#include <util/expr_util.h>
16#include <util/pointer_expr.h>
17#include <util/std_code.h>
18
21 locationt to) const
22{
23 if(!from->is_goto())
24 return true_exprt();
25 else if(std::next(from) == to)
26 return boolean_negate(from->condition());
27 else
28 return from->condition();
29}
30
32{
33 // get predecessor of "to"
34 to--;
35
36 if(to->is_end_function())
37 return static_cast<const exprt &>(get_nil_irep());
38
39 // must be the function call
40 return to->call_lhs();
41}
42
44 const goto_functionst &goto_functions)
45{
46 initialize(goto_functions);
47 fixedpoint(goto_functions);
48}
49
51operator()(const irep_idt &function_id, const goto_programt &goto_program)
52{
53 initialize(goto_program);
54 goto_functionst goto_functions;
55 fixedpoint(function_id, goto_program, goto_functions);
56}
57
59 const goto_functionst &goto_functions,
60 std::ostream &out)
61{
62 for(const auto &gf_entry : goto_functions.function_map)
63 {
64 out << "////\n"
65 << "//// Function: " << gf_entry.first << "\n////\n\n";
66
67 output(gf_entry.first, gf_entry.second.body, out);
68 }
69}
70
72 const irep_idt &,
73 const goto_programt &,
74 std::ostream &out)
75{
76 get_state().output(ns, out);
77}
78
82{
83 PRECONDITION(!working_set.empty());
84
85 // working_sett::iterator i=working_set.begin();
86 // locationt l=i->second;
87 // working_set.erase(i);
88
89 // pop_heap(working_set.begin(), working_set.end());
90 locationt l=working_set.top();
91 working_set.pop();
92
93 return l;
94}
95
97 const irep_idt &function_id,
98 const goto_programt &goto_program,
99 const goto_functionst &goto_functions)
100{
101 if(goto_program.instructions.empty())
102 return false;
103
105
106// make_heap(working_set.begin(), working_set.end());
107
110 goto_program.instructions.begin());
111
112 bool new_data=false;
113
114 while(!working_set.empty())
115 {
117
118 if(visit(function_id, l, working_set, goto_program, goto_functions))
119 new_data=true;
120 }
121
122 return new_data;
123}
124
126 const irep_idt &function_id,
127 locationt l,
129 const goto_programt &goto_program,
130 const goto_functionst &goto_functions)
131{
132 bool new_data=false;
133
134 #if 0
135 std::cout << "Visiting: " << l->function << " " <<
136 l->location_number << '\n';
137 #endif
138
139 seen_locations.insert(l);
140 if(statistics.find(l)==statistics.end())
141 statistics[l]=1;
142 else
143 statistics[l]++;
144
145 for(const auto &to_l : goto_program.get_successors(l))
146 {
147 if(to_l==goto_program.instructions.end())
148 continue;
149
150 bool changed=false;
151
152 if(l->is_function_call())
153 {
154 // this is a big special case
155 changed = do_function_call_rec(
156 function_id,
157 l,
158 l->call_function(),
159 l->call_arguments(),
160 get_state(),
161 goto_functions);
162 }
163 else
164 changed = get_state().transform(ns, function_id, l, function_id, to_l);
165
166 if(changed || !seen(to_l))
167 {
168 new_data=true;
170 }
171 }
172
173// if (id2string(l->function).find("debug")!=std::string::npos)
174// std::cout << l->function << '\n'; //=="messages::debug")
175
176 // {
177 // static unsigned state_cntr=0;
178 // std::string s("pastate"); s += std::to_string(state_cntr);
179 // std::ofstream f(s.c_str());
180 // l->output(f);
181 // f << '\n';
182 // get_state().output(ns, f);
183 // f.close();
184 // state_cntr++;
185 // }
186
187 return new_data;
188}
189
191 const irep_idt &calling_function,
193 const goto_functionst &goto_functions,
194 const goto_functionst::function_mapt::const_iterator f_it,
195 const exprt::operandst &,
196 statet &state)
197{
198 const goto_functionst::goto_functiont &goto_function=f_it->second;
199
200 if(!goto_function.body_available())
201 {
203
206 l_call->call_lhs().type(), l_call->source_location())));
207 r->location_number=0;
208
210 t->location_number=1;
211
213 // do the edge from the call site to the simulated function (the artificial
214 // return statement that we just generated)
215 bool new_data =
216 state.transform(ns, calling_function, l_call, f_it->first, r);
217 // do the edge from the return to the artificial end-of-function
218 new_data = state.transform(ns, f_it->first, r, f_it->first, t) || new_data;
219 // do edge from (artificial) end of function to instruction after call
220 new_data =
221 state.transform(ns, f_it->first, t, calling_function, l_next) || new_data;
222
223 return new_data;
224 }
225
227 !goto_function.body.instructions.empty(), "body must be present");
228
229 bool new_data=false;
230
231 {
232 // get the state at the beginning of the function
233 locationt l_begin=goto_function.body.instructions.begin();
234
235 // do the edge from the call site to the beginning of the function
236 new_data =
237 state.transform(ns, calling_function, l_call, f_it->first, l_begin);
238
239 // do each function at least once
240 if(functions_done.find(f_it->first)==
241 functions_done.end())
242 {
243 new_data=true;
244 functions_done.insert(f_it->first);
245 }
246
247 // do we need to do the fixedpoint of the body?
248 if(new_data)
249 {
250 // recursive call
251 fixedpoint(f_it->first, goto_function.body, goto_functions);
252 new_data=true; // could be reset by fixedpoint
253 }
254 }
255
256 {
257 // get location at end of procedure
258 locationt l_end=--goto_function.body.instructions.end();
259
260 DATA_INVARIANT(l_end->is_end_function(), "must be end of function");
261
262 // do edge from end of function to instruction after call
264 l_next++;
265 new_data =
266 state.transform(ns, f_it->first, l_end, calling_function, l_next) ||
267 new_data;
268 }
269
270 return new_data;
271}
272
274 const irep_idt &calling_function,
276 const exprt &function,
277 const exprt::operandst &arguments,
278 statet &state,
279 const goto_functionst &goto_functions)
280{
281 bool new_data = false;
282
283 if(function.id()==ID_symbol)
284 {
285 const irep_idt &identifier = to_symbol_expr(function).get_identifier();
286
287 if(recursion_set.find(identifier)!=recursion_set.end())
288 {
289 // recursion detected!
290 return false;
291 }
292 else
293 recursion_set.insert(identifier);
294
295 goto_functionst::function_mapt::const_iterator it=
296 goto_functions.function_map.find(identifier);
297
298 if(it==goto_functions.function_map.end())
299 throw "failed to find function "+id2string(identifier);
300
302 calling_function, l_call, goto_functions, it, arguments, state);
303
304 recursion_set.erase(identifier);
305 }
306 else if(function.id()==ID_if)
307 {
308 const auto &if_expr = to_if_expr(function);
309
311 calling_function,
312 l_call,
313 if_expr.true_case(),
314 arguments,
315 state,
316 goto_functions);
317
319 calling_function,
320 l_call,
321 if_expr.false_case(),
322 arguments,
323 state,
324 goto_functions) ||
325 new_data;
326 }
327 else if(function.id()==ID_dereference)
328 {
329 // get value set
330 expr_sett values;
331
332 get_reference_set(function, values);
333
334 // now call all of these
335 for(const auto &v : values)
336 {
337 if(v.id()==ID_object_descriptor)
338 {
340
341 // ... but only if they are actually functions.
342 goto_functionst::function_mapt::const_iterator it=
343 goto_functions.function_map.find(o.object().get(ID_identifier));
344
345 if(it!=goto_functions.function_map.end())
346 {
348 calling_function,
349 l_call,
350 o.object(),
351 arguments,
352 state,
353 goto_functions) ||
354 new_data;
355 }
356 }
357 }
358 }
359 else if(function.id() == ID_null_object)
360 {
361 // ignore, can't be a function
362 }
363 else if(function.id()==ID_member || function.id()==ID_index)
364 {
365 // ignore, can't be a function
366 }
367 else if(function.id()=="builtin-function")
368 {
369 // ignore
370 }
371 else
372 {
373 throw "unexpected function_call argument: "+
374 function.id_string();
375 }
376 return new_data;
377}
378
380 const goto_functionst &goto_functions)
381{
382 // do each function at least once
383
384 for(const auto &gf_entry : goto_functions.function_map)
385 {
386 if(functions_done.find(gf_entry.first) == functions_done.end())
387 {
388 functions_done.insert(gf_entry.first);
389 fixedpoint(gf_entry.first, gf_entry.second.body, goto_functions);
390 }
391 }
392}
393
395{
396 // no need to copy value sets around
397}
398
400{
401 // no need to copy value sets around
402}
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
Base class for all expressions.
Definition expr.h:56
std::vector< exprt > operandst
Definition expr.h:58
exprt get_guard(locationt from, locationt to) const
virtual bool transform(const namespacet &ns, const irep_idt &function_from, locationt from, const irep_idt &function_to, locationt to)=0
std::map< locationt, unsigned, goto_programt::target_less_than > statistics
virtual void output(const goto_functionst &goto_functions, std::ostream &out)
std::priority_queue< locationt, std::vector< locationt >, goto_programt::target_less_than > working_sett
virtual void operator()(const irep_idt &function_id, const goto_programt &goto_program)
virtual void get_reference_set(const exprt &expr, expr_sett &expr_set)=0
locationt get_next(working_sett &working_set)
std::set< locationt, goto_programt::target_less_than > seen_locations
bool fixedpoint(const irep_idt &function_id, const goto_programt &goto_program, const goto_functionst &goto_functions)
bool visit(const irep_idt &function_id, locationt l, working_sett &working_set, const goto_programt &goto_program, const goto_functionst &goto_functions)
virtual void update(const goto_programt &goto_program)
flow_insensitive_abstract_domain_baset::expr_sett expr_sett
bool do_function_call_rec(const irep_idt &calling_function, locationt l_call, const exprt &function, const exprt::operandst &arguments, statet &new_state, const goto_functionst &goto_functions)
goto_programt::const_targett locationt
virtual void initialize(const goto_programt &)
void put_in_working_set(working_sett &working_set, locationt l)
bool do_function_call(const irep_idt &calling_function, locationt l_call, const goto_functionst &goto_functions, const goto_functionst::function_mapt::const_iterator f_it, const exprt::operandst &arguments, statet &new_state)
virtual statet & get_state()=0
A collection of goto functions.
function_mapt function_map
::goto_functiont goto_functiont
A generic container class for the GOTO intermediate representation of one function.
instructionst instructions
The list of instructions in the goto program.
static instructiont make_set_return_value(exprt return_value, const source_locationt &l=source_locationt::nil())
static instructiont make_end_function(const source_locationt &l=source_locationt::nil())
instructionst::iterator targett
std::list< Target > get_successors(Target target) const
Get control-flow successors of a given instruction.
const irep_idt & get(const irep_idt &name) const
Definition irep.cpp:44
const std::string & id_string() const
Definition irep.h:391
const irep_idt & id() const
Definition irep.h:388
Split an expression into a base object and a (byte) offset.
A side_effect_exprt that returns a non-deterministically chosen value.
Definition std_code.h:1520
The Boolean constant true.
Definition std_expr.h:3190
exprt boolean_negate(const exprt &src)
negate a Boolean expression, possibly removing a not_exprt, and swapping false and true
Deprecated expression utility functions.
Flow Insensitive Static Analysis.
const irept & get_nil_irep()
Definition irep.cpp:19
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
static int8_t r
Definition irep_hash.h:60
API to expression classes for Pointers.
const object_descriptor_exprt & to_object_descriptor_expr(const exprt &expr)
Cast an exprt to an object_descriptor_exprt.
#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 PRECONDITION(CONDITION)
Definition invariant.h:463
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition std_expr.h:2577
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:272