Skip to content

Commit 47b4ee9

Browse files
authored
Merge pull request diffblue#1725 from cesaro/exception-handlig-fixes
Exception handling fixes
2 parents d397d6a + 6c9f05e commit 47b4ee9

File tree

11 files changed

+172
-14
lines changed

11 files changed

+172
-14
lines changed
189 Bytes
Binary file not shown.
164 Bytes
Binary file not shown.
780 Bytes
Binary file not shown.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
test.class
3+
^VERIFICATION SUCCESSFUL$
4+
--
5+
^warning: ignoring
6+
--
7+
This test verifies that catches are executed in the correct order
8+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
class A extends RuntimeException {}
2+
class B extends A {}
3+
4+
// This test verifies that catches are executed in the correct order
5+
public class test {
6+
public static void main (String args[]) {
7+
int i = 0;
8+
try {
9+
try {
10+
throw new A();
11+
}
12+
catch(A exc) {
13+
i++;
14+
throw new B();
15+
}
16+
finally
17+
{
18+
// Make sure A threw into the catch
19+
assert(i==1);
20+
i++;
21+
}
22+
}
23+
catch(B exc) {
24+
// Make sure finally was executed
25+
assert(i==2);
26+
i++;
27+
}
28+
// Make sure B was rethrown by finally
29+
assert(i==3);
30+
}
31+
}
189 Bytes
Binary file not shown.
164 Bytes
Binary file not shown.
1.04 KB
Binary file not shown.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
test.class
3+
VERIFICATION SUCCESSFUL
4+
--
5+
^warning: ignoring
6+
--
7+
Tests embedded try-catch-finally to ensure the catching order is correct
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import org.cprover.CProver;
2+
class A extends RuntimeException {}
3+
class B extends A {}
4+
5+
// This test verifies that catches are executed in the correct order
6+
public class test {
7+
public static void main (String args[]) {
8+
int i = 0;
9+
int j = 0;
10+
try {
11+
try {
12+
try {
13+
if (CProver.nondetBoolean()) throw new A();
14+
else throw new B();
15+
}
16+
catch(B exc) {
17+
i++;
18+
}
19+
catch(A exc) {
20+
i++;
21+
throw new B();
22+
}
23+
finally
24+
{
25+
// Make sure A threw into the catch
26+
assert(i==1);
27+
i++;
28+
}
29+
assert(i==2);
30+
// Account for the rethrow in finally
31+
j++;
32+
}
33+
catch(B exc) {
34+
// Make sure finally was executed
35+
assert(i==2);
36+
i++;
37+
throw new B();
38+
}
39+
finally
40+
{
41+
assert ((i+j) == 3);
42+
}
43+
// Account for the rethrow in finally
44+
j++;
45+
}
46+
catch(B exc)
47+
{
48+
i++;
49+
}
50+
// Make sure B was rethrown by finally when A was thrown
51+
// or if B was thrown there was no rethrow
52+
assert(i+j == 4);
53+
}
54+
}

src/goto-programs/remove_exceptions.cpp

Lines changed: 72 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@ class remove_exceptionst
107107
const goto_programt::targett &,
108108
bool may_catch);
109109

