Skip to content

Commit 9f55b59

Browse files
authored
Merge pull request #7524 from qinheping/loop-contract-unwind
CONTRACTS: Add an option to not unwind transformed loops after applying loop contracts
2 parents 669baae + e6e8137 commit 9f55b59

File tree

11 files changed

+66
-6
lines changed

11 files changed

+66
-6
lines changed

doc/man/goto-instrument.1

+3
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,9 @@ force aggressive slicer to preserve all direct paths
999999
\fB\-\-apply\-loop\-contracts\fR
10001000
check and use loop contracts when provided
10011001
.TP
1002+
\fB\-loop\-contracts\-no\-unwind\fR
1003+
do not unwind transformed loops
1004+
.TP
10021005
\fB\-\-replace\-call\-with\-contract\fR \fIfun\fR
10031006
replace calls to \fIfun\fR with \fIfun\fR's contract
10041007
.TP

doc/man/goto-synthesizer.1

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ program transformation for the synthesized contracts, and then writes the
1717
resulting program as GOTO binary on disk.
1818
.SH OPTIONS
1919
.TP
20+
\fB\-loop\-contracts\-no\-unwind\fR
21+
Do not unwind transformed loops after applying the synthesized loop contracts.
22+
.TP
2023
\fB\-\-dump\-loop\-contracts
2124
Dump the synthesized loop contracts as JSON.
2225
.TP
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include <assert.h>
2+
3+
int main()
4+
{
5+
int x = 0;
6+
7+
while(x < 10)
8+
__CPROVER_loop_invariant(0 <= x && x <= 10);
9+
{
10+
x++;
11+
}
12+
13+
assert(x == 10);
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--apply-loop-contracts --loop-contracts-no-unwind _ --unwind 1 --unwinding-assertions
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
\[main.unwind.\d+\] line \d+ unwinding assertion loop 0: FAILURE
7+
^VERIFICATION FAILED$
8+
--
9+
--
10+
Check that transformed loop will not be unwound with flag --loop-contracts-no-unwind.

src/goto-instrument/contracts/contracts.cpp

+7-4
Original file line numberDiff line numberDiff line change
@@ -1445,10 +1445,13 @@ void code_contractst::apply_loop_contracts(
14451445
nondet_static(goto_model, to_exclude_from_nondet_init);
14461446

14471447
// unwind all transformed loops twice.
1448-
unwindsett unwindset{goto_model};
1449-
unwindset.parse_unwindset(loop_names, log.get_message_handler());
1450-
goto_unwindt goto_unwind;
1451-
goto_unwind(goto_model, unwindset, goto_unwindt::unwind_strategyt::ASSUME);
1448+
if(unwind_transformed_loops)
1449+
{
1450+
unwindsett unwindset{goto_model};
1451+
unwindset.parse_unwindset(loop_names, log.get_message_handler());
1452+
goto_unwindt goto_unwind;
1453+
goto_unwind(goto_model, unwindset, goto_unwindt::unwind_strategyt::ASSUME);
1454+
}
14521455

14531456
remove_skip(goto_model);
14541457

src/goto-instrument/contracts/contracts.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ Date: February 2016
3535
" --apply-loop-contracts\n" \
3636
" check and use loop contracts when provided\n"
3737

38+
#define FLAG_LOOP_CONTRACTS_NO_UNWIND "loop-contracts-no-unwind"
39+
#define HELP_LOOP_CONTRACTS_NO_UNWIND \
40+
" --loop-contracts-no-unwind\n" \
41+
" do not unwind transformed loops\n"
42+
3843
#define FLAG_REPLACE_CALL "replace-call-with-contract"
3944
#define HELP_REPLACE_CALL \
4045
" --replace-call-with-contract <function>[/contract]\n" \
@@ -75,7 +80,7 @@ class code_contractst
7580
/// with an assertion that the `requires` clause holds followed by an
7681
/// assumption that the `ensures` clause holds. In order to ensure that `F`
7782
/// actually abides by its `ensures` and `requires` clauses, you should
78-
/// separately call `code_constractst::enforce_contracts()` on `F` and verify
83+
/// separately call `code_contractst::enforce_contracts()` on `F` and verify
7984
/// it using `cbmc --function F`.
8085
void replace_calls(const std::set<std::string> &to_replace);
8186

@@ -139,6 +144,9 @@ class code_contractst
139144

140145
namespacet ns;
141146

147+
// Unwind transformed loops after applying loop contracts or not.
148+
bool unwind_transformed_loops = true;
149+
142150
protected:
143151
goto_modelt &goto_model;
144152
symbol_tablet &symbol_table;
@@ -159,7 +167,7 @@ class code_contractst
159167
std::unordered_map<goto_programt::const_targett, unsigned, const_target_hash>
160168
original_loop_number_map;
161169

162-
/// Loop havoc instructions instrumneted during applying loop contracts.
170+
/// Loop havoc instructions instrumented during applying loop contracts.
163171
std::unordered_set<goto_programt::const_targett, const_target_hash>
164172
loop_havoc_set;
165173

src/goto-instrument/goto_instrument_parse_options.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -1237,7 +1237,17 @@ void goto_instrument_parse_optionst::instrument_goto_program()
12371237
contracts.enforce_contracts(to_enforce, to_exclude_from_nondet_static);
12381238

12391239
if(cmdline.isset(FLAG_LOOP_CONTRACTS))
1240+
{
1241+
if(cmdline.isset(FLAG_LOOP_CONTRACTS_NO_UNWIND))
1242+
{
1243+
contracts.unwind_transformed_loops = false;
1244+
log.warning() << "**** WARNING: transformed loops will not be unwound "
1245+
<< "after applying loop contracts. Remember to unwind "
1246+
<< "them at least twice to pass unwinding-assertions."
1247+
<< messaget::eom;
1248+
}
12401249
contracts.apply_loop_contracts(to_exclude_from_nondet_static);
1250+
}
12411251
}
12421252

12431253
if(cmdline.isset("value-set-fi-fp-removal"))
@@ -1966,6 +1976,7 @@ void goto_instrument_parse_optionst::help()
19661976
"Code contracts:\n"
19671977
HELP_DFCC
19681978
HELP_LOOP_CONTRACTS
1979+
HELP_LOOP_CONTRACTS_NO_UNWIND
19691980
HELP_REPLACE_CALL
19701981
HELP_ENFORCE_CONTRACT
19711982
HELP_ENFORCE_CONTRACT_REC

src/goto-instrument/goto_instrument_parse_options.h

+1
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ Author: Daniel Kroening, [email protected]
9797
"(horn)(skip-loops):(model-argc-argv):" \
9898
OPT_DFCC \
9999
"(" FLAG_LOOP_CONTRACTS ")" \
100+
"(" FLAG_LOOP_CONTRACTS_NO_UNWIND ")" \
100101
"(" FLAG_REPLACE_CALL "):" \
101102
"(" FLAG_ENFORCE_CONTRACT "):" \
102103
OPT_ENFORCE_CONTRACT_REC \

src/goto-synthesizer/cegis_verifier.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,7 @@ optionalt<cext> cegis_verifiert::verify()
610610

611611
// Apply loop contracts we annotated.
612612
code_contractst cont(goto_model, log);
613+
cont.unwind_transformed_loops = false;
613614
cont.apply_loop_contracts();
614615
original_loop_number_map = cont.get_original_loop_number_map();
615616
loop_havoc_set = cont.get_loop_havoc_set();

src/goto-synthesizer/goto_synthesizer_parse_options.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ int goto_synthesizer_parse_optionst::doit()
110110
cmdline.get_values("nondet-static-exclude").begin(),
111111
cmdline.get_values("nondet-static-exclude").end());
112112
code_contractst contracts(goto_model, log);
113+
contracts.unwind_transformed_loops =
114+
!cmdline.isset(FLAG_LOOP_CONTRACTS_NO_UNWIND);
113115
contracts.apply_loop_contracts(to_exclude_from_nondet_static);
114116

115117
// recalculate numbers, etc.
@@ -183,6 +185,7 @@ void goto_synthesizer_parse_optionst::help()
183185
"\n"
184186
"Main options:\n"
185187
HELP_DUMP_LOOP_CONTRACTS
188+
HELP_LOOP_CONTRACTS_NO_UNWIND
186189
"\n"
187190
"Other options:\n"
188191
" --version show version and exit\n"

src/goto-synthesizer/goto_synthesizer_parse_options.h

+3
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@ Author: Qinheping Hu
1313

1414
#include <goto-programs/goto_model.h>
1515

16+
#include <goto-instrument/contracts/contracts.h>
17+
1618
#include "dump_loop_contracts.h"
1719

1820
// clang-format off
1921
#define GOTO_SYNTHESIZER_OPTIONS \
2022
OPT_DUMP_LOOP_CONTRACTS \
23+
"(" FLAG_LOOP_CONTRACTS_NO_UNWIND ")" \
2124
"(verbosity):(version)(xml-ui)(json-ui)" \
2225
// empty last line
2326

0 commit comments

Comments
 (0)