__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 - без необходимости "
Что __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 не предупреждает о недоступном коде
пользователи могут использовать встроенную сборку, которая подразумевает недоступность, но GCC не может определить это. Это упомянуто в руководстве GCC :
Один такой случай следует сразу за оператором asm, который либо никогда не завершается, либо тот, который передает управление в другом месте и никогда не возвращается. В этом примере без __builtin_unreachable GCC выдает предупреждение о том, что элемент управления достигает конца не пустой функции. Он также генерирует код для возврата после asm.
int f (int c, int v)
{
if (c)
{
return v;
}
else
{
asm("jmp error_handler");
__builtin_unreachable ();
}
}
Протестировано на GCC 7.3.0, Ubuntu 18.04.