36
36
37
37
#include < goto-programs/cfg.h>
38
38
#include < goto-programs/class_hierarchy.h>
39
+ #include < goto-programs/remove_returns.h>
39
40
#include < goto-programs/resolve_inherited_component.h>
40
41
41
42
#include < analyses/cfg_dominators.h>
42
43
#include < analyses/uncaught_exceptions_analysis.h>
43
44
44
- #include < limits>
45
45
#include < algorithm>
46
46
#include < functional>
47
- #include < unordered_set >
47
+ #include < limits >
48
48
#include < regex>
49
+ #include < unordered_set>
49
50
50
51
// / Given a string of the format '?blah?', will return true when compared
51
52
// / against a string that matches appart from any characters that are '?'
@@ -428,11 +429,14 @@ void java_bytecode_convert_methodt::convert(
428
429
id2string (class_symbol.name )+" ." +id2string (m.name )+" :" +m.descriptor ;
429
430
method_id=method_identifier;
430
431
431
- symbolt &method_symbol=*symbol_table.get_writeable (method_identifier);
432
-
433
432
// Obtain a std::vector of java_method_typet::parametert objects from the
434
433
// (function) type of the symbol
435
- java_method_typet method_type = to_java_method_type (method_symbol.type );
434
+ // Don't try to hang on to this reference into the symbol table, as we're
435
+ // about to create symbols for the method's parameters, which would invalidate
436
+ // the reference. Instead, copy the type here, set it up, then assign it back
437
+ // to the symbol later.
438
+ java_method_typet method_type =
439
+ to_java_method_type (symbol_table.lookup_ref (method_identifier).type );
436
440
method_type.set (ID_C_class, class_symbol.name );
437
441
method_type.set_is_final (m.is_final );
438
442
method_return_type = method_type.return_type ();
@@ -555,6 +559,8 @@ void java_bytecode_convert_methodt::convert(
555
559
param_index+=java_local_variable_slots (param.type ());
556
560
}
557
561
562
+ symbolt &method_symbol = symbol_table.get_writeable_ref (method_identifier);
563
+
558
564
// The parameter slots detected in this function should agree with what
559
565
// java_parameter_count() thinks about this method
560
566
INVARIANT (
@@ -641,20 +647,39 @@ static irep_idt get_if_cmp_operator(const irep_idt &stmt)
641
647
throw " unhandled java comparison instruction" ;
642
648
}
643
649
644
- static member_exprt to_member (const exprt &pointer, const exprt &fieldref)
650
+ static member_exprt
651
+ to_member (const exprt &pointer, const exprt &fieldref, const namespacet &ns)
645
652
{
646
653
struct_tag_typet class_type (fieldref.get (ID_class));
647
654
648
- const typecast_exprt pointer2 (pointer, java_reference_type (class_type));
655
+ const exprt typed_pointer =
656
+ typecast_exprt::conditional_cast (pointer, java_reference_type (class_type));
657
+
658
+ const irep_idt &component_name = fieldref.get (ID_component_name);
649
659
650
- dereference_exprt obj_deref=checked_dereference (pointer2, class_type);
660
+ exprt accessed_object = checked_dereference (typed_pointer, class_type);
661
+
662
+ // The field access is described as being against a particular type, but it
663
+ // may in fact belong to any ancestor type.
664
+ while (1 )
665
+ {
666
+ struct_typet object_type =
667
+ to_struct_type (ns.follow (accessed_object.type ()));
668
+ auto component = object_type.get_component (component_name);
651
669
652
- const member_exprt member_expr (
653
- obj_deref,
654
- fieldref.get (ID_component_name),
655
- fieldref.type ());
670
+ if (component.is_not_nil ())
671
+ return member_exprt (accessed_object, component);
656
672
657
- return member_expr;
673
+ // Component not present: check the immediate parent type.
674
+
675
+ const auto &components = object_type.components ();
676
+ INVARIANT (
677
+ components.size () != 0 ,
678
+ " infer_opaque_type_fields should guarantee that a member access has a "
679
+ " corresponding field" );
680
+
681
+ accessed_object = member_exprt (accessed_object, components.front ());
682
+ }
658
683
}
659
684
660
685
// / Find all goto statements in 'repl' that target 'old_label' and redirect them
@@ -1530,7 +1555,7 @@ code_blockt java_bytecode_convert_methodt::convert_instructions(
1530
1555
else if (statement==" getfield" )
1531
1556
{
1532
1557
PRECONDITION (op.size () == 1 && results.size () == 1 );
1533
- results[0 ]= java_bytecode_promotion (to_member (op[0 ], arg0));
1558
+ results[0 ] = java_bytecode_promotion (to_member (op[0 ], arg0, ns ));
1534
1559
}
1535
1560
else if (statement==" getstatic" )
1536
1561
{
@@ -2070,34 +2095,63 @@ void java_bytecode_convert_methodt::convert_invoke(
2070
2095
const bool is_virtual (
2071
2096
statement == " invokevirtual" || statement == " invokeinterface" );
2072
2097
2098
+ const irep_idt &invoked_method_id = arg0.get (ID_identifier);
2099
+ INVARIANT (
2100
+ !invoked_method_id.empty (),
2101
+ " invoke statement arg0 must have an identifier" );
2102
+
2103
+ auto method_symbol = symbol_table.symbols .find (invoked_method_id);
2104
+
2105
+ // Use the most precise type available: the actual symbol has generic info,
2106
+ // whereas the type given by the invoke instruction doesn't and is therefore
2107
+ // less accurate.
2108
+ if (method_symbol != symbol_table.symbols .end ())
2109
+ {
2110
+ const auto &restored_type =
2111
+ original_return_type (symbol_table, invoked_method_id);
2112
+ // Note the number of parameters might change here due to constructors using
2113
+ // invokespecial will have zero arguments (the `this` is added below)
2114
+ // but the symbol for the <init> will have the this parameter.
2115
+ INVARIANT (
2116
+ to_java_method_type (arg0.type ()).return_type ().id () ==
2117
+ restored_type.return_type ().id (),
2118
+ " Function return type must not change in kind" );
2119
+ arg0.type () = restored_type;
2120
+ }
2121
+
2122
+ // Note arg0 and arg0.type() are subject to many side-effects in this method,
2123
+ // then finally used to populate the call instruction.
2073
2124
java_method_typet &method_type = to_java_method_type (arg0.type ());
2125
+
2074
2126
java_method_typet::parameterst ¶meters (method_type.parameters ());
2075
2127
2076
2128
if (use_this)
2077
2129
{
2130
+ irep_idt classname = arg0.get (ID_C_class);
2131
+
2078
2132
if (parameters.empty () || !parameters[0 ].get_this ())
2079
2133
{
2080
- irep_idt classname = arg0.get (ID_C_class);
2081
2134
typet thistype = struct_tag_typet (classname);
2082
- // Note invokespecial is used for super-method calls as well as
2083
- // constructors.
2084
- if (statement == " invokespecial" )
2085
- {
2086
- if (is_constructor (arg0.get (ID_identifier)))
2087
- {
2088
- if (needed_lazy_methods)
2089
- needed_lazy_methods->add_needed_class (classname);
2090
- method_type.set_is_constructor ();
2091
- }
2092
- else
2093
- method_type.set (ID_java_super_method_call, true );
2094
- }
2095
2135
reference_typet object_ref_type = java_reference_type (thistype);
2096
2136
java_method_typet::parametert this_p (object_ref_type);
2097
2137
this_p.set_this ();
2098
2138
this_p.set_base_name (ID_this);
2099
2139
parameters.insert (parameters.begin (), this_p);
2100
2140
}
2141
+
2142
+ // Note invokespecial is used for super-method calls as well as
2143
+ // constructors.
2144
+ if (statement == " invokespecial" )
2145
+ {
2146
+ if (is_constructor (invoked_method_id))
2147
+ {
2148
+ if (needed_lazy_methods)
2149
+ needed_lazy_methods->add_needed_class (classname);
2150
+ method_type.set_is_constructor ();
2151
+ }
2152
+ else
2153
+ method_type.set (ID_java_super_method_call, true );
2154
+ }
2101
2155
}
2102
2156
2103
2157
code_function_callt call;
@@ -2160,18 +2214,17 @@ void java_bytecode_convert_methodt::convert_invoke(
2160
2214
// accessible from the original caller, but not from the generated test.
2161
2215
// Therefore we must assume that the method is not accessible.
2162
2216
// We set opaque methods as final to avoid assuming they can be overridden.
2163
- irep_idt id = arg0.get (ID_identifier);
2164
2217
if (
2165
- symbol_table. symbols . find (id) == symbol_table.symbols .end () &&
2218
+ method_symbol == symbol_table.symbols .end () &&
2166
2219
!(is_virtual &&
2167
2220
is_method_inherited (arg0.get (ID_C_class), arg0.get (ID_component_name))))
2168
2221
{
2169
2222
symbolt symbol;
2170
- symbol.name = id ;
2223
+ symbol.name = invoked_method_id ;
2171
2224
symbol.base_name = arg0.get (ID_C_base_name);
2172
2225
symbol.pretty_name = id2string (arg0.get (ID_C_class)).substr (6 ) + " ." +
2173
2226
id2string (symbol.base_name ) + " ()" ;
2174
- symbol.type = arg0. type () ;
2227
+ symbol.type = method_type ;
2175
2228
symbol.type .set (ID_access, ID_private);
2176
2229
to_java_method_type (symbol.type ).set_is_final (true );
2177
2230
symbol.value .make_nil ();
@@ -2196,10 +2249,10 @@ void java_bytecode_convert_methodt::convert_invoke(
2196
2249
else
2197
2250
{
2198
2251
// static binding
2199
- call.function () = symbol_exprt (arg0. get (ID_identifier), arg0. type () );
2252
+ call.function () = symbol_exprt (invoked_method_id, method_type );
2200
2253
if (needed_lazy_methods)
2201
2254
{
2202
- needed_lazy_methods->add_needed_method (arg0. get (ID_identifier) );
2255
+ needed_lazy_methods->add_needed_method (invoked_method_id );
2203
2256
// Calling a static method causes static initialization:
2204
2257
needed_lazy_methods->add_needed_class (arg0.get (ID_C_class));
2205
2258
}
@@ -2543,7 +2596,7 @@ code_blockt java_bytecode_convert_methodt::convert_putfield(
2543
2596
block,
2544
2597
bytecode_write_typet::FIELD,
2545
2598
arg0.get (ID_component_name));
2546
- block.add (code_assignt (to_member (op[0 ], arg0), op[1 ]));
2599
+ block.add (code_assignt (to_member (op[0 ], arg0, ns ), op[1 ]));
2547
2600
return block;
2548
2601
}
2549
2602
@@ -2918,8 +2971,7 @@ optionalt<exprt> java_bytecode_convert_methodt::convert_invoke_dynamic(
2918
2971
if (return_type.id () == ID_empty)
2919
2972
return {};
2920
2973
2921
- const auto value =
2922
- zero_initializer (return_type, location, namespacet (symbol_table));
2974
+ const auto value = zero_initializer (return_type, location, ns);
2923
2975
if (!value.has_value ())
2924
2976
{
2925
2977
error ().source_location = location;
0 commit comments