@@ -195,6 +195,67 @@ bool java_bytecode_languaget::parse(
195
195
return false ;
196
196
}
197
197
198
+ // / Infer fields that must exist on opaque types from field accesses against
199
+ // / them. Note that we don't yet try to infer inheritence between opaque types
200
+ // / here, so we may introduce the same field onto a type and its ancestor
201
+ // / without realising that is in fact the same field, inherited from that
202
+ // / ancestor. This can lead to incorrect results when opaque types are cast
203
+ // / to other opaque types and their fields do not alias as intended.
204
+ // / \param parse_tree: class parse tree
205
+ // / \param symbol_table: global symbol table
206
+ static void infer_opaque_type_fields (
207
+ const java_bytecode_parse_treet &parse_tree,
208
+ symbol_tablet &symbol_table)
209
+ {
210
+ namespacet ns (symbol_table);
211
+ for (const auto &method : parse_tree.parsed_class .methods )
212
+ {
213
+ for (const auto &instruction : method.instructions )
214
+ {
215
+ if (instruction.statement == " getfield" ||
216
+ instruction.statement == " putfield" )
217
+ {
218
+ const exprt &fieldref = instruction.args [0 ];
219
+ const symbolt *class_symbol =
220
+ symbol_table.lookup (fieldref.get (ID_class));
221
+ INVARIANT (
222
+ class_symbol != nullptr , " all field types should have been loaded" );
223
+
224
+ const class_typet *class_type = &to_class_type (class_symbol->type );
225
+ irep_idt class_symbol_id = fieldref.get (ID_class);
226
+ const irep_idt &component_name = fieldref.get (ID_component_name);
227
+ while (!class_type->has_component (component_name))
228
+ {
229
+ if (class_type->get_bool (ID_incomplete_class))
230
+ {
231
+ // Accessing a field of an incomplete (opaque) type.
232
+ symbolt &writable_class_symbol =
233
+ symbol_table.get_writeable_ref (class_symbol_id);
234
+ auto &add_to_components =
235
+ to_struct_type (writable_class_symbol.type ).components ();
236
+ add_to_components.push_back (
237
+ struct_typet::componentt (component_name, fieldref.type ()));
238
+ add_to_components.back ().set_base_name (component_name);
239
+ add_to_components.back ().set_pretty_name (component_name);
240
+ break ;
241
+ }
242
+ else
243
+ {
244
+ // Not present here: check the superclass.
245
+ INVARIANT (
246
+ class_type->bases ().size () != 0 ,
247
+ " class missing an expected field should have a superclass" );
248
+ const symbol_typet &superclass_type =
249
+ to_symbol_type (class_type->bases ()[0 ].type ());
250
+ class_symbol_id = superclass_type.get_identifier ();
251
+ class_type = &to_class_type (ns.follow (superclass_type));
252
+ }
253
+ }
254
+ }
255
+ }
256
+ }
257
+ }
258
+
198
259
bool java_bytecode_languaget::typecheck (
199
260
symbol_tablet &symbol_table,
200
261
const std::string &module)
@@ -248,6 +309,14 @@ bool java_bytecode_languaget::typecheck(
248
309
}
249
310
}
250
311
312
+ // Infer fields on opaque types based on the method instructions just loaded.
313
+ // For example, if we don't have bytecode for field x of class A, but we can
314
+ // see an int-typed getfield instruction referring to it, add that field now.
315
+ for (const auto &c : java_class_loader.class_map )
316
+ {
317
+ infer_opaque_type_fields (c.second , symbol_table);
318
+ }
319
+
251
320
// Now incrementally elaborate methods
252
321
// that are reachable from this entry point.
253
322
if (lazy_methods_mode==LAZY_METHODS_MODE_CONTEXT_INSENSITIVE)
0 commit comments