heapusage обнаруживает утечку памяти, возможно, вызванную printf - PullRequest
4 голосов
/ 02 мая 2019

Я реализую очередь приоритетов со связанным списком в C, однако я получаю утечки памяти, когда я печатаю свои pop операции. У меня другая утечка памяти, и я тоже пытаюсь ее найти.

В качестве примечания я использую heapusage на d99kris вместо Valgrind.

Это сводная куча, когда я использую printf:

HEAP SUMMARY:
in use at exit: 4112 bytes in 2 blocks
total heap usage: 10 allocs, 17 frees, 4536 bytes allocated
peak heap usage: 4256 bytes allocated
16 bytes in 1 block(s) are lost, originally allocated at:
LEAK SUMMARY:
definitely lost: 4112 bytes in 2 blocks

Это сводная куча без printf:

HEAP SUMMARY:
in use at exit: 16 bytes in 1 blocks
total heap usage: 9 allocs, 10 frees, 440 bytes allocated
peak heap usage: 256 bytes allocated
LEAK SUMMARY:
definitely lost: 16 bytes in 1 blocks

Моя pop функция:

void *prio_q_pop(struct prio_q *q) {
     q->size--;
     struct elem *temp = q->first;
     (q->first) = (q->first)->next;
     void *asd = temp->datei;
     free(temp);
     return asd;
 }

И моя main функция, где я звоню printf

struct prio_q *queue;
     char *s;
     int i;

     queue = prio_q_create();

     push(queue, "Bye World", 0);

     for (i = 0; i < 5; i++) {
         s = prio_q_pop(queue);
         //printf("%s\n", s);
     }
     s = prio_q_front(queue);
     //printf("%s\n", s);                                                                          

причина

Проблема не вызвана моим кодом, это проверка памяти. Следующая программа пропускает 1 блок с использованием кучи, равной 2 alloc и 4 free.

#include <stdio.h>

int main() {
    printf("omer");
    return 0;
}

Ответы [ 2 ]

8 голосов
/ 02 мая 2019

Это ложное срабатывание. Во всяком случае, проблема в том, что у heapusage недостаточно хорошей документации. Я рекомендую использовать более качественную систему проверки утечек, например, дезинфицирующее средство от утечек или Valgrind.

Я создал файл test.c.

#include <stdio.h>
int main(int argc, char **argv) {
    puts("Hello, world!");
}

С дезинфицирующим средством от утечек, без ошибок.

$ cc -fsanitize=leak -g test.c
$ ./a.out 
Hello, world!

С адресным дезинфицирующим средством, без ошибок.

$ cc -fsanitize=address -g test.c
$ ./a.out 
Hello, world!

С Valgrind ошибок нет.

$ cc -g test.c
$ valgrind ./a.out
==189174== Memcheck, a memory error detector
==189174== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==189174== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==189174== Command: ./a.out
==189174== 
Hello, world!
==189174== 
==189174== HEAP SUMMARY:
==189174==     in use at exit: 0 bytes in 0 blocks
==189174==   total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated
==189174== 
==189174== All heap blocks were freed -- no leaks are possible
==189174== 
==189174== For counts of detected and suppressed errors, rerun with: -v
==189174== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

С кучей, течь!

$ cc -g test.c                  
$ ./heapusage ./a.out
Hello, world!
==189005== Heapusage - https://github.com/d99kris/heapusage
==189005== 
==189005== HEAP SUMMARY:
==189005==     in use at exit: 1024 bytes in 1 blocks
==189005==   total heap usage: 1 allocs, 0 frees, 1024 bytes allocated
==189005==    peak heap usage: 1024 bytes allocated
==189005== 
==189005== 1024 bytes in 1 block(s) are lost, originally allocated at:
==189005==    at 0x00007f99f0de56a7: malloc + 49
==189005==    at 0x00007f99f0a96a32: _IO_file_doallocate + 114
==189005==    at 0x00007f99f0aa4a46: _IO_doallocbuf + 70
==189005==    at 0x00007f99f0aa3da8: _IO_file_overflow + 472
==189005==    at 0x00007f99f0aa2e86: _IO_file_xsputn + 182
==189005==    at 0x00007f99f0a99033: _IO_puts + 211
==189005==    at 0x000055f667ee7655: 
==189005==    at 0x00007f99f0a502b1: __libc_start_main + 241
==189005==    at 0x000055f667ee755a: 
==189005== 
==189005== LEAK SUMMARY:
==189005==    definitely lost: 1024 bytes in 1 blocks
==189005== 

Анализ

Heapusage работает, перехватывая malloc и free (и не сканирует память на предмет указателей). Heapusage не объясняет преимущества или недостатки этого подхода полностью в документации. Одним из преимуществ является то, что это быстро, но недостатком является то, что это не точно.

В частности, я бы назвал heapusage неправильными сообщениями: слова «определенно потерянный» здесь не применимы!

Если вам нужны более качественные сообщения об ошибках, используйте один из рекомендованных выше инструментов: средство для устранения утечек или Valgrind (memcheck).

В общем, я также хотел бы напомнить людям, что ложные срабатывания являются фактом жизни с такими инструментами. Вопрос о том, является ли программа «Valgrind clean», отличается от правильности программы.

3 голосов
/ 02 мая 2019

В отличие от Valgrind, heapusage не отслеживает память, выделенную библиотекой C для своих собственных целей.printf косвенно вызывает это, поскольку поток stdout буферизуется строкой в ​​терминал и полностью буферизируется в файл.Потоковый буфер распределяется (printf или любой другой выходной функцией) только тогда, когда вы фактически производите вывод.

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

#include <stdio.h>

int main() {
    setvbuf(stdout, NULL, _IONBF, 0);
    printf("omer\n");
    return 0;
}

Если в приведенном выше коде все еще обнаружена утечка, попробуйте эту альтернативу:

#include <stdio.h>

int main() {
    char buf[BUFSIZ];
    setvbuf(stdout, buf, _IONBF, BUFSIZ);
    printf("omer\n");
    fclose(stdout);
    return 0;
}

Обратите внимание также, что чтение ввода из stdin выделит буфер длявходной поток тоже.Любой другой поток, открытый программой, должен быть закрыт до выхода из функции main().Закрытие потока освобождает любую память, выделенную для него за сценой.

...