Skip to content

Commit f09d5ef

Browse files
committed
Document and test thread-specific unwindset option
We had working support for thread-specific limits as of 7f7e3c4, but seemingly never exposed this in documentation. Also cleaned up the command-line parsing code to avoid repeated find/rfind operations.
1 parent fdc7ba5 commit f09d5ef

File tree

7 files changed

+65
-24
lines changed

7 files changed

+65
-24
lines changed

doc/cprover-manual/cbmc-unwinding.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,10 @@ first use:
9090
to obtain a list of all loops in the program. Then identify the loops
9191
you need to set a separate bound for, and note their loop ID. Then use:
9292

93-
--unwindset L:B
93+
--unwindset [T:]L:B
9494

95-
where `L` denotes a loop ID and `B` denotes the bound for that loop. The
96-
option can be given multiple times.
95+
where `L` denotes a loop ID and `B` denotes the bound for that loop in thread T,
96+
if a thread number is included. The option can be given multiple times.
9797

9898
As an example, consider a program with two loops in the function main:
9999

doc/man/cbmc.1

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,9 @@ Only show program expression
137137
Limit search depth
138138
.IP "--unwind nr "
139139
Unwind loops nr times
140-
.IP "--unwindset L:B,..."
141-
Unwind loop L with a bound of B (use \-\-show\-loops to get the loop IDs)
140+
.IP "--unwindset [T:]L:B,..."
141+
Unwind loop L with a bound of B, optionally restricted to thread T (use
142+
\-\-show\-loops to get the loop IDs)
142143
.IP --show-vcc
143144
Show the verification conditions
144145
.IP --slice-formula
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
void *thr1(void *arg)
2+
{
3+
for(int i = 0; i < *(int *)arg; ++i)
4+
;
5+
6+
return 0;
7+
}
8+
9+
int l1 = 1;
10+
int l2 = 2;
11+
12+
int main()
13+
{
14+
__CPROVER_ASYNC_1:
15+
thr1(&l1);
16+
__CPROVER_ASYNC_2:
17+
thr1(&l2);
18+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--unwindset 1:thr1.0:2,2:thr1.0:3 --unwinding-assertions
4+
^VERIFICATION SUCCESSFUL$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^warning: ignoring

src/goto-checker/bmc_util.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Author: Daniel Kroening, Peter Schrammel
1717

1818
#include <goto-symex/build_goto_trace.h>
1919

20+
#include <goto-instrument/unwindset.h>
21+
2022
#include "incremental_goto_checker.h"
2123
#include "properties.h"
2224

@@ -172,7 +174,6 @@ void run_property_decider(
172174
#define OPT_BMC \
173175
"(program-only)" \
174176
"(show-byte-ops)" \
175-
"(show-loops)" \
176177
"(show-vcc)" \
177178
"(show-goto-symex-steps)" \
178179
"(show-points-to-sets)" \
@@ -185,18 +186,17 @@ void run_property_decider(
185186
"(paths):" \
186187
"(show-symex-strategies)" \
187188
"(depth):" \
188-
"(unwind):" \
189189
"(max-field-sensitivity-array-size):" \
190190
"(no-array-field-sensitivity)" \
191191
"(graphml-witness):" \
192-
"(unwindset):" \
193192
"(symex-complexity-limit):" \
194193
"(symex-complexity-failed-child-loops-limit):" \
195194
"(incremental-loop):" \
196195
"(unwind-min):" \
197196
"(unwind-max):" \
198197
"(ignore-properties-before-unwind-min)" \
199198
"(symex-cache-dereferences)" \
199+
OPT_UNWINDSET \
200200

201201
#define HELP_BMC \
202202
" --paths [strategy] explore paths one at a time\n" \
@@ -207,7 +207,6 @@ void run_property_decider(
207207
" pointer dereference. Requires --json-ui.\n" \
208208
" --program-only only show program expression\n" \
209209
" --show-byte-ops show all byte extracts and updates\n" \
210-
" --show-loops show the loops in the program\n" \
211210
" --depth nr limit search depth\n" \
212211
" --max-field-sensitivity-array-size M\n" \
213212
" maximum size M of arrays for which field\n" \
@@ -218,9 +217,7 @@ void run_property_decider(
218217
"this is\n" \
219218
" equivalent to setting the maximum field \n" \
220219
" sensitivity size for arrays to 0\n" \
221-
" --unwind nr unwind nr times\n" \
222-
" --unwindset L:B,... unwind loop L with a bound of B\n" \
223-
" (use --show-loops to get the loop IDs)\n" \
220+
HELP_UNWINDSET \
224221
" --incremental-loop L check properties after each unwinding\n" \
225222
" of loop L\n" \
226223
" (use --show-loops to get the loop IDs)\n" \

src/goto-instrument/unwindset.cpp

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,26 @@ void unwindsett::parse_unwind(const std::string &unwind)
2525

2626
void unwindsett::parse_unwindset_one_loop(std::string val)
2727
{
28-
unsigned thread_nr = 0;
29-
bool thread_nr_set = false;
28+
if(val.empty())
29+
return;
3030

31-
if(!val.empty() && isdigit(val[0]) && val.find(":") != std::string::npos)
31+
optionalt<unsigned> thread_nr;
32+
if(isdigit(val[0]))
3233
{
33-
std::string nr = val.substr(0, val.find(":"));
34-
thread_nr = unsafe_string2unsigned(nr);
35-
thread_nr_set = true;
36-
val.erase(0, nr.size() + 1);
34+
auto c_pos = val.find(':');
35+
if(c_pos != std::string::npos)
36+
{
37+
std::string nr = val.substr(0, c_pos);
38+
thread_nr = unsafe_string2unsigned(nr);
39+
val.erase(0, nr.size() + 1);
40+
}
3741
}
3842

39-
if(val.rfind(":") != std::string::npos)
43+
auto last_c_pos = val.rfind(':');
44+
if(last_c_pos != std::string::npos)
4045
{
41-
std::string id = val.substr(0, val.rfind(":"));
42-
std::string uw_string = val.substr(val.rfind(":") + 1);
46+
std::string id = val.substr(0, last_c_pos);
47+
std::string uw_string = val.substr(last_c_pos + 1);
4348

4449
// the below initialisation makes g++-5 happy
4550
optionalt<unsigned> uw(0);
@@ -49,8 +54,8 @@ void unwindsett::parse_unwindset_one_loop(std::string val)
4954
else
5055
uw = unsafe_string2unsigned(uw_string);
5156

52-
if(thread_nr_set)
53-
thread_loop_map[std::pair<irep_idt, unsigned>(id, thread_nr)] = uw;
57+
if(thread_nr.has_value())
58+
thread_loop_map[std::pair<irep_idt, unsigned>(id, *thread_nr)] = uw;
5459
else
5560
loop_map[id] = uw;
5661
}

src/goto-instrument/unwindset.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,16 @@ class unwindsett
5656
void parse_unwindset_one_loop(std::string loop_limit);
5757
};
5858

59+
#define OPT_UNWINDSET \
60+
"(show-loops)" \
61+
"(unwind):" \
62+
"(unwindset):"
63+
64+
#define HELP_UNWINDSET \
65+
" --show-loops show the loops in the program\n" \
66+
" --unwind nr unwind nr times\n" \
67+
" --unwindset [T:]L:B,... unwind loop L with a bound of B\n" \
68+
" (optionally restricted to thread T)\n" \
69+
" (use --show-loops to get the loop IDs)\n"
70+
5971
#endif // CPROVER_GOTO_INSTRUMENT_UNWINDSET_H

0 commit comments

Comments
 (0)