如何在 x64 上制作“堆栈溢出”异常
Posted
技术标签:
【中文标题】如何在 x64 上制作“堆栈溢出”异常【英文标题】:How can i make "stack oveflow" exception on x64 【发布时间】:2019-02-11 18:15:49 【问题描述】:我试图制造一个“堆栈溢出”异常。
此代码在 x64 调试时引发异常。
void DumpSystem::make***()
static int callCount = 0;
++callCount;
make***();
但是,此代码不会在 x64 版本上引发异常 x64 Release xxx.exe 是 LOOP,不会导致“堆栈溢出”异常。
构建选项:“SEH(/EHa)”
我想使用“SetUnhandledExceptionFilter”创建一个“转储文件”。
这是我使用的代码
LONG saveDumpfile(EXCEPTION_POINTERS* ex);
unsigned __stdcall saveDumpFileFor***(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,
saveDumpFileFor***, 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 版本上不退出。
请问,你能告诉我这个原因吗?
【问题讨论】:
编译器可能做了尾调用优化,有效地将你的递归函数变成了一个循环。尝试在递归函数调用之后添加一个有意义的语句。 @Max 请不要在 cmets 部分提供技术回复/答案。谢谢! @LightnessRacesinOrbit 如果我不确定并且没有时间调查/确认但想为其他人留下指针,我该怎么办? 我将使用更复杂的代码。谢谢!!! @Max:没什么。你没有必须写点什么。但是把它丢在这里,你偷走了我们对你的贡献进行同行评审的能力。由于您自己承认您不确定它实际上是否准确,因此这是双重不利的。如果你不确定答案是什么,你可以把它留给有答案的人。 (同样,如果您没有时间,请留给有时间的人。) 【参考方案1】:您犯了一个常见错误,即认为您的 C++ 源代码是人类指令与机器指令的一对一映射。它不是。这是程序的描述。将该描述转化为计算机可以执行的实际程序的过程非常复杂;我们天真地说现代编译器“优化”了代码,但这实际上是一种倒退的方式。
事实上,编译器会尝试创建一个执行您希望它执行的程序的程序,在给定这些约束的情况下生成可能的最佳代码(或者稍微差一点的代码,如果您要求“低优化级别”,从而导致与您的源代码更匹配的代码,从而允许更方便的调试)。在这种情况下,您只需要求重复且无限地执行该函数的行为(实际上 nothing)。
现在,如果代码被直接转换为递归的跳转序列等等,你最终会出现堆栈溢出,因为你会用完所有函数上下文的堆栈空间.
但是! “Tail call optimisation”存在。这是编译器在某些情况下可以做的事情,以产生比递归调用嵌套更类似于 循环 的东西。在生成的代码中,不需要无限堆栈,因此没有异常。
如上所述,降低优化级别(这是调试构建往往涉及的内容),将导致“更糟糕”的代码更接近于您编写的特定源代码,并且您似乎看到了这在您的调试版本中:即使不需要,也会产生实际的递归。由于递归是无限的,你的程序会崩溃。
【讨论】:
哦! “尾呼”感谢您的详细回答。【参考方案2】:void DumpSystem::make***()
static int callCount = 0;
++callCount;
make***();
可以优化为类似的东西
void DumpSystem::make***()
static int callCount = 0;
while (true) ++callCount;
使用tail call optimization,如果您的编译器正在这样做,那么您将永远不会遇到堆栈溢出。在调试模式下您不会看到这一点,因为调试模式通常不会进行优化。
如果你想强制崩溃有很多方法在:What is the easiest way to make a C++ program crash?
【讨论】:
感谢您的详细解答。我将使用更复杂的代码。以上是关于如何在 x64 上制作“堆栈溢出”异常的主要内容,如果未能解决你的问题,请参考以下文章