WP plugin: Alt-Ergo Syntax Error - frama-c

For the below C function, I'm getting syntax errors from Alt-Ergo for the latest version of Frama-c.
frama-c -wp -wp-rte -lib-entry RoundNearestFive.c -wp-out temp -wp-model="nat, real"
I'm not sure what is wrong in this generated line:
...
let r_0 = dat_0 / 5.0e0 : real in /* syntax error here */
...
C function under analysis
typedef unsigned short int uint16;
/*#
# requires 0<=dat<= 300;
*/
uint16 RoundNearestFive(float dat)
{
uint16 result= 0;
float fra = 0;
result = (uint16)(dat/5);
fra = dat - (float)result*5; // fractional part of the input
if (fra < 2.5)
result = (uint16) (dat-fra);
else
result = (uint16) (dat+(5-fra));
return result;
}

I tried Alt-Ergo (version 0.95.2 and trunk) on the formula below and I got no syntax error. Are you using an old version of Alt-Ergo ? Or maybe the syntax error is elsewhere.
--
logic dat_0 : real
goal g:
let r_0 = dat_0 / 5.0e0 : real in (* syntax error here *)
false

The WP user manual explicitly states that versions of Alt-Ergo prior to 0.95 are not supported (see page 21).

Related

How to verify Why3 output of Proof Obligations

