Когда _set_se_translator с MiniDumpWriteDump не может записать дамп? - PullRequest
0 голосов
/ 15 февраля 2019

У нас есть редкий сбой в 32-битном исполняемом файле C ++ в Windows, который не создает дамп памяти.У нас нет случая воспроизведения, и когда происходит сбой, игра просто исчезает через несколько секунд, поэтому нам нужен дамп памяти, чтобы найти причину.Другие сбои действительно создают дамп памяти, поэтому мы знаем, что наша функция дамп памяти иногда работает, но только не при этом конкретном сбое.

При каких обстоятельствах комбинация _set_se_translator и MiniDumpWriteDump не может создатьдамп памяти?Неужели мы что-то не так делаем в нашей обработке дампа памяти, которая иногда приводит к тому, что он не производит дамп?

Вот что мы сейчас делаем:

В начале основной функции в главном потоке мыcall SetUnhandledExceptionFilter(CrashDumpManager::unhandledExceptionHandler);

В каждом потоке мы вызываем _set_se_translator(CrashDumpManager::MiniDumpFunction);

Вот так выглядит CrashDumpManager.h:

#include <Windows.h>
#include <Dbghelp.h>

class CrashDumpManager
{
public:
    static void MiniDumpFunction(unsigned int nExceptionCode, EXCEPTION_POINTERS *pException);
    static LONG CALLBACK unhandledExceptionHandler(EXCEPTION_POINTERS* e);

    //If the game crashes because of a memory leak then there won't be enough memory free to generate a memory dump
    //Therefore 10MB is allocated here and deleted before the crashdump is written.
    static unsigned char* crashdumpMemory;
};

А вот так выглядит CrashDumpManager.cppкак:

#include "CrashDumpManager.h"

void CrashDumpManager::MiniDumpFunction(unsigned int nExceptionCode, EXCEPTION_POINTERS *pException)
{
    delete crashdumpMemory;
    crashdumpMemory = nullptr;

    // prevent stack overflow when crashing in this function
    static bool calledFunctionOnce = false;
    if (!calledFunctionOnce)
    {
        calledFunctionOnce = true;

        HMODULE dbgHelpModule = LoadLibraryA("dbghelp");
        if (dbgHelpModule == nullptr)
            return;
        auto writeMiniDumpFunction = (decltype(&MiniDumpWriteDump))GetProcAddress(dbgHelpModule, "MiniDumpWriteDump");
        if (writeMiniDumpFunction == nullptr)
            return;

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

        HANDLE dumpFileHandle = CreateFileA(name, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
        if (dumpFileHandle == INVALID_HANDLE_VALUE)
            return;

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

        auto dumped = writeMiniDumpFunction(GetCurrentProcess(), GetCurrentProcessId(), dumpFileHandle,
                                            MINIDUMP_TYPE(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory),
                                            pException ? &exceptionInfo : nullptr, nullptr, nullptr);

        CloseHandle(dumpFileHandle);
    }
}

LONG CALLBACK CrashDumpManager::unhandledExceptionHandler(EXCEPTION_POINTERS* e)
{
    CrashDumpManager::MiniDumpFunction(0, e);
    return EXCEPTION_CONTINUE_SEARCH;
}

unsigned char* CrashDumpManager::crashdumpMemory = new unsigned char[10*1024*1024];
...