@@ -143,7 +143,19 @@ 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 = (<type-of-obj>)return_tmp0;
156
+ // /
157
+ // / We're going to replace all of these lines with
158
+ // / return_tmp0 = NONDET(<type-of-obj>)
147
159
// / \param goto_program: The goto program to modify.
148
160
// / \param target: A single step of the goto program which may be erased and
149
161
// / replaced.
@@ -161,40 +173,69 @@ static goto_programt::targett check_and_replace_target(
161
173
return next_instr;
162
174
}
163
175
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 ()))
176
+ // If we haven't removed returns yet, our function call will have a variable
177
+ // on its left hand side.
178
+ const bool remove_returns_not_run =
179
+ to_code_function_call (target->code ).lhs ().is_not_nil ();
180
+
181
+ irep_idt return_identifier;
182
+ if (remove_returns_not_run)
170
183
{
171
- return next_instr;
184
+ return_identifier =
185
+ to_symbol_expr (to_code_function_call (target->code ).lhs ())
186
+ .get_identifier ();
172
187
}
173
- const auto return_identifier=
174
- to_symbol_expr (next_instr_assign_lhs).get_identifier ();
188
+ else
189
+ {
190
+ // If not, we need to look at the next line instead.
191
+ DATA_INVARIANT (
192
+ next_instr->is_assign (),
193
+ " the code_function_callt for a nondet-returning library function should "
194
+ " either have a variable for the return value in its lhs() or the next "
195
+ " instruction should be an assignment of the return value to a temporary "
196
+ " variable" );
197
+ const exprt &return_value_assignment =
198
+ to_code_assign (next_instr->code ).lhs ();
199
+
200
+ // If the assignment is null, return.
201
+ if (
202
+ !(return_value_assignment.id () == ID_symbol &&
203
+ !return_value_assignment.has_operands ()))
204
+ {
205
+ return next_instr;
206
+ }
175
207
176
- auto &instructions=goto_program.instructions ;
177
- const auto end=instructions.end ();
208
+ // Otherwise it's the temporary variable.
209
+ return_identifier =
210
+ to_symbol_expr (return_value_assignment).get_identifier ();
211
+ }
178
212
179
- // Look for an instruction where this name is on the RHS of an assignment
180
- const auto matching_assignment=std::find_if (
213
+ // Look for the assignment of the temporary return variable into our target
214
+ // variable.
215
+ const auto end = goto_program.instructions .end ();
216
+ auto assignment_instruction = std::find_if (
181
217
next_instr,
182
218
end,
183
219
[&return_identifier](const goto_programt::instructiont &instr)
184
220
{
185
221
return is_assignment_from (instr, return_identifier);
186
222
});
187
223
188
- assert (matching_assignment!=end);
224
+ INVARIANT (
225
+ assignment_instruction != end,
226
+ " failed to find assignment of the temporary return variable into our "
227
+ " target variable" );
189
228
190
229
// Assume that the LHS of *this* assignment is the actual nondet variable
191
- const auto &code_assign= to_code_assign (matching_assignment ->code );
230
+ const auto &code_assign = to_code_assign (assignment_instruction ->code );
192
231
const auto nondet_var=code_assign.lhs ();
193
232
const auto source_loc=target->source_location ;
194
233
195
234
// 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);
235
+ const auto after_matching_assignment = std::next (assignment_instruction);
236
+ INVARIANT (
237
+ after_matching_assignment != end,
238
+ " goto_program missing END_FUNCTION instruction" );
198
239
199
240
std::for_each (
200
241
target,
0 commit comments