Skip to content

Commit 8321fa8

Browse files
committed
Fix bug assigning nondetWithNull to Object
In the case where we really want to create a nondet java.lang.Object, the java compiler does not emit a checkcast instruction, which means that our attempt to divine the nondet type using checkcast fails. This commit changes the behaviour of nondetWithNull so that it will create an Object if the following instruction is not a checkcast. The test nondetCastToObject tests this behaviour.
1 parent 101a65d commit 8321fa8

File tree

5 files changed

+43
-10
lines changed

5 files changed

+43
-10
lines changed

regression/cbmc-java/Makefile

+13
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,16 @@ show:
1818
vim -o "$$dir/*.java" "$$dir/*.out"; \
1919
fi; \
2020
done;
21+
22+
%.class: %.java ../../src/org.cprover.jar
23+
javac -g -cp ../../src/org.cprover.jar:. $<
24+
25+
nondet_java_files := $(shell find . -name "Nondet*.java")
26+
nondet_class_files := $(patsubst %.java, %.class, $(nondet_java_files))
27+
28+
.PHONY: nondet-class-files
29+
nondet-class-files: $(nondet_class_files)
30+
31+
.PHONY: clean-nondet-class-files
32+
clean-nondet-class-files:
33+
-rm $(nondet_class_files)
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import org.cprover.CProver;
2+
3+
class NondetCastToObject
4+
{
5+
void foo()
6+
{
7+
Object o = CProver.nondetWithNull();
8+
CProver.assume(o != null);
9+
assert o != null;
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CORE
2+
NondetCastToObject.class
3+
--function NondetCastToObject.foo
4+
^VERIFICATION SUCCESSFUL$
5+
--
6+
^warning: ignoring

src/java_bytecode/java_bytecode_convert_method.cpp

+13-10
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ static void remove_assert_after_generic_nondet(exprt &expr)
7474
if(&(*it)==before_1)
7575
{
7676
const auto next_it=std::next(it);
77-
assert(next_it!=end);
78-
if(next_it->id()==ID_code &&
77+
if(next_it!=end &&
78+
next_it->id()==ID_code &&
7979
to_code(*next_it).get_statement()=="assert")
8080
{
8181
*next_it=code_skipt();
@@ -1288,16 +1288,23 @@ codet java_bytecode_convert_methodt::convert_instructions(
12881288
".*org.cprover.CProver.(nondetWithNull|nondetWithoutNull).*")) &&
12891289
!working_set.empty())
12901290
{
1291+
// Get the nondet function code type.
1292+
auto func_type=to_code_type(arg0.type());
1293+
1294+
// Find the next instruction.
12911295
const auto working_set_begin=working_set.begin();
12921296
const auto next_address=address_map.find(*working_set_begin);
12931297
assert(next_address!=address_map.end());
12941298

12951299
// Find the correct return type.
12961300
const auto next_source=next_address->second.source;
12971301
const auto next_statement=next_source->statement;
1298-
assert(next_statement=="checkcast");
1299-
assert(next_source->args.size()>=1);
1300-
const auto return_type=pointer_typet(next_source->args[0].type());
1302+
// The next return type is the casted-to type *if* the next statement is
1303+
// a checkcast. Otherwise, we leave it as-is.
1304+
const auto return_type=
1305+
(next_statement=="checkcast" && next_source->args.size()>=1) ?
1306+
pointer_typet(next_source->args[0].type()) :
1307+
func_type.return_type();
13011308

13021309
// Reconstruct a function call with the correct return type.
13031310
code_function_callt call;
@@ -1306,11 +1313,7 @@ codet java_bytecode_convert_methodt::convert_instructions(
13061313
loc.set_function(method_id);
13071314
call.add_source_location()=loc;
13081315
call.function().add_source_location()=loc;
1309-
1310-
// Update the pointed-to type.
1311-
auto func_type=arg0.type();
1312-
to_code_type(func_type).return_type()=return_type;
1313-
1316+
func_type.return_type()=return_type;
13141317
call.function()=symbol_exprt(arg0.get(ID_identifier), func_type);
13151318
call.lhs()=tmp_variable("return", return_type);
13161319

0 commit comments

Comments
 (0)