Преобразование std::exception в EXCEPTION_POINTERS

Возможно, я полностью неправильно понимаю, как использовать Google Breakpad API, и в таком случае я открыт для комментариев/предложений/грубых замечаний. Я пытаюсь вызвать следующую функцию С++:

bool WriteMinidumpForException(EXCEPTION_POINTERS* exinfo);

У меня есть ссылка на std::exception:

try {
  return QApplication::notify(receiver, event);
} catch (std::exception &ex) {
  eh_.WriteMinidumpForException(?????);
  // ... do some more stuff and ultimately kill this process
}

(eh_ is a google_breakpad::ExceptionHandler.)

Что мне указать в ?????

Предыстория: Причина, по которой это необходимо (я думаю), заключается в том, что Qt не поддерживает исключение, генерируемое в обработчике событий. Оно не будет распространяться корректно, поэтому мини-дамп, создаваемый Breakpad, совершенно бесполезен, поскольку фактический контекст исключения был утерян. Вместо этого вы должны перехватывать все исключения и обрабатывать их в переопределении QApplication::notify(), что я и пытаюсь сделать. В случае исключения я хочу немедленно написать свой мини-дамп для этого исключения (что звучит так, как будто WriteMinidumpForException подойдет), а затем уведомить пользователя и выйти из приложения. Но я не уверен, что передать как параметр EXCEPTION_POINTERS*.


person Dave Mateer    schedule 15.03.2011    source источник


Ответы (2)


В компиляторе MSVC исключения C++ подключаются к собственной системе обработки исключений Windows (SEH, структурированная обработка исключений). Однако существует довольно большое несоответствие импеданса, концепция фильтра исключений не имеет хорошего соответствия в C++. К тому времени, когда обработчик catch перехватывает исключение, исключение SEH уже обработано и стек раскручен. Информация EXCEPTION_POINTERS невероятна. Фильтры исключений на самом деле существуют, именно так они фильтруют определенный тип, который вы хотите поймать, однако они автоматически генерируются компилятором. Не существует разумного синтаксиса C++, чтобы сделать их полезными.

Вам нужно погрузиться в поддержку компилятора для обработки исключений SEH. Используйте ключевые слова __try, __except (__finally является необязательным), и ваш фильтр улавливает код исключения для исключения C++, 0xe04d5343 ("MSC"). Однако вы теряете возможность перехватывать определенный тип исключения C++, который скрыт в CRT без источника. Поместите C++ try внутри __try, чтобы исправить это, чтобы ваш __except видел только исключения, которые код C++ не фильтровал.

Использование SetUnhandledExceptionFilter() - еще один способ сделать это, кстати, вы действительно должны рассматривать его как окончательную поддержку любого необработанного исключения, независимо от местоположения кода. Это лучший способ создать мини-дамп сбойного приложения. И последнее, но не менее важное: создание мини-дампа падающего приложения внутри самого процесса — не лучший подход. Есть много шансов, что это не сработает, состояние процесса может быть довольно сильно повреждено. Одним из режимов отказа является блокировка кучи процесса. Не исключено, учитывая, что повреждение кучи является очень распространенной причиной сбоев. Исправьте это с помощью «защитного процесса», используйте именованное событие, чтобы сигнализировать о создании минидампа. Вашему фильтру исключений нужно только установить событие, которое всегда работает.

person Hans Passant    schedule 15.03.2011
comment
Спасибо, это отличная информация. Я пытаюсь использовать библиотеку паузы Google, которая (как я понимаю) делает то, что вы описали выше (используя SetUnhandledExceptionFilter и т. д.). Но Qt не очень хорошо работает, когда из обработчика событий генерируется исключение (что в приложении с графическим интерфейсом является в значительной степени основным случаем), поэтому мне приходится обойти это, заставляя breakpad писать минидамп по запросу. Используя __try, теперь я не могу использовать __try в функциях, требующих раскручивания объекта вздох - person Dave Mateer; 15.03.2011
comment
Используйте небольшую вспомогательную функцию, которая сама не содержит объектов C++ с деструкторами, чтобы вызвать функцию обработки событий. - person Hans Passant; 15.03.2011
comment
У меня возникли проблемы с созданием вспомогательной функции. Мне нужно вызвать QApplication::notify() из MyApplication::notify() (MyApplication наследуется от QApplication). Можно ли вызвать вызов базового класса из функции, не являющейся членом? (Я предполагаю, что мне понадобится функция, не являющаяся членом, поскольку мой класс использует деструктор.) - person Dave Mateer; 15.03.2011

Исключения Windows SEH и С++ никак не связаны друг с другом - простой способ решить эту проблему - использовать собственную оболочку __try __except, например. разыменование нулевого указателя.

Что-то типа:

__try {
  * (int *) 0 = 0;
} 
__except 
    (
        eh_.WriteMinidumpForException(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER
    ) 
{
}
person Erik    schedule 15.03.2011