When using Frama-C WP with the option -wp-out, for example(using swap.c example):
swap.c
// File swap.c:
/*# requires \valid(a) && \valid(b);
# ensures A: *a == \old(*b) ;
# ensures B: *b == \old(*a) ;
# assigns *a,*b ;
#*/
void swap(int *a,int *b)
{
int tmp = *a ;
*a = *b ;
*b = tmp ;
return ;
}
Executing with:
$frama-c -wp -wp-out po_out swap.c
And with output:
[jessie3] Loading Why3 configuration...
[jessie3] Why3 environment loaded.
[jessie3] Loading Why3 theories...
[jessie3] Loading Why3 modules...
[jessie3] Looking up module mach.int.Int32
[jessie3] Looking up module mach.int.Int64
[kernel] preprocessing with "clang -C -E -I. swap.c"
[wp] Running WP plugin...
[wp] Collecting axiomatic usage
[wp] warning: Missing RTE guards
[wp] 5 goals scheduled
[wp] [Qed] Goal typed_swap_post_B : Valid
[wp] [Qed] Goal typed_swap_assign_part1 : Valid
[wp] [Alt-Ergo] Goal typed_swap_assign_part2 : Valid (39ms) (21)
[wp] [Alt-Ergo] Goal typed_swap_post_A : Valid (Qed:1ms) (38ms) (13)
[wp] [Alt-Ergo] Goal typed_swap_assign_part3 : Valid (30ms) (21)
[wp] Proved goals: 5 / 5
Qed: 2 (0ms-1ms)
Alt-Ergo: 3 (30ms-39ms) (21)
It proves the properties and generates a folder with the proof obligations required to prove the proprieties of the program, but not all, only the ones sent to Alt-ergo the ones that Qed proves are not generated.
I understand the purpose of the Qed is to simplify, prove trivial properties to save the prover time and effort, but is it possible to let it generate all the proof obligations to send to the prover? This is, disabling Qed and let Frama-C generate all proof obligations to alt-ergo?
There are two main options that govern the quantity of work that Qed will do on each proof obligation. The output of -wp-help gives the following hints:
-wp-no-simpl prevents simplification constant terms and predicates
-wp-no-let prevents unfolding of local variables
If you use both, you should be able to obtain most proof obligations in your po_out directory, more or less as they have been computed by WP (note that some PO might still be discharged by Qed, e.g. if you have //# assert \true; somewhere).
Related
I tried to verify a program with 2-D array and encountered a problem in the assigns clause.
On the sample code, I can prove the assigns clause in the function of init_2D_2.
But, I failed to prove the same assigns clause in the main function.
The main function does nothing but invokes init_2D_2 so I believe the assigns should be correct.
Can anyone show me why frama-c can't prove it?
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#define size 5
#define page 10
/*#
requires \valid( arr+(0..(size-1)) );
requires \valid( arr[0 .. (size-1)]+(0..(page-1)) );
assigns arr[0 .. (size-1)][0..(page-1)];
ensures \forall integer a,b; 0<=a<size && 0<=b<page ==> arr[a][b] == -1;
*/
void init_2D_2(int arr[size][page]){
/*#
loop invariant 0 <= i <= size;
loop invariant \forall integer a,b; 0<=a<i && 0<=b<page ==> arr[a][b] == -1;
loop assigns i, arr[0 .. (size-1)][0..(page-1)];
loop variant size - i;
*/
for(int i=0; i<size; i++) {
/*#
loop invariant 0 <= j <= page;
loop invariant \forall integer a,b; 0<=a<i && 0<=b<page ==> arr[a][b] == -1;
loop invariant \forall integer b; 0<=b<j ==> arr[i][b] == -1;
loop assigns j, arr[i][0..(page-1)];
loop variant page - j;
*/
for(int j=0; j<page; j++) {
arr[i][j] = -1;
}
}
}
int arr2_1[size][page];
/*#
requires \valid( arr2_1[0 .. (size-1)]+(0..(page-1)) );
assigns arr2_1[0 .. (size-1)][0 .. (page-1)];
ensures \forall integer a,b; 0<=a<size && 0<=b<page ==> arr2_1[a][b] == -1;
*/
void main(){
init_2D_2(arr2_1);
}
Frama-c result of main function
Frama-c result of init_2D_2 function
$ frama-c -wp -wp-rte test.c
[kernel] Parsing test.c (with preprocessing)
[rte:annot] annotating function init_2D_2
[rte:annot] annotating function main
[wp] 33 goals scheduled
[wp] [Alt-Ergo 2.4.1] Goal typed_main_assigns_normal : Timeout (Qed:10ms) (10s) (cached)
[wp] [Alt-Ergo 2.4.1] Goal typed_main_assigns_exit : Timeout (Qed:18ms) (10s) (cached)
[wp] [Cache] found:12
[wp] Proved goals: 31 / 33
Qed: 21 (0.67ms-21ms-62ms)
Alt-Ergo 2.4.1: 10 (18ms-40ms) (261) (interrupted: 2) (cached: 12)
$ frama-c -wp -wp-rte -wp-auto wp:split test.c
[kernel] Parsing test.c (with preprocessing)
[rte:annot] annotating function init_2D_2
[rte:annot] annotating function main
[wp] 33 goals scheduled
[wp] [Failed] Goal typed_main_assigns_exit
Alt-Ergo 2.4.1: Timeout (Qed:7ms) (10s) (cached)
Script: Timeout (Qed:3ms) (10s)
[wp] [Failed] Goal typed_main_assigns_normal
Alt-Ergo 2.4.1: Timeout (Qed:7ms) (10s) (cached)
Script: Timeout (Qed:3ms) (10s)
[wp] [Cache] found:14
[wp] Proved goals: 31 / 33
Qed: 21 (0.56ms-18ms-51ms)
Alt-Ergo 2.4.1: 10 (18ms-40ms) (261) (cached: 10)
First of all, please note that the outcome of such a proof attempt is heavily dependent on the provers you are using, as well as the parameters passed to Frama-C, and finally the version of Frama-C itself. It is thus very important that this information is present in your question if you want an accurate answer. Moreover, the screenshots of Frama-C's gui with the bullets representing the status of each proof obligation do not bring much. It would be more useful to provide, as text, the output of WP on the console.
That said, what follows was obtained with Frama-C 25.0 and Alt-Ergo 2.2.0, using as command line frama-c -wp -wp-rte file.c (with file.c containing your code). I have indeed observed the situation you described:
wp] 33 goals scheduled
[wp] [Alt-Ergo 2.2.0] Goal typed_main_assigns_exit : Unknown (Qed:4ms)
[wp] [Alt-Ergo 2.2.0] Goal typed_main_assigns_normal : Unknown (Qed:3ms)
[wp] [Cache] updated:12
[wp] Proved goals: 31 / 33
Qed: 21 (0.49ms-11ms-31ms)
Alt-Ergo 2.2.0: 10 (9ms-19ms-33ms) (124) (unknown: 2)
Digging a little bit further, I've found out that activating the wp:split auto-search strategy of WP makes it simplify enough the formulas to let Alt-Ergo manage the rest: with frama-c -wp -wp-rte -wp-auto wp:split file.c, everything is proved:
[wp] 33 goals scheduled
[wp] Proved goals: 33 / 33
Qed: 21 (0.40ms-13ms-48ms)
Script: 2 (9ms-15ms) (30)
Alt-Ergo 2.2.0: 10 (8ms-28ms) (124)
-wp-auto is a command-line option that ask WP to perform a few automated tactics from the interactive proof editor before giving the resulting formula to the prover. These tactics are described in more detail in Sect. 2.2 of WP's User manual, especially Sect. 2.2.6 on strategies.
EDIT As mentioned in your comment, Alt-Ergo 2.4.1 does not seem to succeed on the goals generated with the -wp-auto wp:split option. Another solution is to use multiple automated provers instead of only Alt-Ergo. For that, you have to install other provers (for instance CVC4 and Z3), and ensure that why3 recognizes them by issuing why3 config detect. Then frama-c -wp -wp-rte -wp-prover alt-ergo,cvc4 file.c should succeed (I'm using cvc4 1.8).
Note that while in this example CVC4 alone can discharge everything (you can check that with -wp-prover cvc4, this might not be the case on other cases, even for examples where Alt-Ergo succeeds for every PO. Similarly, here, while the combination of Alt-Ergo and Z3 works, Z3 (I'm using v4.11) alone leaves a PO unproved, this time on loop invariants.
All in all, automated provers failing to discharge a PO are a fact of life, and using a combination of them can somehow alleviate the problem, even though, when things become sufficiently complicated, there's no alternative to an interactive session, either with WP's TIP (see aforementioned Sect. 2.2), or with the Coq proof assistant (option -wp-interactive, described in Sect. 2.3.8 of the manual).
I'm trying to learn ACSL but am stumbling with trying to write a complete specification. My code
#include <stdint.h>
#include <stddef.h>
#define NUM_ELEMS (8)
/*# requires expected != test;
# requires \let n = NUM_ELEMS;
# \valid_read(expected + (0.. n-1)) && \valid_read(test + (0.. n-1));
# assigns \nothing;
# behavior matches:
# assumes \let n = NUM_ELEMS;
# \forall integer i; 0 <= i < n ==> expected[i] == test[i];
# ensures \result == 1;
# behavior not_matches:
# assumes \let n = NUM_ELEMS;
# \exists integer i; 0 <= i < n && expected[i] != test[i];
# ensures \result == 0;
# complete behaviors;
# disjoint behaviors;
#*/
int array_equals(const uint32_t expected[static NUM_ELEMS], const uint32_t test[static NUM_ELEMS]) {
for (size_t i = 0; i < NUM_ELEMS; i++) {
if (expected[i] != test[i]) {
return 0;
}
}
return 1;
}
I run it with
frama-c -wp -wp-rte test.c
and I see the following log
[kernel] Parsing FRAMAC_SHARE/libc/__fc_builtin_for_normalization.i (no preprocessing)
[kernel] Parsing test.c (with preprocessing)
[rte] annotating function array_equals
test.c:22:[wp] warning: Missing assigns clause (assigns 'everything' instead)
[wp] 9 goals scheduled
[wp] [Alt-Ergo] Goal typed_array_equals_assign_part1 : Unknown (Qed:2ms) (67ms)
[wp] [Alt-Ergo] Goal typed_array_equals_assert_rte_mem_access_2 : Unknown (Qed:2ms) (128ms)
[wp] [Alt-Ergo] Goal typed_array_equals_assert_rte_mem_access : Unknown (Qed:2ms) (125ms)
[wp] [Alt-Ergo] Goal typed_array_equals_matches_post : Unknown (Qed:10ms) (175ms)
[wp] [Alt-Ergo] Goal typed_array_equals_not_matches_post : Unknown (Qed:7ms) (109ms)
[wp] Proved goals: 4 / 9
Qed: 4 (0.56ms-4ms)
Alt-Ergo: 0 (unknown: 5)
So it seems like my two behaviors and the "assigns \nothing" couldn't be proved. So how do I proceed from here?
EDIT: So I figured out the immediate problem. I have no annotate my loop:
/*# loop invariant \let n = NUM_ELEMS; 0 <= i <= n;
# loop invariant \forall integer k; 0 <= k < i ==> expected[k] == test[k];
# loop assigns i;
# loop variant \let n = NUM_ELEMS; n-i;
#*/
My larger question still stands: what's a good way to debug problems? I solved this one by just changing and deleting code and seeing what is proved/not proved.
I'm afraid there cannot be a definitive answer to this question (to be honest, I have considered voting to close it as "too broad"). Here are however a few guidelines that will probably help you in your proof attempts:
Identifying individual clauses
ACSL specifications are quickly composed of many clauses (requires, ensures, loop invariant, assert, ...). It is important to be able to easily distinguish between them. For that, you have two main ingredients:
Use the GUI. It makes it much easier to see which annotations are proved (green bullet), proved but under the hypothesis that other, unproved clauses are true (green/yellow), or unproved (yellow).
Name your clauses: any ACSL predicate can be attached a name, with the syntax name: pred. When a clause is equipped with a name, WP will use it to refer to the clause.
Usual suspects
It is very easy to miss some very important part of a specification. Here is a quick check list:
All loops must be equipped with loop invariant and loop assigns
All functions called by the one under analysis must have a contract (with at least an assigns clause)
If a memory location mentioned in a loop assigns is not subject of a
corresponding loop invariant, you know nothing about the value stored at that location outside of the loop. This might be an issue.
Debugging individual clauses
Once you're confident that you haven't missed anything obvious, it is time
to start investigating on specific clauses.
Usually, it is much easier to verify that a loop invariant is established
(i.e. true when attaining the loop for the first time) rather than preserved (staying true across a of loop step). If you can't establish a loop invariant, it is either wrong, or you forgot some requires to constraint the input of the function (a typical case for algorithm over arrays is loop invariant 0<=i<=n; that can't be proved if you don't requires n>=0;)
Similarly assigns and loop assigns should be easier to verify than real functional properties. As long as they are not all proved, you should concentrate on them (a common error is to forget to put the index of a loop in
its loop assigns, or to mention that it assigns a[i] and not a[0..i]).
Don't forget that assigns must include all possible assignments, including
the ones done in callees.
Don't hesitate to use assert to check whether WP can prove that a property holds at a given point. This will help you understand where the problems arise. [ edit according to #DavidMENTRÉ's comment below ] Note that in that case, you should take care of the fact that the initial proof obligation might succeed under the hypothesis that the assert holds while the assert itself is not validated. In the GUI, this is reflected by a green/yellow bullet, and of course a yellow bullet in front of the assert. In that case, the proof is not over yet, and you have to understand why the assert is not proved, possibly using the same strategy as above, until you understand exactly where the problem lies.
The ACSL implementation (Version 1.11 Implementation in Aluminium-20160501) lists \NearestEven as a rounding mode (page 23). However, it doesn't appear to be still available at runtime. When I ran the following code:
/*# requires 0x1p-967 <= C <= 0x1p970;
# ensures \result == \round_double(\NearestEven, (x+y)/2) ;
# */
double average(double C, double x, double y) {
if (C <= abs(x))
return x/2+y/2;
else
return (x+y)/2;
}
using the following command: frama-c -wp -wp-rte -wp-prover coq avg.c, I get: [wp] user error: Builtin \NearestEven not defined. None of the other rounding modes was available either.
Any suggestions?
The manual you refer to indicates what is supported by Frama-C's kernel. This does not imply that all plugins (or even any plugin) know how to deal with such a construction. In your particular case, WP indeed does not support \NearestEven.
With -wp-model +float, you might be able to work on a goal such as \result == (double)((x+y)/2), which will very probably use nearest even for the rounding involved by the cast to double (but I have to admit that the paragraph on Float arithmetic model in WP's manual is a bit succinct). This will of course not work if you want to use another rounding mode, for which I think only the Jessie plugin, if there is a version compatible with Aluminium somewhere, will be able to do something.
Note that for handling such proofs, you'll need to resort to Gappa and/or Coq. The prover used in WP by default (Alt-Ergo) is unlikely to discharge much proof obligations related to floating-point computations.
I have the following variables:
int** send_count;
message_struct*** send_queue;
And I have a function I want to declare a contract for
message_record_struct postSend(int destination, double* buf);
How do I declare a contract which allows assignment to the elements of send_count and send_queue?
I'm concerned the following approach only allows assignment to the element at the address of pointer to the array:
# assigns send_count
And the following approach throws an error given the axiomatic theory { logic integer NP; } in an earlier portion of the code):
# assigns *(send_count+(0..NP-1));
# assigns \forall integer i; 0<=i<NP ==>
*(send_count[i]+(0..NP-1));
$ frama-c -wp -wp-prover "why3ide" assign_example.c
[kernel] Parsing FRAMAC_SHARE/libc/__fc_builtin_for_normalization.i (no preprocessing)
[kernel] Parsing assign_example.c (with preprocessing)
assign_example.c:62:[kernel] user error: syntax error (expression expected but predicate found) in annotation.
[kernel] user error: stopping on file "assign_example.c" that has errors. Add '-kernel-msg-key pp' for preprocessing command.
[kernel] Frama-C aborted: invalid user input.
The syntax you are looking for is probably
/*# assigns *(send_count+(0..NP-1));
assigns *(send_count[0..NP-1]+(0..NP-1));
ACSL ranges [a..b] have been introduced to keep assigns clauses quantifiers-free, and should be used as much as possible.
How should I approach proving the correctness of code like the following, which, to avoid some inefficiency, relies on modular arithmetic?
#include <stdint.h>
uint32_t my_add(uint32_t a, uint32_t b) {
uint32_t r = a + b;
if (r < a)
return UINT32_MAX;
return r;
}
I've experimented with WP's "int" model, but, if I understand correctly, that model configures the semantics of logical integers in POs, not the formal models of C code. For example, the WP and RTE plugins still require and inject overflow assertion POs for the unsigned addition above when using the "int" model.
In cases like this, can I add annotations stipulating a logical model for a statement or basic block, so I could tell Frama-C how a particular compiler actually interprets a statement? If so, I could use other verification techniques for things like defined-but-often-defect-inducing behaviors like unsigned wrap-around, compiler-defined behaviors, nonstandard behaviors (inline assy?), etc., and then prove correctness for the surrounding code. I'm picturing something similar to (but more powerful than) the "assert fix" used to inform some static analyzers that certain properties hold when they can't derive the properties for themselves.
I'm working with Frama-C Fluorine-20130601, for reference, with alt-ergo 95.1.
I'm working with Frama-C Fluorine-20130601
Glad to see that you found a way to use the latest version.
Here are some random bits of information that, although they do not completely answer your question, do not fit in a StackOverflow comment:
Jessie has:
#pragma JessieIntegerModel(modulo)
The above pragma makes it consider that all overflows (both the undefined signed ones and the defined unsigned ones) wrap around (in the same of signed overflows, in 2's complement arithmetic). The generated proof obligations are much harder, because they contain additional modulo operations everywhere. Of automated theorem provers, typically only Simplify is able to do something with them.
In Fluorine, RTE does not warn about a + b by default:
$ frama-c -rte t.c -then -print
[kernel] preprocessing with "gcc -C -E -I. t.c"
[rte] annotating function my_add
/* Generated by Frama-C */
typedef unsigned int uint32_t;
uint32_t my_add(uint32_t a, uint32_t b)
{
uint32_t __retres;
uint32_t r;
r = a + b;
if (r < a) {
__retres = 4294967295U;
goto return_label;
}
__retres = r;
return_label: return __retres;
}
RTE can be made to warn about the unsigned addition with option -warn-unsigned-overflow:
$ frama-c -warn-unsigned-overflow -rte t.c -then -print
[kernel] preprocessing with "gcc -C -E -I. t.c"
[rte] annotating function my_add
/* Generated by Frama-C */
typedef unsigned int uint32_t;
uint32_t my_add(uint32_t a, uint32_t b)
{
uint32_t __retres;
uint32_t r;
/*# assert rte: unsigned_overflow: 0 ≤ a+b; */
/*# assert rte: unsigned_overflow: a+b ≤ 4294967295; */
r = a + b;
…
But that's precisely the opposite of what you want so I don't see why you would do that.
You didn't provide the exact command line that you have been using. I guess this is frama-c -wp -wp-rte file.c -pp-annot. In that case, indeed, all assertions that RTE can possibly emit are generated. You can however have a finer control over that, by instructing frama-c to first generate only the categories of RTE that you're interested in (be careful that they are controlled by two kinds of options: the ones of frama-c -rte-help and the -warn-{signed,unsigned}-{overflow,downcast} defined in the kernel), and then launch wp on the result. This is done by frama-c -rte -pp-annot file.c -then -wp By default, rte does not consider unsigned overflow to be an error, so that with the above command line, I'm able to prove that your function respects the following specification:
/*#
behavior no_overflow:
assumes a + b <= UINT32_MAX;
ensures \result == a+b;
behavior saturate:
assumes a+b > UINT32_MAX;
ensures \result == UINT32_MAX;
*/
uint32_t my_add(uint32_t a,uint32_t b);