Diagnóstico de Falhas de Software com Captura de Exceções

Durante a execução de um software, encontrar uma falha inesperada como um encerramento abrupto (crash) pode ser problemático. Em um cenário real, uma aplicação pode finalizar durante a noite, e os logs do Windows podem apenas registrar um código genérico como 0xC0000005, tornando impossível identificar a função específica onde a exceção ocorreu. A solução utiliza o Visual Studio, combinando um arquivo DMP (minidump) gerado no momento da falha com um arquivo PDB (símbolos de depuração) para localizar com precisão a origem do erro.

O código a seguir demonstra como implementar um filtro para exceções não tratadas. Quando um crash ocorre, este código gera um arquivo .dmp no subdiretório 'ErrorDumps' localizado junto ao executável. Para que a análise posterior funcione, é necessário compilar o projeto nos modos 'Debug' ou 'RelWithDebInfo', os quais produzem os arquivos .pdb.


#include <windows.h>
#include <dbghelp.h>
#include <shlwapi.h>
#include <ctime>

#pragma comment(lib, "dbghelp.lib")
#pragma comment(lib, "shlwapi.lib")

// Manipulador global para exceções críticas
LONG __stdcall ProcessUnhandledException(EXCEPTION_POINTERS* pExceptInfo)
{
    WCHAR exeFullPath[MAX_PATH] = {0};
    WCHAR dumpDirectory[MAX_PATH] = {0};
    WCHAR dumpFilePath[MAX_PATH] = {0};

    // Obtém o caminho completo do executável atual
    if (!GetModuleFileNameW(NULL, exeFullPath, MAX_PATH))
        return EXCEPTION_CONTINUE_SEARCH;

    // Extrai apenas o diretório do caminho
    PathRemoveFileSpecW(exeFullPath);

    // Constrói o caminho para a pasta de dumps
    wsprintfW(dumpDirectory, L"%s\\ErrorDumps", exeFullPath);
    CreateDirectoryW(dumpDirectory, NULL);

    // Gera um nome de arquivo único baseado no timestamp atual
    time_t now = time(NULL);
    struct tm* timeInfo = localtime(&now);
    wsprintfW(dumpFilePath, L"%s\\Crash_%04d%02d%02d_%02d%02d%02d.dmp",
              dumpDirectory,
              timeInfo->tm_year + 1900, timeInfo->tm_mon + 1, timeInfo->tm_mday,
              timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec);

    // Cria o arquivo DMP
    HANDLE hFile = CreateFileW(dumpFilePath, GENERIC_WRITE, 0, NULL, 
                              CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile != INVALID_HANDLE_VALUE)
    {
        MINIDUMP_EXCEPTION_INFORMATION exceptInfo;
        exceptInfo.ThreadId = GetCurrentThreadId();
        exceptInfo.ExceptionPointers = pExceptInfo;
        exceptInfo.ClientPointers = FALSE;

        // Gera o dump. MiniDumpWithDataSegs é uma alternativa mais leve que FullMemory
        MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile,
                         MiniDumpWithDataSegs, &exceptInfo, NULL, NULL);

        CloseHandle(hFile);
    }

    return EXCEPTION_EXECUTE_HANDLER;
}

int main()
{
    // Registra o nosso manipulador de exceções
    SetUnhandledExceptionFilter(ProcessUnhandledException);

    // Simulação de um acesso inválido à memória para provocar o crash
    int* pNullPointer = nullptr;
    *pNullPointer = 10;

    return 0;
}

Para projetos que utilizam CMake e necessitam gerar símbolos de depuração no modo Release (essencial para analisar os dumps de um build de produção), as seguintes configurações devem ser adicionadas:


if(MSVC)
    # Ativa a geração de informações de depuração (/Zi) nas compilações Release
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
    
    # Configura o linker para gerar o arquivo PDB e otimizar
    set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF")
endif()

Após obter o arquivo .dmp gerado durante uma falha real, abra-o diretamente no Visual Studio. O ambiente oferecerá a opção de "Depurar em tempo real" (Just-In-Time Debugging). Se o arquivo .pdb correspondente à mesma build estiver acessível (no mesmo diretório ou em um símbolo configurado), o Visual Studio carregará o estado da aplicação no momento exato da exceção, permitindo navegar pela pilha de chamadas e inspecionar as variáveis locais para identificar a causa raiz do problema.

Tags: Windows API Minidump PDB Depuração de Software C++

Publicado em 7-14 07:18