LINUX.ORG.RU

gcc, SIGSEGV и try/catch теперь друзья :)


0

0

Я нарыл способ преобразовывать сигналы типа SIGSEGV в исключения языка C++, которые можно ловить по try/catch, так как это происходит, например, в виндовых компиляторах.

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

Сразу прошу не разводить флуд, мол не надо ловить - правильно падать. Прошу потестить подход на различных платформах, версиях компилятора gcc.

Еще хочу сделать на базе этого кроссплатформенную либу под LGPL, облегчающую эту обработку. Не могу придумать название - libsigsegv, libseh уже есть, пока в голову приходит только libsegv или libsegvcatch :)

PS. Уже проверил на opensuse 11.1, на gentoo компилятор gcc-4.3, на MCBC, компилятор gcc-3.3, платформа i386.

gcc, SIGSEGV и try/catch теперь друзья :)

Это непортабельно.

mv ★★★★★ ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от mv

gcc, SIGSEGV и try/catch теперь друзья :)

Это пример. Я же написал что, планирую сделать либу которая будет портабельна. А внутри будет разводится дефайнами. под разные архитектуры. Есть пример портабельного проекта (не моё) linux/windows-32/64бит, использующего этот принцип.

navrocky ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от navrocky

gcc, SIGSEGV и try/catch теперь друзья :)

По части обработки сигналов посмотри на libsigsegv. Там много для чего заявлена поддержка, но на деле далеко не везде не работает.

mv ★★★★★ ()

gcc, SIGSEGV и try/catch теперь друзья :)

«Теперь»? Да это уж несколько лет как реализовано.

tailgunner ★★★★★ ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от tailgunner

gcc, SIGSEGV и try/catch теперь друзья :)

Нет, ну вот так всегда... Все форумы завалены этим вопросом, никто не дает ответа, я сам искал пол года уже. И вот находится человек который говорит что это уже все знают как десять лет... где вы раньше были батенька?

navrocky ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от mv

gcc, SIGSEGV и try/catch теперь друзья :)

Как раз хотел посмотреть/пощупать. Слишком у них инфа скупая, ничего не понятно. Можно ли в ихнем обработчике выкидывать исключение? и потом ловить это через try/catch?

navrocky ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от navrocky

Re: gcc, SIGSEGV и try/catch теперь друзья :)

> И вот находится человек который говорит что это уже все знают как десять лет...

Про 10 лет я не говорил :)

где вы раньше были батенька?

Здесь же. И вроде как минимум раз я отвечал на такой вопрос ;)

tailgunner ★★★★★ ()

gcc, SIGSEGV и try/catch теперь друзья :)

исключения в c++ неюзабельны и не потому, что ими нельзя сегфолт поймать

Love5an ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от Love5an

gcc, SIGSEGV и try/catch теперь друзья :)

> исключения в c++ неюзабельны и не потому, что ими нельзя сегфолт поймать

а почему еще? :)

lester ★★★★ ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от true_admin

Re: gcc, SIGSEGV и try/catch теперь друзья :)

> Если верить лору, тормоза дикие вызывают

Если использовать их вместо возвращаемого значения?

mannaz ()

gcc, SIGSEGV и try/catch теперь друзья :)

тормозные, очень error prone, нету finally(не надо только про RAII, связывание семантики unwind-protect с деструктором какого-либо класса это убого и ограничено - что если нам надо что-то, непривязанное к какому-либо конкретному объекту сделать в завершении блока? А что если нам надо "прибить" объект в середине блока? Или, например надо что-либо для объектов из разных уровней вложенности сделать? Упс. А если нам надо "подчистить" по-разному в зависимости от состояния нескольких объектов и параметров? деструкторов-мультиметодов в C++ нету, извините)

Love5an ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от Love5an

gcc, SIGSEGV и try/catch теперь друзья :)

тормозные

Ну это обработка критической ситуации. Тут скорость работы, тем более, столь мелкие и несущественные тормоза, уже не имеют сколь-нибудь ощутимого значения. Если программа умудрилась сгенерить SIGSEGV/GPF то она должна быть благодарна за сам факт того, что ей вообще позволили отползти и хоть как-то сохранить при этом лицо. Если конечно получится.

очень error prone,

Это уже к конкретной реализации.

