Skip to content

Commit ff1e81e

Browse files
authored
Merge pull request #2289 from tautschnig/interpreter-deduplicate
Interpreter: de-duplicate code
2 parents 561b33e + eba686f commit ff1e81e

File tree

20 files changed

+268
-75
lines changed

20 files changed

+268
-75
lines changed

regression/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ add_subdirectory(linking-goto-binaries)
6161
add_subdirectory(symtab2gb)
6262
add_subdirectory(validate-trace-xml-schema)
6363
add_subdirectory(cbmc-primitives)
64+
add_subdirectory(goto-interpreter)
6465
add_subdirectory(cbmc-sequentialization)
6566

6667
if(WITH_MEMORY_ANALYZER)

regression/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ DIRS = cbmc \
3535
goto-ld \
3636
validate-trace-xml-schema \
3737
cbmc-primitives \
38+
goto-interpreter \
3839
# Empty last line
3940

4041
ifeq ($(OS),Windows_NT)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
if(WIN32)
2+
set(is_windows true)
3+
else()
4+
set(is_windows false)
5+
endif()
6+
7+
add_test_pl_tests(
8+
"${CMAKE_CURRENT_SOURCE_DIR}/chain.sh $<TARGET_FILE:goto-cc> $<TARGET_FILE:goto-instrument> ${is_windows}"
9+
)

