clang-analysis: как избежать предупреждения о «мусорной стоимости»? - PullRequest
7 голосов
/ 07 марта 2019

При проверке

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char    c[20];
    size_t  l;

    l = fread(c, sizeof c, 1, stdin);
    if (l != 1)
        return 1;

    return c[0] == 42;
}

с помощью clang я получаю

$ clang  --analyze -Xclang -analyzer-checker=alpha x.c
x.c:13:14: warning: The left operand of '==' is a garbage value
        return c[0] == 42;
               ~~~~ ^

$ clang -v
clang version 7.0.1 (Fedora 7.0.1-4.fc29)

Действительно ли существует вероятность того, что c содержит мусор в этот момент?Если нет, то как я могу избежать предупреждения (без явной инициализации c)?

Обновление

Поскольку, как представляется, существует общее мнение, что это ложное срабатывание, я хочусосредоточиться на том, как избежать предупреждения.

Это правда, что fread() является стандартной функцией, и анализаторы должны знать свою семантику так, как они это делают, например, для memset().Но меня интересует более общий способ, который можно использовать, например, в библиотечных функциях.

Я бы вызвал некоторую специальную функцию (пусть она будет вызываться assert_defined()) таким образом, как

    l = fread(c, sizeof c, 1, stdin);
    assert_defined(c, l * sizeof c);

который является

  • noop
  • , но позволяет компилятору / анализатору думать, что l * sizeof c байтов в c инициализированы

Знает ли лязганнотации типа

inline static void assert_defined(void const *p, size_t cnt) 
   __attribute__((__dear_compiler_this_memory_is_not_garbage__(1,2)))
{
}

или есть хитрости вроде

int i = i;

, которые не позволяют gcc выдавать «неинициализированные предупреждения»?

Ответы [ 2 ]

1 голос
/ 07 марта 2019

Да, это может содержать мусор - если fread() не удастся.

Чтобы анализатор понял, что проверка гарантирует, что c[0] не будет прочитан, в случае сбоя fread потребуется анализатор, чтобы понять семантику функции fread(). Это вычислительно дорогостоящая задача для любого нетривиального кода, и она потребует либо просмотра исходного кода библиотеки, либо кодирования стандартной семантики библиотеки - что возможно, но выявит лишь небольшое подмножество проблем, связанных с «известными функциями».

Инициализация массива позволит избежать этой конкретной проблемы:

char c[20] = {0} ;
0 голосов
/ 07 марта 2019

Я бы сказал, что компилятор не должен знать, как работает функция fread ().С точки зрения компилятора, fread () может или не может изменять 'c'.

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

...