@Dementor
программист, архитектор, аналитик

Что означает эта ошибка в С++ ?

К сожалению, совершенно не являюсь ни знатоком по C++, ни по системному программированию. Поэтому мне требуется помощь настоящих специалистов.

У меня есть программа, которая написана на С++ (есть исходники) и откомпилирована под 32-битную Ubuntu 14.04. Обычно эта программа работает нормально, но на некоторых комбинациях входящих данных она тихо умирает с Segmentation fault. Поскольку приложение работает в качестве многопоточного сервера, то ранее понять что и как его роняло у меня было не возможности. И я, как сисадмин, мог решать данную проблему только перезапуском демона. Но за вчера был всего один запрос, который успешно завалил этот сервер. Повторный его вызов все так же успешно убивает приложение.

Вооружившись знаниями из гугла, в скрипт из /etc/init.d я дописал перед стартом строчку ulimit -c unlimited и получил при падении дамп. Далее скормил его на вход GDB и получил следующую информацию:

Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x080ac8a6 in size (this=<optimized out>, this=<optimized out>) at /usr/include/c++/4.8/bits/stl_vector.h:646
646           { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }


Предпоследняя команда по бэктрейсу - это попытка вызова метода size() у вектора из экземпляров некоего класса. Что еще раз подтверждает порождение проблемы во внутренностях STL.

Моих скудных познаний по С++ в объеме двух семестров университета не достаточно, что бы понять причину выбивания Segmentation fault выражением size_type. Совершенно не понятна причина, по которой на большинстве наборов данных все отрабатывает отлично, а ошибку выбивает лишь примерно раз в неделю - хотя данные в среднем однотипные и сбойный набор на глаз ничем не выделяется. Прошу помощи у знающих. Заранее спасибо!

P.S. Не знаю на сколько это важная информация, но лишней она точно не будет. Размер дампового файла 2335М. Работающее приложение в рабочее время показывает следующие показатели потребления памяти: VIRT=2295636, RES=2,11g. Т.е. насколько я понимаю до линуксовой границы в 3g для 32-битный приложений еще далековато. Утечки памяти если и есть, то незначительные (я за неделю-две стабильной работы не успеваю зафиксировать), а приложение успешно падает сразу после запуска без наличия дополнительной нагрузки пользовательскими запросами и с достаточным запасом оперативки для своих вычислений.

Upd. Программа сейчас работает в 3 потока и действительно существуют данные, к которым есть рабочие обращения из всех потоков. Но эти данные используются исключительно для чтения (после запуска программы 2 Гига поднимаются в память и более не изменяются). Сервер получает запрос и передает управление свободному потоку, который делает выборки из общих данных и выполняет требуемые от него расчеты. Еще раз при этом данные на самом сервере не изменяются! Потоки внутри себя создают требуемые для ихних алгоритмов структуры, а по завершению очищают от них память. Так же еще раз подчеркну, что ошибка может выбиваться на всего одном запросе в одном потоке при отсутствии активности от других потоков. В программе есть всего один критический управленческий участок, но доступ к нему регламентирован с помощью мютексов, и он не связан с выполняемыми расчетами и совершенно не имеет никакого отношения к алгоритму и данным в точке падения.
  • Вопрос задан
  • 3293 просмотра
Решения вопроса 1
bogolt
@bogolt
Ошибка в недрах STL событие маловероятное. Эта библиотека тестируется годами на огромном количестве проектов. То что ошибка проявилась именно в std::vector вовсе не значит что ошибка именно там. Вероятнее всего - код пытается работать с удаленной памятью, вызывает функцию получения размера, а так как объект не существует программа падает.
Это совершенно нормально для программ с ручным управлением памятью ( ну и для остальных тоже вроде случается ).
Почему ошибка может происходить время от времени: причин тому множество. Может неправильная работа с многопоточностью ( и тут уже зависит от ОС как она и что распределит ) ведет к тому что изредка один поток обращается к ресурсу удаленному другим потоком. Может ошибка с памятью проявляется не сразу потому что хоть какие-то значения обращаются к несуществующей памяти, но физически эта память находится в адресном пространстве вашей программы, а значит ОС считает что все в порядке. Ну а уже когда указатели выходят за пределы этого пространства - случается большой бум.

Раз уж у вас есть запрос который гарантированно воспроизводит проблему - вам стоит попытаться отладить ваш сервер и найти эту ошибку.
Ответ написан
Пригласить эксперта
Ответы на вопрос 4
Как способ прояснить ситуацию можете попробовать воспользоваться valgrind-ом, он кроме того что утечки отслеживает еще и перехватывает обращение к "чужой" памяти если повезет - это один вариант, другой вариант, если вам доступны исходники, перекомпилируйте программу с флагом -fsanitize=address, с этим флагом программа будет плевать наружу ошибки работы с памятью (что как правило и приводит к segmentation fault).
Ответ написан
Комментировать
TrueBers
@TrueBers
Гуглю за еду
this=optimized out, this=optimized out

Есть возможность выключить -O и включить -g?
Намного больше будет информации вместо optimized out.
Ответ написан
@m0rd
Самая распространенная ошибка, приводящая к Segmentation fault - освободить память, а потом обратиться к ней. Можно попробовать натравить на код статический анализатор, он поможет найти ошибки в коде.
Ответ написан
Комментировать
@Sumor
Действительно можно прогнать статическими анализаторами. Они хорошо отлавливают ситуации, когда идёт обращение к освобождённой памяти. Например:
CLang analizer
CppCheck
PVS-Studio
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы