|
| 1 | +## CBMC Assigns Clause |
| 2 | + |
| 3 | +### Introduction |
| 4 | +Here is described the syntax and semantics of the "assigns" clause as implemented in CBMC. This construct allows the user to specify a list of memory locations which may be written within a particular scope. While an assigns clause may, in general, be interpreted with either "writes" or "modifies" semantics, this design is based on the former. |
| 5 | +This means that memory not captured by the assigns clause must not be written within the given scope, even if the value(s) therein are not modified. |
| 6 | + |
| 7 | +### Scalar Variables |
| 8 | +The initial iteration of this design focuses on specifying an assigns clause for simple variable types and their pointers. Arrays, structured data, and pointers are left to future contributions. |
| 9 | + |
| 10 | + |
| 11 | +##### Syntax |
| 12 | +A special construct is introduced to specify assigns clauses. Its syntax is defined as follows. |
| 13 | + |
| 14 | +``` |
| 15 | + <assigns_clause> := __CPROVER_assigns ( <target_list> ) |
| 16 | +``` |
| 17 | +``` |
| 18 | + <target_list> := <target> |
| 19 | + | <target> , <target_list> |
| 20 | +``` |
| 21 | +``` |
| 22 | + <target> := <identifier> |
| 23 | + | * <target> |
| 24 | +``` |
| 25 | + |
| 26 | + |
| 27 | +The `<assigns_clause>` states that only the memory identified by the dereference expressions and identifiers listed in the contained `<target_list>` may be written within the associated scope, as follows. |
| 28 | + |
| 29 | +##### Semantics |
| 30 | +The semantics of an assigns clause *c* of some function *f* can be understood in two contexts. First, one may consider how the expressions in *c* are treated when a call to *f* is replaced by its contract specification, assuming the contract specification is a sound characterization of the behavior of *f*. Second, one may consider how *c* is applied the function body of *f* in order to determine whether *c* is a sound characterization of the behavior of *f*. We begin by exploring these two perspectives for assigns clauses which contain only scalar expressions. |
| 31 | + |
| 32 | +Let the i<sup>th</sup> expression in some assigns clause *c* be denoted *exprs*<sub>*c*</sub>[i], the j<sup>th</sup> formal parameter of some function *f* be denoted *params*<sub>*f*</sub>[j], and the k<sup>th</sup> argument passed in a call to function *f* be denoted *args*<sub>*f*</sub>[k] (an identifying index may be added to distinguish a *particular* call to *f*, but for simplicity it is omitted here). |
| 33 | + |
| 34 | +###### Replacement |
| 35 | +Assuming an assigns clause *c* is a sound characterization of the behavior of the function *f*, a call to *f* may be replaced a series of non-deterministic assignments. For each expression *e* ∈ *exprs*<sub>*c*</sub>, let there be an assignment ɸ := ∗, where ɸ is *args*<sub>*f*</sub>[i] if *e* is identical to some *params*<sub>*f*</sub>[i], and *e* otherwise. |
| 36 | + |
| 37 | +###### Enforcement |
| 38 | +In order to determine whether an assigns clause *c* is a sound characterization of the behavior of a function *f*, the body of the function should be instrumented with additional statements as follows. |
| 39 | + |
| 40 | +- For each expression *e* ∈ *exprs*<sub>*c*</sub>, create a temporary variable *tmp*<sub>*e*</sub> to store \&(*e*), the address of *e*, at the start of *f*. |
| 41 | +- Before each assignment statement, *lhs* := *rhs*, add an assertion (structured as a disjunction) |
| 42 | + |
| 43 | +assert(∃ *tmp*<sub>*e*</sub>. __CPROVER_same_object(\&(*lhs*), *tmp*<sub>*e*</sub>) |
| 44 | +- Before each function call with an assigns clause *a*, add an assertion for each *e*<sub>*a*</sub> ∈ *exprs*<sub>*a*</sub> (also formulated as a disjunction) |
| 45 | + |
| 46 | +assert(∃ *tmp*<sub>*e*</sub>. __CPROVER_same_object(\&(*e*<sub>*a*</sub>), *tmp*<sub>*e*</sub>) |
| 47 | + |
| 48 | +Here, __CPROVER_same_object is a predicate indicating that the two pointers reference the same object in the CBMC memory model. Additionally, for each function call without an assigns clause, add an assertion assert(*false*) to ensure that the assigns contract will only hold if all called functions have an assigns clause which is compatible with that of the calling function. |
| 49 | + |
| 50 | + |
| 51 | + |
0 commit comments