2

I'm having trouble proving 2 loop invariants:

    loop invariant \forall integer i; 0 <= i < (\at(n, Pre) - n) ==> ((char*)m2)[i] == \at(((char*)m1)[i], Pre);
    loop invariant \forall integer i; 0 <= i < (\at(n, Pre) - n) ==> ((char*)m1)[i] == \at(((char*)m2)[i], Pre);

I'm guessing \at isn't working for arrays as i expect.

There is a similar function in ACSL by Example (page 68, swap_ranges), that uses this, but, as stated, they were not able to prove this particular function with the WP plugin. I tried it on my machine and indeed it is not able to prove the same invariant.

Full code

/*
 * memswap()
 *
 * Swaps the contents of two nonoverlapping memory areas.
 * This really could be done faster...
 */

#include "string.h"

/*@
    requires n >= 1;
    requires \valid(((char*)m1)+(0..n-1));
    requires \valid(((char*)m2)+(0..n-1));
    requires \separated(((char*)m1)+(0..n-1), ((char*)m2)+(0..n-1));
    assigns ((char*)m1)[0..n-1];
    assigns ((char*)m2)[0..n-1];
    ensures \forall integer i; 0 <= i < n ==> ((char*)m1)[i] == \old(((char*)m2)[i]);
    ensures \forall integer i; 0 <= i < n ==> ((char*)m2)[i] == \old(((char*)m1)[i]);
@*/
void memswap(void *m1, void *m2, size_t n)
{
    char *p = m1;
    char *q = m2;
    char tmp;

    /*@
        loop invariant 0 <= n <= \at(n, Pre);
        loop invariant p == m1+(\at(n, Pre) - n);
        loop invariant q == m2+(\at(n, Pre) - n);
        loop invariant (char*)m1 <= p <= (char*)m1+\at(n, Pre);
        loop invariant (char*)m2 <= q <= (char*)m2+\at(n, Pre);
        loop invariant \forall integer i; 0 <= i < (\at(n, Pre) - n) ==> ((char*)m2)[i] == \at(((char*)m1)[i], Pre);
        loop invariant \forall integer i; 0 <= i < (\at(n, Pre) - n) ==> ((char*)m1)[i] == \at(((char*)m2)[i], Pre);
        loop assigns n, tmp, ((char*)m1)[0..\at(n,Pre)-1], ((char*)um2)[0..\at(n, Pre)-1], p, q;
        loop variant n;
    @*/
    while (/*n--*/ n) {
        tmp = *p;
        *p = *q;
        *q = tmp;

        p++;
        q++;

        n--; // inserted code
    }
}

EDIT

Im using Frama-C Oxygen release and tried automatic proving with alt-ergo(0.94) and cvc3(2.4.1)

output from frama-c:

cvc3:

[wp] [Cvc3] Goal store_memswap_loop_inv_7_established : Valid
[wp] [Cvc3] Goal store_memswap_loop_inv_6_established : Valid
[wp] [Cvc3] Goal store_memswap_loop_inv_7_preserved : Unknown
[wp] [Cvc3] Goal store_memswap_loop_inv_6_preserved : Unknown

alt-ergo:

[wp] [Alt-Ergo] Goal store_memswap_loop_inv_7_established : Valid
[wp] [Alt-Ergo] Goal store_memswap_loop_inv_6_established : Valid
[wp] [Alt-Ergo] Goal store_memswap_loop_inv_7_preserved : Timeout
[wp] [Alt-Ergo] Goal store_memswap_loop_inv_6_preserved : Timeout
Daniel Daranas
  • 22,454
  • 9
  • 63
  • 116
Cristiano Sousa
  • 934
  • 1
  • 6
  • 31
  • Hello Cristiano, a few syntactic remarks on your question (that I am not able to answer myself): 1) “It doesn't prove” is meaningless. You should state what provers you have tried. Are we discussing the generation of an unprovable—false— obligation here, or the weakness of the automatic provers you have installed? These are completely different discussions. 2) It wouldn't hurt to say which version of Frama-C you are talking about either. 3) I don't know about the annotations in the ACSL-by-example example, but the annotations in your example are wrong, so you shouldn't expect them to be proved – Pascal Cuoq Mar 23 '13 at 19:58
  • Wait actually 3) is the beginning of an answer, I will expand on that below. – Pascal Cuoq Mar 23 '13 at 19:59
  • I've added some more info, as you pointed out. – Cristiano Sousa Mar 23 '13 at 20:08

1 Answers1

5
/*@
…
    loop invariant \forall integer i; 0 <= i < (\at(n, Pre) - n) ==> ((char*)m2)[i] == \at(((char*)m1)[i], Pre);
    loop invariant \forall integer i; 0 <= i < (\at(n, Pre) - n) ==> ((char*)m1)[i] == \at(((char*)m2)[i], Pre);
    loop assigns n, tmp, ((char*)m1)[0..\at(n,Pre)-1], ((char*)um2)[0..\at(n, Pre)-1], p, q;
…
@*/

You have the wrong loop assigns. The loop assigns annotations tells what memory locations have been modified at each iteration. The number of locations should typically increase as the loop progresses (in your case, as n decreases). It is something like:

loop assigns n, tmp, ((char*)m1)[0..(\at(n, Pre) - n - 1)], ((char*)um2)[0..(\at(n, Pre) - n - 1)], p, q;

But my own proposal above may be off by one in one direction or another. I find it difficult to remember exactly how these “moving” loop assigns clauses work exactly.


Alternately, you may write a simpler, “static” loop assigns annotation (like yours), and add the information about what hasn't changed yet in the loop invariant. This is what I usually do to circumvent my inability to remember how complex loop assigns clauses work. That would be something like (untested):

/*@
…
    loop invariant \forall integer i; 0 <= i < (\at(n, Pre) - n) ==> ((char*)m2)[i] == \at(((char*)m1)[i], Pre);
    loop invariant \forall integer i; 0 <= i < (\at(n, Pre) - n) ==> ((char*)m1)[i] == \at(((char*)m2)[i], Pre);
    loop invariant \forall integer i; (\at(n, Pre) - n) <= i < \at(n, Pre) ==> ((char*)m1)[i] == \at(((char*)m1)[i], Pre);
    loop invariant \forall integer i; (\at(n, Pre) - n) <= i < \at(n, Pre) ==> ((char*)m2)[i] == \at(((char*)m2)[i], Pre);
    loop assigns n, tmp, ((char*)m1)[0..\at(n,Pre)-1], ((char*)um2)[0..\at(n, Pre)-1], p, q;
…
@*/
Pascal Cuoq
  • 79,187
  • 7
  • 161
  • 281
  • That did the trick. I knew about the loop assigns being wrong, but it is still supposed to be correct, it is just a less restrictive invariant. – Cristiano Sousa Mar 23 '13 at 20:30
  • 2
    @CristianoSousa Loop invariants can be “wrong” by being too lax as well as by being too strict. An invariant has to be just right. With the invariant in your question, it was impossible to infer that at the kth iteration, `m[k]` received `\at(n[k],Pre)`. The code showed that it received `n[k]` but it was impossible to know that `n[k]` had not changed (that is, that is was still the same as `\at(n[k], Pre)`. – Pascal Cuoq Mar 23 '13 at 20:37
  • That makes perfect sense! I really didn't think of that! – Cristiano Sousa Mar 23 '13 at 20:48