Scoping rules for struct variables in GCC

238 views Asked by At

Consider the following C program

#include <stdio.h>

typedef struct s {
  int x;
} s_t;

int main() {
  int x;
  s_t a;

  scanf("%d", &x);

  if (x > 0) {
    s_t a;
    a.x = x;
  }

  printf("%d\n", a.x);
}

The a struct variable in the if branch clearly shadows the a struct variable in main. One would expect that the output in printf would be undefined, but with GCC the scoped variable seems to equal the main variable.

For example

gcc test.c -o test
echo 10 | ./test

will output 10.

On the other hand, running this through clang, does as expected

clang test.c -o test
echo 10 | ./test

outputs -2145248048.

Is this a GCC bug or is there some sort of undefined behaviour that this is triggering?

gcc 4.8.2 clang 3.4

4

There are 4 answers

3
Soheil Hassas Yeganeh On BEST ANSWER

As others mentioned, you're reading an uninitialized local variable and that's undefined. So, anything is legit. Having said that, there is a particular reason for this behavior: gcc reuses variables on the stack as much as it can (i.e., as long as the generated code is provably correct). You can fine-tune using the -fstack-reuse option.

To disable stack reuse:

gcc test.c -o test -fstack-reuse=none
echo 10 | ./test
4195808 # prints some random number.

To enable stack reuse for all variables:

gcc test.c -o test -fstack-reuse=all  #, or -fstack-reuse=named_vars
echo 10 | ./test
10 # prints 10, as it reuses the space on the stack.

This is fully documented on GCC Code Generation Options.

1
M.M On

One would expect that the output in printf would be undefined

It is undefined. Undefined behaviour means that anything can happen, including (but not limited to) any particular output.

In this case what's likely happening is that the compiler optimizes both a to have the same address.

0
haccks On

Is this a GCC bug or is there some sort of undefined behavior that this is triggering?

It's undefined behavior. s_t a; in the if statement hides the previous declaration of a.
In the block

if (x > 0) {
    s_t a;
    a.x = x;
}  

x is assigned to the local a.x. After this block, a is no longer available and in printf you are accessing an uninitialized variable. Uninitialized variables may invoke UB.

0
ouah On

No compiler bug, your program invokes undefined behavior.

You are reading an uninitialized automatic object and C says it has indeterminate value and that reading it is undefined behavior.

Give a.x (the one declared in main scope) a value to give your program a specified behavior.