2013-07-10 2 views
2

Хотелось бы узнать, можно ли сделать какой-либо предварительный обработанный срез с помощью Frama-C, и я играю с некоторыми примерами, чтобы понять, как это можно достичь.Понимание результатов резки Frama-C

У меня есть этот простой пример, который, кажется, приводит к неточному срезу, и я не могу понять, почему. Вот функция, я хотел бы порезать:

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

Если я использую эту спецификацию:

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

затем Frama-C возвращает следующий фрагмент (который является точным), используя «е -slice -Возвращение»критерий и е в качестве точки входа:

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

Но при использовании этой спецификации:

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

тогда все инструкции (& аннотаций) остаются (когда я ждал этого кусочка быть возвращено:

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

)

В последнем случае, это срез неточный? В этом случае, что может быть причиной?

С уважением,

Romain

Edit: я написал "еще, если (а = 0!) ...", но проблема остается "еще ..."

ответ

3

В Frama- C, плагин для зависания зависит от результата предварительного статического анализа, называемого анализом значений. Анализ


Это значение может представлять значения для переменной a при a == 0 (множество значений в этом случае { 0 }), но имеет трудное время для представления значения для a, когда известно, что a != 0. В последнем случае, если a еще не известен как положительный или отрицательный, плагин анализа стоимости должен аппроксимировать набор значений для a. Если известно, что a является положительным, например, если оно было unsigned int, то ненулевые значения могут быть представлены как интервал, но плагин анализа стоимости не может представлять «все значения типа int, кроме 0».


Если вы готовы изменить предварительное условие, вы можете записать его в форме, более понятный анализ стоимости плагина (вместе со значением опцией анализа -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; 
} 
+0

Спасибо за ваш ответ (я согласился с ним, кстати, извините, я не знал, что вам нужно и как это сделать, newb spotted =))! Я посмотрел руководство по анализу стоимости, но я не могу понять, почему -уровень должен быть как минимум 3 (почему не только 2)? Не могли бы вы объяснить это кратко? – roo

+1

@roo Опция '-slevel' дает анализ значений лицензии для наложения состояний памяти, например, одного состояния памяти для' a <0' и другого для 'a> 0'. Эффект заключается в том, что условие 'a! = 0' было« представлено »с интервалами в конце концов. Но ваша функция также содержит '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' = Вероятно, это является причиной того, что '-slevel 2' недостаточно. Но нет оснований пытаться использовать только правильное значение для '-slevel', если оно достаточно точное и не использует слишком много времени. Следовательно, '-уровень 10'. –

2

Это не имеет никакого отношения к вашему основному вопросу, но ваш пункт ensures a == \old(a) не делает то, что вы ожидаете. Если вы печатаете свой исходный код с опцией -print, вы увидите, что он был безшовно преобразован в ensures \old(a) == \old(a).

Язык ACSL не позволяет ссылаться на значение формальных переменных в пост-состоянии, главным образом потому, что это не имеет смысла с точки зрения вызывающего. (Рамка стека вызываемого абонента выскочит после завершения вызова.)

+0

Благодарим вас за ответ. Есть ли способ гарантировать, что значение a не изменяется во время выполнения? Я думаю, что мог бы сделать это с сильным глобальным инвариантом, но тогда, я думаю, мне придется либо сделать глобальный, либо использовать другую глобальную переменную, но возможно ли это без изменения текущего кода? – roo

+1

Не совсем, нет. Обратите внимание, что текущая спецификация будет соответствовать глобальной переменной, даже без глобального инварианта. В этом случае нормализация 'a -> \ old (a)' не произойдет, поскольку она выполняется только для формальных параметров. То, что формальный параметр изменяется во время вызова, не отображается у вызывающего (в настройке по умолчанию), поэтому он не выражается в ACSL. Однако вы можете вместо этого аннотировать тело и вставить утверждение 'a == \ old (a)' непосредственно перед командой 'return'. – byako

Смежные вопросы