CBMC
Loading...
Searching...
No Matches
uncaught_exceptions_analysis.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Over-approximating uncaught exceptions analysis
4
5Author: Cristina David
6
7\*******************************************************************/
8
11
12#ifdef DEBUG
13#include <iostream>
14#endif
16
17#include <util/namespace.h>
18#include <util/pointer_expr.h>
19
21
25{
26 if(type.base_type().id() == ID_struct_tag)
27 return to_struct_tag_type(type.base_type()).get_identifier();
28 else
29 return ID_empty;
30}
31
34{
35 if(expr.id() != ID_symbol && expr.operands().size() >= 1)
36 return get_exception_symbol(to_multi_ary_expr(expr).op0());
37
38 return expr;
39}
40
43 const irep_idt &element)
44{
45 thrown.insert(element);
46}
47
49 const std::set<irep_idt> &elements)
50{
51 thrown.insert(elements.begin(), elements.end());
52}
53
55 const std::vector<irep_idt> &elements)
56{
57 thrown.insert(elements.begin(), elements.end());
58}
59
60
65 const namespacet &)
66{
67 const goto_programt::instructiont &instruction=*from;
68
69 switch(instruction.type())
70 {
71 case THROW:
72 {
73 const exprt &exc_symbol = get_exception_symbol(instruction.code());
74 // retrieve the static type of the thrown exception
75 const irep_idt &type_id =
78 // we must consider all the subtypes given that
79 // the runtime type is a subtype of the static type
80 std::vector<irep_idt> subtypes =
82 join(subtypes);
83 break;
84 }
85 case CATCH:
86 {
87 if(!instruction.code().has_operands())
88 {
89 if(!instruction.targets.empty()) // push
90 {
91 std::set<irep_idt> caught;
92 stack_caught.push_back(caught);
93 std::set<irep_idt> &last_caught=stack_caught.back();
94 const irept::subt &exception_list =
95 instruction.code().find(ID_exception_list).get_sub();
96
97 for(const auto &exc : exception_list)
98 {
99 last_caught.insert(exc.id());
100 std::vector<irep_idt> subtypes=
102 last_caught.insert(subtypes.begin(), subtypes.end());
103 }
104 }
105 else // pop
106 {
107 if(!stack_caught.empty())
108 {
109 const std::set<irep_idt> &caught=stack_caught.back();
110 join(caught);
111 // remove the caught exceptions
112 for(const auto &exc_id : caught)
113 thrown.erase(exc_id);
114 stack_caught.pop_back();
115 }
116 }
117 }
118 break;
119 }
120 case FUNCTION_CALL:
121 {
122 const exprt &function_expr = instruction.call_function();
125 "identifier expected to be a symbol");
126 const irep_idt &function_name = to_symbol_expr(function_expr).identifier();
127 // use the current information about the callee
128 join(uea.exceptions_map[function_name]);
129 break;
130 }
131 case DECL: // Safe to ignore in this context
132 case DEAD: // Safe to ignore in this context
133 case ASSIGN: // Safe to ignore in this context
134 break;
135 case SET_RETURN_VALUE:
136#if 0
137 DATA_INVARIANT(false, "Returns must be removed before analysis");
138#endif
139 break;
140 case GOTO: // Ignoring the guard is a valid over-approximation
141 case ATOMIC_BEGIN: // Ignoring is a valid over-approximation
142 case ATOMIC_END: // Ignoring is a valid over-approximation
143 case START_THREAD: // Require a concurrent analysis at higher level
144 case END_THREAD: // Require a concurrent analysis at higher level
145 case END_FUNCTION: // No action required
146 case ASSERT: // No action required
147 case ASSUME: // Ignoring is a valid over-approximation
148 case LOCATION: // No action required
149 case SKIP: // No action required
150 break;
151 case OTHER:
152#if 0
153 DATA_INVARIANT(false, "Unclear what is a safe over-approximation of OTHER");
154#endif
155 break;
156 case INCOMPLETE_GOTO:
158 DATA_INVARIANT(false, "Only complete instructions can be analyzed");
159 break;
160 }
161}
162
164const std::set<irep_idt> &uncaught_exceptions_domaint::get_elements() const
165{
166 return thrown;
167}
168
175
178 const goto_functionst &goto_functions,
179 const namespacet &ns)
180{
181 bool change=true;
182
183 while(change)
184 {
185 change=false;
186 // add all the functions to the worklist
187 for(const auto &gf_entry : goto_functions.function_map)
188 {
190 const goto_programt &goto_program = gf_entry.second.body;
191
192 if(goto_program.empty())
193 continue;
194
196 {
197 domain.transform(instr_it, *this, ns);
198 }
199 // did our estimation for the current function improve?
200 const std::set<irep_idt> &elements=domain.get_elements();
201 if(exceptions_map[gf_entry.first].size() < elements.size())
202 {
203 change=true;
204 exceptions_map[gf_entry.first] = elements;
205 }
206 }
207 }
208}
209
213 const goto_functionst &goto_functions) const
214{
215 (void)goto_functions; // unused parameter
216#ifdef DEBUG
217 for(const auto &gf_entry : goto_functions.function_map)
218 {
219 const auto fn = gf_entry.first;
220 const exceptions_mapt::const_iterator found=exceptions_map.find(fn);
221 // Functions like __CPROVER_assert and __CPROVER_assume are replaced by
222 // explicit GOTO instructions and will not show up in exceptions_map.
223 if(found==exceptions_map.end())
224 continue;
225
226 const auto &fs=found->second;
227 if(!fs.empty())
228 {
229 std::cout << "Uncaught exceptions in function " <<
230 fn << ": " << std::endl;
231 for(const auto exc_id : fs)
232 std::cout << id2string(exc_id) << " ";
233 std::cout << std::endl;
234 }
235 }
236#endif
237}
238
241 const goto_functionst &goto_functions,
242 const namespacet &ns,
244{
245 domain(ns);
246 collect_uncaught_exceptions(goto_functions, ns);
248 output(goto_functions);
249}
250
253 const goto_functionst &goto_functions,
254 const namespacet &ns,
255 std::map<irep_idt, std::set<irep_idt>> &exceptions_map)
256{
258 exceptions(goto_functions, ns, exceptions_map);
259}
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:566
idst get_children_trans(const irep_idt &id) const
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:57
operandst & operands()
Definition expr.h:95
A collection of goto functions.
function_mapt function_map
This class represents an instruction in the GOTO intermediate representation.
const goto_instruction_codet & code() const
Get the code represented by this instruction.
targetst targets
The list of successor instructions.
const exprt & call_function() const
Get the function that is called for FUNCTION_CALL.
goto_program_instruction_typet type() const
What kind of instruction?
A generic container class for the GOTO intermediate representation of one function.
instructionst::const_iterator const_targett
bool empty() const
Is the program empty?
const irep_idt & id() const
Definition irep.h:388
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition namespace.h:91
const symbol_table_baset & get_symbol_table() const
Return first symbol table registered with the namespace.
Definition namespace.h:123
The pointer type These are both 'bitvector_typet' (they have a width) and 'type_with_subtypet' (they ...
const typet & base_type() const
The type of the data what we point to.
computes in exceptions_map an overapproximation of the exceptions thrown by each method
void operator()(const goto_functionst &, const namespacet &, exceptions_mapt &)
Applies the uncaught exceptions analysis and outputs the result.
void output(const goto_functionst &) const
Prints the exceptions map that maps each method to the set of exceptions that may escape it.
std::map< irep_idt, std::set< irep_idt > > exceptions_mapt
void collect_uncaught_exceptions(const goto_functionst &, const namespacet &)
Runs the uncaught exceptions analysis, which populates the exceptions map.
static exprt get_exception_symbol(const exprt &exor)
Returns the symbol corresponding to an exception.
void transform(const goto_programt::const_targett, uncaught_exceptions_analysist &, const namespacet &)
The transformer for the uncaught exceptions domain.
void operator()(const namespacet &ns)
Constructs the class hierarchy.
const std::set< irep_idt > & get_elements() const
Returns the value of the private member thrown.
static irep_idt get_exception_type(const pointer_typet &)
Returns the compile type of an exception.
void join(const irep_idt &)
The join operator for the uncaught exceptions domain.
Goto Programs with Functions.
#define forall_goto_program_instructions(it, program)
@ 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
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
API to expression classes for Pointers.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition invariant.h:534
const multi_ary_exprt & to_multi_ary_expr(const exprt &expr)
Cast an exprt to a multi_ary_exprt.
Definition std_expr.h:991
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:221
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition std_types.h:517
void uncaught_exceptions(const goto_functionst &goto_functions, const namespacet &ns, std::map< irep_idt, std::set< irep_idt > > &exceptions_map)
Applies the uncaught exceptions analysis and outputs the result.
Over-approximative uncaught exceptions analysis.