• win32线程栈溢出问题 (二)


    3.2、函数递归调用引发的栈溢出

    写一段最简单的无穷递归代码,如下:

    #include "stdafx.h"
    void f(void)
    {
        f();
    }
    int _tmain(int argc, _TCHAR* argv[])
    {
        f();
        return 0;
    }

    在VS编译,Debug模式下运行之,结果报错

    观察下调用栈,发现栈没有破坏,但被大量的f()调用沾满,如下:

    这也充分说明了,是递归调用引起了栈溢出

    转到汇编,在地址栏里输入上面错误框里的地址0x011515C9

    可以看到,程序是在执行一次入栈操作时,报错了

    我们转到Windbg运行程序,观察下

    看下相关寄存器的值

    栈顶指针esp=0x000a2f78

    在看下线程栈下限

    栈区界限下限为0x000A1000,然而,此时esp=0x000a2f78,已经非常接近下限了。0x000a2f78-0x000A1000=0x1f78<0x2000,也就是说,限制esp已经进入到栈区的后两个保护页了,当线程访问到倒数第三个页面的的时候,系统会为倒数第二个页面调拨物理存储器,此时还会抛出EXCEPTION_STACK_OVERFLOW。

    针对函数递归调用而引起的栈溢出,我们可以采用下面的方式来解决:

    • 给递归调用加上退出机制
    • 改变设计,不用递归,比如可以用循环语句替代

    3.3、栈里的某缓冲区溢出

    这种情况比较复杂,不好模拟,当在线程里执行的某个函数里,开辟了某个缓冲区,对这个缓冲区进行写操作溢出,刚好覆盖了ESP或EBP值时,可能触发栈溢出异常。对这种栈缓冲区溢出问题,在编写代码时要吗非常小心索引值的检测,或则用安全版本的api来进行读写。

    四、总结

    前面的讲的两种情况,是平时工作中常遇到,也是非常好定位和修改的。这两种情况下,一般调用栈是不会发生破坏的,当我们看到最后调用的是_chkstk,那么通常是栈里使用了超大缓冲区,如果最后是停在了汇编指令push xx或则其他有入栈操作的指令时,且我们在调用栈里明显看到某函数的递归调用,那么这就是递归调用引发的栈溢出。第三种情况要具体问题具体分析了

  • 相关阅读:
    linux scull 函数open 方法
    linux scull 中的设备注册
    linux 字符设备注册
    linux inode 结构
    linux设备驱动文件结构
    linux一些重要数据结构
    Python3.2官方文档翻译--输出格式化
    1021. Deepest Root (25)
    hdu 4779 Tower Defense (思维+组合数学)
    cookie是什么? -- web
  • 原文地址:https://www.cnblogs.com/yilang/p/11367942.html
Copyright © 2020-2023  润新知