@@ -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