一、什么是线程栈溢出

我们都知道,每一个win32线程都会开辟一个空间,用来临时存储线程执行时所调用的一系列函数的参数、返回地址和局部变量及其他上下文信息。这个空间就是线程的栈区。栈区的容量是有限的,在程序编译链接时,就固定下来了。通过VC++编译的程序,默认的栈区大小是1MB。当我们程序执行时,访问超过了这个空间的边界,就叫栈溢出,又叫Stack overflow。这时会产生代码为STATUS_STACK_OVERFLOW(0xC00000FD)的异常,从而导致程序崩溃。注意一定要与栈缓冲区溢出---STATUS_STACK_BUFFER_OVERRUN(0xC0000409)区别开来。

二、栈溢出的原因

栈溢出是用户模式线程可能会遇到的错误。 有三个可能的原因产生此错误:

  • 线程使用为其保留的整个堆栈。这通常是由无限递归引起的。

  • 线程无法扩展堆栈,因为页文件已最大化,因此无法提交其他页来扩展堆栈。

  • 由于系统内使用以扩展页面文件的短时间内,线程不能扩展堆栈。

当一个线程上运行的函数分配的本地变量时,变量放线程的调用堆栈上。 函数所需的堆栈空间量可能大至所有本地变量的大小的总和。 但是,编译器通常会执行优化,降低函数所需的堆栈空间。 例如,如果两个变量,则在不同的作用域中,编译器可以为这两个这些变量使用相同的堆栈内存。 编译器还可能无法完全消除某些本地变量对计算进行优化。优化的量会影响应用在生成时的编译器设置。 例如,调试版本和发布版本具有不同的优化级别。 所需的调试版本中的函数的堆栈空间量可能会大于该发行版中的相同函数所需的堆栈空间量。

在我们编写代码时,如下情况通常引发栈溢出:

  • 由于某些原因,导致函数递归深度很深或无穷递归
  • 在栈里分配了很大的缓冲区
  • 栈里的某缓冲区溢出

三、溢出代码举例

3.1、在栈里分配了很大的缓冲区导致溢出

代码如下:

#include "stdafx.h"

int  LargeBuffer(void)
{
    char buf[1024 * 1024];
    int a = 0;
    int b = buf[2];
    return a+b;
}


int _tmain(int argc, _TCHAR* argv[])
{
    int n=LargeBuffer();
    printf("n=%d\n", n);
    return 0;
}

标签: none

添加新评论