如何提示GCC在编译时无法访问一行?

时间:2010-08-01 09:54:32

标签: c gcc pragma built-in unreachable-code

编译器通常提供switch to warn when code is unreachable。我也看到了一些提供assertions for unreachable code的库的宏。

是否存在提示,例如通过编译指示或内置我可以传递给GCC(或任何其他编译器),如果确定预期的行,则会在编译期间发出警告或错误实际上是无法到达的吗?

以下是一个例子:

    if (!conf->devpath) {
        conf->devpath = arg;
        return 0;
    } // pass other opts into fuse
    else {
        return 1;
    }
    UNREACHABLE_LINE();

这个值的作用是在预期无法到达的行之上的条件发生变化后检测到该行实际上是可达的。

4 个答案:

答案 0 :(得分:14)

gcc 4.5支持内联__builtin_unreachable()编译器,将其与-Wunreachable-code组合可能会做你想要的,但可能会引起虚假警告

答案 1 :(得分:2)

如果您的编译器没有您需要的警告,可以使用静态分析器进行补充。我所讨论的分析器类型将有自己的注释语言和/或识别C assert,并将这些用于提示在执行的特定点应该为true的属性。如果没有无法访问的语句的特定注释,则可以使用assert (false);

我并不熟悉它们,但Klokwork和CodeSonar是两个着名的分析仪。 Goanna是第三个。

答案 2 :(得分:2)

就我在GCC 7.3.0上所见,

2不会生成任何编译时警告

我在文档中也找不到任何提示。

例如,以下示例在编译时没有任何警告:

__builtin_unreachable()

具有:

#include <stdio.h>

int main(void) {
    __builtin_unreachable();
    puts("hello")
    return 0;
}

我认为它唯一要做的是允许编译器根据从未达到特定代码行的事实进行某些优化,并且如果执行以下操作,则会给出未定义的行为:编程错误,而且确实如此。

例如,执行上面的示例似乎可以正常退出,但是没有按预期打印gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -Wunreachable-code main.c 。然后,我们的组装分析表明正常外观的出口只是UB巧合。

GCC的hello标志将-fsanitize=unreachable转换为一个断言,该断言在运行时会失败,并显示以下内容:

__builtin_unreachable();

该标志在Ubuntu 16.04中被打破:ld: unrecognized option '--push-state--no-as-needed'

<stdin>:1:17: runtime error: execution reached a __builtin_unreachable() call 对可执行文件有什么作用?

如果我们使用__builtin_unreachable()和不使用__builtin_unreachable来反汇编代码,则使用

objdump -S a.out

我们看到没有它的那个叫puts

000000000000063a <main>:
#include <stdio.h>

int main(void) {
 63a:   55                      push   %rbp
 63b:   48 89 e5                mov    %rsp,%rbp
    puts("hello");
 63e:   48 8d 3d 9f 00 00 00    lea    0x9f(%rip),%rdi        # 6e4 <_IO_stdin_used+0x4>
 645:   e8 c6 fe ff ff          callq  510 <puts@plt>
    return 0;
 64a:   b8 00 00 00 00          mov    $0x0,%eax
}
 64f:   5d                      pop    %rbp
 650:   c3                      retq
 651:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
 658:   00 00 00
 65b:   0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

而没有的人只会做:

int main(void) {
 5fa:   55                      push   %rbp
 5fb:   48 89 e5                mov    %rsp,%rbp
 5fe:   66 90                   xchg   %ax,%ax

甚至不返回,所以我认为这只是不确定的行为巧合,它并没有爆炸。

为什么GCC无法确定某些代码是否无法访问?

我收集了以下答案:

  • 对于GCC来说,出于某些原因,很难自动确定无法访问的代码,这就是为什么-Wunreachable-code多年来一直无所作为的原因:gcc does not warn for unreachable code

  • 用户可以使用暗示无法访问的内联汇编,但是GCC无法确定。提到了on the GCC manual

      

    一个这样的情况紧跟在一个asm语句之后,该语句要么永不终止,要么将控制权转移到其他地方而永不返回。在此示例中,在没有__builtin_unreachable的情况下,GCC发出警告,指出控件已到达非void函数的末尾。它还会生成代码以在汇编后返回。

    int f (int c, int v)
    {
      if (c)
        {
          return v;
        }
      else
        {
          asm("jmp error_handler");
          __builtin_unreachable ();
        }
    }
    

在GCC 7.3.0,Ubuntu 18.04上进行了测试。

答案 3 :(得分:1)

使用gcc 4.4.0 Windows交叉编译器进行PowerPC编译-O2或-O3以下内容适用于我:

#define unreachable asm("unreachable\n")

如果编译器没有对其进行优化,那么汇编程序会因未知操作而失败,因为它已经断定它无法访问。

是的,很可能在不同的优化选项下“高度不可预测”,并且在我最终更新编译器时可能会中断,但目前它没有任何好处。