我如何找出可用堆栈的大小 space?
How do i find out the size of available stack space?
我们都知道栈是向下增长的,所以真的很直白的假设,如果我们找到last声明的变量的地址,我们会得到最小的地址在堆栈,所以我们可以假设这个地址将是我们剩余的可用堆栈。
我做到了,我得到了一个巨大的地址 {0x000000dc9354f540} = {947364623680}
我们知道堆栈向下增长并且我们知道我们不能低于 0。
所以有点数学:
947364623680 / (1024*1024*1024) = 882.302060425
--> 他们是否暗示我的机器上有 882Gb 的堆栈?!
我测试了一下,在堆栈上分配了额外的 2mb 之后,显然得到了堆栈溢出异常:
uint8 array[1024*1024*2] = {};
我的问题是 WTF 是什么,我怎样才能得到我的实际筹码量?
因为你的问题有一个标签 "visual-studio-debugging" 我假设你使用 windows.
首先你应该得到当前的堆栈指针。获取本地虚拟变量的地址(就像你现在所做的那样),或者通过原始 asm
读取 esp/rsp
,或者获取本地虚拟变量的地址(就像你现在所做的那样),或者获取 CPU 通过 Win32 注册 API 调用 GetThreadContext
).
现在,为了找出可用的堆栈大小,您可以使用 VirtualQuery
查看此虚拟内存区域的起始地址(也称为分配基地址)。基本上减去这些指针会给你剩余的堆栈大小(精度达到当前堆栈帧的大小)。
很久以前我写了一个article about this subject,包括查询当前allocated/reserved 堆栈大小。如果需要,您可以在那里找到更多信息:
Do they imply that i have 882Gb of stack on my machine?!
与"stack on your machine"无关。是关于虚拟地址space,与系统可用的物理存储(RAM+页面文件)无关
另一种获取 win32 应用程序中任何给定点剩余堆栈 space 的近似值的方法类似于以下函数。它使用结构化异常处理来捕获堆栈溢出异常。
注意:@valdo的方案是正确的方案。我发布这个答案是因为这是一种有趣的解决方法。它会非常慢,因为它的运行时间是线性的(就堆栈大小而言),而不是@valdo 解决方案的恒定运行时间。
static uint64_t GetAvailableStackSpace()
{
volatile uint8_t var;
volatile uint8_t* addr = &var;
volatile uint8_t sink;
auto filter = [](unsigned int code) -> int
{
return (code == EXCEPTION_STACK_OVERFLOW) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
};
__try
{
while (true)
{
addr = addr - 1024;
sink = *addr;
}
}
__except (filter(GetExceptionCode()))
{
return (&var - addr);
}
return 0;
}
这是@valdo 提到的VirtualQuery
技术的实现。
此函数 returns 堆栈可用的近似字节数。我在 Windows x64.
上测试了这个
static uint64_t GetAvailableStackSpace()
{
volatile uint8_t var;
MEMORY_BASIC_INFORMATION mbi;
auto virtualQuerySuccess = VirtualQuery((LPCVOID)&var, &mbi, sizeof(mbi));
if (!virtualQuerySuccess)
{
return 0;
}
return &var - mbi.AllocationBase;
}
我们都知道栈是向下增长的,所以真的很直白的假设,如果我们找到last声明的变量的地址,我们会得到最小的地址在堆栈,所以我们可以假设这个地址将是我们剩余的可用堆栈。
我做到了,我得到了一个巨大的地址 {0x000000dc9354f540} = {947364623680}
我们知道堆栈向下增长并且我们知道我们不能低于 0。
所以有点数学:
947364623680 / (1024*1024*1024) = 882.302060425
--> 他们是否暗示我的机器上有 882Gb 的堆栈?!
我测试了一下,在堆栈上分配了额外的 2mb 之后,显然得到了堆栈溢出异常:
uint8 array[1024*1024*2] = {};
我的问题是 WTF 是什么,我怎样才能得到我的实际筹码量?
因为你的问题有一个标签 "visual-studio-debugging" 我假设你使用 windows.
首先你应该得到当前的堆栈指针。获取本地虚拟变量的地址(就像你现在所做的那样),或者通过原始 asm
读取 esp/rsp
,或者获取本地虚拟变量的地址(就像你现在所做的那样),或者获取 CPU 通过 Win32 注册 API 调用 GetThreadContext
).
现在,为了找出可用的堆栈大小,您可以使用 VirtualQuery
查看此虚拟内存区域的起始地址(也称为分配基地址)。基本上减去这些指针会给你剩余的堆栈大小(精度达到当前堆栈帧的大小)。
很久以前我写了一个article about this subject,包括查询当前allocated/reserved 堆栈大小。如果需要,您可以在那里找到更多信息:
Do they imply that i have 882Gb of stack on my machine?!
与"stack on your machine"无关。是关于虚拟地址space,与系统可用的物理存储(RAM+页面文件)无关
另一种获取 win32 应用程序中任何给定点剩余堆栈 space 的近似值的方法类似于以下函数。它使用结构化异常处理来捕获堆栈溢出异常。
注意:@valdo的方案是正确的方案。我发布这个答案是因为这是一种有趣的解决方法。它会非常慢,因为它的运行时间是线性的(就堆栈大小而言),而不是@valdo 解决方案的恒定运行时间。
static uint64_t GetAvailableStackSpace()
{
volatile uint8_t var;
volatile uint8_t* addr = &var;
volatile uint8_t sink;
auto filter = [](unsigned int code) -> int
{
return (code == EXCEPTION_STACK_OVERFLOW) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
};
__try
{
while (true)
{
addr = addr - 1024;
sink = *addr;
}
}
__except (filter(GetExceptionCode()))
{
return (&var - addr);
}
return 0;
}
这是@valdo 提到的VirtualQuery
技术的实现。
此函数 returns 堆栈可用的近似字节数。我在 Windows x64.
static uint64_t GetAvailableStackSpace()
{
volatile uint8_t var;
MEMORY_BASIC_INFORMATION mbi;
auto virtualQuerySuccess = VirtualQuery((LPCVOID)&var, &mbi, sizeof(mbi));
if (!virtualQuerySuccess)
{
return 0;
}
return &var - mbi.AllocationBase;
}