简体   繁体   English

为什么我可以转到alloca:d变量的范围,但不是可变长度数组?

[英]Why can I goto into the scope of a alloca:d variable, but not a variable length array?

See this test program: 看到这个测试程序:

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
  if (argc < 2)
    goto end;

  char s[strlen(argv[1]) + 1];
  strcpy(s, argv[1]);
  printf("s=%s\n", s);

end:
  return 0;
}

It fails to compile with the error "jump into scope of identifier with variably modified type" (see other question ). 它无法编译错误“跳转到具有可变修改类型的标识符范围”(参见其他问题 )。

However it compiles fine if I change the declaration of s into this (and include alloca.h ): 但是,如果我将s的声明更改为this(并包含alloca.h ),它编译得很好:

char *s = alloca(strlen(argv[1]) + 1);

Why does the C standard allow jumping into the scope of an object created with alloca , but not a variable length array? 为什么C标准允许跳入使用alloca创建的对象的范围,而不是可变长度数组? I thought they were equivalent. 我认为他们是等同的。

It is because the compiler must runtime-initialize the frame of the scope with VLAs. 这是因为编译器必须使用VLA运行时初始化作用域的帧。 In other words, you tell it to jump to address :END but you ask it to jump over the initialization code of the frame of that scope. 换句话说,你告诉它跳转到地址:END但你要求它跳过该范围框架的初始化代码。

The code for initializing the space for the VLA is just before the expression that computes the length of the VLA. 初始化VLA空间的代码就在计算VLA长度的表达式之前。 If you skip that code, which some goto can do, all the program will segfault. 如果你跳过那些goto可以做的代码,那么所有的程序都会出现段错误。

Imagine something like: 想象一下:

if (cond) goto end;
...
char a[expr];
end:
a[i] = 20;

In this case the code will simply segfault, as you jump to the mutator of VLA a but a was not initialized. 在这种情况下,代码将只是段错误,因为你跳转到VLA的变异器a但是没有初始化。 The code for initializing a VLA must be inserted in the place of the definition. 必须在定义的位置插入初始化VLA的代码。

Now about alloca . 现在关于alloca The compiler will do the same, but it is not able to detect a segfault. 编译器也会这样做,但它无法检测到段错误。

So this will segfault, with no warning/error from the part of the compiler. 所以这将是段错误,编译器部分没有警告/错误。

The logic is the same as for VLA. 逻辑与VLA相同。

int main(int argc, char *argv[])
{
    goto end;
    char *s = alloca(100);
end:
    s[1] = 2;
    return 0;
}

In ISO 9899 this is why they inserted the statement: 在ISO 9899中,这就是他们插入声明的原因:

6.8.6.1 The goto statement -- Constraints 6.8.6.1 goto语句 - 约束

1 The identifier in a goto statement shall name a label located somewhere in the enclosing function. 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. goto语句不应从具有可变修改类型的标识符范围之外跳转到该标识符的范围内。

The compiler cannot detect during the static analysis the correct answer for this problem, as this is actually the halting problem . 编译器在静态分析期间无法检测到此问题的正确答案,因为这实际上是halting problem

Besides the issue with deallocating the VLA if the program jumped after its declaration, there is also an issue with sizeof . 除了在声明之后程序跳出来解除分配VLA的问题之外, sizeof也存在问题。

Imagine your program was extended with this: 想象一下,你的程序扩展了这个:

end:
    printf("size of str: %zu\n", sizeof s);
    return 0;
}

For the alloca version, sizeof s == sizeof(char*) , which can be computed at compile-time and all is well. 对于alloca版本, sizeof s == sizeof(char*) ,可以在编译时计算,一切都很好。 However, for the VLA version, the length of s is unknown and sizeof s cannot be computed. 但是,对于VLA版本, s的长度未知,并且无法计算sizeof s

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM