Утечка памяти в реализации связанного списка C

Я не знаю, есть ли еще одна ветка с моей проблемой, но если есть, я не смог ее найти.

речь идет об освобождении теперь неиспользуемой ячейки / узла связанного списка. Я получаю с программой в текущем состоянии точный объем утечки, который я предсказываю, но 2 'free ()', которые я использую, кажутся излишними, и IDE уже предупреждает меня о доступе к освобожденной памяти. (Я уже запустил его, и IDE оказалась правильной) Итак, как мне переписать код, чтобы освободить только одну ячейку, которую он должен?

мои узлы:

typedef struct node {
    char val[2] ; //arrays (in this project of size 2)
    struct node * next;
} node_t;
// removes the item at the given position from the list (starting counting from 0)
// memory leakage but idk how to free
node_t* remove_from_list(node_t *head, int index){
    node_t *prev = make_list();
    printf("prev:");
    print_list(prev);
    node_t *target = head;
    printf("target:");
    print_list(target);
    // jumping to the location
    while (index > 0){
        *prev = *target;
        target = target->next;
        index--;
    }
    printf("after jump target:");
    print_list(target);
    printf("new prev:");
    print_list(prev);
    sleep(1);
    //checking if last slot in list
    if (is_list_empty(*target) == 2){ //true
        printf("last in chain");
        sleep(1);
        if (is_list_empty(*prev) == 0){ //list of only 1 elem special case
            printf("and (0)\n");
            sleep(1);
            free(prev);
            free(target);
            return NULL;
        }
        else{
            printf("\n");
            prev->next = NULL;
            //free(target);  <-- this doesnt work
            // else c complains that memory used after free
            return head;
        }
    }
    //if first in list
    if (is_list_empty(*prev) == 0){
        printf("first in chain\n");
        sleep(1);
        head = head->next;
        free(prev);
        return head;
    }
    //else
    printf("in the middle of chain\n");
    *prev->next = *target->next;
    printf("new list:\n");
    print_list(head);
    sleep(1);
    //free(target);  <-- this doesnt work
    return head;
}

вывод консоли в этом состоянии:

(e,f)->(c,d)->(a,b)->(x,y)->
prev:(0)->
target:(e,f)->(c,d)->(a,b)->(x,y)->
after jump target:(c,d)->(a,b)->(x,y)->
new prev:(e,f)->(c,d)->(a,b)->(x,y)->
in the middle of chain
new list:
(e,f)->(a,b)->(x,y)->
(e,f)->(a,b)->(x,y)->

=================================================================
==36817==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x7f9b91de5279 in __interceptor_malloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:145
    #1 0x56450617e2ea in make_list src/llist.c:11
    #2 0x56450617e7db in remove_from_list src/llist.c:66
    #3 0x56450617f16c in main src/main.c:45
    #4 0x7f9b91a1db24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)

Direct leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x7f9b91de5279 in __interceptor_malloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:145
    #1 0x56450617e2ea in make_list src/llist.c:11
    #2 0x56450617e696 in add_to_list src/llist.c:56
    #3 0x56450617f027 in main src/main.c:35
    #4 0x7f9b91a1db24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)

SUMMARY: AddressSanitizer: 32 byte(s) leaked in 2 allocation(s).

вывод консоли с включенными бесплатными:

(e,f)->(c,d)->(a,b)->(x,y)->
prev:(0)->
target:(e,f)->(c,d)->(a,b)->(x,y)->
after jump target:(c,d)->(a,b)->(x,y)->
new prev:(e,f)->(c,d)->(a,b)->(x,y)->
in the middle of chain
new list:
(e,f)->(a,b)->(x,y)->
=================================================================
==36962==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000050 at pc 0x5567843aacc0 bp 0x7ffc96b0e130 sp 0x7ffc96b0e120
READ of size 16 at 0x602000000050 thread T0
    #0 0x5567843aacbf in print_list src/llist.c:125
    #1 0x5567843ab194 in main src/main.c:46
    #2 0x7f415e820b24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)
    #3 0x5567843aa1fd in _start (/home/prog2/Project3/RaphDiener/pagerank+0x21fd)

