Мы находимся на Windows и хотим получить аварийный дамп (возможно, используя MiniDumpWriteDump
) за все сценарии, когда наше приложение неожиданно завершает работу.
Итак, мы определили и настроили следующее:
SetUnhandledExceptionFilter
для необработанного исключения (Win32, а также «нормальные» C ++.)_set_invalid_parameter_handler
для некорректной обработки аргументов CRT_set_abort_behavior
плюс SIGABRT
обработчик для учета звонков abort()
Мы что-то пропустили? (По модулю некоторый код неправомерно вызывает ExitProcess
, TerminateProcess
или один из exit
варианты.)
Отмечу, что этот вопрос здесь ортогонален как затем получается аварийный дамп. Например, если вы хотите аварийный дамп в случае abort
, вы всегда должны использовать _set_abort_behaviour
потому что иначе просто прервать exit
s.
Также отмечу, что в Windows7 + не установка SetUHEF
и просто настраивая «правильные» настройки дампа WER в реестре часто жизнеспособный способ.
Я использую именно те, которые вы перечислили, плюс _set_purecall_handler
плюс этот удобный фрагмент кода:
void EnableCrashingOnCrashes()
{
typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags);
typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags);
static const DWORD EXCEPTION_SWALLOWING = 0x1;
const HMODULE kernel32 = LoadLibraryA("kernel32.dll");
const tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, "GetProcessUserModeExceptionPolicy");
const tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, "SetProcessUserModeExceptionPolicy");
if(pGetPolicy && pSetPolicy)
{
DWORD dwFlags;
if(pGetPolicy(&dwFlags))
{
// Turn off the filter
pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING);
}
}
}
Источник:
http://randomascii.wordpress.com/2012/07/05/when-even-crashing-doesnt-work/
Эти другие статьи на его сайте также помогли мне понять это:
http://randomascii.wordpress.com/2011/12/07/increased-reliability-through-more-crashes/
http://randomascii.wordpress.com/2012/07/22/more-adventures-in-failing-to-crash-properly/
SetUnhandledExceptionFilter категорически недостаточно для захвата всех неожиданных выходов. Если приложение случайно вызывает чисто виртуальную функцию, появится диалоговое окно. Приложение будет зависать, но не вылетает. Поскольку здесь нет исключений, ни SetUnhandledExceptionFilter, ни WER не могут помочь. Есть несколько вариантов на эту тему.
Что еще хуже, это странность, если вы зависаете в обратном вызове ядра, таком как WindowProc. Если это происходит в 32-битном приложении в 64-битной Windows, то ОС ловит исключение, и выполнение продолжается. Да, авария тихо передана. Я нахожу это ужасным.
http://randomascii.wordpress.com/2012/07/05/when-even-crashing-doesnt-work/ следует подробно описать все приемы, необходимые для обработки этих необычных случаев.
Высокий заказ, вкратце:
_set*
функции, SetUnhandledExceptionFilter
достаточно для всех.abort
отключит глобальный обработчик исключений, который вы настроили с помощью SetUnhandledExceptionFilter
, ЭЛТ просто вызовет эту же функцию NULL
параметр, и ваш обработчик исключений отключен (не вызывается), если CRT вызывает сбой! Что ты можешь сделать? [ИКС]CreateToolhelp32Snapshot
и другие функции. Найдите этот процесс и приостановите все остальные запущенные потоки (кроме текущих, конечно).Есть еще кое-что, что я не пробовал (не нашел полезности) — Vectored Exception Handling.
Еще один подход — запустить приложение в отладчике, который вы можете создать самостоятельно! В отладчике вы можете перехватить ВСЕ исключения, так же как отладчик VS отлавливает. См мой статья. Но, вы знаете, это не правильный подход.
РЕДАКТИРОВАТЬ: Просто прочитайте последний контент о завершении процесса. Вы не должны это контролировать. В любом случае вы можете просто подключить необходимые API, которые будут действовать как то, для чего вы кодируете (например, отображение окна сообщения).
[ИКС] Вам нужно использовать перехват API. У меня нет ссылки и подробностей под рукой. Вы бы подключили другие связанные API, но в первую очередь SetUnhandledExceptionFilter
(после того, как ты назвал это для тебя). Ваша фиктивная (подключенная) функция будет выглядеть так:
xxx SetUnhandledExceptionFilter_DUMMY(xxx)
{
// Dont do any thing
return NULL;
}
У меня нет ссылки и подробностей о подключении API под рукой.
И почему бы не попытаться сделать ваше приложение более безопасным?
Я добавлю обходной путь, который можно использовать в определенных сценариях при работе в Windows 7:
Отчет об ошибках Windows (WER) предлагает возможность записать полный дамп памяти при сбое приложения.
Так что, если вы в порядке с этим, вы просто должны убедиться, что сценарии сбоя, которые вас действительно интересуют, вызовут WER. … Что, действительно, возвращает нас к этому самому вопросу, но все же …
Вы можете поймать любое исключение с WER. Как вы уже видели, ЭЛТ иногда заставляет звонить WER.
Если вы хотите всегда обрабатывать исключения в процессе, вам нужно предотвратить вызов SetUnhandledExceptionFilter(NULL)
из ЭЛТ. Для получения дополнительной информации см. Мою запись в блоге: Улучшен «PreventSetUnhandledExceptionFilter»
Чтобы развернуть все ответы, я считаю, что лучше всего подходит для 100M + установок:
станд :: set_terminate а также станд :: set_unexpected возможно, следует также упомянуть.
И самая важная часть, чтобы получить все в порядке:
См. SetExceptionHandlers ниже для справки. Кроме того, скорее всего, вы не хотите подключать все обработчики в отладочных сборках или когда IsDebuggerPresent.
#include <signal.h>
#include <windows.h>
#include <boost/thread/mutex.hpp>
void EnableCrashingOnCrashes();
void PreventSetUnhandledExceptionFilter();
static void exceptionHandler(EXCEPTION_POINTERS* excpInfo)
{
// your code to handle the exception. Ideally it should
// marshal the exception for processing to some other
// thread and waif for the thread to complete the job
}
static boost::mutex unhandledExceptionMx;
static LONG WINAPI unhandledException(EXCEPTION_POINTERS* excpInfo = NULL)
{
boost::mutex::scoped_lock lock(unhandledExceptionMx);
if (!excpInfo == NULL)
{
__try // Generate exception to get proper context in dump
{
RaiseException(EXCEPTION_BREAKPOINT, 0, 0, NULL);
}
__except (exceptionHandler(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER)
{
}
}
else
{
exceptionHandler(excpInfo);
}
return 0;
}
static void invalidParameter(const wchar_t* expr, const wchar_t* func,
const wchar_t* file, unsigned int line, uintptr_t reserved)
{
unhandledException();
}
static void pureVirtualCall()
{
unhandledException();
}
static void sigAbortHandler(int sig)
{
// this is required, otherwise if there is another thread
// simultaneously tries to abort process will be terminated
signal(SIGABRT, sigAbortHandler);
unhandledException();
}
static void setExceptionHandlers()
{
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
SetUnhandledExceptionFilter(unhandledException);
_set_invalid_parameter_handler(invalidParameter);
_set_purecall_handler(pureVirtualCall);
signal(SIGABRT, sigAbortHandler);
_set_abort_behavior(0, 0);
EnableCrashingOnCrashes();
PreventSetUnhandledExceptionFilter();
}