__builtin_unreachable()
GCC 7.3.0で確認できる限り、コンパイル時の警告は生成されません。
また、ドキュメントでそうなることを示唆するものを見つけることもできません。
たとえば、次の例は警告なしでコンパイルされます。
#include <stdio.h>
int main(void) {
__builtin_unreachable();
puts("hello")
return 0;
}
と:
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -Wunreachable-code main.c
私が思うに、それが行う唯一のことは、コードの特定の行に到達しないという事実に基づいてコンパイラが特定の最適化を実行できるようにし、プログラミングエラーが発生した場合に未定義の動作を与えることです。
たとえば、上記の例を実行すると、正常に終了したように見えますがhello
、期待どおりに出力されません。次に、アセンブリ分析は、通常の外観の出口が単なるUBの一致であったことを示しています。
-fsanitize=unreachable
GCCへのフラグ__builtin_unreachable();
は、実行時に次のように失敗するアサーションに変換します。
<stdin>:1:17: runtime error: execution reached a __builtin_unreachable() call
ただし、そのフラグはUbuntu 16.04では壊れています。ld:認識されないオプション'--push-state--no-as-needed'
実行可能ファイルは__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 7.3.0、Ubuntu18.04でテスト済み。