Skip to content

Commit 23aaf82

Browse files
author
pkesseli
committed
- Fixed vtables in Java.
- Removed UB in Java bytecode module. - Recompiled virtual1-virtual4 with JDK 8.
1 parent 5586409 commit 23aaf82

17 files changed

+79
-86
lines changed

regression/cbmc-java/virtual1/A.class

-7 Bytes
Binary file not shown.

regression/cbmc-java/virtual1/B.class

254 Bytes
Binary file not shown.
-266 Bytes
Binary file not shown.

regression/cbmc-java/virtual1/virtual1.java

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class virtual1
1616
public static void main(String[] args)
1717
{
1818
A a=new A();
19+
B b=new B();
1920
a.f();
2021
}
2122
}
17 Bytes
Binary file not shown.

regression/cbmc-java/virtual2/virtual2.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ class virtual2
1515
{
1616
public static void main(String[] args)
1717
{
18-
A a=new B();
19-
a.f();
18+
A a=new A();
19+
A b=new B();
20+
b.f();
2021
}
2122
}
2223

regression/cbmc-java/virtual3/C.class

235 Bytes
Binary file not shown.
24 Bytes
Binary file not shown.
+10-4
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,28 @@
11
interface A
22
{
33
public void f();
4-
};
4+
}
55

66
class B implements A
77
{
88
public void f()
99
{
1010
assert false;
1111
}
12-
};
12+
}
13+
14+
class C implements A
15+
{
16+
public void f(){}
17+
}
1318

1419
class virtual3
1520
{
1621
public static void main(String[] args)
1722
{
18-
A a = new B();
19-
a.f();
23+
A b = new B();
24+
A c = new C();
25+
b.f();
2026
}
2127
}
2228

24 Bytes
Binary file not shown.

regression/cbmc-java/virtual4/virtual4.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ class virtual4
2020
{
2121
public static void main(String[] args)
2222
{
23-
A a = new C();
24-
a.f();
23+
A b = new B();
24+
A c = new C();
25+
c.f();
2526
}
2627
}
2728

src/goto-programs/builtin_functions.cpp

+21-49
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Author: Daniel Kroening, [email protected]
2323
#include <util/pointer_predicates.h>
2424
#include <util/pointer_offset_size.h>
2525
#include <util/vtable.h>
26+
#include <util/namespace_utils.h>
2627

2728
#include <linking/zero_initializer.h>
2829

@@ -545,61 +546,33 @@ symbol_exprt get_vt(const irep_idt &class_name) {
545546
return symbol_exprt(vt_name, vttype);
546547
}
547548

548-
const dereference_exprt cast_if_necessary(const exprt &lhs,
549-
const irep_idt &ptr_class, const irep_idt &vt_class) {
550-
const symbol_typet class_type(vt_class);
551-
if (ptr_class == vt_class) return dereference_exprt(lhs, class_type);
552-
const symbol_typet target_type(ptr_class);
553-
const typecast_exprt cast(lhs, pointer_typet(target_type));
554-
return dereference_exprt(cast, target_type);
555-
}
556-
557-
void assign_vtpointer(goto_programt &dest, const namespacet &ns,
558-
const exprt &lhs, const irep_idt &ptr_class, const irep_idt &vt_class,
559-
const source_locationt &location) {
560-
const symbol_exprt ptr_vt(get_vt(ptr_class));
561-
const symbol_exprt vt(get_vt(vt_class));
562-
const dereference_exprt lhs_ref(cast_if_necessary(lhs, ptr_class, vt_class));
563-
const std::string memb_name(vtnamest::get_pointer(id2string(ptr_class)));
564-
const pointer_typet ptr_vt_type(ptr_vt.type());
565-
const member_exprt vtmember(lhs_ref, memb_name, ptr_vt_type);
566-
const address_of_exprt vtable_ptr(vt);
567-
const goto_programt::targett instr(dest.add_instruction(ASSIGN));
568-
instr->source_location = location;
569-
if (ptr_class == vt_class) {
570-
instr->code = code_assignt(vtmember, vtable_ptr);
571-
} else {
572-
const typecast_exprt cast(vtable_ptr, ptr_vt_type);
573-
instr->code = code_assignt(vtmember, cast);
574-
}
575-
}
576-
577549
bool is_type_missing(const namespacet &ns, const symbol_typet &type)
578550
{
579551
return !ns.get_symbol_table().has_symbol(type.get_identifier());
580552
}
581553

582-
void assign_vtpointers(goto_programt &dest, const namespacet &ns,
583-
const exprt &lhs, const symbol_typet &class_type,
584-
const source_locationt &location)
554+
exprt &get_vt_pointer_member(struct_exprt &expr)
555+
{
556+
// We assume the first member is vt_pointer or super class object.
557+
assert(expr.has_operands());
558+
exprt &op0=expr.op0();
559+
if (ID_struct != op0.id()) return op0;
560+
return get_vt_pointer_member(to_struct_expr(op0));
561+
}
562+
563+
void set_vt_pointer(struct_exprt &expr, const namespacet &ns,
564+
const symbol_typet &class_type)
585565
{
586566
if (is_type_missing(ns, class_type)) return;
587567
const irep_idt &class_name(class_type.get_identifier());
588-
const irep_idt vtname(vtnamest::get_table(id2string(class_name)));
589-
if (ns.get_symbol_table().has_symbol(vtname)) {
590-
const class_typet &full_class_type(to_class_type(ns.follow(class_type)));
591-
const irept::subt &bases(full_class_type.bases());
592-
for (irept::subt::const_iterator it=bases.begin(); it != bases.end(); ++it) {
593-
const typet &type(static_cast<const typet &>(it->find(ID_type)));
594-
const symbol_typet &parent_type(to_symbol_type(type));
595-
if (is_type_missing(ns, parent_type)) continue;
596-
const irep_idt &parent_name(parent_type.get_identifier());
597-
const irep_idt parent_vtname(vtnamest::get_table(id2string(parent_name)));
598-
if(!ns.get_symbol_table().has_symbol(parent_vtname)) continue;
599-
assign_vtpointer(dest, ns, lhs, parent_name, class_name, location);
600-
}
601-
assign_vtpointer(dest, ns, lhs, class_name, class_name, location);
602-
}
568+
const symbol_exprt vt(get_vt(class_name));
569+
exprt &vt_pointer_member=get_vt_pointer_member(expr);
570+
const typet &member_type=vt_pointer_member.type();
571+
const address_of_exprt vt_pointer(vt);
572+
if (type_eq(member_type, vt_pointer.type(), ns))
573+
vt_pointer_member=vt_pointer;
574+
else
575+
vt_pointer_member=typecast_exprt(vt_pointer, member_type);
603576
}
604577
}
605578

@@ -647,11 +620,10 @@ void goto_convertt::do_java_new(
647620
// zero-initialize the object
648621
dereference_exprt deref(lhs, object_type);
649622
exprt zero_object=zero_initializer(object_type, location, ns, get_message_handler());
623+
set_vt_pointer(to_struct_expr(zero_object), ns, to_symbol_type(object_type));
650624
goto_programt::targett t_i=dest.add_instruction(ASSIGN);
651625
t_i->code=code_assignt(deref, zero_object);
652626
t_i->source_location=location;
653-
654-
assign_vtpointers(dest, ns, lhs, to_symbol_type(object_type), location);
655627
}
656628

