As homework, I've decided to try verify an implementation of quicksort (taken and adapted from here) using frama-c with wp and rte plugins. Note that at first leftmost is 0 and rightmost is equal to size-1. Here my proof.
/*@
requires \valid(a);
requires \valid(b);
ensures *a == \old(*b);
ensures *b == \old(*a);
assigns *a,*b;
*/
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
/*@
requires \valid(t +(leftmost..rightmost));
requires 0 <= leftmost;
requires 0 <= rightmost;
decreases (rightmost - leftmost);
assigns *(t+(leftmost..rightmost));
*/
void quickSort(int * t, int leftmost, int rightmost)
{
// Base case: No need to sort arrays of length <= 1
if (leftmost >= rightmost)
{
return;
} // Index indicating the "split" between elements smaller than pivot and
// elements greater than pivot
int pivot = t[rightmost];
int counter = leftmost;
/*@
loop assigns i, counter, *(t+(leftmost..rightmost));
loop invariant 0 <= leftmost <= i <= rightmost + 1 <= INT_MAX ;
loop invariant 0 <= leftmost <= counter <= rightmost;
loop invariant \forall int i; leftmost <= i < counter ==> t[i] <= pivot;
loop variant rightmost - i;
*/
for (int i = leftmost; i <= rightmost; i++)
{
if (t[i] <= pivot)
{
/*@assert \valid(&t[counter]);*/
/*@assert \valid(&t[i]);*/
swap(&t[counter], &t[i]);
counter++;
}
}
// NOTE: counter is currently at one plus the pivot's index
// (Hence, the counter-2 when recursively sorting the left side of pivot)
quickSort(t, leftmost, counter-2); // Recursively sort the left side of pivot
quickSort(t, counter, rightmost); // Recursively sort the right side of pivot
}
As side note, I know that wp doesn't support recursion hence the ignored decreases
statement when running Frama-c -wp -wp-rte
.
here is the result in the gui:
As you can see my loop invariants are not verified even though it makes senses to me.
Frama-c able to verify under hypotheses the second recursive call when it's not supporting recursion. To my understanding the call quickSort(t, leftmost, counter-2)
isn't verified since can violate the precondition requires 0 <= rightmost
. I'am not too sure about Frama-c behaviour in that case though and how to tackle it.
I would like some input about what is going on. I think that the invariant not being verified as nothing to do with recursion as even by removing the recursion calls, they aren't verified. And finally could you explain to me what is the Frama-c behaviour in the case of the recursive calls? Are they treated as any other function call or is there a behaviour that I'am unaware of?
Thanks