Skip to content

Commit 07acde4

Browse files
Refactor user-defined assertion translation for Java
Assertions in Java are "throw a;" statements where a is of type java.lang.AssertionError (an exception, or Throwable, to be precise). Sometimes we want to translate it into an ASSERT instruction in the goto program. Special-casing in order to handle that was scattered across multiple classes. In this commit we special-case it only once in the Java frontend and translate it into assert(false); assume(false); which is then correctly handled by later stages of the translation.
1 parent 04c0205 commit 07acde4

File tree

27 files changed

+88
-85
lines changed

27 files changed

+88
-85
lines changed

jbmc/regression/jbmc-strings/max-length/test1.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ Test.class
33
--refine-strings --verbosity 10 --string-max-input-length 499999 --function Test.checkMaxInputLength
44
^EXIT=0$
55
^SIGNAL=0$
6-
assertion.* line 9 function java::Test.checkMaxInputLength.* bytecode-index 16: SUCCESS
6+
assertion.* line 9 function java::Test.checkMaxInputLength.* bytecode-index 17: SUCCESS

jbmc/regression/jbmc-strings/max-length/test2.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ Test.class
33
--refine-strings --verbosity 10 --string-max-input-length 500000 --function Test.checkMaxInputLength
44
^EXIT=10$
55
^SIGNAL=0$
6-
assertion.* line 9 function java::Test.checkMaxInputLength.* bytecode-index 16: FAILURE
6+
assertion.* line 9 function java::Test.checkMaxInputLength.* bytecode-index 17: FAILURE

jbmc/regression/jbmc-strings/max-length/test3.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ Test.class
33
--refine-strings --verbosity 10 --string-max-length 4001 --function Test.checkMaxLength
44
^EXIT=10$
55
^SIGNAL=0$
6-
assertion.* line 25 function java::Test.checkMaxLength.* bytecode-index 26: FAILURE
6+
assertion.* line 25 function java::Test.checkMaxLength.* bytecode-index 27: FAILURE
300 Bytes
Binary file not shown.
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class Test
2+
{
3+
public static void main(String[] args)
4+
{
5+
AssertionError a = new AssertionError();
6+
if(false)
7+
throw a;
8+
}
9+
}
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
Test.class
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

jbmc/regression/jbmc/exceptions23/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ test.class
44
^EXIT=10$
55
^SIGNAL=0$
66
VERIFICATION FAILED
7-
assertion at file test\.java line 9 function java::test\.main:\(\)V bytecode-index 12: FAILURE
7+
assertion at file test\.java line 9 function java::test\.main:\(\)V bytecode-index 13: FAILURE
88
--
99
^warning: ignoring
1010
--

jbmc/regression/jbmc/exceptions24/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ test.class
44
^EXIT=10$
55
^SIGNAL=0$
66
VERIFICATION FAILED
7-
assertion at file test\.java line 9 function java::test\.main:\(\)V bytecode-index 10: FAILURE
7+
assertion at file test\.java line 9 function java::test\.main:\(\)V bytecode-index 11: FAILURE
88
--
99
^warning: ignoring
1010
--

jbmc/regression/jbmc/finally1/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ test.class
33
--function test.main
44
^EXIT=10$
55
^SIGNAL=0$
6-
assertion at file test\.java line 7 function java::test\.main:\(\)V bytecode-index 9: FAILURE
6+
assertion at file test\.java line 7 function java::test\.main:\(\)V bytecode-index 10: FAILURE
77
^VERIFICATION FAILED$
88
--
99
^warning: ignoring

jbmc/regression/jbmc/finally2/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ test.class
33
--function test.main
44
^EXIT=10$
55
^SIGNAL=0$
6-
assertion at file test\.java line 8 function java::test\.main:\(\)V bytecode-index 9: FAILURE
6+
assertion at file test\.java line 8 function java::test\.main:\(\)V bytecode-index 10: FAILURE
77
^VERIFICATION FAILED$
88
--
99
^warning: ignoring

jbmc/regression/jbmc/finally3/test.desc

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ test.class
33
--function test.main
44
^EXIT=10$
55
^SIGNAL=0$
6-
assertion at file test\.java line 7 function java::test\.main:\(\)V bytecode-index 9: SUCCESS
7-
assertion at file test\.java line 10 function java::test\.main:\(\)V bytecode-index 22: FAILURE
6+
assertion at file test\.java line 7 function java::test\.main:\(\)V bytecode-index 10: SUCCESS
7+
assertion at file test\.java line 10 function java::test\.main:\(\)V bytecode-index 23: FAILURE
88
^VERIFICATION FAILED$
99
--
1010
^warning: ignoring

