gcc, SIGSEGV и try/except теперь друзья :)
От: navrocky  
Дата: 18.11.09 12:27
Оценка: 79 (5)
Долго искал как отловить try except'ом SIGSEGV, перерыл кучу форумов, так ничего и не нашел...

Но случайно наткнулся на нужную инфу, результат я изложил в своей статье.

ЗЫЖ Комментарии приветствуются!
Re: gcc, SIGSEGV и try/except теперь друзья :)
От: remark Россия http://www.1024cores.net/
Дата: 18.11.09 12:39
Оценка:
Здравствуйте, navrocky, Вы писали:

N>Долго искал как отловить try except'ом SIGSEGV, перерыл кучу форумов, так ничего и не нашел...


N>Но случайно наткнулся на нужную инфу, результат я изложил в своей статье.


N>ЗЫЖ Комментарии приветствуются!


Наверное всё же try/catch, а не try/except. try/except — Win32-specific обработка исключений, а в Win32 с этим нет никаких проблем.


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: gcc, SIGSEGV и try/except теперь друзья :)
От: navrocky  
Дата: 18.11.09 12:44
Оценка:
R>Наверное всё же try/catch, а не try/except. try/except — Win32-specific обработка исключений, а в Win32 с этим нет никаких проблем.

Да, вы совершенно правы, запутался я в языках конечно-же try/catch
Re: gcc, SIGSEGV и try/except теперь друзья :)
От: Alexander G Украина  
Дата: 18.11.09 12:52
Оценка: +1
Здравствуйте, navrocky, Вы писали:

N>ЗЫЖ Комментарии приветствуются!


А комментарии не по существу?

Я имею большой опыт разработки, и могу утверждать что как минимум 90% всех SEGV — это безобидный доступ по нулевому указателю


Спорная точка зрения. Да, в Delphi действительно принято преобразовывать EXCEPTION_ACCESS_VIOLATION в EAccessViolation, и показывать его как меседжбокс пользователю. Иногда это работает. Иногда, когда в коде прорисовки или обрабокти таймера AV этих меседжбоксов получается целая пачка.
На самом деле, обработав AV, не знаешь, что произошло. То ли чтение нулевого указателя, то ли выполнение ненулевого. И из какой именно переменной его читают/выполняют. Безобидность сильно варьируется. Лучше делать креш-дамп и завершаться.

Пытаться спасти документ следует, но пытаться продолжить работу — вряд ли.
В Windows есть апи для такой попытки восстановления данных при креше http://msdn.microsoft.com/en-us/library/cc948909(VS.85).aspx , суть в том, что при креше приложение таки завершается, креш дамп таки делается, и при аварийном сохранении никакого UI не показывается.
Русский военный корабль идёт ко дну!
Re: gcc, SIGSEGV и try/except теперь друзья :)
От: Alexander G Украина  
Дата: 18.11.09 13:05
Оценка:
Здравствуйте, navrocky, Вы писали:

N>ЗЫЖ Комментарии приветствуются!


Тут ещё такая тонкость. Delphi не переупорядочивает операции, поэтому там код аналогичный


int * i = 0;
try {
  *i = 5;
} catch (...) {
}

сработает как надо.

Студия опитимизирует агрессивнее, поэтому там генерация для /EHa и /EHs отличается тем, что при /EHa компилятор готов к исключением в неожиданных местах.

Так вот, вопрос, не сгенерит ли gcc с полной оптимизацией код вроде
int * i = 0;
*i = 5;
try {
} catch (...) {
}
Русский военный корабль идёт ко дну!
Re[2]: gcc, SIGSEGV и try/except теперь друзья :)
От: remark Россия http://www.1024cores.net/
Дата: 18.11.09 13:33
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Спорная точка зрения. Да, в Delphi действительно принято преобразовывать EXCEPTION_ACCESS_VIOLATION в EAccessViolation, и показывать его как меседжбокс пользователю. Иногда это работает. Иногда, когда в коде прорисовки или обрабокти таймера AV этих меседжбоксов получается целая пачка.

AG>На самом деле, обработав AV, не знаешь, что произошло. То ли чтение нулевого указателя, то ли выполнение ненулевого. И из какой именно переменной его читают/выполняют. Безобидность сильно варьируется. Лучше делать креш-дамп и завершаться.


Для AV-то как раз это всё известно, это для SIGSEGV не известно.

