操作系统如何检测堆栈溢出?
在许多操作系统上,堆栈和堆从进程虚拟地址空间的相对两侧开始,并向彼此增长。这使得堆栈能够在不触及堆的情况下尽可能地扩展。
假设我有一个程序导致堆栈溢出。我目前的理解是,这将导致堆栈不受控制地向堆增长并最终到达堆。这是正确的吗?如果是,操作系统如何检测堆栈溢出的发生?操作系统似乎无法检测到程序正在尝试使用为堆分配的虚拟内存作为堆栈的一部分,因为它们位于连续的内存区域中。
我知道这是特定于操作系统的,但是了解任何操作系统中发生这种情况的机制肯定会有所帮助。这已经困扰我一段时间了,我似乎找不到任何好的解释。
On many operating systems the stack and heap begin at opposite sides of a process's virtual address space and grow toward one another. This allows the stack to expand as much as possible without hitting the heap.
Suppose that I have a program that causes a stack overflow. My current understanding is that this would result in the stack growing uncontrollably toward the heap and eventually hitting it. Is this correct? If it is, how does the operating system detect that a stack overflow occurs? It seems like the OS wouldn't be able to detect that the program was trying to use virtual memory allocated for the heap as part of the stack, since they'd be in contiguous memory regions.
I know that this is operating-system specific, but insight on the mechanism by which this occurs in any operating system would definitely be helpful. This has been bugging me for a while and I can't seem to find any good explanations.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
操作系统向堆栈分配一些空间。当进程访问堆栈的未分配部分时,处理器会引发页面错误并被操作系统捕获。如果操作系统认为增加堆栈仍然合理,它只需为其分配新空间并将控制权返回给进程。如果不合理,则会引发堆栈溢出异常。
The OS allocates some space to the stack. When the process accesses an unallocated part of the stack, a page fault is raised by the processor and caught by the OS. If the OS believes it's still reasonable to grow the stack, it simply allocates new space for it and returns control to the process. If it's not reasonable, a stack overflow exception is raised.
这只是直觉,但确保堆栈不会干扰堆听起来像是 JVM 的工作。我看不出为什么我不能创建自己的糟糕的编程语言,让堆栈开始覆盖堆(在崩溃之前)。
This is just intuition, but making sure that the stack doesn't interfere with the heap sounds like the job of the JVM. I see no reason why I couldn't make my own terrible programming language where I let the stack begin to overwrite the heap (before crashing).
堆栈溢出在堆栈中向后移动——它们通过覆盖堆栈中已初始化部分中的数据来工作,这正是因为堆栈向下增长而可能发生的。
因此,操作系统无法检测到这种情况,因为进程可以随时修改其堆栈的初始化部分。
扩展堆栈是通过使用堆栈空间的进程来实现的,并且操作系统由于没有设置页面而陷入页面错误处理程序。一些操作系统仅允许在“保护页面”上进行这些访问,即当前堆栈之前的页面将触发重新分配,其他操作系统在发生故障时查看堆栈指针寄存器的内容以查看这是否应该是一个堆栈访问。
Stack overflows go backwards in the stack -- they work by overwriting data in already initialized parts of the stack, which is possible precisely because stacks grow downwards.
Thus, the operating system cannot detect this condition, as the process is allowed to modify the initialized parts of its stack at any time it wants.
Extending the stack works by the process using the stack space, and the OS trapping into the page fault handler because no page has been set up. Some OSes allow these accesses only on a "guard page", i.e. the page immediately before the current stack will trigger reallocation, others look at the contents of the stack pointer register at the time of the fault to see whether this was supposed to be a stack access.
大多数现代处理器都有MMU(内存管理单元),它是向每个程序应用虚拟地址的“硬件”设备,每个程序都存在于自己的内存空间中。操作系统处理该 MMU,并且当程序想要读取或写入专用内存 MMU 之外的地址时,会引发中断。
http://en.wikipedia.org/wiki/Memory_management_unit
这样就非常简单了可能会检测到SO。
堆栈和堆不在连续的内存地址上。
我还看到了使用保护词的不同方法。每个进程的堆栈都分配在堆上并填充了守卫区(类似于 0xc0cac01a)。这样,只需计算保护字就可以轻松获得每个进程的堆栈大小。如果没有至少一个保护字,操作系统就会引发恐慌。
Most modern processors have MMU (memory manegement unit) and it is "hardware" device to apply virtual address to each program and each program lives in its own memory space. OS handle this MMU and when program want to read or write on address out of dedicated memory MMU raises interrupt.
http://en.wikipedia.org/wiki/Memory_management_unit
This way it is pretty straitgfoward how it might detect SO.
Stack and Heap are not on continuous memory addresss.
I have also seen different approach using guard words. Stack for each process was allocated on heap and filled whit guard wards (something like 0xc0cac01a). This way it was easy to get size of stack for each process just by counting guard words. Operating system raised panic if there were not at least one guard word.