Skip to content

Commit fdb2ebc

Browse files
authored
Merge pull request diffblue#1773 from smowton/smowton/feature/string-solver-ensure-class-graph-consistency
Java string solver: ensure base types are loaded
2 parents 1e17db6 + ceafd85 commit fdb2ebc

5 files changed

+78
-14
lines changed

src/java_bytecode/java_bytecode_language.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,16 @@ bool java_bytecode_languaget::parse(
147147
java_class_loader.set_message_handler(get_message_handler());
148148
java_class_loader.set_java_cp_include_files(java_cp_include_files);
149149
java_class_loader.add_load_classes(java_load_classes);
150+
if(string_refinement_enabled)
151+
{
152+
string_preprocess.initialize_known_type_table();
153+
154+
auto get_string_base_classes = [this](const irep_idt &id) { // NOLINT (*)
155+
return string_preprocess.get_string_type_base_classes(id);
156+
};
157+
158+
java_class_loader.set_extra_class_refs_function(get_string_base_classes);
159+
}
150160

151161
// look at extension
152162
if(has_suffix(path, ".class"))

src/java_bytecode/java_class_loader.cpp

+20
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,16 @@ java_bytecode_parse_treet &java_class_loadert::operator()(
7272
it!=parse_tree.class_refs.end();
7373
it++)
7474
queue.push(*it);
75+
76+
// Add any extra dependencies provided by our caller:
77+
if(get_extra_class_refs)
78+
{
79+
std::vector<irep_idt> extra_class_refs =
80+
get_extra_class_refs(c);
81+
82+
for(const irep_idt &id : extra_class_refs)
83+
queue.push(id);
84+
}
7585
}
7686

7787
return class_map[class_name];
@@ -83,6 +93,16 @@ void java_class_loadert::set_java_cp_include_files(
8393
java_cp_include_files=_java_cp_include_files;
8494
}
8595

96+
/// Sets a function that provides extra dependencies for a particular class.
97+
/// Currently used by the string preprocessor to note that even if we don't
98+
/// have a definition of core string types, it will nontheless give them
99+
/// certain known superclasses and interfaces, such as Serializable.
100+
void java_class_loadert::set_extra_class_refs_function(
101+
java_class_loadert::get_extra_class_refs_functiont func)
102+
{
103+
get_extra_class_refs = func;
104+
}
105+
86106
/// Retrieves a class file from a jar and loads it into the tree
87107
bool java_class_loadert::get_class_file(
88108
java_class_loader_limitt &class_loader_limit,

src/java_bytecode/java_class_loader.h

+7
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ class java_class_loadert:public messaget
3434
void set_java_cp_include_files(std::string &);
3535
void add_load_classes(const std::vector<irep_idt> &);
3636

37+
/// A function that yields a list of extra dependencies based on a class name.
38+
typedef std::function<std::vector<irep_idt>(const irep_idt &)>
39+
get_extra_class_refs_functiont;
40+
41+
void set_extra_class_refs_function(get_extra_class_refs_functiont func);
42+
3743
static std::string file_to_class_name(const std::string &);
3844
static std::string class_name_to_file(const irep_idt &);
3945

@@ -133,6 +139,7 @@ class java_class_loadert:public messaget
133139
private:
134140
std::map<std::string, jar_filet> m_archives;
135141
std::vector<irep_idt> java_load_classes;
142+
get_extra_class_refs_functiont get_extra_class_refs;
136143
};
137144

138145
#endif // CPROVER_JAVA_BYTECODE_JAVA_CLASS_LOADER_H

src/java_bytecode/java_string_library_preprocess.cpp

+38-14
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,34 @@ typet string_length_type()
186186
return java_int_type();
187187
}
188188

