Какие действия мне нужно предпринять, чтобы получить аварийный дамп во ВСЕХ сценариях ошибок?

Мы находимся на Windows и хотим получить аварийный дамп (возможно, используя MiniDumpWriteDump) за все сценарии, когда наше приложение неожиданно завершает работу.

Итак, мы определили и настроили следующее:

  • SetUnhandledExceptionFilter для необработанного исключения (Win32, а также «нормальные» C ++.)
  • _set_invalid_parameter_handler для некорректной обработки аргументов CRT
  • _set_abort_behaviorплюс SIGABRT обработчик для учета звонков abort()

Мы что-то пропустили? (По модулю некоторый код неправомерно вызывает ExitProcess, TerminateProcess или один из exit варианты.)


Отмечу, что этот вопрос здесь ортогонален как затем получается аварийный дамп. Например, если вы хотите аварийный дамп в случае abort, вы всегда должны использовать _set_abort_behaviour потому что иначе просто прервать exits.

Также отмечу, что в Windows7 + не установка SetUHEF и просто настраивая «правильные» настройки дампа WER в реестре часто жизнеспособный способ.

12

Решение

Я использую именно те, которые вы перечислили, плюс _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/

6

Другие решения

SetUnhandledExceptionFilter категорически недостаточно для захвата всех неожиданных выходов. Если приложение случайно вызывает чисто виртуальную функцию, появится диалоговое окно. Приложение будет зависать, но не вылетает. Поскольку здесь нет исключений, ни SetUnhandledExceptionFilter, ни WER не могут помочь. Есть несколько вариантов на эту тему.

Что еще хуже, это странность, если вы зависаете в обратном вызове ядра, таком как WindowProc. Если это происходит в 32-битном приложении в 64-битной Windows, то ОС ловит исключение, и выполнение продолжается. Да, авария тихо передана. Я нахожу это ужасным.

http://randomascii.wordpress.com/2012/07/05/when-even-crashing-doesnt-work/ следует подробно описать все приемы, необходимые для обработки этих необычных случаев.

2

Высокий заказ, вкратце:

  • Вам не нужно использовать какие-либо другие _set* функции, SetUnhandledExceptionFilter достаточно для всех.
  • C времени выполнения функций, таких как abort отключит глобальный обработчик исключений, который вы настроили с помощью SetUnhandledExceptionFilter, ЭЛТ просто вызовет эту же функцию NULL параметр, и ваш обработчик исключений отключен (не вызывается), если CRT вызывает сбой! Что ты можешь сделать? [ИКС]
  • Отключите все остальные запущенные потоки, когда вызывается обработчик исключения. Просто найдите все темы, используя CreateToolhelp32Snapshotи другие функции. Найдите этот процесс и приостановите все остальные запущенные потоки (кроме текущих, конечно).
  • Используйте SEH или no-SEH, вызывается обработчик глобальных исключений, если CRT не вмешивается. Не переживать (в большинстве случаев).
  • Не делайте промежуточных CLR, это не позволит обработчику исключений вызывать, если между ними будет какой-либо CLR / управляемый вызов (да из C / C ++).
  • Вы не можете обработать одно исключение — переполнение стека! Считать! Запуск под отладчиком является единственным решением, см. Ниже.

Есть еще кое-что, что я не пробовал (не нашел полезности) — Vectored Exception Handling.

Еще один подход — запустить приложение в отладчике, который вы можете создать самостоятельно! В отладчике вы можете перехватить ВСЕ исключения, так же как отладчик VS отлавливает. См мой статья. Но, вы знаете, это не правильный подход.

РЕДАКТИРОВАТЬ: Просто прочитайте последний контент о завершении процесса. Вы не должны это контролировать. В любом случае вы можете просто подключить необходимые API, которые будут действовать как то, для чего вы кодируете (например, отображение окна сообщения).

[ИКС] Вам нужно использовать перехват API. У меня нет ссылки и подробностей под рукой. Вы бы подключили другие связанные API, но в первую очередь SetUnhandledExceptionFilter (после того, как ты назвал это для тебя). Ваша фиктивная (подключенная) функция будет выглядеть так:

xxx SetUnhandledExceptionFilter_DUMMY(xxx)
{
// Dont do any thing
return NULL;
}

У меня нет ссылки и подробностей о подключении API под рукой.


И почему бы не попытаться сделать ваше приложение более безопасным?

  • Исправьте все предупреждения (да, даже уровень 4).
  • Используйте статический анализ. Сама VS есть (но в более высоких версиях. За исключением 2012 года — все варианты есть). Другие инструменты SA доступны.
  • Сделайте тщательный анализ кода. Это платит!
  • Запустите и отладьте вашу сборку RELEASE из отладчика. Используйте все функции.
  • Посмотрите и исправьте все возможные утечки памяти.
  • Используйте защитный подход к программированию. Вместо того, чтобы проверять нулевое значение, защитите его с помощью ASSERT или своего собственного утверждения. Упакуйте это с утверждением, журналом, возвращением из функции.
1

Я добавлю обходной путь, который можно использовать в определенных сценариях при работе в Windows 7:

Отчет об ошибках Windows (WER) предлагает возможность записать полный дамп памяти при сбое приложения.

Так что, если вы в порядке с этим, вы просто должны убедиться, что сценарии сбоя, которые вас действительно интересуют, вызовут WER. … Что, действительно, возвращает нас к этому самому вопросу, но все же …

0

Вы можете поймать любое исключение с WER. Как вы уже видели, ЭЛТ иногда заставляет звонить WER.

Если вы хотите всегда обрабатывать исключения в процессе, вам нужно предотвратить вызов SetUnhandledExceptionFilter(NULL) из ЭЛТ. Для получения дополнительной информации см. Мою запись в блоге: Улучшен «PreventSetUnhandledExceptionFilter»

0

Чтобы развернуть все ответы, я считаю, что лучше всего подходит для 100M + установок:

станд :: set_terminate а также станд :: set_unexpected возможно, следует также упомянуть.

И самая важная часть, чтобы получить все в порядке:

  • все эти обработчики должны вызывать функцию, которая выполняется в секции мьютекса / критического состояния, чтобы гарантировать, что если в других потоках одновременно произойдут какие-либо другие сбои, все они остановятся и будут ждать, а не вызывать хаос.
  • обработчик сигнала для SIGABRT должен установить себя как обработчик SIGABRT! Без этого, если вы получаете сбои, происходящие в то же время из других потоков, процесс, который вы обрабатываете, немедленно завершается, не давая вам времени для обработки сбоя.
  • фактическая обработка ошибки в идеале должна происходить в другом процессе или, по крайней мере, в другом потоке, который был запущен в начале процесса, в противном случае вы не сможете обрабатывать условия нехватки памяти или ошибки переполнения стека.

См. 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();
}
0
По вопросам рекламы [email protected]