Skip to content

Commit 391b00d

Browse files
committed
Add progressive path exploration strategy
Path exploration can now be run with a new strategy: "progressive-fifo". This strategy prefers to pop the jumps of a goto instruction rather than the next instruction. This is intended to make forward progress through a program rather than dwelling on loops. This commit adds tests for this strategy also. A new class is introduced to hold the names, descriptions and constructor thunks for all path exploration strategies. This provides a uniform way for strategy descriptions to be displayed, which can be done with the --show-symex-strategies flag.
1 parent bbb7bf9 commit 391b00d

File tree

18 files changed

+488
-31
lines changed

18 files changed

+488
-31
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ regression/**/*.smt2
5959

6060
# These files are generated from the test.in file in their directories
6161
regression/cbmc-path-fifo/*/test.desc
62+
regression/cbmc-path-progressive/*/test.desc
6263

6364
# files stored by editors
6465
*~
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
default: tests.log
2+
3+
test: gen-desc
4+
@../test.pl -p -c "../../../src/cbmc/cbmc --paths progressive-fifo --verbosity 10"
5+
6+
tests.log: ../test.pl gen-desc
7+
@../test.pl -p -c "../../../src/cbmc/cbmc --paths progressive-fifo --verbosity 10"
8+
9+
gen-desc:
10+
@../../scripts/make_descs.py
11+
12+
show:
13+
@for dir in *; do \
14+
if [ -d "$$dir" ]; then \
15+
vim -o "$$dir/*.c" "$$dir/*.out"; \
16+
fi; \
17+
done;
18+
19+
clean:
20+
find -name 'test.desc' -execdir $(RM) '{}' \;
21+
find -name '*.out' -execdir $(RM) '{}' \;
22+
find -name '*.gb' -execdir $(RM) '{}' \;
23+
$(RM) tests.log
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
int main()
2+
{
3+
int x;
4+
if(x)
5+
x = 1;
6+
else
7+
x = 0;
8+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
CORE
2+
main.c
3+
4+
activate-multi-line-match
5+
EXIT=0
6+
SIGNAL=0
7+
--
8+
^warning: ignoring
9+
--
10+
This tests that the next path is resumed before the jump path.
11+
12+
Test that the following happens in order:
13+
execute line 4
14+
save next 5
15+
save jump 7
16+
any lines
17+
execute line 4
18+
resume jump 7
19+
execute line 7
20+
any lines
21+
path is successful
22+
any lines
23+
execute line 4
24+
resume next 5
25+
execute line 5
26+
any lines
27+
path is successful
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
int main()
2+
{
3+
int x;
4+
__CPROVER_assume(x == 1);
5+
6+
while(x)
7+
--x;
8+
9+
assert(x);
10+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
CORE
2+
main.c
3+
--unwind 2
4+
activate-multi-line-match
5+
SIGNAL=0
6+
EXIT=10
7+
--
8+
^warning: ignoring
9+
--
10+
This strategy differs from 'fifo' because the failed path is the second
11+
one, not the last one.
12+
13+
Test that the following happens in order:
14+
execute line 6
15+
save next 7
16+
save jump 9
17+
18+
// We skip the loop first with this strategy. This path is infeasible,
19+
// since x is 1 so we must have entered the loop; so the solver is happy.
20+
any lines
21+
execute line 6
22+
resume jump 9
23+
execute line 9
24+
any lines
25+
path is successful
26+
27+
// We now enter the loop and execute it; we then save "entering the loop
28+
// twice" and "bailing out after the first spin".
29+
any lines
30+
execute line 6
31+
resume next 7
32+
execute line 7
33+
any lines
34+
save next 7
35+
save jump 9
36+
37+
// Since the just saved "bailing out after the first spin" is a jump,
38+
// execute that path. That path makes the assertion fail, since we
39+
// decremented x from 1 to 0.
40+
any lines
41+
execute line 6
42+
resume jump 9
43+
execute line 9
44+
any lines
45+
path is unsuccessful
46+
47+
// Finally, execute "entering the loop twice". This path is infeasible
48+
// because we cannot actually have entered the loop twice if x was only
49+
// 1 to begin with, so the solver is happy.
50+
any lines
51+
execute line 6
52+
resume next 7
53+
execute line 7
54+
any lines
55+
path is successful
56+
end
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
int main()
2+
{
3+
int x, y;
4+
if(x)
5+
{
6+
if(y)
7+
y = 1;
8+
else
9+
y = 0;
10+
}
11+
else
12+
{
13+
if(y)
14+
y = 1;
15+
else
16+
y = 0;
17+
}
18+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
CORE
2+
main.c
3+
4+
activate-multi-line-match
5+
EXIT=0
6+
SIGNAL=0
7+
--
8+
^warning: ignoring
9+
--
10+
Test that the following happens in order:
11+
execute line 4
12+
save next 6
13+
save jump 13
14+
15+
any lines
16+
execute line 4
17+
resume jump 13
18+
execute line 13
19+
save next 14
20+
save jump 16
21+
22+
any lines
23+
execute line 13
24+
resume jump 16
25+
execute line 16
26+
any lines
27+
path is successful
28+
29+
any lines
30+
execute line 4
31+
resume next 6
32+
execute line 6
33+
save next 7
34+
save jump 9
35+
36+
any lines
37+
execute line 6
38+
resume jump 9
39+
execute line 9
40+
any lines
41+
path is successful
42+
43+
any lines
44+
execute line 13
45+
resume next 14
46+
execute line 14
47+
any lines
48+
path is successful
49+
50+
any lines
51+
execute line 6
52+
resume next 7
53+
execute line 7
54+
any lines
55+
path is successful
56+
end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
int main()
2+
{
3+
int x;
4+
while(x)
5+
{
6+
int y;
7+
}
8+
int y;
9+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
CORE
2+
main.c
3+
--unwind 2
4+
activate-multi-line-match
5+
EXIT=0
6+
SIGNAL=0
7+
--
8+
^warning: ignoring
9+
--
10+
Test that the following happens in order:
11+
execute line 4
12+
save next 6
13+
save jump 8
14+
15+
// Bail out without having entered loop, ever
16+
any lines
17+
execute line 4
18+
resume jump 8
19+
execute line 8
20+
any lines
21+
path is successful
22+
23+
// Enter loop body for the first time
24+
any lines
25+
execute line 4
26+
resume next 6
27+
execute line 6
28+
any lines
29+
save next 6
30+
save jump 8
31+
32+
// Bail out after executing loop once
33+
any lines
34+
execute line 4
35+
resume jump 8
36+
execute line 8
37+
any lines
38+
path is successful
39+
40+
// Execute loop for the second time
41+
any lines
42+
execute line 4
43+
resume next 6
44+
execute line 6
45+
any lines
46+
path is successful
47+
end

src/cbmc/bmc.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,7 @@ void bmct::setup_unwind()
598598
}
599599

600600
int bmct::do_language_agnostic_bmc(
601+
const path_strategy_choosert &path_strategy_chooser,
601602
const optionst &opts,
602603
const goto_modelt &goto_model,
603604
const ui_message_handlert::uit &ui,
@@ -606,8 +607,12 @@ int bmct::do_language_agnostic_bmc(
606607
{
607608
message_handlert &mh = message.get_message_handler();
608609
safety_checkert::resultt final_result = safety_checkert::resultt::UNKNOWN;
609-
std::unique_ptr<path_storaget> worklist = path_storaget::make(
610-
path_storaget::disciplinet::FIFO);
610+
std::unique_ptr<path_storaget> worklist;
611+
std::string strategy = opts.get_option("exploration-strategy");
612+
INVARIANT(
613+
path_strategy_chooser.is_valid_strategy(strategy),
614+
"Front-end passed us invalid path strategy '" + strategy + "'");
615+
worklist = path_strategy_chooser.get(strategy);
611616
try
612617
{
613618
{

src/cbmc/bmc.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ class bmct:public safety_checkert
130130
/// function object will be called with every \ref bmct object that
131131
/// is constructed by `do_language_agnostic_bmc`.
132132
static int do_language_agnostic_bmc(
133+
const path_strategy_choosert &path_strategy_chooser,
133134
const optionst &opts,
134135
const goto_modelt &goto_model,
135136
const ui_message_handlert::uit &ui,
@@ -299,15 +300,17 @@ class path_explorert : public bmct
299300
"(no-unwinding-assertions)" \
300301
"(no-pretty-names)" \
301302
"(partial-loops)" \
302-
"(paths)" \
303+
"(paths):" \
304+
"(show-symex-strategies)" \
303305
"(depth):" \
304306
"(unwind):" \
305307
"(unwindset):" \
306308
"(graphml-witness):" \
307309
"(unwindset):"
308310

309311
#define HELP_BMC \
310-
" --paths explore paths one at a time\n" \
312+
" --paths [strategy] explore paths one at a time\n" \
313+
" --show-symex-strategies list strategies for use with --paths\n" \
311314
" --program-only only show program expression\n" \
312315
" --show-loops show the loops in the program\n" \
313316
" --depth nr limit search depth\n" \

src/cbmc/cbmc_parse_options.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ cbmc_parse_optionst::cbmc_parse_optionst(int argc, const char **argv):
6969
parse_options_baset(CBMC_OPTIONS, argc, argv),
7070
xml_interfacet(cmdline),
7171
messaget(ui_message_handler),
72-
ui_message_handler(cmdline, "CBMC " CBMC_VERSION)
72+
ui_message_handler(cmdline, "CBMC " CBMC_VERSION),
73+
path_strategy_chooser()
7374
{
7475
}
7576

@@ -80,7 +81,8 @@ ::cbmc_parse_optionst::cbmc_parse_optionst(
8081
parse_options_baset(CBMC_OPTIONS+extra_options, argc, argv),
8182
xml_interfacet(cmdline),
8283
messaget(ui_message_handler),
83-
ui_message_handler(cmdline, "CBMC " CBMC_VERSION)
84+
ui_message_handler(cmdline, "CBMC " CBMC_VERSION),
85+
path_strategy_chooser()
8486
{
8587
}
8688

@@ -107,8 +109,13 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options)
107109
exit(CPROVER_EXIT_USAGE_ERROR);
108110
}
109111

110-
if(cmdline.isset("paths"))
111-
options.set_option("paths", true);
112+
if(cmdline.isset("show-symex-strategies"))
113+
{
114+
std::cout << path_strategy_chooser.show_strategies();
115+
exit(CPROVER_EXIT_SUCCESS);
116+
}
117+
118+
path_strategy_chooser.set_path_strategy_options(cmdline, options, *this);
112119

113120
if(cmdline.isset("program-only"))
114121
options.set_option("program-only", true);
@@ -543,7 +550,11 @@ int cbmc_parse_optionst::doit()
543550
return CPROVER_EXIT_SET_PROPERTIES_FAILED;
544551

545552
return bmct::do_language_agnostic_bmc(
546-
options, goto_model, ui_message_handler.get_ui(), *this);
553+
path_strategy_chooser,
554+
options,
555+
goto_model,
556+
ui_message_handler.get_ui(),
557+
*this);
547558
}
548559

549560
bool cbmc_parse_optionst::set_properties()

src/cbmc/cbmc_parse_options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ class cbmc_parse_optionst:
9393
protected:
9494
goto_modelt goto_model;
9595
ui_message_handlert ui_message_handler;
96+
const path_strategy_choosert path_strategy_chooser;
9697

9798
void eval_verbosity();
9899
void register_languages();

0 commit comments

Comments
 (0)