Skip to content

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

Conversation

remi-delmas-3000
Copy link
Collaborator

@remi-delmas-3000 remi-delmas-3000 commented May 26, 2022

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:

// whole object pointed to by ptr is assignable
__CPROVER_assignable_t __CPROVER_whole_object(void *ptr);

// the range of bytes [ptr, ptr + object_size(ptr)-offset(ptr)] is assignable
__CPROVER_assignable_t __CPROVER_object_from(void *ptr);

// the range of bytes [ptr, ptr + size] is assignable
__CPROVER_assignable_t __CPROVER_object_upto(void *, size_t size);

// for all `expr_t` types and expressions, the range of bytes [&expr, &expr + sizeof(expr_t)] is assignable
__CPROVER_assignable_t __CPROVER_typed_target(exprt_t expr);

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:

__CPROVER_assignable_t my_write_set(char *arr, size_t size)
{
  __CPROVER_assert(
    !arr || __CPROVER_rw_ok(arr, size), "target null or writable");

  if(arr && size > 0)
  { 
    // adds locations in the write set modeled by this function
    __CPROVER_whole_object(arr);
    __CPROVER_object_upto(arr, size);
    __CPROVER_object_from(arr);
    __CPROVER_typed_target(arr[0]);
  }
}

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 :

// the range of bytes [ptr, ptr + size] is assignable
// if is_pointer_to_pointer is true then will be havoced as a pointer during contract replacement
__CPROVER_assignable_t __CPROVER_assignable(void *, size_t size, bool is_pointer_to_pointer);
  • Each commit message has a non-empty body, explaining why the change was made.
  • Methods or procedures I have added are documented, following the guidelines provided in CODING_STANDARD.md.
  • The feature or user visible behaviour I have added or modified has been documented in the User Guide in doc/cprover-manual/
  • Regression or unit tests are included, or existing tests cover the modified code (in this case I have detailed which ones those are in the commit message).
  • [] My commit message includes data points confirming performance improvements (if claimed).
  • My PR is restricted to a single feature or bugfix.
  • White-space or formatting changes outside the feature-related changed lines are in commits of their own.

@remi-delmas-3000 remi-delmas-3000 self-assigned this May 26, 2022
@remi-delmas-3000 remi-delmas-3000 added aws Bugs or features of importance to AWS CBMC users aws-high Code Contracts Function and loop contracts labels May 26, 2022
@codecov
Copy link

codecov bot commented May 26, 2022

Codecov Report

Merging #6886 (8131e13) into develop (b1f440a) will increase coverage by 0.00%.
The diff coverage is 78.04%.

❗ Current head 8131e13 differs from pull request most recent head 23b2b35. Consider uploading reports for the commit 23b2b35 to get more accurate results

@@            Coverage Diff            @@
##           develop    #6886    +/-   ##
=========================================
  Coverage    77.80%   77.80%            
=========================================
  Files         1567     1567            
  Lines       179920   180026   +106     
=========================================
+ Hits        139992   140076    +84     
- Misses       39928    39950    +22     
Impacted Files Coverage Δ
src/analyses/cfg_dominators.h 100.00% <ø> (ø)
src/analyses/flow_insensitive_analysis.cpp 74.64% <0.00%> (ø)
src/analyses/interval_analysis.cpp 0.00% <0.00%> (ø)
src/analyses/invariant_propagation.cpp 0.00% <0.00%> (ø)
src/analyses/invariant_set_domain.cpp 0.00% <0.00%> (ø)
src/analyses/static_analysis.cpp 46.69% <0.00%> (ø)
src/ansi-c/ansi_c_internal_additions.cpp 90.12% <ø> (ø)
src/ansi-c/ansi_c_language.h 75.00% <ø> (ø)
src/ansi-c/expr2c.cpp 67.63% <ø> (ø)
.../goto-instrument/accelerate/acceleration_utils.cpp 2.23% <0.00%> (ø)
... and 225 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c6f83a2...23b2b35. Read the comment docs.

Comment on lines +25 to +32
__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);
Copy link
Collaborator

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)?

Comment on lines +961 to +962
"assignable_t return type for function " +
id2string(ident) + " called in assigns clause"
Copy link
Collaborator

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).

Comment on lines +1950 to +1951
auto arg0 = expr.arguments().at(0);
typecheck_expr(arg0);
Copy link
Collaborator

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)).

Comment on lines +724 to +757
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));
}
Copy link
Collaborator

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?

Comment on lines +759 to +790
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));
}
Copy link
Collaborator

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?

Comment on lines +792 to +817
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));
}
Copy link
Collaborator

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?

Comment on lines +220 to +222
// frame specifications for contracts
// Type that describes assignable memory locations
"typedef void " CPROVER_PREFIX "assignable_t;\n"
Copy link
Collaborator

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?

@feliperodri
Copy link
Collaborator

#6887 supersedes this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
aws Bugs or features of importance to AWS CBMC users aws-high Code Contracts Function and loop contracts
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants