|
Модераторы: xvr |
|
Zerstroer |
|
|||
Опытный Профиль Группа: Участник Сообщений: 285 Регистрация: 8.8.2007 Где: Алма-Ата Репутация: нет Всего: 3 |
Здравствуйте.
Отлаживаю свой проект. Написан на C. Сам по себе проект представляет демон, который постоянно висит в памяти. Поведение в общих чертах у него следующее: использует статическую библиотеку (мою), регулярно делает вызовы её функций, так же, периодически работает со сторонней библиотекой libconfig, кроме этого, периодично с помощью fork и execl делает запуск стороннего бинарника и с помощью pipe обменивается с ним данными. Кроме этого, демон так же регулярно пишет с syslog. Ранее, ошибки, связанные с памятью я отслеживал наблюдая за объемом памяти, которое занимает приложение и обычным прогоном через gdb в IDE. Сейчас столкнулся с проблемой, что через некоторое время работы (порядка 12-24 часов) моя программа падает без каких либо видимых на то причин. При этом, в самом первом падении в лог записалась ошибка вида: glibc detected: double free or corruption (!prev). Более, при падении демон в лог писать ничего не пишет. Сейчас хочу продиагностировать программу с помощью valgrind. Я изменил код таким образом, что бы она завершалась после прохода одной итерации цикла. Перекомпилировал бинарник и свою библиотеку с ключами -g и -O0. После чего, запустил valgrind с такими ключами: valgrind --leak-check=full --leak-resolution=high --trace-children=yes --show-reachable=yes --thack-origins=yes --log-file=/home/user/valgrind.output Кое-какой вывод я разобрал и код исправил соответствующим образом (неинициализированные переменные). Но с кое, чем у меня возникли вопросы. Прилагаю лог valgrind. Вопросы следующие: 1. Верные ли вообще ключи у valgrind? Можно ли с ними проверить приложение на double free or corruption (!prev)? 2. Что означает длиннющщая строка из знаков "дельта" на 82-90 строках лога? 3. Может ли valgrind проверить мою статическую библиотеку, которую демон вызывает? Спасибо. Присоединённый файл ( Кол-во скачиваний: 1 ) valgrind__1_.output 12,96 Kb -------------------- In silico |
|||
|
||||
fish9370 |
|
|||
Опытный Профиль Группа: Участник Сообщений: 663 Регистрация: 15.4.2007 Где: Москва Репутация: 2 Всего: 1 |
мне valgrind ни разу не помог (возможно я не умею его готовить). Им вообще можно дебажить многопоточные приложения? Мне пришлось встроить в приложение инструменты отладки.
Обычно это делают так: переопределяются все стандартные вызовы на свои (malloc, calloc ...). Все данные заносятся в таблицу, где ведется учет обо всех выделениях/освобождениях. Плюс блоки памяти обносятся забором, чтобы отслеживать переполнения буферов. У меня есть встроенный CLI и я когда тестирую вызываю команду, чтобы посмотреть, что у меня с памятью. Сразу становится видно, кто что навыделял. Ну и если где-то возникает переполнение буфера это тоже сразу попадает в лог Valgrind в принципе делает тоже самое, только динамически перехватывая функции, но у меня с ним не сраслось Добавлено через 5 минут и 12 секунд Ну и исходя из твоего лога вижу, что у тебя 7 блоков потеряно. Адреса строк указаны. И да coredump тебе в помощь - неоценимая вещь! -------------------- undefined |
|||
|
||||
Zerstroer |
|
|||
Опытный Профиль Группа: Участник Сообщений: 285 Регистрация: 8.8.2007 Где: Алма-Ата Репутация: нет Всего: 3 |
fish9370, с этими семью блоками все просто - это одноразово выделяемая при запуске демона память. В режиме демона, она как бы и не подразумевается к освобождению, а так как я подправил код на прогон только одной итерации тем, что в теряется память именно в этих семи блоках - можно пренебречь.
Большое спасибо за совет по coredump. Гуглю, как им пользоваться. Жду еще чьих-нибудь советов/ответов. -------------------- In silico |
|||
|
||||
fish9370 |
|
||||
Опытный Профиль Группа: Участник Сообщений: 663 Регистрация: 15.4.2007 Где: Москва Репутация: 2 Всего: 1 |
Я делаю так: В /etc/sysctl.conf прописываем в конце:
sysctl -p В своей программе:
прога должна запускаться из под рута как отлаживать потом это с помощью gdb думаю разберешься Это сообщение отредактировал(а) fish9370 - 6.1.2016, 13:36 -------------------- undefined |
||||
|
|||||
Zerstroer |
|
|||
Опытный Профиль Группа: Участник Сообщений: 285 Регистрация: 8.8.2007 Где: Алма-Ата Репутация: нет Всего: 3 |
fish9370, подскажите, пожалуйста, что делает код, который необходимо встроить в свою программу и куда его нужно встроить? В начало?
Я понял, что он настраивает лимиты ресурсов, но как это работает? Снимается ограничение на размер дампа программы? -------------------- In silico |
|||
|
||||
fish9370 |
|
||||
Опытный Профиль Группа: Участник Сообщений: 663 Регистрация: 15.4.2007 Где: Москва Репутация: 2 Всего: 1 |
это можно встроить в любое место программы, это влияет на ресурсы процесса (виртуальную память), при увеличении их до бесконечности, ядро вынуждено выгрузить дамп на диск при краше (это и хак и фича) у меня это активируется при ключе -g, при запуске демона
Это сообщение отредактировал(а) fish9370 - 6.1.2016, 21:37 -------------------- undefined |
||||
|
|||||
Zerstroer |
|
|||
Опытный Профиль Группа: Участник Сообщений: 285 Регистрация: 8.8.2007 Где: Алма-Ата Репутация: нет Всего: 3 |
fish9370, т.е. это принудительный краш с дампом?
-------------------- In silico |
|||
|
||||
fish9370 |
|
|||
Опытный Профиль Группа: Участник Сообщений: 663 Регистрация: 15.4.2007 Где: Москва Репутация: 2 Всего: 1 |
нет, это дамп памяти процесса, в момент краша, со всеми стеками -------------------- undefined |
|||
|
||||
Zerstroer |
|
|||
Опытный Профиль Группа: Участник Сообщений: 285 Регистрация: 8.8.2007 Где: Алма-Ата Репутация: нет Всего: 3 |
fish9370, пробую воспользоваться этой штукой. Тему пока оставляю открытой, на случай возникновения вопросов.
-------------------- In silico |
|||
|
||||
Zerstroer |
|
||||
Опытный Профиль Группа: Участник Сообщений: 285 Регистрация: 8.8.2007 Где: Алма-Ата Репутация: нет Всего: 3 |
fish9370, ну вот, прошел почти месяц, как я запустил бинарник с реализованым функционалам сброса дампа. Почти через месяц мой демон таки вывалился. Дамп на руках есть. Бинарник, который запускался есть.
Команда gdb бинарник /путь_к_дампу/дамп на моей машине выдает следующее:
Помогите, пожалуйста, интерпретировать результаты. Есть еще два вопроса. 1. Как я могу сделать вывод более информативным? 2. Данные не собрались в дамп ядра или gdb не может их интерпретировать? upd. Почесал макушку и сделал bt. Получил следующий вывод от gdb:
А в main.c на строчке 817 у меня как раз есть free()... Это сообщение отредактировал(а) Zerstroer - 3.2.2016, 19:56 -------------------- In silico |
||||
|
|||||
xvr |
|
|||
Эксперт Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 20 Всего: 223 |
Похоже что на машине, где вы пытаетесь запустит gdb и на машине, где получен core dump разные версии ОС (по крайней мере библиотек)
|
|||
|
||||
fish9370 |
|
|||
Опытный Профиль Группа: Участник Сообщений: 663 Регистрация: 15.4.2007 Где: Москва Репутация: 2 Всего: 1 |
Для начала: нужно собирать с ключем -ggdb Второе: вместо голого gdb лучше использовать cgdb (https://cgdb.github.io) - это консольный отладчик на базе gdb Отлаживать надо так: - определяем список потоков: info threads - переключаемся в нужный поток: thread <номер> - делаем вывод стека вызовов: backtrace - идем по кадрам снизу вверх, рассматривая параметры: frame <номер стекового кадра> чтобы отлаживать требуется: - чтобы система была такой же - на вход нужно передать исполнимый файл (cgdb gconv_db) - в консоли gdb указываешь core-file /tmp/core.6953.e.11
Лезть в ядро нет ни какого смысла, если мы пишем в usermode. В помощь отладчику можно установить доп пакет, и он будет показывать, что вызывается в ядре, но это не нужно PS: можешь выслать сордамп и бинарник, если можешь вышли исходник, попробуем определить проблему -------------------- undefined |
|||
|
||||
fish9370 |
|
|||
Опытный Профиль Группа: Участник Сообщений: 663 Регистрация: 15.4.2007 Где: Москва Репутация: 2 Всего: 1 |
ну значит, двойное освобождение тут я бы посоветовал обнулять указатели после освобождения и делать проверку указателя на NULL -------------------- undefined |
|||
|
||||
Zerstroer |
|
|||
Опытный Профиль Группа: Участник Сообщений: 285 Регистрация: 8.8.2007 Где: Алма-Ата Репутация: нет Всего: 3 |
fish9370, обнуления указателей у меня как раз таки и не было. Присвоение NULL после free() сделал. Хотя ситуация очень странная, перепроверил код, не нашел ничего, что могло бы приводить к двойному освобождению.
Я правильно понял, что проверку на NULL нужно выполнять перед вызовом free()? Пока опять же запустил бинарник в работу. Coredump и бинарник вышлю, если опять произойдет вывал. Исходники не маленькие и им явно требуется сторонняя ревизия так как пишу я в одиночку и могу заблуждаться насчет читабельности и адекватности своего кода. Это сообщение отредактировал(а) Zerstroer - 5.2.2016, 10:06 -------------------- In silico |
|||
|
||||
fish9370 |
|
|||
Опытный Профиль Группа: Участник Сообщений: 663 Регистрация: 15.4.2007 Где: Москва Репутация: 2 Всего: 1 |
да, правильно. Но такая ситуация, скорее всего, свидетельствует о том, что в логике присутствует ошибка, так как такого быть не должно. И возможно тут следует поставить assert подождем Добавлено через 4 минуты и 15 секунд честно сказать, интересно было бы взглянуть. Интересно сравнить со своими поделками -------------------- undefined |
|||
|
||||
Правила форума "С/С++: Программирование под Unix/Linux" | |
|
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, xvr. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Программирование под Unix/Linux | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |