Skip to content

Commit 49207dd

Browse files
Enable propagation of AssertionError
Introduces --propagate-assertion-error which allows to propgate AssertionError as performed in the JVM rather than using a goto ASSERT statement.
1 parent 08fd020 commit 49207dd

10 files changed

+95
-17
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
assert3.class
3+
--propagate-assertion-error
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
^\[.*\] no uncaught exception: FAILURE$
8+
--
9+
^warning: ignoring
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
assert3.class
3+
--propagate-assertion-error --no-uncaught-exception-check
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

jbmc/src/janalyzer/janalyzer_parse_options.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ bool janalyzer_parse_optionst::process_goto_program(const optionst &options)
670670
remove_virtual_functions(goto_model);
671671
// remove Java throw and catch
672672
// This introduces instanceof, so order is important:
673-
remove_exceptions(goto_model);
673+
remove_exceptions(goto_model, cmdline.isset("propagate-assertion-error"));
674674
// remove rtti
675675
remove_instanceof(goto_model);
676676

jbmc/src/java_bytecode/java_bytecode_language.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Author: Daniel Kroening, [email protected]
2929
// clang-format off
3030
#define JAVA_BYTECODE_LANGUAGE_OPTIONS /*NOLINT*/ \
3131
"(no-uncaught-exception-check)" \
32+
"(propagate-assertion-error)" \
3233
"(java-assume-inputs-non-null)" \
3334
"(java-throw-runtime-exceptions)" \
3435
"(java-max-input-array-length):" \
@@ -42,6 +43,7 @@ Author: Daniel Kroening, [email protected]
4243

4344
#define JAVA_BYTECODE_LANGUAGE_OPTIONS_HELP /*NOLINT*/ \
4445
" --no-uncaught-exception-check ignore uncaught exceptions and errors\n" \
46+
" --propagate-assertion-error propagate java.lang.AssertionError as exception\n" \
4547
" --java-assume-inputs-non-null never initialize reference-typed parameter to the\n" /* NOLINT(*) */ \
4648
" entry point with null\n" /* NOLINT(*) */ \
4749
" --java-throw-runtime-exceptions make implicit runtime exceptions explicit\n" /* NOLINT(*) */ \

jbmc/src/java_bytecode/remove_exceptions.cpp

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,11 @@ class remove_exceptionst
8888
explicit remove_exceptionst(
8989
symbol_table_baset &_symbol_table,
9090
function_may_throwt _function_may_throw,
91+
bool propagate_assertion_error,
9192
bool remove_added_instanceof)
9293
: symbol_table(_symbol_table),
9394
function_may_throw(_function_may_throw),
95+
propagate_assertion_error(propagate_assertion_error),
9496
remove_added_instanceof(remove_added_instanceof)
9597
{
9698
}
@@ -101,6 +103,7 @@ class remove_exceptionst
101103
protected:
102104
symbol_table_baset &symbol_table;
103105
function_may_throwt function_may_throw;
106+
bool propagate_assertion_error;
104107
bool remove_added_instanceof;
105108

