Last week I had to use an hour to debug an intermittent issue in my program that
ended up being a simple, accidental use of uninitialized memory (rr
made the
debugging session much faster; go try it).
Many compilers have basic static analysis features to detect such bugs, and
throw a warning. gcc
is such a compiler, and these warnings (turned on with
-Wuninitialized
, which is a part of -Wall
) are incredibly useful. And if
this worked properly, I wouldn't have had to spend that hour debugging. The
minimized program looks like this:
void f(void); double g(void) { f(); struct S { double x[2]; double y; } s; for(int i=0; i<2; i++) s.x[i] = 2.0; return s.y; }
I have an object of type struct S
. I initialize some parts of it (s.x
), but
not others (s.y
). Then I return the uninitialized s.y
. I'm unambiguously
returning an uninitialized value, but when I build this with gcc 7.1.0, no
warning is produced:
$ gcc-7 -Wall -Wextra -o /dev/null -c tst.c [ no warning ]
One could argue that this isn't a bug, but rather a missing feature: maybe gcc
simply isn't sophisticated enough to analyze this properly. This isn't true,
however: I can get the warning if I either remove the f()
call or unroll the
for()
loop. With the latter:
void f(void); double g(void) { f(); struct S { double x[2]; double y; } s; s.x[0] = 2.0; s.x[1] = 2.0; return s.y; }
produces
$ gcc-7 -Wall -Wextra -o /dev/null -c tst.c tst.c: In function 'g': tst.c:16:13: warning: 's.y' is used uninitialized in this function [-Wuninitialized] return s.y; ~^~
Interestingly, a simpler test case was broken similarly in gcc 6, but works in gcc 7:
void f(void); double g(void) { f(); double a[6]; return a[0]; }
As before, this produces the warning correctly if the f()
call is removed.
Finally, it looks like clang
, for whatever reason, fails to produce the
warning in all of these cases. I tried out the pre-release clang
5.0, and all
of these are too complicated for it to handle here.
The gcc bug report: