Skip to content

Commit ec41608

Browse files
smowtonthk123
authored and
thk123
committed
Ensure member_exprt's type matches the addressed component
Previously we created the expression with the partial type given at the access site (i.e. as part of the get/setfield bytecode), but this lacked any generic type information, which the actual component *did* have. The member expression could therefore be type-inconsistent with the object is addressed. Since it's no longer necessary to make the expression approximately and later fix it up in typecheck_expr, let's just get it right the first time, including giving it the right type.
1 parent ace71e7 commit ec41608

4 files changed

+32
-58
lines changed

jbmc/src/java_bytecode/java_bytecode_convert_method.cpp

+30-12
Original file line numberDiff line numberDiff line change
@@ -641,20 +641,39 @@ static irep_idt get_if_cmp_operator(const irep_idt &stmt)
641641
throw "unhandled java comparison instruction";
642642
}
643643

644-
static member_exprt to_member(const exprt &pointer, const exprt &fieldref)
644+
static member_exprt
645+
to_member(const exprt &pointer, const exprt &fieldref, const namespacet &ns)
645646
{
646647
struct_tag_typet class_type(fieldref.get(ID_class));
647648

648-
const typecast_exprt pointer2(pointer, java_reference_type(class_type));
649+
const exprt typed_pointer =
650+
typecast_exprt::conditional_cast(pointer, java_reference_type(class_type));
649651

650-
dereference_exprt obj_deref=checked_dereference(pointer2, class_type);
652+
const irep_idt &component_name = fieldref.get(ID_component_name);
651653

652-
const member_exprt member_expr(
653-
obj_deref,
654-
fieldref.get(ID_component_name),
655-
fieldref.type());
654+
exprt accessed_object = checked_dereference(typed_pointer, class_type);
656655

657-
return member_expr;
656+
// The field access is described as being against a particular type, but it
657+
// may in fact belong to any ancestor type.
658+
while(1)
659+
{
660+
struct_typet object_type =
661+
to_struct_type(ns.follow(accessed_object.type()));
662+
auto component = object_type.get_component(component_name);
663+
664+
if(component.is_not_nil())
665+
return member_exprt(accessed_object, component);
666+
667+
// Component not present: check the immediate parent type.
668+
669+
const auto &components = object_type.components();
670+
INVARIANT(
671+
components.size() != 0,
672+
"infer_opaque_type_fields should guarantee that a member access has a "
673+
"corresponding field");
674+
675+
accessed_object = member_exprt(accessed_object, components.front());
676+
}
658677
}
659678

660679
/// Find all goto statements in 'repl' that target 'old_label' and redirect them
@@ -1530,7 +1549,7 @@ code_blockt java_bytecode_convert_methodt::convert_instructions(
15301549
else if(statement=="getfield")
15311550
{
15321551
PRECONDITION(op.size() == 1 && results.size() == 1);
1533-
results[0]=java_bytecode_promotion(to_member(op[0], arg0));
1552+
results[0] = java_bytecode_promotion(to_member(op[0], arg0, ns));
15341553
}
15351554
else if(statement=="getstatic")
15361555
{
@@ -2543,7 +2562,7 @@ code_blockt java_bytecode_convert_methodt::convert_putfield(
25432562
block,
25442563
bytecode_write_typet::FIELD,
25452564
arg0.get(ID_component_name));
2546-
block.add(code_assignt(to_member(op[0], arg0), op[1]));
2565+
block.add(code_assignt(to_member(op[0], arg0, ns), op[1]));
25472566
return block;
25482567
}
25492568

@@ -2918,8 +2937,7 @@ optionalt<exprt> java_bytecode_convert_methodt::convert_invoke_dynamic(
29182937
if(return_type.id() == ID_empty)
29192938
return {};
29202939

2921-
const auto value =
2922-
zero_initializer(return_type, location, namespacet(symbol_table));
2940+
const auto value = zero_initializer(return_type, location, ns);
29232941
if(!value.has_value())
29242942
{
29252943
error().source_location = location;

jbmc/src/java_bytecode/java_bytecode_convert_method_class.h

+2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class java_bytecode_convert_methodt:public messaget
4343
bool threading_support)
4444
: messaget(_message_handler),
4545
symbol_table(symbol_table),
46+
ns(symbol_table),
4647
max_array_length(_max_array_length),
4748
throw_assertion_error(throw_assertion_error),
4849
threading_support(threading_support),
@@ -69,6 +70,7 @@ class java_bytecode_convert_methodt:public messaget
6970

7071
protected:
7172
symbol_table_baset &symbol_table;
73+
namespacet ns;
7274
const size_t max_array_length;
7375
const bool throw_assertion_error;
7476
const bool threading_support;

jbmc/src/java_bytecode/java_bytecode_typecheck.h

-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ class java_bytecode_typecheckt:public typecheckt
6969
void typecheck_code(codet &);
7070
void typecheck_type(typet &);
7171
void typecheck_expr_symbol(symbol_exprt &);
72-
void typecheck_expr_member(member_exprt &);
7372
void typecheck_expr_java_new(side_effect_exprt &);
7473
void typecheck_expr_java_new_array(side_effect_exprt &);
7574

jbmc/src/java_bytecode/java_bytecode_typecheck_expr.cpp

-45
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,6 @@ void java_bytecode_typecheckt::typecheck_expr(exprt &expr)
5252
else if(statement==ID_java_new_array)
5353
typecheck_expr_java_new_array(to_side_effect_expr(expr));
5454
}
55-
else if(expr.id()==ID_member)
56-
typecheck_expr_member(to_member_expr(expr));
5755
}
5856

5957
void java_bytecode_typecheckt::typecheck_expr_java_new(side_effect_exprt &expr)
@@ -120,46 +118,3 @@ void java_bytecode_typecheckt::typecheck_expr_symbol(symbol_exprt &expr)
120118
expr.type()=symbol.type;
121119
}
122120
}
123-
124-
void java_bytecode_typecheckt::typecheck_expr_member(member_exprt &expr)
125-
{
126-
// The member might be in a parent class or an opaque class, which we resolve
127-
// here.
128-
const irep_idt component_name=expr.get_component_name();
129-
130-
while(1)
131-
{
132-
typet base_type(ns.follow(expr.struct_op().type()));
133-
134-
if(base_type.id()!=ID_struct)
135-
break; // give up
136-
137-
struct_typet &struct_type=
138-
to_struct_type(base_type);
139-
140-
if(struct_type.has_component(component_name))
141-
return; // done
142-
143-
// look at parent
144-
struct_typet::componentst &components=
145-
struct_type.components();
146-
147-
if(components.empty())
148-
break;
149-
150-
const struct_typet::componentt &c=components.front();
151-
152-
member_exprt m(expr.struct_op(), c.get_name(), c.type());
153-
m.add_source_location()=expr.source_location();
154-
155-
expr.struct_op()=m;
156-
}
157-
158-
warning().source_location=expr.source_location();
159-
warning() << "failed to find field `"
160-
<< component_name << "` in class hierarchy" << eom;
161-
162-
// We replace by a non-det of same type
163-
side_effect_expr_nondett nondet(expr.type(), expr.source_location());
164-
expr.swap(nondet);
165-
}

0 commit comments

Comments
 (0)