@@ -143,7 +143,20 @@ 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 = 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.
147160// / \param goto_program: The goto program to modify.
148161// / \param target: A single step of the goto program which may be erased and
149162// / replaced.
@@ -161,40 +174,64 @@ static goto_programt::targett check_and_replace_target(
161174 return next_instr;
162175 }
163176
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)
170184 {
171- return next_instr;
185+ return_identifier =
186+ to_symbol_expr (to_code_function_call (target->code ).lhs ())
187+ .get_identifier ();
172188 }
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+ }
175203
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+ }
178208
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 (
181213 next_instr,
182214 end,
183215 [&return_identifier](const goto_programt::instructiont &instr)
184216 {
185217 return is_assignment_from (instr, return_identifier);
186218 });
187219
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" );
189224
190225 // 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 );
192227 const auto nondet_var=code_assign.lhs ();
193228 const auto source_loc=target->source_location ;
194229
195230 // 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" );
198235
199236 std::for_each (
200237 target,
0 commit comments