我可以在 C/C++ 中获得堆栈的限制吗?

Posted

技术标签:

【中文标题】我可以在 C/C++ 中获得堆栈的限制吗?【英文标题】:Can I get the limits of the stack in C / C++? 【发布时间】:2015-04-26 19:24:54 【问题描述】:

我的问题非常简单明了:如果我有例如1MB RAM分配给程序的栈,我能得到开始和结束的地址,还是开始和长度的地址?

我正在使用 Visual Studio 2013。

【问题讨论】:

我认为它是特定于操作系统的,所以我帮不了你,但我对答案很感兴趣...... en.wikipedia.org/wiki/Win32_Thread_Information_Block 我猜你对剩下的空闲堆栈没什么兴趣,对吧? 没有便携方法可以做到这一点。 这里有一些很好的答案:***.com/questions/53827/… 【参考方案1】:

您应该质疑您对堆栈布局的假设。

也许the stack doesn't have just one top and bottom

也许it has no fixed bottom at all

显然没有可移植的方式来查询不可移植的概念。

不过,在 Visual C++ 中,您可以使用 Win32 API,具体取决于 Windows 版本。

在 Windows 8 上非常简单,只需拨打GetCurrentThreadStackLimits

早期版本需要使用VirtualQueryEx 并对结果进行一些处理。在堆栈中获取一个地址很容易,只需在局部变量上使用&。然后,您需要找到包含该地址的保留区域的限制。 Joe Duffy 写了a blog post showing the details of finding the bottom address of the stack

【讨论】:

正如Thread Stack Size 所说,default 初始和保留大小可以从 PE 标头中获得(它没有指定 哪个模块的 标头) . @ivan_pozdeev:这只是主线程的堆栈大小,虽然它也用作稍后创建的线程的默认值,但它们的大小是动态设置的。当然,它是可执行映像的 PE 头,与 GetModuleHandle(NULL) 匹配的那个。 您认为 Visual C++ == Win32 不会正确的假设 much longer @Damien_The_Unbeliever:该页面以“Visual C++”的名称快速播放。是的,Visual Studio 开发环境可能针对其他平台,甚至是其他平台上的 C++ 本机开发,但它是通过 Visual C++ 以外的编译器的工具链插件完成的,而不是通过将其他平台添加到 Visual C++ 工具链。使用 Windows Store API 会是一个更好的论据,它不是 Win32,而是使用 Visual C++ 工具链完成的。 @BenVoigt:PE 标头中指定的 默认 堆栈大小不会总是 应用于辅助线程。调用者决定在调用CreateThread()/_beginthread/ex()时。【参考方案2】:

GetCurrentThreadStackLimits 似乎在做你正在寻找的事情,将堆栈的下/上边界放入指针地址:

ULONG_PTR lowLimit;
ULONG_PTR highLimit;
GetCurrentThreadStackLimits(&lowLimit, &highLimit);

看起来它只在 Windows 8 和 Server 2012 上可用。

查看MSDN

【讨论】:

【参考方案3】:

在 8 之前的 Windows 上,自己实现 GetCurrentThreadStackLimits():

#include <windows.h>
#if _WIN32_WINNT < 0x0602
VOID WINAPI GetCurrentThreadStackLimits(LPVOID *StackLimit, LPVOID *StackBase)

    NT_TIB *tib = (NT_TIB *) NtCurrentTeb();
    *StackLimit = tib->StackLimit;
    *StackBase = tib->StackBase;

#endif

【讨论】:

来自我在回答中链接的 Joe Duffy 文章:不幸的是,StackLimit 仅在您实际触摸堆栈上的页面时才会更新,因此 这不是一种可靠的方式找出还有多少未提交的堆栈。 CLR 使用 kernel32!VirtualAlloc 提交页面,而不是通过实际移动保护页面,因此 StackLimit 不会像您预期的那样更新。 但是如果您阅读下面的 cmets在回答之前的问题,您就已经知道 TIB 不包含所需的信息。 @BenVoigt TIB 确实包含该信息。 GetCurrentThreadStackLimits 返回的“低”值是未记录的 DeallocationStack 字段,位于 FS:[0xE0C] (x86) / GS:[0x1478] (x64)。至少从 Windows 2000 开始。因此,可以在 Win8 之前的操作系统上使用未记录的字段,并在 Win8+ 上使用 GetCurrentThreadStackLimits。 @Alex:也许,但这个答案引用了StackLimit 字段,它给出了错误的结果。 @BenVoigt 那么,应该有人编辑答案吗?这是一个有效的答案(考虑到“修复”)——当然比公认的答案建议的更好(通过VirtualQuery 调用内核)。我没有足够的 MS C++ 经验来正确编写它。 @Alex:我仍然坚持我的回答......它在所有平台上都能正常工作,而将未记录的字段从 TIB 中拉出需要每个平台的代码。

以上是关于我可以在 C/C++ 中获得堆栈的限制吗?的主要内容,如果未能解决你的问题,请参考以下文章

堆栈内存有限制吗?

如何在 c / c++ 程序中检测可能/潜在的堆栈溢出问题?

C/C++ 程序的最大堆栈大小?

学习堆栈大小限制

缓冲区溢出是与程序堆栈相关的唯一可能的错误吗?

Python递归限制与堆栈大小?