@@ -11,6 +11,8 @@ Author: Diffblue Ltd.
1111
1212#include " c_nondet_symbol_factory.h"
1313
14+ #include < ansi-c/c_object_factory_parameters.h>
15+
1416#include < util/arith_tools.h>
1517#include < util/c_types.h>
1618#include < util/fresh_symbol.h>
@@ -27,21 +29,20 @@ class symbol_factoryt
2729 std::vector<const symbolt *> &symbols_created;
2830 symbol_tablet &symbol_table;
2931 const source_locationt &loc;
30- const bool assume_non_null;
3132 namespacet ns;
3233 const c_object_factory_parameterst &object_factory_params;
3334
35+ typedef std::set<irep_idt> recursion_sett;
36+
3437public:
3538 symbol_factoryt (
3639 std::vector<const symbolt *> &_symbols_created,
3740 symbol_tablet &_symbol_table,
3841 const source_locationt &loc,
39- const bool _assume_non_null,
4042 const c_object_factory_parameterst &object_factory_params)
4143 : symbols_created(_symbols_created),
4244 symbol_table (_symbol_table),
4345 loc(loc),
44- assume_non_null(_assume_non_null),
4546 ns(_symbol_table),
4647 object_factory_params(object_factory_params)
4748 {}
@@ -52,7 +53,11 @@ class symbol_factoryt
5253 const typet &allocate_type,
5354 const bool static_lifetime);
5455
55- void gen_nondet_init (code_blockt &assignments, const exprt &expr);
56+ void gen_nondet_init (
57+ code_blockt &assignments,
58+ const exprt &expr,
59+ const std::size_t depth = 0 ,
60+ recursion_sett recursion_set = recursion_sett());
5661};
5762
5863// / Create a symbol for a pointer to point to
@@ -103,9 +108,13 @@ exprt symbol_factoryt::allocate_object(
103108// / \param assignments: The code block to add code to
104109// / \param expr: The expression which we are generating a non-determinate value
105110// / for
111+ // / \param depth number of pointers followed so far during initialisation
112+ // / \param recursion_set names of structs seen so far on current pointer chain
106113void symbol_factoryt::gen_nondet_init (
107114 code_blockt &assignments,
108- const exprt &expr)
115+ const exprt &expr,
116+ const std::size_t depth,
117+ recursion_sett recursion_set)
109118{
110119 const typet &type=ns.follow (expr.type ());
111120
@@ -115,6 +124,22 @@ void symbol_factoryt::gen_nondet_init(
115124 const pointer_typet &pointer_type=to_pointer_type (type);
116125 const typet &subtype=ns.follow (pointer_type.subtype ());
117126
127+ if (subtype.id () == ID_struct)
128+ {
129+ const struct_typet &struct_type = to_struct_type (subtype);
130+ const irep_idt struct_tag = struct_type.get_tag ();
131+
132+ if (
133+ recursion_set.find (struct_tag) != recursion_set.end () &&
134+ depth >= object_factory_params.max_nondet_tree_depth )
135+ {
136+ code_assignt c (expr, null_pointer_exprt (pointer_type));
137+ assignments.move (c);
138+
139+ return ;
140+ }
141+ }
142+
118143 code_blockt non_null_inst;
119144
120145 exprt allocated=allocate_object (non_null_inst, expr, subtype, false );
@@ -128,9 +153,9 @@ void symbol_factoryt::gen_nondet_init(
128153 {
129154 init_expr=dereference_exprt (allocated, allocated.type ().subtype ());
130155 }
131- gen_nondet_init (non_null_inst, init_expr);
156+ gen_nondet_init (non_null_inst, init_expr, depth + 1 , recursion_set );
132157
133- if (assume_non_null )
158+ if (depth < object_factory_params. min_null_tree_depth )
134159 {
135160 // Add the following code to assignments:
136161 // <expr> = <aoe>;
@@ -157,7 +182,25 @@ void symbol_factoryt::gen_nondet_init(
157182 assignments.move (null_check);
158183 }
159184 }
160- // TODO(OJones): Add support for structs and arrays
185+ else if (type.id () == ID_struct)
186+ {
187+ const struct_typet &struct_type = to_struct_type (type);
188+
189+ const irep_idt struct_tag = struct_type.get_tag ();
190+
191+ recursion_set.insert (struct_tag);
192+
193+ for (const auto &component : struct_type.components ())
194+ {
195+ const typet &component_type = component.type ();
196+ const irep_idt name = component.get_name ();
197+
198+ member_exprt me (expr, name, component_type);
199+ me.add_source_location () = loc;
200+
201+ gen_nondet_init (assignments, me, depth, recursion_set);
202+ }
203+ }
161204 else
162205 {
163206 // If type is a ID_c_bool then add the following code to assignments:
@@ -181,15 +224,13 @@ void symbol_factoryt::gen_nondet_init(
181224// / \param base_name: The name to use for the symbol created
182225// / \param type: The type for the symbol created
183226// / \param loc: The location to assign to generated code
184- // / \param allow_null: Whether to allow a null value when type is a pointer
185227// / \return Returns the symbol_exprt for the symbol created
186228exprt c_nondet_symbol_factory (
187229 code_blockt &init_code,
188230 symbol_tablet &symbol_table,
189231 const irep_idt base_name,
190232 const typet &type,
191233 const source_locationt &loc,
192- bool allow_null,
193234 const c_object_factory_parameterst &object_factory_parameters)
194235{
195236 irep_idt identifier=id2string (goto_functionst::entry_point ())+
@@ -213,7 +254,7 @@ exprt c_nondet_symbol_factory(
213254 symbols_created.push_back (main_symbol_ptr);
214255
215256 symbol_factoryt state (
216- symbols_created, symbol_table, loc, !allow_null, object_factory_parameters);
257+ symbols_created, symbol_table, loc, object_factory_parameters);
217258 code_blockt assignments;
218259 state.gen_nondet_init (assignments, main_symbol_expr);
219260
0 commit comments