3

我正在尝试对 C 项目运行静态分析以识别死代码,即从未调用过的函数或代码行。我可以使用适用于 Windows 的 Visual Studio .Net 或使用适用于 Linux 的 gcc 来构建这个项目。我一直在尝试找到一些可以为我做到这一点的合理工具,但到目前为止我还没有成功。我已经阅读了有关 Stack Overflow 的相关问题,即thisthis,并且我尝试-Wunreachable-code与 gcc 一起使用,但 gcc 中的输出不是很有帮助。它具有以下格式

/home/adnan/my_socket.c: In function ‘my_sockNtoH32’: 
/home/adnan/my_socket.c:666: warning: will never be executed

但是当我查看第 666 行时my_socket.c,它实际上位于从函数 my_sockNtoH32() 调用的另一个函数中,并且不会针对此特定实例执行,但会在从其他一些函数调用时执行。

我需要的是找到永远不会执行的代码。有人可以帮忙吗?

PS:我无法说服管理层为这项任务购买工具,所以请坚持使用免费/开源工具。

4

3 回答 3

3

如果 GCC 不适合您,请尝试clang(或更准确地说,它的静态分析器)。它(通常,您的里程可能会有所不同)比 GCC 具有更好的静态分析(并产生更好的输出)。它在 Apple 的 Xcode 中使用,但它是开源的,可以单独使用。

于 2011-06-17T15:34:34.243 回答
1

当 GCC 说“将永远不会被执行”时,它意味着它。您可能有一个错误,实际上确实会生成死代码。例如,类似:

if (a = 42) {
    // some code
} else {
    // warning: unreachable code
}

当然,如果没有看到代码,就不可能具体。

请注意,如果第 666 行有一个宏,则 GCC 也可能引用了该宏的一部分。

于 2011-06-17T19:24:40.967 回答
1

GCC 将帮助您在编译中找到死代码。如果它可以跨多个编译单元找到死代码,我会感到惊讶。编译单元中函数或变量的文件级声明意味着其他编译单元可能会引用它。因此,在文件的顶层声明的任何内容,GCC 都无法消除,因为它可以说一次只能看到一个编译单元。

问题变得越来越难。假设编译单元 A 声明了函数 a,而编译单元 B 有一个函数 b 调用 a。是死人吗?从表面上看,没有。但实际上,这取决于;如果 b 已死,并且对 a 的唯一引用在 b 中,则 a 也已死。如果 b 只接受&a并将其放入数组 X 中,我们会遇到同样的问题。现在要确定 a 是否已死,我们需要对整个系统进行指向分析,以查看指向 a 的指针是否在任何地方使用。

要获得这种准确的“死”信息,您需要对整个编译单元集有一个全局视图,并且需要计算一个指向分析,然后基于该指向分析构建一个调用图. 仅当调用图(作为树,以 main 作为根)没有在某处引用它时,函数 a 才死。(一些警告是必要的:无论分析是什么,实际上它必须是保守的,因此即使是完整的分析点也可能无法正确地将函数识别为死函数。您还必须担心从外部使用 C 工件C 函数集,例如,从一些汇编代码调用 a)。

线程使情况变得更糟;每个线程都有一些根函数,它可能位于调用 DAG 的顶部。由于 C 编译器没有定义线程的启动方式,因此应该清楚地确定多线程 C 应用程序是否有死代码,必须以某种方式告诉线程根函数的分析,或者告诉如何通过寻找线程初始化原语。

关于如何获得正确答案,您没有得到很多回应。虽然它不是开源的,但我们的DMS 软件重组工具包及其C 前端具有执行此操作的所有机制,包括 C 解析器、控制和数据流分析、本地和全局点分析以及全局调用图构建. DMS 很容易定制以包含额外的信息,例如来自汇编程序的外部调用,和/或线程根列表或作为线程初始化调用的特定源模式,我们实际上已经(很容易)为一些大型嵌入式引擎控制器做到了这一点拥有数百万行代码。DMS 已被应用于多达 2600 万行代码(大约 18000 个编译单元)的系统,用于构建此类调用图。

[有趣的是:在处理单个编译单元时,出于缩放原因,DMS 实际上会删除该编译单元中未使用的符号和相关代码。值得注意的是,当您考虑到通常隐藏在包含文件嵌套中的冰山时,这消除了大约 95% 的代码量。它说 C 软件通常具有不良因素的包含文件。我想你们都已经知道了。]

像 GCC 这样的工具会在编译时删除死代码。这很有帮助,但死代码仍然存在于编译单元源代码中,占用了开发人员的注意力(他们也必须弄清楚它是否死了!)。可以配置 DMS 在其程序转换模式下,以一些预处理器问题为模,从源代码中实际删除该死代码。在非常大的软件系统上,您并不想手动执行此操作。

于 2011-07-06T07:45:51.190 回答