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;
}