GNU readline: огромная утечка памяти - PullRequest
4 голосов
/ 16 марта 2019

Рассмотрим следующий фрагмент:

#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>

int main() {
    for (;;) {
        char *buf = readline(">>> ");
        if (!buf)
            break;

        free(buf);
    }
}

Компиляция с -lreadline, выполнение программы под valgrind и ввод некоторых строк приводят к огромной утечке памяти, на моей системе приговор valgrinds выглядит примерно так:

==7651== LEAK SUMMARY:
==7651==    definitely lost: 0 bytes in 0 blocks
==7651==    indirectly lost: 0 bytes in 0 blocks
==7651==      possibly lost: 0 bytes in 0 blocks
==7651==    still reachable: 213,455 bytes in 217 blocks
==7651==         suppressed: 0 bytes in 0 blocks

Запуск с --show-leak-kinds=all приводит к чему-то вроде этого (всего несколько сотен строк, я покажу только начало):

==7693== 5 bytes in 1 blocks are still reachable in loss record 1 of 57
==7693==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==7693==    by 0x48CE409: xmalloc (in /usr/lib/libreadline.so.8.0)
==7693==    by 0x48A72E6: rl_set_prompt (in /usr/lib/libreadline.so.8.0)
==7693==    by 0x48A87E6: readline (in /usr/lib/libreadline.so.8.0)
==7693==    by 0x10915C: main (in /home/.../a.out)
==7693== 
==7693== 5 bytes in 1 blocks are still reachable in loss record 2 of 57
==7693==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==7693==    by 0x48CE409: xmalloc (in /usr/lib/libreadline.so.8.0)
==7693==    by 0x48B95BC: ??? (in /usr/lib/libreadline.so.8.0)
==7693==    by 0x48B9D25: rl_expand_prompt (in /usr/lib/libreadline.so.8.0)
==7693==    by 0x48A7309: rl_set_prompt (in /usr/lib/libreadline.so.8.0)
==7693==    by 0x48A87E6: readline (in /usr/lib/libreadline.so.8.0)
==7693==    by 0x10915C: main (in /home/.../a.out)
==7693== 
==7693== 8 bytes in 1 blocks are still reachable in loss record 3 of 57
==7693==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==7693==    by 0x496C49E: strdup (in /usr/lib/libc-2.28.so)
==7693==    by 0x4AEEDCD: _nc_trim_sgr0 (in /usr/lib/libncursesw.so.6.1)
==7693==    by 0x4AE7EA2: tgetent_sp (in /usr/lib/libncursesw.so.6.1)
==7693==    by 0x48C39BC: _rl_init_terminal_io (in /usr/lib/libreadline.so.8.0)
==7693==    by 0x48A851C: rl_initialize (in /usr/lib/libreadline.so.8.0)
==7693==    by 0x48A87EC: readline (in /usr/lib/libreadline.so.8.0)
==7693==    by 0x10915C: main (in /home/.../a.out)

Теперь, несмотря на то, что память не потеряна, тот факт, что readline просто не освобождает огромные куски памяти до выхода из программы, кажется мне совершенно абсурдным. Я что-то пропустил? Должен ли я вручную вызывать некоторые плохо документированные функции очистки? Это ошибка? Это происходит в каждой системе?

Похоже, что в Интернете возникает несколько похожих проблем, но я был удивлен, увидев, что это происходит даже в простейшем случае использования.

РЕДАКТИРОВАТЬ: потому что было много обсуждений, я поясню немного: ответ Бруно, конечно, правильный, это не утечка памяти в традиционном смысле и почти на всех платформах это не будет иметь никакого значения (я включил тег Linux, который был ошибкой, я удалил его сейчас), но я все же хотел бы знать, действительно ли это сделано намеренно или произойдет ли это потому, что память освобождается только после того, как valgrind выдаст свою статистику, и если есть какой-либо способ обойти это (или, по крайней мере, заставить valgrind игнорировать его, чтобы он не скрывал пропущенные вызовы free в остальной части моего кода)

1 Ответ

11 голосов
/ 16 марта 2019

GNU readline: огромная утечка памяти

==7651== LEAK SUMMARY:
==7651==    definitely lost: 0 bytes in 0 blocks
==7651==    indirectly lost: 0 bytes in 0 blocks
==7651==      possibly lost: 0 bytes in 0 blocks

Нет утечки памяти

==7651==    still reachable: 213,455 bytes in 217 blocks
==7651==         suppressed: 0 bytes in 0 blocks
...

A достижимо память не является утечкой памяти

==7693== 5 bytes in 1 blocks are still reachable in loss record 1 of 57
==7693==    at 0x483777F: malloc (vg_replace_malloc.c:299)
==7693==    by 0x48CE409: xmalloc (in /usr/lib/libreadline.so.8.0)
==7693==    by 0x48A72E6: rl_set_prompt (in /usr/lib/libreadline.so.8.0)
==7693==    by 0x48A87E6: readline (in /usr/lib/libreadline.so.8.0)
==7693==    by 0x10915C: main (in /home/.../a.out)
...

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

Function: void rl_clear_history (void)
  Clear the history list by deleting all of the entries, in the same
  manner as the History library's clear_history() function. This differs
  from clear_history because it frees private data Readline saves in the history list.
...