Подтвердить что ты не робот

Какие действия необходимо предпринять для получения дампа сбоя во всех сценариях ошибок?

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

До сих пор мы определили и установили следующее:

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

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


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

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

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

Ответ 3

Высокий порядок, просто вкратце:

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

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

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

EDIT: просто прочитайте последнее содержание о завершении процесса. Вы не должны это контролировать. В любом случае вы можете просто подключить необходимые API-интерфейсы, которые будут действовать так, как вы кодируете (например, отображать окно сообщения).

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

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

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


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

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

Ответ 4

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

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

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

Ответ 5

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

Если вы хотите всегда захватывать excpetion in-process, вам необходимо предотвратить вызов SetUnhandledExceptionFilter(NULL) из CRT. Для получения дополнительной информации см. Мою запись в блоге: Улучшено "PreventSetUnhandledExceptionFilter"

Ответ 6

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

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

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

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

См. 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();
}