C++ 我怎样才能做到;“堆栈流”;x64上的异常

C++ 我怎样才能做到;“堆栈流”;x64上的异常,c++,C++,我试图创建一个“堆栈溢出”异常 此代码在x64调试时引发异常 void DumpSystem::makeStackOverflow() { static int callCount = 0; ++callCount; makeStackOverflow(); } 但是,此代码不会在x64版本上引发异常 x64发行版xxx.exe在循环中没有引起“堆栈溢出”异常 构建选项:“SEH(/EHa)” 我想使用“SetUnhandledExceptionFilter”创建一个“

我试图创建一个“堆栈溢出”异常

此代码在x64调试时引发异常

void DumpSystem::makeStackOverflow()
{
    static int callCount = 0;
    ++callCount;
    makeStackOverflow();
}
但是,此代码不会在x64版本上引发异常 x64发行版xxx.exe在循环中没有引起“堆栈溢出”异常

构建选项:“SEH(/EHa)”

我想使用“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;
}
“x64调试exe”这是工作。 这样我就可以生成“dump.dmp”文件

但是,“x64发布exe”不起作用。 我无法生成“dump.dmp”文件

我想知道为什么程序在x64版本上不退出


请告诉我这个原因。

< P>你犯了一个常见的错误,那就是把你的C++源代码看作是人类指令到机器指令的一一对应的映射。事实并非如此。这是对一个程序的描述。将这种描述转换成计算机可以执行的实际程序的过程非常复杂;我们天真地说,现代编译器“优化”了代码,但这实际上是一种倒退的观点

事实上,编译器将尝试创建一个程序来完成您希望它做的事情,在这些约束条件下生成尽可能最好的代码(或者如果您要求“低优化级别”,则生成稍差的代码),从而生成与源代码更接近的代码,从而允许更方便的调试)。在本例中,您只是要求反复无限地执行该函数的行为(实际上什么都不是)

现在,如果将代码直接转换为一个递归的跳跃序列等等,那么最终会出现堆栈溢出,因为所有函数上下文的堆栈空间都已用完

但是!”“存在。在某些情况下,编译器可以这样做,以生成比递归调用嵌套更类似于循环的东西。在生成的代码中,不需要无限堆栈,因此没有异常

如上所述,降低优化级别(调试构建往往会涉及到这一点)将导致“更糟糕”的代码与您编写的特定源代码更加匹配,并且您似乎在调试构建中看到了这种效果:即使不需要,也会产生实际的递归。因为递归是无限的,所以程序会崩溃

void DumpSystem::makeStackOverflow()
{
    static int callCount = 0;
    ++callCount;
    makeStackOverflow();
}
可以优化为

void DumpSystem::makeStackOverflow()
{
    static int callCount = 0;
    while (true) ++callCount;
}
如果编译器就是这样做的,那么你永远不会得到堆栈溢出。在调试模式下,您不会看到这种情况,因为调试模式通常不进行优化


如果您想强制崩溃,有许多方法在中介绍:

编译器可能进行了尾部调用优化,有效地将递归函数转化为循环。尝试在递归函数调用后添加有意义的语句。@Max请不要在“注释”部分提供技术响应/答案。谢谢@LightnessRacesinOrbit如果我不确定,没有时间调查/确认,但想给其他人留下一个指针,我该怎么办?我将使用更复杂的代码。谢谢你@马克斯:没什么。你不必写东西。但你把它扔在这里,偷走了我们对你的贡献进行同行评审的能力。因为你自己承认你不确定它是否准确,这是双重的不好。如果你不确定答案是什么,你可以把它留给真正的人。(同样,如果你没有时间,就留给有时间的人。)哦!!“尾部呼叫”谢谢你的详细回答。谢谢你的详细回答。我将使用更复杂的代码。
void DumpSystem::makeStackOverflow()
{
    static int callCount = 0;
    while (true) ++callCount;
}