0x602000000050 is located 0 bytes inside of 16-byte region [0x602000000050,0x602000000060)
freed by thread T0 here:
    #0 0x7f415ebe7f19 in __interceptor_free /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:127
    #1 0x5567843aabba in remove_from_list src/llist.c:116
    #2 0x5567843ab184 in main src/main.c:45
    #3 0x7f415e820b24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)

previously allocated by thread T0 here:
    #0 0x7f415ebe8279 in __interceptor_malloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:145
    #1 0x5567843aa2ea in make_list src/llist.c:11
    #2 0x5567843aa696 in add_to_list src/llist.c:56
    #3 0x5567843ab0d1 in main src/main.c:39
    #4 0x7f415e820b24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)

SUMMARY: AddressSanitizer: heap-use-after-free src/llist.c:125 in print_list
Shadow bytes around the buggy address:
  0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fff8000: fa fa 00 00 fa fa 00 00 fa fa[fd]fd fa fa 00 00
  0x0c047fff8010: fa fa 00 00 fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==36962==ABORTING
# linked-list memory-leaks memory-management singly-linked-list
Источник
  • 2
    Вам нужно показать минимально воспроизводимый пример
  • 0
    @Add Какова цель этого глупого оператора node_t * prev = make_list ();?!
  • 0
    @Add Этот цикл while (index> 0) {* prev = * target; цель = цель-> далее; показатель--; } может вызывать неопределенное поведение, когда количество узлов в списке меньше значения индекса.
  • 0
    В опубликованном коде нет динамического распределения памяти, так где же утечка памяти?
  • 0
    @Lundin А что с make_list? :)
  • 0
    @VladfromMoscow Определение не размещено. Насколько я знаю, это может быть функция форматирования HD.
  • 0
    Общее практическое правило: освободите память на том же уровне / модуле, где вы ее распределяете. Итак, если есть функция make_list, выполняющая динамическое размещение, должна быть соответствующая функция delete_list.
  • 0
    @Add Обсуждать нечего. Ваше определение функции не имеет смысла. Например, этот оператор if if (is_list_empty (* target) == 2) {выглядит очень глупо. Перепишите функцию заново.
  • 0
    @Add Функция is_list_empty должна возвращать либо true (1), либо false (0). Что означает 2 для читателей кода ?! В целом определение функции глупое. Вы выделяете память, когда она не требуется. Вы написали цикл while, который может вызывать неопределенное поведение и так далее. Очень и очень глупое определение функции.
Codelisting
за 0 против

Неверное определение функции имеет избыточное выделение памяти

node_t *prev = make_list();

(если функции нужно что-то удалить, зачем она что-то создает ?!) может вызывать неопределенное поведение.

while (index > 0){
    *prev = *target;
    target = target->next;
    index--;
}

(в цикле нет проверки, равна ли target NULL) и его код неясен

if (is_list_empty(*target) == 2){ //true

(что означает магическое число 2 ?! Читатель кода ожидает, что функция вернет либо 1 (истина), либо 0 (ложь))

Я покажу, как можно просто реализовать эту функцию. Исследуйте это В любом случае, если вы хотите написать собственное определение функции, тем не менее, представленное определение функции будет вам полезно.

int remove_from_list( node_t **head, size_t index )
{
    while ( *head && index-- )
    {
        head = &( *head )->next;
    }

    int success = *head != NULL;

    if ( success )
    {
        node_t *tmp = *head;
        *head = ( *head )->next;
        free( tmp );
    }

    return success;
} 

И функция может вызываться хотя бы как

remove_from_list( &head, index );
Codelisting
Популярные категории
На заметку программисту