How do I debug ACSL in frama-c? - frama-c

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.

Related

Frama-c : Trouble understanding WP memory models

I'm looking for WP options/model that could allow me to prove basic C memory manipulations like :
memcpy : I've tried to prove this simple code :
struct header_src{
char t1;
char t2;
char t3;
char t4;
};
struct header_dest{
short t1;
short t2;
};
/*# requires 0<=n<=UINT_MAX;
# requires \valid(dest);
# requires \valid_read(src);
# assigns (dest)[0..n-1] \from (src)[0..n-1];
# assigns \result \from dest;
# ensures dest[0..n] == src[0..n];
# ensures \result == dest;
*/
void* Frama_C_memcpy(char *dest, const char *src, uint32_t n);
int main(void)
{
struct header_src p_header_src;
struct header_dest p_header_dest;
p_header_src.t1 = 'e';
p_header_src.t2 = 'b';
p_header_src.t3 = 'c';
p_header_src.t4 = 'd';
p_header_dest.t1 = 0x0000;
p_header_dest.t2 = 0x0000;
//# assert \valid(&p_header_dest);
Frama_C_memcpy((char*)&p_header_dest, (char*)&p_header_src, sizeof(struct header_src));
//# assert p_header_dest.t1 == 0x6265;
//# assert p_header_dest.t2 == 0x6463;
}
but the two last assert weren't verified by WP (with default prover Alt-Ergo). It can be proved thanks to Value analysis, but I mostly want to be able to prove the code not using abstract interpretation.
Cast pointer to int : Since I'm programming embedded code, I want to be able to specify something like:
#define MEMORY_ADDR 0x08000000
#define SOME_SIZE 10
struct some_struct {
uint8_t field1[SOME_SIZE];
uint32_t field2[SOME_SIZE];
}
// [...]
// some function body {
struct some_struct *p = (some_struct*)MEMORY_ADDR;
if(p == NULL) {
// Handle error
} else {
// Do something
}
// } body end
I've looked a little bit at WP's documentation and it seems that the version of frama-c that I use (Magnesium-20151002) has several memory model (Hoare, Typed , +cast, +ref, ...) but none of the given example were proved with any of the model above. It is explicitly said in the documentation that Typed model does not handle pointer-to-int casts. I've a lot of trouble to understand what's really going on under the hood with each wp-model. It would really help me if I was able to verify at least post-conditions of the memcpy function. Plus, I have seen this issue about void pointer that apparently are not very well handled by WP at least in the Magnesium version. I didn't tried another version of frama-c yet, but I think that newer version handle void pointer in a better way.
Thank you very much in advance for your suggestions !
memcpy
Reasoning about the result of memcpy (or Frama_C_memcpy) is out of range of the current WP plugin. The only memory model that would work in your case is Bytes (page 13 of the manual for Chlorine), but it is not implemented.
Independently, please note that your postcondition from Frama_C_memcpy is not what you want here. You are asserting the equality of the sets dest[0..n] and src[0..n]. First, you should stop at n-1. Second, and more importantly, this is far too weak, and is in fact not sufficient to prove the two assertions in the caller. What you want is a quantification on all bytes. See e.g. the predicate memcmp in Frama-C's stdlib, or the variant \forall int i; 0 <= i < n -> dest[i] == src[i];
By the way, this postcondition holds only if dest and src are properly separated, which your function does not require. Otherwise, you should write dest[i] == \at (src[i], Pre). And your requires are also too weak for another reason, as you only require the first character to be valid, not the n first ones.
Cast pointer to int
Basically, all current models implemented in WP are unable to reason on codes in which the memory is accessed with multiple incompatible types (through the use of unions or pointer casts). In some cases, such as Typed, the cast is detected syntactically, and a warning is issued to warn that the code cannot be analyzed. The Typed+Cast model is a variant of Typed in which some casts are accepted. The analysis is correct only if the pointer is re-cast into its original type before being used. The idea is to allow using some libc functions that require a cast to void*, but not much more.
Your example is again a bit different, because it is likely that MEMORY_ADDR is always addressed with type some_stuct. Would it be acceptable to change the code slightly, and change your function as taking a pointer to this type? This way, you would "hide" the cast to MEMORY_ADDR inside a function that would remain unproven.
I tried this example in the latest version of Frama-C (of course the format is modified a little bit).
for the memcpy case
Assertion 2 fails but assertion 3 is successfully proved (basically because the failure of assertion 2 leads to a False assumption, which proves everything).
So in fact both assertion cannot be proved, same as your problem.
This conclusion is sound because the memory models used in the wp plugin (as far as I know) has no assumption on the relation between fields in a struct, i.e. in header_src the first two fields are 8 bit chars, but they may not be nestedly organized in the physical memory like char[2]. Instead, there may be paddings between them (refer to wiki for detailed description). So when you try to copy bits in such a struct to another struct, Frama-C becomes completely confused and has no idea what you are doing.
As far as I am concerned, Frama-C does not support any approach to precisely control the memory layout, e.g. gcc's PACKED which forces the compiler to remove paddings.
I am facing the same problem, and the (not elegant at all) solution is, use arrays instead. Arrays are always nested, so if you try to copy a char[4] to a short[2], I think the assertion can be proved.
for the Cast pointer to int case
With memory model Typed+cast, the current version I am using (Chlorine-20180501) supports casting between pointers and uint64_t. You may want to try this version.
Moreover, it is strongly suggested to call Z3 and CVC4 through why3, whose performance is certainly better than Alt-Ergo.

