Russian Qt Forum

Программирование => Общий => Тема начата: Igors от Август 13, 2016, 10:55



Название: Поиск краша
Отправлено: Igors от Август 13, 2016, 10:55
Добрый день

Не самый плохой, но достаточно мерзкий случай: вылетает раз в 2-3 дня, когда уже успеваю забыть о нем.  Подробности

1)
Цитировать
Нужен код т.т.п.
Увы, это "не транспортабельно"

2) Краш происходит всегда в одном месте, на выходе из большого (неск сотен строк) статического метода писаного  не мной. Отладчик показывает что летит на деструкторе ~std::string - верить этому необязательно. Ну конечно просмотрел все используемые string, окружил их проверками, но зацепиться за что-то не удалось. Полезные symbolic breakpoint (часто с их помощью удается найти повторное удаление и.т.п.) в этот раз молчат

3) Пытался зациклить ф-цию (с одним и тем же входом и разными) чтобы спровоцировать вылет - нет, и полчаса работает, не летит.

Что можно предпринять?

Спасибо


Название: Re: Поиск краша
Отправлено: Bepec от Август 13, 2016, 11:14
Покряхтев, можно натыкать логов много, от слова "дофига". И после очередного краха смотреть по логам где точно произошёл вылет.
Но и это не гарантирует результат, ибо память может портиться где нить в первом часу, а вылет произойдёт во втором :D


Название: Re: Поиск краша
Отправлено: __Heaven__ от Август 13, 2016, 13:03
У вас поломка, скорее всего далеко не в этом месте. Просто так везёт, что перенаправляет в деструктор строки. Я бы поискал объекты, которые могли бы рядом с этой строкой в стэке стоять. Быть может запись за пределами массива происходит. Вообще, valgrind в помощь.


Название: Re: Поиск краша
Отправлено: Racheengel от Август 13, 2016, 13:09
Расход памяти проверить стоит.
У нас была с этим проблема - вылетало раз в 2-3 недели.
Выяснилось, что при определенных условиях просто не хватало памяти.
Да, еще очень помогают вещи вроде breakpad и crashrpt.

https://chromium.googlesource.com/breakpad/breakpad/

http://crashrpt.sourceforge.net/


Название: Re: Поиск краша
Отправлено: _Bers от Август 13, 2016, 15:25
Что можно предпринять?

1.
отладчики умеют брякаццо на факт изменения значения по адресу.

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

ну а дальше нужно пасти - кто меняет.
почему, и на каком основании.

то есть смотрим стек вызовов.
может быть кто-то из соседнего потока накосячил?

2.
техника отладки называется "хвостик".

смысл идеи в том, что бы выявить факт пробоя памяти.
для этого нужно подвинуть аварийный объект в сторонку:
Код:
int main()
{
    std::string ololo;
}

Код:
int main()
{
    int border1[255];
    std::string ololo;
    int border2[255];
}

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

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

строка выживает.
но скорее всего краш будет где-то дальше
(а может и не будет)

3.
дебажный велосипед.
в отдельном потоке состояние строки постоянно мониторится.
идет проверка: находится ли строка в консистентном состоянии,
или уже нет.

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

===========================================


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


Название: Re: Поиск краша
Отправлено: Igors от Август 13, 2016, 15:43
вы знаете, какой объект у вас слетает.
К сожалению - пока нет

отладчики умеют брякаццо на факт изменения значения по адресу.
...
значит можете поставить бряку на его изменение.
Пока эти попитки ни к чему не привели - отладчик (gdb) просто вешается намертво 

смысл идеи в том, что бы выявить факт пробоя памяти.
для этого нужно подвинуть аварийный объект в сторонку:
Да, реагирует на изменения в коде. Вот уже неск дней нету после того как я добавил тестовую печать по if

дебажный велосипед.
в отдельном потоке состояние строки постоянно мониторится.
идет проверка: находится ли строка в консистентном состоянии,
или уже нет.
Строка (если это строка, пока не факт) - одна из локальных переменных, которых в ф-ции десятка полтора, многие контейнеры. Т.е. возможно и строка - но не та что в ф-ции, а член класса одного из эл-тов контейнера.


Название: Re: Поиск краша
Отправлено: GreatSnake от Август 13, 2016, 16:00
Довольно-таки странно, что до сих пор не прогнали через valgrind.


Название: Re: Поиск краша
Отправлено: Igors от Август 13, 2016, 16:53
Довольно-таки странно, что до сих пор не прогнали через valgrind.
Он на OSX не очень - захлебывается при выделениях 500 метров и выше. Да и что там хотим увидеть - "разрушен блок памяти <адрес>"? Это мне и так бы сообщили в gdb, но в данном случае этого нет.


Название: Re: Поиск краша
Отправлено: _Bers от Август 13, 2016, 17:02
Да и что там хотим увидеть - "разрушен блок памяти <адрес>"? Это мне и так бы сообщили в gdb, но в данном случае этого нет.

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


Название: Re: Поиск краша
Отправлено: Igors от Август 13, 2016, 17:57
зная адрес пробитого блока,
можно с точностью установить что за объект был подбит.
зная этот объект, можно поставить бряку на его изменение.
и отловить момент этого изменения.
станет видно кто именно постарался.
Убрал все тестовые печати - и вылет довольно быстро объявился. Пришел к выводу что да, испорчена строка, локальная переменная в ф-ции. Хмм... ну и как на нее поставить "бряку"? Адреса-то я не имею до входа в ф-цию. Опять налепил тестовых печатей - и опять вылет не появляется...


Название: Re: Поиск краша
Отправлено: Racheengel от Август 13, 2016, 18:36
А дебажный вывод где стоит? до проблемной строки или после?
Если "до" строки воткнуть какой-нибудь безвредный ничонеделающий мусор вместо дебага - эффект тот же?
Я бы все же попробовал брекпадом - хотя не знаю, как он на макаке себя вести будет, но на винде нам эта тулза пару раз хорошо помогла.


Название: Re: Поиск краша
Отправлено: _Bers от Август 13, 2016, 20:07
Убрал все тестовые печати - и вылет довольно быстро объявился. Пришел к выводу что да, испорчена строка, локальная переменная в ф-ции. Хмм... ну и как на нее поставить "бряку"? Адреса-то я не имею до входа в ф-цию. Опять налепил тестовых печатей - и опять вылет не появляется...
[/quote]

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

далее:
Debug -> New Breakpoint -> New Data Breakpoint

в открывшемся диалоге вбил адрес охраняемого объекта:
&myVariable

после чего как только произойдет изменение содержимого адреса отлаживаемого объекта,
сработает бряк.


насчет вас не знаю.
я не телепат.



Название: Re: Поиск краша
Отправлено: Igors от Август 14, 2016, 10:59
Вот она, сучка

Код
C++ (Qt)
char line[8192];
std::string baseName;   // эта переменная иногда убита
...
 
while(!file.eof() && file.good())
{
file.getline(line, 8192, '\n');
 
// remove any trailing \r
if (line[strlen(line) - 1] == '\r')
line[strlen(line) - 1] = '\0';
 
// ignore blank lines
if (strlen(line) == 0)
continue;
 
 
Исправил так
Код
C++ (Qt)
while(!file.eof() && file.good())
{
file.getline(line, 8192, '\n');
size_t sLen = strlen(line);
 
// remove any trailing \r
if (sLen && line[sLen - 1] == '\r')
line[sLen - 1] = '\0';
 
// ignore blank lines
if (strlen(line) == 0)
continue;
 
 


Название: Re: Поиск краша
Отправлено: GreatSnake от Август 14, 2016, 13:46
Вот она, сучка
Да уж, такой код иначе и не назовёшь.


Название: Re: Поиск краша
Отправлено: qate от Август 14, 2016, 18:45
Вот она, сучка

И зачем при наличии qt использовать сишные споособы работы ?


Название: Re: Поиск краша
Отправлено: __Heaven__ от Август 15, 2016, 09:15
Вот она, сучка

И зачем при наличии qt использовать сишные споособы работы ?
just for lulz


Название: Re: Поиск краша
Отправлено: __Heaven__ от Август 15, 2016, 09:20
Довольно-таки странно, что до сих пор не прогнали через valgrind.
Он на OSX не очень - захлебывается при выделениях 500 метров и выше. Да и что там хотим увидеть - "разрушен блок памяти <адрес>"? Это мне и так бы сообщили в gdb, но в данном случае этого нет.
Имхо, пускай захлёбывается. Уж лучше он будет сутки искать ошибку, чем это буду делать я трое суток. Я это время потрачу на что-нибудь другое.


Название: Re: Поиск краша
Отправлено: Igors от Август 15, 2016, 09:52
И зачем при наличии qt использовать сишные споособы работы ?
Да уж, такой код иначе и не назовёшь.
Ну как сказать.. А как бы написал я при отсутствии Qt? Наверное тоже бы читал ifstream в буфер, тоже бы отсекал вындозный конец строки - в общем принципиально ничем не лучше

Имхо, пускай захлёбывается. Уж лучше он будет сутки искать ошибку, чем это буду делать я трое суток. Я это время потрачу на что-нибудь другое.
Ну в данном случае он бы ничего не нашел - утечек нет, куча не бита. В свое время мой интерес к valgrind быстро охладел когда я познакомился с гораздо более приятными "Instruments" (Memory Leak и др)


Название: Re: Поиск краша
Отправлено: __Heaven__ от Август 15, 2016, 10:27
Есть экспериментальный инструмент SGCheck, который включается опцией --tool=exp-sgcheck, возможно, он бы вам помог.
А тут пример того, как безопасно можно было бы прочитать строку http://en.cppreference.com/w/cpp/string/basic_string/getline


Название: Re: Поиск краша
Отправлено: Igors от Август 15, 2016, 10:58
А тут пример того, как безопасно можно было бы прочитать строку http://en.cppreference.com/w/cpp/string/basic_string/getline
Конечно прочитать в std::string было бы аккуратнее. Вообще осуждать др программиста писавшего этот код легко. Но при этом не стоит забывать - "плохой" код реализует не слабый кусок ф-ционала. В аттаче пример файла что он читает. И у меня как-то не возникает желания переписать это чтение с нуля  :) Ну заменю я массив на контейнер и strlen/strtok на что-то получше - так это пол-процента от всей работы (такова обычная цена умничания  :))


Название: Re: Поиск краша
Отправлено: __Heaven__ от Август 15, 2016, 11:46
Так ведь, не с нуля. Можно написать тестик и потихонечку выделять отдельные операции в методы и постепенно заменять их на c++ функционал. Вы, скорее всего, снова наступите на эти грабли и суммарное время потраченное на поиск ошибок превысит время, которое бы ушло на исправление этого участка кода.


Название: Re: Поиск краша
Отправлено: Igors от Август 15, 2016, 11:53
Так ведь, не с нуля. Можно написать тестик и потихонечку выделять отдельные операции в методы и постепенно заменять их на c++ функционал. Вы, скорее всего, снова наступите на эти грабли и суммарное время потраченное на поиск ошибок превысит время, которое бы ушло на исправление этого участка кода.
Да, если бы найти не удалось - пришлось бы рефакторить, но это тоже совсем не дешево. A "потихонечку" (постепенно улучшать) не всегда есть возможность.


Название: Re: Поиск краша
Отправлено: Авварон от Август 23, 2016, 18:41
А вас не смущает тройной (после фикса двойной) вызов strlen?