如何在x64上进行“堆栈溢出”异常

问题描述 投票:-3回答:2

我试图做出“堆栈溢出”异常。

此代码在x64 Debug上引发异常。

void DumpSystem::makeStackOverflow()
{
    static int callCount = 0;
    ++callCount;
    makeStackOverflow();
}

但是,此代码不会在x64版本上引发异常x64 Release xxx.exe是LOOP而不会导致“Stack Overflow”异常。

构建选项:“sah(/ this)”

我想使用“SetUnhandledExceptionFilter”创建一个“转储文件”。

这是我使用的代码

LONG saveDumpfile(EXCEPTION_POINTERS* ex);

unsigned __stdcall saveDumpFileForStackOverflow(void* arg)
{
    EXCEPTION_POINTERS* ex = static_cast<EXCEPTION_POINTERS*>(arg);
    return saveDumpfile(ex);
}

LONG exceptionHandling(EXCEPTION_POINTERS* ex)
{

    if (ex &&
        ex->ExceptionRecord &&
        ex->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW)
    {

        HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0,
            saveDumpFileForStackOverflow, ex, NULL, NULL);
        WaitForSingleObject(hThread, INFINITE);
        CloseHandle(hThread);
        return EXCEPTION_EXECUTE_HANDLER;
    }

    return saveDumpfile(ex);
}

void registrationDumpSystem()
{
    ::SetUnhandledExceptionFilter(exceptionHandling);
}

LONG saveDumpfile(EXCEPTION_POINTERS* ex)
{
    if (ex == NULL)
        return EXCEPTION_EXECUTE_HANDLER;

    LONG result = EXCEPTION_EXECUTE_HANDLER;

    //%APPDATA% : C:\Users\[user name]\AppData\Roaming
    wstring filePath = getAppDataFolderPath();


    SHCreateDirectoryEx(NULL, filePath.c_str(), NULL);


    filePath.append(TEXT("\\Dump.dmp"));
    HANDLE file = CreateFile(filePath.c_str(),
        GENERIC_WRITE,
        FILE_SHARE_WRITE,
        NULL,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL, NULL);

    if (file == INVALID_HANDLE_VALUE)
    {
        DWORD lerr = GetLastError();
        return lerr;
    }

    HANDLE processHandle = GetCurrentProcess();
    DWORD processId = GetCurrentProcessId();

    MINIDUMP_EXCEPTION_INFORMATION mei;
    mei.ThreadId = GetCurrentThreadId();
    mei.ExceptionPointers = ex;
    mei.ClientPointers = false;

    MiniDumpWriteDump(processHandle, processId, file,
        MiniDumpNormal, &mei, NULL, NULL);

    CloseHandle(file);

    return result;
}

main.cpp中

int APIENTRY _tWinMain(HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPTSTR    lpCmdLine,
    int       nCmdShow)
{
    registrationDumpSystem();
    //to do
    return 0;
}

“x64 Debug exe”这是工作。所以我可以制作“dump.dmp”文件。

但是,“x64 release exe”是行不通的。我无法制作“dump.dmp”文件

enter image description here我想知道为什么程序不会在x64版本上退出。

拜托,你能告诉我这个原因吗?

c++
2个回答
0
投票

你犯了一个常见错误,就是将你的C ++源代码视为人机指令与机器指令的一对一映射。事实并非如此。这是一个程序的描述。将此描述转换为计算机可以执行的实际程序的过程非常复杂;天真的我们说现代编译器“优化”代码,但这确实是一种向后看待它的方式。

事实上,编译器将尝试创建一个程序来执行您希望它执行的操作,在给定这些约束的情况下生成最佳代码(或者如果您要求“低优化级别”,则代码稍差,导致代码更多与您的源密切匹配,从而允许更方便的调试)。在这种情况下,您只需要反复无限地执行该函数的行为(实际上没有任何内容)。

现在,如果代码被直接转换为递归的跳转序列和诸如此类的东西,那么最终会出现堆栈溢出,因为你的所有函数上下文都没有堆栈空间。

但! “Tail call optimisation”存在。在某些情况下,编译器可以做的事情是生成一个更像循环而不是递归调用嵌套的东西。在生成的代码中,不需要无限堆栈,因此没有例外。

如上所述,降低优化级别(这是调试构建所涉及的)将导致“更差”的代码更紧密地匹配您编写的特定源,并且您似乎看到了这种影响debug build:即使不需要,也会产生实际的递归。由于递归是无限的,你的程序崩溃了。


0
投票
void DumpSystem::makeStackOverflow()
{
    static int callCount = 0;
    ++callCount;
    makeStackOverflow();
}

可以优化到类似的东西

void DumpSystem::makeStackOverflow()
{
    static int callCount = 0;
    while (true) ++callCount;
}

使用tail call optimization,如果这是你的编译器正在做的事情,那么你永远不会得到堆栈溢出。您不会在调试模式下看到它,因为调试模式通常不会进行优化。

如果你想强行崩溃,有许多方法:What is the easiest way to make a C++ program crash?

© www.soinside.com 2019 - 2024. All rights reserved.