Bug 86940

Summary: False positive with -Wuninitialized
Product: gcc Reporter: Aritz Erkiaga <aerkiaga6>
Component: middle-endAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED INVALID    
Severity: normal CC: msebor
Priority: P3 Keywords: diagnostic
Version: 8.2.0   
Target Milestone: ---   
Host: x86_64-pc-linux-gnu Target: x86_64-pc-linux-gnu
Build: x86_64-pc-linux-gnu Known to work:
Known to fail: 8.2.0 Last reconfirmed:
Attachments: Preprocessed source

Description Aritz Erkiaga 2018-08-13 21:26:54 UTC
Created attachment 44532 [details]
Preprocessed source

Compiling the code with the following command:
    gcc -v -save-temps -Wall -O test.c

Gives this output:

gcc -v -save-temps -Wall -O test.c
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-pc-linux-gnu/8.2.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../gcc-8.2.0/configure --enable-languages=c,c++
Thread model: posix
gcc version 8.2.0 (GCC) 
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-O' '-mtune=generic' '-march=x86-64'
 /usr/local/libexec/gcc/x86_64-pc-linux-gnu/8.2.0/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu test.c -mtune=generic -march=x86-64 -Wall -O -fpch-preprocess -o test.i
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/local/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../x86_64-pc-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/lib/gcc/x86_64-pc-linux-gnu/8.2.0/include
 /usr/local/include
 /usr/local/lib/gcc/x86_64-pc-linux-gnu/8.2.0/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-O' '-mtune=generic' '-march=x86-64'
 /usr/local/libexec/gcc/x86_64-pc-linux-gnu/8.2.0/cc1 -fpreprocessed test.i -quiet -dumpbase test.c -mtune=generic -march=x86-64 -auxbase test -O -Wall -version -o test.s
GNU C17 (GCC) version 8.2.0 (x86_64-pc-linux-gnu)
	compiled by GNU C version 8.2.0, GMP version 6.1.2, MPFR version 4.0.1, MPC version 1.1.0, isl version isl-0.19-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
GNU C17 (GCC) version 8.2.0 (x86_64-pc-linux-gnu)
	compiled by GNU C version 8.2.0, GMP version 6.1.2, MPFR version 4.0.1, MPC version 1.1.0, isl version isl-0.19-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 82490e2e2080530dcab0165c2e5082fa
test.c: In function ‘main’:
test.c:15:20: warning: ‘str’ may be used uninitialized in this function [-Wmaybe-uninitialized]
     if(initialize) free(str);
                    ^~~~~~~~~
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-O' '-mtune=generic' '-march=x86-64'
 /usr/local/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../x86_64-pc-linux-gnu/bin/as -v --64 -o test.o test.s
GNU assembler version 2.31.1 (x86_64-pc-linux-gnu) using BFD version (GNU Binutils) 2.31.1
COMPILER_PATH=/usr/local/libexec/gcc/x86_64-pc-linux-gnu/8.2.0/:/usr/local/libexec/gcc/x86_64-pc-linux-gnu/8.2.0/:/usr/local/libexec/gcc/x86_64-pc-linux-gnu/:/usr/local/lib/gcc/x86_64-pc-linux-gnu/8.2.0/:/usr/local/lib/gcc/x86_64-pc-linux-gnu/:/usr/local/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../x86_64-pc-linux-gnu/bin/
LIBRARY_PATH=/usr/local/lib/gcc/x86_64-pc-linux-gnu/8.2.0/:/usr/local/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../lib64/:/lib/x86_64-linux-gnu/:/lib/../lib64/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib64/:/usr/local/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../x86_64-pc-linux-gnu/lib/:/usr/local/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-O' '-mtune=generic' '-march=x86-64'
 /usr/local/libexec/gcc/x86_64-pc-linux-gnu/8.2.0/collect2 -plugin /usr/local/libexec/gcc/x86_64-pc-linux-gnu/8.2.0/liblto_plugin.so -plugin-opt=/usr/local/libexec/gcc/x86_64-pc-linux-gnu/8.2.0/lto-wrapper -plugin-opt=-fresolution=test.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o /usr/local/lib/gcc/x86_64-pc-linux-gnu/8.2.0/crtbegin.o -L/usr/local/lib/gcc/x86_64-pc-linux-gnu/8.2.0 -L/usr/local/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../lib64 -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib64 -L/usr/local/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../x86_64-pc-linux-gnu/lib -L/usr/local/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../.. test.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/local/lib/gcc/x86_64-pc-linux-gnu/8.2.0/crtend.o /usr/lib/x86_64-linux-gnu/crtn.o
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-O' '-mtune=generic' '-march=x86-64'


GCC complains that 'str' may be uninitialized, which is not possible.

Requirements for triggering the bug include compiling with -O1 or greater. Omitting this flag gives no warning. Also, no warning is produced if func() returns just a constant value.

It appears like GCC thinks that func() may have some side effects which change the value of initialize, which is not the case.

Also, while substituting the call to free() with another expression with str (e.g. puts(str) or printf("%p", str)) does not remove the warning, the call to malloc() turns out to be important. Replacing it with a constant value makes the warning dissapear, regardless of the expression used in place of free().
Comment 1 Andrew Pinski 2018-08-13 21:34:15 UTC
How does GCC know that rand does not change the global variable initialize? Or something else before main has changed it from 1 to 0?
Comment 2 Aritz Erkiaga 2018-08-13 21:45:22 UTC
I don't know. Somehow it does know it when the testcase is compiled without any -O flags, but it not something trivial, and so I would not be surprised if GCC were not able to get that information.
Comment 3 Andrew Pinski 2018-08-13 21:47:45 UTC
(In reply to Aritz Erkiaga from comment #2)
> I don't know. Somehow it does know it when the testcase is compiled without
> any -O flags, but it not something trivial, and so I would not be surprised
> if GCC were not able to get that information.

Because without any -O option (aka -O0) GCC does not enable any flow based uninitilization checking.
Comment 4 Aritz Erkiaga 2018-08-13 22:11:41 UTC
Ok, then this is not a bug. Maybe a feature request?

Well, actually I think it would be safe for the compiler to assume that libc (and possibly other external libraries) don't have access to variables defined in the source file being compiled. Of course, they could do whatever they like, but the possibility is not worth a warning, as I see it.
Comment 5 Martin Sebor 2018-08-14 02:28:56 UTC
(In reply to Aritz Erkiaga from comment #4)

GCC does have knowledge about many libc functions but rand() isn't one of them (yet).  It would be possible to add rand() to the list but it would only solve this one test case (i.e., involving rand()).  I don't think adding a built-in just to avoid a -Wuninitialized in this case is worth it.  There may be other reasons to add it, such as constraining its return value to [0, RAND_MAX].  If you can make a more compelling case for it there's a decent chance that it will be added.

Barring that, the test case reduces to:

$ cat pr86940.c && gcc -O2 -S -Wall pr86940.c
int f (void);

void g (void)
{
  void *p;
  if (f ())
    p = __builtin_malloc (8);

  if (f ()) 
    __builtin_free (p);
}
pr86940.c: In function ‘g’:
pr86940.c:10:5: warning: ‘p’ may be used uninitialized in this function [-Wmaybe-uninitialized]
     __builtin_free (p);
     ^~~~~~~~~~~~~~~~~~