Russian Qt Forum

Qt => Кладовая готовых решений => Тема начата: Sergeich от Октябрь 30, 2010, 14:03



Название: Кросс-платформенный код для отлова крэшей
Отправлено: Sergeich от Октябрь 30, 2010, 14:03
Навеяно топиком "Ловля SIGSEGV через try/catch" (http://www.prog.org.ru/topic_15120_0.html)

  Иногда случаются ситуации, когда приходится пользовать нестабильно работающие компоненты, код которых нельзя изменить (например third-party ActiveX компоненты или плагины). Для отлова падений в этих компонетах можно использовать SEH под Windows (что это такое неплохо описано у Рихтера (http://flibusta.net/b/133375)) и sigaction/siglongjmp под UNIX. Приведенный ниже код - кроссплатформенная обертка, использующая эти методики. Использование этого кода чревато утечками памяти и не спасает от "кровавого месива", которое может устроить в памяти процесса нестабильно работающий компонент.
  Код тестировался на MacOSX 10.6, Windows XP SP3 (msvc) и Ubuntu Linux 10.10

Пример использования:
Код:
#include <stdio.h>
#include "crashhandler.h"

int main()
{
  try_exec {
    int* p = 0;
    ++(*p);
  }
  on_crash {
    printf( "It crashed!" );
  }
  printf( " ... but we still alive\n" );
  return 0;
}

crashhandler.h
Код:
///////////////////////////////////////////////////////////////////////////////
///
/// @file crashhandler.h
///
/// @brief Cross-platform implementation try/except statements for crash handling
///
/// @author Sergeich ( 2sergeich <at> gmail <dot> com )
///
///////////////////////////////////////////////////////////////////////////////

#ifndef CRASH_HANDLER_H
#define CRASH_HANDLER_H

#include <QtGlobal>

#ifdef Q_OS_UNIX

#include <setjmp.h>
#include <signal.h>

///////////////////////////////////////////////////////////////////////////////

typedef void (* SignalHandlerFunc) (int);

class SigactionWrap
{
public:
SigactionWrap( int signum, SignalHandlerFunc handler ) : sig_num(signum)
{
new_action.sa_handler = handler;
sigemptyset(&new_action.sa_mask);
new_action.sa_flags = 0;
sigaction (signum, &new_action, &old_action);
}

~SigactionWrap()
{
sigaction (sig_num, &old_action, 0);
}

private:
struct sigaction new_action, old_action;
int sig_num;
};

///////////////////////////////////////////////////////////////////////////////

static sigjmp_buf sigjmp_env;
static void crashHandler( int )
{
siglongjmp (sigjmp_env, 1);
}

#define try_exec \
SigactionWrap segvAct( SIGSEGV, crashHandler ); \
SigactionWrap  busAct( SIGBUS,  crashHandler ); \
SigactionWrap  illAct( SIGILL,  crashHandler ); \
SigactionWrap abrtAct( SIGABRT, crashHandler ); \
if ( sigsetjmp( sigjmp_env, 1 ) == 0 )

#define on_crash

#endif // Q_OS_UNIX

///////////////////////////////////////////////////////////////////////////////

#ifdef Q_OS_WIN32

#include <Windows.h>

#define try_exec __try
#define on_crash __except( EXCEPTION_EXECUTE_HANDLER )

#endif // Q_OS_WIN32


#endif // CRASH_HANDLER_H

В аттаче тест для сабжа


Название: Re: Кросс-платформенный код для отлова крэшей
Отправлено: zenden от Октябрь 30, 2010, 15:46
Нестабильные компоненты в продакшне? Боже упаси!  :o


Название: Re: Кросс-платформенный код для отлова крэшей
Отправлено: Sergeich от Октябрь 30, 2010, 19:27
Нестабильные компоненты в продакшне? Боже упаси!  :o
Иногда приходиться. Под виндой падает Windows Media Player, под маком - QuickTime и Quartz Composer


Название: Re: Кросс-платформенный код для отлова крэшей
Отправлено: SASA от Ноябрь 01, 2010, 13:10
Я увидел дефайны только для винды и никсов. А как происходит отлов исключений под MacOSX?


Название: Re: Кросс-платформенный код для отлова крэшей
Отправлено: Sergeich от Ноябрь 01, 2010, 16:17
Я увидел дефайны только для винды и никсов. А как происходит отлов исключений под MacOSX?
Mac OS X (http://ru.wikipedia.org/wiki/Mac_OS_X) -  POSIX-совместимая операционная система корпорации Apple.


Название: Re: Кросс-платформенный код для отлова крэшей
Отправлено: iukash от Апрель 18, 2011, 16:21
Не компилится. У меня Windows XP, Qt 4.7, Qt Creator с MinGW. Вот что в консоли
Цитировать
Widget.cpp: In member function 'void Widget::tryToCrash()':

Widget.cpp:38: error: expected 'catch' before '__except'

Widget.cpp:38: error: expected '(' before '__except'

Widget.cpp:38: error: expected type-specifier before '__except'

Widget.cpp:38: error: expected ')' before '(' token

Widget.cpp:38: error: expected '{' before '(' token

Widget.cpp:38: error: expected ';' before '{' token

Widget.cpp:40: warning: statement has no effect


Название: Re: Кросс-платформенный код для отлова крэшей
Отправлено: iukash от Апрель 28, 2011, 08:13
Заменил on_crash на catch(...), все собралось запустилось под виндой должен ловить, но не ловит!  :(


Название: Re: Кросс-платформенный код для отлова крэшей
Отправлено: iukash от Май 01, 2011, 12:05
Если поставить Qt под Visual Studio то все работает, проблема только под MinGW!  :(


Название: Re: Кросс-платформенный код для отлова крэшей
Отправлено: zenden от Май 01, 2011, 13:24
Потому что Mingw не умеет SEH. Странно, что авторы об этом не подумали...


Название: Re: Кросс-платформенный код для отлова крэшей
Отправлено: Sancho_s_rancho от Май 01, 2011, 15:26
Потому что Mingw не умеет SEH. Странно, что авторы об этом не подумали...
Конечно. Ведь SEH нестандартное расширение причем ломающее стандартный с++ (смешивать с++ исключения и SEH нельзя). Иными словами вас посадят на иглу (Microsoft c++).


Название: Re: Кросс-платформенный код для отлова крэшей
Отправлено: iukash от Май 25, 2011, 22:17
Цитировать
Не компилится. У меня Windows XP, Qt 4.7, Qt Creator с MinGW. Вот что в консоли
Цитировать
Widget.cpp: In member function 'void Widget::tryToCrash()':

Widget.cpp:38: error: expected 'catch' before '__except'

Widget.cpp:38: error: expected '(' before '__except'

Widget.cpp:38: error: expected type-specifier before '__except'

Widget.cpp:38: error: expected ')' before '(' token

Widget.cpp:38: error: expected '{' before '(' token

Widget.cpp:38: error: expected ';' before '{' token

Widget.cpp:40: warning: statement has no effect
Вот эта проблема не решена? Есть ли решения отлова исключения используя Windows и MinGW?