В С++ проблема то, что низкоуровневые исключения и возможность происхождения чего-то плохого практически ортогональны. Если исключения не было, то где гарантия, что данные уже не попортились или что не выполнился произвольный код? Тогда получается надо аварийно завершать приложение сражу в main(), а вдруг что плохое случилось или случится. Вы скажете — вероятность выше. Я очень-очень редко вижу, что бы при низкоуровневых исключения портились данные и при этом приложение бы выполнялось дальше. Зато вот при buffer overrun атаках никаких исключений не происходит...
Так что, по-моему, завершение приложения при исключениях — это чистая иллюзия в С++.
Ну и плюс надо учитывать контекст приложения. Если это какое-то критическое health care приложение, то разумно перезапускаться при исключении. Если это текстовый редактор, то я думаю, целесообразно спасти документы 100 пользователей, и полностью запороть документ 1 пользователя в результате продолжения работы после исключения.



1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: gcc, SIGSEGV и try/except теперь друзья :)
От: navrocky  
Дата: 18.11.09 13:51
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Спорная точка зрения. Да, в Delphi действительно принято преобразовывать EXCEPTION_ACCESS_VIOLATION в EAccessViolation, и показывать его как меседжбокс пользователю. Иногда это работает. Иногда, когда в коде прорисовки или обрабокти таймера AV этих меседжбоксов получается целая пачка.


Ну я же и говорю что 90% случаев это некритичные ошибки которые не вызывают никаких проблем, и не только в Дельфи, а под виндой вообще. Пользователя можно культурно предупредить об ошибке, и пусть он решает, перезапускать программу или нет.
Наш проект содержит 500000 строк кода, сервер работает 24/7 и не падает, на ранних стадиях там случались мелкие AV, которые мы оперативно устраняли, но сервер работал и не вываливался.

AG>На самом деле, обработав AV, не знаешь, что произошло. То ли чтение нулевого указателя, то ли выполнение ненулевого. И из какой именно переменной его читают/выполняют. Безобидность сильно варьируется. Лучше делать креш-дамп и завершаться.

AG>Пытаться спасти документ следует, но пытаться продолжить работу — вряд ли.

Это кому как нравится.

AG>В Windows есть апи для такой попытки восстановления данных при креше http://msdn.microsoft.com/en-us/library/cc948909(VS.85).aspx , суть в том, что при креше приложение таки завершается, креш дамп таки делается, и при аварийном сохранении никакого UI не показывается.


Не под windows что использовать?

Вообще, эта технология хоть немного но увеличивает устойчивость программы. Решения до сих пор я, например, найти не мог. Поищите по этой теме и увидите сколько людей по форумам мается.
Re[3]: gcc, SIGSEGV и try/except теперь друзья :)
От: Alexander G Украина  
Дата: 18.11.09 13:52
Оценка:
Здравствуйте, remark, Вы писали:

R>В С++ проблема то, что низкоуровневые исключения и возможность происхождения чего-то плохого практически ортогональны. Если исключения не было, то где гарантия, что данные уже не попортились или что не выполнился произвольный код? Тогда получается надо аварийно завершать приложение сражу в main(), а вдруг что плохое случилось или случится. Вы скажете — вероятность выше. Я очень-очень редко вижу, что бы при низкоуровневых исключения портились данные и при этом приложение бы выполнялось дальше. Зато вот при buffer overrun атаках никаких исключений не происходит...


У майкрософтовской безопасной STL не только кидается исключение в случае переполнения вектора, но и обеспечивается, чтобы его никто не поймал. Правда, с этим борятся через "#define _SECURE_SCL 0" Я не борюсь, и мне дампы такие приходили.

А ещё кое-где для больших блоков можно использовать VirtualAlloc так, чтобы как можно раньше после выделнного блока был кусок с MEM_RESERVE и без MEM_COMMIT.

Ещё, достаточно непредсказуема попытка вызвать виртуальный метод уничтоженного объекта. Фактически, может что-то вызваться и не упасть по AV или Invalid Opcode.

R>Так что, по-моему, завершение приложения при исключениях — это чистая иллюзия в С++.


Этой фразы не понял.


Русский военный корабль идёт ко дну!
Re[2]: gcc, SIGSEGV и try/except теперь друзья :)
От: navrocky  
Дата: 18.11.09 13:56
Оценка:
AG>Так вот, вопрос, не сгенерит ли gcc с полной оптимизацией код вроде
AG>
AG>int * i = 0;
AG>*i = 5;
AG>try {
AG>} catch (...) {
AG>}
AG>


Код обработки сигналов и конвертации в исключения взят из исходников gcc, а не думаю что он будет глючить.
Re[3]: gcc, SIGSEGV и try/except теперь друзья :)
От: Alexander G Украина  
Дата: 18.11.09 14:05
Оценка:
Здравствуйте, navrocky, Вы писали:

