Skip to content

Commit b4262f3

Browse files
committed
Always allocate an exception object at throw site
Previously we could erroneously fail to initialise the object on second and subsequent exception throw-sites in a particular function, and so throw a nondet object rather than an initialised exception instance. The attached test case checks for this by ensuring that in particular we can't throw null and so hit an assertion when trying to read its class-identifier for catch dispatch. This commit also fixes the classid of ClassCastException, which would otherwise expose a failure in test ClassCastException1
1 parent bbae82d commit b4262f3

File tree

4 files changed

+63
-29
lines changed

4 files changed

+63
-29
lines changed
445 Bytes
Binary file not shown.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
test.class
3+
--function test.f --java-throw-runtime-exceptions
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
VERIFICATION SUCCESSFUL
7+
--
8+
reference is null in .*: FAILURE
9+
--
10+
This checks that the second use of a particular exception type in a given function is correctly initialised.
11+
In the failing case the #exception_value variable is nondet at the time it is thrown, so cbmc can set it to null and fail an assertion.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
public class test {
2+
3+
int field;
4+
5+
public static void f() {
6+
7+
test testinstance = new test();
8+
test testnull = null;
9+
int x = 0;
10+
try {
11+
x = testinstance.field;
12+
}
13+
catch(NullPointerException e) {
14+
x++;
15+
}
16+
try {
17+
x = testnull.field;
18+
}
19+
catch(NullPointerException e) {
20+
x++;
21+
}
22+
}
23+
24+
}

src/java_bytecode/java_bytecode_instrument.cpp

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Date: June 2017
99
\*******************************************************************/
1010

1111
#include <util/arith_tools.h>
12+
#include <util/fresh_symbol.h>
1213
#include <util/std_code.h>
1314
#include <util/std_expr.h>
1415
#include <util/symbol_table.h>
@@ -18,7 +19,6 @@ Date: June 2017
1819
#include "java_bytecode_convert_class.h"
1920
#include "java_bytecode_instrument.h"
2021
#include "java_entry_point.h"
21-
#include "java_object_factory.h"
2222
#include "java_root_class.h"
2323
#include "java_types.h"
2424
#include "java_utils.h"
@@ -90,47 +90,46 @@ codet java_bytecode_instrumentt::throw_exception(
9090
const source_locationt &original_loc,
9191
const irep_idt &exc_name)
9292
{
93-
exprt exc;
94-
code_blockt init_code;
95-
const irep_idt &exc_obj_name=
96-
id2string(goto_functionst::entry_point())+
97-
"::"+id2string(exc_name);
93+
irep_idt exc_class_name("java::"+id2string(exc_name));
9894

99-
if(!symbol_table.has_symbol(exc_obj_name))
95+
if(!symbol_table.has_symbol(exc_class_name))
10096
{
10197
generate_class_stub(
10298
exc_name,
10399
symbol_table,
104100
get_message_handler());
105-
const symbolt &exc_symbol=symbol_table.lookup(
106-
"java::"+id2string(exc_name));
107-
108-
// create the exception object
109-
exc=object_factory(
110-
pointer_typet(exc_symbol.type),
111-
exc_name,
112-
init_code,
113-
false,
114-
symbol_table,
115-
max_array_length,
116-
allocation_typet::LOCAL,
117-
original_loc);
118101
}
119-
else
120-
exc=symbol_table.lookup(exc_obj_name).symbol_expr();
102+
103+
pointer_typet exc_ptr_type;
104+
exc_ptr_type.subtype()=symbol_typet(exc_class_name);
105+
106+
// Allocate and throw an instance of the exception class:
107+
108+
symbolt &new_symbol=
109+
get_fresh_aux_symbol(
110+
exc_ptr_type,
111+
"new_exception",
112+
"new_exception",
113+
original_loc,
114+
ID_java,
115+
symbol_table);
116+
117+
side_effect_exprt new_instance(ID_java_new, exc_ptr_type);
118+
code_assignt assign_new(new_symbol.symbol_expr(), new_instance);
121119

122120
side_effect_expr_throwt throw_expr;
123-
throw_expr.add_source_location()=original_loc;
124-
throw_expr.move_to_operands(exc);
121+
throw_expr.copy_to_operands(new_symbol.symbol_expr());
122+
123+
code_blockt throw_code;
124+
throw_code.move_to_operands(assign_new);
125+
throw_code.copy_to_operands(code_expressiont(throw_expr));
125126

126127
code_ifthenelset if_code;
127128
if_code.add_source_location()=original_loc;
128129
if_code.cond()=cond;
129-
if_code.then_case()=code_expressiont(throw_expr);
130-
131-
init_code.move_to_operands(if_code);
130+
if_code.then_case()=throw_code;
132131

133-
return init_code;
132+
return if_code;
134133
}
135134

136135
/// Checks whether the array access array_struct[idx] is out-of-bounds,
@@ -209,7 +208,7 @@ codet java_bytecode_instrumentt::check_class_cast(
209208
throw_exception(
210209
not_exprt(class_cast_check),
211210
original_loc,
212-
"ClassCastException");
211+
"java.lang.ClassCastException");
213212
}
214213
else
215214
{

0 commit comments

Comments
 (0)