Skip to content

Commit ade4e66

Browse files
committed
Use c nondet object factory in function body generation
This removes the existing code in the function body generation for havoc-ing objects (in havoc_expr_rec()) and replaces it with calls to the c nondet symbol factory (gen_nondet_init()).
1 parent 3e4701a commit ade4e66

File tree

2 files changed

+66
-103
lines changed

2 files changed

+66
-103
lines changed

src/goto-instrument/generate_function_bodies.cpp

Lines changed: 65 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class assume_false_generate_function_bodiest : public generate_function_bodiest
6868
protected:
6969
void generate_function_body_impl(
7070
goto_functiont &function,
71-
const symbol_tablet &symbol_table,
71+
symbol_tablet &symbol_table,
7272
const irep_idt &function_name) const override
7373
{
7474
auto const &function_symbol = symbol_table.lookup_ref(function_name);
@@ -91,7 +91,7 @@ class assert_false_generate_function_bodiest : public generate_function_bodiest
9191
protected:
9292
void generate_function_body_impl(
9393
goto_functiont &function,
94-
const symbol_tablet &symbol_table,
94+
symbol_tablet &symbol_table,
9595
const irep_idt &function_name) const override
9696
{
9797
auto const &function_symbol = symbol_table.lookup_ref(function_name);
@@ -122,7 +122,7 @@ class assert_false_then_assume_false_generate_function_bodiest
122122
protected:
123123
void generate_function_body_impl(
124124
goto_functiont &function,
125-
const symbol_tablet &symbol_table,
125+
symbol_tablet &symbol_table,
126126
const irep_idt &function_name) const override
127127
{
128128
auto const &function_symbol = symbol_table.lookup_ref(function_name);
@@ -150,8 +150,7 @@ class assert_false_then_assume_false_generate_function_bodiest
150150
}
151151
};
152152

153-
class havoc_generate_function_bodiest : public generate_function_bodiest,
154-
private messaget
153+
class havoc_generate_function_bodiest : public generate_function_bodiest
155154
{
156155
public:
157156
havoc_generate_function_bodiest(
@@ -160,107 +159,52 @@ class havoc_generate_function_bodiest : public generate_function_bodiest,
160159
const c_object_factory_parameterst &object_factory_parameters,
161160
message_handlert &message_handler)
162161
: generate_function_bodiest(),
163-
messaget(message_handler),
164162
globals_to_havoc(std::move(globals_to_havoc)),
165163
parameters_to_havoc(std::move(parameters_to_havoc)),
166-
object_factory_parameters(object_factory_parameters)
164+
object_factory_parameters(object_factory_parameters),
165+
message(message_handler)
167166
{
168167
}
169168

170169
private:
171170
void havoc_expr_rec(
172171
const exprt &lhs,
173-
const namespacet &ns,
174-
const std::function<goto_programt::targett(void)> &add_instruction,
175-
const irep_idt &function_name) const
172+
const std::size_t initial_depth,
173+
const source_locationt &source_location,
174+
symbol_tablet &symbol_table,
175+
goto_programt &dest) const
176176
{
177-
// resolve type symbols
178-
auto const lhs_type = ns.follow(lhs.type());
179-
// skip constants
180-
if(!lhs_type.get_bool(ID_C_constant))
181-
{
182-
// expand arrays, structs and union, everything else gets
183-
// assigned nondet
184-
if(lhs_type.id() == ID_struct || lhs_type.id() == ID_union)
185-
{
186-
// Note: In the case of unions it's often enough to assign
187-
// just one member; However consider a case like
188-
// union { struct { const int x; int y; } a;
189-
// struct { int x; const int y; } b;};
190-
// in this case both a.y and b.x must be assigned
191-
// otherwise these parts stay constant even though
192-
// they could've changed (note that type punning through
193-
// unions is allowed in the C standard but forbidden in C++)
194-
// so we're assigning all members even in the case of
195-
// unions just to be safe
196-
auto const lhs_struct_type = to_struct_union_type(lhs_type);
197-
for(auto const &component : lhs_struct_type.components())
198-
{
199-
havoc_expr_rec(
200-
member_exprt(lhs, component.get_name(), component.type()),
201-
ns,
202-
add_instruction,
203-
function_name);
204-
}
205-
}
206-
else if(lhs_type.id() == ID_array)
207-
{
208-
auto const lhs_array_type = to_array_type(lhs_type);
209-
if(!lhs_array_type.subtype().get_bool(ID_C_constant))
210-
{
211-
bool constant_known_array_size = lhs_array_type.size().is_constant();
212-
if(!constant_known_array_size)
213-
{
214-
warning() << "Cannot havoc non-const array " << format(lhs)
215-
<< " in function " << function_name
216-
<< ": Unknown array size" << eom;
217-
}
218-
else
219-
{
220-
auto const array_size =
221-
numeric_cast<mp_integer>(lhs_array_type.size());
222-
INVARIANT(
223-
array_size.has_value(),
224-
"Array size should be known constant integer");
225-
if(array_size.value() == 0)
226-
{
227-
// Pretty much the same thing as a unknown size array
228-
// Technically not allowed by the C standard, but we model
229-
// unknown size arrays in structs this way
230-
warning() << "Cannot havoc non-const array " << format(lhs)
231-
<< " in function " << function_name << ": Array size 0"
232-
<< eom;
233-
}
234-
else
235-
{
236-
for(mp_integer i = 0; i < array_size.value(); ++i)
237-
{
238-
auto const index =
239-
from_integer(i, lhs_array_type.size().type());
240-
havoc_expr_rec(
241-
index_exprt(lhs, index, lhs_array_type.subtype()),
242-
ns,
243-
add_instruction,
244-
function_name);
245-
}
246-
}
247-
}
248-
}
249-
}
250-
else
251-
{
252-
auto assign_instruction = add_instruction();
253-
assign_instruction->make_assignment(
254-
code_assignt(
255-
lhs, side_effect_expr_nondett(lhs_type, lhs.source_location())));
256-
}
257-
}
177+
symbol_factoryt symbol_factory(
178+
symbol_table,
179+
source_location,
180+
object_factory_parameters,
181+
lifetimet::DYNAMIC);
182+
183+
code_blockt assignments;
184+
185+
symbol_factory.gen_nondet_init(
186+
assignments,
187+
lhs,
188+
initial_depth,
189+
symbol_factoryt::recursion_sett(),
190+
false); // do not initialize const objects at the top level
191+
192+
code_blockt init_code;
193+
194+
symbol_factory.declare_created_symbols(init_code);
195+
init_code.append(assignments);
196+
197+
goto_programt tmp_dest;
198+
goto_convert(
199+
init_code, symbol_table, tmp_dest, message.get_message_handler(), ID_C);
200+
201+
dest.destructive_append(tmp_dest);
258202
}
259203

260204
protected:
261205
void generate_function_body_impl(
262206
goto_functiont &function,
263-
const symbol_tablet &symbol_table,
207+
symbol_tablet &symbol_table,
264208
const irep_idt &function_name) const override
265209
{
266210
auto const &function_symbol = symbol_table.lookup_ref(function_name);
@@ -276,18 +220,29 @@ class havoc_generate_function_bodiest : public generate_function_bodiest,
276220
{
277221
if(
278222
parameter.type().id() == ID_pointer &&
223+
!parameter.type().subtype().get_bool(ID_C_constant) &&
279224
std::regex_match(
280225
id2string(parameter.get_base_name()), parameters_to_havoc))
281226
{
282-
// if (param != nullptr) { *param = nondet(); }
283227
auto goto_instruction = add_instruction();
228+
229+
const irep_idt base_name = parameter.get_base_name();
230+
CHECK_RETURN(!base_name.empty());
231+
232+
dereference_exprt dereference_expr(
233+
symbol_exprt(parameter.get_identifier(), parameter.type()),
234+
parameter.type().subtype());
235+
236+
goto_programt dest;
284237
havoc_expr_rec(
285-
dereference_exprt(
286-
symbol_exprt(parameter.get_identifier(), parameter.type()),
287-
parameter.type().subtype()),
288-
ns,
289-
add_instruction,
290-
function_name);
238+
dereference_expr,
239+
1, // depth 1 since we pass the dereferenced pointer
240+
function_symbol.location,
241+
symbol_table,
242+
dest);
243+
244+
function.body.destructive_append(dest);
245+
291246
auto label_instruction = add_instruction();
292247
goto_instruction->make_goto(
293248
label_instruction,
@@ -301,12 +256,19 @@ class havoc_generate_function_bodiest : public generate_function_bodiest,
301256
for(auto const &global_id : globals_to_havoc)
302257
{
303258
auto const &global_sym = symbol_table.lookup_ref(global_id);
259+
260+
goto_programt dest;
261+
304262
havoc_expr_rec(
305263
symbol_exprt(global_sym.name, global_sym.type),
306-
ns,
307-
add_instruction,
308-
function_name);
264+
0,
265+
function_symbol.location,
266+
symbol_table,
267+
dest);
268+
269+
function.body.destructive_append(dest);
309270
}
271+
310272
if(function.type.return_type() != void_typet())
311273
{
312274
auto return_instruction = add_instruction();
@@ -324,6 +286,7 @@ class havoc_generate_function_bodiest : public generate_function_bodiest,
324286
const std::vector<irep_idt> globals_to_havoc;
325287
std::regex parameters_to_havoc;
326288
const c_object_factory_parameterst &object_factory_parameters;
289+
mutable messaget message;
327290
};
328291

329292
class generate_function_bodies_errort : public std::runtime_error

src/goto-instrument/generate_function_bodies.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class generate_function_bodiest
3232
/// \param function_name: Identifier of function
3333
virtual void generate_function_body_impl(
3434
goto_functiont &function,
35-
const symbol_tablet &symbol_table,
35+
symbol_tablet &symbol_table,
3636
const irep_idt &function_name) const = 0;
3737

3838
public:

0 commit comments

Comments
 (0)