-
Notifications
You must be signed in to change notification settings - Fork 273
CONTRACTS: introduce __CPROVER_assignable_t and related built-in functions #6886
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
CONTRACTS: introduce __CPROVER_assignable_t and related built-in functions #6886
Conversation
function calls in assigns clauses.
8131e13
to
23b2b35
Compare
Codecov Report
@@ Coverage Diff @@
## develop #6886 +/- ##
=========================================
Coverage 77.80% 77.80%
=========================================
Files 1567 1567
Lines 179920 180026 +106
=========================================
+ Hits 139992 140076 +84
- Misses 39928 39950 +22
Continue to review full report at Codecov.
|
__CPROVER_assignable_t __CPROVER_typed_target(expr_t expr); | ||
``` | ||
|
||
Given a pointer `ptr` pointing into some object `o`, | ||
`__CPROVER_whole_object(ptr)` specifies that all bytes of the object `o` | ||
are assignable: | ||
```c | ||
__CPROVER_assignable_t __CPROVER_whole_object(void *ptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't __CPROVER_typed_target(x)
expressible as __CPROVER_whole_object(&x)
?
"assignable_t return type for function " + | ||
id2string(ident) + " called in assigns clause" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit picking: use <<
instead of +
and then use ident
instead of id2string(ident)
.
auto arg0 = expr.arguments().at(0); | ||
typecheck_expr(arg0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check that there is exactly one argument and else report back via error()
and throw
. It should not be possible for a user to trigger a system exception (.at(0)
).
void goto_convertt::do_whole_object( | ||
const exprt &lhs, | ||
const symbol_exprt &function, | ||
const exprt::operandst &arguments, | ||
goto_programt &dest, | ||
const irep_idt &mode) | ||
{ | ||
// We enable overflow checks on pointer and size computation | ||
auto source_location = function.find_source_location(); | ||
source_location.add_pragma("enable:pointer-check"); | ||
source_location.add_pragma("enable:pointer-overflow-check"); | ||
source_location.add_pragma("enable:signed-overflow-check"); | ||
source_location.add_pragma("enable:unsigned-overflow-check"); | ||
const auto &arg0 = arguments[0]; | ||
|
||
// Rewrite to a call to CPROVER_PREFIX "assignable" | ||
exprt::operandst new_arguments; | ||
// pointer | ||
new_arguments.emplace_back(typecast_exprt::conditional_cast( | ||
minus_exprt{ | ||
typecast_exprt::conditional_cast(arg0, pointer_type(char_type())), | ||
pointer_offset_exprt{arg0, size_type()}}, | ||
pointer_type(empty_typet()))); | ||
// size | ||
new_arguments.emplace_back(object_size_exprt{arg0, size_type()}); | ||
// is_pointer | ||
new_arguments.emplace_back(false_exprt()); | ||
|
||
const auto &fun = | ||
symbol_table.lookup_ref(CPROVER_PREFIX "assignable").symbol_expr(); | ||
code_function_callt function_call(std::move(fun), std::move(new_arguments)); | ||
|
||
dest.add(goto_programt::make_function_call(function_call, source_location)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can't we do this in the C front-end (during type checking) already?
void goto_convertt::do_object_from( | ||
const exprt &lhs, | ||
const symbol_exprt &function, | ||
const exprt::operandst &arguments, | ||
goto_programt &dest, | ||
const irep_idt &mode) | ||
{ | ||
// We enable overflow checks on pointer and size computation | ||
auto source_location = function.find_source_location(); | ||
source_location.add_pragma("enable:pointer-check"); | ||
source_location.add_pragma("enable:pointer-overflow-check"); | ||
source_location.add_pragma("enable:signed-overflow-check"); | ||
source_location.add_pragma("enable:unsigned-overflow-check"); | ||
const auto &arg0 = arguments[0]; | ||
|
||
// Rewrite to a call to CPROVER_PREFIX "assignable" | ||
exprt::operandst new_arguments; | ||
// ptr | ||
new_arguments.emplace_back(arg0); | ||
// size | ||
new_arguments.emplace_back(minus_exprt{ | ||
object_size_exprt{arg0, size_type()}, | ||
pointer_offset_exprt{arg0, size_type()}}); | ||
// is_pointer | ||
new_arguments.emplace_back(false_exprt()); | ||
|
||
const auto &fun = | ||
symbol_table.lookup_ref(CPROVER_PREFIX "assignable").symbol_expr(); | ||
code_function_callt function_call(std::move(fun), std::move(new_arguments)); | ||
|
||
dest.add(goto_programt::make_function_call(function_call, source_location)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above: can't we do this in the C front-end?
void goto_convertt::do_object_upto( | ||
const exprt &lhs, | ||
const symbol_exprt &function, | ||
const exprt::operandst &arguments, | ||
goto_programt &dest, | ||
const irep_idt &mode) | ||
{ | ||
// We enable overflow checks on pointer and size computation | ||
auto source_location = function.find_source_location(); | ||
const auto &arg0 = arguments[0]; | ||
const auto &arg1 = arguments[1]; | ||
|
||
// Rewrite to a call to CPROVER_PREFIX "assignable" | ||
exprt::operandst new_arguments; | ||
// pointer | ||
new_arguments.emplace_back(arg0); | ||
// size | ||
new_arguments.emplace_back(arg1); | ||
// is_pointer | ||
new_arguments.emplace_back(false_exprt()); | ||
const auto &fun = | ||
symbol_table.lookup_ref(CPROVER_PREFIX "assignable").symbol_expr(); | ||
code_function_callt function_call(std::move(fun), std::move(new_arguments)); | ||
|
||
dest.add(goto_programt::make_function_call(function_call, source_location)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above: can't we do this in the C front-end already?
// frame specifications for contracts | ||
// Type that describes assignable memory locations | ||
"typedef void " CPROVER_PREFIX "assignable_t;\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need this typedef?
#6887 supersedes this PR. |
Adds a new built-in type
__CPROVER_assignable_t
to represent sets of assignable memory locations and related built-in functions. This new specification format will be used in an upcoming update of assigns clause checking.The built-in functions are:
These built-ins can now be used as targets in assigns clauses.
In addition, users can define their own functions returning
__CPROVER_assignable_t
to model sets of assignable locations:Internally, calls to the above built-ins are normalised during typechecking (for
__CPROVER_typed_target
) and goto conversion (for the rest) into calls to another built-in :