CBMC
Loading...
Searching...
No Matches
goto_convert_exceptions.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Program Transformation
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
11
12#include "goto_convert_class.h"
13
14#include <util/std_expr.h>
16
18 const codet &code,
19 goto_programt &dest,
20 const irep_idt &mode)
21{
23 code.operands().size() == 2,
24 "msc_try_finally expects two arguments",
26
29
30 {
31 // save 'leave' target
32 leave_targett leave_target(targets);
33 targets.set_leave(tmp.instructions.begin());
34
35 // first put 'finally' code onto destructor stack
36 node_indext old_stack_top = targets.scope_stack.get_current_node();
37 targets.scope_stack.add(to_code(code.op1()), {});
38
39 // do 'try' code
40 convert(to_code(code.op0()), dest, mode);
41
42 // pop 'finally' from destructor stack
43 targets.scope_stack.set_current_node(old_stack_top);
44
45 // 'leave' target gets restored here
46 }
47
48 // now add 'finally' code
49 convert(to_code(code.op1()), dest, mode);
50
51 // this is the target for 'leave'
53}
54
56 const codet &code,
57 goto_programt &dest,
58 const irep_idt &mode)
59{
61 code.operands().size() == 3,
62 "msc_try_except expects three arguments",
64
65 convert(to_code(code.op0()), dest, mode);
66
67 // todo: generate exception tracking
68}
69
71 const codet &code,
72 goto_programt &dest,
73 const irep_idt &mode)
74{
76 targets.leave_set, "leave without target", code.find_source_location());
77
78 // need to process destructor stack
80 code.source_location(), dest, mode, targets.leave_stack_node);
81
82 dest.add(
84}
85
87 const codet &code,
88 goto_programt &dest,
89 const irep_idt &mode)
90{
92 code.operands().size() >= 2,
93 "try_catch expects at least two arguments",
95
96 // add the CATCH-push instruction to 'dest'
99
101
102 // the CATCH-push instruction is annotated with a list of IDs,
103 // one per target
104 code_push_catcht::exception_listt &exception_list =
105 push_catch_code.exception_list();
106
107 // add a SKIP target for the end of everything
108 goto_programt end;
110
111 // the first operand is the 'try' block
112 convert(to_code(code.op0()), dest, mode);
113
114 // add the CATCH-pop to the end of the 'try' block
117 catch_pop_instruction->code_nonconst() = code_pop_catcht();
118
119 // add a goto to the end of the 'try' block
121
122 for(std::size_t i = 1; i < code.operands().size(); i++)
123 {
124 const codet &block = to_code(code.operands()[i]);
125
126 // grab the ID and add to CATCH instruction
127 exception_list.push_back(
129
131 convert(block, tmp, mode);
132 catch_push_instruction->targets.push_back(tmp.instructions.begin());
134
135 // add a goto to the end of the 'catch' block
137 }
138
139 catch_push_instruction->code_nonconst() = push_catch_code;
140
141 // add the end-target
142 dest.destructive_append(end);
143}
144
146 const codet &code,
147 goto_programt &dest,
148 const irep_idt &mode)
149{
151 code.operands().size() == 2,
152 "CPROVER_try_catch expects two arguments",
153 code.find_source_location());
154
155 // this is where we go after 'throw'
158
159 // set 'throw' target
160 throw_targett throw_target(targets);
161 targets.set_throw(tmp.instructions.begin());
162
163 // now put 'catch' code onto destructor stack
165 catch_code.add_source_location() = code.source_location();
166
167 // Store the point before the temp catch code.
168 node_indext old_stack_top = targets.scope_stack.get_current_node();
169 targets.scope_stack.add(catch_code, {});
170
171 // now convert 'try' code
172 convert(to_code(code.op0()), dest, mode);
173
174 // pop 'catch' code off stack
175 targets.scope_stack.set_current_node(old_stack_top);
176
177 // add 'throw' target
179}
180
182 const codet &code,
183 goto_programt &dest,
184 const irep_idt &mode)
185{
186 // set the 'exception' flag
188 exception_flag(mode), true_exprt(), code.source_location()));
189
190 // do we catch locally?
191 if(targets.throw_set)
192 {
193 // need to process destructor stack
195 code.source_location(), dest, mode, targets.throw_stack_node);
196
197 // add goto
198 dest.add(
199 goto_programt::make_goto(targets.throw_target, code.source_location()));
200 }
201 else // otherwise, we do a return
202 {
203 // need to process destructor stack
204 unwind_destructor_stack(code.source_location(), dest, mode);
205
206 // add goto
207 dest.add(
208 goto_programt::make_goto(targets.return_target, code.source_location()));
209 }
210}
211
213 const codet &code,
214 goto_programt &dest,
215 const irep_idt &mode)
216{
218 code.operands().size() == 2,
219 "CPROVER_try_finally expects two arguments",
220 code.find_source_location());
221
222 // first put 'finally' code onto destructor stack
223 node_indext old_stack_top = targets.scope_stack.get_current_node();
224 targets.scope_stack.add(to_code(code.op1()), {});
225
226 // do 'try' code
227 convert(to_code(code.op0()), dest, mode);
228
229 // pop 'finally' from destructor stack
230 targets.scope_stack.set_current_node(old_stack_top);
231
232 // now add 'finally' code
233 convert(to_code(code.op1()), dest, mode);
234}
235
237{
238 irep_idt id = "$exception_flag";
239
240 symbol_table_baset::symbolst::const_iterator s_it =
241 symbol_table.symbols.find(id);
242
243 if(s_it == symbol_table.symbols.end())
244 {
245 symbolt new_symbol{id, bool_typet{}, mode};
246 new_symbol.base_name = "$exception_flag";
247 new_symbol.is_lvalue = true;
248 new_symbol.is_thread_local = true;
249 symbol_table.insert(std::move(new_symbol));
250 }
251
252 return symbol_exprt(id, bool_typet());
253}
254
281 const source_locationt &source_location,
282 goto_programt &dest,
283 const irep_idt &mode,
284 std::optional<node_indext> end_index,
285 std::optional<node_indext> starting_index)
286{
287 // As we go we'll keep targets.scope_stack.current_node pointing at the
288 // next node we intend to destroy, so that if our convert(...) call for each
289 // destructor returns, throws or otherwise unwinds then it will carry on from
290 // the correct point in the stack of variables we intend to destroy, and if it
291 // contains any DECL statements they will be added as a new child branch,
292 // again at the right point.
293
294 // We back up the current node as of entering this function so this
295 // side-effect is only noticed by that convert(...) call.
296
298 starting_index.value_or(targets.scope_stack.get_current_node());
299
300 targets.scope_stack.set_current_node(start_id);
301
302 node_indext end_id = end_index.value_or(0);
303
304 while(targets.scope_stack.get_current_node() > end_id)
305 {
306 node_indext current_node = targets.scope_stack.get_current_node();
307
308 std::optional<codet> &destructor =
309 targets.scope_stack.get_destructor(current_node);
310
311 // Descend the tree before unwinding so we don't re-do the current node
312 // in event that convert(...) recurses into this function:
313 targets.scope_stack.descend_tree();
314 if(destructor)
315 {
316 // Copy, assign source location then convert.
317 codet copied_instruction = *destructor;
318 copied_instruction.add_source_location() = source_location;
319 convert(copied_instruction, dest, mode);
320 }
321 }
322
323 // Restore the working destructor stack to how it was before we began:
324 targets.scope_stack.set_current_node(start_id);
325}
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
The Boolean type.
Definition std_types.h:36
codet representation of an if-then-else statement.
Definition std_code.h:460
Pops an exception handler from the stack of active handlers (i.e.
Definition std_code.h:1899
Pushes an exception handler, of the form: exception_tag1 -> label1 exception_tag2 -> label2 ....
Definition std_code.h:1805
std::vector< exception_list_entryt > exception_listt
Definition std_code.h:1849
Data structure for representing an arbitrary statement in a program.
exprt & op0()
Definition expr.h:133
exprt & op1()
Definition expr.h:136
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
const source_locationt & find_source_location() const
Get a source_locationt from the expression or from its operands (non-recursively).
Definition expr.cpp:147
operandst & operands()
Definition expr.h:94
const source_locationt & source_location() const
Definition expr.h:231
symbol_table_baset & symbol_table
void convert_CPROVER_throw(const codet &code, goto_programt &dest, const irep_idt &mode)
void convert_msc_try_finally(const codet &code, goto_programt &dest, const irep_idt &mode)
void unwind_destructor_stack(const source_locationt &source_location, goto_programt &dest, const irep_idt &mode, std::optional< node_indext > destructor_end_point={}, std::optional< node_indext > destructor_start_point={})
Unwinds the destructor stack and creates destructors for each node between destructor_start_point and...
struct goto_convertt::targetst targets
symbol_exprt exception_flag(const irep_idt &mode)
void convert_CPROVER_try_catch(const codet &code, goto_programt &dest, const irep_idt &mode)
void convert_msc_try_except(const codet &code, goto_programt &dest, const irep_idt &mode)
void convert_try_catch(const codet &code, goto_programt &dest, const irep_idt &mode)
void convert(const codet &code, goto_programt &dest, const irep_idt &mode)
converts 'code' and appends the result to 'dest'
void convert_CPROVER_try_finally(const codet &code, goto_programt &dest, const irep_idt &mode)
void convert_msc_leave(const codet &code, goto_programt &dest, const irep_idt &mode)
A generic container class for the GOTO intermediate representation of one function.
instructionst::iterator targett
void destructive_append(goto_programt &p)
Appends the given program p to *this. p is destroyed.
static instructiont make_assignment(const code_assignt &_code, const source_locationt &l=source_locationt::nil())
Create an assignment instruction.
static instructiont make_skip(const source_locationt &l=source_locationt::nil())
static instructiont make_catch(const source_locationt &l=source_locationt::nil())
targett add(instructiont &&instruction)
Adds a given instruction at the end.
static instructiont make_goto(targett _target, const source_locationt &l=source_locationt::nil())
const irep_idt & get(const irep_idt &name) const
Definition irep.cpp:44
Expression to hold a symbol (variable)
Definition std_expr.h:131
virtual std::pair< symbolt &, bool > insert(symbolt symbol)=0
Move or copy a new symbol to the symbol table.
const symbolst & symbols
Read-only field, used to look up symbols given their names.
Symbol table entry.
Definition symbol.h:28
The Boolean constant true.
Definition std_expr.h:3190
Program Transformation.
std::size_t node_indext
Definition scope_tree.h:19
#define INVARIANT_WITH_DIAGNOSTICS(CONDITION, REASON,...)
Same as invariant, with one or more diagnostics attached Diagnostics can be of any type that has a sp...
Definition invariant.h:437
const codet & to_code(const exprt &expr)
API to expression classes.
Author: Diffblue Ltd.