Как найти место, где программа вылетает?

Модератор: Модераторы разделов

Ответить
MiK13
Сообщения: 1180
ОС: Linux Debian

Как найти место, где программа вылетает?

Сообщение MiK13 »

Имеется программа. Довольно сложная. Обрабатывает данные в реальном времени. Файлов много (может быть 3-4 лишних):

Код: Выделить всё

$ ls *.cpp *.h | wc
     45      45     844
$ wc *.cpp *.h | grep итого
  25194   93318 1273293 итого

Была написана довольно давно (больше 5 лет назад, но дорабатывалась) на Borland Builder.
Потом была "доработана" для g++, чтобы работать совместно с другими программами в системе под управлением Linux.
Программа работает. Иногда стабильно, хотя не очень корректно обрабатывает поступающие на её вход данные.
А иногда вылетает по ошибке сегментации. Где -- найти не могу. И, главное, не знаю как.
Может быть кто-нибудь посоветует как найти это место?
На вход данных поступает довольно много, И непрерывно. За секунду несколько десятков, а то и сотня пакетов.Программа может работать непрерывно пол минуты, может 10 минут. А может и больше. А потом, вдруг, "Ошибка сегментации".
Пока для "защиты" сделал такой скрипт:

Код: Выделить всё

#! /bin/bash

while true ; do
  if [[ -z "`pgrep -x Prog`" ]] ; then
    echo === `date +%F,%T` === Restart Prog >>Prog_wd.log
    ./Prog -b
  fi
  sleep 1
done
который запускается вместе с этой программой. По логу могу судить как часто эта программа вылетает.
Но мне надо найти место, где она вылетает. Кто может посоветовать КАК его искать?

У меня нет оснований считать, что g++ не такой "правильный", как bc. Правда, во время первой "адаптации" была одна проблема -- g++ не понимал некоторые конструкции. Но разработчик, почитав описание C++, пришёл к выводу, что "по стандарту" это надо делать немного по-другому. После чего g++ всё принял.

И был ещё один момент: программа вылетала по ошибке сегментации при попытке записать содержимое некоторого объекта в файл. Запись выполнялась простой строкой "of<<obj", но в классе этого объекта были определены операторы << для каждого его элемента. Многие из которых также были классами (и таких уровней было 3 или 4).
Я этот кусок переписал на чистый C, используя fprintf, и программа вылетать перестала. Почему -- так и не понял. Автор утверждает, что в "виндовом" варианте никаких проблем нет.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20794
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Как найти место, где программа вылетает?

Сообщение Bizdelnick »

Собственно, искать причину вылета — забота разработчика, а не Ваша. Он-то должен уметь пользоваться отладчиком.
Если разработчик недоступен/неадекватен — собирайте программу с дебагом (опция -g) и запускайте её через gdb, как упадёт — давайте команду bt. В трассировке будет видно, что откуда вызывалось. Поможет ли это Вам — вот уж не знаю.
https://www.opennet.ru/docs/RUS/gdb/gdb_5.html#SEC15
Upd. Также может иметь смысл запустить программу (собранную с дебагом) под valgrind. В некоторых случаях он выдаёт довольно понятные описания ошибок. Не повредит и прогнать по коду cppcheck. Но, как я понял из Вашего сообщения, код скорее всего ужасен, и ошибок вылезет море.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
MiK13
Сообщения: 1180
ОС: Linux Debian

Re: Как найти место, где программа вылетает?

Сообщение MiK13 »

Bizdelnick писал(а):
04.05.2016 19:52
Собственно, искать причину вылета — забота разработчика, а не Ваша. Он-то должен уметь пользоваться отладчиком.
Если разработчик недоступен/неадекватен
Разработчик доступен и вполне адекватен. И старается помочь мне решить проблему.
Но вся беда в том, что он не программист. И у него полно забот на своей работе, не связанных с программированием.
Кроме того, у него практически нет опыта работы с линуксом. И даже доступа к нему нет.
Bizdelnick писал(а):
04.05.2016 19:52
собирайте программу с дебагом (опция -g) и запускайте её через gdb, как упадёт — давайте команду bt. В трассировке будет видно, что откуда вызывалось. Поможет ли это Вам — вот уж не знаю.
https://www.opennet.ru/docs/RUS/gdb/gdb_5.html#SEC15

