You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows 7下MiniDumpWriteDump执行失败及未知异常码问题求助

Windows 7下MiniDumpWriteDump调用失败问题排查与解决

问题背景

需要实现Windows系统运行进程的转储收集功能,依赖MiniDumpWriteDump函数。该函数在Windows 7之前的系统运行正常,但在Windows 7上调用返回值为0,转储生成失败。此前针对Windows 7设置exceptionInfo.ClientPointers = TRUE,旧系统设为FALSE,但当前通过EXCEPTION_POINTERS获取到的错误码148696056未在官方文档中定义。

原实现代码:

for( const auto& process : GetActiveProcesses() )
{
   if( process.ExeFile() == mProcessName )
   {
      try
      {
         String dump_name = GetDumpFileName( process.ProcessID() );
         bfs::wpath dump_path = assembly_directory / dump_name;

         MINIDUMP_EXCEPTION_INFORMATION exceptionInfo = { 0 };
         if( IsWindows8OrGreater() )
             exceptionInfo.ClientPointers = FALSE;
         else
             exceptionInfo.ClientPointers = TRUE;

         HANDLE hProcess =
            ::OpenProcess( PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, process.ProcessID() );
         exceptionInfo.ThreadId = GetThreadId(hProcess) ;
         EXCEPTION_POINTERS exceptionPointers;
         exceptionInfo.ExceptionPointers = &exceptionPointers;
         if( hProcess == INVALID_HANDLE_VALUE )
         {
            // error log
         }
         HANDLE hDumpFile = ::CreateFile( dump_path.wstring().c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
                                          FILE_ATTRIBUTE_NORMAL, NULL );
         if( hDumpFile == INVALID_HANDLE_VALUE )
         {
            ::CloseHandle( hProcess );
            // error log
         }
         auto res =
            ::MiniDumpWriteDump( hProcess, process.ProcessID(), hDumpFile,
                                 ( MINIDUMP_TYPE )( MiniDumpNormal | MiniDumpWithIndirectlyReferencedMemory |
                                                    MiniDumpWithDataSegs | MiniDumpWithFullMemory ),
                                 &exceptionInfo, nullptr, nullptr );
         ::CloseHandle( hProcess );
         ::CloseHandle( hDumpFile );
         if( res )
         {
            // work with dump
         }
         else
         {
            bfs::remove( dump_path );
            DWORD exceptionCode = exceptionInfo.ExceptionPointers->ExceptionRecord->ExceptionCode;
            String result = L"";
            switch (exceptionCode)
                {
                    case EXCEPTION_ACCESS_VIOLATION:
                        result = L"Access Violation Exception";
                        break;
                    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
                        result = L"Array Bounds Exceeded Exception";
                        break;
                    case EXCEPTION_BREAKPOINT:
                        result = L"Breakpoint Exception";
                        break;
                    case EXCEPTION_DATATYPE_MISALIGNMENT:
                        result = L"Datatype Misalignment Exception";
                        break;
                    case EXCEPTION_FLT_DENORMAL_OPERAND:
                        result = L"Floating Point Denormal Operand Exception";
                        break;
                    case EXCEPTION_FLT_DIVIDE_BY_ZERO:
                        result = L"Floating Point Divide By Zero Exception";
                        break;
                    case EXCEPTION_ILLEGAL_INSTRUCTION:
                        result = L"Illegal Instruction Exception";
                        break;
                    case EXCEPTION_IN_PAGE_ERROR:
                        result = L"In Page Error Exception";
                        break;
                    case EXCEPTION_INT_DIVIDE_BY_ZERO:
                        result = L"Integer Divide By Zero Exception";
                        break;
                    case EXCEPTION_INVALID_DISPOSITION:
                        result = L"Invalid Disposition Exception";
                        break;
                    case EXCEPTION_NONCONTINUABLE_EXCEPTION:
                        result = L"Noncontinuable Exception";
                        break;
                    case EXCEPTION_PRIV_INSTRUCTION:
                        result = L"Privileged Instruction Exception";
                        break;
                    case EXCEPTION_STACK_OVERFLOW:
                        result = L"Stack Overflow Exception";
                        break;
                    default:
                        result = L"Unknown Exception";
                        break;
                }
            ErrorMsg( Format( L"Error type: %1%"_sv, result ) );
         }
      }
      catch( ... )
      {
         // error log
      }
   }
}

