1

While writing some code for a code golf competition, I noticed some strange behavior. For example:

int main(void)
{
    goto jmp;
    char *str = "Hello, World!";
jmp:
    puts(str);
}

Compiling with GCC (and Clang and MSVC) results in no warnings or errors, but running it throws SIGSEGV. How come the compilers don't catch that the goto is jumping around the variable declaration?

I decided to test this (bug?) out, and rewrote the example:

int main(void)
{
    goto jmp;
    int x;
jmp:
    putchar(x);
}

Again, compilation yields no errors. Furthermore, nothing is thrown upon execution, yet in MSVC the process exits with a non-zero exit code.

What's going on here? Is this simply another reason we shouldn't use gotos? And how come no errors are thrown in the second example, while SIGSEGV is thrown in the first?

DEADBEEF
  • 525
  • 1
  • 5
  • 19
  • This is undefined behaviour. You've skipped over a variable declaration, and try to use it later. How does it make sense to even *attempt* to do this? What kind of result are you expecting? –  May 09 '17 at 03:18
  • 2
    That's not the compiler's job. – kaylum May 09 '17 at 03:22
  • 2
    @InternetAussie OP mentions he was code golfing. Maybe for [this](https://codegolf.stackexchange.com/q/23250/61563) challenge? – MD XF May 09 '17 at 03:22
  • @MDXF Perhaps, but undefined behaviour shouldn't be relied on for anything. Unless you know the details of how the particular compiler and implementation will handle it, undefined behaviour should just be avoided. –  May 09 '17 at 03:24
  • @InternetAussie True... However, UB could be perfectly utilized for that particular challenge. – MD XF May 09 '17 at 03:25
  • @MDXF S'pose so. –  May 09 '17 at 03:26
  • 3
    I compiled on ubuntu gcc 5.4.0 with flags `-Wall -Wextra -pedantic`. There was not an error, but there was a warning ` warning: ‘str’ is used uninitialized in this function [-Wuninitialized]`. – Paul Rooney May 09 '17 at 03:26
  • Because it's not an error in C. – user3528438 May 09 '17 at 03:32

1 Answers1

4

It's permitted to jump past initialization of a local variable, the effect will be that the variable is uninitialized.

Passing an uninitialized variable to puts is undefined behaviour, but not a constraint violation nor a syntax error. This means the C Standard does not require the compiler to give an error.

However, compilers are thoughtful and tend to supply various warning flags. In this case , gcc can warn about potential use of uninitialized variables. By using -Wall, or -Wuninitialized, you should see a warning. You can use -Werror or -Werror=uninitialized to get an error instead of a warning.

Some people advise to always compile in standard mode with warnings, e.g. -std=c11 -pedantic -Wall -Wextra.


Regarding "in MSVC the process exits with a non-zero exit code." , the MSVC compiler is only up to the C89 standard, in which falling off the end of main without returning a value, returns garbage. You should have return 0; at the end of main if needing to support ancient compilers like that.

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365