Skip to content

Commit d263955

Browse files
authored
Merge pull request #4921 from angelhof/cprover-postcondition
Add a __CPROVER_postcondition builtin
2 parents 06ef36d + 119ce60 commit d263955

File tree

10 files changed

+82
-2
lines changed

10 files changed

+82
-2
lines changed

doc/cprover-manual/cbmc-assertions.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,34 @@ for(i=0; i<100; i++)
5959
assert(a[i]==0);
6060
```
6161

62+
CPROVER also supports writing function pre and postconditions, using
63+
the built-in functions `__CPROVER_precondition` and
64+
`__CPROVER_postcondition`. They can be used to express intent, and at
65+
the moment they are just transformed to assertions in the goto
66+
program. As such, they can be used as simple assertions in
67+
code. However, it is advised to use `__CPROVER_precondition` at the
68+
beginning of a function's body, and `__CPROVER_postcondition` before
69+
the exit points in a function (either the return statements, or the
70+
end of the body if the function returns void). The following is an
71+
example usage:
72+
73+
```C
74+
int foo(int a, int b) {
75+
__CPROVER_precondition(a >= 0);
76+
__CPROVER_precondition(b > 0);
77+
78+
int rval = a / b;
79+
80+
__CPROVER_postcondition(rval >= 0);
81+
return rval;
82+
}
83+
```
84+
85+
A future release of CPROVER will support using these pre and
86+
postconditions to create a function contract, which can be used for
87+
modular verification.
88+
89+
6290
Future CPROVER releases will support explicit quantifiers with a syntax
6391
that resembles Spec\#:
6492
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
int func(int a)
2+
{
3+
__CPROVER_precondition(a > 10, "Argument should be larger than 10");
4+
int rval = a - 10;
5+
__CPROVER_postcondition(rval > 1, "Return value should be positive");
6+
return rval;
7+
}
8+
9+
int main()
10+
{
11+
int a = 11;
12+
int rval = func(a);
13+
return 0;
14+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
--
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
void func(int a)
2+
{
3+
__CPROVER_precondition(a > 10, "Argument should be larger than 10.");
4+
}
5+
6+
int main()
7+
{
8+
int a = 10;
9+
10+
func(a);
11+
12+
return 0;
13+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
--

src/ansi-c/cprover_builtin_headers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ void __CPROVER_assume(__CPROVER_bool assumption);
22
void __VERIFIER_assume(__CPROVER_bool assumption);
33
void __CPROVER_assert(__CPROVER_bool assertion, const char *description);
44
void __CPROVER_precondition(__CPROVER_bool precondition, const char *description);
5+
void __CPROVER_postcondition(__CPROVER_bool assertion, const char *description);
56
void __CPROVER_havoc_object(void *);
67
__CPROVER_bool __CPROVER_equal();
78
__CPROVER_bool __CPROVER_same_object(const void *, const void *);

src/ansi-c/library/cprover.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ extern const void *__CPROVER_memory_leak;
2020
void __CPROVER_assume(__CPROVER_bool assumption) __attribute__((__noreturn__));
2121
void __CPROVER_assert(__CPROVER_bool assertion, const char *description);
2222
void __CPROVER_precondition(__CPROVER_bool assertion, const char *description);
23+
void __CPROVER_postcondition(__CPROVER_bool assertion, const char *description);
2324

2425
__CPROVER_bool __CPROVER_is_zero_string(const void *);
2526
__CPROVER_size_t __CPROVER_zero_string_length(const void *);

src/cpp/library/cprover.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ extern const void *__CPROVER_memory_leak;
2121
void __CPROVER_assume(__CPROVER_bool assumption) __attribute__((__noreturn__));
2222
void __CPROVER_assert(__CPROVER_bool assertion, const char *description);
2323
void __CPROVER_precondition(__CPROVER_bool assertion, const char *description);
24+
void __CPROVER_postcondition(__CPROVER_bool assertion, const char *description);
2425

2526
void __CPROVER_input(const char *description, ...);
2627
void __CPROVER_output(const char *description, ...);

src/goto-programs/builtin_functions.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -735,8 +735,10 @@ void goto_convertt::do_function_call_symbol(
735735
throw 0;
736736
}
737737
}
738-
else if(identifier==CPROVER_PREFIX "assert" ||
739-
identifier==CPROVER_PREFIX "precondition")
738+
else if(
739+
identifier == CPROVER_PREFIX "assert" ||
740+
identifier == CPROVER_PREFIX "precondition" ||
741+
identifier == CPROVER_PREFIX "postcondition")
740742
{
741743
if(arguments.size()!=2)
742744
{
@@ -747,6 +749,7 @@ void goto_convertt::do_function_call_symbol(
747749

748750
bool is_precondition=
749751
identifier==CPROVER_PREFIX "precondition";
752+
bool is_postcondition = identifier == CPROVER_PREFIX "postcondition";
750753

751754
const irep_idt description=
752755
get_string_constant(arguments[1]);
@@ -760,6 +763,10 @@ void goto_convertt::do_function_call_symbol(
760763
{
761764
t->source_location.set_property_class(ID_precondition);
762765
}
766+
else if(is_postcondition)
767+
{
768+
t->source_location.set_property_class(ID_postcondition);
769+
}
763770
else
764771
{
765772
t->source_location.set(

src/util/irep_ids.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ IREP_ID_ONE(assume)
8989
IREP_ID_ONE(assert)
9090
IREP_ID_ONE(assertion)
9191
IREP_ID_ONE(precondition)
92+
IREP_ID_ONE(postcondition)
9293
IREP_ID_ONE(precondition_instance)
9394
IREP_ID_ONE(goto)
9495
IREP_ID_ONE(gcc_computed_goto)

0 commit comments

Comments
 (0)