Фильтрация критических / фатальных исключений для использования с AddVectoredExceptionHandler - PullRequest
0 голосов
/ 21 февраля 2019

Я пытаюсь улучшить диагностику исключений (больше похоже на базовую обработку сбоев) в некоторых случаях, когда SetUnhandledExceptionFilter (https://msdn.microsoft.com/en-us/library/windows/desktop/ms680634(v=vs.85).aspx), похоже, не помогает при обнаружении фатальных ошибок. Например, при завершении работы и другом atexitфункции и одноэлементные деструкторы и т. д. работают (очищаются). Также вызывает беспокойство случай, когда деструктор завершает работу из-за несоответствующего объявления noexcept.

Использование AddVectoredExceptionHandler (https://msdn.microsoft.com/en-us/library/windows/desktop/ms679274(v=vs.85).aspx)на самом деле, вместо этого кажется хорошей альтернативой, поскольку он функционирует больше как «исключение первого случая» отладчика, однако поэтому он также вызывается (путём) слишком многих случаев (также нормальных исключений, некоторых сигналов и т. д.).

  1. В идеале был бы какой-то способ определить, будет ли обработано исключение
    или если в результате будет вызвано завершение.
  2. Код исключения - это еще один способ фильтрации -с созданным cpp кодом исключения throw очевидно, что он должен продолжаться - у меня такое ощущение, что это будет слишком многонакапливание проб или ошибок для получения «правильных» (фатальных) кодов исключений для фильтрации.

Ответы [ 2 ]

0 голосов
/ 26 февраля 2019

Обработчики VEH, добавленные AddVectoredExceptionHandler, будут обрабатывать исключения до того, как они достигнут обработчиков на основе фреймов.

Фильтр, установленный SetUnhandledExceptionFilter, будет обрабатывать исключения после сбоя обработчиков на основе фреймов.

Обаобычная обработка (например, try...except или try...catch) и обработчики сигналов реализованы как обработчики на основе кадров, как обработчики сигналов - как последние обработчики на основе кадров.

Нет надежного способа отличить fatal и нефатальные исключения до тех пор, пока не размотается цепь.И языковые исключения (код 0xE06D7363), иные программные исключения, и аппаратные исключения (например, нарушение доступа с кодом 0xC0000005) - все это может быть как фатальным, так и нефатальным.

Итак, AddVectoredExceptionHandlerвряд ли пригодится.Вам придется обрабатывать set_terminate, signal, _set_invalid_parameter_handler и т. Д. В дополнение к SetUnhandledExceptionFilter.

Вы можете убедиться, что обработчики signal вернутся к значениям по умолчанию, установив SIG_DFL, в этом случае он вернется к обработчику, установленному SetUnhandledExceptionFilter.

По умолчанию _set_invalid_parameter_handler преднамеренно не возвращается к обработчику, установленному в SetUnhandledExceptionFilter, но если вы установили свою функцию, переданную в _set_invalid_parameter_handler, чтобы вызвать ваше собственное исключение SEH, она вернется к обработчику, установленному SetUnhandledExceptionFilter.

Я не помню, что с set_terminate и другими.Вам нужно будет поэкспериментировать с этим.Но в крайнем случае вы всегда можете вызвать собственное исключение SEH, перехватить его с помощью __except и перейти к UnhandledExceptionFilter, тогда будет вызван ваш SetUnhandledExceptionFilter обратный вызов:

__try
{
     RaiseException(0xE0000001,0,0,NULL);
}
__except(UnhandledExceptionFilter(GetExceptionInformation()))
{
}
0 голосов
/ 22 февраля 2019

Что вы можете сделать, это добавить векторизованный обработчик исключений, но на самом деле не проверять там исключение, а либо сохранить его где-нибудь (поток отображения карты идентифицирует некоторую часть информации об исключении), и установить обработчик завершения - еслиэто называется, тогда вы знаете, что одно из исключений на вашей карте является ошибочным.Чтобы избежать хранения избыточных данных, добавьте локальный класс raii потока, который удаляет записи из карты после выхода из потока.Конечно, это своего рода снижение производительности (блокировка карты при каждом исключении), но если это действительно то, что вам нужно, то это правильный подход.

Общий код:

#include <exception>
#include <iostream>
#include <thread>

#include <Windows.h>

void termination_handler()
{
    // Look at the map, you will not know which one caused it but at least have all of them
    std::cout << "termination_handler called\n";
}

LONG VectoredExceptionHandler(_EXCEPTION_POINTERS *ExceptionInfo)
{
    // Put exception record somewhere - e.g map of thread ids to to exception record, maybe symbols
    return EXCEPTION_CONTINUE_SEARCH;
}

void foo()  
{
    throw std::exception();
}

int main(int argc, char** argv)
{
    AddVectoredExceptionHandler(0, VectoredExceptionHandler);
    std::set_terminate(termination_handler);
    std::thread t(foo);
    t.join();
    return 0;
}
...