jbmc/regression/jbmc/finally4/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ test.class
33
--function test.main
44
^EXIT=10$
55
^SIGNAL=0$
6-
assertion at file test\.java line 11 function java::test\.main:\(\)V bytecode-index 7: FAILURE
6+
assertion at file test\.java line 11 function java::test\.main:\(\)V bytecode-index 8: FAILURE
77
^VERIFICATION FAILED$
88
--
99
^warning: ignoring

jbmc/regression/jbmc/finally5/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ test.class
33
--function test.main
44
^EXIT=10$
55
^SIGNAL=0$
6-
assertion at file test\.java line 7 function java::test\.main:\(\)V bytecode-index 12: FAILURE
6+
assertion at file test\.java line 7 function java::test\.main:\(\)V bytecode-index 13: FAILURE
77
^VERIFICATION FAILED$
88
--
99
^warning: ignoring

jbmc/regression/jbmc/finally6/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ test.class
33
--function test.main
44
^EXIT=10$
55
^SIGNAL=0$
6-
assertion at file test\.java line 8 function java::test\.main:\(\)V bytecode-index 12: FAILURE
6+
assertion at file test\.java line 8 function java::test\.main:\(\)V bytecode-index 13: FAILURE
77
^VERIFICATION FAILED$
88
--
99
^warning: ignoring

jbmc/regression/jbmc/finally7/test.desc

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ test.class
33
--function test.main
44
^EXIT=10$
55
^SIGNAL=0$
6-
assertion at file test\.java line 7 function java::test\.main:\(\)V bytecode-index 12: SUCCESS
7-
assertion at file test\.java line 10 function java::test\.main:\(\)V bytecode-index 25: FAILURE
6+
assertion at file test\.java line 7 function java::test\.main:\(\)V bytecode-index 13: SUCCESS
7+
assertion at file test\.java line 10 function java::test\.main:\(\)V bytecode-index 26: FAILURE
88
^VERIFICATION FAILED$
99
--
1010
^warning: ignoring

jbmc/regression/jbmc/no-main-int-array-maybe-null1/test.desc

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ Main.class
44
^EXIT=10$
55
^SIGNAL=0$
66
^VERIFICATION FAILED$
7-
assertion at file Main\.java line 5 function .* bytecode-index 6: FAILURE
8-
assertion at file Main\.java line 6 function .* bytecode-index 14: FAILURE
9-
assertion at file Main\.java line 12 function .* bytecode-index 31: SUCCESS
7+
assertion at file Main\.java line 5 function .* bytecode-index 7: FAILURE
8+
assertion at file Main\.java line 6 function .* bytecode-index 15: FAILURE
9+
assertion at file Main\.java line 12 function .* bytecode-index 32: SUCCESS
1010
\*\* 2 of .* failed
1111
--
1212
^warning: ignoring

jbmc/regression/jbmc/no-main-multi-array-maybe-null1/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Main.class
44
^EXIT=10$
55
^SIGNAL=0$
66
^VERIFICATION FAILED$
7-
assertion at file Main\.java line 5 function .* bytecode-index 24: FAILURE
7+
assertion at file Main\.java line 5 function .* bytecode-index 25: FAILURE
88
\*\* 1 of .* failed
99
--
1010
^warning: ignoring

jbmc/regression/jbmc/no-main-multi-array-maybe-null2/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Main.class
44
^EXIT=10$
55
^SIGNAL=0$
66
^VERIFICATION FAILED$
7-
assertion at file Main\.java line 5 function .* bytecode-index 24: FAILURE
7+
assertion at file Main\.java line 5 function .* bytecode-index 25: FAILURE
88
\*\* 1 of .* failed
99
--
1010
^warning: ignoring

jbmc/regression/jbmc/no-main-object-array-elements-maybe-null1/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Main.class
44
^EXIT=10$
55
^SIGNAL=0$
66
^VERIFICATION FAILED$
7-
assertion at file Main\.java line 6 function .* bytecode-index 13: FAILURE
7+
assertion at file Main\.java line 6 function .* bytecode-index 14: FAILURE
88
\*\* 1 of .* failed
99
--
1010
^warning: ignoring