189+
/// Gets the base classes for known String and String-related types, or returns
190+
/// an empty list for other types.
191+
/// \param class_name: class identifier, without "java::" prefix.
192+
/// \return a list of base classes, again without "java::" prefix.
193+
std::vector<irep_idt>
194+
java_string_library_preprocesst::get_string_type_base_classes(
195+
const irep_idt &class_name)
196+
{
197+
if(!is_known_string_type(class_name))
198+
return {};
199+
200+
std::vector<irep_idt> bases;
201+
bases.reserve(3);
202+
if(class_name != "java.lang.CharSequence")
203+
{
204+
bases.push_back("java.io.Serializable");
205+
bases.push_back("java.lang.CharSequence");
206+
}
207+
if(class_name == "java.lang.String")
208+
bases.push_back("java.lang.Comparable");
209+
210+
if(class_name == "java.lang.StringBuilder" ||
211+
class_name == "java.lang.StringBuffer")
212+
bases.push_back("java.lang.AbstractStringBuilder");
213+
214+
return bases;
215+
}
216+
189217
/// Add to the symbol table type declaration for a String-like Java class.
190218
/// \param class_name: a name for the class such as "java.lang.String"
191219
/// \param symbol_table: symbol table to which the class will be added
@@ -206,17 +234,10 @@ void java_string_library_preprocesst::add_string_type(
206234
string_type.components()[2].type() = pointer_type(java_char_type());
207235
string_type.set_access(ID_public);
208236
string_type.add_base(symbol_typet("java::java.lang.Object"));
209-
if(class_name!="java.lang.CharSequence")
210-
{
211-
string_type.add_base(symbol_typet("java::java.io.Serializable"));
212-
string_type.add_base(symbol_typet("java::java.lang.CharSequence"));
213-
}
214-
if(class_name=="java.lang.String")
215-
string_type.add_base(symbol_typet("java::java.lang.Comparable"));
216237

217-
if(class_name=="java.lang.StringBuilder" ||
218-
class_name=="java.lang.StringBuffer")
219-
string_type.add_base(symbol_typet("java::java.lang.AbstractStringBuilder"));
238+
std::vector<irep_idt> bases = get_string_type_base_classes(class_name);
239+
for(const irep_idt &base_name : bases)
240+
string_type.add_base(symbol_typet("java::" + id2string(base_name)));
220241

221242
symbolt tmp_string_symbol;
222243
tmp_string_symbol.name="java::"+id2string(class_name);
@@ -1848,16 +1869,19 @@ bool java_string_library_preprocesst::is_known_string_type(
18481869
return string_types.find(class_name)!=string_types.end();
18491870
}
18501871

1851-
/// fill maps with correspondence from java method names to conversion functions
1852-
void java_string_library_preprocesst::initialize_conversion_table()
1872+
void java_string_library_preprocesst::initialize_known_type_table()
18531873
{
1854-
character_preprocess.initialize_conversion_table();
1855-
18561874
string_types=
18571875
std::unordered_set<irep_idt, irep_id_hash>{"java.lang.String",
18581876
"java.lang.StringBuilder",
18591877
"java.lang.CharSequence",
18601878
"java.lang.StringBuffer"};
1879+
}
1880+
1881+
/// fill maps with correspondence from java method names to conversion functions
1882+
void java_string_library_preprocesst::initialize_conversion_table()
1883+
{
1884+
character_preprocess.initialize_conversion_table();
18611885

18621886
// The following list of function is organized by libraries, with
18631887
// constructors first and then methods in alphabetic order.

src/java_bytecode/java_string_library_preprocess.h

+3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class java_string_library_preprocesst:public messaget
4343
{
4444
}
4545

46+
void initialize_known_type_table();
4647
void initialize_conversion_table();
4748
void initialize_refined_string_type();
4849

@@ -56,6 +57,8 @@ class java_string_library_preprocesst:public messaget
5657
{
5758
return character_preprocess.replace_character_call(call);
5859
}
60+
std::vector<irep_idt> get_string_type_base_classes(
61+
const irep_idt &class_name);
5962
void add_string_type(const irep_idt &class_name, symbol_tablet &symbol_table);
6063
bool is_known_string_type(irep_idt class_name);
6164

0 commit comments

Comments
 (0)