Как намекнуть GCC, что строка должна быть недоступна во время компиляции? - PullRequest
13 голосов
/ 01 августа 2010

Обычно компиляторы предоставляют переключатель для предупреждения, когда код недоступен . Я также видел макросы для некоторых библиотек, которые предоставляют утверждения для недоступного кода .

Есть ли подсказка, например, через прагму или встроенную функцию, которую я могу передать GCC (или любым другим компиляторам в этом отношении), которая будет предупреждать или сообщать об ошибке во время компиляции, если будет определено, что строка ожидает быть недоступным на самом деле может быть достигнут?

Вот пример:

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

Значение этого заключается в обнаружении, после изменения условий выше ожидаемой недоступной линии, что линия фактически достижима.

Ответы [ 4 ]

14 голосов
/ 01 августа 2010

gcc 4.5 поддерживает встроенный компилятор __builtin_unreachable(), объединяя его с -Wunreachable-code, возможно, то, что вы хотите, но, вероятно, вызовет ложные предупреждения

2 голосов

__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.

2 голосов
/ 22 января 2018

С кросс-компилятором Windows gcc 4.4.0 для PowerPC, компилируемым с -O2 или -O3, у меня работает следующее:

#define unreachable asm("unreachable\n")

Сбой ассемблера с неизвестной операцией, если компилятор не оптимизирует егопотому что он пришел к выводу, что он недоступен.

Да, вполне вероятно, что он «крайне непредсказуем при разных вариантах оптимизации» и может сломаться, когда я наконец обновлю компилятор, но на данный момент это лучше, чем ничего.

2 голосов
/ 01 августа 2010

Если у вашего компилятора нет предупреждения, которое вам нужно, его можно дополнить статическим анализатором. Тип анализатора, о котором я говорю, будет иметь свой собственный язык аннотаций и / или распознавать C assert, и использовать их для подсказок свойств, которые должны быть истинными в определенных точках выполнения. Если для недостижимых операторов нет конкретной аннотации, возможно, вы могли бы использовать assert (false);.

Я лично не знаком с ними, но Klokwork и CodeSonar - два известных анализатора. Гоанна - третий.

...