我试图做出“堆栈溢出”异常。
此代码在x64调试上引发异常。
void DumpSystem::makeStackOverflow()
{
static int callCount = 0;
++callCount;
makeStackOverflow();
}
但是,此代码在x64发行版上不会引发异常 x64版本xxx.exe处于LOOP状态,没有引起“堆栈溢出”异常。
构建选项:“ 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;
}
main.cpp
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
registrationDumpSystem();
//to do
return 0;
}
“ x64调试exe”正在工作。 这样我就可以制作“ dump.dmp”文件。
但是,“ x64版本exe”不起作用。 我无法制作“ dump.dmp”文件
enter image description here 我想知道为什么该程序不能在x64版本上退出。
请你告诉我这个原因吗?
答案 0 :(得分:0)
您犯了一个普遍的错误,那就是将您的C ++源代码视为人类指令与机器指令的一对一映射。不是。它是程序的描述。将该描述转换为计算机可以执行的实际程序的过程非常复杂。我们天真地说现代编译器“优化”了代码,但这实际上是一种向后看的方式。
实际上,编译器将尝试创建一个可以执行您想要的程序的程序,在给定这些约束的情况下,可能会产生最佳的代码(或者,如果您要求“低优化级别”,则可能会产生更差的代码,从而导致与您的源代码更加匹配的代码,从而可以进行更方便的调试)。在这种情况下,您只是简单地要求重复无限制地执行该功能的行为(实际上是什么都不做)。
现在,如果将代码直接转换为递归的跳转序列,那么,最终将导致堆栈溢出,因为所有函数上下文的堆栈空间都用完了
但是!存在“ Tail call optimisation”。在某些情况下,编译器可以这样做,以产生比循环调用嵌套更像 loop 的东西。在生成的代码中,不需要无限堆栈,因此也没有异常。
如上文所述,降低优化级别(这是调试版本往往会涉及的问题),将导致“更糟糕”的代码与您编写的特定源代码更加匹配,并且看来您正在看到这在您的调试版本中:即使不需要,也会产生实际的递归。由于递归是无限的,因此您的程序将崩溃。
答案 1 :(得分: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?