c - 如何用AST树或其他工具做静态代码逻辑分析?

标签 c compiler-construction abstract-syntax-tree cppcheck

void f1(char *s)
{
 s[20] = 0;
}
void f2()
{
 char a[10];
 if (x + y == 2) {
 f1(a);
 }
}

Cppcheck 将报告此消息: 数组 'a[10]' 索引 20 越界

Cppcheck 如何获得 f2 中的“a”和 f1 中的“s”之间的联系?

我构建了AST树,但是它只提供了每个符号的信息,并没有给我关于符号逻辑关系的信息。 计算机怎么知道 f2 中的“a”和 f1 中的“s”是同一个东西? 据我所知,我们必须考虑很多情况,例如:

void f1(char *s)
{
 char str_arry[30];
 s= str_arry;
 s[20] = 0;
}

在这种情况下,“s”和“a”不是一回事。

最佳答案

我不知道 Cppcheck 究竟是如何工作的,但我会告诉您如何解决这个问题。相关函数的分析主要有两种方法。

在第一种情况下,当分析器遇到函数调用时,它开始分析其主体,考虑通过函数传输的事实参数的值。只有知道哪些值被传输到函数时,这种情况才会自然发生。这指的是:一个精确值、一个范围、一组值、空/非空指针等。传输信息的复杂性取决于分析仪的复杂程度。例如,它可以开始分析函数体,知道两个传输的指针指向同一个数组。

这是一种非常准确的方法。但是有一个严重的问题。基于这个概念的分析器非常慢。他们必须一遍又一遍地分析具有不同输入数据集的函数体。这些函数依次调用其他函数,依此类推。并且在某些时候必须停止“内部”分析,这在实践中使这种方法不像理论上看起来那么准确和出色。

还有第二种方法。它基于自动功能注释。问题是,在分析函数时,会关注有关如何使用其参数以及它们不能采用哪些值的信息。让我们考虑一下我在名为“Technologies used in the PVS-Studio code analyzer for finding bugs and potential vulnerabilities”的文章中给出的简单示例'.

int Div(int X)
{
  return 10 / X;
}
void Foo()
{
  for (int i = 0; i < 5; ++i)
    Div(i);
}

分析器识别出 X 变量在 Div 函数中用作分隔符。以此为基础,自动创建了一个特殊的Div函数注解。然后它考虑到 [0..4] 值范围作为 X 参数传输到函数这一事实。分析器得出结论,应该出现被零除。

这种方法更粗糙,不如第一种方法准确。但它速度非常快,可以在不影响生产力的情况下在大量功能之间建立强关联。

在实践中可能要复杂得多。例如,PVS-Studio 分析器使用第二种方法作为主要方法,但并非总是如此。有时在处理模板函数时,我们会再次分析它们(第一种方法)。换句话说,我们使用组合方法来保持分析深度和速度之间的平衡。

关于c - 如何用AST树或其他工具做静态代码逻辑分析?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57067538/

相关文章:

c - 中止陷阱 : 6 on Mac when trying to run program with quicksort

compiler-construction - 是否可以为所有当前显卡编译 OpenCL 代码?

java - 从注释中获取值(value)

python - 如何使用 antlr 为 Python 源代码生成 AST(抽象语法树)

c - Mex 文件点积

c - 函数声明中显式 "extern"关键字的含义/意义是什么?

c# - 为我的应用程序重新分发和使用 CS.exe 编译器 (C#)

compiler-construction - LL(1) 是哪些当代计算机语言?

python - 用于 XPATH 查询的 AST

c - 删除一个字符的字符串匹配