• 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或则其他有入栈操作的指令时,且我们在调用栈里明显看到某函数的递归调用,那么这就是递归调用引发的栈溢出。第三种情况要具体问题具体分析了

  • 相关阅读:
    Centos 7 zabbix 实战应用
    Centos7 Zabbix添加主机、图形、触发器
    Centos7 Zabbix监控部署
    Centos7 Ntp 时间服务器
    Linux 150命令之查看文件及内容处理命令 cat tac less head tail cut
    Kickstart 安装centos7
    Centos7与Centos6的区别
    Linux 150命令之 文件和目录操作命令 chattr lsattr find
    Linux 发展史与vm安装linux centos 6.9
    Linux介绍
  • 原文地址:https://www.cnblogs.com/yilang/p/11367942.html
Copyright © 2020-2023  润新知