旧版C / C ++项目中的死代码检测[关闭]


68

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


2
:这里那里有更多的活动类似的问题stackoverflow.com/questions/4813947/...
鲨鱼先生

Answers:


30

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

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

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

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

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

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

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


我仍然坚持使用Sun C ++编译器,但是我们正在进行gcc迁移,因此我将尝试一下。谢谢。
纳兹哥布

代码覆盖率分析(例如gcov)可以提供该软件的特定运行未覆盖的代码数据-未覆盖的代码不一定是无效代码。软件的不同运行(例如不同的编译选项,不同的运行时选项或不同的输入数据)或不同的执行路径(例如错误处理)可能会触发一个之前未调用的功能。
阿伦(Arun)

17

使用-Wunreachable-code在gcc下进行编译。

我认为该版本越新,您可以获得的效果越好,但是我印象错了,因为他们一直在积极努力。请注意,这确实进行了流量分析,但是我不相信它会告诉您“代码”在离开预处理器时已经死掉的原因,因为编译器从未对其进行解析。它也不会检测到例如从未被调用的导出函数,或者由于没有人调用带有该参数的函数而恰好是不可能的特殊情况处理代码-您需要对此进行代码覆盖(并运行功能测试,而不是单元测试应该是单元测试具有100%的代码覆盖率,因此就应用程序而言,执行的代码路径“死”了。尽管如此,考虑到这些限制,这是一种开始在代码库中找到最完全复杂的例程的简单方法。

该CERT咨询列出了一些其他用于静态死代码检测的工具


3
对于从-gcc中删除-Wunreachable-code选项的事实,此答案不再有效。gcc.gnu.org/ml/gcc-help/2011-05/msg00360.html
philippe lhardy 2013年

耻辱。在许多方面,“不稳定”的死代码检测总比没有好。除了其他方面,通常不可能进行完美的死代码检测(停止问题),因此每个人都知道他们使用的任何工具都不完美。大概有人实际上在乎它的不完美-O0之处-O3,或者在优化器改进时不希望有新的警告。
史蒂夫·杰索普

3
尽管如此,如果您的代码不使用任何新功能,您仍然可以使用旧的gcc作为静态分析工具。所以我的回答并不完全错误。我知道有点可及;-)
史蒂夫·杰索普

4

您的方法取决于可用性(自动)测试。如果您有一个信任的测试套件可以覆盖足够多的功能,则可以使用覆盖率分析,如先前的建议一样。

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

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

如果那也不能给您足够的帮助,并且您特别想找出与预处理器相关的无效代码,那么我建议您发布一些有关该代码的更多详细信息。例如,如果它主要与#ifdef设置的各种组合有关,则可以编写脚本来确定设置的(组合),并找出实际上从未构建过的组合,等等。


4

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,而是从那里调用的;只有链接器可以确定。


4

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

如果您遇到“死代码”问题,您可能也有兴趣删除“备用代码”,这些代码已执行但对最终结果没有帮助。这就要求您提供I / O函数的准确建模(您不希望删除看似“备用”但用作的参数的计算printf)。Frama-C具有指出备用代码的选项。



3

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

我们使用了DMS软件再造工具包,通过一次解析所有涉及的编译单元,为所有内容构建符号表并跟踪所有引用来针对Java代码实现此功能。没有引用且没有声称是外部API项的顶级定义已失效。该工具还会自动剥离无效代码,最后您可以选择所需内容:无效实体的报告,或剥离了这些实体的代码。

DMS还解析各种方言中的C ++(2014年2月编辑:包括MS和GCC版本的C ++ 14 [EDIT 2017年11月:现在为C ++ 17]),并构建所有必要的符号表。从这一点开始,跟踪失效的引用将很容易。DMS也可用于将其剥离。参见http://www.semanticdesigns.com/Products/DMS/DMSToolkit.html


1

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


值得吗?有经验吗?他们有一个试用版,所以我可能会检查出来,如果它有效,我们可以购买:)
Nazgob

是的。我在Symbian平台上使用过……绝对值得购买
Ashwin,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.