如果可能的话,应该从单独的进程中调用
MiniDumpWriteDump,而不是从正在转储的目标进程中调用。
所以我编写了一个小的MFC崩溃处理程序就是这样做的。我遵循Hans在这就是答案中的建议,即将异常指针的值从崩溃程序传递给崩溃处理程序,即使异常指针在崩溃处理程序的上下文中无效。当我在调试版本中运行测试时,这很好,但是当我切换到发布版本时,崩溃处理程序就会崩溃,MiniDumpWriteDump函数内部会发生访问冲突。
我很困惑。为什么在调试版本中应该这样做,而在发布版本中却不能这样做呢?这令人恼火,因为访问冲突通常是访问无效指针的指示符,而我在崩溃处理程序中接收到的异常指针确实是无效的--但另一方面,我被告知,这不重要,因为MiniDumpWriteDump是在崩溃过程的上下文中解释指针的(从指针的起源地)。
知道我可能做错了什么吗?
在一个侧面:在他的回答中,汉斯提出了一个解决方案,其中的看门狗进程是预先启动,然后进入睡眠和醒来时,它被触发的过程。我的解决方案略有不同:我只是在崩溃发生时启动崩溃处理程序,然后通过命令行参数将必要的信息从崩溃程序传递给崩溃处理程序。我反复检查正在传递的信息是否正确,特别是异常指针.
发布于 2017-04-24 15:09:42
我改变了我的方法,这样最终的解决方案看起来就像汉斯·帕桑( Hans )建议的那样:看门狗进程是预先启动的,然后进入睡眠状态,当它被崩溃过程触发时醒来。崩溃过程对EXCEPTION_POINTERS结构进行深度复制,并将该信息传递给看门狗进程。
这是做深拷贝的代码。正如问题的注释中提到的,主要的“问题”是EXCEPTION_RECORD,它是一个潜在无限大小的链接列表。
// 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引用指向无效的内存地址,即仅在崩溃过程中有效的内存地址。下面的函数(必须在监视狗进程中运行)修复了这些引用。
// 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函数了。
注意:显然这不是一个完整的解决方案。您可能希望将更多的信息从崩溃过程传递给看门狗进程。CrashInfo结构是保存此信息的候选结构。此外,这里没有显示进程如何相互通信的方式。在我的例子中,我使用Hans提出的解决方案,该解决方案在问题的开头链接:使用事件进行同步(CreateEvent + SetEvent)和使用内存映射文件(CreateFileMapping + MapViewOfFile)将信息从一个进程洗牌到下一个进程。事件和内存映射文件的(唯一)名称由主进程确定,并通过命令行参数传递给看门狗进程。
发布于 2016-09-22 21:34:24
我与一个类似的问题斗争,现在终于发现了什么是错误的。
信息的MSDN文档指出,如果ClientPointers地址来自目标进程而不是本地进程,则ExceptionPointers字段必须是TRUE。
在正确设置这个字段之后,我可以简单地从崩溃过程中传递ThreadId和ExceptionPointers,并将它们填充到转储写入过程中的MINIDUMP_EXCEPTION_INFORMATION中,并且它工作得非常完美。
https://stackoverflow.com/questions/32691914
复制相似问题