Skip to content

Commit 80fe6ff

Browse files
committed
goto_symex: implement SET_RETURN_VALUE
This (re-)implements the goto-instruction SET_RETURN_VALUE in goto_symex. This enables dropping the requirement that SET_RETURN_INSTRUCTIONS are removed prior to invoking symex.
1 parent e27dba6 commit 80fe6ff

File tree

13 files changed

+118
-109
lines changed

13 files changed

+118
-109
lines changed

regression/cbmc-cover/block-coverage-report2/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ main.c
44
block 1 \(lines main.c:main:13,14\): SATISFIED
55
block 2 \(lines main.c:main:15\): SATISFIED
66
block 3 \(lines main.c:main:17,18\): SATISFIED
7-
block 4 \(lines main.c:main:18,19\): SATISFIED
7+
block 4 \(lines main.c:main:19\): SATISFIED
88
block 5 \(lines main.c:main:20\): SATISFIED
99
block 6 \(lines main.c:main:15,21,22\): SATISFIED
1010
block 7 \(lines main.c:main:24,25\): SATISFIED

regression/cbmc/reachability-slice-interproc3/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ main.c
33
--reachability-slice-fb --show-goto-functions
44
^EXIT=0$
55
^SIGNAL=0$
6-
ASSIGN main#return_value := 1
6+
SET RETURN VALUE 1$
77
--
88
^warning: ignoring

src/goto-analyzer/goto_analyzer_parse_options.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Author: Daniel Kroening, [email protected]
2626
#include <goto-programs/initialize_goto_model.h>
2727
#include <goto-programs/link_to_library.h>
2828
#include <goto-programs/process_goto_program.h>
29+
#include <goto-programs/remove_returns.h>
2930
#include <goto-programs/set_properties.h>
3031
#include <goto-programs/show_properties.h>
3132
#include <goto-programs/show_symbol_table.h>
@@ -388,6 +389,7 @@ int goto_analyzer_parse_optionst::doit()
388389
// Preserve backwards compatibility in processing
389390
options.set_option("partial-inline", true);
390391
options.set_option("rewrite-union", false);
392+
options.set_option("remove-returns", true);
391393

392394
if(process_goto_program(options))
393395
return CPROVER_EXIT_INTERNAL_ERROR;

src/goto-programs/mm_io.cpp

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Date: April 2017
1313

1414
#include "mm_io.h"
1515

16+
#include <util/fresh_symbol.h>
1617
#include <util/pointer_expr.h>
1718
#include <util/pointer_offset_size.h>
1819
#include <util/pointer_predicates.h>
@@ -35,6 +36,7 @@ void collect_deref_expr(
3536

3637
void mm_io(
3738
const exprt &mm_io_r,
39+
const exprt &mm_io_r_value,
3840
const exprt &mm_io_w,
3941
goto_functionst::goto_functiont &goto_function,
4042
const namespacet &ns)
@@ -60,21 +62,20 @@ void mm_io(
6062
source_locationt source_location = it->source_location();
6163
const code_typet &ct=to_code_type(mm_io_r.type());
6264

63-
irep_idt identifier=to_symbol_expr(mm_io_r).get_identifier();
64-
auto return_value = return_value_symbol(identifier, ns);
65-
if_exprt if_expr(integer_address(d.pointer()), return_value, d);
65+
if_exprt if_expr(integer_address(d.pointer()), mm_io_r_value, d);
6666
replace_expr(d, if_expr, a_rhs);
6767

6868
const typet &pt=ct.parameters()[0].type();
6969
const typet &st=ct.parameters()[1].type();
7070
auto size_opt = size_of_expr(d.type(), ns);
7171
CHECK_RETURN(size_opt.has_value());
72-
const code_function_callt fc(
72+
auto call = goto_programt::make_function_call(
73+
mm_io_r_value,
7374
mm_io_r,
7475
{typecast_exprt(d.pointer(), pt),
75-
typecast_exprt(size_opt.value(), st)});
76-
goto_function.body.insert_before_swap(it);
77-
*it = goto_programt::make_function_call(fc, source_location);
76+
typecast_exprt(size_opt.value(), st)},
77+
source_location);
78+
goto_function.body.insert_before_swap(it, call);
7879
it++;
7980
}
8081
}
@@ -105,26 +106,37 @@ void mm_io(
105106
}
106107
}
107108

