【问题标题】:Finding "fallthroughs" in C code在 C 代码中查找“失败”
【发布时间】:2017-09-01 11:54:52
【问题描述】:

在我正在开发的产品中发现了几个令人讨厌的错误,所有这些错误都与 switch 语句中的无意“失败”有关。

现在,我想更进一步——我想检测大量 C 代码中的 switch 语句是否失效。 我只能使用 Linux 和 gcc 5.6 进行编译(所以没有 clang 或更新的 gcc;这是因为我们项目的目标架构不存在更新的 gcc)。

这是一个没有落空的代码:

    switch(m_loadAnimSubCt){
        case 0: 
        case 1: 
            // Do something
            break;
        case 2:
        case 3:
        case 4:
            // Do something
            break;
   }

这是一个失败的代码:

   switch(m_loadAnimSubCt){
        case 0: 
        case 1: 
            // Do something but fall through to the other cases 
            // after doing it.
        case 2:
        case 3:
        case 4:
            // Do something else.
            break;
   }

【问题讨论】:

  • 你应该研究一下statical analysislinter这两个术语。
  • 您的两个示例都有“失败”-案例0 失败到案例1。无论如何,如果您想检测此类事情,请编写一些代码来解析您的源文件,并在您想要的条件不满足时尖叫。 C 编译器通常不会诊断此类事情,因为代码是有效的 - 所以你自己编写代码来做。
  • 这很奇怪,我还没有找到任何涵盖此的静态分析工具。基本上自从它们被发明以来,它就一直是 C 语言的一部分。这就是为什么在预期会发生故障的情况下使用像 /*FALLTRHOUGH*/ 这样的 cmets 很常见的原因,因此 linter 可以检查这一点。这些天我主要使用clang-analyzer,没有检查它是否默认启用,但我确定它必须存在一个开关。
  • “静态”不是一个词。它只是“静态的”。
  • 您可以编写一个 GCC 插件(或 GCC MELT 扩展)来执行您想要的额外检查。

标签: c switch-statement static-analysis


【解决方案1】:

如果您使用的是 GCC,则应使用 Wimplicit-fallthrough compiler option 生成失败警告。您也可以使用 -Werror 将其变为错误(即 -Werror=implicit-fallthrough 用于此特定警告。

我更喜欢使用-Wextra(包括此警告和许多其他附加警告),但如果这是一些大型遗留代码库,它可能会产生太多噪音。 你应该努力的,通过-Wextra -Wpedantic -Werror 传递构建。

如果您的编译器版本不支持这样的选项,也许您可​​以编写自己的正则表达式来匹配所有 cases,而不是前面的 case 语句,尽管您必须小心确保regex 匹配所有匹配项,无论格式/cmets。

例如,您可以使用这样的东西(这里是demo):

(?# match any 'case' following 'break;', ':' or '{' into a non-capturing group)
(?# then match the remaining 'case' into a named "fallthrough" group)
(?:(break;|:|{)[\r\n\s]*case) | (?<fallthrough>case)

因此,您可以针对您的文件夹运行 perl(或 python 或其他)脚本并转储捕获“fallthrough”组的所有行。

【讨论】:

  • 很好,但 -Wimplicit-fallthrough 仅在最新版本的 GCC 中
  • @BasileStarynkevitch:你说得对,我注意到 OP 使用的是 gcc 5.4。我想一个正则表达式可能可以解决问题,我会在有空的时候更新答案。
  • 我升级了gcc,所以我会接受这个答案。
【解决方案2】:

我建议使用较新的编译器编译您的代码,以检测那些(我知道您提到您无法为项目执行此操作,但有时将其与其他东西一起编译以对事物有不同的看法很有用)。

我们在工作中拥有的是一个(可怕的)旧版本的 GCC,它编译我们的“官方”代码并 Clang 做一个虚拟编译,只是为了获得更好的静态分析。

【讨论】:

  • 这也是一个相当合理的建议,使用较新编译器的虚拟编译将用作外部 linter。
  • 我的目标架构不存在更新的 gcc。 5.6 是最新的。 @格鲁
  • @VividD 你不需要为你的目标架构进行编译,这就是重点,因为你只需要编译器提供的 linting 信息
猜你喜欢
  • 1970-01-01
  • 2016-11-15
  • 2015-12-30
  • 2011-01-22
  • 1970-01-01
  • 2011-07-24
  • 1970-01-01
  • 2022-01-25
  • 1970-01-01
相关资源
最近更新 更多