I believe I can generate proofs using why3 with different provers,
frama-c -wp -wp-prover cvc4 -wp-rte -wp-out proof swap.c
frama-c -wp -wp-prover z3-ce -wp-rte -wp-out proof swap.c
frama-c -wp -wp-prover alt-ergo -wp-rte -wp-out proof swap.c
This generates different 'why' files. I would like to validate the proof obligations with an external program. It seems each proof obligation is in a different format; LispClojure and OCaml? What exactly is the format? Is it correct that these are proof and are sufficient to show the contract/proof is correct without proving that Z3, alt-ergo, etc are correct?
swap.c
For the wp tutorial,
int h = 42;
/*#
requires \valid(a) && \valid(b);
assigns *a, *b;
ensures *a == \old(*b) && *b == \old(*a);
*/
void swap(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
int main()
{
int a = 24;
int b = 37;
//# assert h == 42;
swap(&a, &b);
//# assert a == 37 && b == 24;
//# assert h == 42;
return 0;
}
This works fine and the frama-c-gui shows me how to develop contracts and annotations.
Alter-ergo
(* WP Task for Prover Alt-Ergo,2.4.1 *) (* this is the prelude for Alt-Ergo, version >= 2.4.0 *) (* this is a prelude for Alt-Ergo integer arithmetic *) (* this is a prelude for Alt-Ergo real arithmetic *) type string
logic match_bool : bool, 'a, 'a -> 'a
axiom match_bool_True : (forall z:'a. forall z1:'a. (match_bool(true, z, z1) = z))
The full proof is truncated for brevity.
z3-ce
(* WP Task for Prover Z3,4.8.11,counterexamples *) ;;; generated by SMT-LIB2 driver ;;; SMT-LIB2 driver: bit-vectors, common part ;;; generated by SMT-LIB strings ;;; generated by SMT-LIB strings (set-option :produce-models true) ;;; SMT-LIB2: integer arithmetic ;;; SMT-LIB2: real arithmetic (declare-sort uni 0)
(declare-sort ty 0)
(declare-fun sort (ty uni) Bool)
(declare-fun witness (ty) uni)
The full proof is truncated for brevity.
I have to admit that I'm not completely sure that I completely understand what you want to achieve here, but here are the answers to your questions:
It seems each proof obligation is in a different format; Lisp and OCaml? What exactly is the format?
These files represent the formulas that are given to the provers you ask Frama-C to launch. The format depends on the prover. If I recall correctly, for many provers, this will be smtlib, or tptp, but some provers such as Alt-Ergo can also enjoy a custom output. The generation of the file is described by Why3's driver files, as mentioned (quite briefly) in section 12.4 of the Why3 manual.
Is it correct that these are proof ?
No, these are formulas to be validated by the prover they have been generated for.
and are sufficient to show the contract/proof is correct without proving that Z3, alt-ergo, etc are correct?
No. If the provers you use have a bug, they might mistakenly tell you that a given proof obligation is valid. Some provers are able to provide a proof trace (e.g. if you tweak a driver to use the get-proof command of smtlib), but as far as I know, the format of such a trace is prover-specific, so that it would probably be difficult to have it checked by an external tool.

Frama-C acsl max example from manual not working

I believe I am missing something obvious, but I have tried a lot and I haven't managed to find the source of the problem.
I am following the acsl guide from Frama-C.
There is this introductory example of how to verify the correctness of finding the maximum value in an array:
/*# requires n > 0;
requires \valid(p+ (0 .. n-1));
ensures \forall int i; 0 <= i <= n-1 ==> \result >= p[i];
ensures \exists int e; 0 <= e <= n-1 && \result == p[e];
*/
int max_seq(int* p, int n) {
int res = *p;
for(int i = 0; i < n; i++) {
if (res < *p) { res = *p; }
p++;
}
return res;
}
However, running frama-c -wp -wp-prover alt-ergo samenum.c -then -report I get:
[wp] Warning: Missing RTE guards
[wp] samenum.c:8: Warning: Missing assigns clause (assigns 'everything' instead)
[wp] 2 goals scheduled
[wp] [Alt-Ergo] Goal typed_max_seq_ensures_2 : Timeout (Qed:1ms) (10s)
[wp] [Alt-Ergo] Goal typed_max_seq_ensures : Timeout (Qed:2ms) (10s)
[wp] Proved goals: 0 / 2
Alt-Ergo: 0 (interrupted: 2)
[report] Computing properties status...
--------------------------------------------------------------------------------
--- Properties of Function 'max_seq'
--------------------------------------------------------------------------------
[ - ] Post-condition (file samenum.c, line 3)
tried with Wp.typed.
[ - ] Post-condition (file samenum.c, line 4)
tried with Wp.typed.
[ - ] Default behavior
tried with Frama-C kernel.
It seems that alt-ergo times out before proving the property. For what is worth, I tried with higher time-out but it still doesn't work.
I am using:
frama-c: 19.1
why3: 1.2.0
alt-ergo: 2.3.2
I am running this on Ubuntu 18.04 and before running the command I run: why3 config --detect to make sure why3 knows about alt-ergo.
Any ideas? Can anyone verify that this is example is not working?
Any help would be greatly appreciated!
This mini-tutorial was written quite a long time ago and is not really up to date. A new version of the website should appear in the upcoming months. Basically, this contract, as well as the invariant for the loop pointed by #iguerNL were meant to be verified using the Jessie plugin, and not the WP plugin of Frama-C. Among the differences between these two plugins, Jessie did not need assigns clauses for loops and functions, while WP needs them.
Thus, a complete annotated max_seq function could be this one:
/*# requires n > 0;
requires \valid(p+ (0..n−1));
assigns \nothing;
ensures \forall int i; 0 <= i <= n−1 ==> \result >= p[i];
ensures \exists int e; 0 <= e <= n−1 && \result == p[e];
*/
int max_seq(int* p, int n) {
int res = *p;
//# ghost int e = 0;
/*# loop invariant \forall integer j; 0 <= j < i ==> res >= \at(p[j],Pre);
loop invariant \valid(\at(p,Pre)+e) && \at(p,Pre)[e] == res;
loop invariant 0<=i<=n;
loop invariant p==\at(p,Pre)+i;
loop invariant 0<=e<n;
loop assigns i, res, p, e;
loop variant n-i;
*/
for(int i = 0; i < n; i++) {
if (res < *p) {
res = *p;
//# ghost e = i;
}
p++;
}
return res;
}
where we specify that the functions does not assign anything in memory, and that the loop assigns the different local variables i, res, p and e (thus leaving n unchanged).
Note that more recent tutorials are available to learn about the use of Frama-C with the WP plugin. The future version of the Frama-C website mentions:
A comprehensive tutorial on ACSL and WP
Another tutorial, with specifications inspired notably from C++ containers
You probably forgot to add invariants for the "for" loop. See Section "10.2 Loop Invariants" in the manual you gave (https://frama-c.com/acsl_tutorial_index.html)

How to prove this assign clause?

/*#
# requires \valid(p);
# assigns \nothing;
*/
void foo(int *p)
{
int *pb;
pb = p;
*pb = 1;
return;
}
void main(){
int a = 0;
foo(&a);
return;
}
As I understand the assigns clause for a function contract only works with the function's input variables. So I make the assigns clause to nothing but then get yellow status with -wp.
frama-c -wp test1.c
[kernel] Parsing test1.c (with preprocessing)
[wp] Warning: Missing RTE guards
[wp] 3 goals scheduled
[wp] [Alt-Ergo] Goal typed_foo_assign_part2 : Unknown (Qed:4ms) (51ms)
[wp] Proved goals: 2 / 3
Qed: 2
Alt-Ergo: 0 (unknown: 1)
How to prove foo() if assigns \nothing is not working?
I'm unsure of what you mean by "assigns [...] only works with the function's input variable". An assigns clause is supposed to give a superset of all memory locations that are allocated in both the pre- and post- states of the contract (there are specific clauses for handling dynamic (de)allocation) and that might be modified during the execution of the function (or the statement for a statement contract).
In particular, your function foo can't have an assigns \nothing; clause since it modifies the value of the location pointed to by p: you must have something like assigns *p;, which is easily proved by frama-c -wp.

Frama-c cannot prove validity of buffer pointer of type other than `char*`

Consider the following C code:
#include <stdio.h>
/*#
requires \valid(p+(0..n-1));
requires \valid(fp);
*/
void f(/*unsigned*/ char *p, size_t n, FILE *fp)
{
fread(p, 1, n, fp);
}
Frama-c can prove that the pre-conditions to fread are met. However, with unsigned restored, frama-c fails to see the obvious fact that \valid((char*)p+(0..n-1)) holds. Why?
It looks like the conversion from unsigned char * in f to char * in the pre-condition of fread is confusing the WP plug-in of Frama-C. When using -wp-out foo to get the files given to the external provers in directory foo/, I get the following goal in Alt-Ergo's syntax:
goal f_call_fread_pre_valid_ptr_block:
forall i : int.
forall t : int farray.
forall t_1 : (addr,int) farray.
forall a_2,a_1,a : addr.
(region(a_1.base) <= 0) ->
(region(a_2.base) <= 0) ->
linked(t) ->
sconst(t_1) ->
is_uint32(i) ->
valid_rw(t, a_2, 2) ->
valid_rw(t, shift_uint8(a_1, 0), i) ->
valid_rw(t, shift_sint8(a, 0), i)
Note in particular that the hypothesis (i.e. the requires of f) mentions variable a_1, while the goal (i.e. the requires of fread that we are trying to prove), mentions variable a, and that there is absolutely nothing tying a_1 and a together.
I'd tend to see that as a bug, but I'm not expert in WP's internals. You might want to report that on Frama-C's BTS.

Frama-C is proving invalid assertions

I am able to prove the following program using Frama-C, which is surprising because 1) there is an assert false, and 2) the loop invariant does not hold (array a holds 1's not 2's). Am I missing something here?
/*# requires \valid(a+ (0..9)) && \valid(b+ (0..9));
*/
void test_foo(int *a, char *b) {
int i = 0;
/*# loop invariant \forall int j; 0 <= j < i ==> a[j] == 2;
loop invariant \forall int j; 0 <= j < i ==> b[j] == 'a';
*/
for (int i = 0; i < 10; i++) {
a[i] = 1;
b[i] = 'a';
}
//# assert \false;
}
I am running frama-c as:
frama-c -wp -wp-invariants -wp-prover "why3:alt-ergo" -wp-model "Typed,int,real" -wp-par 8 -wp-timeout 15 -wp-out wp.out test.c
I see same behavior on both Sodium and Magnesium versions.
-wp-invariants is not meant to handle "normal" loop invariants such as the ones you have provided, but "general inductive invariants" in the sense of ACSL section 2.4.2. You can thus remove this option from your command line. Then some proof obligations fail as expected.
Note in addition that your loop annotations are incomplete: as warned by WP, you should have a loop assigns, such as
loop assigns i, a[0 .. 9], b[0 .. 9];
Then, in order to be able to prove this loop assigns, you will need to specify i interval of variation:
loop invariant 0<=i<=10;
Finally, the fact that -wp-invariants make proof obligations behave strangely in presence of normal loop annotations should probably be considered as a bug and reported on Frama-C's bts.

Resources