Reputation: 6984
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
)?
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
l * sizeof c
bytes at c
are initializedDoes 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
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
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
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