5

I'd like to know if it's possible to do some kind of forward conditioned slicing with Frama-C and I'm playing with some examples to understand how one could achieve this.

I've got this simple example which seems to result in an imprecise slice and I can't understand why. Here is the function I'd like to slice :

int f(int a){
int x;
if(a == 0)
    x = 0;
else if(a != 0)
    x = 1;
return x;
}

If I use this specification :

/*@ requires a == 0;
  @ ensures \old(a) == a;
  @ ensures \result == 0;
*/

then Frama-C returns the following slice (which is precise), using "f -slice-return" criterion and f as entry point :

/*@ ensures \result ≡ 0; */
int f(void){
  int x;
  x = 0;
  return x;
}

But when using this specification :

/*@ requires a != 0;
  @ ensures \old(a) == a;
  @ ensures \result == 1;
*/

then all instructions (& annotations) remain (when I was waiting for this slice to be returned :

/*@ ensures \result ≡ 1; */
int f(void){
  int x;
  x = 1;
 return x;
}

)

In the last case, is the slice imprecise? In this case, what could be the cause?

Regards,

Romain

Edit : I wrote "else if(a != 0) ..." but the problem remains with "else ..."

roo
  • 149
  • 9

2 Answers2

5

In Frama-C, the slicing plug-in relies on the result of a preliminary static analysis plug-in called the value analysis.


This value analysis can represent the values for variable a when a == 0 (the set of values is in this case { 0 }) but has a hard time to represent the values for a when it is known that a != 0. In the latter case, if a is not already known to be positive or negative, the value analysis plug-in needs to approximate the set of values for a. If a was known to be positive, for instance if it was an unsigned int, then the nonzero values could be represented as an interval, but the value analysis plug-in cannot represent “all values of type int except 0”.


If you are willing to change the pre-condition, you can write it in a form that is more easily understood by the value analysis plug-in (together with value analysis option -slevel):

$ cat t.c
/*@ requires a < 0 || a > 0 ;
  @ ensures \old(a) == a;
  @ ensures \result == 0;
*/

int f(int a){
int x;
if(a == 0)
    x = 0;
else if(a != 0)
    x = 1;
return x;
}
$ frama-c -slevel 10 t.c -main f -slice-return f -then-on 'Slicing export' -print 
…
/* Generated by Frama-C */
/*@ ensures \result ≡ 0; */
int f(void)
{
  int x;
  x = 1;
  return x;
}
Pascal Cuoq
  • 79,187
  • 7
  • 161
  • 281
  • Thanks for your answer (I accepted it by the way - sorry, I didn't knew you have to and how to do it, newb spotted =) )! I looked at the Value analysis manual but I can't understand why -slevel needs to be 3 at least (why not just 2)? Could you explain it briefly? – roo Jul 12 '13 at 09:50
  • 1
    @roo Option `-slevel` gives the value analysis a license to superpose memory states, for instance one memory state for `a < 0` and another for `a > 0`. The effect is that the condition `a != 0` has been “represented” with intervals after all. But your function also contains `if`s, the states coming from the two branches of which the option `-slevel` also tries to superpose. This is probably the reason why `-slevel 2` does not suffice. But there is no reason to try to use just the right value for `-slevel`, as long as it is precise enough and does not use too much time. Hence, `-slevel 10`. – Pascal Cuoq Jul 12 '13 at 09:56
2

This has no relevance whatsoever with your main question, but your ensures a == \old(a) clause is not doing what you expect. If you pretty-print your source code with option -print, you will see it has been silently transformed into ensures \old(a) == \old(a).

The ACSL language does not permit referring about the value of formal variables in the post-state, mostly because this is meaningless from the point of view of the caller. (The stack frame of the callee is popped after the call terminates.)

byako
  • 3,372
  • 2
  • 21
  • 36
  • Thank you for your answer. Is there a way to ensure that the value of a is unchanged during execution? I think I could do that with a strong global invariant but then I guess I would have to either make a global or use another global variable but is it possible without modifying the current code? – roo Jul 12 '13 at 10:00
  • 1
    Not really, no. Note that your current specification would be ok with a global variable, even without a global invariant. In this case, the normalization `a -> \old(a)` would not occur, as it is performed only for formal parameters. That a formal parameter is modified during a call is not visible from the caller (in a call-by-value setting), so it is not expressible in ACSL. However, you can instead annotate the body, and insert an assertion `a == \old(a)` just before the `return` instruction. – byako Jul 12 '13 at 11:28