Skip to content

Commit af4edae

Browse files
committed
Fixing inheritance issue for java programs.
CBMC was incorrectly stubbing inherited methods. This leads to such methods being treated as non-det. The fix simply prevents CBMC from stubbing methods that are inherited.
1 parent d325431 commit af4edae

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+287
-4
lines changed

regression/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ DIRS = ansi-c \
33
cbmc \
44
cpp \
55
cbmc-java \
6+
cbmc-java-inheritance \
67
goto-analyzer \
78
goto-instrument \
89
goto-instrument-typedef \
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
default: tests.log
2+
3+
test:
4+
@if ! ../test.pl -c ../../../src/cbmc/cbmc ; then \
5+
../failed-tests-printer.pl ; \
6+
exit 1 ; \
7+
fi
8+
9+
tests.log: ../test.pl
10+
@if ! ../test.pl -c ../../../src/cbmc/cbmc ; then \
11+
../failed-tests-printer.pl ; \
12+
exit 1 ; \
13+
fi
14+
15+
show:
16+
@for dir in *; do \
17+
if [ -d "$$dir" ]; then \
18+
vim -o "$$dir/*.java" "$$dir/*.out"; \
19+
fi; \
20+
done;
21+
22+
clean:
23+
find -name '*.out' -execdir $(RM) '{}' \;
24+
find -name '*.gb' -execdir $(RM) '{}' \;
25+
$(RM) tests.log
26+
27+
%.class: %.java ../../src/org.cprover.jar
28+
javac -g -cp ../../src/org.cprover.jar:. $<
29+
30+
nondet_java_files := $(shell find . -name "Nondet*.java")
31+
nondet_class_files := $(patsubst %.java, %.class, $(nondet_java_files))
32+
33+
.PHONY: nondet-class-files
34+
nondet-class-files: $(nondet_class_files)
35+
36+
.PHONY: clean-nondet-class-files
37+
clean-nondet-class-files:
38+
-rm $(nondet_class_files)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CORE
2+
test.class
3+
--function test.check
4+
^EXIT=0$
5+
^SIGNAL=0$
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
class A
2+
{
3+
public int toInt()
4+
{
5+
return 12345;
6+
}
7+
}
8+
9+
class B extends A
10+
{
11+
}
12+
13+
class test
14+
{
15+
void check()
16+
{
17+
B b=new B();
18+
assert(b.toInt()==12345);
19+
}
20+
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CORE
2+
test.class
3+
--function test.check
4+
^EXIT=0$
5+
^SIGNAL=0$
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
class A
2+
{
3+
protected int toInt()
4+
{
5+
return 12345;
6+
}
7+
}
8+
9+
class B extends A
10+
{
11+
public void secondary()
12+
{
13+
assert(toInt()==12345);
14+
}
15+
}
16+
17+
class test
18+
{
19+
void check()
20+
{
21+
B b=new B();
22+
b.secondary();
23+
}
24+
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CORE
2+
test.class
3+
--function test.check
4+
^EXIT=0$
5+
^SIGNAL=0$
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
class Z
2+
{
3+
public int toInt()
4+
{
5+
return 12345;
6+
}
7+
}
8+
9+
class A extends Z
10+
{
11+
}
12+
13+
class B extends A
14+
{
15+
}
16+
17+
class test
18+
{
19+
void check()
20+
{
21+
B b=new B();
22+
assert(b.toInt()==12345);
23+
}
24+
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CORE
2+
test.class
3+
--function test.check
4+
^EXIT=0$
5+
^SIGNAL=0$
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
class A
2+
{
3+
public int toInt()
4+
{
5+
return 12345;
6+
}
7+
}
8+
9+
class B extends A
10+
{
11+
public int toInt()
12+
{
13+
return 9999;
14+
}
15+
}
16+
17+
class Z extends B
18+
{
19+
}
20+
21+
class test
22+
{
23+
void check()
24+
{
25+
Z z=new Z();
26+
assert(z.toInt()==9999);
27+
}
28+
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CORE
2+
test.class
3+
--function test.check
4+
^EXIT=0$
5+
^SIGNAL=0$
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
interface A
2+
{
3+
public int toInt();
4+
}
5+
6+
class B implements A
7+
{
8+
public int toInt()
9+
{
10+
return 12345;
11+
}
12+
}
13+
14+
class test
15+
{
16+
void check()
17+
{
18+
B b=new B();
19+
assert(b.toInt()==12345);
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package temp;
2+
3+
class A
4+
{
5+
int toint()
6+
{
7+
return 123456;
8+
}
9+
}
10+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package temp;
2+
3+
public class B extends A
4+
{
5+
public int check()
6+
{
7+
return toint();
8+
}
9+
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CORE
2+
test.class
3+
--function test.check
4+
^EXIT=0$
5+
^SIGNAL=0$
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import temp.B;
2+
3+
public class test
4+
{
5+
public void check()
6+
{
7+
B myObject = new B();
8+
assert(myObject.check()==123456);
9+
}
10+
}
11+

src/java_bytecode/java_bytecode_convert_method.cpp

+44-4
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ Author: Daniel Kroening, [email protected]
1919
#include <util/prefix.h>
2020
#include <util/arith_tools.h>
2121
#include <util/ieee_float.h>
22+
#include <util/invariant.h>
2223

2324
#include <linking/zero_initializer.h>
2425

2526
#include <goto-programs/cfg.h>
2627
#include <goto-programs/remove_exceptions.h>
28+
#include <goto-programs/class_hierarchy.h>
2729
#include <analyses/cfg_dominators.h>
2830

2931
#include "java_bytecode_convert_method.h"
@@ -32,6 +34,7 @@ Author: Daniel Kroening, [email protected]
3234
#include "java_types.h"
3335
#include "java_utils.h"
3436
#include "java_string_library_preprocess.h"
37+
#include "java_utils.h"
3538

3639
#include <limits>
3740
#include <algorithm>
@@ -1428,12 +1431,12 @@ codet java_bytecode_convert_methodt::convert_instructions(
14281431

14291432
assert(arg0.id()==ID_virtual_function);
14301433

1431-
// does the function symbol exist?
1434+
// if we don't have a definition for the called symbol, and we won't
1435+
// inherit a definition from a super-class, create a stub.
14321436
irep_idt id=arg0.get(ID_identifier);
1433-
1434-
if(symbol_table.symbols.find(id)==symbol_table.symbols.end())
1437+
if(symbol_table.symbols.find(id)==symbol_table.symbols.end() &&
1438+
!(is_virtual && is_method_inherited(arg0.get(ID_C_class), id)))
14351439
{
1436-
// no, create stub
14371440
symbolt symbol;
14381441
symbol.name=id;
14391442
symbol.base_name=arg0.get(ID_C_base_name);
@@ -2687,3 +2690,40 @@ void java_bytecode_convert_method(
26872690

26882691
java_bytecode_convert_method(class_symbol, method);
26892692
}
2693+
2694+
const bool java_bytecode_convert_methodt::is_method_inherited(
2695+
const irep_idt &classname, const irep_idt &methodid) const
2696+
{
2697+
class_hierarchyt ch;
2698+
namespacet ns(symbol_table);
2699+
ch(symbol_table);
2700+
2701+
std::string stripped_methodid(id2string(methodid));
2702+
stripped_methodid.erase(0, classname.size());
2703+
2704+
const std::string &classpackage=java_class_to_package(id2string(classname));
2705+
const auto &parents=ch.get_parents_trans(classname);
2706+
for(const auto &parent : parents)
2707+
{
2708+
const irep_idt id=id2string(parent)+stripped_methodid;
2709+
const symbolt *symbol;
2710+
if(!ns.lookup(id, symbol) &&
2711+
symbol->type.id()==ID_code)
2712+
{
2713+
const auto &access=symbol->type.get(ID_access);
2714+
if(access==ID_public || access==ID_protected)
2715+
return true;
2716+
// methods with the default access modifier are only
2717+
// accessible within the same package.
2718+
else if(access==ID_default &&
2719+
java_class_to_package(id2string(parent))==classpackage)
2720+
return true;
2721+
else if(access==ID_private)
2722+
continue;
2723+
else
2724+
INVARIANT(false, "Unexpected access modifier.");
2725+
}
2726+
}
2727+
return false;
2728+
}
2729+

src/java_bytecode/java_bytecode_convert_method_class.h

+4
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,10 @@ class java_bytecode_convert_methodt:public messaget
258258
bool class_needs_clinit(const irep_idt &classname);
259259
exprt get_or_create_clinit_wrapper(const irep_idt &classname);
260260
codet get_clinit_call(const irep_idt &classname);
261+
262+
const bool is_method_inherited(
263+
const irep_idt &classname,
264+
const irep_idt &methodid) const;
261265
};
262266

263267
#endif

src/java_bytecode/java_utils.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Author: Daniel Kroening, [email protected]
1010
#include <util/prefix.h>
1111
#include <util/std_types.h>
1212
#include <util/invariant.h>
13+
#include <util/string_utils.h>
1314

1415
#include "java_utils.h"
1516
#include "java_types.h"
@@ -52,3 +53,8 @@ unsigned java_method_parameter_slots(const code_typet &t)
5253

5354
return slots;
5455
}
56+
57+
const std::string java_class_to_package(const std::string &canonical_classname)
58+
{
59+
return trim_from_last_delimiter(canonical_classname, '.');
60+
}

src/java_bytecode/java_utils.h

+2
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@ unsigned java_local_variable_slots(const typet &t);
2424
/// pass, upon call, the arguments of a Java method whose type is \p t.
2525
unsigned java_method_parameter_slots(const code_typet &t);
2626

27+
const std::string java_class_to_package(const std::string &canonical_classname);
28+
2729
#endif // CPROVER_JAVA_BYTECODE_JAVA_UTILS_H

src/util/string_utils.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,14 @@ void split_string(
9999
left=result[0];
100100
right=result[1];
101101
}
102+
103+
std::string trim_from_last_delimiter(
104+
const std::string &s,
105+
const char delim)
106+
{
107+
std::string result="";
108+
const size_t index=s.find_last_of(delim);
109+
if(index!=std::string::npos)
110+
result=s.substr(0, index);
111+
return result;
112+
}

src/util/string_utils.h

+4
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,8 @@ void split_string(
2929
std::string &right,
3030
bool strip=false);
3131

32+
std::string trim_from_last_delimiter(
33+
const std::string &s,
34+
const char delim);
35+
3236
#endif

0 commit comments

Comments
 (0)