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