108-
void mm_io(
109-
const symbol_tablet &symbol_table,
110-
goto_functionst &goto_functions)
109+
void mm_io(symbol_tablet &symbol_table, goto_functionst &goto_functions)
111110
{
112111
const namespacet ns(symbol_table);
113-
exprt mm_io_r=nil_exprt(), mm_io_w=nil_exprt();
112+
exprt mm_io_r = nil_exprt(), mm_io_r_value = nil_exprt(),
113+
mm_io_w = nil_exprt();
114114

115115
irep_idt id_r=CPROVER_PREFIX "mm_io_r";
116116
irep_idt id_w=CPROVER_PREFIX "mm_io_w";
117117

118118
auto maybe_symbol=symbol_table.lookup(id_r);
119119
if(maybe_symbol)
120+
{
120121
mm_io_r=maybe_symbol->symbol_expr();
121122

123+
const auto &value_symbol = get_fresh_aux_symbol(
124+
to_code_type(mm_io_r.type()).return_type(),
125+
id2string(id_r) + "$value",
126+
id2string(id_r) + "$value",
127+
maybe_symbol->location,
128+
maybe_symbol->mode,
129+
symbol_table);
130+
131+
mm_io_r_value = value_symbol.symbol_expr();
132+
}
133+
122134
maybe_symbol=symbol_table.lookup(id_w);
123135
if(maybe_symbol)
124136
mm_io_w=maybe_symbol->symbol_expr();
125137

126138
for(auto & f : goto_functions.function_map)
127-
mm_io(mm_io_r, mm_io_w, f.second, ns);
139+
mm_io(mm_io_r, mm_io_r_value, mm_io_w, f.second, ns);
128140
}
129141

130142
void mm_io(goto_modelt &model)

src/goto-programs/process_goto_program.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,16 @@ bool process_goto_program(
5858
}
5959

6060
// remove returns, gcc vectors, complex
61-
remove_returns(goto_model);
61+
if(
62+
options.get_bool_option("remove-returns") ||
63+
options.get_bool_option("string-abstraction"))
64+
{
65+
remove_returns(goto_model);
66+
}
67+
6268
remove_vector(goto_model);
6369
remove_complex(goto_model);
70+
6471
if(options.get_bool_option("rewrite-union"))
6572
rewrite_union(goto_model);
6673

src/goto-programs/validate_goto_model.cpp

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ Date: Oct 2018
1414
#include <util/pointer_expr.h>
1515

1616
#include "goto_functions.h"
17-
#include "remove_returns.h"
1817

1918
namespace
2019
{
@@ -38,18 +37,6 @@ class validate_goto_modelt
3837
/// Check that no function calls via function pointer are present
3938
void function_pointer_calls_removed();
4039

41-
/// Check returns have been removed
42-
///
43-
/// Calls via function pointer must have been removed already when
44-
/// removing returns, thus enabling this check also enables the check
45-
/// that all calls via function pointer have been removed
46-
///
47-
/// Sub-checks are:
48-
/// - no return statements in any of the functions
49-
/// - lhs of every \ref code_function_callt instruction is nil
50-
/// - all return types are void (of both calls and functions themselves)
51-
void check_returns_removed();
52-
5340
/// Check that for all:
5441
/// -# functions that are called or
5542
/// -# functions of which the address is taken
@@ -74,19 +61,11 @@ validate_goto_modelt::validate_goto_modelt(
7461
if(validation_options.entry_point_exists)
7562
entry_point_exists();
7663

77-
/// NB function pointer calls must have been removed before removing
78-
/// returns - so 'check_returns_removed' also enables
79-
// 'function_pointer_calls_removed'
80-
if(
81-
validation_options.function_pointer_calls_removed ||
82-
validation_options.check_returns_removed)
64+
if(validation_options.function_pointer_calls_removed)
8365
{
8466
function_pointer_calls_removed();
8567
}
8668

87-
if(validation_options.check_returns_removed)
88-
check_returns_removed();
89-
9069
if(validation_options.check_called_functions)
9170
check_called_functions();
9271
}
@@ -116,30 +95,6 @@ void validate_goto_modelt::function_pointer_calls_removed()
11695
}
11796
}
11897

