跳转到转到VLA阵列时的分段错误

Nuc*_*ear 4 c++ gcc variable-length-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;
        }
}
Run Code Online (Sandbox Code Playgroud)

最初,"剩余"变量的初始化有点长,我曾经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
$1 = 0xfffffffffffffe00 <error: Cannot access memory at address 0xfffffffffffffe00>
Run Code Online (Sandbox Code Playgroud)

我的gcc版本:

gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
Run Code Online (Sandbox Code Playgroud)

编译:

g++ -o testc test.cpp
Run Code Online (Sandbox Code Playgroud)

如果我删除goto,或用固定数组替换可变参数数组,分段错误就消失了.实际上发生了什么?

这是一个gcc bug吗?如果goto不允许组合和变量数组,那么应该有警告吗?

Sha*_*our 5

可变长度数组(VLA)是gcc支持的C99功能,作为C++中的扩展,在C99中,跳转到VLA声明是未定义的行为,来自草案C99标准部分6.8.6.1 goto语句:

goto语句不应从具有可变修改类型的标识符范围之外跳转到该标识符的范围内.

clanggcc 4.9实际上使这样的错误,并说:

error: goto into protected scope
    goto loop;
    ^

note: jump bypasses initialization of variable length array
            unsigned char tmp[remaining];
                          ^
Run Code Online (Sandbox Code Playgroud)

请参阅gcc错误报告:跳转到VLA或VM范围,不会拒绝C++.

跳过C++中自动变量声明的规则在6.7 [stmt.dcl]部分中有所说明:

可以转换为块,但不能以初始化绕过声明的方式.从具有自动存储持续时间的变量不在范围内的点跳转到其在范围内的点的程序是不正确的,除非该变量具有标量类型,具有普通默认构造函数的类类型和普通的析构函数,这些类型之一的cv限定版本,或者前面类型之一的数组,并且在没有初始值设定项的情况下声明(8.5).[例如:

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
}
Run Code Online (Sandbox Code Playgroud)

- 末端的例子]