Skip to content

Commit 6c2d7cc

Browse files
authored
Merge pull request #8360 from qinheping/feature/check_side_effect_during_instrumentation
[CONTRACTS] Check side effect of loop contracts during instrumentation
2 parents 51b157f + 2d416e1 commit 6c2d7cc

File tree

16 files changed

+193
-65
lines changed

16 files changed

+193
-65
lines changed

doc/man/goto-instrument.1

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1015,7 +1015,13 @@ force aggressive slicer to preserve all direct paths
10151015
.SS "Code contracts:"
10161016
.TP
10171017
\fB\-\-apply\-loop\-contracts\fR
1018-
check and use loop contracts when provided
1018+
.TP
1019+
\fB\-disable\-loop\-contracts\-side\-effect\-check\fR
1020+
UNSOUND OPTION. Disable checking the absence of side effects in loop
1021+
contract clauses. In absence of such checking, loop contracts clauses will
1022+
accept more expressions, such as pure functions and statement expressions.
1023+
But user have to make sure the loop contracts are side-effect free by them self
1024+
to get a sound result.
10191025
.TP
10201026
\fB\-loop\-contracts\-no\-unwind\fR
10211027
do not unwind transformed loops
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
int main()
2+
{
3+
unsigned i;
4+
5+
while(i > 1)
6+
__CPROVER_loop_invariant(({
7+
unsigned b = i >= 1;
8+
goto label;
9+
b = i < 1;
10+
label:
11+
b;
12+
}))
13+
{
14+
i--;
15+
}
16+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--dfcc main --apply-loop-contracts --disable-loop-contracts-side-effect-check
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
This test demonstrates a case where the loop invariant
10+
is a side-effect free statement expression.

regression/contracts-dfcc/variant_function_call_fail/test.desc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
CORE
22
main.c
33
--dfcc main --apply-loop-contracts
4-
^Decreases clause is not side-effect free. \(at: file main.c line .* function main\)$
5-
^EXIT=70$
4+
^Decreases clause is not side-effect free.$
5+
^EXIT=6$
66
^SIGNAL=0$
77
--
88
--

regression/contracts-dfcc/variant_side_effects_fail/test.desc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
CORE
22
main.c
33
--dfcc main --apply-loop-contracts
4-
^Decreases clause is not side-effect free. \(at: file main.c line .* function main\)$
5-
^EXIT=70$
4+
^Decreases clause is not side-effect free.$
5+
^EXIT=6$
66
^SIGNAL=0$
77
--
88
--
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
int main()
2+
{
3+
unsigned i;
4+
5+
while(i > 1)
6+
__CPROVER_loop_invariant(({
7+
unsigned b = i >= 1;
8+
goto label;
9+
b = i < 1;
10+
label:
11+
b;
12+
}))
13+
{
14+
i--;
15+
}
16+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--apply-loop-contracts --disable-loop-contracts-side-effect-check
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
This test demonstrates a case where the loop invariant
10+
is a side-effect free statement expression.

src/ansi-c/goto-conversion/goto_convert.cpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,12 +1036,6 @@ void goto_convertt::convert_loop_contracts(
10361036
static_cast<const exprt &>(code.find(ID_C_spec_loop_invariant));
10371037
if(!invariant.is_nil())
10381038
{
1039-
if(has_subexpr(invariant, ID_side_effect))
1040-
{
1041-
throw incorrect_goto_program_exceptiont(
1042-
"Loop invariant is not side-effect free.", code.find_source_location());
1043-
}
1044-
10451039
PRECONDITION(loop->is_goto() || loop->is_incomplete_goto());
10461040
loop->condition_nonconst().add(ID_C_spec_loop_invariant).swap(invariant);
10471041
}
@@ -1050,13 +1044,6 @@ void goto_convertt::convert_loop_contracts(
10501044
static_cast<const exprt &>(code.find(ID_C_spec_decreases));
10511045
if(!decreases_clause.is_nil())
10521046
{
1053-
if(has_subexpr(decreases_clause, ID_side_effect))
1054-
{
1055-
throw incorrect_goto_program_exceptiont(
1056-
"Decreases clause is not side-effect free.",
1057-
code.find_source_location());
1058-
}
1059-
10601047
PRECONDITION(loop->is_goto() || loop->is_incomplete_goto());
10611048
loop->condition_nonconst().add(ID_C_spec_decreases).swap(decreases_clause);
10621049
}

src/cprover/instrument_given_invariants.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Author: Daniel Kroening, [email protected]
1111

1212
#include "instrument_given_invariants.h"
1313

14+
#include <util/expr_util.h>
15+
1416
#include <goto-programs/goto_model.h>
1517

1618
void instrument_given_invariants(goto_functionst::function_mapt::value_type &f)
@@ -25,6 +27,15 @@ void instrument_given_invariants(goto_functionst::function_mapt::value_type &f)
2527
{
2628
const auto &invariants = static_cast<const exprt &>(
2729
it->condition().find(ID_C_spec_loop_invariant));
30+
if(!invariants.is_nil())
31+
{
32+
if(has_subexpr(invariants, ID_side_effect))
33+
{
34+
throw incorrect_goto_program_exceptiont(
35+
"Loop invariant is not side-effect free.",
36+
it->condition().find_source_location());
37+
}
38+
}
2839

2940
for(const auto &invariant : invariants.operands())
3041
{

src/goto-instrument/contracts/contracts.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -983,12 +983,11 @@ void code_contractst::apply_loop_contract(
983983
goto_function.body, loop_head, goto_programt::make_skip());
984984
loop_end->set_target(loop_head);
985985

986-
exprt assigns_clause =
987-
static_cast<const exprt &>(loop_end->condition().find(ID_C_spec_assigns));
988-
exprt invariant = static_cast<const exprt &>(
989-
loop_end->condition().find(ID_C_spec_loop_invariant));
990-
exprt decreases_clause = static_cast<const exprt &>(
991-
loop_end->condition().find(ID_C_spec_decreases));
986+
exprt assigns_clause = get_loop_assigns(loop_end);
987+
exprt invariant =
988+
get_loop_invariants(loop_end, loop_contract_config.check_side_effect);
989+
exprt decreases_clause =
990+
get_loop_decreases(loop_end, loop_contract_config.check_side_effect);
992991

993992
if(invariant.is_nil())
994993
{

0 commit comments

Comments
 (0)