在进程外调用MiniDumpWriteDump中的访问冲突 [英] Access violation in MiniDumpWriteDump when invoked out-of-process

查看:122
本文介绍了在进程外调用MiniDumpWriteDump中的访问冲突的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

MiniDumpWriteDump函数的文档指出

MiniDumpWriteDump应该尽可能从一个单独的进程中调用,而不是从正在转储的目标进程中调用.

MiniDumpWriteDump should be called from a separate process if at all possible, rather than from within the target process being dumped.

所以我写了一个小型的MFC崩溃处理程序程序.我遵循了Hans Passant在此SO答案中的建议,即我正在从崩溃的程序中传递异常指针的值即使异常指针在崩溃处理程序的上下文中无效,也可以将其添加到崩溃处理程序.当我在调试版本中运行测试时,此方法效果很好,但是当我切换到发行版本时,崩溃处理程序程序崩溃,并且在MiniDumpWriteDump函数内部发生访问冲突.

So I wrote a small MFC crash handler program that does just that. I followed the advice in this SO answer by Hans Passant, i.e. I am passing the value of the exception pointer from the crashing program to the crash handler program even though the exception pointer is not valid in the context of the crash handler program. This works well when I run tests in a debug build, but when I switch to a release build the crash handler program crashes, with an access violation that occurs inside the MiniDumpWriteDump function.

我很困惑.为什么这在调试版本中有效,而在发行版本中无效?这很令人发疯,因为访问冲突通常是访问无效指针的指示,并且我在崩溃处理程序中接收到的异常指针确实是无效的-但另一方面,我被告知这无关紧要,因为MiniDumpWriteDump解释了崩溃过程中的指针(指针起源).

I am stumped. Why should this work in debug builds, but not in release builds? It's maddening because access violations often are indicators for accessing invalid pointers, and the exception pointer I am receiving in the crash handler program is indeed invalid - but on the other hand I am told that this should not matter, that MiniDumpWriteDump is interpreting the pointer in the context of the crashing process (from where the pointer originated).

有什么主意我可能做错了吗?

Any ideas what I could be doing wrong?

在旁注中:汉斯(Hans)提出了一个解决方案,其中预启动看门狗进程,然后进入睡眠状态,然后由崩溃进程触发唤醒.我的解决方案略有不同:我只是在发生崩溃时启动崩溃处理程序,然后将必要的信息从崩溃程序通过命令行参数传递给崩溃处理程序.我仔细检查了传递的信息是否正确,特别是异常指针.

On a sidenote: In his answer, Hans proposes a solution where the watchdog process is pre-launched, then goes to sleep and wakes up when it is triggeredd by the crashing process. My solution is slightly different: I am simply launching the crash handler program at the time when the crash occurs, then I pass the necessary information from the crashing program to the crash handler program via command line arguments. I double-checked that the information being passed is correct, specifically the exception pointer.

推荐答案

我更改了方法,使最终解决方案看起来像汉斯·帕桑特(Hans Passant)建议的那样:看门狗进程已预先启动,然后进入睡眠状态并醒来.当它由崩溃进程触发时.崩溃进程对EXCEPTION_POINTERS结构进行了深复制,并将该信息传递给看门狗进程.

I changed my approach so that the final solution looks like the one suggested by Hans Passant: The watchdog process is pre-launched, then goes to sleep and wakes up when it is triggeredd by the crashing process. The crashing process makes a deep-copy of the EXCEPTION_POINTERS structure and passes that information to the watchdog process.

这是进行深度复制的代码.正如对该问题的评论中所提到的,主要的问题"是EXCEPTION_RECORD,它是一个可能无限大小的链表.

Here's the code that makes the deep-copy. As mentioned in the comments to the question, the main "problem" is EXCEPTION_RECORD which is a linked-list of potentially unlimited size.

// The maximum number of nested exception that we can handle. The value we
// use for this constant is an arbitrarily chosen number that is, hopefully,
// sufficiently high to support all realistic and surrealistic scenarios.
//
// sizeof(CrashInfo) for a maximum of 1000 = ca. 80 KB
const int MaximumNumberOfNestedExceptions = 1000;