Вот за это спасибо. Почитаю, как работать с отладчиком.
Я когда-то пытался его использовать, но почти ничего не добился. И основная отладка у меня -- через printf.
Bizdelnick писал(а):
04.05.2016 19:52
Upd. Также может иметь смысл запустить программу (собранную с дебагом) под valgrind. В некоторых случаях он выдаёт довольно понятные описания ошибок. Не повредит и прогнать по коду cppcheck. Но, как я понял из Вашего сообщения, код скорее всего ужасен, и ошибок вылезет море.
Вот это для меня новое. Попробую с этим разобраться.
Как я уже когда-то писал, стараюсь добиться того, чтобы при трансляции с -Wall компилятор не выдавал никаких сообщений.
Но при сборке той программы выскакивает довольно много разных предупреждений. Я обращал его внимание на них, но он отвечал, что это неважно, не стоит обращать на них внимания.
Но беда в том, что я практически не знаком с C++ и поэтому не могу оценить значимость этих сообщений.

Пример сообщений при трансляции одного их модулей:

Код:

$ make g++ -c -Wall -ggdb ApproximatAndInterpolat.cpp In file included from ApproximatAndInterpolat.h:10:0, from ApproximatAndInterpolat.cpp:6: rmatrix.h:42:33: warning: friend declaration ‘T norm(Rvector<T>&)’ declares a non-template function [-Wnon-template-friend] friend T norm(Rvector<T>&); ^ rmatrix.h:42:33: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) rmatrix.h:43:33: warning: friend declaration ‘T abs(Rvector<T>&)’ declares a non-template function [-Wnon-template-friend] friend T abs (Rvector<T>&); ^ rmatrix.h:103:42: warning: friend declaration ‘Rmatrix<T> transp(Rmatrix<T>&)’ declares a non-template function [-Wnon-template-friend] friend Rmatrix<T> transp (Rmatrix<T>&); ^ rmatrix.h:104:42: warning: friend declaration ‘T Sp(Rmatrix<T>&)’ declares a non-template function [-Wnon-template-friend] friend T Sp (Rmatrix<T>&); ^ rmatrix.h:105:42: warning: friend declaration ‘T tr(Rmatrix<T>&)’ declares a non-template function [-Wnon-template-friend] friend T tr (Rmatrix<T>&); ^ rmatrix.h:106:42: warning: friend declaration ‘Rmatrix<T> inverse(Rmatrix<T>&)’ declares a non-template function [-Wnon-template-friend] friend Rmatrix<T> inverse(Rmatrix<T>&); ^ rmatrix.h:107:42: warning: friend declaration ‘T det(Rmatrix<T>&)’ declares a non-template function [-Wnon-template-friend] friend T det (Rmatrix<T>&); ^ In file included from ApproximatAndInterpolat.cpp:6:0: ApproximatAndInterpolat.h: In constructor ‘ComponentSplaynInterpolat::ComSplayn::ComSplayn(double, SplaynInterpolat&)’: ApproximatAndInterpolat.h:163:32: warning: ‘ComponentSplaynInterpolat::ComSplayn::t_begin’ will be initialized after [-Wreorder] double t_begin; ^ ApproximatAndInterpolat.h:162:42: warning: ‘SplaynInterpolat ComponentSplaynInterpolat::ComSplayn::Splayn’ [-Wreorder] SplaynInterpolat Splayn; ^ ApproximatAndInterpolat.h:166:25: warning: when initialized here [-Wreorder] ComSplayn(double t_beg, SplaynInterpolat &Spl ) ^ ApproximatAndInterpolat.cpp: In member function ‘virtual double LineInterpolat::Interpolat(double)’: ApproximatAndInterpolat.cpp:170:4: warning: suggest explicit braces to avoid ambiguous ‘else’ [-Wparentheses] if( VP.size() == 1 ) if(X == VP[0].X) return VP[0].Y; else return 0.0; ^ In file included from ApproximatAndInterpolat.h:10:0, from ApproximatAndInterpolat.cpp:6: rmatrix.h: In instantiation of ‘const T* const& Rmatrix<T>::operator[](int) const [with T = double]’: rmatrix.h:313:68: required from ‘Rmatrix<T>::Rmatrix(const Rmatrix<T>&) [with T = double]’ ApproximatAndInterpolat.cpp:400:46: required from here rmatrix.h:73:63: warning: returning reference to temporary [-Wreturn-local-addr] const T* const & operator[](int index)const{return M[index];}; ^
Но файл ApproximatAndInterpolat.o в результате трансляции был создан.
Но подобные предупреждения выдаются при трансляции почти всех 18 составляющих модулей.

P.S. Ещё такой момент (даже два)
1. Так как программа создавалась под виндой, то и кодировка комментариев в ней CP1251, а у меня сейчас UTF-8. Но это не важно.
2. В линуксе нет тех файлов.h, которые были в борланде. То есть файлы, в принципе, есть, но они не имеют окончания .h. Его пришлось убрать. И также нет файла io.h. Но, как я понял, вместо него можно использовать unistd.h
Но является ли такая замена полностью эквивалентной, не знаю
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20794
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Как найти место, где программа вылетает?

Сообщение Bizdelnick »

