Skip to content

Commit 9892924

Browse files
authored
Merge pull request #6093 from tautschnig/java_static_init
java_static_lifetime_init: Deterministic order of initialisation
2 parents b1f1e81 + 3258d81 commit 9892924

File tree

1 file changed

+141
-109
lines changed

1 file changed

+141
-109
lines changed

jbmc/src/java_bytecode/java_entry_point.cpp

Lines changed: 141 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,125 @@ static constant_exprt constant_bool(bool val)
106106
return from_integer(val ? 1 : 0, java_boolean_type());
107107
}
108108

109+
static std::unordered_set<irep_idt> init_symbol(
110+
const symbolt &sym,
111+
code_blockt &code_block,
112+
symbol_table_baset &symbol_table,
113+
const source_locationt &source_location,
114+
bool assume_init_pointers_not_null,
115+
const java_object_factory_parameterst &object_factory_parameters,
116+
const select_pointer_typet &pointer_type_selector,
117+
bool string_refinement_enabled,
118+
message_handlert &message_handler)
119+
{
120+
std::unordered_set<irep_idt> additional_symbols;
121+
122+
if(
123+
const symbolt *class_literal_init_method =
124+
get_class_literal_initializer(sym, symbol_table))
125+
{
126+
const std::string &name_str = id2string(sym.name);
127+
irep_idt class_name =
128+
name_str.substr(0, name_str.size() - strlen(JAVA_CLASS_MODEL_SUFFIX));
129+
const symbolt &class_symbol = symbol_table.lookup_ref(class_name);
130+
131+
bool class_is_array = is_java_array_tag(sym.name);
132+
133+
journalling_symbol_tablet journalling_table =
134+
journalling_symbol_tablet::wrap(symbol_table);
135+
136+
symbol_exprt class_name_literal = get_or_create_string_literal_symbol(
137+
to_class_type(class_symbol.type).get_tag(),
138+
journalling_table,
139+
string_refinement_enabled);
140+
141+
// If that created any new symbols make sure we initialise those too:
142+
additional_symbols = journalling_table.get_inserted();
143+
144+
// Call the literal initializer method instead of a nondet initializer:
145+
146+
// For arguments we can't parse yet:
147+
side_effect_expr_nondett nondet_bool(java_boolean_type(), sym.location);
148+
149+
const auto &java_class_type = to_java_class_type(class_symbol.type);
150+
151+
// Argument order is: name, isAnnotation, isArray, isInterface,
152+
// isSynthetic, isLocalClass, isMemberClass, isEnum
153+
154+
code_function_callt initializer_call(
155+
class_literal_init_method->symbol_expr(),
156+
{// this:
157+
address_of_exprt(sym.symbol_expr()),
158+
// name:
159+
address_of_exprt(class_name_literal),
160+
// isAnnotation:
161+
constant_bool(java_class_type.get_is_annotation()),
162+
// isArray:
163+
constant_bool(class_is_array),
164+
// isInterface:
165+
constant_bool(java_class_type.get_interface()),
166+
// isSynthetic:
167+
constant_bool(java_class_type.get_synthetic()),
168+
// isLocalClass:
169+
nondet_bool,
170+
// isMemberClass:
171+
nondet_bool,
172+
// isEnum:
173+
constant_bool(java_class_type.get_is_enumeration())});
174+
175+
// First initialize the object as prior to a constructor:
176+
namespacet ns(symbol_table);
177+
178+
auto zero_object = zero_initializer(sym.type, source_locationt(), ns);
179+
if(!zero_object.has_value())
180+
{
181+
messaget message(message_handler);
182+
message.error() << "failed to zero-initialize " << sym.name
183+
<< messaget::eom;
184+
throw 0;
185+
}
186+
set_class_identifier(
187+
to_struct_expr(*zero_object), ns, to_struct_tag_type(sym.type));
188+
189+
code_block.add(
190+
std::move(code_frontend_assignt(sym.symbol_expr(), *zero_object)));
191+
192+
// Then call the init function:
193+
code_block.add(std::move(initializer_call));
194+
}
195+
else if(sym.value.is_nil() && sym.type != java_void_type())
196+
{
197+
const bool is_class_model = has_suffix(id2string(sym.name), "@class_model");
198+
const bool not_allow_null = is_java_string_literal_id(sym.name) ||
199+
is_non_null_library_global(sym.name) ||
200+
assume_init_pointers_not_null;
201+
202+
java_object_factory_parameterst parameters = object_factory_parameters;
203+
if(not_allow_null && !is_class_model)
204+
parameters.min_null_tree_depth = 1;
205+
206+
gen_nondet_init(
207+
sym.symbol_expr(),
208+
code_block,
209+
symbol_table,
210+
source_location,
211+
false,
212+
lifetimet::STATIC_GLOBAL,
213+
parameters,
214+
pointer_type_selector,
215+
update_in_placet::NO_UPDATE_IN_PLACE,
216+
message_handler);
217+
}
218+
else if(sym.value.is_not_nil())
219+
{
220+
code_frontend_assignt assignment(sym.symbol_expr(), sym.value);
221+
assignment.add_source_location() = source_location;
222+
code_block.add(assignment);
223+
}
224+
225+
return additional_symbols;
226+
}
227+
109228
void java_static_lifetime_init(
110229
symbol_table_baset &symbol_table,
111230
const source_locationt &source_location,
@@ -142,127 +261,40 @@ void java_static_lifetime_init(
142261
// external. Iterate over a copy of the symtab, as its iterators are
143262
// invalidated by object_factory:
144263

145-
std::list<irep_idt> symbol_names;
264+
// sort alphabetically for reproducible results
265+
std::set<std::string> symbol_names;
146266
for(const auto &entry : symbol_table.symbols)
147-
symbol_names.push_back(entry.first);
148-
149-
// Don't use a for-each loop here because the loop extends the list, and the
150-
// for-each loop may only read `.end()` once.
151-
for(
152-
auto symbol_it = symbol_names.begin();
153-
symbol_it != symbol_names.end();
154-
++symbol_it)
267+
symbol_names.insert(id2string(entry.first));
268+
269+
std::set<std::string> additional_symbols;
270+
while(!symbol_names.empty() || !additional_symbols.empty())
155271
{
156-
const auto &symname = *symbol_it;
157-
const symbolt &sym = symbol_table.lookup_ref(symname);
158-
if(should_init_symbol(sym))
272+
if(!additional_symbols.empty())
273+
symbol_names.swap(additional_symbols);
274+
275+
for(const auto &symbol_name : symbol_names)
159276
{
160-
if(const symbolt *class_literal_init_method =
161-
get_class_literal_initializer(sym, symbol_table))
162-
{
163-
const std::string &name_str = id2string(sym.name);
164-
irep_idt class_name =
165-
name_str.substr(0, name_str.size() - strlen(JAVA_CLASS_MODEL_SUFFIX));
166-
const symbolt &class_symbol = symbol_table.lookup_ref(class_name);
167-
168-
bool class_is_array = is_java_array_tag(sym.name);
169-
170-
journalling_symbol_tablet journalling_table =
171-
journalling_symbol_tablet::wrap(symbol_table);
172-
173-
symbol_exprt class_name_literal = get_or_create_string_literal_symbol(
174-
to_class_type(class_symbol.type).get_tag(),
175-
journalling_table,
176-
string_refinement_enabled);
177-
178-
// If that created any new symbols make sure we initialise those too:
179-
const auto &new_symbols = journalling_table.get_inserted();
180-
symbol_names.insert(
181-
symbol_names.end(), new_symbols.begin(), new_symbols.end());
182-
183-
// Call the literal initializer method instead of a nondet initializer:
184-
185-
// For arguments we can't parse yet:
186-
side_effect_expr_nondett nondet_bool(java_boolean_type(), sym.location);
187-
188-
const auto &java_class_type = to_java_class_type(class_symbol.type);
189-
190-
// Argument order is: name, isAnnotation, isArray, isInterface,
191-
// isSynthetic, isLocalClass, isMemberClass, isEnum
192-
193-
code_function_callt initializer_call(
194-
class_literal_init_method->symbol_expr(),
195-
{// this:
196-
address_of_exprt(sym.symbol_expr()),
197-
// name:
198-
address_of_exprt(class_name_literal),
199-
// isAnnotation:
200-
constant_bool(java_class_type.get_is_annotation()),
201-
// isArray:
202-
constant_bool(class_is_array),
203-
// isInterface:
204-
constant_bool(java_class_type.get_interface()),
205-
// isSynthetic:
206-
constant_bool(java_class_type.get_synthetic()),
207-
// isLocalClass:
208-
nondet_bool,
209-
// isMemberClass:
210-
nondet_bool,
211-
// isEnum:
212-
constant_bool(java_class_type.get_is_enumeration())});
213-
214-
// First initialize the object as prior to a constructor:
215-
namespacet ns(symbol_table);
216-
217-
auto zero_object = zero_initializer(sym.type, source_locationt(), ns);
218-
if(!zero_object.has_value())
219-
{
220-
messaget message(message_handler);
221-
message.error() << "failed to zero-initialize " << sym.name
222-
<< messaget::eom;
223-
throw 0;
224-
}
225-
set_class_identifier(
226-
to_struct_expr(*zero_object), ns, to_struct_tag_type(sym.type));
227-
228-
code_block.add(
229-
std::move(code_frontend_assignt(sym.symbol_expr(), *zero_object)));
230-
231-
// Then call the init function:
232-
code_block.add(std::move(initializer_call));
233-
}
234-
else if(sym.value.is_nil() && sym.type != java_void_type())
277+
const symbolt &sym = symbol_table.lookup_ref(symbol_name);
278+
if(should_init_symbol(sym))
235279
{
236-
const bool is_class_model =
237-
has_suffix(id2string(sym.name), "@class_model");
238-
const bool not_allow_null = is_java_string_literal_id(sym.name) ||
239-
is_non_null_library_global(sym.name) ||
240-
assume_init_pointers_not_null;
241-
242-
java_object_factory_parameterst parameters = object_factory_parameters;
243-
if(not_allow_null && !is_class_model)
244-
parameters.min_null_tree_depth = 1;
245-
246-
gen_nondet_init(
247-
sym.symbol_expr(),
280+
auto new_symbols = init_symbol(
281+
sym,
248282
code_block,
249283
symbol_table,
250284
source_location,
251-
false,
252-
lifetimet::STATIC_GLOBAL,
253-
parameters,
285+
assume_init_pointers_not_null,
286+
object_factory_parameters,
254287
pointer_type_selector,
255-
update_in_placet::NO_UPDATE_IN_PLACE,
288+
string_refinement_enabled,
256289
message_handler);
257-
}
258-
else if(sym.value.is_not_nil())
259-
{
260-
code_frontend_assignt assignment(sym.symbol_expr(), sym.value);
261-
assignment.add_source_location()=source_location;
262-
code_block.add(assignment);
290+
for(const auto &new_symbol_name : new_symbols)
291+
additional_symbols.insert(id2string(new_symbol_name));
263292
}
264293
}
294+
295+
symbol_names.clear();
265296
}
297+
266298
initialize_symbol.value = std::move(code_block);
267299
}
268300

0 commit comments

Comments
 (0)