// Structure with information about the crash that we can pass to the
// watchdog process
struct CrashInfo
{
    EXCEPTION_POINTERS exceptionPointers;
    int numberOfExceptionRecords;
    // Contiguous area of memory that can easily be processed by memcpy
    EXCEPTION_RECORD exceptionRecords[MaximumNumberOfNestedExceptions];
    CONTEXT contextRecord;
};


// The EXCEPTION_POINTERS parameter is the original exception pointer
// that we are going to deep-copy.
// The CrashInfo parameter receives the copy.
void FillCrashInfoWithExceptionPointers(CrashInfo& crashInfo, EXCEPTION_POINTERS* exceptionPointers)
{
    // De-referencing creates a copy
    crashInfo.exceptionPointers = *exceptionPointers;
    crashInfo.contextRecord = *(exceptionPointers->ContextRecord);

    int indexOfExceptionRecord = 0;
    crashInfo.numberOfExceptionRecords = 0;
    EXCEPTION_RECORD* exceptionRecord = exceptionPointers->ExceptionRecord;

    while (exceptionRecord != 0)
    {
        if (indexOfExceptionRecord >= MaximumNumberOfNestedExceptions)
        {
            // Yikes, maximum number of nested exceptions reached
            break;
        }

        // De-referencing creates a copy
        crashInfo.exceptionRecords[indexOfExceptionRecord] = *exceptionRecord;

        ++indexOfExceptionRecord;
        ++crashInfo.numberOfExceptionRecords;
        exceptionRecord = exceptionRecord->ExceptionRecord;
    }
}

当我们在看门狗进程中接收到CrashInfo结构时,我们现在遇到一个问题:EXCEPTION_RECORD引用指向无效的内存地址,即仅在崩溃过程中有效的内存地址.以下功能(必须在看门狗进程中运行)可以修复这些引用.

When we receive the CrashInfo structure in the watchdog process we now have a problem: The EXCEPTION_RECORD references are pointing to invalid memory addresses, i.e. to memory addresses that are valid only in the crashing process. The following function (which must be run in the watchdog process) fixes those references.

// The CrashInfo parameter is both in/out
void FixExceptionPointersInCrashInfo(CrashInfo& crashInfo)
{
    crashInfo.exceptionPointers.ContextRecord = &(crashInfo.contextRecord);

    for (int indexOfExceptionRecord = 0; indexOfExceptionRecord < crashInfo.numberOfExceptionRecords; ++indexOfExceptionRecord)
    {
        if (0 == indexOfExceptionRecord)
            crashInfo.exceptionPointers.ExceptionRecord = &(crashInfo.exceptionRecords[indexOfExceptionRecord]);
        else
            crashInfo.exceptionRecords[indexOfExceptionRecord - 1].ExceptionRecord = &(crashInfo.exceptionRecords[indexOfExceptionRecord]);
    }
}

我们现在准备将&(crashInfo.exceptionPointers)传递给MiniDumpWriteDump函数.

We are now ready to pass &(crashInfo.exceptionPointers) to the MiniDumpWriteDump function.

注意:显然,这不是一个完整的解决方案.您可能希望将更多信息从崩溃过程传递到看门狗过程. CrashInfo结构是保存此信息的候选者.此外,此处未显示进程之间如何通信的方式.在我的情况下,我采用了汉斯·帕桑特(Hans Passant)提出的解决方案,该解决方案在问题的开头进行了链接:使用一个事件进行同步(CreateEvent + SetEvent)和一个内存映射文件(CreateFileMapping + MapViewOfFile)从一个进程中清除信息到下一个.事件和内存映射文件的(唯一)名称由主进程确定,并通过命令行参数传递给看门狗进程.

Note: Obviously this is not a complete solution. You will probably want to pass more info from the crashing process to the watchdog process. The CrashInfo structure is the candidate to hold this information. Also the way how the processes communicate with each other is not shown here. In my case I went with the solution presented by Hans Passant which is linked at the beginning of the question: Use an event for synchronization (CreateEvent + SetEvent) and a memory-mapped file (CreateFileMapping + MapViewOfFile) to shuffle the information from one process to the next. The (unique) names of the event and the memory-mapped file are determined by the main process and passed to the watchdog process via command line arguments.

这篇关于在进程外调用MiniDumpWriteDump中的访问冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