I try to use Frama-C to prove the invariant below. With the precondition that the array clean has at least one "true" in the first half, the loop should terminate before the last iteration and hence i will never be increased to BLOCK_NUM (=1000). However, Frama-C seems to ignore the content of clean and failed to establish the loop invariant. Does anyone know how to fix this proof?
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#define BLOCK_NUM 1000
bool clean[BLOCK_NUM] ; // clean bit for physical block; phy block ID -> bool
/*@
requires \exists integer j; 0 <= j < BLOCK_NUM/2 ==> clean[j] == true;
*/
void test(){
int i = 0;
/*@
loop assigns i;
loop invariant 0 <= i < BLOCK_NUM;
*/
while( i < BLOCK_NUM && clean[i] == false ){
i += 1;
}
}
I also tried a different version adding more information to the invariant
void test(){
int i = 0;
/*@
loop assigns i;
loop invariant 0 <= i < BLOCK_NUM &&
\exists integer j; i <= j < BLOCK_NUM/2 ==> clean[j] == true;
*/
while( i < BLOCK_NUM && clean[i] == false ){
i += 1;
}
//@ assert 0 <= i < BLOCK_NUM;
}
This translates to the following proof condition.
Goal Invariant (preserved):
Assume {
Type: is_sint32(i@L4) /\ is_sint32(1 + i@L4).
[...]
Stmt { L4: }
(* Invariant *)
Have: (0 <= i@L4) /\ (i@L4 <= 999) /\
(((i@L4 <= i_3) -> ((i_3 <= 499) -> (clean@L1[i_3] = 1)))).
(* Then *)
Have: clean@L1[i@L4] = 0.
}
Prove: ((-1) <= i@L4) /\ (i@L4 <= 998) /\
(exists i_4 : Z. ((i@L4 < i_4) -> ((i_4 <= 499) -> (clean@L1[i_4] = 1)))).
--------------------------------------------------------------------------------
Prover Alt-Ergo 2.4.1: Timeout (Qed:101ms) (10s) (cached).
But still all solvers (including Z3 and CVC4) fail to show it.