Frama-C generates confusing assertions about pointer comparison

I'm getting assertions that don't make sense to me.
Code:
struct s {
int pred;
};
/*# assigns \result \from \nothing;
ensures \valid(\result);
*/
struct s *get(void);
int main(void)
{
return !get()->pred;
}
Frama-C output:
$ frama-c -val frama-ptr.c
[...]
frama-ptr.c:12:[kernel] warning: pointer comparison.
assert \pointer_comparable((void *)0, (void *)tmp->pred);
(tmp from get())
Am I doing something wrong or is it a bug in Frama-C?
This is not really a bug, although this behavior is not really satisfactory either. I recommend that you observe the analysis in the GUI (frama-c-gui -val frama-ptr.c), in particular the value of tmp->pred at line 12 in the Values tab.
Value before:
∈
{{ garbled mix of &{alloced_return_get}
(origin: Library function {c/ptrcmp.c:12}) }}
This is a very imprecise value, that has been generated because the return value of function get is a pointer. The Eva plugin generates a dummy variable (alloced_return_get), and fills it with dummy contents (garbled mix of &{alloced_return_get}). Even though the field pred is an integer, the analyzer assumes that (imprecise) pointers can also be present. This is why an alarm for pointer comparison is emitted.
There are at least two ways to avoid this:
use option -val-warn-undefined-pointer-comparison pointer, so that pointer comparison alarms are emitted only on comparisons involving lvalues with pointer type. The contents of the field pred will remain imprecise, though.
add a proper body to function get, possibly written using malloc, so that the field pred receives a more accurate value.
On a more general note, the Eva/Value plugin requires precise specifications for functions without a body; see section 7.2 of the manual. For functions that return pointers, you won't be able to write satisfactory specifications: you need to write allocates clauses, and those are currently not handled by Eva/Value. Thus, I suggest that you write a body for get.

Make Frama-c show dependencies even of "dead branches"

I am using frama-c Aluminium-20160502 version and I want to find out the dependencies in a large program. When using the option -deps in the command line I found some dependencies are missing. In particular when several conditions are joined in one if, the dependency analysis stops whenever one condition is false. In this example here:
#include<stdio.h>
#include<stdbool.h>
/*Global variable definitions*/
bool A = true;
bool B = false;
bool C = true;
bool X;
bool Y;
bool res;
void main(){
if (A && B && C) {
res = X;
}else res = Y;
}
when I try: frama-c -deps program.c
frama shows the following dependencies:
[from] ====== DEPENDENCIES COMPUTED ======
These dependencies hold at termination for the executions that terminate:
[from] Function main:
res FROM A; B; Y
[from] ====== END OF DEPENDENCIES ======
so it does not reach the condition C because already B is false.
I wonder if there is a way to tell frama to compute all dependencies even if the condition is not fulfilled. I tried with the option -slevel but with no results. I know there is a way to use an interval Frama_C_interval(0,1) but when I use it the variable using this function is not shown in the dependencies. I would like to get X and Y dependent on A,B,C and res dependent on A,B,C,X,Y
Any ideas?
The From plugin uses the results of the Value analysis plugin. In your example, the values of A and B are sufficiently precise that Value is able to infer that the condition is entirely determined (since the && operator is lazily evaluated, from left to right) before reaching C, therefore C never affects the outcome and is thus not a dependency from the point of view of From.
Unfortunately, Frama_C_interval cannot be used directly at global initializers:
user error: Call to Frama_C_interval in constant.
You can, however, use a "hack" (not always the best solution, but works here):
volatile bool nondet;
bool A = nondet;
bool B = nondet;
bool C = nondet;
...
Note that because nondet is volatile, each variable A, B and C is assigned a different non-deterministic value.
In this case, Value has to consider both branches of the conditionals, and therefore C becomes a dependency in your example, since it is possible that C will be read during the execution of main. You'll then have:
These dependencies hold at termination for the executions that terminate:
[from] Function main:
res FROM A; B; C; X; Y
Note that some plugins require special treatment when dealing with volatile variables, so this is not always the best solution.
This however only deals with some kinds of dependencies. As mentioned in Chapter 6 of the Value Analysis user manual, the From plugin computes functional, imperative and operational dependencies. These do not include indirect control dependencies, which are those such as X from A, B, C, as you mention. For those, you need the PDG (Program Dependence Graph) plugin, but it does not currently have a textual output of the dependencies. You can use -pdg to compute it, and then -pdg-dot <file> to export the dependency graph in dot (graphviz) format. Here's what I get for your main function (using the volatile hack as mentioned previously):
Finally, as a side note: -slevel is mostly used to improve precision, but in your example you already have too much precision (that is, Value is already able to infer that C is never read inside main).

Is "\NearestEven" available in frama-c Aluminium-20160501?

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.

Proofs for code that relies on unsigned integer overflow?

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);

Resources