__builtin_unreachable()
does not generate any compile time warnings as far as I can see on GCC 7.3.0
Neither can I find anything in the docs that suggest that it would.
For example, the following example compiles without any warning:
#include <stdio.h>
int main(void) {
__builtin_unreachable();
puts("hello")
return 0;
}
with:
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -Wunreachable-code main.c
The only thing I think it does do, is to allow the compiler to do certain optimizations based on the fact that a certain line of code is never reached, and give undefined behaviour if you make a programming error and it ever does.
For example, executing the above example appears to exit normally, but does not print hello
as expected. Our assembly analysis then shows that the normal looking exit was just an UB coincidence.
The -fsanitize=unreachable
flag to GCC converts the __builtin_unreachable();
to an assertion which fails at runtime with:
<stdin>:1:17: runtime error: execution reached a __builtin_unreachable() call
That flag is broken in Ubuntu 16.04 though: ld: unrecognized option '--push-state--no-as-needed'
What does __builtin_unreachable()
do to the executable?
If we disassemble both the code with and without __builtin_unreachable
with:
objdump -S a.out
we see that the one without it calls 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)
while the one without does only:
int main(void) {
5fa: 55 push %rbp
5fb: 48 89 e5 mov %rsp,%rbp
5fe: 66 90 xchg %ax,%ax
and does not even return, so I think it is just an undefined behaviour coincidence that it did not just blow up.
Why isn't GCC able to determine if some code is unreachable?
I gather the following answers:
determining unreachable code automatically is too hard for GCC for some reason, which is why for years now -Wunreachable-code
does nothing: gcc does not warn for unreachable code
users may use inline assembly that implies unreachability, but GCC cannot determine that. This is mentioned on the GCC manual:
One such case is immediately following an asm statement that either never terminates, or one that transfers control elsewhere and never returns. In this example, without the __builtin_unreachable, GCC issues a warning that control reaches the end of a non-void function. It also generates code to return after the asm.
int f (int c, int v)
{
if (c)
{
return v;
}
else
{
asm("jmp error_handler");
__builtin_unreachable ();
}
}
Tested on GCC 7.3.0, Ubuntu 18.04.
-Wunreachable-code
option was removed in later versions of gcc (because it was highly unpredictable under different optimization options) – Cassella