MiK13 писал(а):
04.05.2016 22:10
Так как программа создавалась под виндой, то и кодировка комментариев в ней CP1251, а у меня сейчас UTF-8.

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

MiK13 писал(а):
04.05.2016 22:10
В линуксе нет тех файлов.h, которые были в борланде. То есть файлы, в принципе, есть, но они не имеют окончания .h.

Вообще-то на то, какие заголовки должны присутствовать, имеется стандарт. См. http://www.cplusplus.com/reference/.

MiK13 писал(а):
04.05.2016 22:10
И также нет файла io.h. Но, как я понял, вместо него можно использовать unistd.h
Но является ли такая замена полностью эквивалентной, не знаю

Вот тут ничего не могу сказать. unistd.h — это POSIX-заголовок, не знаю, в какой степени он эквивалентен чему-то виндовому.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
MiK13
Сообщения: 1180
ОС: Linux Debian

Re: Как найти место, где программа вылетает?

Сообщение MiK13 »

Bizdelnick писал(а):
04.05.2016 23:51
Вот тут ничего не могу сказать. unistd.h — это POSIX-заголовок, не знаю, в какой степени он эквивалентен чему-то виндовому.
Я тоже не знаю, по этому действовал простым методом. Закоментировал его включение и посмотрел, на что ругается компилятор. Потом по ману посмотрел на эти функции и увидел, что их определение в unostd.h. сделал ln -s unistd.h io.h. Это прошло.
Bizdelnick писал(а):
04.05.2016 19:52
Upd. Также может иметь смысл запустить программу (собранную с дебагом) под valgrind. В некоторых случаях он выдаёт довольно понятные описания ошибок. Не повредит и прогнать по коду cppcheck. Но, как я понял из Вашего сообщения, код скорее всего ужасен, и ошибок вылезет море.
valgrind поставил, но пока под ним ещё не проверял.
cppcheck тоже поставил. Прогнал через него все файлы. На *.h он ничего не выдал. А вот на *.cpp ...
Из 22 файлов на один выдал три ошибки "(error) Dereferenced iterator 'it' has been erased" На другой -- две ошибки
"(error) Possible null pointer dereference: pointerDann - otherwise it is redundant to check if pointerDann is null at line 116"
И ещё на один -- 7 ошибок "(error) Returning reference to auto variable"
Но, что самое непонятное, на две моих программы (точнее два варианта одной) он выдал такую ошибку:
[rlog.c:247]: (error) Mismatching allocation and deallocation: f
Что это означает -- понятно не могу. Ругается он на следующую строку

Код: Выделить всё

[247]  if(nf) pclose(f);
[248]  else fclose(f);

f -- обычный FILE *. Если имя файла, который я читаю оканчивается на .dat, то я его открываю чеерз fonen, а если на .gz, то через popen("zcat файл","r"). Соответственно, в конце закрываю либо по pclose, либо по fclose.
Что не нравится чекеру, понять не могу.
Правда, если добавить опцию --enable=all, то сообщений появляется очень много.
В общем, буду с этим разбираться.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20794
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Как найти место, где программа вылетает?

Сообщение Bizdelnick »

MiK13 писал(а):
05.05.2016 16:27
сделал ln -s unistd.h io.h

Зря. Лучше в коде поправить, возможно в #ifdef...#else, если совместимость с виндой надо сохранить.

MiK13 писал(а):
05.05.2016 16:27
Из 22 файлов на один выдал три ошибки "(error) Dereferenced iterator 'it' has been erased" На другой -- две ошибки
"(error) Possible null pointer dereference: pointerDann - otherwise it is redundant to check if pointerDann is null at line 116"

Вот в любом из этих мест и может случиться сегфолт. Впрочем, это вовсе не означает, что он не может случиться где-то ещё.

MiK13 писал(а):
05.05.2016 16:27
Что не нравится чекеру, понять не могу.

Возможно, он просто не въехал в логику и увидел fopen(), за которым следует pclose(). Логика действительно, скажем так, нелинейная, хотя если всё так, как Вы описали, то ошибки быть не должно.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
MiK13
Сообщения: 1180
ОС: Linux Debian

Re: Как найти место, где программа вылетает?

Сообщение MiK13 »

Ситуация у меня непонятная.
Собирался написать (и даже написал) довольно много строк. Даже привёл код одной функции из класса, в которой происходила ошибка сегментации. Причём происходила она на операторе
os << ID_OpenFile<< ' ' << endl; // Файл открыт
где ID_OpenFile была обычной целой константой.
А до этого была непонятная ситуация с передачей значений.
Разработчик программы попросил меня добавить модуль документирования входной информации. Чтобы самому её проанализировать.
Данные, которые получала функция документирования сильно отличались от того, что я ей передавал (разница была в числе раз гораздо большем, чем атомов во Вселенной :-))
Потом я сообразил, что проблема в выравнивании: я в свои программы ставлю #pragma pack(1), а сюда не поставил.
Добавил этот оператор в файл.h и файл.cpp -- и программа стала вылетать в том месте, о котором я написал выше.
Тогда я убрал эту пракму в файле.cpp, но оставил в файле.h. И программа стала работать. Правда, пока без основной обработки.
Почему при наличии оператора #pragma pack(1) в файле.cpp приводило к тому, что программа вылетала на простом операторы вывода, непонятно.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20794
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Как найти место, где программа вылетает?

Сообщение Bizdelnick »

MiK13 писал(а):
06.05.2016 18:56
я в свои программы ставлю #pragma pack(1)

Зачем???
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
MiK13
Сообщения: 1180
ОС: Linux Debian

Re: Как найти место, где программа вылетает?

Сообщение MiK13 »

Bizdelnick писал(а):
06.05.2016 19:48
MiK13 писал(а):
06.05.2016 18:56
я в свои программы ставлю #pragma pack(1)

Зачем???

"Бережёного Бог бережёт" сказала монашка...
А если серьёзно, то чтобы иметь полный контроль над расположением данных в памяти.
Я, правда, стараюсь и так все структуры делать так, чтобы их элементы располагались по адресам кратным размеру. Но не все делают так. И когда говорят, что, например, в приходящем пакете данных сначала идёт байт, в котором находится число элементов, а потом идут 4-байтовые числа, то приходится для приёма этих данных делать соответствующую структуру. Без выравнивания.
Спасибо сказали:
Аватара пользователя
Olej
Сообщения: 659
ОС: Fedora, Mint, Debian, QNX
Контактная информация:

Re: Как найти место, где программа вылетает?

Сообщение Olej »

MiK13 писал(а):
04.05.2016 19:38
У меня нет оснований считать, что g++ не такой "правильный", как bc. Правда, во время первой "адаптации" была одна проблема -- g++ не понимал некоторые конструкции. Но разработчик, почитав описание C++, пришёл к выводу, что "по стандарту" это надо делать немного по-другому. После чего g++ всё принял.

У вас должно быть много-много оснований считать, что gcc во много раз точнее соответствет стандартам ANSI C/C++ чем bc.
А вот bc - это отстой :angry: ... и ожидать там можно всего что угодно.




MiK13 писал(а):
06.05.2016 18:56
Потом я сообразил, что проблема в выравнивании: я в свои программы ставлю #pragma pack(1), а сюда не поставил.

Ни в коем случае!
За исключением особых обоснованных случаев ... что бывает крайне редко, да и то зачастую в embedded приложениях.

Спасибо сказали:
Аватара пользователя
Olej
Сообщения: 659
ОС: Fedora, Mint, Debian, QNX
Контактная информация:

Re: Как найти место, где программа вылетает?

Сообщение Olej »

MiK13 писал(а):
04.05.2016 22:10
Как я уже когда-то писал, стараюсь добиться того, чтобы при трансляции с -Wall компилятор не выдавал никаких сообщений.
Но при сборке той программы выскакивает довольно много разных предупреждений. Я обращал его внимание на них, но он отвечал, что это неважно, не стоит обращать на них внимания.

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

MiK13 писал(а):
04.05.2016 22:10
Но беда в том, что я практически не знаком с C++ и поэтому не могу оценить значимость этих сообщений.

И тогда уж тем более!

MiK13 писал(а):
04.05.2016 22:10
2. В линуксе нет тех файлов.h, которые были в борланде. То есть файлы, в принципе, есть, но они не имеют окончания .h. Его пришлось убрать. И также нет файла io.h. Но, как я понял, вместо него можно использовать unistd.h
Но является ли такая замена полностью эквивалентной, не знаю

Linux здесь не при чём: современный стандарт C++ не предусматривает (и уже довольно давно) заголовочные файлы вида *.h, теперь они должны выглядеть, например, так: <iostream>.
Конечно, замена Borland заголовочных файлов (которые не соответствуют никакому стандарту) на GCC (где заголовки соответствуют ANSI) не эквивалентна.
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 20794
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Как найти место, где программа вылетает?

Сообщение Bizdelnick »

MiK13 писал(а):
06.05.2016 22:20
чтобы иметь полный контроль над расположением данных в памяти.

Зачем? Помимо того, что это может привести к такой вот несогласованности, Вы ещё и замедляете работу программы. Только в случаях, когда это абсолютно необходимо, стоит использовать

Код: Выделить всё

__attribute__ ((__packed__))
для отдельных структур. Ну или, если нужна совместимость с виндовыми компиляторами, может быть

Код: Выделить всё

#pragma pack(push, 1)
// определение структуры
#pragma pack(pop)
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Ответить