In the code below why is b[9]
uninitialized instead of out-of-bounds?
#include <stdio.h> int main(void) { char b[] = {'N', 'i', 'c', 'e', ' ', 'y', 'o', 'u', '!'}; printf("b[9] = %d\n", b[9]); return 0; }
Compiler call:
% gcc -O2 -W -Wall -pedantic -c foo.c foo.c: In function ‘main’: foo.c:6:5: warning: ‘b[9]’ is used uninitialized in this function [-Wuninitialized] printf("b[9] = %d\n", b[9]); % gcc --version gcc (Ubuntu 5.4.0-6ubuntu1~16.04.6) 5.4.0 20160609 Copyright (C) 2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Update: Now this is odd:
#include <stdio.h> void foo(char *); int main(void) { char b[] = {'N', 'i', 'c', 'e', ' ', 'y', 'o', 'u', '!'}; foo(&b[9]); foo(&b[10]); printf("b[9] = %d\n", b[9]); printf("b[10] = %d\n", b[10]); return 0; }
Compiling this results in the warnings one would expect:
% gcc -O2 -W -Wall -pedantic -c foo.c foo.c: In function ‘main’: foo.c:9:5: warning: array subscript is above array bounds [-Warray-bounds] foo(&b[10]); ^ foo.c:10:29: warning: array subscript is above array bounds [-Warray-bounds] printf("b[9] = %d\n", b[9]); ^ foo.c:11:29: warning: array subscript is above array bounds [-Warray-bounds] printf("b[10] = %d\n", b[10]);
Suddenly gcc sees the out-of-bounds for what it is.
An uninitialized variable has an undefined value, often corresponding to the data that was already in the particular memory location that the variable is using. This can lead to errors that are very hard to detect since the variable's value is effectively random, different values cause different errors or none at all.
In C, variables with static storage duration that are not initialized explicitly are initialized to zero (or null, for pointers).
I believe this could be the case here: in the first code, GCC notices that you don't need the entire char array at all, just b[9]
, so it can replace the code with
char b_9; // = ??? printf("b[9] = %d\n", b_9);
Now, this is a completely legal transform, because as the array was accessed out of bounds, the behaviour is completely undefined. Only in latter phase does it then notice that this variable, which is a substitute for b[9]
, is uninitialized, and issues the diagnostics message.
Why I believe this? Because if I add just any code that will reference the array's address in memory, for example printf("%p\n", &b[8]);
anywhere, the array now is fully realized in memory, and compiler will diagnose array subscript is above array bounds.
What I find even more interesting is that GCC does not diagnose out-of-bounds access at all unless optimizations are enabled. This would again suggest that whenever you're writing a program new program you should compile it with optimizations enabled to make the bugs highly visible instead of keeping them hidden with debug mode ;)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With