нету finally(не надо только про RAII, связывание семантики unwind-protect с деструктором какого-либо класса это убого и ограничено -

Если честно, с __finally встретился в первый раз в жизни. AFAIU это http://msdn.microsoft.com/en-us/library/9xtt5hxz(VS.80).aspx ?

The compound statement after the __try clause is the guarded section. The compound statement after the __finally clause is the termination handler. The handler specifies a set of actions that execute when the guarded section is exited, regardless of whether the guarded section is exited by an exception (abnormal termination), or by standard fall through (normal termination).

Control reaches a __try statement by simple sequential execution (fall through). When control enters the __try, its associated handler becomes active. If the flow of control reaches the end of the try block, execution proceeds as follows:

1. The termination handler is invoked. 2. When the termination handler completes, execution continues after the __finally statement. Regardless of how the guarded section ends (for example, via a goto out of the guarded body or a return statement), the termination handler is executed before the flow of control moves out of the guarded section.

A __finally statement does not block searching for an appropriate exception handler.

ОК, попробуем прикинуть.

что если нам надо что-то, непривязанное к какому-либо конкретному объекту сделать в завершении блока?

__try {
    run
}
__finally {
    cleanup
}

Чем это принципиально отличается от приведенного ниже?

try {
    run
} catch (...) {
}
cleanup

Ну хорошо, есть конечно goto и return. С первым, особенно в C++, все понятно. Со вторым.. Ну приятно конечно иметь такую фичу, спорить не буду. Но она IMHO будет скорее развращать и без неё тоже все прекрасно пишется.

А что если нам надо «прибить» объект в середине блока? Или, например надо что-либо для объектов из разных уровней вложенности сделать? Упс.

Примерчик бы не помешал. Мне как-то сложно придумать use case причем чтобы он упирался в __finally. Может, потому, что я его естественным образом не использую.

А если нам надо «подчистить» по-разному в зависимости от состояния нескольких объектов и параметров? деструкторов-мультиметодов в C++ нету, извините)

Ну а __finally вам сам по себе чем то поможет в подчистке и сам определит и разведет application specific состояния? Все равно руками разгребать.

bibi ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от bibi

gcc, SIGSEGV и try/catch теперь друзья :)

> Чем это принципиально отличается от приведенного ниже?

Тем, что после cleanup в __finally может юыть перезапущено исключение.

tailgunner ★★★★★ ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от tailgunner

gcc, SIGSEGV и try/catch теперь друзья :)

Тем, что после cleanup в __finally может юыть перезапущено исключение.

Ну оно как бы и в обработчике обычного исключения может быть перезапущено, не проблема. AFAIU радость __finally в том, что:

If an exception occurs in the __try block, the operating system must find a handler for the exception or the program will fail. If a handler is found, any and all __finally blocks are executed and execution resumes in the handler.

For example, suppose a series of function calls links function A to function D, as shown in the following figure. Each function has one termination handler. If an exception is raised in function D and handled in A, the termination handlers are called in this order as the system unwinds the stack: D, C, B.

Т.е. 'деструктор', привязанный не к объекту но к блоку исполнения. Охотно верю, что в некоторых случаях такой функционал языка может быть полезен и удобен. Правда, ничего кроме смешанного C/C++ кода т.е. 'exception unsafe' с ходу в голову не приходит. Я не буду громко кричать 'костыль! костыль!' т.к. в бою как в бою и ничего тут не поделаешь, если такой код, но... Если делать как дохтор прописал можно прекрасно и гарантированно обходиться и без __finally :)

Anyway, __finally - вещь в себе и её и так нет в g++ и это сугубо MSVC Specific фича. Так что тот факт, что предложенное решение не поддерживает __finally IMHO ммм.. не совсем агрумент в g++ :)

bibi ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от bibi

Re: gcc, SIGSEGV и try/catch теперь друзья :)

>> Тем, что после cleanup в __finally может юыть перезапущено исключение.

Ну оно как бы и в обработчике обычного исключения может быть перезапущено, не проблема

Ты хоть сам смотрел, что написал? Твой cleanup вне обработчика, исключение потеряно.

tailgunner ★★★★★ ()
Ответ на: Re: gcc, SIGSEGV и try/catch теперь друзья :) от tailgunner

