Skip to content

Commit e033ba1

Browse files
authored
Merge pull request #8605 from qinheping/quantifiers-with-statement-expressions
Handle quantifiers with statement expressions
2 parents 9bade97 + 5cdfb0b commit e033ba1

File tree

16 files changed

+440
-14
lines changed

16 files changed

+440
-14
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
int main()
2+
{
3+
// clang-format off
4+
// no side effects!
5+
int j = 0;
6+
//assert(j++);
7+
//assert(({int i = 0; while(i <3) i++; i <3;}));
8+
int a[5] = {0 , 0, 0, 0, 0};
9+
assert(__CPROVER_forall { int i; ({ int j = i; i=i; if(i < 0 || i >4) i = 1; ( a[i] < 5); }) });
10+
// clang-format on
11+
12+
return 0;
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
int main()
2+
{
3+
int b[2];
4+
int c[2];
5+
6+
// clang-format off
7+
// clang-format would rewrite the "==>" as "== >"
8+
__CPROVER_assume( __CPROVER_forall { char i; ({ _Bool flag = (i>=0 && i<2); flag ==> b[i]>=10 && b[i]<=10; }) } );
9+
__CPROVER_assume( __CPROVER_forall { unsigned i; ({ _Bool flag = (i>=0 && i<2); flag ==> c[i]>=10 && c[i]<=10; }) } );
10+
// clang-format on
11+
12+
assert(b[0] == 10 && b[1] == 10);
13+
assert(c[0] == 10 && c[1] == 10);
14+
15+
return 0;
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE no-new-smt
2+
main.c
3+
4+
^\*\* Results:$
5+
^\[main.assertion.1\] line 12 assertion b\[.*0\] == 10 && b\[.*1\] == 10: SUCCESS$
6+
^\[main.assertion.2\] line 13 assertion c\[.*0\] == 10 && c\[.*1\] == 10: SUCCESS$
7+
^VERIFICATION SUCCESSFUL$
8+
^EXIT=0$
9+
^SIGNAL=0$
10+
--
11+
^warning: ignoring
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
int func()
2+
{
3+
return 1;
4+
}
5+
6+
int main()
7+
{
8+
// clang-format off
9+
// no side effects!
10+
assert(__CPROVER_forall { int i; func() });
11+
// clang-format on
12+
13+
return 0;
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
quantifier-with-function-call.c
3+
4+
^EXIT=6$
5+
^SIGNAL=0$
6+
quantifier must not contain function calls
7+
--
8+
^warning: ignoring

regression/cbmc/Quantifiers1/quantifier-with-side-effect.c

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
1-
int func()
2-
{
3-
return 1;
4-
}
5-
61
int main()
72
{
3+
int j = 0;
84
// clang-format off
95
// no side effects!
10-
assert(__CPROVER_forall { int i; func() });
6+
assert(__CPROVER_forall { int i; ({ j = 1; j; }) });
117
// clang-format on
128

139
return 0;
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
CORE
22
quantifier-with-side-effect.c
33

4-
^EXIT=6$
4+
^EXIT=(127|134)$
55
^SIGNAL=0$
6-
^file .* line 10 function main: quantifier must not contain side effects$
6+
^Invariant check failed
7+
^Reason: quantifier must not contain side effects
78
--
8-
^warning: ignoring
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// clang-format off
2+
int f1(int *arr)
3+
__CPROVER_requires(__CPROVER_exists {
4+
int i;
5+
({(0 <= i && i < 8) && arr[i] == 0;})
6+
})
7+
__CPROVER_ensures(__CPROVER_exists {
8+
int i;
9+
({(0 <= i && i < 8) && arr[i] == 0;})
10+
})
11+
// clang-format on
12+
{
13+
return 0;
14+
}
15+
16+
int main()
17+
{
18+
int arr[8];
19+
f1(arr);
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE
2+
with_statement_expression.c
3+
--dfcc main --enforce-contract f1
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[f1.postcondition.\d+\] line \d+ Check ensures clause( of contract contract::f1 for function f1)?: SUCCESS$
7+
^VERIFICATION SUCCESSFUL$
8+
--
9+
^warning: ignoring
10+
--
11+
The purpose of this test is to ensure that we can safely use __CPROVER_exists within both
12+
positive and negative contexts (ENSURES and REQUIRES clauses).
13+
14+
With the SAT backend existential quantifiers in a positive context,
15+
e.g., the ENSURES clause being enforced in this case,
16+
are supported only if the quantifier is bound to a constant range.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include <stdlib.h>
2+
3+
#define MAX_LEN 8
4+
5+
// clang-format off
6+
int f1(int *arr, int len)
7+
__CPROVER_requires(
8+
len > 0 ==> __CPROVER_exists {
9+
int i;
10+
// constant bounds for explicit unrolling with SAT backend
11+
({ (0 <= i && i < MAX_LEN) && (
12+
// actual symbolic bound for `i`
13+
i < len && arr[i] == 0
14+
); })
15+
}
16+
)
17+
__CPROVER_ensures(
18+
len > 0 ==> __CPROVER_exists {
19+
int i;
20+
// constant bounds for explicit unrolling with SAT backend
21+
({ (0 <= i && i < MAX_LEN) && (
22+
// actual symbolic bound for `i`
23+
i < len && arr[i] == 0
24+
); })
25+
}
26+
)
27+
// clang-format on
28+
{
29+
return 0;
30+
}
31+
32+
int main()
33+
{
34+
int len;
35+
__CPROVER_assume(0 <= len && len <= MAX_LEN);
36+
37+
int *arr = malloc(len);
38+
if(len > 0)
39+
arr[0] = 0;
40+
41+
f1(arr, len);
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE
2+
with_statement_expression.c
3+
--no-malloc-may-fail --dfcc main --replace-call-with-contract f1 _ --no-standard-checks
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[f1.precondition.\d+\] line \d+ Check requires clause of (contract contract::f1 for function f1|f1 in main): SUCCESS$
7+
^VERIFICATION SUCCESSFUL$
8+
--
9+
^warning: ignoring
10+
--
11+
The purpose of this test is to ensure that we can safely use __CPROVER_exists within both
12+
positive and negative contexts (ENSURES and REQUIRES clauses).
13+
14+
With the SAT backend existential quantifiers in a positive context,
15+
e.g., the REQUIRES clause being replaced in this case,
16+
are supported only if the quantifier is bound to a constant range.

regression/validate-trace-xml-schema/check.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@
7474
# the SAT back-end only
7575
['integer-assignments1', 'test.desc'],
7676
# this test is expected to abort, thus producing invalid XML
77-
['String_Abstraction17', 'test.desc']
77+
['String_Abstraction17', 'test.desc'],
78+
['Quantifiers1', 'quantifier-with-side-effect.desc']
7879
]))
7980

8081
# TODO maybe consider looking them up on PATH, but direct paths are

src/ansi-c/c_typecheck_expr.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -316,10 +316,16 @@ void c_typecheck_baset::typecheck_expr_main(exprt &expr)
316316
}
317317
}
318318

319-
if(has_subexpr(where, ID_side_effect))
319+
if(has_subexpr(
320+
where,
321+
[&](const exprt &subexpr)
322+
{
323+
return can_cast_expr<side_effect_exprt>(subexpr) &&
324+
can_cast_expr<side_effect_expr_function_callt>(subexpr);
325+
}))
320326
{
321327
error().source_location = expr.source_location();
322-
error() << "quantifier must not contain side effects" << eom;
328+
error() << "quantifier must not contain function calls" << eom;
323329
throw 0;
324330
}
325331

0 commit comments

Comments
 (0)