【问题标题】:Memory leak in linked list implementation C链表实现 C 中的内存泄漏
【发布时间】:2021-08-21 09:17:58
【问题描述】:

我不知道是否有其他线程与我的问题,但如果有,我找不到它。

问题是释放链表中现在未使用的单元/节点。 我在当前状态下得到了我预测的确切泄漏量,但是我使用的 2 'free()' 看起来有点过分了,IDE 已经警告我有关释放内存的访问。 (我已经运行了它并且 IDE 是正确的) 那么,如何重写我的代码以真正释放它应该释放的 1 个单元格?

我的节点:

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

【问题讨论】:

  • @Add 这个傻话的目的是什么 node_t *prev = make_list();?!
  • @Add This loop while (index > 0){ *prev = *target;目标=目标->下一个;指数 - ; } 可以在列表中的节点数小于 index 的值时调用未定义的行为。
  • 贴出的代码中没有动态内存分配,那么内存泄漏在哪里?
  • @Lundin make_list 呢?:)

标签: c memory-management memory-leaks linked-list singly-linked-list


【解决方案1】:

函数定义不正确有多余的内存分配

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 );

【讨论】:

    猜你喜欢
    • 2019-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-13
    • 2016-08-16
    • 2012-03-15
    • 1970-01-01
    • 2021-05-19
    相关资源
    最近更新 更多