Я не знаю, есть ли еще одна ветка с моей проблемой, но если есть, я не смог ее найти.
речь идет об освобождении теперь неиспользуемой ячейки / узла связанного списка. Я получаю с программой в текущем состоянии точный объем утечки, который я предсказываю, но 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
Неверное определение функции имеет избыточное выделение памяти
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 );