Skip to content

Commit ea871b6

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 ea871b6

File tree

1 file changed

+59
-18
lines changed

1 file changed

+59
-18
lines changed

src/goto-programs/replace_java_nondet.cpp

+59-18
Original file line numberDiff line numberDiff line change
@@ -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,69 @@ 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,
183219
[&return_identifier](const goto_programt::instructiont &instr)
184220
{
185221
return is_assignment_from(instr, return_identifier);
186222
});
187223

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");
189228

190229
// 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);
192231
const auto nondet_var=code_assign.lhs();
193232
const auto source_loc=target->source_location;
194233

195234
// 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");
198239

199240
std::for_each(
200241
target,

0 commit comments

Comments
 (0)