gcc, SIGSEGV и try/catch теперь друзья :)

Ты хоть сам смотрел, что написал? Твой cleanup вне обработчика, исключение потеряно.

Конечно же смотрел и оно намеренно вне обработчика.

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

AFAIU решение с __finally:

__try {
    run
} __finally {
    cleanup
}

...и без:

try {
    run
} catch (...) {
}
cleanup

Подчистка вызывается? Вызывается. По завершению блока? По завершению блока. Всегда вызывается? Всегда. Вывод: должно работать. Если же хочется ещё и исключение поймать дабы было таковое - пожалуйста, ловим в catch() и обрабатываем.

С другой стороны, по ссылке с MSDN я так и не понял - можно ли делать цепочку __finally для различных исключений как с обычным catch? И, кстати, как будет работать такой __finally:

__try {
    run
} __finally (xxx) {
    cleanup
}

...в случае, когда исключения не произошло? Содержимое xxx не несёт смысловой нагрузки. Что будет, если к нему обратиться? Как вообще понять, почему мы попали в __finally - из-за возникновения исключения или же потому, что просто завершился блок?

bibi ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от bibi

gcc, SIGSEGV и try/catch теперь друзья :)

> Подчистка вызывается? Вызывается. По завершению блока? По завершению блока. Всегда вызывается? Всегда. Вывод: должно работать. Если же хочется ещё и исключение поймать дабы было таковое - пожалуйста, ловим в catch() и обрабатываем.

Мде. Мне его не поймать хочется, а перезапустить. Покажешь способ, которым можно перезапустить неизвестное исключение вне catch(...){} ?

tailgunner ★★★★★ ()

gcc, SIGSEGV и try/catch теперь друзья :)

#include <signal.h>

void mysigsegv(int msig) {
throw something;
}

int main() {
signal(SIGSEGV, mysigsegv);
}

Не?

Werehuman ★★ ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от tailgunner

gcc, SIGSEGV и try/catch теперь друзья :)

Мде. Мне его не поймать хочется, а перезапустить. Покажешь способ, которым можно перезапустить неизвестное исключение вне catch(...){} ?

Нет, конечно же не покажу. Я понял. Ты к тому, что по возникновению исключения оно пролетает насквозь до найденного обработчика, отрабатывая при этом по ходу цепочку __finally? Ну хорошо, допустим. Фича интересная и я бы может быть тоже не отказался видеть её в g++. Впрочем, тогда уж и в стандарте.

bibi ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от true_admin

gcc, SIGSEGV и try/catch теперь друзья :)

Да лор - это вообще врач в поликлинике, как ты ему можешь доверять в вопросах программирования ?!?!? А?

navrocky ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от navrocky

gcc, SIGSEGV и try/catch теперь друзья :)

Да лор - это вообще врач в поликлинике, как ты ему можешь доверять в вопросах программирования ?!?!? А?

Лялялял... Возьми да замерь. Делов на 10 минут. Без всяких врачей сам все увидишь.

bibi ()
Ответ на: Re: gcc, SIGSEGV и try/catch теперь друзья :) от tailgunner

gcc, SIGSEGV и try/catch теперь друзья :)

> Здесь же. И вроде как минимум раз я отвечал на такой вопрос ;)

К сожалению не нашел ваш ответ. Здесь когда-то спрашивал, наверное год назад...

navrocky ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от bibi

gcc, SIGSEGV и try/catch теперь друзья :)

А на кой замерять время исполнения исключения? Это ведь исключительная ситуация %) Пусть оно хоть минуту исполняется.. главное чтобы обработалось.

navrocky ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от bibi

gcc, SIGSEGV и try/catch теперь друзья :)

> __finally? Ну хорошо, допустим. Фича интересная и я бы может быть тоже не отказался видеть её в g++. Впрочем, тогда уж и в стандарте.

Я вот тоже хочу эту фичу уже давно, много находил поделок её эмулирующих но не до конца.

navrocky ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от bibi

gcc, SIGSEGV и try/catch теперь друзья :)

> Лялялял... Возьми да замерь. Делов на 10 минут. Без всяких врачей сам все увидишь.

http://www.linux.org.ru/view-message.jsp?msgid=3856841

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

и еще, практический подход к программированию на языке и вопрос дизайна языка — несколько разные вещи

