@@ -143,7 +143,20 @@ static bool is_assignment_from(
143
143
144
144
// / Given an iterator into a list of instructions, modify the list to replace
145
145
// / 'nondet' library functions with CBMC-native nondet expressions, and return
146
- // / an iterator to the next instruction to check.
146
+ // / an iterator to the next instruction to check. It's important to note that
147
+ // / this method also deals with the fact that in the GOTO program it assigns
148
+ // / function return values to temporary variables, performs validation and then
149
+ // / assigns the value into the actual variable.
150
+ // /
151
+ // / Example:
152
+ // /
153
+ // / return_tmp0=org.cprover.CProver.nondetWithoutNull:()Ljava/lang/Object;();
154
+ // / ... Various validations of type and value here.
155
+ // / obj = return_tmp0;
156
+ // /
157
+ // / We're going to replace return_tmp0 with a nondet declaration and remove
158
+ // / everything between the obj assignment and that variable because it's all
159
+ // / redundant.
147
160
// / \param goto_program: The goto program to modify.
148
161
// / \param target: A single step of the goto program which may be erased and
149
162
// / replaced.
@@ -161,40 +174,64 @@ static goto_programt::targett check_and_replace_target(
161
174
return next_instr;
162
175
}
163
176
164
- // Look at the next instruction, ensure that it is an assignment
165
- assert (next_instr->is_assign ());
166
- // Get the name of the LHS of the assignment
167
- const auto &next_instr_assign_lhs=to_code_assign (next_instr->code ).lhs ();
168
- if (!(next_instr_assign_lhs.id ()==ID_symbol &&
169
- !next_instr_assign_lhs.has_operands ()))
177
+ // If we haven't removed returns yet, our function call will have a variable
178
+ // on its left hand side.
179
+ const bool remove_returns_not_run =
180
+ to_code_function_call (target->code ).lhs ().is_not_nil ();
181
+
182
+ irep_idt return_identifier;
183
+ if (remove_returns_not_run)
170
184
{
171
- return next_instr;
185
+ return_identifier =
186
+ to_symbol_expr (to_code_function_call (target->code ).lhs ())
187
+ .get_identifier ();
172
188
}
173
- const auto return_identifier=
174
- to_symbol_expr (next_instr_assign_lhs).get_identifier ();
189
+ else
190
+ {
191
+ // If not, we need to look at the next line instead.
192
+ assert (next_instr->is_assign ());
193
+ const exprt &return_value_assignment =
194
+ to_code_assign (next_instr->code ).lhs ();
195
+
196
+ // If the assignment is null, return.
197
+ if (
198
+ !(return_value_assignment.id () == ID_symbol &&
199
+ !return_value_assignment.has_operands ()))
200
+ {
201
+ return next_instr;
202
+ }
175
203
176
- auto &instructions=goto_program.instructions ;
177
- const auto end=instructions.end ();
204
+ // Otherwise it's the temporary variable.
205
+ return_identifier =
206
+ to_symbol_expr (return_value_assignment).get_identifier ();
207
+ }
178
208
179
- // Look for an instruction where this name is on the RHS of an assignment
180
- const auto matching_assignment=std::find_if (
209
+ // Look for the assignment of the temporary return variable into our target
210
+ // variable.
211
+ const auto end = goto_program.instructions .end ();
212
+ auto assignment_instruction = std::find_if (
181
213
next_instr,
182
214
end,
183
215
[&return_identifier](const goto_programt::instructiont &instr)
184
216
{
185
217
return is_assignment_from (instr, return_identifier);
186
218
});
187
219
188
- assert (matching_assignment!=end);
220
+ INVARIANT (
221
+ assignment_instruction != end,
222
+ " failed to find assignment of the temporary return variable into our "
223
+ " target variable" );
189
224
190
225
// Assume that the LHS of *this* assignment is the actual nondet variable
191
- const auto &code_assign= to_code_assign (matching_assignment ->code );
226
+ const auto &code_assign = to_code_assign (assignment_instruction ->code );
192
227
const auto nondet_var=code_assign.lhs ();
193
228
const auto source_loc=target->source_location ;
194
229
195
230
// Erase from the nondet function call to the assignment
196
- const auto after_matching_assignment=std::next (matching_assignment);
197
- assert (after_matching_assignment!=end);
231
+ const auto after_matching_assignment = std::next (assignment_instruction);
232
+ INVARIANT (
233
+ after_matching_assignment != end,
234
+ " goto_program missing END_FUNCTION instruction" );
198
235
199
236
std::for_each (
200
237
target,
0 commit comments