分配了多少内存给调用堆栈?
以前我见过很多C++函数的汇编。在gcc中,它们都以这些指令开头:
push rbp
mov rbp, rsp
sub rsp, <X> ; <X> is size of frame
我知道这些指令存储前一个函数的帧指针,然后为当前函数设置一个帧。但在这里,程序集既不要求映射内存(如 malloc),也不检查 rbp 指向的内存是否分配给进程。
因此它假设启动代码已经为调用堆栈的整个深度映射了足够的内存。那么到底为调用堆栈分配了多少内存呢?启动代码如何知道调用栈的最大深度?
这也意味着,我可以远距离访问越界数组,因为虽然它不在当前帧中,但它映射到进程。所以我写了这段代码:
int main() {
int arr[3] = {};
printf("%d", arr[900]);
}
当索引为 900 时,这是以 SIGSEGV
退出。但令人惊讶的是,当索引为 901 时,它不会。同样,对于某些随机索引,它以 SIGSEGV
退出不适合某些人。在 编译器浏览器。
Previously I had seen assembly of many functions in C++. In gcc, all of them start with these instructions:
push rbp
mov rbp, rsp
sub rsp, <X> ; <X> is size of frame
I know that these instructions store the frame pointer of previous function and then sets up a frame for current function. But here, assembly is neither asking for mapping memory (like malloc) and nor it is checking weather the memory pointed by rbp
is allocated to the process.
So it assumes that startup code has mapped enough memory for the entire depth of call stack. So exactly how much memory is allocated for call stack? How does startup code can know the maximum depth of call stack?
It also means that, I can access array out of bound for a long distance since although it is not in current frame, it mapped to the process. So I wrote this code:
int main() {
int arr[3] = {};
printf("%d", arr[900]);
}
This is exiting with SIGSEGV
when index is 900. But surprisingly not when index is 901. Similarly, it is exiting with SIGSEGV
for some random indices and not for some. This behavior was observed when compiled with gcc-x86-64-11.2 in compiler explorer.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
事实并非如此。
在大多数常见的实现中,堆栈的大小是恒定的。
如果程序超出了常量大小的堆栈,则称为堆栈溢出。这就是为什么您必须避免在自动存储中创建大型对象(通常是但不一定是数组),以及为什么必须避免具有线性深度的递归(例如递归链表算法)。
在大多数桌面/服务器系统上,它是可配置的,并且默认为一到几兆字节。在嵌入式系统上它可能要少得多。
在这两种情况下,程序的行为都是未定义的。
是的。您可以阅读目标系统的文档。如果您打算编写可移植程序,那么您必须假设所有目标系统的最小值。对于桌面/服务器,我提到的 1 MB 是合理的。
C++ 中没有获取大小的标准方法。
It doesn't.
In most common implementation, the size of the stack is constant.
If the program exceeds the constant sized stack, that is called a stack overflow. This is why you must avoid creating large objects (which are typically, but not necessarily, arrays) in automatic storage, and why you must avoid recursion with linear depth (such as recursive linked list algorithms).
On most desktop/server systems it's configurable, and defaults to one to few megabytes. It can be much less on embedded systems.
In both cases, the behaviour of the program is undefined.
Yes. You can read the documentation of the target system. If you intend to write a portable program, then you must assume the minimum of all target systems. For desktop/server, 1 megabyte that I mentioned is reasonable.
There is no standard way to acquire the size within C++.