5

My GCC 7.3.0 and 8.2.0 has some strange behavior I can't explain. This program, which obviously ends in a Segmentation fault:

int main()
{
    double array[2]={0, 0};
    printf("%f\n", array[999]);

    return 0;
}

Compiled with

gcc -Wall -O2 main.c

Produces the warning

main.c: In function 'main':
main.c:6:5: warning: 'array[999]' is used uninitialized in this function [-Wuninitialized]
     printf("%f\n", array[999]);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~

But with optimization turned off:

gcc -Wall main.c

it produces no warning at all. My Code linter and Debug compile (gcc -g) uses -O0 and didn't pick up on a similar out of bounds error I made, until I compiled it as Release with Optimization turned on. Setting -O1 in the linter posts the warning as expected.

valiano
  • 16,433
  • 7
  • 64
  • 79
FrostKiwi
  • 741
  • 1
  • 6
  • 16
  • Does this happen with GCC 8.2? – tadman Aug 02 '18 at 17:27
  • Is it an error from you or does it really say 'array[100]' when you call 'array[999]'? – Benjamin Barrois Aug 02 '18 at 17:29
  • 2
    Will try out 8.2 now @BenjaminBarrois Changed from 100 to 999 to produce segfault for added drama. Didn't copy paste properly, now fixed. – FrostKiwi Aug 02 '18 at 17:30
  • 1
    I find this not chocking. With no optimization, the compiler keeps unaware of how is memory used in your program. It just sees pointers to memory addresses which do exist. When optimizing, it tries to optimize memory placement and sees more things. That's why sometimes in debug mode everything seems to work and when using release mode with O2, O3, you get segfaults. – Benjamin Barrois Aug 02 '18 at 17:39
  • 1
    Typical small gcc bug. Report it and forget about it – 0___________ Aug 02 '18 at 17:39
  • @P__J__ Guess you are right - will do. Same with 8.2.0 Benjamins explanation makes total sense. Guess will run my Linter with -O0 now ;] – FrostKiwi Aug 02 '18 at 17:43
  • FWIW, clang generates the warning regardless of optimization level, and even without `-Wall`. – user3386109 Aug 02 '18 at 17:43
  • I don't understand why would static analysis depend on optimization levels. These should be done independently... – Eugene Sh. Aug 02 '18 at 17:54
  • @EugeneSh. If you are doing both static analysis and optimization, sure, do them independently. Gcc is **not** a static analysis tool, it is an optimizing compiler (llvm is different and includes a static analyzer). If as a side effect of doing optimization it notices something worth warning about, it does it. But that's officially not its main goal. – Marc Glisse Aug 04 '18 at 20:20

1 Answers1

10

This is a long-standing, documented limitation in GCC. Quoting the manual for GCC 3.0:

-Wuninitialized

Warn if an automatic variable is used without first being initialized or if a variable may be clobbered by a setjmp call.

These warnings are possible only in optimizing compilation, because they require data flow information that is computed only when optimizing. If you don't specify -O, you simply won't get these warnings.

The current version of the manual has actually removed the second paragraph of this quotation, saying instead "Because these warnings depend on optimization, the exact variables or elements for which there are warnings depends on the precise optimization options and version of GCC used." This is because, at some point between GCC 3.0 (released 2001) and GCC 8.2 (released 2018) the compiler was improved so that it will give warnings for at least some uses of uninitialized variables when not optimizing. For instance, the trivial test

int foo(void) { int x; return x; }

does provoke a warning when compiled with GCC 8.2 using -O0 -Wall.

It is worth pointing out that perfect diagnosis of uninitialized variables reduces to the infamous Halting Problem—which means it can't be done. You can implement a set of rules that are conservatively correct (they will detect all uses of uninitialized variables, but they may claim that some variables are used uninitialized when they aren't), e.g. Java's definite assignment rules, but that approach has historically been unpopular among C programmers. Given a demand for minimal false positives but also quick compilation when not optimizing, GCC's approach of doing more elaborate analysis when optimization is on is understandable.

zwol
  • 135,547
  • 38
  • 252
  • 361
  • Thanks! This explains it perfectly! Unfortunately -Og doesn't pick it up and with -fsyntax-only, which the linter uses kills this warning. (I have read that -fsyntax-only is known to kill optimization related warnings) It is what it is - Guess I'll just avoid doing stuff like that in the first place and become a better programmer ;] – FrostKiwi Aug 03 '18 at 00:26