我如何找出可用堆栈的大小 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;
}