在许多操作系统上,堆栈和堆从进程的虚拟地址空间的相对侧开始,并朝向彼此增长。这允许堆栈尽可能地扩展而不会碰到堆。
假设我有一个导致堆栈溢出的程序。我目前的理解是,这将导致堆栈不受控制地向堆增长并最终击中它。它是否正确?如果是,操作系统如何检测到堆栈溢出?似乎操作系统无法检测到程序试图使用为堆分配的虚拟内存作为堆栈的一部分,因为它们位于连续的内存区域中。
我知道这是特定于操作系统的,但是对任何操作系统中发生这种情况的机制的深入了解肯定会有所帮助。这已经困扰了我一段时间,我似乎找不到任何好的解释。
答案 0 :(得分:4)
操作系统为堆栈分配一些空间。当进程访问堆栈的未分配部分时,处理器引发页面错误并由OS捕获。如果操作系统认为增加堆栈仍然是合理的,那么它只需为其分配新空间并将控制权返回给流程。如果不合理,则会引发堆栈溢出异常。
答案 1 :(得分:2)
这只是直觉,但确保堆栈不会干扰堆听起来像JVM的工作。我没有理由为什么我不能创建自己糟糕的编程语言,让堆栈开始覆盖堆(崩溃之前)。
答案 2 :(得分:1)
堆栈溢出在堆栈中向后移动 - 它们通过覆盖堆栈已经初始化的部分中的数据来工作,这可能正是因为堆栈向下增长。
因此,操作系统无法检测到这种情况,因为允许进程在任何时候修改其堆栈的初始化部分。
使用堆栈空间扩展堆栈工作,并且操作系统陷入页面错误处理程序,因为没有设置页面。一些操作系统只允许在“保护页面”上进行这些访问,即紧接在当前堆栈之前的页面将触发重新分配,其他操作系统在故障时查看堆栈指针寄存器的内容以查看是否应该是堆栈访问。
答案 3 :(得分:1)
大多数现代处理器都有MMU(内存管理单元),它是将硬件地址应用于每个程序的“硬件”设备,每个程序都存在于自己的内存空间中。 OS处理此MMU,当程序想要读取或写入专用存储器中的地址时,MMU会引发中断。
http://en.wikipedia.org/wiki/Memory_management_unit
通过这种方式,如何检测SO是非常严峻的。 堆栈和堆不在连续的内存地址上。
我也看到过使用保护词的不同方法。每个进程的堆栈都分配在堆上并填充了白色防护病房(类似于0xc0cac01a)。这样,通过计算保护字,很容易获得每个进程的堆栈大小。如果没有至少一个保护词,操作系统会引起恐慌。