110+
goto_programt::targett find_universal_exception(
111+
const remove_exceptionst::stack_catcht &stack_catch,
112+
goto_programt &goto_program,
113+
std::size_t &universal_try,
114+
std::size_t &universal_catch);
115+
110116
void add_exception_dispatch_sequence(
111117
goto_programt &goto_program,
112118
const goto_programt::targett &instr_it,
@@ -229,6 +235,55 @@ void remove_exceptionst::instrument_exception_handler(
229235
instr_it->make_skip();
230236
}
231237

238+
/// Find the innermost universal exception handler for the current
239+
/// program location which may throw (i.e. the first catch of type
240+
/// any in the innermost try that contains such). We record this one
241+
/// because no handler after it can possibly catch.
242+
/// The context is contained in stack_catch which is a stack of all the tries
243+
/// which contain the current program location in their bodies. Each of these
244+
/// in turn contains a list of all possible catches for that try giving the
245+
/// type of exception they catch and the location of the handler.
246+
/// This function returns the indices of the try and the catch within that try
247+
/// as well as the location of the handler.
248+
/// The first loop is in forward order because the insertion reverses the order
249+
/// we note that try1{ try2 {} catch2c {} catch2d {}} catch1a() {} catch1b{}
250+
/// must catch in the following order: 2c 2d 1a 1b hence the numerical index
251+
/// is reversed whereas the letter ordering remains the same.
252+
/// @param stack_catch exception table
253+
/// @param goto_program program being evaluated
254+
/// @param[out] universal_try returns the try block
255+
/// corresponding to the desired exception handler
256+
/// @param[out] universal_catch returns the catch block
257+
/// corresponding to the exception desired exception handler
258+
/// @return the desired exception handler
259+
goto_programt::targett remove_exceptionst::find_universal_exception(
260+
const remove_exceptionst::stack_catcht &stack_catch,
261+
goto_programt &goto_program,
262+
std::size_t &universal_try,
263+
std::size_t &universal_catch)
264+
{
265+
for(std::size_t i=stack_catch.size(); i>0;)
266+
{
267+
i--;
268+
for(std::size_t j=0; j<stack_catch[i].size(); ++j)
269+
{
270+
if(stack_catch[i][j].first.empty())
271+
{
272+
// Record the position of the default behaviour as any further catches
273+
// will not capture the throw
274+
universal_try=i;
275+
universal_catch=j;
276+
277+
// Universal handler. Highest on the stack takes
278+
// precedence, so overwrite any we've already seen:
279+
return stack_catch[i][j].second;
280+
}
281+
}
282+
}
283+
// Unless we have a universal exception handler, jump to end of function
284+
return goto_program.get_end_function();
285+
}
286+
232287
/// Emit the code:
233288
/// if (exception instanceof ExnA) then goto handlerA
234289
/// else if (exception instanceof ExnB) then goto handlerB
@@ -244,10 +299,6 @@ void remove_exceptionst::add_exception_dispatch_sequence(
244299
const remove_exceptionst::stack_catcht &stack_catch,
245300
const std::vector<exprt> &locals)
246301
{
247-
// Unless we have a universal exception handler, jump to end of function
248-
// if not caught:
249-
goto_programt::targett default_target=goto_program.get_end_function();
250-
251302
// Jump to the universal handler or function end, as appropriate.
252303
// This will appear after the GOTO-based dynamic dispatch below
253304
goto_programt::targett default_dispatch=goto_program.insert_after(instr_it);
@@ -259,21 +310,28 @@ void remove_exceptionst::add_exception_dispatch_sequence(
259310
symbol_exprt exc_thrown =
260311
get_inflight_exception_global();
261312

313+
std::size_t default_try=0;
314+
std::size_t default_catch=(!stack_catch.empty()) ? stack_catch[0].size() : 0;
315+
316+
goto_programt::targett default_target=
317+
find_universal_exception(stack_catch, goto_program,
318+
default_try, default_catch);
319+
262320
// add GOTOs implementing the dynamic dispatch of the
263-
// exception handlers
264-
for(std::size_t i=stack_catch.size(); i-->0;)
321+
// exception handlers.
322+
// The first loop is in forward order because the insertion reverses the order
323+
// we note that try1{ try2 {} catch2c {} catch2d {}} catch1a() {} catch1b{}
324+
// must catch in the following order: 2c 2d 1a 1b hence the numerical index
325+
// is reversed whereas the letter ordering remains the same.
326+
for(std::size_t i=default_try; i<stack_catch.size(); i++)
265327
{
266-
for(std::size_t j=stack_catch[i].size(); j-->0;)
328+
for(std::size_t j=(i==default_try) ? default_catch : stack_catch[i].size();
329+
j>0;)
267330
{
331+
j--;
268332
goto_programt::targett new_state_pc=
269333
stack_catch[i][j].second;
270-
if(stack_catch[i][j].first.empty())
271-
{
272-
// Universal handler. Highest on the stack takes
273-
// precedence, so overwrite any we've already seen:
274-
default_target=new_state_pc;
275-
}
276-
else
334+
if(!stack_catch[i][j].first.empty())
277335
{
278336
// Normal exception handler, make an instanceof check.
279337
goto_programt::targett t_exc=goto_program.insert_after(instr_it);

0 commit comments

Comments
 (0)