Skip to content

Commit 3897b39

Browse files
smowtonthk123
authored and
thk123
committed
Java method converter: ensure type consistency of generated function calls
This both ensures that the reference to the callee precisely matches the callee's symbol type, and that parameters match. For example, previously the callee could specifically take a List<Integer>, but the type given at the callsite might just be `callee(List)`, omitting the generic type information, leading to a pointer changing type without a cast.
1 parent f490894 commit 3897b39

File tree

1 file changed

+37
-20
lines changed

1 file changed

+37
-20
lines changed

jbmc/src/java_bytecode/java_bytecode_convert_method.cpp

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2094,34 +2094,52 @@ void java_bytecode_convert_methodt::convert_invoke(
20942094
const bool is_virtual(
20952095
statement == "invokevirtual" || statement == "invokeinterface");
20962096

2097+
const irep_idt &invoked_method_id = arg0.get(ID_identifier);
2098+
INVARIANT(
2099+
!invoked_method_id.empty(),
2100+
"invoke statement arg0 must have an identifier");
2101+
2102+
auto method_symbol = symbol_table.symbols.find(invoked_method_id);
2103+
2104+
// Use the most precise type available: the actual symbol has generic info,
2105+
// whereas the type given by the invoke instruction doesn't and is therefore
2106+
// less accurate.
2107+
if(method_symbol != symbol_table.symbols.end())
2108+
arg0.type() = to_java_method_type(method_symbol->second.type);
2109+
2110+
// Note arg0 and arg0.type() are subject to many side-effects in this method,
2111+
// then finally used to populate the call instruction.
20972112
java_method_typet &method_type = to_java_method_type(arg0.type());
2113+
20982114
java_method_typet::parameterst &parameters(method_type.parameters());
20992115

21002116
if(use_this)
21012117
{
2118+
irep_idt classname = arg0.get(ID_C_class);
2119+
21022120
if(parameters.empty() || !parameters[0].get_this())
21032121
{
2104-
irep_idt classname = arg0.get(ID_C_class);
21052122
typet thistype = struct_tag_typet(classname);
2106-
// Note invokespecial is used for super-method calls as well as
2107-
// constructors.
2108-
if(statement == "invokespecial")
2109-
{
2110-
if(is_constructor(arg0.get(ID_identifier)))
2111-
{
2112-
if(needed_lazy_methods)
2113-
needed_lazy_methods->add_needed_class(classname);
2114-
method_type.set_is_constructor();
2115-
}
2116-
else
2117-
method_type.set(ID_java_super_method_call, true);
2118-
}
21192123
reference_typet object_ref_type = java_reference_type(thistype);
21202124
java_method_typet::parametert this_p(object_ref_type);
21212125
this_p.set_this();
21222126
this_p.set_base_name(ID_this);
21232127
parameters.insert(parameters.begin(), this_p);
21242128
}
2129+
2130+
// Note invokespecial is used for super-method calls as well as
2131+
// constructors.
2132+
if(statement == "invokespecial")
2133+
{
2134+
if(is_constructor(invoked_method_id))
2135+
{
2136+
if(needed_lazy_methods)
2137+
needed_lazy_methods->add_needed_class(classname);
2138+
method_type.set_is_constructor();
2139+
}
2140+
else
2141+
method_type.set(ID_java_super_method_call, true);
2142+
}
21252143
}
21262144

21272145
code_function_callt call;
@@ -2184,18 +2202,17 @@ void java_bytecode_convert_methodt::convert_invoke(
21842202
// accessible from the original caller, but not from the generated test.
21852203
// Therefore we must assume that the method is not accessible.
21862204
// We set opaque methods as final to avoid assuming they can be overridden.
2187-
irep_idt id = arg0.get(ID_identifier);
21882205
if(
2189-
symbol_table.symbols.find(id) == symbol_table.symbols.end() &&
2206+
method_symbol == symbol_table.symbols.end() &&
21902207
!(is_virtual &&
21912208
is_method_inherited(arg0.get(ID_C_class), arg0.get(ID_component_name))))
21922209
{
21932210
symbolt symbol;
2194-
symbol.name = id;
2211+
symbol.name = invoked_method_id;
21952212
symbol.base_name = arg0.get(ID_C_base_name);
21962213
symbol.pretty_name = id2string(arg0.get(ID_C_class)).substr(6) + "." +
21972214
id2string(symbol.base_name) + "()";
2198-
symbol.type = arg0.type();
2215+
symbol.type = method_type;
21992216
symbol.type.set(ID_access, ID_private);
22002217
to_java_method_type(symbol.type).set_is_final(true);
22012218
symbol.value.make_nil();
@@ -2220,10 +2237,10 @@ void java_bytecode_convert_methodt::convert_invoke(
22202237
else
22212238
{
22222239
// static binding
2223-
call.function() = symbol_exprt(arg0.get(ID_identifier), arg0.type());
2240+
call.function() = symbol_exprt(invoked_method_id, method_type);
22242241
if(needed_lazy_methods)
22252242
{
2226-
needed_lazy_methods->add_needed_method(arg0.get(ID_identifier));
2243+
needed_lazy_methods->add_needed_method(invoked_method_id);
22272244
// Calling a static method causes static initialization:
22282245
needed_lazy_methods->add_needed_class(arg0.get(ID_C_class));
22292246
}

0 commit comments

Comments
 (0)