www_linux_org_ru ★★★★★ ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от www_linux_org_ru

gcc, SIGSEGV и try/catch теперь друзья :)

Нет, ну это же изврат возвращать значение из функции исключением.... Как такое вообще можно замерять? Пусть меня поправят. Или кто-то так подходит к конструированию кода? o_O

navrocky ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от www_linux_org_ru

gcc, SIGSEGV и try/catch теперь друзья :)

В CL, вообще, достаточно сложный механизм событий(conditions), без раскрутки стека, с рестартами, соответственно и т.п. Но есть аналог примитивным throw и catch, называется тоже, как ни странно, throw и catch, и работает быстрее плюсовских исключений(в sbcl, по крайней мере)

вот код для сравнения:

(declaim (optimize (speed 3) (space 0) (safety 0) (debug 0)))

(defun f (x)
  (declare (type fixnum x))
  (unless (zerop x)
    (throw 'error nil)))

(defun g (x)
  (declare (type fixnum x))
  (catch 'error
    (f x)))

(defun main (n x)
  (declare (type fixnum n x))
  (dotimes (i n)
    (declare (type fixnum i))
    (g x)))
#include <stdlib.h>
#include <iostream>

class Error {} error;

void f(int x)
{
        if(!x)
                throw error;
}

void g(int x)
{
        try
        {
                f(x);
        }
        catch(Error)
        {
                return;
        }
}

int main(int argc, char *argv[])
{
        if(argc!=3)
                return -1;
        int n = strtoul(argv[1], NULL, 10),
            x = strtoul(argv[2], NULL, 10);
        while(n--)
                g(x);
        return 0;
}
у меня лисповский отрабатывает за ~330 мс, плюсовый - ~530 (-O3 и т.п., естественно, включены)

Love5an ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от navrocky

gcc, SIGSEGV и try/catch теперь друзья :)

щас *опять* придется долго объяснять

представь, что f — это функция парсинга лога и возвращает количество байт в данной строке, тогда логично ее неудачу сделать исключение

www_linux_org_ru ★★★★★ ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от Love5an

gcc, SIGSEGV и try/catch теперь друзья :)

время - за миллион повторений, забыл сказать
мерял плюсы из шелла с помощью time, лисп - с помощью макроса time из repl

Love5an ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от Love5an

gcc, SIGSEGV и try/catch теперь друзья :)

> у меня лисповский отрабатывает за ~330 мс, плюсовый - ~530 (-O3 и т.п., естественно, включены)

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

перепиши мой пример на лиспе и сравни http://www.linux.org.ru/view-message.jsp?msgid=3856841

www_linux_org_ru ★★★★★ ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от Love5an

gcc, SIGSEGV и try/catch теперь друзья :)

> время - за миллион повторений, забыл сказать мерял плюсы из шелла с помощью time, лисп - с помощью макроса time из repl

меряй оба варианта time-ом (стартапом на 3 секундах уже можно пренебречь)

www_linux_org_ru ★★★★★ ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от www_linux_org_ru

gcc, SIGSEGV и try/catch теперь друзья :)

> щас *опять* придется долго объяснять

Я знаю как правильно применять исключения. Совершенно верно, их выкидывать по ошибке. Но ошибка - это не штатный режим работы программы, и соответственно на производительность никак не влияет.

А если важна производительность, то коды возврата в руки и вперед!...

navrocky ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от navrocky

gcc, SIGSEGV и try/catch теперь друзья :)

> Я знаю как правильно применять исключения. Совершенно верно, их выкидывать по ошибке. Но ошибка - это не штатный режим работы программы, и соответственно на производительность никак не влияет.

0.5% случаев можно назвать достаточно редким и нештатным режимом работы?

www_linux_org_ru ★★★★★ ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от www_linux_org_ru

gcc, SIGSEGV и try/catch теперь друзья :)

> 0.5% случаев можно назвать достаточно редким и нештатным режимом работы?

Да. А в чем подвох вопроса?

navrocky ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от www_linux_org_ru

Re: gcc, SIGSEGV и try/catch теперь друзья :)

> возвращает количество байт в данной строке, тогда логично ее неудачу сделать исключение

Гкхм-кхм.

LamerOk ★★★★★ ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от navrocky

Re: gcc, SIGSEGV и try/catch теперь друзья :)

