如何编写会崩溃并生成转储文件的示例代码?

Posted

技术标签:

【中文标题】如何编写会崩溃并生成转储文件的示例代码?【英文标题】:How to write a sample code that will crash and produce dump file? 【发布时间】:2011-06-29 01:33:11 【问题描述】:

我开始学习windbg,我发现了这个好帖子 How to use WinDbg to analyze the crash dump for VC++ application?

现在我想按照说明一步一步地做。问题来了:我需要编写一些可以立即崩溃的示例代码,并创建一些可供windbg使用的转储文件。

这样的代码怎么写?

void Example4()

    int* i = NULL;
    *i = 80;

上面的代码会立即崩溃;但是,我不知道在哪里可以找到转储文件?

谢谢

【问题讨论】:

也看看这个:debuginfo.com/articles/effminidumps.html 我发现它非常有用。它还包含一些示例代码。 【参考方案1】:
#include <Windows.h>
#include <Dbghelp.h>

void make_minidump(EXCEPTION_POINTERS* e)

    auto hDbgHelp = LoadLibraryA("dbghelp");
    if(hDbgHelp == nullptr)
        return;
    auto pMiniDumpWriteDump = (decltype(&MiniDumpWriteDump))GetProcAddress(hDbgHelp, "MiniDumpWriteDump");
    if(pMiniDumpWriteDump == nullptr)
        return;

    char name[MAX_PATH];
    
        auto nameEnd = name + GetModuleFileNameA(GetModuleHandleA(0), name, MAX_PATH);
        SYSTEMTIME t;
        GetSystemTime(&t);
        wsprintfA(nameEnd - strlen(".exe"),
            "_%4d%02d%02d_%02d%02d%02d.dmp",
            t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);
    

    auto hFile = CreateFileA(name, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
    if(hFile == INVALID_HANDLE_VALUE)
        return;

    MINIDUMP_EXCEPTION_INFORMATION exceptionInfo;
    exceptionInfo.ThreadId = GetCurrentThreadId();
    exceptionInfo.ExceptionPointers = e;
    exceptionInfo.ClientPointers = FALSE;

    auto dumped = pMiniDumpWriteDump(
        GetCurrentProcess(),
        GetCurrentProcessId(),
        hFile,
        MINIDUMP_TYPE(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory),
        e ? &exceptionInfo : nullptr,
        nullptr,
        nullptr);

    CloseHandle(hFile);

    return;


LONG CALLBACK unhandled_handler(EXCEPTION_POINTERS* e)

    make_minidump(e);
    return EXCEPTION_CONTINUE_SEARCH;


int main()

    SetUnhandledExceptionFilter(unhandled_handler);

    return *(int*)0;

【讨论】:

【参考方案2】:

这将产生一个空指针取消引用异常: *((int*) 0) = 0;

这将产生整数除以零: int a = 0; int b = 5 / a;

编辑:Post-Mortem Debugging Your Application with Minidumps and Visual Studio .NET 包含大量示例代码和有关使用小型转储的理论。

【讨论】:

感谢您的代码。你能告诉我在哪里可以找到转储文件吗? @q0987 该文件将在您使用 MiniDumpWriteDump() 写入的任何位置。如果你打开了 UAC,你可能无法直接在 C:\ 上写它。在这种情况下,请使用您用户下的文件夹,或以管理员身份启动应用程序。【参考方案3】:

要创建故障转储,我将按照@Abyx 的建议编写未处理的异常处理程序,原因如下:

a) 在某些缓冲区溢出或堆栈溢出的情况下,处理未处理异常的代码可能已损坏。如果出现 OutOfMemoryException,如何加载另一个库,如 DbgHelp.dll?

b) 你写的代码可能有问题。该代码是否在写入转储之前检查可用磁盘空间?您如何测试代码以编写故障转储?你有一个单元测试吗?您的单元测试如何检查转储是否正确?

c) 如果 Windows 可以为您编写代码,为什么还要编写代码?

MSDN 在Collecting user mode dumps 上有一篇文章。基本上,您可以进行一些注册表设置。优点是:Windows 将由操作系统创建故障转储,而不是由您自己的应用程序中的某些损坏的代码。

