【问题标题】:Dead code detection in legacy C/C++ project [closed]遗留 C/C++ 项目中的死代码检测 [关闭]
【发布时间】:2010-09-18 17:57:40
【问题描述】:

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

【问题讨论】:

标签: c++ automation static-analysis legacy-code dead-code


【解决方案1】:

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

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

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

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

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

无论如何,您最终会得到一组漂亮的网页,其中显示了一些覆盖率信息,指出没有覆盖率因此未被使用的代码片段。

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

【讨论】:

  • 我仍然坚持使用 Sun C++ 编译器,但我们正在进行 gcc 迁移,所以我要试试这个。谢谢。
  • 代码覆盖率分析(例如gcov)可以提供软件的特定运行没有覆盖哪些代码的数据——没有覆盖的代码不一定是死代码。软件的不同运行(如不同的编译选项、不同的运行时选项或不同的输入数据)或不同的执行路径(如错误处理)可能会触发之前未调用的函数。
【解决方案2】:

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

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

This CERT advisory lists some other tools for static dead code detection

【讨论】:

  • 这个答案不再有效,因为 -Wunreachable-code 选项已从 gcc 中删除。 gcc.gnu.org/ml/gcc-help/2011-05/msg00360.html
  • 耻辱。出于许多目的,“不稳定”的死代码检测总比没有好。撇开别的不说,一般来说完美的死代码检测是不可能的(停机问题),所以每个人都知道他们使用的任何工具都是不完美的。大概有人真的关心-O0-O3 更不完美,或者在优化器改进时不想要新的警告。
  • 不过,如果您的代码没有使用新功能,您仍然可以使用旧的 gcc 作为静态分析工具。所以我的回答并没有完全错。有点影响力,我知道 ;-)
【解决方案3】:

您的方法取决于可用性(自动化)测试。如果您有一个您信任的测试套件可以涵盖足够多的功能,您可以使用覆盖率分析,正如之前的答案已经建议的那样。

如果你不是那么幸运,你可能想看看像SciTools'这样的源代码分析工具,了解它可以帮助你使用大量内置的分析报告来分析你的代码。我使用该工具的经验可以追溯到 2 年前,因此我无法为您提供太多细节,但我确实记得,他们得到了令人印象深刻的支持,以及非常快的错误修复和问题解答周转时间。

我在static source code analysis 上发现了一个页面,其中还列出了许多其他工具。

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

【讨论】:

    【解决方案4】:

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

    如果您有“死代码”问题,您可能还感兴趣 删除“备用代码”,即已执行但未执行的代码 为最终结果做出贡献。这需要您提供 I/O 函数的精确建模(你不会想要 删除看似“备用”的计算,但 用作printf 的参数)。 Frama-C 有一个选项可以指出多余的代码。

    【讨论】:

      【解决方案5】:

      MozillaOpen Office 都有自己的解决方案。

      【讨论】:

      • 这两个链接现在都无法访问。有人可以更新吗?
      • 我已将第一个链接从博客文章切换到(希望更持久)文档页面。 Open Office 链接似乎可以使用。
      【解决方案6】:

      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 并从那里调用;只有链接器才能确定。

      【讨论】:

        【解决方案7】:

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

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

        DMS 还解析各种方言中的 C++(2014 年 2 月编辑:including MS and GCC versions of C++14 [EDIT Nov 2017: now C++17])并构建所有必要的符号表。从那时起,追踪死引用就很简单了。 DMS 也可用于剥离它们。见http://www.semanticdesigns.com/Products/DMS/DMSToolkit.html

        【讨论】:

          【解决方案8】:

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

          【讨论】:

          • 值钱吗?有什么经验吗?他们有试用版,所以我可能会检查一下,如果有效,我们可以购买:)
          • 是的..我在塞班平台上用过...绝对值得购买
          猜你喜欢
          • 2011-01-23
          • 1970-01-01
          • 2011-05-19
          • 1970-01-01
          • 2010-09-09
          • 1970-01-01
          • 2010-12-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多