Option -Wuninitialized does not work as documented with volatile

Bug #1008090 reported by Zakhar on 2012-06-03
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
gcc-4.6 (Ubuntu)
Wishlist
Unassigned

Bug Description

Versions of Ubuntu and gcc:
-------------------------------------

(Precise amd64, out-of-the-box gcc)

$ LANG=ENG && uname -a && echo && gcc -v
Linux zakhar-desktop 3.2.0-24-generic #39-Ubuntu SMP Mon May 21 16:52:17 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.3-1ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)

WHAT HAPPENS:
--------------------

Consider the source code below:

/*01*/ int fct(volatile int *p);
/*02*/
/*03*/ int
/*04*/ foo( p )
/*05*/ volatile int *p;
/*06*/ {
/*07*/ volatile int foobar,barfoo;
/*08*/ volatile int flag=0;
/*09*/ volatile int *bar;
/*10*/
/*11*/ do
/*12*/ {
/*13*/ if ( *p )
/*14*/ {
/*15*/ flag= fct( p );
/*16*/ bar = p;
/*17*/ }
/*18*/ if ( fct( p ) ) break;
/*19*/ if ( flag )
/*20*/ {
/*21*/ barfoo = *bar;
/*22*/ if ( bar == (int *)0 ) break;
/*23*/ foobar = *bar;
/*24*/ return foobar + barfoo;
/*25*/ }
/*26*/ }
/*27*/ while ( fct( p ) );
/*28*/
/*29*/ return 0;
/*30*/ }

Compile it and you get:

$ gcc -O3 -c uninit.c -o /dev/null -Wall

uninit.c: In function 'foo':
uninit.c:23:27: warning: 'bar' may be used uninitialized in this function [-Wuninitialized]

WHAT SHOULD HAPPEN:
------------------------------

1) gcc makes a *VERY BAD* job at detecting uninitialized!
Per se, this is not a bug, because it is duly documented that in some situations, gcc cannot guess.
Here, simple logic proves that the detection is bad:
- you cannot reach lines 21-24 unless flag is not zero.
- flag is initialized to zero, and the only place it can take another value is line 15, where it gets the result of our external function.
- if we go to line 15, the next line in sequence would initialize 'bar'.
- thus when we go to lines 21-24 'bar' is definitely initialized.

Other strange things about this false detection:
- it warns on line 23, and not on lines 21 or 22 that already use the same variable BEFORE line 23!
- it stops warning if you remove line 18! This is odd, because line 18 only breaks out of the flow on certain condition, and as this is before we use the allegedly uninitialized variable, it can do no harm. One could argue that gcc can move line 18 up, but I hope it does not... as we don't know whether our external function has side effect (and no way I know in C to instruct the compiler it does not!), if it has side effects this would break the behaviour of the code as fct is already called on line 15, prior to line 18.

2) Apart from that bad detection of uninitialized, the behaviour is *NOT COMPLIANT with the documentation*.

If you look at the documentation page here:
http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

It says:
-Wuninitialized
    Warn if an automatic variable is used without first being initialized (...)

   (...)

   (...) They do not occur for *variables or elements declared volatile*.

As you see, in the code: 'bar' is an automatic variable, 'bar' has been declared volatile (and as demonstrated in 1: it *IS* initialized!), and gcc continues to spit out the warning.

CONCLUSION:
---------------

We do certainly have a bad detection of 'uninitialized'

Plus,
- either we have a bug in gcc that do not remove the warning in spite of the volatile qualifier
- either we have a bug in the documentation, and 'volatile' is irrelevant to that warning!.. but then gcc should provide a way so that the programmer can make the warning disappear when he does perfectly know un-initialization can't happen.

Matthias Klose (doko) wrote :

this is upstream behaviour. please report it upstream.

Changed in gcc-4.6 (Ubuntu):
importance: Undecided → Wishlist
status: New → Confirmed
Zakhar (alainb06) wrote :

My bad, you can mark this bug as Solved/Invalid.

The lines 3 to 9 should read:

/*03*/ extern int
/*04*/ foo( p )
/*05*/ int * volatile p;
/*06*/ {
/*07*/ volatile int foobar,barfoo;
/*08*/ volatile int flag=0;
/*09*/ int * volatile bar;

As I was reporting, the pointer was not volatile, it's location was, thus the warning that is correct.

Zakhar (alainb06) wrote :

I reopened 'upstream'.

There is indeed no 'bug', as when you mark the pointer volatile, the warning disappears.

But there is for sure either 'bad detection', or a detection of '*bar' that can indeed be un-initialized but is reported as 'bar' being un-initialized.

Thus it is not a 'bug' per se, as it conforms to the document that says that in some case, uninitialized warning can appear where it should not, but it is definitely a case where this can be improved.

So, not a 'bug' but an 'enhancement wish' with an example.

The link on gcc buzilla is: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54544

To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.