ensc
ensc

Reputation: 6984

clang-analyze: how to avoid "garbage value" warning?

When checking

#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;
}

with clang, I get

$ 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)

Is there really a chance that c contains garbage at this point? If not, how can I avoid the warning (without the obvious initialization of c)?

Update

Because it seems to be common consensus, that this is a false positive, I want to focus on the way how to avoid the warning.

It is true that fread() is a standard function and analyzers should know their semantics as they are doing e.g. for memset() already. But I am interested in a more generic way which can be used e.g. on library functions.

I would call some special function (let call it assert_defined()) in a way like

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

which is

Does clang know annotations like

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

or are there tricks like the related

int i = i;

which prevents gcc to emit "uninitialized warnings"?

Upvotes: 9

Views: 2387

Answers (3)

calamari
calamari

Reputation: 337

This worked for me. It's a very broad stroke as it ignores ANY problem, not just the false positive, so it's not ideal, but better than wasting cycles on unnecessary initialization. This expression is simple enough, but if there was something more complex it should probably be broken up to focus the hand-holding.

#ifndef __clang_analyzer__
    return c[0] == 42;
#else
    return 0;
#endif

Could also do something like this (although it goes against the wishes of the question):

#ifndef __clang_analyzer__
    char    c[20];
#else
    char    c[20] = {0};
#endif

Upvotes: 0

Clifford
Clifford

Reputation: 93446

Yes it could contain garbage - if fread() fails.

For the analyser to understand that the check guarantees c[0] is not read if fread fails would require the analyser to understand the semantics of the fread() function. That's computationally expensive task for any non-trivial code, and would require either sight of the library source, or encoding of the standard library semantics - which is possible but would only spot a small subset of issues involving "known functions".

Initialising the array will avoid this specific issue:

char c[20] = {0} ;

Upvotes: 2

machine_1
machine_1

Reputation: 4454

I would say that the compiler is not supposed to know the working of the function fread(). From the perspective of the compiler, fread() may or may not modify 'c'.

So if you do not explicitly initialize your variable in your specific case, the compiler has no option but to emit a warning.

Upvotes: 0

Related Questions