(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Обработка Segmentation Fault в C++

Вводная

 C++ является "небезопасным" ("unmanaged") языком, поэтому программы могут "вылетать" - аварийно завершать работу без сохранения данных пользователя, сообщения об ошибке и т.п. - стоит только, например, залезть в не инициализированную память. Например:
void fall()
{
  char * s = "short_text";
  sprintf(s,"This is very long text");
}

 или
void fall()
{
  int * pointer = NULL;
  *pointer = 13;
}

 Всем было бы лучше, если бы мы могли "отловить" падение программы - точно так же, как в java ловим исключения - и выполнить хоть что-то перед тем, как программа упадет (сохранить документ пользователя, вывести диалог с сообщением об ошибке и т.п.)

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

Способ 1: SEH

 Если Вы используете OS Windows в качестве целевой ОС и Visual C++ в качестве компилятора, то Вы можете использовать Structured Exception Handling - расширение языка С++ от Microsoft, позволяющее отлавливать любые исключения, происходящие в программе.

 Общий синтаксис обработки исключений выглядит следующим образом:

__try
{
  segfault1();
}
__except( condition1 )
{
  // обработка исключения, если condition1 == EXCEPTION_EXECUTE_HANDLER.
  // в condition1 может (должен) быть вызов метода, проверяющего
  //    тип исключения, и возвращающего EXCEPTION_EXECUTE_HANDLER
  //    если тип исключения соответствует тому, что мы хотим обработать
}
__except( condition2 )
{
  // еще один обработчик
}
__finally
{
  // то, что выполнится если ни один из обработчиков не почешется
}

 Вот "работающий пример" - "скопируй и вставь в Visual Studio"
#include <stdio.h>
#include <windows.h>
#include <excpt.h>

int memento() // обработка Segfault
{
    MessageBoxA(NULL,"Memento Mori","Exception catched!",NULL);
    return 0;
}

void fall() // генерация segfault
{
      int* p = 0x00000000;  
      *p = 13;
}

int main(int argc, char *argv[])
{
    __try
    {
        fall();
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        memento();
    }
}

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

 Данная методика, при всей ее привлекательности, имеет ряд минусов:

Один компилятор. Одна ОС. Не "чистый С++". Если Вы хотите работать без средств MS - Вы не сможете использовать эту методику
Один поток - одна таблица. Если Вы напишете конструкцию из __try… __except, внутри __try запустите другой поток и, не выходя из __try второй поток вызовет segfault, то… ничего не произойдет, программа упадет "как обычно". Потому, что на каждый поток нужно писать отдельный обработчик SEH.

 Минусов оказалось настолько много, что приходится искать второе решение.

Способ 2: POSIX - сигналы

 Способ рассчитан на то, что в момент падения программа получает POSIX-сообщение SIGSEGV. Это безусловно так во всех UNIX-системах, но это фактически так (хотя никто не гарантировал, windows - не posix-совместима) и в windows тоже.

 Методика простая - мы должны написать обработчик сообщения SIGSEGV, в котором программа совершит "прощальные действия" и, наконец, упадет:
void posix_death_signal(int signum)
{
    memento(); // прощальные действия
        signal(signum, SIG_DFL); // перепосылка сигнала
    exit(3); //выход из программы. Если не сделать этого, то обработчик будет вызываться бесконечно.
}

 после чего мы должны зарегистрировать этот обработчик:
signal(SIGSEGV, posix_death_signal);

 Вот готовый пример:
#include <stdio.h>
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <signal.h>

int memento()
{
    int a=0;
    MessageBoxA(NULL,"Memento mori","POSIX Signal",NULL);
    return 0;
}
void fall()
{
      int* p = 0x00000000;
      *p = 13;
}
void posix_death_signal(int signum)
{
    memento();
    signal(signum, SIG_DFL);
    exit(3);
}

int main(int argc, char *argv[])
{
    signal(SIGSEGV, posix_death_signal);
    fall();
}

 В отличие от SEH, это работает всегда: решение "многопоточное" (вы можете уронить программу в любом потоке, обработчик запустится в любом случае) и "кроссплатформенное" - работает под любым компилятором, и под любой POSIX-совместимой ОС.

Ссылки по теме


 Распечатать »
 Правила публикации »
  Обсудить материал в конференции Embarcadero »
Написать редактору 
 Рекомендовать » Дата публикации: 01.11.2011 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
Enterprise Connectors (1 Year term)
Delphi Professional Named User
Microsoft Office для дома и учебы 2019 (лицензия ESD)
Panda Gold Protection - ESD версия - на 1 устройство - (лицензия на 1 год)
Bitdefender Antivirus Plus 2020/1 год/1 ПК
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Безопасность компьютерных сетей и защита информации
Новости ITShop.ru - ПО, книги, документация, курсы обучения
Программирование на Microsoft Access
CASE-технологии
СУБД Oracle "с нуля"
Проект mic-hard - все об XP - новости, статьи, советы
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
Обсуждения в форумах
Слот Биг Бэнг (6)
Большой взрыв как правящая теория сотворения мира. Теперь вы можете поиграть слот Big Bang в...
 
Отличается ли ДрифтКазино от беттинга? (57)
Друзья, давно заметил, что на Дрифте уже несколько месяцев во всю рекламируется и предлагается...
 
Подскажите лучшее онлайн казино (8)
Вот нашёл интересную игровую площадку, и это онлайн казино Вавада. Может кто что подсказать по...
 
Помощь по MS Access (345)
Доброе время суток. Случайно оказался на этом сайте, искал статьи по OLAP. Вижу, что...
 
Требуется Краснодар: Java -разрабочик (2)
Обязанности: Разработка корпоративных backend-приложений для автоматизации розничных продаж...
 
 
 



    
rambler's top100 Rambler's Top100