【问题标题】:Can you "allocate" stack space with VirtualAlloc?你能用 VirtualAlloc“分配”堆栈空间吗?
【发布时间】:2014-06-25 03:11:13
【问题描述】:

我在搞乱VirtualAlloc 和动态代码生成,我对某些事情感到好奇。

VirtualAlloc的第一个参数指定要分配的地址范围的开始,或者更准确地说,包含该地址的页面指定页面范围的开始 被分配。对吧?

我开始怀疑。你能在堆栈上腾出一堆空间并用VirtualAlloc“分配”那个内存吗?例如,将其权限更改为PAGE_EXECUTE_READWRITE?

(作为上述的扩展,我很好奇堆栈在Windows进程中的确切位置。它是如何设置的?是什么设置的?)

tl;dr 你能用VirtualAlloc“分配”堆栈空间吗?

【问题讨论】:

    标签: winapi memory-management x86


    【解决方案1】:

    在创建线程时,堆栈空间由VirtualAllocMEM_RESERVE 标志(或者可能直接使用底层系统调用)分配。这会导致为该线程堆栈保留进程的地址空间。

    当堆栈增长超过实际提交的区域时,使用保护页面会导致访问冲突。操作系统通过提交额外的内存(如果有足够的保留空间)或在到达保留区域的边缘时向进程生成EXCEPTION_STACK_OVERFLOW 来自动处理这个问题。在第一种情况下,设置了一个新的保护页面。其次,如果您尝试处理该异常并恢复,则重新创建保护页是重要的一步。

    您可以使用VirtualAllocVirtualProtect 预先提交您的线程堆栈。但是它们不接触堆栈指针,因此它们不能用于堆栈分配(使用堆栈指针的代码很乐意重用“您的”分配给自动变量、函数参数等)。要从堆栈分配空间,您需要调整堆栈指针。大多数 C 和 C++ 编译器为此提供了 _alloca() 内部函数。

    如果您正在执行动态代码生成,请不要为此使用堆栈。不可执行堆栈是针对远程执行漏洞的宝贵保护。在这种特殊情况下,您当然可以使用VirtualAlloc 进行动态分配,而不是使用通用分配器HeapAllocmallocnew[]。通用分配器最终都从VirtualAlloc 中获取内存,但随后将其打包成不与页面边界对齐的块。

    【讨论】:

    • @Remy:我考虑过以这种方式构建它,但是(1)它使句子变得非常冗长和复杂,并且(2)它导致了(a || b && c) 歧义(编译器定义明确,令人困惑给读者)
    • A guard page 不会导致访问冲突,它会导致页面错误。有两个非常不同且截然不同的错误,这就是我最初编辑您的答案的原因。
    • @remy 页面错误是非常具体的事情,这意味着在 TLB 或通过 CR3 找到的页表中,页面根本不存在任何映射。您链接的保护页面文档没有提供有关如何实现的提示,方法是取消活动页表中的访问权限或完全删除 PTE。 (当然它仍然存在于操作系统数据结构中以及正确的访问标志)
    • 再仔细阅读文档:“如果程序试图访问保护页内的地址,系统会引发STATUS_GUARD_PAGE_VIOLATION (0x80000001) 异常。系统还会清除PAGE_GUARD 修饰符,移除内存页的保护页状态。系统不会停止下一次访问内存页的尝试,并出现STATUS_GUARD_PAGE_VIOLATION 异常。"
    • 页面错误,保护错误,to-ma-to,tom-a-to :) 你的回答声称这仍然不是访问冲突。
    猜你喜欢
    • 2012-12-26
    • 2015-05-02
    • 2011-02-11
    • 2012-07-19
    • 2015-08-13
    • 2015-12-17
    • 2016-12-14
    • 1970-01-01
    • 2011-08-04
    相关资源
    最近更新 更多