106109
symbol_exprt get_inflight_exception_global();
@@ -164,6 +167,9 @@ bool remove_exceptionst::function_or_callees_may_throw(
164167
{
165168
if(instr_it->is_throw())
166169
{
170+
if(propagate_assertion_error)
171+
return true;
172+
167173
const exprt &exc =
168174
uncaught_exceptions_domaint::get_exception_symbol(instr_it->code);
169175
bool is_assertion_error =
@@ -385,10 +391,10 @@ bool remove_exceptionst::instrument_throw(
385391
uncaught_exceptions_domaint::get_exception_type(exc_expr.type())).
386392
find("java.lang.AssertionError")!=std::string::npos;
387393

388-
// we don't count AssertionError (we couldn't catch it anyway
389-
// and this may reduce the instrumentation considerably if the programmer
390-
// used assertions)
391-
if(assertion_error)
394+
// we allow AssertionError not to be propagated since
395+
// this may reduce the instrumentation considerably if the programmer
396+
// used assertions
397+
if(assertion_error && !propagate_assertion_error)
392398
return false;
393399

394400
add_exception_dispatch_sequence(
@@ -472,7 +478,21 @@ void remove_exceptionst::instrument_exceptions(
472478

473479
Forall_goto_program_instructions(instr_it, goto_program)
474480
{
475-
if(instr_it->is_decl())
481+
if(instr_it->is_assert())
482+
{
483+
if(propagate_assertion_error)
484+
{
485+
// suppress user-provided assertion
486+
// because we propgate the AssertionError
487+
if(
488+
instr_it->guard.is_false() &&
489+
instr_it->source_location.get_bool("user-provided"))
490+
{
491+
instr_it->make_skip();
492+
}
493+
}
494+
}
495+
else if(instr_it->is_decl())
476496
{
477497
code_declt decl=to_code_decl(instr_it->code);
478498
locals.push_back(decl.symbol());
@@ -580,18 +600,21 @@ void remove_exceptionst::operator()(goto_programt &goto_program)
580600
void remove_exceptions(
581601
symbol_table_baset &symbol_table,
582602
goto_functionst &goto_functions,
603+
bool propagate_assertion_error,
583604
remove_exceptions_typest type)
584605
{
585606
const namespacet ns(symbol_table);
586607
std::map<irep_idt, std::set<irep_idt>> exceptions_map;
587-
uncaught_exceptions(goto_functions, ns, exceptions_map);
608+
uncaught_exceptions(
609+
goto_functions, ns, propagate_assertion_error, exceptions_map);
588610
remove_exceptionst::function_may_throwt function_may_throw =
589611
[&exceptions_map](const irep_idt &id) {
590612
return !exceptions_map[id].empty();
591613
};
592614
remove_exceptionst remove_exceptions(
593615
symbol_table,
594616
function_may_throw,
617+
propagate_assertion_error,
595618
type == remove_exceptions_typest::REMOVE_ADDED_INSTANCEOF);
596619
remove_exceptions(goto_functions);
597620
}
@@ -612,6 +635,7 @@ void remove_exceptions(
612635
void remove_exceptions(
613636
goto_programt &goto_program,
614637
symbol_table_baset &symbol_table,
638+
bool propagate_assertion_error,
615639
remove_exceptions_typest type)
616640
{
617641
remove_exceptionst::function_may_throwt any_function_may_throw =
@@ -620,12 +644,20 @@ void remove_exceptions(
620644
remove_exceptionst remove_exceptions(
621645
symbol_table,
622646
any_function_may_throw,
647+
propagate_assertion_error,
623648
type == remove_exceptions_typest::REMOVE_ADDED_INSTANCEOF);
624649
remove_exceptions(goto_program);
625650
}
626651

627652
/// removes throws/CATCH-POP/CATCH-PUSH
628-
void remove_exceptions(goto_modelt &goto_model, remove_exceptions_typest type)
653+
void remove_exceptions(
654+
goto_modelt &goto_model,
655+
bool propagate_assertion_error,
656+
remove_exceptions_typest type)
629657
{
630-
remove_exceptions(goto_model.symbol_table, goto_model.goto_functions, type);
658+
remove_exceptions(
659+
goto_model.symbol_table,
660+
goto_model.goto_functions,
661+
propagate_assertion_error,
662+
type);
631663
}

jbmc/src/java_bytecode/remove_exceptions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@ enum class remove_exceptions_typest
3232
void remove_exceptions(
3333
goto_programt &goto_program,
3434
symbol_table_baset &symbol_table,
35+
bool propagate_assertion_error,
3536
remove_exceptions_typest type =
3637
remove_exceptions_typest::DONT_REMOVE_INSTANCEOF);
3738

3839
void remove_exceptions(
3940
goto_modelt &goto_model,
41+
bool propagate_assertion_error,
4042
remove_exceptions_typest type =
4143
remove_exceptions_typest::DONT_REMOVE_INSTANCEOF);
4244

jbmc/src/jbmc/jbmc_parse_options.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,11 @@ void jbmc_parse_optionst::get_command_line_options(optionst &options)
382382

383383
PARSE_OPTIONS_GOTO_TRACE(cmdline, options);
384384

385+
if(cmdline.isset("propagate-assertion-error"))
386+
options.set_option("propagate-assertion-error", true);
387+
else
388+
options.set_option("propagate-assertion-error", false);
389+
385390
if(cmdline.isset("symex-driven-lazy-loading"))
386391
{
387392
options.set_option("symex-driven-lazy-loading", true);
@@ -743,6 +748,8 @@ void jbmc_parse_optionst::process_goto_function(
743748

744749
bool using_symex_driven_loading =
745750
options.get_bool_option("symex-driven-lazy-loading");
751+
bool propagate_assertion_error =
752+
options.get_bool_option("propagate-assertion-error");
746753

747754
try
748755
{
@@ -761,6 +768,7 @@ void jbmc_parse_optionst::process_goto_function(
761768
remove_exceptions(
762769
goto_function.body,
763770
symbol_table,
771+
propagate_assertion_error,
764772
remove_exceptions_typest::REMOVE_ADDED_INSTANCEOF);
765773
}
766774

@@ -899,6 +907,8 @@ bool jbmc_parse_optionst::process_goto_functions(
899907

900908
bool using_symex_driven_loading =
901909
options.get_bool_option("symex-driven-lazy-loading");
910+
bool propagate_assertion_error =
911+
options.get_bool_option("propagate-assertion-error");
902912

903913
// When using symex-driven lazy loading, *all* relevant processing is done
904914
// during process_goto_function, so we have nothing to do here.
@@ -908,7 +918,9 @@ bool jbmc_parse_optionst::process_goto_functions(
908918
// remove catch and throw
909919
// (introduces instanceof but request it is removed)
910920
remove_exceptions(
911-
goto_model, remove_exceptions_typest::REMOVE_ADDED_INSTANCEOF);
921+
goto_model,
922+
propagate_assertion_error,
923+
remove_exceptions_typest::REMOVE_ADDED_INSTANCEOF);
912924

913925
// instrument library preconditions
914926
instrument_preconditions(goto_model);

jbmc/src/jdiff/jdiff_parse_options.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ bool jdiff_parse_optionst::process_goto_program(
346346
// Java virtual functions -> explicit dispatch tables:
347347
remove_virtual_functions(goto_model);
348348
// remove catch and throw
349-
remove_exceptions(goto_model);
349+
remove_exceptions(goto_model, cmdline.isset("propagate-assertion-error"));
350350
// Java instanceof -> clsid comparison:
351351
remove_instanceof(goto_model);
352352

src/analyses/uncaught_exceptions_analysis.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ void uncaught_exceptions_domaint::transform(
7272
const irep_idt &type_id=get_exception_type(exc_symbol.type());
7373
bool assertion_error=
7474
id2string(type_id).find("java.lang.AssertionError")!=std::string::npos;
75-
if(!assertion_error)
75+
if(!assertion_error || propagate_assertion_error)
7676
{
7777
join(type_id);
7878
// we must consider all the subtypes given that
@@ -227,8 +227,9 @@ void uncaught_exceptions_analysist::operator()(
227227
void uncaught_exceptions(
228228
const goto_functionst &goto_functions,
229229
const namespacet &ns,
230+
bool propagate_assertion_error,
230231
std::map<irep_idt, std::set<irep_idt>> &exceptions_map)
231232
{
232-
uncaught_exceptions_analysist exceptions;
233+
uncaught_exceptions_analysist exceptions(propagate_assertion_error);
233234
exceptions(goto_functions, ns, exceptions_map);
234235
}

src/analyses/uncaught_exceptions_analysis.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@ class uncaught_exceptions_analysist;
2323

2424
class uncaught_exceptions_domaint
2525
{
26-
public:
26+
public:
27+
explicit uncaught_exceptions_domaint(bool propagate_assertion_error)
28+
: propagate_assertion_error(propagate_assertion_error)
29+
{
30+
}
31+
2732
void transform(const goto_programt::const_targett,
2833
uncaught_exceptions_analysist &,
2934
const namespacet &);
@@ -46,18 +51,24 @@ class uncaught_exceptions_domaint
4651

4752
void operator()(const namespacet &ns);
4853

49-
private:
54+
private:
55+
const bool propagate_assertion_error;
5056
typedef std::vector<std::set<irep_idt>> stack_caughtt;
5157
stack_caughtt stack_caught;
5258
std::set<irep_idt> thrown;
5359
class_hierarchyt class_hierarchy;
5460
};
5561

56-
/// computes in exceptions_map an overapproximation of the exceptions thrown by
62+
/// computes in exceptions_map an overapproximation of the exceptions thrown by
5763
/// each method
5864
class uncaught_exceptions_analysist
5965
{
6066
public:
67+
explicit uncaught_exceptions_analysist(bool propagate_assertion_error)
68+
: domain(propagate_assertion_error)
69+
{
70+
}
71+
6172
typedef std::map<irep_idt, std::set<irep_idt>> exceptions_mapt;
6273

6374
void collect_uncaught_exceptions(
@@ -73,14 +84,15 @@ class uncaught_exceptions_analysist
7384

7485
friend class uncaught_exceptions_domaint;
7586

76-
private:
87+
private:
7788
uncaught_exceptions_domaint domain;
7889
exceptions_mapt exceptions_map;
7990
};
8091

8192
void uncaught_exceptions(
8293
const goto_functionst &,
8394
const namespacet &,
95+
bool propagate_assertion_error,
8496
std::map<irep_idt, std::set<irep_idt>> &);
8597

8698
#endif

0 commit comments

Comments
 (0)