Skip to content

Commit 67fa7ba

Browse files
author
Owen Jones
committed
Make remove_java_nondet work before remove_returns
Previously, remove_java_nondet assumed that remove_returns had been run. Now it will work even if remove_returns hasn't been run.
1 parent 69fb74a commit 67fa7ba

File tree

1 file changed

+55
-18
lines changed

1 file changed

+55
-18
lines changed

src/goto-programs/replace_java_nondet.cpp

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)