LINUX.ORG.RU

Секреты создания неубиваемых программ на C++

 ,


0

3

Хочется чтобы исключения c++, а также run-time исключения типа SEGFAULT и прочие не приводили к завершению работы программы.
Какие хуки, хаки, архитектурные извороты и прочие хитрости кто использует?
Как оно в продакшне, работает успешно?



Последнее исправление: nerdogeek (всего исправлений: 1)
Ответ на: комментарий от LongLiveUbuntu

А как у java с runtime-exceptions ?
Или их тоже можно отловить с успехом в catch?
Думаю что в этом плане там ситуация аналогичная для отказоустойчивых систем.

nerdogeek
() автор топика
Ответ на: комментарий от anonymous

Во вторых-код ПРИМИТИВЕН,до ужаса,на тойже джаве реализуется короче И ПОНЯТНЕЕ.

я не читал весь тот бред, что ниже, уж извините, мне достаточно одного - напишите аналог, этот примитивный до ужаса и короткий аналог, задача более подробно описана по ссылке чуть ниже

wota ★★
()
Ответ на: комментарий от nerdogeek

Все исключения, возникающие в твоем приложении, будут ловиться. Исключения самой Java-машины должна обрабатывать внешняя среда.

LongLiveUbuntu ★★★★★
()
Ответ на: комментарий от wota

ты идиот?

Отвези меня в космос,я не верю что земля круглая.

Что тебе еще сделать,весь список давай.

Ты требуешь пояснения банальным вещам.Я чувствую себя идиотом объясняя банальные вещи.

я не читал весь тот бред, что ниже

Неправда.Чтоб дать оценку «бред» ты сначала почитал.У вас очевидные проблемы с логикой,и демонстрируете это в который раз.

anonymous
()
Ответ на: комментарий от anonymous

Что тебе еще сделать,весь список давай.

я так и знал, что писать простыни текста для тебя более простая задача, чем написать «простой до ужаса пример»

Неправда.Чтоб дать оценку «бред» ты сначала почитал.

я сделал вывод на основании первых строк + капслока + !!!!!11111, сейчас прочитал все - вывод был верен

wota ★★
()
Ответ на: комментарий от tailgunner

respawn в inittab (уверен есть аналог этой фичи в любом upstart/systemd etc. дистр) всегда можно дописать, независимо от языка или типа исползуемой вм. а вот erlang ты зря пинаешь, он специально для непробиваемых приложений сделан.

nanoolinux ★★★★
()

watchdog делай или используй имеющийся функционал из upstart/systemd. Все остальные методы, в том числе перехват 11го сигнала, не работают в c++

Reset ★★★★★
()
Ответ на: комментарий от i-rinat

ничего не понял что я хотел сказать

Отладчик всё равно стопается на сигнале так что не ссы, а gссы.

queen3 ★★★★★
()

Погугли и обрящешь, например:

http://www.visualdata.ru/blog/109-segv-signal.html

Но:
- тот же -fnon-call-exceptions работает не для всех сигналов
- некоторые segv исправить не получится (например call по неверному адресу ещё можно исправить т.к. в стеке есть возврат, а вот jmp вряд ли)
- ты либо игнорируешь сигнал (и программа падает ещё раз) либо исправляешь его, а сделать это можно только переходом по валидному адресу. В лучшем случае ты сделаешь это исключением, в худшем longjmp-ом и твои RAII не сработают. В любом случае, если беда случится не в C++ коде то скорее всего твоя программа завершится т.к. исключение будет неожиданное. На этот случай у gcc есть -fno-enforce-eh-specs но и это не панацея.

В общем, тебе придётся изрядно поработать, чтобы оно хотя бы более-менее работало. Например, дополнительно неплохо бы перехватывать _pure_call. При сегфолте вручную дизассемблировать стек и пытаться восстановить адрес возврата (а вариантов call несколько). В специфичных случаях будет работать (например если гарантированно все вызовы - виртуальные через *%rxx), но в общем - нет.

Впрочем, в случаях когда не будет работать, ты всегда можешь сделать terminate(). Но это не «гарантированно» неубиваемая программа.

Где работает - например в языке D такое собирались сделать или сделали, см http://www.deadalnix.me/2012/03/24/get-an-exception-from-a-segfault-on-linux-...

queen3 ★★★★★
()

Без проблем работает в продакшне.

  • Первое правило - всегда писать код, безопасный к исключениям. Хотя библиотеки обычно исключений не бросают, любой оператор new (и любое изменение std::string/std::vector) может выбросить std::bad_alloc, dynamic_cast может выбросить std::bad_cast, потоки ввода-вывода тоже могут бросать исключения. Значит, если в одной строчке кода дважды вызывается new - перед вызовом второго new указатель, возвращённый первым, уже должен сохраниться в чём-то, что его уничтожит. Например:
    void canLeak()
    {
        A* pa = new A();
        B* pb = new B(); // вылетевшее здесь исключение, будучи перехваченным выше, всё равно вызовет утечку указателя A* pa.
    }
    void neverLeaks()
    {
        std::unique_ptr<A> pa(new A());
        std::unique_ptr<B> pb(new B());
    }
    
  • Второе - любые длительные задачи можно скинуть в отдельный поток и там перехватывать возможные исключения, после чего освобождать все ресурсы (либо они освободятся автоматически в деструкторах, либо грохнется единый пул памяти, например). Скажем, если программа грузит какой-нибудь *.doc и вдруг обнаруживает, что файл поломан - можно просто выбросить исключение, а на верхнем уровне (откуда была вызвана загрузка файла, но обязательно в том же потоке) его поймать и сообщить, что такой-то файл повреждён.
  • Третье - деструкторы никогда не должны бросать исключения. Конструкторы тоже не должны, если хранят сишный указатель на что-то; а вот если в полях класса есть только умные указатели - то бросать в принципе можно.
  • Что касается восстановления после креша: есть три типа сигнала: SIGILL, SIGFPE, SIGSEGV, их можно поймать в обработчике сигналов. Но тут проблема - в обработчике программа находится в неопределённом состоянии, и количество разрешённых действий крайне ограничего. Но pthread_exit сделать можно. А вот если надо ещё и почистить данные при выходе из потока - надо смотреть, как это сделано в llvm::CrashRecoveryContext. Как используется этот класс, можно глянуть в исходниках clang, например в реализации функции clang_parseTranslationUnit (кстати, этот сайт тоже работает на основе clang).
  • В 64-битных системах вероятность случайного нарушения памяти другого потока, как я понимаю, ничтожно мала - пруфов не видел. У данных текущего потока и правда можно проверить целостность, как вы и сказали.
quiet_readonly ★★★★
()
Ответ на: комментарий от quiet_readonly

Третье - деструкторы никогда не должны бросать исключения. Конструкторы тоже не должны, если хранят сишный указатель на что-то

на счёт конструкторов не факт. можно обернуть сишный указать в unique_ptr и в качестве деаллокатора установить close какой-нибудь. я такое подсмотрел в stackoverflow когда-то.

class Library
{
	public:
		Library(const char *str): dl_(::dlopen(str, 0), ::dlclose) {
			if (dl_.get() == NULL) {
				throw LibraryException("traly valy");
			}
		}
	private:
		unique_ptr <void, int (*)(void *)> dl_;
};

nanoolinux ★★★★
()
Ответ на: комментарий от nanoolinux

чёрт, я протупил.

class Library
{
	public:
		Library(const char *str){
			unique_ptr <void, int (*)(void *)> dl(::dlopen(str, 0), ::dlclose);
			if (dl.get() == NULL) {
				throw LibraryException("privet");
			}
                        // some other init of something here
			dl_ = dl.release();

		}
		~Library() {
			dlclose(dl_);
		}
	private:
		void *dl_;
                //some other types and vars
};

nanoolinux ★★★★
()

Ну, можно отлавливать сигналы. Но зачем, кроме как, в некоторых совсем уж ужасных случаях?

cattail
()

Кстати, если добавить хэндлер для SIGSEGV ( sigaction(SIGSEGV, &handler, 0) ), то ядро бесконечно будет вызывать этот хэндлер в случае SEGFAULT'а.
Так что как отлавливать SIGSEGV и продолжать дальше работать хз как.
В принципе, все что можно сделать при словленом SIGSEGV в хэндлере, это просигналить master-process'у чтоб он рестартанул наш процесс и затем вызвать exit/abort.

nerdogeek
() автор топика

Хочется чтобы исключения c++,

try {} catch (ex1& e) {} catch(...){handle unknown errors}

а также run-time исключения типа SEGFAULT

выпрямитель для рук

ckotinko ☆☆☆
()
Ответ на: комментарий от ckotinko

try {} catch (ex1& e) {} catch(...){handle unknown errors}

Вы в курсе что есть unhandled exceptions (std::set_unhandled) которые могут привести к безусловной остановке программы? Например из-за exception-specification: void m() throw(int) {throw 1.0;}

выпрямитель для рук

Всякое в жизни бывает. Особенно в чужих либах.

nerdogeek
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.