-
Notifications
You must be signed in to change notification settings - Fork 273
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CONTRACTS: is_fresh now checks separation of byte-intervals instead o…
…f whole objects. When assumed, is_fresh still builds distinct objects. When asserted, it allows for either distinct objects, or distinct byte intervals within the same object. A function foo(int *a, int *b) that requires is_fresh(a) and is_fresh(b) is checked under the assumption that a and b are distinct objects, but can still be used in contexts where a and b are distinct slices within the same base object. This is sound because the function is checked under the stronger precondition and hence is proved to not perform any operation that requires that a and b be in the same object, such as pointer differences or comparisons.
- Loading branch information
Remi Delmas
committed
Feb 28, 2025
1 parent
159af34
commit 7bdf6f7
Showing
9 changed files
with
206 additions
and
20 deletions.
There are no files selected for viewing
34 changes: 34 additions & 0 deletions
34
regression/contracts-dfcc/test_is_fresh_weak_assert_ensures_fail/main.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#include <stdlib.h> | ||
int nondet_int(); | ||
|
||
void foo(int *a, int **b_out, int **c_out) | ||
// clang-format off | ||
__CPROVER_requires(__CPROVER_is_fresh(a, 2*sizeof(int))) | ||
__CPROVER_requires(__CPROVER_is_fresh(b_out, sizeof(int*))) | ||
__CPROVER_requires(__CPROVER_is_fresh(c_out, sizeof(int*))) | ||
__CPROVER_ensures(__CPROVER_is_fresh(*b_out, sizeof(int))) | ||
__CPROVER_ensures(__CPROVER_is_fresh(*c_out, sizeof(int))) | ||
__CPROVER_assigns(*b_out, *c_out) | ||
__CPROVER_ensures(**b_out == a[0]) | ||
__CPROVER_ensures(**c_out == a[1]) | ||
// clang-format on | ||
{ | ||
if (nondet_int()) { | ||
*b_out = malloc(sizeof(int)); | ||
__CPROVER_assume(*b_out != NULL); | ||
*c_out = malloc(sizeof(int)); | ||
__CPROVER_assume(*c_out != NULL); | ||
} else { | ||
*b_out = malloc(2*sizeof(int)); | ||
__CPROVER_assume(*b_out != NULL); | ||
*c_out = *b_out; // not separated, expect failure | ||
} | ||
**b_out = a[0]; | ||
**c_out = a[1]; | ||
} | ||
|
||
int main() | ||
{ | ||
int *a, **b_out, **c_out; | ||
foo(a, b_out, c_out); | ||
} |
12 changes: 12 additions & 0 deletions
12
regression/contracts-dfcc/test_is_fresh_weak_assert_ensures_fail/test.desc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
CORE dfcc-only | ||
main.c | ||
--dfcc main --enforce-contract foo | ||
^\[foo.postcondition.\d+\].*Check ensures clause of contract contract::foo for function foo: FAILURE$ | ||
^EXIT=10$ | ||
^SIGNAL=0$ | ||
^VERIFICATION FAILED$ | ||
-- | ||
-- | ||
This test checks that when __CPROVER_is_fresh is asserted in ensures clauses | ||
in contract checking mode, it detects byte interval separation failure | ||
within the same object. |
34 changes: 34 additions & 0 deletions
34
regression/contracts-dfcc/test_is_fresh_weak_assert_ensures_pass/main.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#include <stdlib.h> | ||
int nondet_int(); | ||
|
||
void foo(int *a, int **b_out, int **c_out) | ||
// clang-format off | ||
__CPROVER_requires(__CPROVER_is_fresh(a, 2*sizeof(int))) | ||
__CPROVER_requires(__CPROVER_is_fresh(b_out, sizeof(int*))) | ||
__CPROVER_requires(__CPROVER_is_fresh(c_out, sizeof(int*))) | ||
__CPROVER_ensures(__CPROVER_is_fresh(*b_out, sizeof(int))) | ||
__CPROVER_ensures(__CPROVER_is_fresh(*c_out, sizeof(int))) | ||
__CPROVER_assigns(*b_out, *c_out) | ||
__CPROVER_ensures(**b_out == a[0]) | ||
__CPROVER_ensures(**c_out == a[1]) | ||
// clang-format on | ||
{ | ||
if (nondet_int()) { | ||
*b_out = malloc(sizeof(int)); | ||
__CPROVER_assume(*b_out != NULL); | ||
*c_out = malloc(sizeof(int)); | ||
__CPROVER_assume(*c_out != NULL); | ||
} else { | ||
*b_out = malloc(2*sizeof(int)); | ||
__CPROVER_assume(*b_out != NULL); | ||
*c_out = *b_out + 1; | ||
} | ||
**b_out = a[0]; | ||
**c_out = a[1]; | ||
} | ||
|
||
int main() | ||
{ | ||
int *a, **b_out, **c_out; | ||
foo(a, b_out, c_out); | ||
} |
12 changes: 12 additions & 0 deletions
12
regression/contracts-dfcc/test_is_fresh_weak_assert_ensures_pass/test.desc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
CORE dfcc-only | ||
main.c | ||
--dfcc main --enforce-contract foo | ||
^\[foo.postcondition.\d+\].*Check ensures clause of contract contract::foo for function foo: SUCCESS$ | ||
^EXIT=0$ | ||
^SIGNAL=0$ | ||
^VERIFICATION SUCCESSFUL$ | ||
-- | ||
-- | ||
This test checks that when __CPROVER_is_fresh is asserted in ensures clauses | ||
in contract checking mode, it allows both objet level separation and byte | ||
interval separation within the same object. |
36 changes: 36 additions & 0 deletions
36
regression/contracts-dfcc/test_is_fresh_weak_assert_requires_fail/main.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#include <stdlib.h> | ||
|
||
void foo(int *a, int *b) | ||
// clang-format off | ||
__CPROVER_requires(__CPROVER_is_fresh(a, 3*sizeof(int))) | ||
__CPROVER_requires(__CPROVER_is_fresh(b, 3*sizeof(int))) | ||
__CPROVER_assigns(__CPROVER_object_upto(a, 3*sizeof(int))) | ||
__CPROVER_ensures(a[0] == b[0]) | ||
__CPROVER_ensures(a[1] == b[1]) | ||
__CPROVER_ensures(a[2] == b[2]) | ||
; | ||
|
||
int nondet_int(); | ||
|
||
void bar() | ||
{ | ||
int a[6]; | ||
int b[3]; | ||
// c is either either a slice of `a` that overlaps a[0..2] or `b` | ||
int *c = nondet_int() ? &a[0] + 2: &b[0]; | ||
int old_c0 = c[0]; | ||
int old_c1 = c[1]; | ||
int old_c2 = c[2]; | ||
foo(a, c); // failure of preconditions | ||
__CPROVER_assert(a[0] == c[0], "same value 0"); | ||
__CPROVER_assert(a[1] == c[1], "same value 1"); | ||
__CPROVER_assert(a[2] == c[2], "same value 2"); | ||
__CPROVER_assert(old_c0 == c[0], "unmodified 0"); | ||
__CPROVER_assert(old_c1 == c[1], "unmodified 1"); | ||
__CPROVER_assert(old_c2 == c[2], "unmodified 2"); | ||
} | ||
|
||
int main() | ||
{ | ||
bar(); | ||
} |
13 changes: 13 additions & 0 deletions
13
regression/contracts-dfcc/test_is_fresh_weak_assert_requires_fail/test.desc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
CORE dfcc-only | ||
main.c | ||
--dfcc main --enforce-contract bar --replace-call-with-contract foo | ||
^\[bar.assertion.\d+\].* unmodified 0: FAILURE$ | ||
^\[foo.precondition.\d+\].*Check requires clause of contract contract::foo for function foo: FAILURE$ | ||
^EXIT=10$ | ||
^SIGNAL=0$ | ||
^VERIFICATION FAILED$ | ||
-- | ||
-- | ||
This test checks that when __CPROVER_is_fresh is asserted in requires clauses | ||
in contract replacement mode, it detects byte interval separation failure within | ||
the same object. |
36 changes: 36 additions & 0 deletions
36
regression/contracts-dfcc/test_is_fresh_weak_assert_requires_pass/main.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#include <stdlib.h> | ||
|
||
void foo(int *a, int *b) | ||
// clang-format off | ||
__CPROVER_requires(__CPROVER_is_fresh(a, 3*sizeof(int))) | ||
__CPROVER_requires(__CPROVER_is_fresh(b, 3*sizeof(int))) | ||
__CPROVER_assigns(__CPROVER_object_upto(a, 3*sizeof(int))) | ||
__CPROVER_ensures(a[0] == b[0]) | ||
__CPROVER_ensures(a[1] == b[1]) | ||
__CPROVER_ensures(a[2] == b[2]) | ||
; | ||
|
||
int nondet_int(); | ||
|
||
void bar() | ||
{ | ||
int a[6]; | ||
int b[3]; | ||
// c is either either a slice of `a` disjoint from a[0..2] or `b` | ||
int *c = nondet_int() ? &a[0] + 3: &b[0]; | ||
int old_c0 = c[0]; | ||
int old_c1 = c[1]; | ||
int old_c2 = c[2]; | ||
foo(a, c); // success of preconditions | ||
__CPROVER_assert(a[0] == c[0], "same value 0"); | ||
__CPROVER_assert(a[1] == c[1], "same value 1"); | ||
__CPROVER_assert(a[2] == c[2], "same value 2"); | ||
__CPROVER_assert(old_c0 == c[0], "unmodified 0"); | ||
__CPROVER_assert(old_c1 == c[1], "unmodified 1"); | ||
__CPROVER_assert(old_c2 == c[2], "unmodified 2"); | ||
} | ||
|
||
int main() | ||
{ | ||
bar(); | ||
} |
11 changes: 11 additions & 0 deletions
11
regression/contracts-dfcc/test_is_fresh_weak_assert_requires_pass/test.desc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
CORE dfcc-only | ||
main.c | ||
--dfcc main --enforce-contract bar --replace-call-with-contract foo _ --z3 --slice-formula | ||
^\[foo.precondition.\d+\].*Check requires clause of contract contract::foo for function foo: SUCCESS$ | ||
^EXIT=0$ | ||
^SIGNAL=0$ | ||
^VERIFICATION SUCCESSFUL$ | ||
-- | ||
-- | ||
This test checks that when __CPROVER_is_fresh in preconditions replacement checks | ||
succeed when separation and size are as expected. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters