gpt4 book ai didi

c++ - 分配过大的堆栈结构是未定义的行为吗?

转载 作者:IT老高 更新时间:2023-10-28 13:01:30 25 4
gpt4 key购买 nike

这是一个 C 规范问题。

我们都知道这是合法的 C 并且应该可以在任何平台上正常工作:

/* Stupid way to count the length of a number */
int count_len(int val) {
char buf[256];
return sprintf(buf, "%d", val);
}

但这几乎肯定会崩溃:

/* Stupid way to count the length of a number */
int count_len(int val) {
char buf[256000000];
return sprintf(buf, "%d", val);
}

不同之处在于后一个程序会破坏堆栈并且可能会崩溃。但是,纯粹从语义上来说,它确实与之前的程序没有任何不同。

根据 C 规范,后一个程序实际上是未定义的行为吗?如果是这样,它与前者有什么区别?如果不是,C 规范中的什么规定可以让符合要求的实现崩溃?

(如果这在 C89/C99/C11/C++* 之间有所不同,这也会很有趣)。

最佳答案

C(899911)的语言标准以具有此措辞的范围部分开头(在某些 C++、C#、Fortran 和 Pascal 标准中也有发现):

本国际标准未规定

  • 程序及其数据的大小或复杂性将超过任何特定数据处理系统的容量或特定处理器的容量;
  • 能够支持合规实现的数据处理系统的所有最低要求。

gcc 编译器确实提供了 an option to check for stack overflow at runtime

21.1 堆栈溢出检查

For most operating systems, gcc does not perform stack overflow checking by default. This means that if the main environment task or some other task exceeds the available stack space, then unpredictable behavior will occur. Most native systems offer some level of protection by adding a guard page at the end of each task stack. This mechanism is usually not enough for dealing properly with stack overflow situations because a large local variable could “jump” above the guard page. Furthermore, when the guard page is hit, there may not be any space left on the stack for executing the exception propagation code. Enabling stack checking avoids such situations. To activate stack checking, compile all units with the gcc option -fstack-check. For example:

gcc -c -fstack-check package1.adb

Units compiled with this option will generate extra instructions to check that any use of the stack (for procedure calls or for declaring local variables in declare blocks) does not exceed the available stack space. If the space is exceeded, then a Storage_Error exception is raised.

在 C99 到 make a stronger statement within the standard 的标准化过程中进行了尝试虽然规模和复杂性超出了标准的范围,但实现者有责任记录限制。

理由是

The definition of conformance has always been a problem with the C Standard, being described by one author as "not even rubber teeth, more like rubber gums". Though there are improvements in C9X compared with C89, many of the issues still remain.

This paper proposes changes which, while not perfect, hopefully improve the situation.

建议将以下措辞纳入第 5.2.4.1 节

  • 如果程序或其数据的大小或复杂性超过了实现的容量,则翻译或执行可能会失败。
  • 实现应记录确定正确程序的规模或复杂性是否超过或可能超过实现能力的方法。

    5.2.4.1. An implementation is always free to state that a given program is too large or too complex to be translated or executed. However, to stop this being a way to claim conformance while providing no useful facilities whatsoever, the implementer must show provide a way to determine whether a program is likely to exceed the limits. The method need not be perfect, so long as it errs on the side of caution. One way to do this would be to have a formula which converted values such as the number of variables into, say, the amount of memory the compiler would need. Similarly, if there is a limit on stack space, the formula need only show how to determine the stack requirements for each function call (assuming this is the only place the stack is allocated) and need not work through every possible execution path (which would be impossible in the face of recursion). The compiler could even have a mode which output a value for each function in the program.

提议的措辞并未纳入 C99 标准,因此该领域仍超出标准范围。 C99 第 5.2.4.1 节确实列出了这些限制

实现应能够翻译和执行至少一个程序,该程序包含以下每个限制的至少一个实例:

  • 127 个嵌套级别的 block
  • 63 个嵌套级别的条件包含
  • 12 个指针、数组和函数声明符(任意组合)修改声明中的算术、结构、 union 或不完整类型
  • 63 层括号内的声明符嵌套在一个完整的声明符中
  • 完整表达式中括号表达式的 63 层嵌套
  • 内部标识符或宏名称中的 63 个重要初始字符(每个通用字符名称或扩展源字符都被视为单个字符)
  • 外部标识符中的 31 个有效初始字符(每个指定短标识符为 0000FFFF 或更少的通用字符名称被视为 6 个字符,每个指定短标识符为 00010000 或更大的通用字符名称被视为 10 个字符,每个扩展源字符被视为与相应的通用字符名称相同的字符数(如果有)
  • 一个翻译单元中有 4095 个外部标识符
  • 在一个 block 中声明了 511 个 block 范围的标识符
  • 在一个预处理翻译单元中同时定义 4095 个宏标识符
  • 一个函数定义中包含 127 个参数
  • 一个函数调用中有 127 个参数
  • 一个宏定义中包含 127 个参数
  • 一次宏调用中包含 127 个参数
  • 逻辑源代码行中有 4095 个字符
  • 字符串文字或宽字符串文字中的 4095 个字符(连接后)
  • 对象中的 65535 字节(仅在托管环境中)
  • #included 文件的 15 个嵌套级别
  • 1023 个 switch 语句的 case 标签(不包括任何嵌套 switch 语句的标签)
  • 单个结构或 union 中的 1023 个成员
  • 单个枚举中的 1023 个枚举常量
  • 单个 struct-declaration-list 中的 63 级嵌套结构或 union 定义

关于c++ - 分配过大的堆栈结构是未定义的行为吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23141654/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com