22
22
23
23
#include " java_object_factory.h" // gen_nondet_init
24
24
25
+ // / Returns true if `expr` is a nondet pointer that isn't a function pointer or
26
+ // / a void* pointer as these can be meaningfully non-det initalized.
27
+ static bool is_nondet_pointer (exprt expr)
28
+ {
29
+ // If the expression type doesn't have a subtype then I guess it's primitive
30
+ // and we do not want to convert it. If the type is a ptr-to-void or a
31
+ // function pointer then we also do not want to convert it.
32
+ const typet &type = expr.type ();
33
+ const bool non_void_non_function_pointer = type.id () == ID_pointer &&
34
+ type.subtype ().id () != ID_empty &&
35
+ type.subtype ().id () != ID_code;
36
+ return can_cast_expr<side_effect_expr_nondett>(expr) &&
37
+ non_void_non_function_pointer;
38
+ }
39
+
40
+ // / Populate `instructions` with goto instructions to nondet init
41
+ // / `aux_symbol_expr`
42
+ static goto_programt get_gen_nondet_init_instructions (
43
+ const symbol_exprt &aux_symbol_expr,
44
+ const source_locationt &source_loc,
45
+ symbol_table_baset &symbol_table,
46
+ message_handlert &message_handler,
47
+ const object_factory_parameterst &object_factory_parameters,
48
+ const irep_idt &mode)
49
+ {
50
+ code_blockt gen_nondet_init_code;
51
+ const bool skip_classid = true ;
52
+ gen_nondet_init (
53
+ aux_symbol_expr,
54
+ gen_nondet_init_code,
55
+ symbol_table,
56
+ source_loc,
57
+ skip_classid,
58
+ allocation_typet::DYNAMIC,
59
+ object_factory_parameters,
60
+ update_in_placet::NO_UPDATE_IN_PLACE);
61
+
62
+ goto_programt instructions;
63
+ goto_convert (
64
+ gen_nondet_init_code, symbol_table, instructions, message_handler, mode);
65
+ return instructions;
66
+ }
67
+
25
68
// / Checks an instruction to see whether it contains an assignment from
26
69
// / side_effect_expr_nondet. If so, replaces the instruction with a range of
27
70
// / instructions to properly nondet-initialize the lhs.
28
71
// / \param goto_program: The goto program to modify.
29
72
// / \param target: One of the steps in that goto program.
30
73
// / \param symbol_table: The global symbol table.
31
74
// / \param message_handler: Handles logging.
32
- // / \param max_nondet_array_length: Maximum size of new nondet arrays.
33
- // / \return The next instruction to process with this function.
34
- static goto_programt::targett insert_nondet_init_code (
75
+ // / \param object_factory_parameters: Parameters for the generation of nondet
76
+ // / objects.
77
+ // / \param mode: Language mode
78
+ // / \return The next instruction to process with this function and a boolean
79
+ // / indicating whether any changes were made to the goto program.
80
+ static std::pair<goto_programt::targett, bool > insert_nondet_init_code (
35
81
goto_programt &goto_program,
36
82
const goto_programt::targett &target,
37
83
symbol_table_baset &symbol_table,
38
84
message_handlert &message_handler,
39
85
object_factory_parameterst object_factory_parameters,
40
86
const irep_idt &mode)
41
87
{
42
- // Return if the instruction isn't an assignment
43
- const auto next_instr=std::next (target);
44
- if (!target->is_assign ())
45
- {
46
- return next_instr;
47
- }
88
+ const auto next_instr = std::next (target);
48
89
49
- // Return if the rhs of the assignment isn't a side effect expression
50
- const auto &assign=to_code_assign (target->code );
51
- if (assign.rhs ().id ()!=ID_side_effect)
90
+ // We only expect to find nondets in the rhs of an assignments, and in return
91
+ // statements if remove_returns has not been run, but we do a more general
92
+ // check on all operands in case this changes
93
+ for (exprt &op : target->code .operands ())
52
94
{
53
- return next_instr;
54
- }
95
+ if (!is_nondet_pointer (op))
96
+ {
97
+ continue ;
98
+ }
55
99
56
- // Return if the rhs isn't nondet
57
- const auto &side_effect=to_side_effect_expr (assign.rhs ());
58
- if (side_effect.get_statement ()!=ID_nondet)
59
- {
60
- return next_instr;
61
- }
100
+ const auto &nondet_expr = to_side_effect_expr_nondet (op);
62
101
63
- const auto lhs=assign.lhs ();
64
- // If the lhs type doesn't have a subtype then I guess it's primitive and
65
- // we want to bail out now
66
- if (!lhs.type ().has_subtype ())
67
- {
68
- return next_instr;
69
- }
102
+ if (!nondet_expr.get_nullable ())
103
+ object_factory_parameters.max_nonnull_tree_depth = 1 ;
70
104
71
- // Although, if the type is a ptr-to-void then we also want to bail
72
- if (lhs.type ().subtype ().id ()==ID_empty ||
73
- lhs.type ().subtype ().id ()==ID_code)
74
- {
75
- return next_instr;
76
- }
105
+ const source_locationt &source_loc = target->source_location ;
77
106
78
- // Check whether the nondet object may be null
79
- if (!to_side_effect_expr_nondet (side_effect).get_nullable ())
80
- object_factory_parameters.max_nonnull_tree_depth = 1 ;
81
- // Get the symbol to nondet-init
82
- const auto source_loc=target->source_location ;
107
+ // Currently the code looks like this
108
+ // target: instruction containing op
109
+ // When we are done it will look like this
110
+ // target : declare aux_symbol
111
+ // . <gen_nondet_init_instructions - many lines>
112
+ // . <gen_nondet_init_instructions - many lines>
113
+ // . <gen_nondet_init_instructions - many lines>
114
+ // target2: instruction containing op, with op replaced by aux_symbol
115
+ // dead aux_symbol
83
116
84
- // Erase the nondet assignment
85
- target->make_skip ();
117
+ symbolt &aux_symbol = get_fresh_aux_symbol (
118
+ op.type (),
119
+ id2string (goto_programt::get_function_id (goto_program)),
120
+ " nondet_tmp" ,
121
+ source_loc,
122
+ ID_java,
123
+ symbol_table);
86
124
87
- // Generate nondet init code
88
- code_blockt init_code;
89
- gen_nondet_init (
90
- lhs,
91
- init_code,
92
- symbol_table,
93
- source_loc,
94
- true ,
95
- allocation_typet::DYNAMIC,
96
- object_factory_parameters,
97
- update_in_placet::NO_UPDATE_IN_PLACE);
125
+ const symbol_exprt aux_symbol_expr = aux_symbol.symbol_expr ();
126
+ op = aux_symbol_expr;
98
127
99
- // Convert this code into goto instructions
100
- goto_programt new_instructions;
101
- goto_convert (
102
- init_code, symbol_table, new_instructions, message_handler, mode);
128
+ // Insert an instruction declaring `aux_symbol` before `target`, being
129
+ // careful to preserve jumps to `target`
130
+ goto_programt::instructiont decl_aux_symbol;
131
+ decl_aux_symbol.make_decl (code_declt (aux_symbol_expr));
132
+ decl_aux_symbol.source_location = source_loc;
133
+ goto_program.insert_before_swap (target, decl_aux_symbol);
103
134
104
- // Insert the new instructions into the instruction list
105
- goto_program.destructive_insert (next_instr, new_instructions);
106
- goto_program.update ();
135
+ // Keep track of the new location of the instruction containing op.
136
+ const goto_programt::targett target2 = std::next (target);
107
137
108
- return next_instr;
138
+ goto_programt gen_nondet_init_instructions =
139
+ get_gen_nondet_init_instructions (
140
+ aux_symbol_expr,
141
+ source_loc,
142
+ symbol_table,
143
+ message_handler,
144
+ object_factory_parameters,
145
+ mode);
146
+ goto_program.destructive_insert (target2, gen_nondet_init_instructions);
147
+
148
+ goto_programt::targett dead_aux_symbol = goto_program.insert_after (target2);
149
+ dead_aux_symbol->make_dead ();
150
+ dead_aux_symbol->code = code_deadt (aux_symbol_expr);
151
+ dead_aux_symbol->source_location = source_loc;
152
+
153
+ // In theory target could have more than one operand which should be
154
+ // replaced by convert_nondet, so we return target2 so that it
155
+ // will be checked again
156
+ return std::make_pair (target2, true );
157
+ }
158
+
159
+ return std::make_pair (next_instr, false );
109
160
}
110
161
111
162
// / For each instruction in the goto program, checks if it is an assignment from
@@ -114,25 +165,35 @@ static goto_programt::targett insert_nondet_init_code(
114
165
// / \param goto_program: The goto program to modify.
115
166
// / \param symbol_table: The global symbol table.
116
167
// / \param message_handler: Handles logging.
117
- // / \param max_nondet_array_length: Maximum size of new nondet arrays.
168
+ // / \param object_factory_parameters: Parameters for the generation of nondet
169
+ // / objects.
170
+ // / \param mode: Language mode
118
171
void convert_nondet (
119
172
goto_programt &goto_program,
120
173
symbol_table_baset &symbol_table,
121
174
message_handlert &message_handler,
122
175
const object_factory_parameterst &object_factory_parameters,
123
176
const irep_idt &mode)
124
177
{
125
- for (auto instruction_iterator=goto_program.instructions .begin (),
126
- end=goto_program.instructions .end ();
127
- instruction_iterator!=end;)
178
+ bool changed = false ;
179
+ auto instruction_iterator = goto_program.instructions .begin ();
180
+
181
+ while (instruction_iterator != goto_program.instructions .end ())
128
182
{
129
- instruction_iterator = insert_nondet_init_code (
183
+ auto ret = insert_nondet_init_code (
130
184
goto_program,
131
185
instruction_iterator,
132
186
symbol_table,
133
187
message_handler,
134
188
object_factory_parameters,
135
189
mode);
190
+ instruction_iterator = ret.first ;
191
+ changed |= ret.second ;
192
+ }
193
+
194
+ if (changed)
195
+ {
196
+ goto_program.update ();
136
197
}
137
198
}
138
199
0 commit comments