跳转到 VLA 阵列上时出现分段错误
Segmentation fault when jumping to goto over VLA array
以下示例演示了该问题:
#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;
}
}
最初,"remaining"变量的初始化有点长,我用goto
一行初始化。但是,现在这个例子在 printf
行给出了分段错误。
数组似乎没有正确初始化。
即使 gdb 也无法打印 tmp 数组的地址:
Program received signal SIGSEGV, Segmentation fault.
0x00000000004005b8 in main () at test.cpp:11
11 printf("&tmp: %p\n",tmp);
(gdb) p tmp
= 0xfffffffffffffe00 <error: Cannot access memory at address 0xfffffffffffffe00>
我的 gcc 版本:
gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
编译:
g++ -o testc test.cpp
如果我删除 goto,或用固定数组替换可变数组,分段错误就会消失。
到底发生了什么?
这是 gcc 错误吗?如果不允许 goto
和可变数组的组合,应该有警告?
可变长度数组(VLA)是 gcc 支持的 C99 特性 an extension in C++ 并且在 C99 中,跨 VLA 声明的跳转是未定义的行为,来自草案C99标准部分6.8.6.1
goto语句:
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
和 gcc 4.9
实际上使这个错误并说:
error: goto into protected scope
goto loop;
^
note: jump bypasses initialization of variable length array
unsigned char tmp[remaining];
^
参见gcc bug report: Jumps into VLA or VM scope not rejected for C++。
在 C++ 中跳过自动变量声明的规则在 6.7
[stmt.dcl] 节中介绍:
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 ]
以下示例演示了该问题:
#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;
}
}
最初,"remaining"变量的初始化有点长,我用goto
一行初始化。但是,现在这个例子在 printf
行给出了分段错误。
数组似乎没有正确初始化。
即使 gdb 也无法打印 tmp 数组的地址:
Program received signal SIGSEGV, Segmentation fault.
0x00000000004005b8 in main () at test.cpp:11
11 printf("&tmp: %p\n",tmp);
(gdb) p tmp
= 0xfffffffffffffe00 <error: Cannot access memory at address 0xfffffffffffffe00>
我的 gcc 版本:
gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
编译:
g++ -o testc test.cpp
如果我删除 goto,或用固定数组替换可变数组,分段错误就会消失。 到底发生了什么?
这是 gcc 错误吗?如果不允许 goto
和可变数组的组合,应该有警告?
可变长度数组(VLA)是 gcc 支持的 C99 特性 an extension in C++ 并且在 C99 中,跨 VLA 声明的跳转是未定义的行为,来自草案C99标准部分6.8.6.1
goto语句:
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
和 gcc 4.9
实际上使这个错误并说:
error: goto into protected scope
goto loop;
^
note: jump bypasses initialization of variable length array
unsigned char tmp[remaining];
^
参见gcc bug report: Jumps into VLA or VM scope not rejected for C++。
在 C++ 中跳过自动变量声明的规则在 6.7
[stmt.dcl] 节中介绍:
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 ]