Forwarding this message to the linaro toolchain list instead.  I am not the 
person who should be supporting the Linaro ODP project with GCC questiosn; the 
toolchain team inside Linaro should be instead.

Thanks,
Andrew Pinski

________________________________________
From: Ola Liljedahl <ola.liljed...@linaro.org>
Sent: Monday, November 24, 2014 2:31 PM
To: lng-...@lists.linaro.org; Pinski, Andrew
Subject: strange behavior in GCC for use of uninitialized variables

Consider the following code fragment (from real life):

#include <stdint.h>

typedef volatile uint32_t odp_atomic_u32_t;

static inline uint32_t odp_atomic_fetch_inc_u32(odp_atomic_u32_t *ptr)
{
        return __sync_fetch_and_add(ptr, 1);
}

static inline void odp_spin(void)
{
#ifdef __SSE2__
        __asm__ __volatile__ ("pause");
#else
        __asm__ __volatile__ ("rep; nop");
#endif
}

typedef struct {
        int count;
        odp_atomic_u32_t bar;
} odp_barrier_t;

void odp_barrier_wait(odp_barrier_t *barrier)
{
        uint32_t count;
        int wasless;

//     wasless = barrier->bar < barrier->count;  <<<lost on git add -p
       __atomic_thread_fence(__ATOMIC_SEQ_CST);
        count   = odp_atomic_fetch_inc_u32(&barrier->bar);

        if (count == 2*barrier->count-1) {
                barrier->bar = 0;
        } else {
                while ((barrier->bar < barrier->count) == wasless)
                        odp_spin();
        }

        __atomic_thread_fence(__ATOMIC_SEQ_CST);
}

While fixing and cleaning up this code, the indicated line that
initializes 'wasless' was dropped (because it reappears in a later
patch in the patch set after the odp_atomic_fetch_inc call). To my
surprise, GCC did not complain when compiling this file (using -O2
-Wall). But it does complain when compiling with -O0 -Wall. With some
investigation, it seems like GCC understands that if a statement does
not have any side effects so it can optimize away everything,
including the usage of the uninitialized variable and thus also the
corresponding warning.

olli@macmini:~/hacking/gcc-wunit$ gcc -O2 -Wall -c odp_barrier.c
olli@macmini:~/hacking/gcc-wunit$ gcc -O0 -Wall -c odp_barrier.c
odp_barrier.c: In function ‘odp_barrier_wait’:
odp_barrier.c:42:9: warning: ‘wasless’ may be used uninitialized in
this function [-Wmaybe-uninitialized]
   while ((barrier->bar < barrier->count) == wasless)
         ^

However the proper code seems to be generated in both cases (there is
a "pause" instruction inlined or a call to odp_spin). So odp_spin() is
not without side effects and is not optimized away. This contradicts
my hypothesis.

Consider this minimalistic example:
olli@macmini:~/hacking/gcc-wunit$ cat wunit.c
#include <stdlib.h>

void test(void)
{
        int wasless;
        int wasmore;

        if (wasless) (void)0;
        if (wasmore) abort();
}

olli@macmini:~/hacking/gcc-wunit$ gcc -O0 -Wall -c wunit.c
wunit.c: In function ‘test’:
wunit.c:9:5: warning: ‘wasmore’ is used uninitialized in this function
[-Wuninitialized]
  if (wasmore) abort();
     ^
olli@macmini:~/hacking/gcc-wunit$ gcc -O2 -Wall -c wunit.c
wunit.c: In function ‘test’:
wunit.c:9:5: warning: ‘wasmore’ is used uninitialized in this function
[-Wuninitialized]
  if (wasmore) abort();
     ^

Here GCC warns when used with both -O0 and -O2 but only for the usage
where there is a side effect. The use of 'wasless' that does not lead
to any side-effects is ignored (and possibly rightly so, I can imagine
this is undefined behavior, fortunately I did not attempt to run this
program or my computer could have melted).

It is a bit worrying to me that instances of use of initialized
variables is sometimes missed by GCC. Both because of lack of
diagnostics for what is most likely a bug but also because I don't
understand why GCC does this and the implications of that (at least it
is a known unknown now).

-- Ola

_______________________________________________
linaro-toolchain mailing list
linaro-toolchain@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/linaro-toolchain

Reply via email to