c99 goto past initialization

A jump like that is indeed allowed by the standard, so this is not a bug in GCC. The standard lists this situation as a suggested warning in Annex I.

The only restriction imposed on jumps in C99 with regard to scope is that it is illegal to jump into scope of a variable of variably modified type, like a VLA

int main() {
  int n = 5;
  goto label; // <- ERROR: illegal jump
  int a[n];
label:;
}

In other words, it is not correct to say that "a jump is just a jump in C". Jumps are somewhat restricted when it comes to entering variable scope, albeit not as strictly as in C++. The situation you describe is not one of the restricted ones.


You can ask gcc to warn you when you jump over a variable definition by using -Wjump-misses-init and then you can use -Werror (or, more precisely, -Werror=jump-misses-init) to force the users to deal with it. This warning is included in -Wc++-compat so the gcc developers are aware that the code behaves differently in C versus C++.

You could also change the code slightly:

int func()
{
    char *p1 = malloc(...);
    if (p1 == NULL)
        goto err_exit_1;

    char *p2 = malloc(...);
    if (p2 == NULL)
        goto err_exit_2;

    ...

err_exit_2:
    free(p2);
err_exit_1:
    free(p1);

    return -1;
}

... and just keep pairing labels with initialized variables. You'll have the same problem with calling many other functions with unitialized variables, free just happens to be a more obvious one.


Hmm, it's not because the new standard allows for variable declarations anywhere that it's always a good idea to use it. In your case I would do like we did it in classic C.

int func()
{
char *p1 = NULL;    /* So we have a defined value */
char *p2 = NULL;

  p1 = malloc(...);
  if(!p1)
    goto err_exit;

  p2 = malloc(...);
  if(!p2)
    goto err_exit;

  ...

  err_exit:
    free(p2);
    free(p1);

  return -1;
}

Tags:

C

Goto

Gcc

C99