Skip to content

Function contracts: preliminary support for conditional targets in assigns clause checking #6546

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion regression/contracts/assigns_enforce_address_of/test.desc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ main.c
--enforce-contract foo
^EXIT=(1|64)$
^SIGNAL=0$
^.*error: non-lvalue target in assigns clause$
^.*error: assigns clause target must be an lvalue or __CPROVER_POINTER_OBJECT expression$
^CONVERSION ERROR$
--
--
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include <stdbool.h>

bool cond()
{
return true;
}

int foo(int a, int *x, int *y)
// clang-format off
__CPROVER_assigns(a && cond() : *x)
// clang-format on
{
if(a)
{
if(cond())
*x = 0; // must pass
}
else
{
*x = 0; // must fail
}
return 0;
}

int main()
{
bool a;
int x;
int y;

foo(a, &x, &y);
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
CORE
main.c
--enforce-contract foo
^main.c function foo$
^\[foo\.\d+\] line 16 Check that \*x is assignable: SUCCESS$
^\[foo\.\d+\] line 20 Check that \*x is assignable: FAILURE$
^VERIFICATION FAILED$
^EXIT=10$
^SIGNAL=0$
--
--
Checks that function calls are allowed in conditions.
Remark: we allow function calls without further checks for now because they
are mandatory for some applications.
The next step must be to check that the called functions have a contract
with an empty assigns clause and that they indeed satisfy their contract
using a CI check.
Comment on lines +15 to +17
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a issue to track this?

29 changes: 29 additions & 0 deletions regression/contracts/assigns_enforce_conditional_lvalue/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <stdbool.h>

int foo(bool a, int *x, int *y) __CPROVER_assigns(a : *x; !a : *y)
{
if(a)
{
*x = 0; // must pass
*y = 0; // must fail
}
else
{
*x = 0; // must fail
*y = 0; // must pass
}

*x = 0; // must fail
*y = 0; // must fail
return 0;
}

int main()
{
bool a;
int x;
int y;

foo(a, &x, &y);
return 0;
}
17 changes: 17 additions & 0 deletions regression/contracts/assigns_enforce_conditional_lvalue/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
CORE
main.c
--enforce-contract foo
main.c function foo
^\[foo\.\d+\] line 7 Check that \*x is assignable: SUCCESS$
^\[foo\.\d+\] line 8 Check that \*y is assignable: FAILURE$
^\[foo\.\d+\] line 12 Check that \*x is assignable: FAILURE$
^\[foo\.\d+\] line 13 Check that \*y is assignable: SUCCESS$
^\[foo\.\d+\] line 16 Check that \*x is assignable: FAILURE$
^\[foo\.\d+\] line 17 Check that \*y is assignable: FAILURE$
^VERIFICATION FAILED$
^EXIT=10$
^SIGNAL=0$
--
--
Check that lvalue conditional assigns clause targets
match with control flow path conditions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <stdbool.h>

int foo(bool a, int *x, int *y) __CPROVER_assigns(a : *x, *y)
{
if(a)
{
*x = 0; // must pass
*y = 0; // must pass
}
else
{
*x = 0; // must fail
*y = 0; // must fail
}

*x = 0; // must fail
*y = 0; // must fail
return 0;
}

int main()
{
bool a;
int x;
int y;

foo(a, &x, &y);
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
CORE
main.c
--enforce-contract foo
main.c function foo
^\[foo\.\d+\] line 7 Check that \*x is assignable: SUCCESS$
^\[foo\.\d+\] line 8 Check that \*y is assignable: SUCCESS$
^\[foo\.\d+\] line 12 Check that \*x is assignable: FAILURE$
^\[foo\.\d+\] line 13 Check that \*y is assignable: FAILURE$
^\[foo\.\d+\] line 16 Check that \*x is assignable: FAILURE$
^\[foo\.\d+\] line 17 Check that \*y is assignable: FAILURE$
^VERIFICATION FAILED$
^EXIT=10$
^SIGNAL=0$
--
--
Check that conditional assigns clause `c ? {lvalue, ..}`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use this pattern anymore.

match with control flow path conditions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <stdbool.h>

int *identity(int *ptr)
{
return ptr;
}

int foo(bool a, int *x, int offset) __CPROVER_assigns(a : !x)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: it'd be nice to add a comment here like

int foo(bool a, int *x, int offset) __CPROVER_assigns(a : !x) // !x Boolean not allowed as target, only lvalues.

or something similar.

{
return 0;
}

int main()
{
bool a;
int x;
int y;

foo(a, &x, &y);
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CORE
main.c
--enforce-contract foo
^.*error: assigns clause target must be an lvalue or __CPROVER_POINTER_OBJECT expression$
^CONVERSION ERROR
^EXIT=(1|64)$
^SIGNAL=0$
--
--
Checks that non-lvalue targets are rejected from conditional targets.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <stdbool.h>

int *identity(int *ptr)
{
return ptr;
}

int foo(bool a, int *x, int *y) __CPROVER_assigns(a : !x, *y)
{
return 0;
}

int main()
{
bool a;
int x;
int y;

foo(a, &x, &y);
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CORE
main.c
--enforce-contract foo
^.*error: assigns clause target must be an lvalue or __CPROVER_POINTER_OBJECT expression$
^CONVERSION ERROR
^EXIT=(1|64)$
^SIGNAL=0$
--
--
Checks that non-lvalue targets are rejected from conditional targets.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include <stdbool.h>

int foo(bool a, char *x, char *y)
// clang-format off
__CPROVER_assigns(
a: __CPROVER_POINTER_OBJECT(x);
!a: __CPROVER_POINTER_OBJECT(y);
)
// clang-format on
{
if(a)
{
x[0] = 0; // must pass
y[0] = 0; // must fail
}
else
{
x[0] = 0; // must fail
y[0] = 0; // must pass
}

x[0] = 0; // must fail
y[0] = 0; // must fail
return 0;
}

int main()
{
bool a;
char x[2];
char y[2];

foo(a, &x, &y);
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
CORE
main.c
--enforce-contract foo
main.c function foo
^\[foo\.\d+\] line 13 Check that x\[\(signed (long )?long int\)0\] is assignable: SUCCESS$
^\[foo\.\d+\] line 14 Check that y\[\(signed (long )?long int\)0\] is assignable: FAILURE$
^\[foo\.\d+\] line 18 Check that x\[\(signed (long )?long int\)0\] is assignable: FAILURE$
^\[foo\.\d+\] line 19 Check that y\[\(signed (long )?long int\)0\] is assignable: SUCCESS$
^\[foo\.\d+\] line 22 Check that x\[\(signed (long )?long int\)0\] is assignable: FAILURE$
^\[foo\.\d+\] line 23 Check that y\[\(signed (long )?long int\)0\] is assignable: FAILURE$
^VERIFICATION FAILED$
^EXIT=10$
^SIGNAL=0$
--
--
Check that conditional assigns clause `c ? __CPROVER_POINTER_OBJECT((p)`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use this pattern anymore.

match with control flow path conditions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <stdbool.h>

int foo(bool a, char *x, char *y)
// clang-format off
__CPROVER_assigns(
a : __CPROVER_POINTER_OBJECT(x), __CPROVER_POINTER_OBJECT(y)
)
// clang-format on
{
if(a)
{
x[0] = 0; // must pass
y[0] = 0; // must pass
}
else
{
x[0] = 0; // must fail
y[0] = 0; // must fail
}

x[0] = 0; // must fail
y[0] = 0; // must fail
return 0;
}

int main()
{
bool a;
char x[2];
char y[2];

foo(a, &x, &y);
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
CORE
main.c
--enforce-contract foo
main.c function foo
^\[foo\.\d+\] line 12 Check that x\[\(signed (long )?long int\)0\] is assignable: SUCCESS$
^\[foo\.\d+\] line 13 Check that y\[\(signed (long )?long int\)0\] is assignable: SUCCESS$
^\[foo\.\d+\] line 17 Check that x\[\(signed (long )?long int\)0\] is assignable: FAILURE$
^\[foo\.\d+\] line 18 Check that y\[\(signed (long )?long int\)0\] is assignable: FAILURE$
^\[foo\.\d+\] line 21 Check that x\[\(signed (long )?long int\)0\] is assignable: FAILURE$
^\[foo\.\d+\] line 22 Check that y\[\(signed (long )?long int\)0\] is assignable: FAILURE$
^VERIFICATION FAILED$
^EXIT=10$
^SIGNAL=0$
--
--
Check that conditional assigns clause `c ? {__CPROVER_POINTER_OBJECT((p), .. }`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use this pattern anymore.

match with control flow path conditions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include <stdbool.h>

int foo(int a, int *x, int *y) __CPROVER_assigns(a++ : *x)
{
if(a)
{
*x = 0;
}
return 0;
}

int main()
{
bool a;
int x;
int y;

foo(a, &x, &y);
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CORE
main.c
--enforce-contract foo
^.* error: side-effects not allowed in assigns clause conditions$
^CONVERSION ERROR$
^EXIT=(1|64)$
^SIGNAL=0$
--
--
Checks that side-effect expressions in target conditions cause hard errors.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include <stdbool.h>

int foo(bool a, int *x, int *y) __CPROVER_assigns(a : *x++)
{
return 0;
}

int main()
{
bool a;
int x;
int y;

foo(a, &x, &y);
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CORE
main.c
--enforce-contract foo
^.* error: side-effects not allowed in assigns clause targets$
^CONVERSION ERROR$
^EXIT=(1|64)$
^SIGNAL=0$
--
--
Checks that side-effect expressions are rejected from conditional targets.
Loading