@@ -500,6 +500,79 @@ int foo()
500
500
}
501
501
```
502
502
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
+
503
576
## Additional Resources
504
577
505
578
- @ref contracts-functions
0 commit comments