119-
void validate_goto_modelt::check_returns_removed()
120-
{
121-
for(const auto &fun : function_map)
122-
{
123-
const goto_functiont &goto_function = fun.second;
124-
125-
for(const auto &instr : goto_function.body.instructions)
126-
{
127-
DATA_CHECK(
128-
vm,
129-
!instr.is_set_return_value(),
130-
"no SET_RETURN_VALUE instructions should be present");
131-
132-
if(instr.is_function_call())
133-
{
134-
DATA_CHECK(
135-
vm,
136-
!does_function_call_return(instr),
137-
"function call lhs return should be nil");
138-
}
139-
}
140-
}
141-
}
142-
14398
void validate_goto_modelt::check_called_functions()
14499
{
145100
auto test_for_function_address =

src/goto-symex/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ SRC = auto_objects.cpp \
3131
symex_goto.cpp \
3232
symex_main.cpp \
3333
symex_other.cpp \
34+
symex_set_return_value.cpp \
3435
symex_start_thread.cpp \
3536
symex_target.cpp \
3637
symex_target_equation.cpp \

src/goto-symex/frame.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Author: Romain Brenguier, [email protected]
1414

1515
#include "goto_state.h"
1616
#include "symex_target.h"
17+
1718
#include <analyses/lexical_loops.h>
1819

1920
/// Stack frames -- these are used for function calls and for exceptions
@@ -30,7 +31,8 @@ struct framet
3031
std::vector<irep_idt> parameter_names;
3132
guardt guard_at_function_start;
3233
goto_programt::const_targett end_of_function;
33-
exprt return_value = nil_exprt();
34+
exprt call_lhs = nil_exprt(); // cleaned, but not renamed
35+
optionalt<symbol_exprt> return_value_symbol; // not renamed
3436
bool hidden_function = false;
3537

3638
symex_level1t old_level1;

src/goto-symex/goto_symex.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,10 @@ class goto_symext
303303
/// Symbolically execute a GOTO instruction in the context of unreachable code
304304
/// \param state: Symbolic execution state for current instruction
305305
void symex_unreachable_goto(statet &state);
306+
/// Symbolically execute a SET_RETURN_VALUE instruction
307+
/// \param state: Symbolic execution state for current instruction
308+
/// \param return_value: The value to be returned
309+
void symex_set_return_value(statet &state, const exprt &return_value);
306310
/// Symbolically execute a START_THREAD instruction
307311
/// \param state: Symbolic execution state for current instruction
308312
virtual void symex_start_thread(statet &state);

src/goto-symex/symex_function_call.cpp

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,11 +332,33 @@ void goto_symext::symex_function_call_post_clean(
332332
// assign actuals to formal parameters
333333
parameter_assignments(identifier, goto_function, state, cleaned_arguments);
334334

335-
frame.end_of_function=--goto_function.body.instructions.end();
336-
frame.return_value = cleaned_lhs;
335+
frame.call_lhs = cleaned_lhs;
336+
frame.end_of_function = --goto_function.body.instructions.end();
337337
frame.function_identifier=identifier;
338338
frame.hidden_function = goto_function.is_hidden();
339339

340+
// set up the 'return value symbol' when needed
341+
if(frame.call_lhs.is_not_nil())
342+
{
343+
irep_idt return_value_symbol_identifier =
344+
"goto_symex::return_value::" + id2string(identifier);
345+
346+
if(!state.symbol_table.has_symbol(return_value_symbol_identifier))
347+
{
348+
const symbolt &function_symbol = ns.lookup(identifier);
349+
auxiliary_symbolt
350+
new_symbol; // these are thread-local and have dynamic lifetime
351+
new_symbol.base_name = "return_value";
352+
new_symbol.name = return_value_symbol_identifier;
353+
new_symbol.type = to_code_type(function_symbol.type).return_type();
354+
new_symbol.mode = function_symbol.mode;
355+
state.symbol_table.add(new_symbol);
356+
}
357+
358+
frame.return_value_symbol =
359+
ns.lookup(return_value_symbol_identifier).symbol_expr();
360+
}
361+
340362
const framet &p_frame = state.call_stack().previous_frame();
341363
for(const auto &pair : p_frame.loop_iterations)
342364
{
@@ -405,14 +427,33 @@ static void pop_frame(
405427
/// do function call by inlining
406428
void goto_symext::symex_end_of_function(statet &state)
407429
{
430+
PRECONDITION(!state.call_stack().empty());
431+
408432
const bool hidden = state.call_stack().top().hidden_function;
409433

410434
// first record the return
411435
target.function_return(
412436
state.guard.as_expr(), state.source.function_id, state.source, hidden);
413437

414-
// then get rid of the frame
438+
// before we drop the frame, remember the call LHS
439+
// and the return value symbol, if any
440+
auto call_lhs = state.call_stack().top().call_lhs;
441+
auto return_value_symbol = state.call_stack().top().return_value_symbol;
442+
443+
// now get rid of the frame
415444
pop_frame(state, path_storage, symex_config.doing_path_exploration);
445+
446+
// after dropping the frame, assign the return value, if any
447+
if(state.reachable && call_lhs.is_not_nil())
448+
{
449+
DATA_INVARIANT(
450+
return_value_symbol.has_value(),
451+
"must have return value symbol when assigning call lhs");
452+
// the type of the call lhs and the return type might not match
453+
auto casted_return_value = typecast_exprt::conditional_cast(
454+
return_value_symbol.value(), call_lhs.type());
455+
symex_assign(state, call_lhs, casted_return_value);
456+
}
416457
}
417458

418459
/// Preserves locality of parameters of a given function by applying L1

src/goto-symex/symex_main.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -661,8 +661,9 @@ void goto_symext::execute_next_instruction(
661661
break;
662662

663663
case SET_RETURN_VALUE:
664-
// This case should have been removed by return-value removal
665-
UNREACHABLE;
664+
if(state.reachable)
665+
symex_set_return_value(state, instruction.return_value());
666+
symex_transition(state);
666667
break;
667668

668669
case ASSIGN:
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*******************************************************************\
2+
3+
Module: Symbolic Execution of ANSI-C
4+
5+
Author: Daniel Kroening, [email protected]
6+
7+
\*******************************************************************/
8+
9+
/// \file
10+
/// Symbolic Execution of ANSI-C
11+
12+
#include "goto_symex.h"
13+
14+
void goto_symext::symex_set_return_value(
15+
statet &state,
16+
const exprt &return_value)
17+
{
18+
// we must be inside a function that was called
19+
PRECONDITION(!state.call_stack().empty());
20+
21+
framet &frame = state.call_stack().top();
22+
if(frame.return_value_symbol.has_value())
23+
{
24+
symex_assign(state, frame.return_value_symbol.value(), return_value);
25+
}
26+
}

0 commit comments

Comments
 (0)