• 关于 _resetstkoflw


       当从 stack overflow exception(c00000fd) 恢复的时候需要调用 _resetstkoflw. 
        如果发生了 stack overflow (c00000fd) 异常, 而这个函数没有被调用, 那么就没有 guard page (PAGE_GUARD) 了; 
        下一次 stack overflow 时, 进程不会产生 stack overflow 异常了, 而很可能因为访问堆栈外的地址而产生AV异常, 或者更严重的错误.

        
        当 esp 访问 guard page 地址的时候, 会产生一个异常, 这时系统做三件事:
        1) 移除 guard page 上的 PAGE_GUARD 保护, 所以那个页面可以被读写.
        2) 在更低地址处 alloc 新的 guard page.
        3) 返回产生异常的指令, 继续执行.
        这样, 系统能够自动增加 stack 的 size.

        
        当超过 stack 的最大 size, 系统会:
        1) 移除 guard page 上的 PAGE_GUARD 标志.
        2) 试图在更低地址 alloc 新的 guard page, 但是这会失败, 因为超过了 stack 的最大 size.
        3) 产生异常, 这样线程就能处理这个异常了.


        注意: 这时, stack 已经没有 guard page 了, 下次栈溢出将一直到底, (本应该有 guard page 的), 
        程序会访问 stack 之外的地址并产生 AV 异常.

        当 stack overflow 异常被处理之后, 应该调用 _resetstkoflw 来恢复 guard page.
        _resetstkoflw 不能在以下场合使用:
        1) A filter expression. (SEH)
        2) A filter function. (SEH)
        3) A function called from a filter function. (SEH)
        4) A catch block. (C++)
        5) A __finally block. (SEH)
        因为这时 stack 还没有 完全 unwind.

        SEH 在 __except { ... } 中处理.
        C++ 在 catch {}  之后处理.

        即使在正确的位置调用 _resetstkoflw 也可能产生错误: 比如 unwinding stack 之后, 留下的 stack 空间还是非常少, 
        不足以执行 _resetstkoflw 来写 PAGE_GUARD 到 stack 的最后一页.
        _resetstkoflw 就会失败, 然后返回0. 所以, 安全使用这个函数 需要检查返回值, 而不是假设 stack 可以被安全使用.

      最后 PAGE_GUARD 的触发是因为: 尽管这个页面提交了, 但是因为该页面不在物理内存中, 通过!pte查看该页面对应的页表项, 会发现页表项的最后一位是0, 说明该页面不在物理内存中, 不在物理内存中的页面被访问会触发缺页中断, 而系统(windows)正是利用这个中断知道一个页面被访问, 再结合属性知道守护页面被访问, 最后系统来扩展stack。

  • 相关阅读:
    spring service层单元测试
    Java源码学习 -- java.lang.StringBuilder,java.lang.StringBuffer,java.lang.AbstractStringBuilder
    Java源码学习 -- java.lang.String
    动态规划算法
    单元测试(Spring)
    Servlet/JSP
    Log4j2 — Log4j2导入、LogEvent、配置文件编写及路径
    idea 控制台输出 中文乱码 解决方法
    常见正则表达式
    读《浪潮之巅》(吴军著)有感
  • 原文地址:https://www.cnblogs.com/happylong/p/4501390.html
Copyright © 2020-2023  润新知