Skip to content

Commit e6e5134

Browse files
author
Thomas Kiley
authored
Merge pull request diffblue#1911 from thk123/bugfix/TG-2434/static-constructor-calling-opaque-constructor
[TG-2434] static constructor calling opaque constructor
2 parents 6505e8c + 1a89e97 commit e6e5134

11 files changed

+365
-56
lines changed

src/java_bytecode/java_bytecode_convert_method.cpp

+37-52
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,9 @@ static bool operator==(const irep_idt &what, const patternt &pattern)
120120
return pattern==what;
121121
}
122122

123-
// name contains <init> or <clinit>
124-
bool java_bytecode_convert_methodt::is_constructor(
125-
const class_typet::methodt &method)
123+
static bool is_constructor(const irep_idt &method_name)
126124
{
127-
const std::string &name(id2string(method.get_name()));
128-
const std::string::size_type &npos(std::string::npos);
129-
return npos!=name.find("<init>") || npos!=name.find("<clinit>");
125+
return id2string(method_name).find("<init>") != std::string::npos;
130126
}
131127

132128
exprt::operandst java_bytecode_convert_methodt::pop(std::size_t n)
@@ -256,11 +252,12 @@ const exprt java_bytecode_convert_methodt::variable(
256252
/// message handler to collect warnings
257253
/// \return
258254
/// the constructed member type
259-
typet member_type_lazy(const std::string &descriptor,
260-
const optionalt<std::string> &signature,
261-
const std::string &class_name,
262-
const std::string &method_name,
263-
message_handlert &message_handler)
255+
code_typet member_type_lazy(
256+
const std::string &descriptor,
257+
const optionalt<std::string> &signature,
258+
const std::string &class_name,
259+
const std::string &method_name,
260+
message_handlert &message_handler)
264261
{
265262
// In order to construct the method type, we can either use signature or
266263
// descriptor. Since only signature contains the generics info, we want to
@@ -285,7 +282,7 @@ typet member_type_lazy(const std::string &descriptor,
285282
if(to_code_type(member_type_from_signature).parameters().size()==
286283
to_code_type(member_type_from_descriptor).parameters().size())
287284
{
288-
return member_type_from_signature;
285+
return to_code_type(member_type_from_signature);
289286
}
290287
else
291288
{
@@ -303,7 +300,7 @@ typet member_type_lazy(const std::string &descriptor,
303300
<< descriptor << message.eom;
304301
}
305302
}
306-
return member_type_from_descriptor;
303+
return to_code_type(member_type_from_descriptor);
307304
}
308305

309306
/// This creates a method symbol in the symtab, but doesn't actually perform
@@ -324,7 +321,7 @@ void java_bytecode_convert_method_lazy(
324321
{
325322
symbolt method_symbol;
326323

327-
typet member_type=member_type_lazy(
324+
code_typet member_type = member_type_lazy(
328325
m.descriptor,
329326
m.signature,
330327
id2string(class_symbol.name),
@@ -337,20 +334,20 @@ void java_bytecode_convert_method_lazy(
337334
method_symbol.location=m.source_location;
338335
method_symbol.location.set_function(method_identifier);
339336
if(m.is_public)
340-
member_type.set(ID_access, ID_public);
337+
member_type.set_access(ID_public);
341338
else if(m.is_protected)
342-
member_type.set(ID_access, ID_protected);
339+
member_type.set_access(ID_protected);
343340
else if(m.is_private)
344-
member_type.set(ID_access, ID_private);
341+
member_type.set_access(ID_private);
345342
else
346-
member_type.set(ID_access, ID_default);
343+
member_type.set_access(ID_default);
347344

348-
if(method_symbol.base_name=="<init>")
345+
if(is_constructor(method_symbol.base_name))
349346
{
350347
method_symbol.pretty_name=
351348
id2string(class_symbol.pretty_name)+"."+
352349
id2string(class_symbol.base_name)+"()";
353-
member_type.set(ID_constructor, true);
350+
member_type.set_is_constructor();
354351
}
355352
else
356353
method_symbol.pretty_name=
@@ -360,8 +357,7 @@ void java_bytecode_convert_method_lazy(
360357
// do we need to add 'this' as a parameter?
361358
if(!m.is_static)
362359
{
363-
code_typet &code_type=to_code_type(member_type);
364-
code_typet::parameterst &parameters=code_type.parameters();
360+
code_typet::parameterst &parameters = member_type.parameters();
365361
code_typet::parametert this_p;
366362
const reference_typet object_ref_type=
367363
java_reference_type(symbol_typet(class_symbol.name));
@@ -390,9 +386,8 @@ void java_bytecode_convert_methodt::convert(
390386

391387
// Obtain a std::vector of code_typet::parametert objects from the
392388
// (function) type of the symbol
393-
typet member_type=method_symbol.type;
394-
member_type.set(ID_C_class, class_symbol.name);
395-
code_typet &code_type=to_code_type(member_type);
389+
code_typet code_type = to_code_type(method_symbol.type);
390+
code_type.set(ID_C_class, class_symbol.name);
396391
method_return_type=code_type.return_type();
397392
code_typet::parameterst &parameters=code_type.parameters();
398393

@@ -519,25 +514,12 @@ void java_bytecode_convert_methodt::convert(
519514
param_index==slots_for_parameters,
520515
"java_parameter_count and local computation must agree");
521516

522-
const bool is_virtual=!m.is_static && !m.is_final;
523-
524-
// Construct a methodt, which lives within the class type; this object is
525-
// never used for anything useful and could be removed
526-
class_typet::methodt method;
527-
method.set_base_name(m.base_name);
528-
method.set_name(method_identifier);
529-
method.set(ID_abstract, m.is_abstract);
530-
method.set(ID_is_virtual, is_virtual);
531-
method.type()=member_type;
532-
if(is_constructor(method))
533-
method.set(ID_constructor, true);
534-
535517
// Check the fields that can't change are valid
536518
INVARIANT(
537-
method_symbol.name==method.get_name(),
519+
method_symbol.name == method_identifier,
538520
"Name of method symbol shouldn't change");
539521
INVARIANT(
540-
method_symbol.base_name==method.get_base_name(),
522+
method_symbol.base_name == m.base_name,
541523
"Base name of method symbol shouldn't change");
542524
INVARIANT(
543525
method_symbol.module.empty(),
@@ -551,16 +533,21 @@ void java_bytecode_convert_methodt::convert(
551533
// The pretty name of a constructor includes the base name of the class
552534
// instead of the internal method name "<init>". For regular methods, it's
553535
// just the base name of the method.
554-
if(method.get_base_name()=="<init>")
555-
method_symbol.pretty_name=id2string(class_symbol.pretty_name)+"."+
556-
id2string(class_symbol.base_name)+"()";
536+
if(is_constructor(method_symbol.base_name))
537+
{
538+
method_symbol.pretty_name = id2string(class_symbol.pretty_name) + "." +
539+
id2string(class_symbol.base_name) + "()";
540+
INVARIANT(
541+
code_type.get_is_constructor(),
542+
"Member type should have already been marked as a constructor");
543+
}
557544
else
558-
method_symbol.pretty_name=id2string(class_symbol.pretty_name)+"."+
559-
id2string(method.get_base_name())+"()";
545+
{
546+
method_symbol.pretty_name = id2string(class_symbol.pretty_name) + "." +
547+
id2string(method_symbol.base_name) + "()";
548+
}
560549

561-
method_symbol.type=member_type;
562-
if(is_constructor(method))
563-
method_symbol.type.set(ID_constructor, true);
550+
method_symbol.type = code_type;
564551

565552
current_method=method_symbol.name;
566553
method_has_this=code_type.has_this();
@@ -1280,13 +1267,11 @@ codet java_bytecode_convert_methodt::convert_instructions(
12801267
// constructors.
12811268
if(statement=="invokespecial")
12821269
{
1283-
if(
1284-
id2string(arg0.get(ID_identifier)).find("<init>") !=
1285-
std::string::npos)
1270+
if(is_constructor(arg0.get(ID_identifier)))
12861271
{
12871272
if(needed_lazy_methods)
12881273
needed_lazy_methods->add_needed_class(classname);
1289-
code_type.set(ID_constructor, true);
1274+
code_type.set_is_constructor();
12901275
}
12911276
else
12921277
code_type.set(ID_java_super_method_call, true);

src/java_bytecode/java_bytecode_convert_method_class.h

-4
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,6 @@ class java_bytecode_convert_methodt:public messaget
161161
void pop_residue(std::size_t n);
162162
void push(const exprt::operandst &o);
163163

164-
/// Determines whether the `method` is a constructor or a static initializer,
165-
/// by checking whether its name equals either <init> or <clinit>
166-
bool is_constructor(const class_typet::methodt &method);
167-
168164
/// Returns true iff the slot index of the local variable of a method (coming
169165
/// from the LVT) is a parameter of that method. Assumes that
170166
/// `slots_for_parameters` is initialized upon call.

src/util/std_types.h

+10
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,16 @@ class code_typet:public typet
889889
return set(ID_access, access);
890890
}
891891

892+
bool get_is_constructor() const
893+
{
894+
return get_bool(ID_constructor);
895+
}
896+
897+
void set_is_constructor()
898+
{
899+
set(ID_constructor, true);
900+
}
901+
892902
// this produces the list of parameter identifiers
893903
std::vector<irep_idt> parameter_identifiers() const
894904
{
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
class ClassWithConstructors {
2+
public ClassWithConstructors() {
3+
4+
}
5+
6+
public ClassWithConstructors(int primitiveParam, Object referenceParam, OpaqueClass opaqueParam) {
7+
8+
}
9+
}
10+
11+
class ClassWithoutConstructors {
12+
13+
}
14+
15+
class ClassWithStaticConstructor {
16+
static int primitiveA = 4;
17+
static int primitiveB;
18+
static int primitiveC;
19+
static Object referenceA = new Object();
20+
static Object referenceB;
21+
static Object referenceC;
22+
23+
static {
24+
primitiveB = 5;
25+
referenceB = new Object();
26+
}
27+
28+
public ClassWithStaticConstructor() {
29+
30+
}
31+
32+
public ClassWithStaticConstructor(int primitiveParam, Object referenceParam, OpaqueClass opaqueParam) {
33+
34+
}
35+
}
36+
37+
class StaticClassUsingOpaqueStaticConstructor {
38+
static int primitiveA = OpaqueClass.primitiveA;
39+
static int primitiveB = OpaqueClass.primitiveB;
40+
static int primitiveC = OpaqueClass.primitiveC;
41+
static Object referenceA = OpaqueClass.referenceA;
42+
static Object referenceB = OpaqueClass.referenceB;
43+
static Object referenceC = OpaqueClass.referenceC;
44+
}
45+
46+
class ClassUsingOpaqueStaticConstructor {
47+
int primitiveA;
48+
int primitiveB;
49+
int primitiveC;
50+
Object referenceA;
51+
Object referenceB;
52+
Object referenceC;
53+
54+
public ClassUsingOpaqueStaticConstructor(){
55+
primitiveA = OpaqueClass.primitiveA;
56+
primitiveB = OpaqueClass.primitiveB;
57+
primitiveC = OpaqueClass.primitiveC;
58+
referenceA = OpaqueClass.referenceA;
59+
referenceB = OpaqueClass.referenceB;
60+
referenceC = OpaqueClass.referenceC;
61+
}
62+
}
63+
64+
class DummyClassLoadingOpaqueClass {
65+
DummyClassLoadingOpaqueClass() {
66+
OpaqueClass o = new OpaqueClass();
67+
int primitiveA = OpaqueClass.primitiveA;
68+
int primitiveB = OpaqueClass.primitiveB;
69+
int primitiveC = OpaqueClass.primitiveC;
70+
Object referenceA = OpaqueClass.referenceA;
71+
Object referenceB = OpaqueClass.referenceB;
72+
Object referenceC = OpaqueClass.referenceC;
73+
74+
}
75+
}
76+
77+
class OpaqueClass {
78+
static int primitiveA = 4;
79+
static int primitiveB;
80+
static int primitiveC;
81+
static Object referenceA = new Object();
82+
static Object referenceB;
83+
static Object referenceC;
84+
85+
static {
86+
primitiveB = 5;
87+
referenceB = new Object();
88+
}
89+
90+
public OpaqueClass() {
91+
// opaque constructor
92+
}
93+
}

0 commit comments

Comments
 (0)