jbmc/regression/jbmc/no-main-object-array-elements-maybe-null2/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Main.class
44
^EXIT=10$
55
^SIGNAL=0$
66
^VERIFICATION FAILED$
7-
assertion at file Main\.java line 6 function .* bytecode-index 13: FAILURE
7+
assertion at file Main\.java line 6 function .* bytecode-index 14: FAILURE
88
\*\* 1 of .* failed
99
--
1010
^warning: ignoring

jbmc/regression/jbmc/no-main-object-array-maybe-null1/test.desc

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ Main.class
44
^EXIT=10$
55
^SIGNAL=0$
66
^VERIFICATION FAILED$
7-
assertion at file Main\.java line 10 function .* bytecode-index 6: FAILURE
8-
assertion at file Main\.java line 14 function .* bytecode-index 26: FAILURE
7+
assertion at file Main\.java line 10 function .* bytecode-index 7: FAILURE
8+
assertion at file Main\.java line 14 function .* bytecode-index 27: FAILURE
99
\*\* 2 of .* failed
1010
--
1111
^warning: ignoring

jbmc/regression/jbmc/no-main-object-array-maybe-null2/test.desc

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ Main.class
44
^EXIT=10$
55
^SIGNAL=0$
66
^VERIFICATION FAILED$
7-
assertion at file Main\.java line 10 function .* bytecode-index 6: FAILURE
8-
assertion at file Main\.java line 14 function .* bytecode-index 26: FAILURE
7+
assertion at file Main\.java line 10 function .* bytecode-index 7: FAILURE
8+
assertion at file Main\.java line 14 function .* bytecode-index 27: FAILURE
99
\*\* 2 of .* failed
1010
--
1111
^warning: ignoring

jbmc/src/java_bytecode/java_bytecode_convert_method.cpp

+36-4
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,14 @@ Author: Daniel Kroening, [email protected]
3232
#include <util/simplify_expr.h>
3333
#include <util/std_expr.h>
3434
#include <util/string2int.h>
35+
#include <util/string_constant.h>
3536

3637
#include <goto-programs/cfg.h>
3738
#include <goto-programs/class_hierarchy.h>
3839
#include <goto-programs/resolve_inherited_component.h>
40+
3941
#include <analyses/cfg_dominators.h>
42+
#include <analyses/uncaught_exceptions_analysis.h>
4043

4144
#include <limits>
4245
#include <algorithm>
@@ -2248,10 +2251,39 @@ void java_bytecode_convert_methodt::convert_athrow(
22482251
codet &c,
22492252
exprt::operandst &results) const
22502253
{
2251-
side_effect_expr_throwt throw_expr;
2252-
throw_expr.add_source_location() = location;
2253-
throw_expr.copy_to_operands(op[0]);
2254-
c = code_expressiont(throw_expr);
2254+
if(
2255+
uncaught_exceptions_domaint::get_exception_type(op[0].type()) ==
2256+
"java::java.lang.AssertionError")
2257+
{
2258+
// we translate athrow into
2259+
// ASSERT false;
2260+
// ASSUME false:
2261+
code_assertt assert_code;
2262+
assert_code.assertion() = false_exprt();
2263+
source_locationt assert_location = location; // copy
2264+
assert_location.set_comment("assertion at " + location.as_string());
2265+
assert_location.set("user-provided", true);
2266+
assert_location.set_property_class(ID_assertion);
2267+
assert_code.add_source_location() = assert_location;
2268+
2269+
code_assumet assume_code;
2270+
assume_code.assumption() = false_exprt();
2271+
source_locationt assume_location = location; // copy
2272+
assume_location.set("user-provided", true);
2273+
assume_code.add_source_location() = assume_location;
2274+
2275+
code_blockt ret_block;
2276+
ret_block.move_to_operands(assert_code);
2277+
ret_block.move_to_operands(assume_code);
2278+
c = ret_block;
2279+
}
2280+
else
2281+
{
2282+
side_effect_expr_throwt throw_expr;
2283+
throw_expr.add_source_location() = location;
2284+
throw_expr.copy_to_operands(op[0]);
2285+
c = code_expressiont(throw_expr);
2286+
}
22552287
results[0] = op[0];
22562288
}
22572289

jbmc/src/java_bytecode/java_bytecode_typecheck_expr.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ void java_bytecode_typecheckt::typecheck_expr_symbol(symbol_exprt &expr)
8181

