计算导致满足谓词的输入范围

时间:2016-02-09 10:04:16

标签: c frama-c formal-verification alt-ergo value-analysis

假设我们有以下C代码:

int my_main(int x){
    if (x > 5){
        x++;
        if (x > 8){
            x++;
            if (x < 15){
                //@(x >= 9 && x <= 14);
            }
        }   
    }
    return 0;
}

我想在初始化时使用静态分析计算变量x的边界,从而得到满意的谓词。在这个例子中,main开头的x的间隔应该是[8,12]。

TL; DR:在代码中的某个位置给出断言,计算这些范围的最佳方法是什么?

到目前为止我尝试了什么:

我认为解决这个问题的最佳方法是使用最弱的前提条件计算器。我试图使用frama-c的wp插件,但由于它是为验证目的而构建的,我不确定它在这个用例中有多大用处。在以下代码上应用插件时:

int main(void){
    int n = 0;
    int x;

    if (x > 5){
        x++;
        if (x > 8){
            x++;
            if (x < 15){
                n = x;
            }
        }   
    }
    //@ assert p: n >= 9 && n <= 14;
    return 0;
}

我将以下谓词发送给alt-ergo求解器:

  goal main_assert_p:
    forall i_1,i : int.
    is_sint32(i) ->
    is_sint32(i_1) ->
    (((i < 6) -> (0 = i_1)) and
     (**(6 <= i)** ->
      (((i < 8) -> (0 = i_1)) and
       (**(8 <= i)** ->
        (((12 < i) -> (0 = i_1)) and (**(i <= 12)** -> (i_1 = (2 + i)))))))) ->
    ((9 <= i_1) and (i_1 <= 14))

如果仔细观察,可以通过遵循导致(i_1 = 0)的变量i的界限来确定输入所需的间隔。我注意到了这些界限。这不是很强大,例如,如果断言变为&amp;&amp; n <= 13 ,&#39;左侧&#39;暗示谓词保持不变,没有任何条件改变。此外,我不确定这在其他场景中有多大用处,例如在调用函数时将我的断言更改为require语句,我无法理解结果谓词:

if (x < 15){
      sum(x);
}

在函数中添加一个require语句:

//@requires (n >= 6 && n <= 11);
int sum(int n){

我明白了:

    goal main_call_sum_pre:
  forall i : int.
  (6 <= i) ->
  (8 <= i) ->
  (i <= 12) ->
  is_sint32(i) ->
  is_sint32(1 + i) ->
  is_sint32(2 + i) ->
  ((4 <= i) and (i <= 9))

2 个答案:

答案 0 :(得分:3)

你是对的,基于“最弱前提条件”范式的WP(或Jessie)是在这里使用的正确工具。然而,他们所做的是建立暗示:

规范给出的前提条件==&gt;计算最弱的前提条件

外部证明者然后尝试证明上述含义,(在一般情况下)仅提供真/假/超时答案。

您可以通过反复试验,使用“LOWER_BOUND≤x≤UPPER_BOUND”作为user_input(*)的后置条件,并查看暗示是否得到证实。使用你作为黑盒子的工具,你可以通过几分之二到达间隔。你永远不会知道你是否有最佳间隔,或者证明者是否已经不能证明一个仍然存在的财产,但这就是生命。

或者你可以让证明者为你做简化工作,但这需要一种更复杂的交互,而不仅仅是“这个属性是真的吗?”。有些证明文件可以让您更轻松地访问其他信息。在WP完成其工作之后,这一切都在证明者的手中,而且你的问题实际上是“一个证明将一个逻辑公式减少到x以使公式成立的证据”,而不是关于Frama-下进行。

这个study涉及到“在某些地方给你最好的间隔”的问题。它是关于浮点的,但由于浮点只是整数推理的难度,因此使用的工具和技术也可能适用于您的问题。特别是,“Gappa”证明者,其特点是浮点,本地间隔工作,IIRC是在该研究中提供必要的“最佳”间隔的证明者(第11页,“例如,我们是怎么做的在我们的说明性例子中确定界限1/16?“)

(*)请注意,在将调用添加到user_input()以澄清含义之后,您要查找的内容实际上是该函数的后置条件,而不是主函数的前置条件。

答案 1 :(得分:-1)

assert采用布尔表达式,如果FALSE,则使用消息中止应用程序。 assert通常是一个宏,在程序的非调试版本中,在预处理过程中会删除对这些宏的调用。

您的布尔表达式包含常量。如果用变量替换那些变量,那么就可以使用灵活的断言。