Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ Windows线程堆栈保护页机制在未初始化局部变量的情况下如何工作?_C++_Windows_Assembly_Callstack_Function Call - Fatal编程技术网

C++ Windows线程堆栈保护页机制在未初始化局部变量的情况下如何工作?

C++ Windows线程堆栈保护页机制在未初始化局部变量的情况下如何工作?,c++,windows,assembly,callstack,function-call,C++,Windows,Assembly,Callstack,Function Call,在Windows OS for x86-32/x86-64体系结构上,线程堆栈虚拟内存由“保留部分”、“提交部分”、“保护页”和“保留页”组成 问题: 假设我有1页的提交内存,以及1MB的线程堆栈保留内存。 我在堆栈上分配一些等于K个页面的内存,而不进行初始化。例如,K等于10。似乎在堆栈开始时,堆栈上的帧内存将由用户空间代码分配,如下所示: sub esp, K*4096 当存在对保护页的读写请求时,保护页机制工作 但是我将对一些超出此保护页的内存执行读/写操作,这将是什么呢?您通常会开始测

在Windows OS for x86-32/x86-64体系结构上,线程堆栈虚拟内存由“保留部分”、“提交部分”、“保护页”和“保留页”组成

问题:

假设我有1页的提交内存,以及1MB的线程堆栈保留内存。 我在堆栈上分配一些等于K个页面的内存,而不进行初始化。例如,K等于10。似乎在堆栈开始时,堆栈上的帧内存将由用户空间代码分配,如下所示:

sub esp, K*4096
当存在对保护页的读写请求时,保护页机制工作


但是我将对一些超出此保护页的内存执行读/写操作,这将是什么呢?

您通常会开始测试在启用运行时检查的情况下编译的代码,在调试配置中默认启用,它在函数序言中注入对_chkstk()的调用。GCC/g++已经实现了

它探测函数序言中分配的页面,每隔4096字节读取一次。这确保了当你出错时,你总是会点击防护页面,触发此站点的名称并帮助你修复错误


如果没有适当的检查,您可以从技术上解决根本不属于堆栈的页面。尽管它很可能触发处理器的#GP陷阱,但由于页面可能已被另一个不相关的分配映射,因此不能保证这一点。你一定很倒霉,事情已经过去了。基本UB,诊断起来非常糟糕,因为您从未怀疑堆栈,/RTC非常有价值。

当访问地址超出保护页时,您的程序将崩溃,但默认情况下,每次本地分配超过4K时,编译器都会调用_chkstk()函数


这里有一篇文章解释了堆栈保护页在windows中的工作原理:

我想是一个页面错误中断..好问题。我不知道它在最近的O/S版本中是如何工作的,但我知道一个事实,几年前,我当时使用的一个编译器必须进行修改,以便它在分配大量局部变量时发出的代码实际上触及了内存的每一页,精确地强制发生保护页错误并分配堆栈内存。如果不进行此更改,触摸保护页以外的内存将导致应用程序崩溃(消失而无痕迹)。2马丁:在这种情况下,您应该从“需要更多提交”内存中取消对内存的非法访问。不过,谢谢您的建议。顺便说一句,在Linux上,您不需要触摸中间的页面。如果您触摸任何保留用作堆栈的页面(即使尚未映射),页面错误处理程序也会增加堆栈映射。(这仅适用于Linux上的初始进程堆栈。Linux上的线程堆栈需要完全分配它们的空间,以防止其他分配占用它们将来所需的空间。尽管如此,它们仍然可以延迟地连接到实际的页表中(页错误,而不仅仅是TLB未命中)这个答案似乎错误地表明,点击堆栈保护页是终端故障(“…修复错误”),并且只有在启用运行时检查时才会发出
\u chkstk()
。无声地点击堆栈保护页会增加堆栈大小(前提是有空间这样做),并为现在更大的堆栈创建一个新的保护页。只要堆栈可以展开,就不会在用户进程中生成异常。因此,每当有超过1页的局部变量触发此扩展机制并确保堆栈具有足够的大小时,MSVC++编译器总是发出
\u chkstk()
。这是不正确的,命中保护页总是触发堆栈溢出异常(异常代码0xc00000fd)。代码可以捕获SEH异常并处理该故障,通常通过重新映射保护页来提供约7KB的额外空间。让程序继续而不是通过诊断终止程序是不明智的,但从技术上讲,必须通过诊断恢复防护。