如何在 Windows x64 C++ 应用程序中捕获堆栈溢出

Posted

技术标签:

【中文标题】如何在 Windows x64 C++ 应用程序中捕获堆栈溢出【英文标题】:How to trap stack overflow in a Windows x64 C++ application 【发布时间】:2015-03-30 14:47:19 【问题描述】:

我正在尝试在 Windows 中将应用程序编译为 x64 平台架构。处理脚本语言解析的几个线程使用此代码recommended by Microsoft to trap stack overflows and avoid access violation exceptions:

__try

    DoSomethingThatMightUseALotOfStackMemory();

__except(EXCEPTION_EXECUTE_HANDLER)

    LPBYTE lpPage;
    static SYSTEM_INFO si;
    static MEMORY_BASIC_INFORMATION mi;
    static DWORD dwOldProtect;

    // Get page size of system
    GetSystemInfo(&si);

    // Find SP address
    _asm mov lpPage, esp;

    // Get allocation base of stack
    VirtualQuery(lpPage, &mi, sizeof(mi));

    // Go to page beyond current page
    lpPage = (LPBYTE)(mi.BaseAddress)-si.dwPageSize;

    // Free portion of stack just abandoned
    if (!VirtualFree(mi.AllocationBase,
                    (LPBYTE)lpPage - (LPBYTE)mi.AllocationBase,
                     MEM_DECOMMIT))
    
        exit(1);
    

    // Reintroduce the guard page
    if (!VirtualProtect(lpPage, si.dwPageSize, 
                        PAGE_GUARD | PAGE_READWRITE, 
                        &dwOldProtect))
    
        exit(1);
    
    Sleep(2000);

不幸的是,它使用一行内联汇编程序来获取堆栈指针。 Visual Studio 不支持 x64 模式的内联汇编,我也找不到用于获取堆栈指针的 compiler intrinsic。

是否可以以 x64 友好的方式执行此操作?

【问题讨论】:

msdn.microsoft.com/en-us/library/89f73td2.aspx @HansPassant :该链接实际上解决了问题。 _resetstkoflw 似乎是使用而不是上面的 hack 的调用。也许这应该作为正确的答案添加? 欢迎发布。 【参考方案1】:

正如对该问题的评论中所指出的,上面的整个“hack”都可以替换为_resetstkoflw 函数。这在 x86 和 x64 模式下都可以正常工作。

那么上面的代码sn-p就变成了:

// Filter for the stack overflow exception. This function traps
// the stack overflow exception, but passes all other exceptions through. 
int stack_overflow_exception_filter(int exception_code)

    if (exception_code == EXCEPTION_STACK_OVERFLOW)
    
        // Do not call _resetstkoflw here, because at this point
        // the stack is not yet unwound. Instead, signal that the
        // handler (the __except block) is to be executed.
        return EXCEPTION_EXECUTE_HANDLER;
    
    else
        return EXCEPTION_CONTINUE_SEARCH;


void example()

    int result = 0;
    __try
    
        DoSomethingThatMightUseALotOfStackMemory();
    
    __except(stack_overflow_exception_filter(GetExceptionCode()))
    
        // Here, it is safe to reset the stack.
        result = _resetstkoflw();
    

    // Terminate if _resetstkoflw failed (returned 0)
    if (!result)
        return 3;

    return 0;

【讨论】:

以上是关于如何在 Windows x64 C++ 应用程序中捕获堆栈溢出的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用 C++ 中的 RegDeleteKeyEx 的情况下在 64 位树中删除 Windows x64 中的注册表项?

如何在 Windows 10 上使用 Visual Studio 2015 x64 配置和构建 Tesseract OCR C++

如何在 Win x64 上使用 WinAPI 正确安装虚拟打印机?

即使在安装 Visual C++ 2008 Express 和 Windows SDK 后也无法为 x64 编译

我需要安装啥来获得在 Windows Server 2012 R2 Standard 上运行的 C++ hello world .exe 的 x64 调试版本?

如何在默认桌面和 Winlogon 桌面之间切换进程?