代码之家  ›  专栏  ›  技术社区  ›  Matt Joiner

如何向GCC提示一行在编译时不可访问?

  •  13
  • Matt Joiner  · 技术社区  · 14 年前

    编译器提供 switch to warn when code is unreachable . 我也见过一些库的宏,它们提供 assertions for unreachable code .

    有没有一个提示,比如通过pragma或内置的,我可以传递给GCC(或任何其他编译器)的,在编译过程中,如果确定一个预期不可访问的行实际上可以访问,它会发出警告或出错?

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

    它的价值在于,在预期的不可到达行之上的条件发生变化之后,检测该行实际上是可到达的。

    4 回复  |  直到 6 年前
        1
  •  18
  •   Hasturkun    14 年前

    gcc 4.5支持 __builtin_unreachable() 编译器内联,将此与 -Wunreachable-code

        2
  •  6
  •   Moritz Rathgeber    7 年前

    使用gcc 4.4.0 Windows交叉编译器到PowerPC,使用-O2或-O3编译,我可以使用以下工具:

    #define unreachable asm("unreachable\n")

    如果编译器没有对其进行优化,因为它得出了不可访问的结论,那么汇编程序将失败,并执行未知操作。

    是的,它很可能是“在不同的优化选项下高度不可预测的”,当我最终更新编译器时,它可能会崩溃,但目前它比什么都没有要好。

        3
  •  6
  •   Ciro Santilli OurBigBook.com    6 年前

    __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
    

    我唯一认为 do,就是允许编译器基于某行代码永远达不到这一事实来进行某些优化,如果你犯了一个编程错误,它就会给出未定义的行为。

    例如,执行上述示例似乎正常退出,但不打印 hello 一如预期。我们的组装分析表明,正常的出口只是一个巧合。

    -fsanitize=unreachable 将标志转换为GCC __builtin_unreachable(); 对于在运行时失败的断言:

    <stdin>:1:17: runtime error: execution reached a __builtin_unreachable() call
    

    在Ubuntu 16.04中,这个标志被破坏了: ld: unrecognized option '--push-state--no-as-needed'

    是什么 __内置的不可访问() 你对可执行文件做了什么?

    如果我们同时反汇编代码 __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 :

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

    在GCC 7.3.0和Ubuntu 18.04上测试。

        4
  •  2
  •   Pascal Cuoq    14 年前

    assert ,并将其用于在特定执行点处应为真的属性提示。如果没有针对不可访问语句的特定注释,则可以使用 assert (false); .

    我个人并不熟悉他们,但Klokwork和CodeSonar是两个著名的分析仪。戈安娜是第三个。