旧版 C/C++ 项目中的死代码检测



您将如何在C/C++代码中进行死代码检测?我有一个相当大的代码库可以使用,至少有 10-15% 是死代码。有没有基于Unix的工具可以识别这个区域?有些代码段仍然使用大量的预处理器,自动化过程可以处理吗?

为此,

您可以使用代码覆盖率分析工具,并在代码中查找未使用的位置。

gcc工具

链的一个流行工具是gcov,以及图形前端lcov(http://ltp.sourceforge.net/coverage/lcov.php)。

如果使用 gcc,则可以使用 gcov 支持进行编译,该支持由"--coverage"标志启用。接下来,使用此启用 gcov 的版本运行应用程序或运行测试套件。

基本上 gcc 会在编译过程中发出一些额外的文件,应用程序也会在运行时发出一些覆盖数据。您必须收集所有这些(.gcdo 和 .gcda 文件)。我在这里没有详细介绍,但您可能需要设置两个环境变量以理智的方式收集覆盖数据:GCOV_PREFIX 和 GCOV_PREFIX_STRIP...

运行后,您可以将所有覆盖率数据放在一起,并通过 lcov 工具套件运行它。合并来自不同测试运行的所有覆盖文件也是可能的,尽管有点复杂。

无论如何,你最终会得到一组很好的网页,显示一些覆盖率信息,指出没有覆盖率的代码片段,因此没有被使用。

当然,您需要仔细检查代码部分是否在任何情况下都没有使用,这在很大程度上取决于您的测试对代码库的执行程度。 但至少,这将给出一个关于可能的死代码候选者的想法......

在 gcc 下使用 -Wunreachable-code 编译它。

我认为版本越新,你会得到更好的结果,但我的印象可能是错误的,这是他们一直在积极努力的事情。请注意,这确实进行了流分析,但我不相信它会告诉您"代码"在离开预处理器时已经死亡,因为编译器永远不会解析它。它也不会检测到例如从未调用的导出函数,或者碰巧是不可能的特殊情况处理代码,因为没有任何东西使用该参数调用函数 - 您需要为此代码覆盖(并运行功能测试,而不是单元测试。单元测试应该具有 100% 的代码覆盖率,因此执行就应用程序而言"死"的代码路径)。尽管如此,考虑到这些限制,这是开始在代码库中查找最完整的 bollixed 例程的简单方法。

此 CERT 通报列出了一些用于静态死代码检测的其他工具

仅适用于 C 代码,并假设整个项目的源代码可用,使用开源工具 Frama-C 启动分析。在 GUI 中显示红色的程序的任何语句都是死代码。

如果你有"死代码"问题,你可能也对删除"备用代码",即已执行但未执行的代码为最终结果做出贡献。这需要您提供I/O 函数的准确建模(您不希望删除看似"备用"但用作printf 的参数)。Frama-C有一个用于指出备用代码的选项。

您的方法取决于可用性(自动)测试。如果您信任的测试套件可以涵盖足够数量的功能,则可以使用覆盖率分析,如前面的答案所示。

如果你不是那么幸运,你可能想看看源代码分析工具,比如SciTools的Understand,它可以帮助你使用大量内置的分析报告来分析你的代码。我对该工具的经验可以追溯到 2 年前,所以我不能给你太多细节,但我记得的是,他们得到了令人印象深刻的支持,错误修复和问题答案的周转时间非常快。

我找到了一个关于静态源代码分析的页面,其中还列出了许多其他工具。

如果这对你也没有足够的帮助,并且你特别有兴趣找出与预处理器相关的死代码,我建议你发布一些关于代码的更多详细信息。例如,如果它主要与 #ifdef 设置的各种组合相关,则可以编写脚本来确定(组合)设置并找出哪些组合从未实际构建过,等等。

Mozilla和Open Office都有本土解决方案。

> g++ 4.01 -Wunreachable-code 警告函数中无法访问的代码,但不警告未使用的函数。

int foo() { 
    return 21; // point a
}
int bar() {
  int a = 7;
  return a;
  a += 9;  // point b
  return a;
}
int main(int, char **) {
    return bar();
}

G++ 4.01 会发出关于 B 点的警告,但对 foo()(A 点)只字未提,即使它在此文件中无法访问。 这种行为是正确的,尽管令人失望,因为编译器无法知道函数 foo() 没有在其他编译单元中声明 extern 并从那里调用;只有链接器才能确定。

像这样的死代码分析需要对整个项目进行全局分析。您无法通过单独分析翻译单元来获取此信息(好吧,如果它们完全位于单个翻译单元中,您可以检测到死实体,但我认为这不是您真正想要的)。

我们使用 DMS 软件再造工具包为 Java 代码实现了这一点,通过一次解析所有涉及的编译单元,为所有内容构建符号表并追踪所有引用。没有引用且没有声明为外部 API 项的顶级定义已失效。这个工具还会自动去除死代码,最后你可以选择你想要的内容:死实体的报告,或者去掉这些实体的代码。

DMS 还解析各种方言中的C++(编辑 2014 年 2 月:包括 MS 和 GCC 版本的 C++14 [编辑 Nov 2017:现在 C++17]),并构建所有必要的符号表。从那时起,追踪死引用将很简单。DMS也可以用来剥离它们。请参阅 http://www.semanticdesigns.com/Products/DMS/DMSToolkit.html

Bullseye 覆盖工具会有所帮助。不过它不是免费的。

相关内容

  • 没有找到相关文章

最新更新