> Да. А в чем подвох вопроса?

Читай ту ветку целиком. Сэкономишь кучу времени и постов в этой.

LamerOk ★★★★★ ()
Ответ на: Re: gcc, SIGSEGV и try/catch теперь друзья :) от LamerOk

gcc, SIGSEGV и try/catch теперь друзья :)

> Читай ту ветку целиком. Сэкономишь кучу времени и постов в этой.

Прочел. Тот-же бред что и в этой. Тоесть ты клонишь к тому что можно не продолжать? :D

navrocky ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от www_linux_org_ru

gcc, SIGSEGV и try/catch теперь друзья :)

Каких замечаний? Вот тот код, переписанный, ладно.

(declaim (optimize (speed 3) (space 0) (safety 0) (debug 0)))

(deftype ufixnum () '(integer 0 #.most-positive-fixnum))

(define-symbol-macro +BITS+ 10)

(declaim (type ufixnum *i0* *i1*)
         (type condition *condition*))
(defvar *i0* 0)
(defvar *i1* 0)
(defvar *condition* (make-condition 'condition))

(defun f (arg)
  (declare (type ufixnum arg))
  (if (zerop (logand (ash arg -16)
                     (1- (ash 1 +BITS+))))
    (throw *condition*
      (incf *i1*))
    (incf *i0*))
  nil)

(defun main (&aux (i 0) (x 1))
  (declare (type ufixnum i x))
  (loop do (incf i)
           (incf x (ash x 2))
           (catch *condition*
             (f x))
        while (/= x 1))
  (format t "i=~a i0=~a i1=~a i0+i1=~a~%"
          i *i0* *i1* (+ *i0* *i1*))
  (format t "  ~a    ~a    ~a       ~a~%"
          #x40000000 (- i *i1*)
          (ash (ash 1 (- 16 +BITS+)) 14)
          #x40000000))
Время получается примерно как в плюсах - 2.42 секунд real, +- 20 мс Ну, учитывая в лиспе 50-100 мс на подгрузку рантайма, плюс оверхед на доступ к динамическим переменным, получается, что в лиспе оно таки быстрее :)

У меня на 32-битной системе, правда, оверфлоу ufixnum происходит(fixnum на 32битном sbcl равно (signed-byte 29)), но это мелочи :)

Love5an ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от Love5an

gcc, SIGSEGV и try/catch теперь друзья :)

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

Love5an ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от Love5an

gcc, SIGSEGV и try/catch теперь друзья :)

> У меня на 32-битной системе, правда, оверфлоу ufixnum происходит(fixnum на 32битном sbcl равно (signed-byte 29)), но это мелочи :)

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

www_linux_org_ru ★★★★★ ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от Love5an

gcc, SIGSEGV и try/catch теперь друзья :)

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

У меня там раскручивать нечего. К слову, рестарты чем-то отличаются от подачи «во внутрь» анонимной функции, определенной «снаружи»?

www_linux_org_ru ★★★★★ ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от Love5an

gcc, SIGSEGV и try/catch теперь друзья :)

> У меня на 32-битной системе, правда, оверфлоу ufixnum происходит(fixnum на 32битном sbcl равно (signed-byte 29)), но это мелочи :)

у тебя там есть нормальные 32-разрядные беззнаковые?

www_linux_org_ru ★★★★★ ()

gcc, SIGSEGV и try/catch теперь друзья :)

Хоре трындеть про скорость работы с исключениями, если ты на ноль делишь миллион раз - миллион раз тебе руки оторвать надо.

Все кто спорят - читайте что такое исключения и зачем они нужны.

И наконец, есть какой-либо другой вариант(соизмеримо-простой) сделать так, чтоб сторонний плагин обращающийся по нулевому указателю не завершал извлекающий его код(plasma-plugins под kde4)?

PS: из 7 скачанных плагинов 4 убивают плазму.

jerry_ru ()
Ответ на: gcc, SIGSEGV и try/catch теперь друзья :) от Love5an

Re: gcc, SIGSEGV и try/catch теперь друзья :)

> время - за миллион повторений, забыл сказать мерял плюсы из шелла с помощью time, лисп - с помощью макроса time из repl

У тебя на старт процесса много сжирается, делай 100 млн. циклов.

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