Skip to content

Commit c14a5f3

Browse files
committed
fix recording old variant value at the beginning of loop body
The loop variant value is supposed to be recorded just after the loop head (i.e., at the beginning of the loop body). Previously this was done by computing std::next(loop_head). However, complex C loop guards could be compiled to multiple GOTO instructions and it might be necessarey to advance the loop_head multiple times. The proposed change advanced the loop_head instruction pointer until the source_location differs.
1 parent d92a29f commit c14a5f3

File tree

3 files changed

+40
-1
lines changed

3 files changed

+40
-1
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
int main()
2+
{
3+
int x = 0;
4+
int *y = &x;
5+
6+
while(*y <= 0 && *y < 10)
7+
// clang-format off
8+
__CPROVER_loop_invariant(1 == 1)
9+
__CPROVER_decreases(10 - x)
10+
// clang-format on
11+
{
12+
x++;
13+
}
14+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
CORE
2+
main.c
3+
--apply-loop-contracts
4+
^VERIFICATION FAILED$
5+
^EXIT=10$
6+
^SIGNAL=0$
7+
--
8+
--
9+
This test fails even without the fix proposed in the commit, so it should be improved.
10+
It is expected to fail because the proposed invariant isn't strong enough to help prove
11+
termination using the specified variant.
12+
13+
The test highlights a case where a C loop guard is compiled to multiple GOTO instructions.
14+
Therefore the loop_head pointer needs to be advanced multiple times to get to the loop body,
15+
where the initial value of the loop variant (/ ranking function) must be recorded.
16+
17+
The proposed fix advances the pointer until the source_location differs from the original
18+
loop_head's source_location. However, this might still not work if the loop guard in the
19+
original C code was split across multiple lines in the first place.

src/goto-instrument/contracts/contracts.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,13 @@ void code_contractst::check_apply_loop_contracts(
209209
converter.goto_convert(old_decreases_assignment, havoc_code, mode);
210210
}
211211

212-
goto_function.body.destructive_insert(std::next(loop_head), havoc_code);
212+
// Forward the loop_head iterator until the start of the body.
213+
// This is necessary because complex C loop_head conditions could be
214+
// converted to multiple GOTO instructions (e.g. temporaries are introduced).
215+
const auto head_loc = loop_head->source_location();
216+
while(loop_head->source_location() == head_loc)
217+
loop_head = std::next(loop_head);
218+
goto_function.body.destructive_insert(loop_head, havoc_code);
213219
}
214220

215221
// Generate: assert(invariant) just after the loop exits

0 commit comments

Comments
 (0)