Skip to content

Commit 62f4b81

Browse files
committed
Invoke goto_functions.update() after inlining
Inlining will alter location (instruction) numbers, which need to be updated to once again be globally unique. With this change, invar_check_large requires an assigns clause for the loop as the local may alias analysis returns "UNKNOWN." The previous result was actually unsound, because the automatically computed assigns set did not include arr0, arr1, arr2, arr3, arr4. Once we havoc these, however, the loop invariant is no longer strong enough to prove the decreases clause.
1 parent 40fd86b commit 62f4b81

File tree

3 files changed

+20
-5
lines changed

3 files changed

+20
-5
lines changed

regression/contracts/invar_check_large/main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ int main()
2323
int r = 1;
2424
while(h > l)
2525
// clang-format off
26+
__CPROVER_assigns(arr0, arr1, arr2, arr3, arr4, h, l, r)
2627
__CPROVER_loop_invariant(
2728
// Turn off `clang-format` because it breaks the `==>` operator.
2829
h >= l &&

regression/contracts/invar_check_large/test.desc

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
CORE
1+
KNOWNBUG
22
main.c
33
--apply-loop-contracts
44
^EXIT=0$
55
^SIGNAL=0$
66
^\[main.1\] .* Check loop invariant before entry: SUCCESS$
7-
^\[main.2\] .* Check that loop invariant is preserved: SUCCESS$
7+
^\[main.\d+\] .* Check that loop invariant is preserved: SUCCESS$
88
^\[main.assertion.1\] .* assertion 0 <= r && r < 5: SUCCESS$
99
^\[main.assertion.2\] .* assertion \*\(arr\[r\]\) == pivot: SUCCESS$
1010
^\[main.assertion.3\] .* assertion 0 < r ==> arr0 <= pivot: SUCCESS$
@@ -23,3 +23,7 @@ This test checks the invariant contracts on a larger problem --- in this case,
2323
the partition function of quicksort, applied to a fixed-length array.
2424
This serves as a stop-gap test until issues to do with quantifiers and
2525
side-effects in loop invariants are fixed.
26+
27+
We currently fail to prove the "decreases" clause once "arr0, arr1, arr2, arr3,
28+
arr4" are listed in the assigns clause. Automatic inference of the assigns
29+
clause failed to call these out, resulting in a spurious termination proof.

src/goto-instrument/contracts/contracts.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -682,14 +682,23 @@ void code_contractst::apply_loop_contract(
682682
const irep_idt &function_name,
683683
goto_functionst::goto_functiont &goto_function)
684684
{
685-
local_may_aliast local_may_alias(goto_function);
686-
natural_loops_mutablet natural_loops(goto_function.body);
685+
const bool may_have_loops = std::any_of(
686+
goto_function.body.instructions.begin(),
687+
goto_function.body.instructions.end(),
688+
[](const goto_programt::instructiont &instruction)
689+
{
690+
return instruction.is_backwards_goto();
691+
});
687692

688-
if(!natural_loops.loop_map.size())
693+
if(!may_have_loops)
689694
return;
690695

691696
goto_function_inline(
692697
goto_functions, function_name, ns, log.get_message_handler());
698+
goto_functions.update();
699+
700+
local_may_aliast local_may_alias(goto_function);
701+
natural_loops_mutablet natural_loops(goto_function.body);
693702

694703
// A graph node type that stores information about a loop.
695704
// We create a DAG representing nesting of various loops in goto_function,
@@ -1008,6 +1017,7 @@ bool code_contractst::check_frame_conditions_function(const irep_idt &function)
10081017
// Inline all function calls.
10091018
goto_function_inline(
10101019
goto_functions, function_obj->first, ns, log.get_message_handler());
1020+
goto_functions.update();
10111021

10121022
// Insert write set inclusion checks.
10131023
check_frame_conditions(

0 commit comments

Comments
 (0)