8282
if(s_it==symbol_table.symbols.end())
8383
{
84-
PRECONDITION(has_prefix(id2string(identifier), "java::"));
84+
PRECONDITION(
85+
has_prefix(id2string(identifier), "java::") ||
86+
has_prefix(id2string(identifier), CPROVER_PREFIX));
8587

8688
// no, create the symbol
8789
symbolt new_symbol;

jbmc/src/java_bytecode/remove_exceptions.cpp

+1-16
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,7 @@ bool remove_exceptionst::function_or_callees_may_throw(
164164
{
165165
if(instr_it->is_throw())
166166
{
167-
const exprt &exc =
168-
uncaught_exceptions_domaint::get_exception_symbol(instr_it->code);
169-
bool is_assertion_error =
170-
id2string(uncaught_exceptions_domaint::get_exception_type(exc.type())).
171-
find("java.lang.AssertionError")!=std::string::npos;
172-
if(!is_assertion_error)
173-
return true;
167+
return true;
174168
}
175169

176170
if(instr_it->is_function_call())
@@ -380,15 +374,6 @@ bool remove_exceptionst::instrument_throw(
380374

381375
const exprt &exc_expr=
382376
uncaught_exceptions_domaint::get_exception_symbol(instr_it->code);
383-
bool assertion_error=id2string(
384-
uncaught_exceptions_domaint::get_exception_type(exc_expr.type())).
385-
find("java.lang.AssertionError")!=std::string::npos;
386-
387-
// we don't count AssertionError (we couldn't catch it anyway
388-
// and this may reduce the instrumentation considerably if the programmer
389-
// used assertions)
390-
if(assertion_error)
391-
return false;
392377

393378
add_exception_dispatch_sequence(
394379
goto_program, instr_it, stack_catch, locals);

src/analyses/uncaught_exceptions_analysis.cpp

+6-11
Original file line numberDiff line numberDiff line change
@@ -70,17 +70,12 @@ void uncaught_exceptions_domaint::transform(
7070
const exprt &exc_symbol=get_exception_symbol(instruction.code);
7171
// retrieve the static type of the thrown exception
7272
const irep_idt &type_id=get_exception_type(exc_symbol.type());
73-
bool assertion_error=
74-
id2string(type_id).find("java.lang.AssertionError")!=std::string::npos;
75-
if(!assertion_error)
76-
{
77-
join(type_id);
78-
// we must consider all the subtypes given that
79-
// the runtime type is a subtype of the static type
80-
std::vector<irep_idt> subtypes=
81-
class_hierarchy.get_children_trans(type_id);
82-
join(subtypes);
83-
}
73+
join(type_id);
74+
// we must consider all the subtypes given that
75+
// the runtime type is a subtype of the static type
76+
std::vector<irep_idt> subtypes =
77+
class_hierarchy.get_children_trans(type_id);
78+
join(subtypes);
8479
break;
8580
}
8681
case CATCH:

src/goto-programs/builtin_functions.cpp

-28
Original file line numberDiff line numberDiff line change
@@ -736,34 +736,6 @@ void goto_convertt::do_function_call_symbol(
736736
a->source_location=function.source_location();
737737
a->source_location.set("user-provided", true);
738738
}
739-
else if(has_prefix(
740-
id2string(identifier), "java::java.lang.AssertionError.<init>:"))
741-
{
742-
// insert function call anyway
743-
code_function_callt function_call;
744-
function_call.lhs()=lhs;
745-
function_call.function()=function;
746-
function_call.arguments()=arguments;
747-
function_call.add_source_location()=function.source_location();
748-
749-
copy(function_call, FUNCTION_CALL, dest);
750-
751-
if(arguments.size() != 1 && arguments.size() != 2 && arguments.size() != 3)
752-
{
753-
error().source_location=function.find_source_location();
754-
error() << "`" << identifier
755-
<< "' expected to have one, two or three arguments" << eom;
756-
throw 0;
757-
}
758-
759-
goto_programt::targett t=dest.add_instruction(ASSERT);
760-
t->guard=false_exprt();
761-
t->source_location=function.source_location();
762-
t->source_location.set("user-provided", true);
763-
t->source_location.set_property_class(ID_assertion);
764-
t->source_location.set_comment(
765-
"assertion at "+function.source_location().as_string());
766-
}
767739
else if(identifier=="assert" &&
768740
!ns.lookup(identifier).location.get_function().empty())
769741
{

0 commit comments

Comments
 (0)