Skip to content

Commit f254d1a

Browse files
authored
Merge pull request #7318 from qinheping/loop-contract-simplification
CONTRACTS: Unwind transformed loops after loop contract transformation
2 parents d5c5872 + aecc7b4 commit f254d1a

File tree

4 files changed

+38
-2
lines changed

4 files changed

+38
-2
lines changed

regression/contracts/invar_assigns_empty/test.desc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ main.c
33
--apply-loop-contracts
44
^EXIT=0$
55
^SIGNAL=0$
6-
^\[main.1\] .* Check loop invariant before entry: SUCCESS$
7-
^\[main.2\] .* Check that loop invariant is preserved: SUCCESS$
6+
^\[main.\d+\] .* Check loop invariant before entry: SUCCESS$
7+
^\[main.\d+\] .* Check that loop invariant is preserved: SUCCESS$
88
^VERIFICATION SUCCESSFUL$
99
--
1010
--
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CORE
2+
main.c
3+
--apply-loop-contracts --unwind 1 --unwinding-assertions
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main\.\d+\] .* Check loop invariant before entry: SUCCESS$
7+
^\[main\.\d+\] .* Check that loop invariant is preserved: SUCCESS$
8+
^\[main.assigns.\d+\] .* Check that s is assignable: SUCCESS$
9+
^\[main.assigns.\d+\] .* Check that r is assignable: SUCCESS$
10+
^\[main\.assertion\.\d+\] .* assertion r == 0: SUCCESS$
11+
^\[main\.assertion\.\d+\] .* assertion s == 1: SUCCESS$
12+
^VERIFICATION SUCCESSFUL$
13+
--
14+
This test checks that there is no loop after contract transforamtion.

src/goto-instrument/contracts/contracts.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ Date: February 2016
3636
#include <ansi-c/c_expr.h>
3737
#include <goto-instrument/havoc_utils.h>
3838
#include <goto-instrument/nondet_static.h>
39+
#include <goto-instrument/unwind.h>
40+
#include <goto-instrument/unwindset.h>
3941
#include <langapi/language_util.h>
4042

4143
#include "cfg_info.h"
@@ -1016,6 +1018,17 @@ void code_contractst::apply_loop_contract(
10161018
goto_functions.update();
10171019
natural_loops_mutablet updated_loops(goto_function.body);
10181020

1021+
// We will unwind all transformed loops twice. Store the names of
1022+
// to-unwind-loops here and perform the unwinding after transformation done.
1023+
// As described in `check_apply_loop_contracts`, loops with loop contracts
1024+
// will be transformed to a loop that execute exactly twice: one for base
1025+
// case and one for step case. So we unwind them here to avoid users
1026+
// incorrectly unwind them only once.
1027+
std::string to_unwind = id2string(function_name) + "." +
1028+
std::to_string(loop_node.end_target->loop_number) +
1029+
":2";
1030+
loop_names.push_back(to_unwind);
1031+
10191032
check_apply_loop_contracts(
10201033
function_name,
10211034
goto_function,
@@ -1459,6 +1472,12 @@ void code_contractst::apply_loop_contracts(
14591472
"of static/global variables."
14601473
<< messaget::eom;
14611474
nondet_static(goto_model, to_exclude_from_nondet_init);
1475+
1476+
// unwind all transformed loops twice.
1477+
unwindsett unwindset{goto_model};
1478+
unwindset.parse_unwindset(loop_names, log.get_message_handler());
1479+
goto_unwindt goto_unwind;
1480+
goto_unwind(goto_model, unwindset, goto_unwindt::unwind_strategyt::ASSUME);
14621481
}
14631482

14641483
void code_contractst::enforce_contracts(

src/goto-instrument/contracts/contracts.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ class code_contractst
141141

142142
std::unordered_set<irep_idt> summarized;
143143

144+
/// Name of loops we are going to unwind.
145+
std::list<std::string> loop_names;
146+
144147
public:
145148
/// Translates a function_pointer_obeys_contract_exprt into an assertion
146149
/// ```

0 commit comments

Comments
 (0)