Вызов calloc - утечка памяти Valgrind - PullRequest
4 голосов
/ 27 мая 2010

Следующий код является примером из библиотеки меню NCURSES . Я не уверен, что может быть не так с кодом, но valgrind сообщает о некоторых проблемах. Есть идеи ...

==4803== 1,049 (72 direct, 977 indirect) bytes in 1 blocks are definitely lost in loss record 25 of 36
==4803==    at 0x4C24477: calloc (vg_replace_malloc.c:418)
==4803==    by 0x400E93: main (in /home/gerardoj/a.out)
==4803== 
==4803== LEAK SUMMARY:
==4803==    definitely lost: 72 bytes in 1 blocks
==4803==    indirectly lost: 977 bytes in 10 blocks
==4803==      possibly lost: 0 bytes in 0 blocks
==4803==    still reachable: 64,942 bytes in 262 blocks

Исходный код:

#include <curses.h>
#include <menu.h>

#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define CTRLD   4

char *choices[] = {
    "Choice 1",
    "Choice 2",
    "Choice 3",
    "Choice 4",
    "Choice 5",
    "Choice 6",
    "Choice 7",
    "Exit",
}
;

int main()
{
    ITEM **my_items;
    int c;
    MENU *my_menu;
    int n_choices, i;
    ITEM *cur_item;

    /* Initialize curses */
    initscr();
    cbreak();
    noecho();
    keypad(stdscr, TRUE);

    /* Initialize items */
    n_choices = ARRAY_SIZE(choices);
    my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
    for (i = 0; i < n_choices; ++i) {
        my_items[i] = new_item(choices[i], choices[i]);
    }
    my_items[n_choices] = (ITEM *)NULL;

    my_menu = new_menu((ITEM **)my_items);

    /* Make the menu multi valued */
    menu_opts_off(my_menu, O_ONEVALUE);

    mvprintw(LINES - 3, 0, "Use <SPACE> to select or unselect an item.");
    mvprintw(LINES - 2, 0, "<ENTER> to see presently selected items(F1 to Exit)");
    post_menu(my_menu);
    refresh();

    while ((c = getch()) != KEY_F(1)) {
        switch (c) {
        case KEY_DOWN:
            menu_driver(my_menu, REQ_DOWN_ITEM);
            break;
        case KEY_UP:
            menu_driver(my_menu, REQ_UP_ITEM);
            break;
        case ' ':
            menu_driver(my_menu, REQ_TOGGLE_ITEM);
            break;
        case 10:
            {
                char temp[200];
                ITEM **items;

                items = menu_items(my_menu);
                temp[0] = '\0';
                for (i = 0; i < item_count(my_menu); ++i)
                if(item_value(items[i]) == TRUE) {
                    strcat(temp, item_name(items[i]));
                    strcat(temp, " ");
                }
                move(20, 0);
                clrtoeol();
                mvprintw(20, 0, temp);
                refresh();
            }
            break;
        }
    }
    unpost_menu(menu);
    free_item(my_items[0]);
    free_item(my_items[1]);
    free_item(my_items[2]);
    free_item(my_items[3]);
    free_item(my_items[4]);
    free_item(my_items[5]);
    free_item(my_items[6]);
    free_item(my_items[7]);
    free_menu(my_menu);
    endwin();
}

Ответы [ 4 ]

3 голосов
/ 27 мая 2010

В соответствии с инструкцией NCURSES , использование библиотеки меню требует следующих шагов:

Инициализировать проклятия Создание элементов с помощью new_item (). Вы можете указать название и описание для предметов. Создайте меню с помощью new_menu (), указав элементы, к которым нужно присоединиться. Опубликовать меню с помощью menu_post () и обновить экран. Обрабатывает пользовательские запросы с помощью цикла и делает необходимые обновления в меню с помощью menu_driver. Отмена публикации меню с помощью menu_unpost () Освободить память, выделенную для меню free_menu () Освободить память, выделенную для элементов с помощью free_item () Конечные проклятия

Из того, что я могу сказать из вашего кода:

  • Вы не можете отменить публикацию меню (которое может привести к утечке или может просто испортить экран).
  • Меню освобождается после освобождения элементов (что, я думаю, может или не может быть проблемой в зависимости от того, как реализован ncurses).
  • Только элементы 0 и 1 из 8-элементного массива элементов освобождаются. Это, вероятно, утечка.
  • Массив указателей my_items никогда не освобождается. Это, безусловно, утечка.

Как сказал @ lh3, компиляция с опцией -g позволит Valgrind указать номер строки потерянной памяти.

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

Другими словами, каждый calloc или malloc нуждается в free, каждый new_item нуждается в free_item и т. Д.

for (i = 0; i < n_choices; ++i) {
    free_item(my_items[i]);
}
free(my_items);
1 голос
/ 27 мая 2010

Что следует отметить с Valgrind (это часто встречается в списке рассылки пользователя Valgrind часто):

still reachable: 64,942 bytes in 262 blocks

Это просто ссылка на блоки, которые все еще были доступны в main() на выходе, которые (при любом современном ядре) будут в любом случае исправлены ОС.

Хотя рекомендуется явно free() каждый отдельный выделенный блок перед вызовом exit, это не technically утечка памяти, поскольку она все еще может быть достигнута во время выхода.

Сосредоточьтесь на прямых, косвенных и, возможно, потерянных блоках, как предложил Джош Келли . Это всего лишь дополнение к ответам, которые уже указали на возможные источники утечек.

0 голосов
/ 27 мая 2010
free_item(my_items[7]);
free(my_items);
0 голосов
/ 27 мая 2010

попробуйте запустить valgrind с --leak-check = full возможно?

...