Skip to content

Commit

Permalink
Add org.cprover.MustNotThrow method attribute
Browse files Browse the repository at this point in the history
This asserts that a particular method must not throw exceptions, intended for use with
internal methods such as cproverNondetInitialize, which must not propagate exceptions to
their callsite. In such a case, instead of an exception dispatch table we introduce an
assumption checking one was not in fact thrown.
  • Loading branch information
smowton committed Jun 12, 2018
1 parent 774060b commit ab60852
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 10 deletions.
Binary file not shown.
17 changes: 17 additions & 0 deletions jbmc/regression/jbmc/must-not-throw-annotation/Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
public class Test {

@org.cprover.MustNotThrow
public static void mustNotThrow() {
throw new RuntimeException("Oh dear");
}

public static void main() {
try {
mustNotThrow();
}
catch(Throwable e) {
assert false;
}
}

}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package org.cprover;

public @interface MustNotThrow { }
8 changes: 8 additions & 0 deletions jbmc/regression/jbmc/must-not-throw-annotation/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CORE
Test.class
--function Test.main
^EXIT=0$
^SIGNAL=0$
^VERIFICATION SUCCESSFUL$
--
^warning: ignoring
7 changes: 7 additions & 0 deletions jbmc/src/java_bytecode/java_bytecode_convert_method.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,13 @@ void java_bytecode_convert_method_lazy(
// Not used in jbmc at present, but other codebases that use jbmc as a library
// use this information.
method_symbol.type.set(ID_C_abstract, m.is_abstract);

if(java_bytecode_parse_treet::find_annotation(
m.annotations, "java::org.cprover.MustNotThrow"))
{
method_symbol.type.set(ID_C_must_not_throw, true);
}

symbol_table.add(method_symbol);
}

Expand Down
30 changes: 20 additions & 10 deletions jbmc/src/java_bytecode/remove_exceptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,19 +432,29 @@ bool remove_exceptionst::instrument_function_call(

if(function_may_throw(callee_id))
{
add_exception_dispatch_sequence(
goto_program, instr_it, stack_catch, locals);

// add a null check (so that instanceof can be applied)
equal_exprt eq_null(
equal_exprt no_exception_currently_in_flight(
get_inflight_exception_global(),
null_pointer_exprt(pointer_type(empty_typet())));

goto_programt::targett t_null=goto_program.insert_after(instr_it);
t_null->make_goto(next_it);
t_null->source_location=instr_it->source_location;
t_null->function=instr_it->function;
t_null->guard=eq_null;
if(symbol_table.lookup_ref(callee_id).type.get_bool(ID_C_must_not_throw))
{
// Function is annotated must-not-throw, but we can't prove that here.
// Insert an ASSUME(@inflight_exception == null):
goto_programt::targett assume_null = goto_program.insert_after(instr_it);
assume_null->make_assumption(no_exception_currently_in_flight);
}
else
{
add_exception_dispatch_sequence(
goto_program, instr_it, stack_catch, locals);

// add a null check (so that instanceof can be applied)
goto_programt::targett t_null=goto_program.insert_after(instr_it);
t_null->make_goto(next_it);
t_null->source_location=instr_it->source_location;
t_null->function=instr_it->function;
t_null->guard=no_exception_currently_in_flight;
}

return true;
}
Expand Down
1 change: 1 addition & 0 deletions src/util/irep_ids.def
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,7 @@ IREP_ID_ONE(bits_per_byte)
IREP_ID_TWO(C_abstract, #abstract)
IREP_ID_ONE(synthetic)
IREP_ID_ONE(interface)
IREP_ID_TWO(C_must_not_throw, #must_not_throw)

// Projects depending on this code base that wish to extend the list of
// available ids should provide a file local_irep_ids.h in their source tree and
Expand Down

0 comments on commit ab60852

Please sign in to comment.