Skip to content

Commit 961c0a3

Browse files
Refactoring the runtime exception instrumentation out of java_bytecode_convert
Now the instrumentation for runtime exceptions is added in an independent pass (as described in java_bytecode_instrument.cpp), between the bytecode conversion and typechecking.
1 parent 72677f2 commit 961c0a3

13 files changed

+577
-91
lines changed

src/cbmc/cbmc_parse_options.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,6 +1070,7 @@ void cbmc_parse_optionst::help()
10701070
// NOLINTNEXTLINE(whitespace/line_length)
10711071
" --java-max-vla-length limit the length of user-code-created arrays\n"
10721072
// NOLINTNEXTLINE(whitespace/line_length)
1073+
" --java-throw-runtime-exceptions Make implicit runtime exceptions explicit"
10731074
" --java-cp-include-files regexp or JSON list of files to load (with '@' prefix)\n"
10741075
" --java-unwind-enum-static try to unwind loops in static initialization of enums\n"
10751076
"\n"

src/cbmc/cbmc_parse_options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class optionst;
6565
"(graphml-witness):" \
6666
"(java-max-vla-length):(java-unwind-enum-static)" \
6767
"(java-cp-include-files):" \
68+
"(java-throw-runtime-exceptions)" \
6869
"(localize-faults)(localize-faults-method):" \
6970
"(lazy-methods)" \
7071
"(test-invariant-failure)" \

src/java_bytecode/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ SRC = bytecode_info.cpp \
1616
java_class_loader.cpp \
1717
java_class_loader_limit.cpp \
1818
java_entry_point.cpp \
19+
java_bytecode_instrument.cpp \
1920
java_local_variable_table.cpp \
2021
java_object_factory.cpp \
2122
java_pointer_casts.cpp \

src/java_bytecode/java_bytecode_convert_method.cpp

Lines changed: 16 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -509,39 +509,14 @@ static member_exprt to_member(const exprt &pointer, const exprt &fieldref)
509509

510510
const dereference_exprt obj_deref(pointer2, class_type);
511511

512-
return member_exprt(
512+
member_exprt member_expr(
513513
obj_deref,
514514
fieldref.get(ID_component_name),
515515
fieldref.type());
516-
}
517516

518-
codet java_bytecode_convert_methodt::get_array_bounds_check(
519-
const exprt &arraystruct,
520-
const exprt &idx,
521-
const source_locationt &original_sloc)
522-
{
523-
constant_exprt intzero=from_integer(0, java_int_type());
524-
binary_relation_exprt gezero(idx, ID_ge, intzero);
525-
const member_exprt length_field(arraystruct, "length", java_int_type());
526-
binary_relation_exprt ltlength(idx, ID_lt, length_field);
527-
code_blockt bounds_checks;
528-
529-
bounds_checks.add(code_assertt(gezero));
530-
bounds_checks.operands().back().add_source_location()=original_sloc;
531-
bounds_checks.operands().back().add_source_location()
532-
.set_comment("Array index < 0");
533-
bounds_checks.operands().back().add_source_location()
534-
.set_property_class("array-index-out-of-bounds-low");
535-
bounds_checks.add(code_assertt(ltlength));
536-
537-
bounds_checks.operands().back().add_source_location()=original_sloc;
538-
bounds_checks.operands().back().add_source_location()
539-
.set_comment("Array index >= length");
540-
bounds_checks.operands().back().add_source_location()
541-
.set_property_class("array-index-out-of-bounds-high");
542-
543-
// TODO make this throw ArrayIndexOutOfBoundsException instead of asserting.
544-
return bounds_checks;
517+
// tag it so it's easy to identify during instrumentation
518+
member_expr.set(ID_java_member_access, true);
519+
return member_expr;
545520
}
546521

547522
/// Find all goto statements in 'repl' that target 'old_label' and redirect them
@@ -1256,50 +1231,26 @@ codet java_bytecode_convert_methodt::convert_instructions(
12561231
else if(statement=="athrow")
12571232
{
12581233
assert(op.size()==1 && results.size()==1);
1259-
code_blockt block;
1260-
// TODO throw NullPointerException instead
1261-
const typecast_exprt lhs(op[0], pointer_typet(empty_typet()));
1262-
const exprt rhs(null_pointer_exprt(to_pointer_type(lhs.type())));
1263-
const exprt not_equal_null(
1264-
binary_relation_exprt(lhs, ID_notequal, rhs));
1265-
code_assertt check(not_equal_null);
1266-
check.add_source_location()
1267-
.set_comment("Throw null");
1268-
check.add_source_location()
1269-
.set_property_class("null-pointer-exception");
1270-
block.move_to_operands(check);
12711234

12721235
side_effect_expr_throwt throw_expr;
12731236
throw_expr.add_source_location()=i_it->source_location;
12741237
throw_expr.copy_to_operands(op[0]);
12751238
c=code_expressiont(throw_expr);
12761239
results[0]=op[0];
1277-
1278-
block.move_to_operands(c);
1279-
c=block;
12801240
}
12811241
else if(statement=="checkcast")
12821242
{
12831243
// checkcast throws an exception in case a cast of object
12841244
// on stack to given type fails.
12851245
// The stack isn't modified.
1286-
// TODO: convert assertions to exceptions.
12871246
assert(op.size()==1 && results.size()==1);
12881247
binary_predicate_exprt check(op[0], ID_java_instanceof, arg0);
12891248
code_assertt assert_class(check);
12901249
assert_class.add_source_location().set_comment("Dynamic cast check");
12911250
assert_class.add_source_location().set_property_class("bad-dynamic-cast");
1292-
// checkcast passes when the operand is null.
1293-
empty_typet voidt;
1294-
pointer_typet voidptr(voidt);
1295-
exprt null_check_op=op[0];
1296-
if(null_check_op.type()!=voidptr)
1297-
null_check_op.make_typecast(voidptr);
1298-
code_ifthenelset conditional_check;
1299-
notequal_exprt op_not_null(null_check_op, null_pointer_exprt(voidptr));
1300-
conditional_check.cond()=std::move(op_not_null);
1301-
conditional_check.then_case()=std::move(assert_class);
1302-
c=std::move(conditional_check);
1251+
// we add this assert such that we can recognise it
1252+
// during the instrumentation phase
1253+
c=std::move(assert_class);
13031254
results[0]=op[0];
13041255
}
13051256
else if(statement=="invokedynamic")
@@ -1525,17 +1476,12 @@ codet java_bytecode_convert_methodt::convert_instructions(
15251476
pointer_typet(java_type_from_char(type_char)));
15261477

15271478
plus_exprt data_plus_offset(data_ptr, op[1], data_ptr.type());
1479+
// tag it so it's easy to identify during instrumentation
1480+
data_plus_offset.set(ID_java_array_access, true);
15281481
typet element_type=data_ptr.type().subtype();
15291482
const dereference_exprt element(data_plus_offset, element_type);
15301483

1531-
c=code_blockt();
1532-
codet bounds_check=
1533-
get_array_bounds_check(deref, op[1], i_it->source_location);
1534-
bounds_check.add_source_location()=i_it->source_location;
1535-
c.move_to_operands(bounds_check);
1536-
code_assignt array_put(element, op[2]);
1537-
array_put.add_source_location()=i_it->source_location;
1538-
c.move_to_operands(array_put);
1484+
c=code_assignt(element, op[2]);
15391485
c.add_source_location()=i_it->source_location;
15401486
}
15411487
else if(statement==patternt("?store"))
@@ -1569,11 +1515,10 @@ codet java_bytecode_convert_methodt::convert_instructions(
15691515
pointer_typet(java_type_from_char(type_char)));
15701516

15711517
plus_exprt data_plus_offset(data_ptr, op[1], data_ptr.type());
1518+
// tag it so it's easy to identify during instrumentation
1519+
data_plus_offset.set(ID_java_array_access, true);
15721520
typet element_type=data_ptr.type().subtype();
15731521
dereference_exprt element(data_plus_offset, element_type);
1574-
1575-
c=get_array_bounds_check(deref, op[1], i_it->source_location);
1576-
c.add_source_location()=i_it->source_location;
15771522
results[0]=java_bytecode_promotion(element);
15781523
}
15791524
else if(statement==patternt("?load"))
@@ -2136,14 +2081,6 @@ codet java_bytecode_convert_methodt::convert_instructions(
21362081
java_new_array.add_source_location()=i_it->source_location;
21372082

21382083
c=code_blockt();
2139-
// TODO make this throw NegativeArrayIndexException instead.
2140-
constant_exprt intzero=from_integer(0, java_int_type());
2141-
binary_relation_exprt gezero(op[0], ID_ge, intzero);
2142-
code_assertt check(gezero);
2143-
check.add_source_location().set_comment("Array size < 0");
2144-
check.add_source_location()
2145-
.set_property_class("array-create-negative-size");
2146-
c.move_to_operands(check);
21472084

21482085
if(max_array_length!=0)
21492086
{
@@ -2175,27 +2112,20 @@ codet java_bytecode_convert_methodt::convert_instructions(
21752112
if(!i_it->source_location.get_line().empty())
21762113
java_new_array.add_source_location()=i_it->source_location;
21772114

2178-
code_blockt checkandcreate;
2179-
// TODO make this throw NegativeArrayIndexException instead.
2180-
constant_exprt intzero=from_integer(0, java_int_type());
2181-
binary_relation_exprt gezero(op[0], ID_ge, intzero);
2182-
code_assertt check(gezero);
2183-
check.add_source_location().set_comment("Array size < 0");
2184-
check.add_source_location()
2185-
.set_property_class("array-create-negative-size");
2186-
checkandcreate.move_to_operands(check);
2115+
code_blockt create;
21872116

21882117
if(max_array_length!=0)
21892118
{
21902119
constant_exprt size_limit=
21912120
from_integer(max_array_length, java_int_type());
21922121
binary_relation_exprt le_max_size(op[0], ID_le, size_limit);
21932122
code_assumet assume_le_max_size(le_max_size);
2194-
checkandcreate.move_to_operands(assume_le_max_size);
2123+
create.move_to_operands(assume_le_max_size);
21952124
}
21962125

21972126
const exprt tmp=tmp_variable("newarray", ref_type);
2198-
c=code_assignt(tmp, java_new_array);
2127+
create.copy_to_operands(code_assignt(tmp, java_new_array));
2128+
c=std::move(create);
21992129
results[0]=tmp;
22002130
}
22012131
else if(statement=="arraylength")

src/java_bytecode/java_bytecode_convert_method_class.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,6 @@ class java_bytecode_convert_methodt:public messaget
123123
INST_INDEX_CONST=3
124124
};
125125

126-
codet get_array_bounds_check(
127-
const exprt &arraystruct,
128-
const exprt &idx,
129-
const source_locationt &original_sloc);
130-
131126
// return corresponding reference of variable
132127
const variablet &find_variable_for_slot(
133128
size_t address,

0 commit comments

Comments
 (0)