N>Код обработки сигналов и конвертации в исключения взят из исходников gcc, а не думаю что он будет глючить.


Я немного про другое. Вот такой код:


int f()
{
  int i = 1;
  int j = 0;
  try 
  {
    return i / j;
  }
  catch(...)
  {
    return 1;
  }
}


int _tmain(int argc, _TCHAR* argv[])
{
  return f();
}


С /EHs в релизе MSVC вообще не генерит никакого try..catch кода:


#include "stdafx.h"

int f()
{
  int i = 1;
  int j = 0;
  try 
  {
    return i / j;
00401000  mov         eax,1 
00401005  cdq              
00401006  xor         ecx,ecx 
00401008  idiv        eax,ecx 
  }
  catch(...)
  {
    return 1;
  }
}
0040100A  ret              
--- No source file -------------------------------------------------------------
0040100B  int         3    
0040100C  int         3    
0040100D  int         3    
0040100E  int         3    
0040100F  int         3    
--- d:\projects\work\sv\sv\sv.cpp ----------------------------------------------


int _tmain(int argc, _TCHAR* argv[])
{
    return f();
00401010  jmp         f (401000h)


Так вот, не будет ли gcc "оптимизировать" т.е. устранять или переупорядочивать важные try..catch ?
Русский военный корабль идёт ко дну!
Re[4]: gcc, SIGSEGV и try/except теперь друзья :)
От: remark Россия http://www.1024cores.net/
Дата: 18.11.09 14:08
Оценка: 1 (1)
Здравствуйте, Alexander G, Вы писали:

AG>Здравствуйте, remark, Вы писали:


R>>В С++ проблема то, что низкоуровневые исключения и возможность происхождения чего-то плохого практически ортогональны. Если исключения не было, то где гарантия, что данные уже не попортились или что не выполнился произвольный код? Тогда получается надо аварийно завершать приложение сражу в main(), а вдруг что плохое случилось или случится. Вы скажете — вероятность выше. Я очень-очень редко вижу, что бы при низкоуровневых исключения портились данные и при этом приложение бы выполнялось дальше. Зато вот при buffer overrun атаках никаких исключений не происходит...


AG>У майкрософтовской безопасной STL не только кидается исключение в случае переполнения вектора, но и обеспечивается, чтобы его никто не поймал. Правда, с этим борятся через "#define _SECURE_SCL 0" Я не борюсь, и мне дампы такие приходили.


AG>А ещё кое-где для больших блоков можно использовать VirtualAlloc так, чтобы как можно раньше после выделнного блока был кусок с MEM_RESERVE и без MEM_COMMIT.


AG>Ещё, достаточно непредсказуема попытка вызвать виртуальный метод уничтоженного объекта. Фактически, может что-то вызваться и не упасть по AV или Invalid Opcode.


Именно.

R>>Так что, по-моему, завершение приложения при исключениях — это чистая иллюзия в С++.


AG>Этой фразы не понял.



Я имею в виду саму идею, что это как-то увеличивает безопасность.
Хакер сделал буфер оверран и никакого исключения не было.
Получился расстрел данных, перевели деньги на неправильный счёт и никакого исключения не было.
Вызвали виртуальную функцию разрушенного объекта, выполнили произвольный код, и никакого исключения не было.
А произошло безвредное обращение по нулевому указателю, и мы сразу мочим программу и несохраненные пользовательские данные.
Спрашивается и зачем?
Уж лучше бы дали пользователю сохранить данные. А если данные попортились... ну так они и так могли попортиться.


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[5]: gcc, SIGSEGV и try/except теперь друзья :)
От: Alexander G Украина  
Дата: 18.11.09 14:32
Оценка:
Здравствуйте, remark, Вы писали:

AG>>Ещё, достаточно непредсказуема попытка вызвать виртуальный метод уничтоженного объекта. Фактически, может что-то вызваться и не упасть по AV или Invalid Opcode.


R>Именно.


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

Или не падать и не отравлять дамп если позаботиться об обработке исключений.
Русский военный корабль идёт ко дну!
Re[4]: gcc, SIGSEGV и try/except теперь друзья :)
От: navrocky  
Дата: 18.11.09 14:32
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Так вот, не будет ли gcc "оптимизировать" т.е. устранять или переупорядочивать важные try..catch ?


