Skip to content

Commit 7cd36a7

Browse files
committed
Unwinding options --unwinding-assertions and --partial-loops do not conflict
By default, bounded loop unwinding will yield an assumption to ensure that all counterexamples are genuine. Option --unwinding-assertions requests that an additional assertion be generated, which will furthermore ensure that successful verification does not constitute spurious proof. Option --partial-loops disables generating the unwinding assumption. Therefore, --unwinding-assertions and --partial-loops each control (not) generating one instruction, but there is no overlap in the instructions that they are (not) generating. It is, thus, safe to use these options together.
1 parent 3f175c9 commit 7cd36a7

File tree

11 files changed

+46
-48
lines changed

11 files changed

+46
-48
lines changed

doc/cprover-manual/cbmc-unwinding.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,9 @@ to the later assertion, use the option
161161
This option will allow paths that execute loops only partially, enabling
162162
a counterexample for the assertion above even for small unwinding
163163
bounds. The disadvantage of using this option is that the resulting path
164-
may be spurious, that is, it may not exist in the original program.
164+
may be spurious, that is, it may not exist in the original program. If
165+
`--unwinding-assertions` is also used and all unwinding assertions pass,
166+
then no counterexample involved such a spurious path.
165167

166168
### Depth-based Unwinding
167169

jbmc/src/jbmc/jbmc_parse_options.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -252,14 +252,6 @@ void jbmc_parse_optionst::get_command_line_options(optionst &options)
252252
"partial-loops",
253253
cmdline.isset("partial-loops"));
254254

255-
if(options.get_bool_option("partial-loops") &&
256-
options.get_bool_option("unwinding-assertions"))
257-
{
258-
log.error() << "--partial-loops and --unwinding-assertions "
259-
<< "must not be given together" << messaget::eom;
260-
exit(1); // should contemplate EX_USAGE from sysexits.h
261-
}
262-
263255
// remove unused equations
264256
options.set_option(
265257
"slice-formula",

regression/cbmc-concurrency/recursion1/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
CORE
22
main.c
3-
--unwind 1 --partial-loops --depth 100
3+
--unwind 1 --partial-loops --unwinding-assertions --depth 100
44
^EXIT=10$
55
^SIGNAL=0$
66
^VERIFICATION FAILED$
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--unwind 9 --unwinding-assertions --partial-loops
4+
^\[main.assertion.1\] line 6 fails when fully unwinding the loop: FAILURE$
5+
^\*\* 2 of 2 failed
6+
^EXIT=10$
7+
^SIGNAL=0$
8+
^VERIFICATION FAILED$
9+
--
10+
^warning: ignoring

src/cbmc/cbmc_parse_options.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -160,14 +160,6 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options)
160160
options.set_option("no-array-field-sensitivity", true);
161161
}
162162

