缺少静态分析检测到/ else语句

时间:2011-02-17 08:19:23

标签: static-analysis conditional-statements if-statement abstract-syntax-tree

我正试图在if语句中捕获缺少未处理的expressiong条件。

第一个例子

if (a < 5) {
    // Do something
} else {
    // handled else condition
}

第二个例子

if (a < 5) {
    // Do something
} else if (a >= 5){
    // handled else if condition
}

这两个例子是正确的,所有可能性都得到了处理。

但我正试图让像

这样的条件成为现实
if ((a < 5) && b > 10) {
    // Do something
} else if ((a >= 5) && (b > 10)){
    // handled else condition
} else if((a < 5) && (b <= 10)) {
    // handled else condition
}

但是这种情况并没有处理所有可能性,并且缺少

的条件
} else if ((a >= 5) && (b <= 10)) {
   // missing condition which is not handled
}

我试图通过静态分析和使用源代码的抽象语法树来发现这种漏洞。是否存在任何算法,方法或任何研究类似问题的论文?

2 个答案:

答案 0 :(得分:3)

如果你有像

这样的代码
if(A) { ... }
else if (B) { ... }
else if (C) { ... }

并且您希望确保处理所有可能性,然后您必须证明公式A or B or C始终评估为true。如果您所做的只是检查范围,那么我会将此公式转换为conjunctive normal form

在此转换后,您有一个表格式

(F1 or F2 or ...) and (G1 or G2 or G3) and (H1 or H2 or H3) ...

其中每个原子命题的格式为(x < c)(x ≤ c)(x > c)(x ≥ c),其中x是变量,c是一个常数。这些命题可以通过使用以下转换进行组合:

    如果(x < c1) ,则
  1. (x > c2)true一起转换为(c1 > c2) 如果(x < c1)
  2. ,则
  3. (x ≥ c2)true一起转换为(c1 ≥ c2) 如果(x ≤ c1)
  4. ,则
  5. (x > c2)true一起转换为(c1 ≥ c2) 如果(x ≤ c1)
  6. ,则
  7. (x ≥ c2)true一起转换为(c1 ≥ c2)

    现在看看(F1 or F2 or ...)条款。只要您能够执行其中一个转换,那么整个子句就有效,您可以开始检查下一个子句。

    如果所有条款都有效,则处理所有可能性。

    通用解决方案(if语句中的条件可以是任何东西)并不是那么简单。例如,如果您想检查if(f(x) || g(x))f()g()可能会产生副作用,或执行非常复杂的计算。

答案 1 :(得分:3)

如果您希望将问题减少到更常见的问题,可以转换代码


if ((a < 5) && b > 10) {
    // Do something
} else if ((a >= 5) && (b > 10)){
    // handled else condition
} else if((a < 5) && (b <= 10)) {
    // handled else condition
}

成:


if ((a < 5) && b > 10) {
    // Do something
} else if ((a >= 5) && (b > 10)){
    // handled else condition
} else if((a < 5) && (b <= 10)) {
    // handled else condition
} else {
/*@ assert false ; */
}

合理的编译器会为转换后的版本发出与原始版本相同的代码,现在您可以使用静态分析或测试生成来验证assert是否成立,这与验证永远不会使用最后else,这正是您感兴趣的属性。

如果上面的代码是Java(断言可以是JML注释),C(断言可以是ACSL注释)或C#(断言可以是Spec#注释),则存在工具。 Elian Ebbing的算法很好,但我建议让自动化定理证明器用作这些工具的后端而不需要重新实现确定给定逻辑命题是否是重言式的轮子。有可能现有的车轮比你能够做得更好。

C中的示例,使用Frama-C和Jessie:

int a, b;

main(){
  if ((a < 5) && b > 10) {
    // Do something
  } else if ((a >= 5) && (b > 10)){
    // handled else condition
  } else if((a < 5) && (b <= 10)) {
    // handled else condition
  } else {
    /*@ assert \false ; */
  } 
}

断言未经验证,表明Jessie无法验证最后一个案例是否无法访问。添加} else if ((a >= 5) && (b <= 10)) {,验证断言。