regression/goto-interpreter/Makefile

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
default: tests.log
2+
3+
include ../../src/config.inc
4+
include ../../src/common
5+
6+
ifeq ($(BUILD_ENV_),MSVC)
7+
exe=../../../src/goto-cc/goto-cl
8+
is_windows=true
9+
else
10+
exe=../../../src/goto-cc/goto-cc
11+
is_windows=false
12+
endif
13+
14+
test:
15+
@../test.pl -e -p -c '../chain.sh $(exe) ../../../src/goto-instrument/goto-instrument $(is_windows)'
16+
17+
tests.log:
18+
@../test.pl -e -p -c '../chain.sh $(exe) ../../../src/goto-instrument/goto-instrument $(is_windows)'
19+
20+
show:
21+
@for dir in *; do \
22+
if [ -d "$$dir" ]; then \
23+
vim -o "$$dir/*.c" "$$dir/*.out"; \
24+
fi; \
25+
done;
26+
27+
clean:
28+
@for dir in *; do \
29+
$(RM) tests.log; \
30+
if [ -d "$$dir" ]; then \
31+
cd "$$dir"; \
32+
$(RM) *.out *.gb; \
33+
cd ..; \
34+
fi \
35+
done
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
union U {
2+
int x;
3+
char c[sizeof(int)];
4+
};
5+
6+
int main()
7+
{
8+
union U u;
9+
// make the lowest and highest byte 1
10+
u.x = 1 | (1 << (sizeof(int) * 8 - 8));
11+
int i = u.x;
12+
char c0 = u.c[0];
13+
char c1 = u.c[1];
14+
char c2 = u.c[2];
15+
char c3 = u.c[3];
16+
17+
__CPROVER_assert(u.c[0] == 1, "");
18+
19+
return 0;
20+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
KNOWNBUG
2+
main.c
3+
se
4+
^Starting interpreter$
5+
^\d+- Program End\.$
6+
^EXIT=0$
7+
^SIGNAL=0$
8+
--
9+
^assertion failed at \d+$
10+
--
11+
The memory model of the interpreter does not record individual bytes. Therefore,
12+
an access to individual bytes still yields the full object, making the assertion
13+
in this test spuriously fail.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
se
4+
^Starting interpreter$
5+
^\d+- Program End\.$
6+
^EXIT=0$
7+
^SIGNAL=0$
8+
--

regression/goto-interpreter/chain.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
5+
goto_cc=$1
6+
goto_instrument=$2
7+
is_windows=$3
8+
9+
options=${*:4:$#-4}
10+
name=${*:$#}
11+
base_name=${name%.c}
12+
13+
if [[ "${is_windows}" == "true" ]]; then
14+
"${goto_cc}" "${name}"
15+
mv "${base_name}.exe" "${base_name}.gb"
16+
else
17+
"${goto_cc}" "${name}" -o "${base_name}.gb"
18+
fi
19+
20+
echo ${options} | tr , '\n' | "${goto_instrument}" --interpreter "${base_name}.gb"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
int main()
2+
{
3+
return 0;
4+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
CORE
2+
main.c
3+
h,q
4+
^Starting interpreter$
5+
^Interpreter help$
6+
^h: display this menu$
7+
^j: output json trace$
8+
^m: output memory dump$
9+
^o: output goto trace$
10+
^q: quit$
11+
^r: run up to entry point$
12+
^s#: step a number of instructions$
13+
^sa: step across a function$
14+
^so: step out of a function$
15+
^se: step until end of program$
16+
^\d+- Program End\.$
17+
^EXIT=0$
18+
^SIGNAL=0$
19+
--
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
int main()
2+
{
3+
return 0;
4+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
main.c
3+
m
4+
^Starting interpreter$
5+
^__CPROVER_rounding_mode\[0\]=0$
6+
^\d+- Program End\.$
7+
^EXIT=0$
8+
^SIGNAL=0$
9+
--
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
int main()
2+
{
3+
__CPROVER_rounding_mode = 1;
4+
// test single stepping
5+
int i = 1;
6+
i = 2;
7+
i = 3;
8+
int x;
9+
__CPROVER_assert(x == 42, "should fail");
10+
return 0;
11+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
r,q
4+
^Starting interpreter$
5+
^\d+- Program End\.$
6+
^EXIT=0$
7+
^SIGNAL=0$
8+
--
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
CORE
2+
main.c
3+
r0,s,sa,m,s2,m,s2,m,so,m,se
4+
^Starting interpreter$
5+
^__CPROVER_rounding_mode\[0\]=0$
6+
^__CPROVER_rounding_mode\[0\]=1$
7+
^main::1::i\[0\]=1$
8+
^\d+- Program End\.$
9+
^EXIT=0$
10+
^SIGNAL=0$
11+
--
12+
^main::1::i\[0\]=2$
13+
--
14+
Use the various step instructions: restart execution without running
15+
initialization (r0), execute one step (s), step over __CPROVER_initialize (sa),
16+
generate the first memory dump (__CPROVER_rounding_mode set to 0), step into
17+
main and execute the first assignment (__CPROVER_rounding_mode set to 1),
18+
execute two steps (s2) to declare i and assign 1 to i, step to the end of the
19+
function (so) without dumping intermittent values, thus never dumping i==2. The
20+
execute to the end of the program (se).

src/goto-instrument/goto_instrument_parse_options.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ Author: Daniel Kroening, [email protected]
4141
#include <goto-programs/remove_unused_functions.h>
4242
#include <goto-programs/remove_virtual_functions.h>
4343
#include <goto-programs/restrict_function_pointers.h>
44+
#include <goto-programs/rewrite_union.h>
4445
#include <goto-programs/set_properties.h>
4546
#include <goto-programs/show_properties.h>
4647
#include <goto-programs/show_symbol_table.h>
@@ -599,6 +600,9 @@ int goto_instrument_parse_optionst::doit()
599600

600601
if(cmdline.isset("interpreter"))
601602
{
603+
do_indirect_call_and_rtti_removal();
604+
rewrite_union(goto_model);
605+
602606
log.status() << "Starting interpreter" << messaget::eom;
603607
interpreter(goto_model, ui_message_handler);
604608
return CPROVER_EXIT_SUCCESS;

src/goto-programs/interpreter.cpp

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ void interpretert::operator()()
6464
void interpretert::initialize(bool init)
6565
{
6666
build_memory_map();
67+
// reset the call stack
68+
call_stack = call_stackt{};
6769

6870
total_steps=0;
6971
const goto_functionst::function_mapt::const_iterator
@@ -83,15 +85,20 @@ void interpretert::initialize(bool init)
8385
done=false;
8486
if(init)
8587
{
86-
stack_depth=call_stack.size()+1;
87-
show_state();
88-
step();
89-
while(!done && (stack_depth<=call_stack.size()) && (stack_depth!=npos))
88+
// execute instructions up to and including __CPROVER_initialize()
89+
while(!done && call_stack.size() == 0)
9090
{
9191
show_state();
9292
step();
9393
}
94-
while(!done && (call_stack.size()==0))
94+
// initialization
95+
while(!done && call_stack.size() > 0)
96+
{
97+
show_state();
98+
step();
99+
}
100+
// invoke the user entry point
101+
while(!done && call_stack.size() == 0)
95102
{
96103
show_state();
97104
step();
@@ -140,18 +147,18 @@ void interpretert::command()
140147
done=true;
141148
else if(ch=='h')
142149
{
143-
status()
144-
<< "Interpreter help\n"
145-
<< "h: display this menu\n"
146-
<< "j: output json trace\n"
147-
<< "m: output memory dump\n"
148-
<< "o: output goto trace\n"
149-
<< "q: quit\n"
150-
<< "r: run until completion\n"
151-
<< "s#: step a number of instructions\n"
152-
<< "sa: step across a function\n"
153-
<< "so: step out of a function\n"
154-
<< eom;
150+
status() << "Interpreter help\n"
151+
<< "h: display this menu\n"
152+
<< "j: output json trace\n"
153+
<< "m: output memory dump\n"
154+
<< "o: output goto trace\n"
155+
<< "q: quit\n"
156+
<< "r: run up to entry point\n"
157+
<< "s#: step a number of instructions\n"
158+
<< "sa: step across a function\n"
159+
<< "so: step out of a function\n"
160+
<< "se: step until end of program\n"
161+
<< eom;
155162
}
156163
else if(ch=='j')
157164
{
@@ -200,7 +207,7 @@ void interpretert::command()
200207
else if((ch=='s') || (ch==0))
201208
{
202209
num_steps=1;
203-
stack_depth=npos;
210+
std::size_t stack_depth = npos;
204211
ch=tolower(command[1]);
205212
if(ch=='e')
206213
num_steps=npos;
@@ -210,7 +217,7 @@ void interpretert::command()
210217
stack_depth=call_stack.size()+1;
211218
else
212219
{
213-
num_steps=safe_string2size_t(command+1);
220+
num_steps = unsafe_string2size_t(command + 1);
214221
if(num_steps==0)
215222
num_steps=1;
216223
}
@@ -742,9 +749,7 @@ void interpretert::execute_assert()
742749
{
743750
if(!evaluate_boolean(pc->get_condition()))
744751
{
745-
if((target_assert==pc) || stop_on_assertion)
746-
throw "program assertion reached";
747-
else if(show)
752+
if(show)
748753
error() << "assertion failed at " << pc->location_number
749754
<< "\n" << eom;
750755
}
@@ -860,6 +865,7 @@ void interpretert::execute_function_call()
860865
void interpretert::build_memory_map()
861866
{
862867
// put in a dummy for NULL
868+
memory.clear();
863869
memory.resize(1);
864870
inverse_memory_map[0] = {};
865871

@@ -1071,12 +1077,11 @@ void interpretert::print_memory(bool input_flags)
10711077
const memory_cellt &cell=cell_address.second;
10721078
const auto identifier = address_to_symbol(i).get_identifier();
10731079
const auto offset=address_to_offset(i);
1074-
debug() << identifier << "[" << offset << "]"
1075-
<< "=" << cell.value << eom;
1080+
status() << identifier << "[" << offset << "]"
1081+
<< "=" << cell.value << eom;
10761082
if(input_flags)
1077-
debug() << "(" << static_cast<int>(cell.initialized) << ")"
1078-
<< eom;
1079-
debug() << eom;
1083+
status() << "(" << static_cast<int>(cell.initialized) << ")" << eom;
1084+
status() << eom;
10801085
}
10811086
}
10821087

src/goto-programs/interpreter_class.h

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,13 @@ class interpretert:public messaget
3030
interpretert(
3131
const symbol_tablet &_symbol_table,
3232
const goto_functionst &_goto_functions,
33-
message_handlert &_message_handler):
34-
messaget(_message_handler),
35-
symbol_table(_symbol_table),
36-
ns(_symbol_table),
37-
goto_functions(_goto_functions),
38-
stack_pointer(0),
39-
done(false),
40-
stop_on_assertion(false)
33+
message_handlert &_message_handler)
34+
: messaget(_message_handler),
35+
symbol_table(_symbol_table),
36+
ns(_symbol_table),
37+
goto_functions(_goto_functions),
38+
stack_pointer(0),
39+
done(false)
4140
{
4241
show=true;
4342
}
@@ -265,18 +264,16 @@ class interpretert:public messaget
265264
list_input_varst function_input_vars;
266265

267266
goto_functionst::function_mapt::const_iterator function;
268-
goto_programt::const_targett pc, next_pc, target_assert;
267+
goto_programt::const_targett pc, next_pc;
269268
goto_tracet steps;
270269
bool done;
271270
bool show;
272-
bool stop_on_assertion;
273271
static const size_t npos;
274272
size_t num_steps;
275273
size_t total_steps;
276274

277275
dynamic_typest dynamic_types;
278276
int num_dynamic_objects;
279-
mp_integer stack_depth;
280277
unsigned thread_id;
281278

282279
bool evaluate_boolean(const exprt &expr)

0 commit comments

Comments
 (0)