657629
/*******************************************************************\

src/java_bytecode/java_bytecode_convert.cpp

-4
Original file line numberDiff line numberDiff line change
@@ -747,12 +747,8 @@ codet java_bytecode_convertt::convert_instructions(
747747

748748
if(is_virtual)
749749
{
750-
#if 0
751750
const exprt &this_arg=call.arguments().front();
752751
call.function() = make_vtable_function(arg0, this_arg);
753-
#else
754-
call.function() = arg0;
755-
#endif
756752
}
757753
else
758754
call.function() = arg0;

src/java_bytecode/java_bytecode_language.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ bool java_bytecode_languaget::typecheck(
160160
return true;
161161
}
162162

163+
// Construct vtable symbols before typecheck
164+
if (java_bytecode_vtable(symbol_table, module))
165+
return true;
166+
163167
// now typecheck all
164168
if(java_bytecode_typecheck(
165169
symbol_table, get_message_handler()))

src/java_bytecode/java_bytecode_parser.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,7 @@ void java_bytecode_parsert::rinterfaces(classt &parsed_class)
591591
u2 interfaces_count=read_u2();
592592

593593
for(unsigned i=0; i<interfaces_count; i++)
594-
parsed_class.implements.push_back(pool_entry(read_u2()).s);
594+
parsed_class.implements.push_back(constant(read_u2()).type().get(ID_C_base_name));
595595
}
596596

597597
/*******************************************************************\

src/java_bytecode/java_bytecode_vtable.cpp

+32-20
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,8 @@ class java_bytecode_vtable_factoryt
162162
std::vector<class_typet> bases;
163163
extract_types(bases, class_type.bases(), method);
164164
//extract_types(bases, class_type.find(ID_interfaces).get_sub(), method);
165-
for(std::vector<class_typet>::const_iterator b=bases.begin(); b != bases.end(); ++b)
166-
add_vtable_entry(vtable_value, *b, class_type, method);
165+
for(const std::vector<class_typet>::value_type &b : bases)
166+
add_vtable_entry(vtable_value, b, class_type, method);
167167
}
168168

169169
void create_vtable_entry(struct_exprt &vtable_value,
@@ -189,21 +189,21 @@ class java_bytecode_vtable_factoryt
189189
return symbol_table.has_symbol(vtnamest::get_type(class_name));
190190
}
191191

192-
void operator()(const std::pair<const irep_idt, symbolt> &named_symbol)
192+
void operator()(const irep_idt &symbol_name)
193193
{
194-
const symbolt &symbol(named_symbol.second);
194+
const symbolt &symbol = symbol_table.lookup(symbol_name);
195195
if (!is_class_with_vt(symbol)) return;
196196
const class_typet &class_type(to_class_type(symbol.type));
197-
const std::string &class_name(id2string(named_symbol.first));
197+
const std::string &class_name(id2string(symbol_name));
198198
if (symbol_table.has_symbol(vtnamest::get_table(class_name))) return;
199199
symbolt vtable_symbol;
200200
create_vtable_symbol(vtable_symbol, class_type);
201201
const class_typet::methodst &methods(class_type.methods());
202202
struct_exprt vtable_value;
203-
for (class_typet::methodst::const_iterator m=methods.begin(); m != methods.end(); ++m)
204-
create_base_vtable_entries(vtable_value, class_type, *m);
205-
for (class_typet::methodst::const_iterator m=methods.begin(); m != methods.end(); ++m)
206-
create_vtable_entry(vtable_value, class_type, *m);
203+
for (const class_typet::methodst::value_type &m : methods)
204+
create_base_vtable_entries(vtable_value, class_type, m);
205+
for (const class_typet::methodst::value_type &m : methods)
206+
create_vtable_entry(vtable_value, class_type, m);
207207
set_vtable_value(vtable_symbol, class_type, vtable_value);
208208
assert(!symbol_table.add(vtable_symbol));
209209
}
@@ -228,12 +228,18 @@ bool java_bytecode_vtable(
228228
const std::string &module)
229229
{
230230
const symbol_tablet::symbolst &symbols(symbol_table.symbols);
231+
std::vector<irep_idt> names;
232+
names.reserve(symbols.size());
233+
std::transform(symbols.begin(), symbols.end(), std::back_inserter(names),
234+
[](const std::pair<irep_idt, symbolt> &entry)
235+
{ return entry.first;});
231236
java_bytecode_vtable_factoryt factory(symbol_table, module);
232-
std::for_each(symbols.begin(), symbols.end(), factory);
237+
std::for_each(names.begin(), names.end(), factory);
233238
return factory.has_error;
234239
}
235240

236-
namespace {
241+
namespace
242+
{
237243

238244
void create_vtable_type(const irep_idt &vt_name, symbol_tablet &symbol_table,
239245
const symbolt &class_symbol) {
@@ -252,6 +258,7 @@ void create_vtable_type(const irep_idt &vt_name, symbol_tablet &symbol_table,
252258
}
253259

254260
const char ID_isvtptr[] = "is_vtptr";
261+
const char ID_vtable_pointer[] = "@vtable_pointer";
255262

256263
void add_vtable_pointer_member(
257264
const irep_idt &vt_name,
@@ -260,9 +267,9 @@ void add_vtable_pointer_member(
260267
struct_typet::componentt comp;
261268

262269
comp.type()=pointer_typet(symbol_typet(vt_name));
263-
comp.set_name("@vtable_pointer");
264-
comp.set_base_name("@vtable_pointer");
265-
comp.set_pretty_name("@vtable_pointer");
270+
comp.set_name(ID_vtable_pointer);
271+
comp.set_base_name(ID_vtable_pointer);
272+
comp.set_pretty_name(ID_vtable_pointer);
266273
comp.set(ID_isvtptr, true);
267274

268275
struct_typet &class_type=to_struct_type(class_symbol.type);
@@ -386,17 +393,22 @@ exprt make_vtable_function(
386393
const irep_idt &func_name(func.get(ID_identifier));
387394
const std::string class_id(get_full_class_name(id2string(func_name)));
388395

389-
//if (class_id.find("java.lang.") != std::string::npos) {
390-
// TODO: Handle unavailable models!
391-
//return func;
392-
//}
396+
// TODO: Handle unavailable models!
397+
if (class_id.find("java.") != std::string::npos) {
398+
// When translating a single java_bytecode_parse_treet, we don't know
399+
// which classes will eventually be available yet. If we could provide
400+
// access to the class loader here, we know which classes have been
401+
// loaded successfully. For classes which have not been loaded, returning
402+
// "func" is equivalent to an unimplemented function.
403+
return func;
404+
}
393405

394406
const symbol_typet vtable_type(vtnamest::get_type(class_id));
395-
const pointer_typet vtable_pointer_type(vtable_type);
407+
const pointer_typet vt_ptr_type(vtable_type);
396408
const symbol_typet target_type(class_id);
397409
const exprt this_ref(get_ref(this_obj, target_type));
398410
const typet ref_type(this_ref.type());
399-
const member_exprt vtable_member(this_ref, "@vtable_pointer", vtable_pointer_type);
411+
const member_exprt vtable_member(this_ref, ID_vtable_pointer, vt_ptr_type);
400412
const dereference_exprt vtable(vtable_member, vtable_type); // TODO: cast?
401413
const pointer_typet func_ptr_type(func.type());
402414
const member_exprt func_ptr(vtable, func_name, func_ptr_type);

src/java_bytecode/java_bytecode_vtable.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ void create_vtable_symbol(
1818
symbol_tablet &symbol_table,
1919
const class symbolt &class_symbol);
2020

21-
code_assignt make_vtable_assignment(
22-
const symbol_tablet &symbol_table,
23-
const exprt &func);
24-
2521
exprt make_vtable_function(
2622
const exprt &function,
2723
const exprt &this_obj);
2824

2925
void set_virtual_name(
3026
class_typet::methodt &method);
3127

28+
bool java_bytecode_vtable(
29+
symbol_tablet &symbol_table,
30+
const std::string &module);
31+
3232
#endif /* CPROVER_JAVA_BYTECODE_VTABLE_H */

0 commit comments

Comments
 (0)