Ситуация: У нас есть приложение MFC / C ++ Visual Studio (2005), состоящее из множества исполняемых файлов и множества dll, все из которых используют MFC и связаны с DCOM.Некоторые из них работают на контроллере (w2012), который управляет подчиненными компьютерами, работающими на WES2009.
Проблема: В целях диагностики мы встраиваем мини-дампы во все наши процессы,Этот механизм прекрасно работает во всех процессах, кроме одного: GUI exe.Все процессы, включая GUI, делают файлы dmp НО содержимое файла dmp в GUI выглядит как другой / неправильный .Когда я намеренно завершаю работу нашего приложения, например, с разыменованием нулевого указателя, все dmp-файлы всех процессов / dll (кроме GUI) указывают на причину (разыменование нулевого указателя)!Файл dmp процесса графического интерфейса пользователя может быть открыт в Visual Studio, но ни один из потоков не указывает на причину (разыменование нулевого указателя).Также windbg не находит причину!Странно то, что когда мы вручную используем WriteStackDetails () для выгрузки стека вызовов, он возвращает правильную проблемную строку!Так почему же MinidumpWriteDump () не может сделать то же самое только для одного процесса?Что может быть отличительным фактором?Кто-нибудь есть идеи?
Что мы пробовали: Мы пробовали сбои во всех других процессах и DLL, и все они, кажется, работают нормально, за исключением процесса графического интерфейса!Unicode / non-Unicode, похоже, не имеет значения.Отдельное тестовое приложение работает хорошо, даже когда я связываю нашу библиотеку производственного кода, которая содержит UnhandledExceptionFilter () и MinidumpWriteDump ().Сбои в sub (-sub) dlls, похоже, не имеют значения.Настройки проекта в отношении обработки исключений выглядят одинаково.Кто-нибудь есть идеи?
Еще немного информации и замечаний:
Наш производственный код (контроллер и ведомые устройства) выполняется в отдельных виртуальных блоках для целей разработки.
да, мы понимаем, что в идеале мини-дамп должен быть создан из другого процесса (некоторый пример где-нибудь: «Запросы к процессу и безопасность»), но выполнение этого в процессе пока работает «всегда хорошо».Таким образом, на данный момент мы принимаем на себя риск того, что он может зависнуть в редких ситуациях.
То, что я имею в виду с содержимым файла dmp, отличается / неверно следующее: Для нашего ex-приложения без графического интерфейса мыполучить следующую информацию о потоке OK / стека вызовов: 0xC0000005: расположение чтения нарушения доступа 0x00000000.Studio автоматически открывает правильный источник, и точка останова устанавливается на ошибочную строку кода.На вкладке стека вызовов я вижу свои собственные функции в моей собственной DLL, которая вызвала сбой: разыменование нулевого указателя.На вкладке «Потоки» я также вижу свой активный поток и местоположение, которое также указывает на сбойную функцию, которая вызвала сбой.Так что в этой ситуации все хорошо и удобно!Супер удобная функциональность!
Для нашего исполняемого файла GUI, который ссылается на один и тот же код производственной библиотеки с кодом MinidumpWriteDump () и ExceptionHandlingFiler (), мы получаем следующую информацию о потоке / колл-стоке NOK: Необработанныйисключение в 0x77d66e29 (ntdll.dll) в our_exe_pid_2816_tid_2820_crash.dmp: 0xC0150010: Деактивированный контекст активации не активен для текущего потока выполнения Visual Studio 2005 не показывает мой неисправный код как причину!На вкладке Стек вызовов я не вижу свою собственную неисправную функцию.Вкладка «Стек вызовов» показывает, что проблема в ntdll.dll! RtlDeactivateActivationContextUnsafeFast () Самый верхний вызов функции, который показан в нашем коде, находится в совершенно другой вспомогательной dll-программе, которая не связана с моим намеренно введенным сбоем!Вкладка Темы также показывает то же самое.
Для обеих ситуаций я использую одну и ту же Visual Studio 2005 (работает на w7) с одинаковыми настройками путей символов !!!Также Visual Studio 2017 не может анализировать «неправильные» dmp-файлы.В промежутке между обоими тестами, приведенными выше, перестройка отсутствует, поэтому между exe / dll и pdbs не происходит несоответствия.В одной ситуации он работает нормально, а в другой нет!?!
Код упрощенного кода, который мы используем, показан ниже
typedef BOOL (_stdcall *tMiniDumpWriteDump)(HANDLE hProcess, DWORD dwPid, HANDLE hFile,
MINIDUMP_TYPE DumpType, CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
TCHAR CCrashReporter :: s_szLogFileNameDmp [MAX_PATH];CRITICAL_SECTION CCrashReporter :: s_csGuard;LPTOP_LEVEL_EXCEPTION_FILTER CCrashReporter :: s_previousFilter = 0;HMODULE CCrashReporter :: s_hDbgHelp = 0;tMiniDumpWriteDump CCrashReporter :: s_fpMiniDumpWriteDump = 0;
CCrashReporter :: CCrashReporter () {LoadDBGHELP ();
s_previousFilter = :: SetUnhandledExceptionFilter (Unhand);:: InitializeCriticalSection (& s_csGuard);}
CCrashReporter :: ~ CCrashReporter () {:: SetUnhandledExceptionFilter (s_previousFilter);
...
if (0! = S_hDbgHelp) {FreeLibrary (s_hDbgHelp);}
:: DeleteCriticalSection (& s_csGuard);}
LONG WINAPI CCrashReporter :: UnhandledExceptionFilter (PEXCEPTION_POINTERS pExceptionInfo) {:: EnterCriticalSection (& s_csGuard);
...
GenerateMinidump (pExNessFogShmpF):: LeaveCriticalSection (& s_csGuard);return EXCEPTION_EXECUTE_HANDLER;}
void CCrashReporter :: LoadDBGHELP () {/ * ... поиск кода dbghelp.dll ... * /
s_hDbgHelp = :: LoadLibrary (strDBGHELP_FILENAME);
if (0 == s_hDbgHelp) {/ * ... сообщить об ошибке ... * /}
if (0! = S_hDbgHelp) {...
s_fpMiniDumpWriteDump = (tMiniDumpWriteDump)GetProcAddress(s_hDbgHelp, "MiniDumpWriteDump");
if (!s_fpMiniDumpWriteDump)
{
FreeLibrary(s_hDbgHelp);
}
else
{
/* ... log ok ... */
}
}}
* * 1 077 аннулируются CCrashReporter :: GenerateMinidump (Const PEXCEPTION_POINTERS pExceptionInfo, LPCTSTR pszLogFileNameDmp) {HANDLE hReportFileDmp (:: CreateFile (pszLogFileNameDmp, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, 0));
if (INVALID_HANDLE_VALUE! = hReportFileDmp) {MINIDUMP_EXCEPTION_INFORMATION stMDEI;
stMDEI.ThreadId = ::GetCurrentThreadId();
stMDEI.ExceptionPointers = pExceptionInfo;
stMDEI.ClientPointers = TRUE;
if(!s_fpMiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(),
hReportFileDmp, MiniDumpWithIndirectlyReferencedMemory,
&stMDEI, 0, 0))
{
/* ... report error ...*/
}
else
{
/* ... report ok ... */
}
::CloseHandle(hReportFileDmp);
} else {/ * ... ошибка отчета ... * /}}