Разрешение избыточной проверки нулевого указателя на границе доверия - PullRequest
6 голосов
/ 01 июля 2019

Недавно я просматривал код, в котором clang генерировал предупреждения из-за -Wtautological-pointer-compare.

Код можно упростить до чего-то вроде:

void foo(const char*s) __attribute__((nonnull)) {
   if (s) { /* Test added just in case*/
      if (s[0]=='a') s[0]='b'; /* Dummy code using the pointer */
   }
}

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

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

В Visual Studio с SAL кажется, что вы можете использовать _In_ _Pre_defensive_ для обработки этот случай.

В этом случае _In_ _Pre_defensive_ предпочтительнее в трасте границы, чтобы указать, что, хотя вызывающая сторона получит ошибку, если она Попытка передать NULL, тело функции будет проанализировано, как если бы параметр может быть НЕДЕЙСТВИТЕЛЕН, и любые попытки отменить ссылку на указатель без предварительной проверки его на NULL будет помечено.

Возможно ли нечто подобное с Clang?

1 Ответ

4 голосов
/ 01 июля 2019

Обратите внимание, что проблема хуже, чем просто увидеть нежелательное предупреждение.Поскольку функция имеет этот атрибут, компилятор удалит if, как будто вы написали:

if (true)

, потому что вы обещали, что указатель не будет NULL.Так что ваша нулевая проверка не имеет никакого эффекта.См .:

https://godbolt.org/z/l8w4x1

int func(void* ptr) __attribute__((nonnull))
{
    if (ptr)
        return 1;
    return 0;
}

Безоговорочно возвращается 1:

mov eax, 1
ret

Так что вы должны серьезно отнестись к этому предупреждению.

Я не понимаюНе знаю ни одного обходного пути для этого, кроме компиляции с -fno-delete-null-pointer-checks для предотвращения оптимизации проверок нулевого указателя и -Wno-tautological-pointer-compare для отключения предупреждения.Вы не хотите использовать эти флаги глобально, очевидно.Поэтому вам следует объединить функции с этим атрибутом в их собственный исходный файл и использовать эти флаги только при компиляции этого файла.

...