问题
The following example demonstrates the issue:
#include <cstdio>
int main()
{
unsigned int remaining=1;
goto loop;
while(remaining) {
unsigned char tmp[remaining];
printf("&tmp: %p\n",tmp);
loop:
remaining = 512;//or something else;
}
}
Initially, the initialization of "remaining" variable was a bit long and I used goto
to initialize it on one line. However, now this example gives segmentation fault on the printf
line.
It looks like the array is not initialized properly.
Even gdb cannot print the tmp array's address:
Program received signal SIGSEGV, Segmentation fault.
0x00000000004005b8 in main () at test.cpp:11
11 printf("&tmp: %p\n",tmp);
(gdb) p tmp
$1 = 0xfffffffffffffe00 <error: Cannot access memory at address 0xfffffffffffffe00>
My gcc version:
gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
compiling with:
g++ -o testc test.cpp
If I remove the goto, or replace the variadic array with a fixed array, the segmentation fault is gone. What is happening actually?
Is this a gcc bug? If the combination of goto
and variadic arrays is not allowed, there should be a warning?
回答1:
Variable length arrays(VLA) are a C99 feature that gcc supports as an extension in C++ and in C99 a jump across a VLA declaration is undefined behavior, from the draft C99 standard section 6.8.6.1
The goto statement:
A goto statement shall not jump from outside the scope of an identifier having a variably modified type to inside the scope of that identifier.
clang
and gcc 4.9
actually makes this an error and says:
error: goto into protected scope
goto loop;
^
note: jump bypasses initialization of variable length array
unsigned char tmp[remaining];
^
See the gcc bug report: Jumps into VLA or VM scope not rejected for C++.
The rules for jumping past a declaration of an automatic variable in C++ is covered in section 6.7
[stmt.dcl] which says:
It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps87 from a point where a variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has scalar type, class type with a trivial default constructor and a trivial destructor, a cv-qualified version of one of these types, or an array of one of the preceding types and is declared without an initializer (8.5). [ Example:
void f() { // ... goto lx; // ill-formed: jump into scope of a ly: X a = 1; // ... lx: goto ly; // OK, jump implies destructor // call for a followed by construction // again immediately following label ly }
—end example ]
来源:https://stackoverflow.com/questions/29124145/segmentation-fault-when-jumping-to-goto-over-vla-array