核心问题分析

  1. EXCEPTION_POINTERS未初始化:代码中声明了EXCEPTION_POINTERS但未赋值,直接传入MiniDumpWriteDump会导致读取未初始化内存,得到的错误码是随机无效值。
  2. GetThreadId参数错误:GetThreadId需要传入线程句柄,代码中传入的是进程句柄hProcess,导致ThreadId值完全错误。
  3. 进程权限不足:OpenProcess仅请求了PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,生成全内存转储需要PROCESS_VM_OPERATION、PROCESS_DUP_HANDLE等额外权限。
  4. 错误码获取方式错误:非异常上下文下,EXCEPTION_POINTERS无效,应该用GetLastError()获取系统真实错误码。
  5. 转储类型冗余:MiniDumpWithFullMemory已包含MiniDumpNormal等类型的内容,重复指定可能引发兼容性问题。

修正后的代码

for( const auto& process : GetActiveProcesses() )
{
    if( process.ExeFile() == mProcessName )
    {
        try
        {
            String dump_name = GetDumpFileName( process.ProcessID() );
            bfs::wpath dump_path = assembly_directory / dump_name;

            MINIDUMP_EXCEPTION_INFORMATION exceptionInfo = { 0 };
            // 非异常上下文下,ExceptionPointers设为NULL即可,无需设置ClientPointers
            exceptionInfo.ThreadId = GetCurrentThreadId(); // 若需目标进程线程,需枚举其线程列表

            // 请求转储所需的完整权限
            HANDLE hProcess = ::OpenProcess( 
                PROCESS_VM_READ | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_DUP_HANDLE, 
                FALSE, 
                process.ProcessID() 
            );
            if( hProcess == INVALID_HANDLE_VALUE )
            {
                // 记录GetLastError()获取的权限错误
                continue;
            }

            HANDLE hDumpFile = ::CreateFile( 
                dump_path.wstring().c_str(), 
                GENERIC_WRITE, 
                0, 
                NULL, 
                CREATE_ALWAYS,
                FILE_ATTRIBUTE_NORMAL, 
                NULL 
            );
            if( hDumpFile == INVALID_HANDLE_VALUE )
            {
                ::CloseHandle( hProcess );
                // 记录文件创建错误
                continue;
            }

            // 简化转储类型,避免冗余
            auto res = ::MiniDumpWriteDump( 
                hProcess, 
                process.ProcessID(), 
                hDumpFile,
                (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithDataSegs),
                nullptr, // 无异常时传入NULL
                nullptr, 
                nullptr 
            );

            ::CloseHandle( hProcess );
            ::CloseHandle( hDumpFile );

            if( res )
            {
                // 处理转储文件
            }
            else
            {
                bfs::remove( dump_path );
                DWORD lastError = GetLastError();
                String result;
                switch (lastError)
                {
                    case ERROR_ACCESS_DENIED:
                        result = L"权限不足,无法访问目标进程";
                        break;
                    case ERROR_INVALID_HANDLE:
                        result = L"无效的进程或文件句柄";
                        break;
                    case ERROR_NOT_ENOUGH_MEMORY:
                        result = L"系统内存不足,无法生成转储";
                        break;
                    default:
                        result = Format(L"未知错误,错误码: %lu", lastError);
                        break;
                }
                ErrorMsg( result );
            }
        }
        catch( ... )
        {
            // 记录异常信息
        }
    }
}

关键修复说明

  • 移除无效的EXCEPTION_POINTERS:非异常场景下,直接将exceptionInfo.ExceptionPointers设为NULL,避免读取未初始化内存。
  • 修正ThreadId赋值:若生成当前进程转储,用GetCurrentThreadId();若需目标进程线程,需通过CreateToolhelp32Snapshot枚举其线程列表获取有效ID。
  • 补充进程权限:添加PROCESS_VM_OPERATION和PROCESS_DUP_HANDLE,满足全内存转储的权限要求。
  • 改用GetLastError()获取错误:MiniDumpWriteDump失败时,操作系统会设置错误码,调用GetLastError()才能拿到真实的失败原因。
  • 简化转储类型:保留MiniDumpWithFullMemory和MiniDumpWithDataSegs即可,减少冗余配置引发的兼容性问题。

内容的提问来源于stack exchange,提问作者TheKilAnt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 14:32:04