@@ -143,7 +143,19 @@ static bool is_assignment_from(
143143
144144// / Given an iterator into a list of instructions, modify the list to replace
145145// / '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>)
147159// / \param goto_program: The goto program to modify.
148160// / \param target: A single step of the goto program which may be erased and
149161// / replaced.
@@ -161,40 +173,68 @@ static goto_programt::targett check_and_replace_target(
161173 return next_instr;
162174 }
163175
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)
170183 {
171- return next_instr;
184+ return_identifier =
185+ to_symbol_expr (to_code_function_call (target->code ).lhs ())
186+ .get_identifier ();
172187 }
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+ }
175207
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+ }
178212
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 (
181217 next_instr,
182218 end,
183- [&return_identifier](const goto_programt::instructiont &instr)
184- {
219+ [&return_identifier](const goto_programt::instructiont &instr) {
185220 return is_assignment_from (instr, return_identifier);
186221 });
187222
188- assert (matching_assignment!=end);
223+ INVARIANT (
224+ assignment_instruction != end,
225+ " failed to find assignment of the temporary return variable into our "
226+ " target variable" );
189227
190228 // Assume that the LHS of *this* assignment is the actual nondet variable
191- const auto &code_assign= to_code_assign (matching_assignment ->code );
229+ const auto &code_assign = to_code_assign (assignment_instruction ->code );
192230 const auto nondet_var=code_assign.lhs ();
193231 const auto source_loc=target->source_location ;
194232
195233 // 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);
234+ const auto after_matching_assignment = std::next (assignment_instruction);
235+ INVARIANT (
236+ after_matching_assignment != end,
237+ " goto_program missing END_FUNCTION instruction" );
198238
199239 std::for_each (
200240 target,
0 commit comments