【讨论】:

有效点,但引用了 MSDN 文章 Enabling the feature requires administrator privileges,这对于软件部署可能是不可能的【参考方案4】:

如果您想查看故障转储,您需要创建一个。见Heisenbug: WinApi program crashes on some computers。虽然您可以在不通过 WinQual 的情况下获得旨在为 WER 发送的故障转储,但它有点混乱(基本上您可以在发送之前从临时位置复制它,具体细节取决于您的操作系统) ,我建议使用 Win API MiniDump 提供的函数创建自己的故障转储。所有需要的代码都可以在The CodeProject page mentioned in the linked answer找到。

【讨论】:

您还可以为您的应用配置一个位置,WER 将在其中保存小型转储。在此处查看更多详细信息:docs.microsoft.com/en-us/windows/win32/wer/…【参考方案5】:

自动小型转储生成由事后调试器完成,因此您需要从那里开始。最重要的是,它是由调试器完成的。因此,如果您只想生成一个小型转储,您可以使用您的典型调试器(可能是 Visual Studio 或 Windbg)。甚至任务管理器也可以创建转储文件。

指定事后调试器的注册表设置是HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug

查看Debugger 字符串,您就可以找到您的小型转储了。

【讨论】:

【参考方案6】:

转储文件可以通过编程或程序错误调试工具创建。在第一种情况下,您可以使用MiniDumpWriteDump 函数,在第二种情况下,您可以使用 Dr. Watson(对于 XP:看看这个 description 和这个非常具有描述性的 video;对于 Vista,看看 here)

【讨论】:

【参考方案7】:

大多数情况下,您会发现所有应用程序都转储在 C:\windows\minidumps 中。

要生成转储文件,您可以使用简单的解决方案:

    打开windbg 文件->打开可执行文件 您运行的应用程序会崩溃 会触发断点 现在您可以在 windbg 中使用 .dump 来创建 dmp 文件

    运行应用程序并等待崩溃 打开windbg并附加到进程(文件->附加到进程) 运行.dump

这样您就可以随时分析该崩溃:)

【讨论】:

【参考方案8】:

我前段时间测试WinDbg时使用了下面的代码。

下面的代码可以运行并将生成故障转储 有两个函数,因此您可以看到带有明显函数链的堆栈跟踪。 要查找故障转储,请在 C:\Users 中搜索 *.dmp 或 *.mdmp 最好让操作系统为您生成转储。这可能就是您看到的大多数真实故障转储的生成方式。 代码首先分配 1 KiB 的内存,然后用可识别的十六进制值写入它和后面的 1 KiB。这通常会遇到操作系统标记为不可写的内存页面,这将触发崩溃。
#include "stdafx.h"
#include "stdio.h"
#include "malloc.h"

void Function2(int * ptr2)

    for(int i=0; i < (2 * 1024); i++)
    
        *ptr2++ = 0xCAFECAFE;
    


void Function1()

    int * ptr1 = (int *)malloc(1024 * sizeof(int));

    Function2(ptr1);


int _tmain(int argc, _TCHAR* argv[])

    printf("Press enter to allocate and corrupt.\r\n");
    getc(stdin);

    printf("Allocating and corrupting...\r\n");
    Function1();

    printf("Done.  Press enter to exit process.\r\n");
    getc(stdin);

    return 0;

【讨论】:

【参考方案9】:

试试这个:

int main()

   int v[5];

   printf("%d", v[10]);
   return 0;

或访问随机内存位置。

【讨论】:

这可能不会崩溃 - v[10] 处的堆栈内存可能实际上已分配,而 printf 只会打印出垃圾。

以上是关于如何编写会崩溃并生成转储文件的示例代码?的主要内容,如果未能解决你的问题,请参考以下文章

Android 不会在运行时崩溃时转储错误跟踪

Sun JDK 能否在 JVM 崩溃时生成核心/堆转储文件?

Core dump文件和ECFS

当 gcc 中的应用程序在没有 gdb 的情况下崩溃时,如何生成堆栈转储和转储的寄存器值?

一步步完成thrift rpc示例

gdb 调试远程核心转储