163-
if(cmdline.isset("partial-loops") && cmdline.isset("unwinding-assertions"))
164-
{
165-
log.error()
166-
<< "--partial-loops and --unwinding-assertions must not be given "
167-
<< "together" << messaget::eom;
168-
exit(CPROVER_EXIT_USAGE_ERROR);
169-
}
170-
171163
if(cmdline.isset("reachability-slice") &&
172164
cmdline.isset("reachability-slice-fb"))
173165
{

src/goto-checker/bmc_util.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ void run_property_decider(
234234
" --show-vcc show the verification conditions\n" \
235235
" --slice-formula remove assignments unrelated to property\n" \
236236
" --unwinding-assertions generate unwinding assertions (cannot be\n" \
237-
" used with --cover or --partial-loops)\n" \
237+
" used with --cover)\n" \
238238
" --partial-loops permit paths with partial loops\n" \
239239
" --no-self-loops-to-assumptions\n" \
240240
" do not simplify while(1){} to assume(0)\n" \

src/goto-instrument/goto_instrument_parse_options.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,17 +184,26 @@ int goto_instrument_parse_optionst::doit()
184184
bool unwinding_assertions=cmdline.isset("unwinding-assertions");
185185
bool partial_loops=cmdline.isset("partial-loops");
186186
bool continue_as_loops=cmdline.isset("continue-as-loops");
187-
188-
if(unwinding_assertions+partial_loops+continue_as_loops>1)
189-
throw "more than one of --unwinding-assertions,--partial-loops,"
190-
"--continue-as-loops selected";
187+
if(continue_as_loops)
188+
{
189+
if(unwinding_assertions)
190+
{
191+
throw "unwinding assertions cannot be used with "
192+
"--continue-as-loops";
193+
}
194+
else if(partial_loops)
195+
throw "partial loops cannot be used with --continue-as-loops";
196+
}
191197

192198
goto_unwindt::unwind_strategyt unwind_strategy=
193199
goto_unwindt::unwind_strategyt::ASSUME;
194200

195201
if(unwinding_assertions)
196202
{
197-
unwind_strategy = goto_unwindt::unwind_strategyt::ASSERT_ASSUME;
203+
if(partial_loops)
204+
unwind_strategy = goto_unwindt::unwind_strategyt::ASSERT_PARTIAL;
205+
else
206+
unwind_strategy = goto_unwindt::unwind_strategyt::ASSERT_ASSUME;
198207
}
199208
else if(partial_loops)
200209
{

src/goto-instrument/unwind.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ void goto_unwindt::unwind(
130130
{
131131
PRECONDITION(
132132
unwind_strategy == unwind_strategyt::ASSERT_ASSUME ||
133+
unwind_strategy == unwind_strategyt::ASSERT_PARTIAL ||
133134
unwind_strategy == unwind_strategyt::ASSUME);
134135

135136
goto_programt::const_targett t=loop_exit;
@@ -148,7 +149,9 @@ void goto_unwindt::unwind(
148149
exit_cond = loop_head->get_condition();
149150
}
150151

151-
if(unwind_strategy == unwind_strategyt::ASSERT_ASSUME)
152+
if(
153+
unwind_strategy == unwind_strategyt::ASSERT_ASSUME ||
154+
unwind_strategy == unwind_strategyt::ASSERT_PARTIAL)
152155
{
153156
goto_programt::targett assertion = rest_program.add(
154157
goto_programt::make_assertion(exit_cond, loop_head->source_location()));

src/goto-instrument/unwind.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class goto_unwindt
2626
CONTINUE,
2727
PARTIAL,
2828
ASSERT_ASSUME,
29+
ASSERT_PARTIAL,
2930
ASSUME
3031
};
3132

src/goto-symex/symex_function_call.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -245,15 +245,10 @@ void goto_symext::symex_function_call_post_clean(
245245
// see if it's too much
246246
if(stop_recursing)
247247
{
248-
if(symex_config.partial_loops)
248+
if(symex_config.unwinding_assertions)
249+
vcc(false_exprt(), "recursion unwinding assertion", state);
250+
if(!symex_config.partial_loops)
249251
{
250-
// it's ok, ignore
251-
}
252-
else
253-
{
254-
if(symex_config.unwinding_assertions)
255-
vcc(false_exprt(), "recursion unwinding assertion", state);
256-
257252
// Rule out this path:
258253
symex_assume_l2(state, false_exprt());
259254
}

src/goto-symex/symex_goto.cpp

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -932,25 +932,19 @@ void goto_symext::loop_bound_exceeded(
932932
else
933933
negated_cond=not_exprt(guard);
934934

935-
if(!symex_config.partial_loops)
935+
if(symex_config.unwinding_assertions)
936936
{
937-
if(symex_config.unwinding_assertions)
938-
{
939-
// Generate VCC for unwinding assertion.
940-
vcc(
941-
negated_cond,
942-
"unwinding assertion loop " + std::to_string(loop_number),
943-
state);
944-
}
937+
// Generate VCC for unwinding assertion.
938+
vcc(
939+
negated_cond,
940+
"unwinding assertion loop " + std::to_string(loop_number),
941+
state);
942+
}
945943

944+
if(!symex_config.partial_loops)
945+
{
946946
// generate unwinding assumption, unless we permit partial loops
947947
symex_assume_l2(state, negated_cond);
948-
949-
if(symex_config.unwinding_assertions)
950-
{
951-
// add to state guard to prevent further assignments
952-
state.guard.add(negated_cond);
953-
}
954948
}
955949
}
956950

0 commit comments

Comments
 (0)