Skip to content

Commit db815f7

Browse files
authored
Merge pull request #8516 from qinheping/qinheping-patch-1
CONTRACTS: add doc for loop assigns inference
2 parents d47727f + fe41d1c commit db815f7

File tree

1 file changed

+73
-0
lines changed

1 file changed

+73
-0
lines changed

src/goto-instrument/contracts/doc/user/contracts-assigns.md

+73
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,79 @@ int foo()
500500
}
501501
```
502502

503+
## Loop Assigns Inference
504+
505+
When loop invariant clauses are specified but loop assigns are not, CBMC will infer
506+
loop assigns clauses and use them to apply loop contracts. The idea of the inference
507+
is to include all the left hand side of assignments in the loop.
508+
509+
For example, in the loop in the following function, we assume that only the loop
510+
invariant `i <= SIZE` is specified. Then CBMC will infer loop assigns targets `i`, `j`
511+
and `__CPROVER_object_whole(b)` for the loop.
512+
513+
```
514+
int j;
515+
516+
void set_j(int i)
517+
{
518+
j = i;
519+
}
520+
521+
void incr(int *n)
522+
{
523+
(*n)++;
524+
}
525+
526+
void test_loop_assigns_inference()
527+
{
528+
int *b = malloc(SIZE * sizeof(int));
529+
for(unsigned i = 0; i < SIZE; incr(&i))
530+
// __CPROVER_assigns(i, j, __CPROVER_object_whole(b))
531+
__CPROVER_loop_invariant(i <= SIZE)
532+
{
533+
int k = i + 1;
534+
set_j(i);
535+
b[j] = 1;
536+
}
537+
}
538+
```
539+
540+
The inference algorithm consist of three stages:
541+
1. function inlining,
542+
2. collecting assigns targets with local-may-alias analysis,
543+
3. assigns targets widening.
544+
545+
We do the function inlining first so that we can infer those assigns targets
546+
hidden in the function call, for example, `j` is assigned to in `set_j`.
547+
548+
Then we collect all targets of assignments in the loop after inlining. In the
549+
`test_loop_assigns_inference` example, there are five assignments in the loop.
550+
1. `n = &i`, with assign target `n`. `n` will not be included in the inferred
551+
set as it is a loop local.
552+
2. `*n++`, with assign target `*n`. We add `i` to the inferred set as `&i`
553+
aliasing `n` according to the above assignment.
554+
3. `k = i + 1`, with assign target `k`. `k` is also a loop local, and will not
555+
be added to the inferred set.
556+
4. `j = i` with assign target `j`. So we add `j` to the inferred set.
557+
5. `b[j] = 1` with assign target `b[j]`. So we add `b[j]` to the inferred set.
558+
559+
At last, we widen `b[j]` to `__CPROVER_object_whole(b)` as its index `j` is
560+
non constant.
561+
562+
### Limitation
563+
564+
The main limitation of the inference algorithm is that the local-may-alias
565+
analysis we use is field insensitive, hence it is inaccurate in the cases
566+
with struct fields.
567+
568+
As an example, for assignment `ptr = box.ptr`, we cannot determine that `ptr`
569+
aliases `box.ptr`. And hence if we later write to `*ptr`, we will fail to
570+
infer the assigns target `__CPROVER_object_whole(box.ptr)`.
571+
572+
However, the failed inference does not result in unsoundness.
573+
That is, CBMC will report assignability-checks failure when the inferred
574+
assigns clauses are not accurate.
575+
503576
## Additional Resources
504577

505578
- @ref contracts-functions

0 commit comments

Comments
 (0)