Модераторы: xvr
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> отлов ошибок с памятью с помощью valgrind, Помогите разобраться с valgrind. 
:(
    Опции темы
Zerstroer
Дата 6.1.2016, 09:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 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
PM MAIL ICQ   Вверх
fish9370
Дата 6.1.2016, 11:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 663
Регистрация: 15.4.2007
Где: Москва

Репутация: 2
Всего: 1



мне valgrind ни разу не помог (возможно я не умею его готовить). Им вообще можно дебажить многопоточные приложения? Мне пришлось встроить в приложение инструменты отладки. 
Обычно это делают так: переопределяются все стандартные вызовы на свои (malloc, calloc ...). Все данные заносятся в таблицу, где ведется учет обо всех выделениях/освобождениях. Плюс блоки памяти обносятся забором, чтобы отслеживать переполнения буферов.

У меня есть встроенный CLI и я когда тестирую вызываю команду, чтобы посмотреть, что у меня с памятью. Сразу становится видно, кто что навыделял. Ну и если где-то возникает переполнение буфера это тоже сразу попадает в лог

Valgrind в принципе делает тоже самое, только динамически перехватывая функции, но у меня с ним не сраслось

Добавлено через 5 минут и 12 секунд
Ну и исходя из твоего лога вижу, что у тебя 7 блоков потеряно. Адреса строк указаны.

И да coredump тебе в помощь - неоценимая вещь!


--------------------
undefined
PM MAIL WWW ICQ   Вверх
Zerstroer
Дата 6.1.2016, 13:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 8.8.2007
Где: Алма-Ата

Репутация: нет
Всего: 3



fish9370, с этими семью блоками все просто - это одноразово выделяемая при запуске демона память. В режиме демона, она как бы и не подразумевается к освобождению, а так как я подправил код на прогон только одной итерации тем, что в теряется память именно в этих семи блоках - можно пренебречь.
Большое спасибо за совет по coredump. Гуглю, как им пользоваться.
Жду еще чьих-нибудь советов/ответов.


--------------------
In silico
PM MAIL ICQ   Вверх
fish9370
Дата 6.1.2016, 13:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 663
Регистрация: 15.4.2007
Где: Москва

Репутация: 2
Всего: 1



Цитата(Zerstroer @  6.1.2016,  13:00 Найти цитируемый пост)
Большое спасибо за совет по coredump


Я делаю так:
В /etc/sysctl.conf прописываем в конце:

Код

kernel.core_pattern = /tmp/core.%p.%e.%s
fs.suid_dumpable = 1


sysctl -p 

В своей программе:
Код

#include <sys/resource.h> /* for setrlimit */

...

if (flags.coredump) {
     struct rlimit l;

     memset(&l, 0, sizeof(l));
     l.rlim_cur = RLIM_INFINITY;
     l.rlim_max = RLIM_INFINITY;
     if (setrlimit(RLIMIT_CORE, &l)) {
           bs_verbose(LOG_VERBOSE, "Unable to disable core size resource limit: %s\n", 
                   strerror(errno));
     }
}



прога должна запускаться из под рута

как отлаживать потом это с помощью gdb думаю разберешься

Это сообщение отредактировал(а) fish9370 - 6.1.2016, 13:36


--------------------
undefined
PM MAIL WWW ICQ   Вверх
Zerstroer
Дата 6.1.2016, 16:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 8.8.2007
Где: Алма-Ата

Репутация: нет
Всего: 3



fish9370, подскажите, пожалуйста, что делает код, который необходимо встроить в свою программу и куда его нужно встроить? В начало?
Я понял, что он настраивает лимиты ресурсов, но как это работает? Снимается ограничение на размер дампа программы?


--------------------
In silico
PM MAIL ICQ   Вверх
fish9370
Дата 6.1.2016, 20:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 663
Регистрация: 15.4.2007
Где: Москва

Репутация: 2
Всего: 1



Цитата(Zerstroer @  6.1.2016,  16:28 Найти цитируемый пост)
fish9370, подскажите, пожалуйста, что делает код, который необходимо встроить в свою программу и куда его нужно встроить? В начало?


Цитата(Zerstroer @  6.1.2016,  16:28 Найти цитируемый пост)
как это работает?


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

у меня это активируется при ключе -g, при запуске демона

Код

static struct option long_options[] = {
       {"help", 0, 0, '?'},
        ...
        {"coredump", 0, 0, 'g'},
       {0, 0, 0, 0}
};

int c, index = 0;
while ((c = getopt_long(argc, argv, "hg", long_options, &index)) != -1) {
        switch(c) {
        ...
        case 'g':
               flags.coredump = true;
               break;
       }
}

...
if (flags.coredump) {
        struct rlimit l;

        memset(&l, 0, sizeof(l));
        l.rlim_cur = RLIM_INFINITY;
        l.rlim_max = RLIM_INFINITY;
        if (setrlimit(RLIMIT_CORE, &l)) {
                bs_verbose(LOG_VERBOSE, "Unable to disable core size resource limit: %s\n", 
                        strerror(errno));
        }
}




Это сообщение отредактировал(а) fish9370 - 6.1.2016, 21:37


--------------------
undefined
PM MAIL WWW ICQ   Вверх
Zerstroer
Дата 7.1.2016, 13:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 8.8.2007
Где: Алма-Ата

Репутация: нет
Всего: 3



fish9370, т.е. это принудительный краш с дампом?


--------------------
In silico
PM MAIL ICQ   Вверх
fish9370
Дата 7.1.2016, 14:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 663
Регистрация: 15.4.2007
Где: Москва

Репутация: 2
Всего: 1



Цитата(Zerstroer @  7.1.2016,  13:45 Найти цитируемый пост)
т.е. это принудительный краш с дампом? 


нет, это дамп памяти процесса, в момент краша, со всеми стеками 



--------------------
undefined
PM MAIL WWW ICQ   Вверх
Zerstroer
Дата 8.1.2016, 13:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 8.8.2007
Где: Алма-Ата

Репутация: нет
Всего: 3



fish9370, пробую воспользоваться этой штукой. Тему пока оставляю открытой, на случай возникновения вопросов.


--------------------
In silico
PM MAIL ICQ   Вверх
Zerstroer
Дата 3.2.2016, 19:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 8.8.2007
Где: Алма-Ата

Репутация: нет
Всего: 3



fish9370, ну вот, прошел почти месяц, как я запустил бинарник с реализованым функционалам сброса дампа. Почти через месяц мой демон таки вывалился. Дамп на руках есть. Бинарник, который запускался есть.
Команда
gdb бинарник /путь_к_дампу/дамп на моей машине выдает следующее:

Код

Reading symbols from binary0_00_debug...done.

warning: core file may not match specified executable file.
[New LWP 59888]

warning: .dynamic section for "/lib/x86_64-linux-gnu/libc.so.6" is not at the expected address (wrong library or version mismatch?)

warning: .dynamic section for "/lib64/ld-linux-x86-64.so.2" is not at the expected address (wrong library or version mismatch?)
Core was generated by `./binary0_00_debug -f my_config/ylsk.conf'.
Program terminated with signal SIGABRT, Aborted.
#0  0x00007feb36576425 in find_derivation (toset=0x7fff0bfbed00 "\310\373\373\v\377\177", toset_expand=0x7fff0bfbec40 "", fromset=0x7feb3662fcdf <__getcwd+1503> "\201,", fromset_expand=0x0, handle=0x7fff0bfbfbc0, nsteps=0x0)
    at gconv_db.c:523
523     gconv_db.c: Нет такого файла или каталога.


Помогите, пожалуйста, интерпретировать результаты. 
Есть еще два вопроса.
1. Как я могу сделать вывод более информативным?
2. Данные не собрались в дамп ядра или gdb не может их интерпретировать?

upd.
Почесал макушку и сделал bt.
Получил следующий вывод от gdb:
Код

(gdb) bt 10
#0  0x00007feb36576425 in raise () from /lib/x86_64-linux-gnu/libc.so.6
#1  0x00007feb36579b8b in abort () from /lib/x86_64-linux-gnu/libc.so.6
#2  0x00007feb365b439e in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#3  0x00007feb365beb96 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#4  0x0000000000411610 in main (argc=3, argv=0x7fff0bfbfbc8) at main.c:817


А в main.c на строчке 817 у меня как раз есть free()...

Это сообщение отредактировал(а) Zerstroer - 3.2.2016, 19:56


--------------------
In silico
PM MAIL ICQ   Вверх
xvr
Дата 4.2.2016, 13:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 20
Всего: 223



Похоже что на машине, где вы пытаетесь запустит gdb и на машине, где получен core dump разные версии ОС (по крайней мере библиотек)

PM MAIL   Вверх
fish9370
Дата 5.2.2016, 00:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 663
Регистрация: 15.4.2007
Где: Москва

Репутация: 2
Всего: 1



Цитата(Zerstroer @  3.2.2016,  19:24 Найти цитируемый пост)
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

Цитата(Zerstroer @  3.2.2016,  19:24 Найти цитируемый пост)
2. Данные не собрались в дамп ядра или gdb не может их интерпретировать?


Лезть в ядро нет ни какого смысла, если мы пишем в usermode. В помощь отладчику можно установить доп пакет, и он будет показывать, что вызывается в ядре, но это не нужно

PS: можешь выслать сордамп и бинарник, если можешь вышли исходник, попробуем определить проблему


--------------------
undefined
PM MAIL WWW ICQ   Вверх
fish9370
Дата 5.2.2016, 00:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 663
Регистрация: 15.4.2007
Где: Москва

Репутация: 2
Всего: 1



Цитата(Zerstroer @  3.2.2016,  19:24 Найти цитируемый пост)
А в main.c на строчке 817 у меня как раз есть free()...


ну значит, двойное освобождение

тут я бы посоветовал обнулять указатели после освобождения и делать проверку указателя на NULL


--------------------
undefined
PM MAIL WWW ICQ   Вверх
Zerstroer
Дата 5.2.2016, 09:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 8.8.2007
Где: Алма-Ата

Репутация: нет
Всего: 3



fish9370, обнуления указателей у меня как раз таки и не было. Присвоение NULL после free() сделал. Хотя ситуация очень странная, перепроверил код, не нашел ничего, что могло бы приводить к двойному освобождению.
Я правильно понял, что проверку на NULL нужно выполнять перед вызовом free()?

Пока опять же запустил бинарник в работу.

Coredump и бинарник вышлю, если опять произойдет вывал.

Исходники не маленькие и им явно требуется сторонняя ревизия так как пишу я в одиночку и могу заблуждаться насчет читабельности и адекватности своего кода.  smile 

Это сообщение отредактировал(а) Zerstroer - 5.2.2016, 10:06


--------------------
In silico
PM MAIL ICQ   Вверх
fish9370
Дата 6.2.2016, 12:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 663
Регистрация: 15.4.2007
Где: Москва

Репутация: 2
Всего: 1



Цитата(Zerstroer @  5.2.2016,  09:05 Найти цитируемый пост)
Я правильно понял, что проверку на NULL нужно выполнять перед вызовом free()?


да, правильно. Но такая ситуация, скорее всего, свидетельствует о том, что в логике присутствует ошибка, так как такого быть не должно. И возможно тут следует поставить assert


Цитата(Zerstroer @  5.2.2016,  09:05 Найти цитируемый пост)
Coredump и бинарник вышлю, если опять произойдет вывал.


подождем  smile

Добавлено через 4 минуты и 15 секунд
Цитата(Zerstroer @  5.2.2016,  09:05 Найти цитируемый пост)
Исходники не маленькие и им явно требуется сторонняя ревизия 


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


--------------------
undefined
PM MAIL WWW ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Программирование под Unix/Linux"
xvr
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • Не забывайте пользоваться кнопкой "Код".
  • Вопросы мобильной разработки тут
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к разделу форума. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, xvr.

 
 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Программирование под Unix/Linux | Следующая тема »


 




[ Время генерации скрипта: 0.1701 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.