diff --git a/regression/cbmc-java/ArithmeticException1/ArithmeticExceptionTest.class b/regression/cbmc-java/ArithmeticException1/ArithmeticExceptionTest.class new file mode 100644 index 00000000000..3ad4e6ebe86 Binary files /dev/null and b/regression/cbmc-java/ArithmeticException1/ArithmeticExceptionTest.class differ diff --git a/regression/cbmc-java/ArithmeticException1/ArithmeticExceptionTest.java b/regression/cbmc-java/ArithmeticException1/ArithmeticExceptionTest.java new file mode 100644 index 00000000000..7988e85700e --- /dev/null +++ b/regression/cbmc-java/ArithmeticException1/ArithmeticExceptionTest.java @@ -0,0 +1,11 @@ +public class ArithmeticExceptionTest { + public static void main(String args[]) { + try { + int i=0; + int j=10/i; + } + catch(ArithmeticException exc) { + assert false; + } + } +} diff --git a/regression/cbmc-java/ArithmeticException1/test.desc b/regression/cbmc-java/ArithmeticException1/test.desc new file mode 100644 index 00000000000..e8f7c941fd4 --- /dev/null +++ b/regression/cbmc-java/ArithmeticException1/test.desc @@ -0,0 +1,9 @@ +CORE +ArithmeticExceptionTest.class +--java-throw-runtime-exceptions +^EXIT=10$ +^SIGNAL=0$ +^.*assertion at file ArithmeticExceptionTest.java line 8 function.*: FAILURE$ +^VERIFICATION FAILED +-- +^warning: ignoring diff --git a/src/java_bytecode/java_bytecode_convert_method.cpp b/src/java_bytecode/java_bytecode_convert_method.cpp index 4ae7c72ed69..967b3cc239f 100644 --- a/src/java_bytecode/java_bytecode_convert_method.cpp +++ b/src/java_bytecode/java_bytecode_convert_method.cpp @@ -1051,6 +1051,7 @@ codet java_bytecode_convert_methodt::convert_instructions( i_it->statement=="checkcast" || i_it->statement=="newarray" || i_it->statement=="anewarray" || + i_it->statement==patternt("?div") || i_it->statement==patternt("?astore") || i_it->statement==patternt("?aload") || i_it->statement=="invokestatic" || diff --git a/src/java_bytecode/java_bytecode_instrument.cpp b/src/java_bytecode/java_bytecode_instrument.cpp index b41e1e73baf..35ea54e9cbd 100644 --- a/src/java_bytecode/java_bytecode_instrument.cpp +++ b/src/java_bytecode/java_bytecode_instrument.cpp @@ -57,6 +57,10 @@ class java_bytecode_instrumentt:public messaget const exprt &idx, const source_locationt &original_loc); + codet check_arithmetic_exception( + const exprt &denominator, + const source_locationt &original_loc); + codet check_null_dereference( const exprt &expr, const source_locationt &original_loc, @@ -132,6 +136,32 @@ codet java_bytecode_instrumentt::throw_exception( return init_code; } + +/// Checks whether there is a division by zero +/// and throws ArithmeticException if necessary. +/// Exceptions are thrown when the `throw_runtime_exceptions` +/// flag is set. +/// \return Based on the value of the flag `throw_runtime_exceptions`, +/// it returns code that either throws an ArithmeticException +/// or is a skip +codet java_bytecode_instrumentt::check_arithmetic_exception( + const exprt &denominator, + const source_locationt &original_loc) +{ + symbolt exc_symbol; + + const constant_exprt &zero=from_integer(0, denominator.type()); + const binary_relation_exprt equal_zero(denominator, ID_equal, zero); + + if(throw_runtime_exceptions) + return throw_exception( + equal_zero, + original_loc, + "java.lang.ArithmeticException"); + + return code_skipt(); +} + /// Checks whether the array access array_struct[idx] is out-of-bounds, /// and throws ArrayIndexOutofBoundsException/generates an assertion /// if necessary; Exceptions are thrown when the `throw_runtime_exceptions` @@ -463,6 +493,13 @@ codet java_bytecode_instrumentt::instrument_expr( expr.op0(), expr.source_location()); } + else if(expr.id()==ID_div) + { + // check division by zero + return check_arithmetic_exception( + expr.op1(), + expr.source_location()); + } else if(expr.id()==ID_member && expr.get_bool(ID_java_member_access)) {