通过静态分析检测缺少 if/else 语句

发布于 2024-10-17 17:01:39 字数 843 浏览 7 评论 0原文

我试图捕获 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
}

我正在尝试通过静态分析和使用源代码的抽象语法树来查找此类漏洞。有没有任何算法、方法或任何论文研究这样的问题?

I'm trying to catch missing unhandled conditions of expressiong inside if statements.

First Example

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

Second Example

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

this two examples are correct and all possibilities are handled.

But I'm trying to cathc the conditions like

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
}

But this condition does not handle all possibilities and there is a missing condition of

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

I'm trying to find these kind of vulnerability by static analysis and using Abstract Syntax Tree of source codes. Is there any algorithm, approach or any paper which is studied on problem like that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

阪姬 2024-10-24 17:01:39

如果您有类似的代码

if(A) { ... }
else if (B) { ... }
else if (C) { ... }

并且希望确保处理所有可能性,那么您必须证明公式 A 或 B 或 C 的计算结果始终为 true。如果您所做的只是检查范围,那么我会将此公式转换为联合范式

经过此转换后,您将得到以下形式的公式

(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 是常量。这些命题可以通过使用以下转换进行组合:

  1. (x < c1)(x > c2) 一起转换为 true 如果(c1 > c2)
  2. (x < c1)(x ≥ c2) 一起转换为 true if (c1 ≥ c2)
  3. (x ≤ c1)(x > c2) 一起转换为 true if (c1 ≥ c2)
  4. (x ≤ c1)(x ≥ c2) 一起转换为 true if (c1 ≥ c2)

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

如果所有子句都有效,则处理所有可能性。

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

If you have code like

if(A) { ... }
else if (B) { ... }
else if (C) { ... }

and you want to make sure that all possibilities are handled, then you have to prove that the formula A or B or C always evaluates to true. If all you do is check for ranges, then I would transform this formula to a conjunctive normal form.

After this transformation you have a formula of the form

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

where each atomic proposition is of the form (x < c), (x ≤ c), (x > c) or (x ≥ c), where x is a variable and c is a constant. These propositions can be combined by using the following transformations:

  1. (x < c1) together with (x > c2) transforms to true if (c1 > c2)
  2. (x < c1) together with (x ≥ c2) transforms to true if (c1 ≥ c2)
  3. (x ≤ c1) together with (x > c2) transforms to true if (c1 ≥ c2)
  4. (x ≤ c1) together with (x ≥ c2) transforms to true if (c1 ≥ c2)

Now look at the clause (F1 or F2 or ...). As soon as you are able to perform one of these transformations, then the entire clause is valid, and you can begin checking the next clause.

If all clauses are valid, then all possibilities are handled.

A generic solution (where the conditions in the if statements can be anything) is not as trivial. For instance, if you want to check if(f(x) || g(x)), it is possible that f() or g() have side effects, or perform very complex calculations.

醉生梦死 2024-10-24 17:01:39

如果您希望将问题简化为更普遍的问题,可以将代码转换


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)) {,断言得到验证。

If you wish to reduce your problem to a more general problem, you can transform the code


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
}

into:


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 ; */
}

A reasonable compiler would emit the same code for the transformed version as for the original version, and now you can use static analysis or test generation to verify that the assert holds, which is the same as verifying that the last else is never taken, which is exactly the property you are interested in.

Tools exist if the above code is Java (the assert can be a JML annotation), C (the assert can be an ACSL annotation), or C# (the assert can be a Spec# annotation). Elian Ebbing's algorithm is fine, but the alternative I suggest it to let the automated theorem provers used as back-end for these tools do the job without re-implementing the wheel that determines if a given logical proposition is a tautology. Chances are that the existing wheels are doing a better job than you'll ever be able to get.

Example in C, using Frama-C and 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 ; */
  } 
}

The assertion is not verified, indicating that Jessie wasn't able to verify that the last case was unreachable. Adding } else if ((a >= 5) && (b <= 10)) {, the assertion is verified.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文