Ну это только в таких банальных примерах, gcc способен что-то оптимизировать, но достаточно в блоке сделать вызов функции, как вся оптимизация закончится.
Re[6]: gcc, SIGSEGV и try/except теперь друзья :)
От: navrocky  
Дата: 18.11.09 14:36
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Так вот, в этом случае программа кроме выполнения произвольного кода будет также падать и отправлять дамп (смотря что там в куче окажется), и ошибка будет выявлена и устранена.


AG>Или не падать и не отравлять дамп если позаботиться об обработке исключений.


А кто мешает отправить дамп и продолжить работу?
Re[6]: gcc, SIGSEGV и try/except теперь друзья :)
От: remark Россия http://www.1024cores.net/
Дата: 18.11.09 14:47
Оценка:
Здравствуйте, Alexander G, Вы писали:


AG>>>Ещё, достаточно непредсказуема попытка вызвать виртуальный метод уничтоженного объекта. Фактически, может что-то вызваться и не упасть по AV или Invalid Opcode.


R>>Именно.


AG>Так вот, в этом случае программа кроме выполнения произвольного кода будет также падать и отправлять дамп (смотря что там в куче окажется), и ошибка будет выявлена и устранена.


С чего она будет падать?


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[7]: gcc, SIGSEGV и try/except теперь друзья :)
От: Alexander G Украина  
Дата: 18.11.09 14:55
Оценка:
Здравствуйте, navrocky, Вы писали:

N>А кто мешает отправить дамп и продолжить работу?


В принципе никто, но в моём случае (Windows) при продолжении работы пришлось бы реализовывать отправку дампов самостоятельно, а при "штатном" аварийном завершении всё происходит само как надо.

Хорошо, убедили, что мой случай не следует распространять на остальных.
Русский военный корабль идёт ко дну!
Re[7]: gcc, SIGSEGV и try/except теперь друзья :)
От: Alexander G Украина  
Дата: 18.11.09 14:59
Оценка:
Здравствуйте, remark, Вы писали:


AG>>>>Ещё, достаточно непредсказуема попытка вызвать виртуальный метод уничтоженного объекта. Фактически, может что-то вызваться и не упасть по AV или Invalid Opcode.


R>>>Именно.


AG>>Так вот, в этом случае программа кроме выполнения произвольного кода будет также падать и отправлять дамп (смотря что там в куче окажется), и ошибка будет выявлена и устранена.


R>С чего она будет падать?


Ну как, если где-то берётся из кучи указатель на vtable, которой уже нет, то может получаться указатель на другую vtable или невалидный указатель — всё это будет зависить от фазы луны. Да, опасность представляют именно те проявления ошибок, которые не привели к SEH исключениям, но те, которые привели, дают возможность знать об ошибках.
Русский военный корабль идёт ко дну!
Re: gcc, SIGSEGV и try/except теперь друзья :)
От: alpha21264 СССР  
Дата: 18.11.09 16:05
Оценка:
Здравствуйте, navrocky, Вы писали:

N>Долго искал как отловить try except'ом SIGSEGV, перерыл кучу форумов, так ничего и не нашел...


N>Но случайно наткнулся на нужную инфу, результат я изложил в своей статье.


N>ЗЫЖ Комментарии приветствуются!


Что у меня одного не работает?!

terminate called after throwing an instance of 'std::runtime_error'
what(): Segmentation fault
Аварийное завершение

Флаги -fexceptions -fnon-call-exceptions поставил.

Течёт вода Кубань-реки куда велят большевики.
Re[2]: gcc, SIGSEGV и try/except теперь друзья :)
От: navrocky  
Дата: 18.11.09 19:16
Оценка:
Здравствуйте, alpha21264, Вы писали:

A>Что у меня одного не работает?!


A>terminate called after throwing an instance of 'std::runtime_error'

A> what(): Segmentation fault
A>Аварийное завершение

A>Флаги -fexceptions -fnon-call-exceptions поставил.


Там есть исходники примера, они не работают? И еще одно замечание — этот пример только под linux-i386 32bit. Для других архитектур надо инклюдить другие хедеры. Моя кофигурация opensuse 11.1, i386, gcc 4.3.
Re[8]: gcc, SIGSEGV и try/except теперь друзья :)
От: navrocky  
Дата: 18.11.09 19:56
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Здравствуйте, navrocky, Вы писали:


N>>А кто мешает отправить дамп и продолжить работу?


AG>В принципе никто, но в моём случае (Windows) при продолжении работы пришлось бы реализовывать отправку дампов самостоятельно, а при "штатном" аварийном завершении всё происходит само как надо.


Да, это наверное единственное преимущество
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.