从内存泄漏中释放后的堆使用

问题描述 投票:1回答:1

因此,我正在测试一个函数,该函数可以正常工作,但是由于某种原因,当我与valgrind一起使用fsantize时,我在释放后获得了堆使用率,而在free之后就没有了。

错误:

==18707==ERROR: AddressSanitizer: heap-use-after-free on address 0x6030000093e8 at pc 0x55d773ca7cab bp 0x7fffc6cd72c0 sp 0x7fffc6cd72b0
READ of size 8 at 0x6030000093e8 thread T0
    #0 0x55d773ca7caa in main /home/martim/Desktop/projeto iaed/teste de linked lists/teste_todo.c:114
    #1 0x7f78eabb7b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #2 0x55d773ca40c9 in _start (/home/martim/Desktop/projeto iaed/teste de linked lists/foo_3689+0x10c9)

0x6030000093e8 is located 24 bytes inside of 32-byte region [0x6030000093d0,0x6030000093f0)
freed by thread T0 here:
    #0 0x7f78eb0657a8 in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xde7a8)
    #1 0x55d773ca4fc0 in FREEnode_v /home/martim/Desktop/projeto iaed/teste de linked lists/Listas_ligadas2.h:82
    #2 0x55d773ca50cf in delete_el_v /home/martim/Desktop/projeto iaed/teste de linked lists/Listas_ligadas2.h:97
    #3 0x55d773ca7c82 in main /home/martim/Desktop/projeto iaed/teste de linked lists/teste_todo.c:115
    #4 0x7f78eabb7b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)

previously allocated by thread T0 here:
    #0 0x7f78eb065b40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40)
    #1 0x55d773ca4baa in NEW_vit /home/martim/Desktop/projeto iaed/teste de linked lists/Listas_ligadas2.h:30
    #2 0x55d773ca4db7 in insertEnd_v /home/martim/Desktop/projeto iaed/teste de linked lists/Listas_ligadas2.h:49
    #3 0x55d773ca690c in adiciona_eq /home/martim/Desktop/projeto iaed/teste de linked lists/FUNCOES_AUX.h:296
    #4 0x55d773ca6c1d in A /home/martim/Desktop/projeto iaed/teste de linked lists/FUNCOES_MAIN.h:20
    #5 0x55d773ca765d in main /home/martim/Desktop/projeto iaed/teste de linked lists/teste_todo.c:56
    #6 0x7f78eabb7b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)

我基本上使用此free功能的功能:

这是使用的主要功能(FUNCOES_MAIN.h的一部分)

void A(char nome[], link_v* head2,int valores[]) {
    int check;
    check = adiciona_eq(nome, &*head2, valores);
    if (check == 1)
        printf("%d Equipa existente.\n", valores[1]);
}

这是一个辅助功能,基本上可以完成我想要的所有事情(FUNCOES_AUX.h的一部分)

int adiciona_eq(char nome[], link_v* head, int valores[]) {
    link_v t;
    for (t = *head; t != NULL; t = t->next) {
        if (strcmp(t->v.nome, nome) == 0)
            return 1;
    }
    *head = insertEnd_v(*head, nome, valores);
    valores[3] = 0;
    return 0;
}

这是我用于链接列表的头文件的一部分(这是此函数中使用的唯一部分,也是Listas_ligadas2.h的一部分)

typedef struct vit {
    int id;
    char *nome;
    int vit;
} vit;

/*--------- Estrutura que representa um nodo de uma lista de vitorias ------------*/

typedef struct node_v {
    vit v;
    struct node_v *next;
} *link_v;

/*A funcao NEW_v cria um nodo da lista de vitorias.*/
link_v NEW_vit(char *nome, int val[]) {
    link_v x = (link_v)malloc(sizeof(struct node_v));
    x->v.nome = (char*)malloc(sizeof(char) * (strlen(nome) + 1));
    strcpy(x->v.nome, nome);
    x->v.vit = 0;
    x->v.id = val[0];
    x->next = NULL;
    val[0]++;
    return x;
}

/*A funcao insertEnd_v insere o nodo criado por NEW_v na lista de vitorias.*/
link_v insertEnd_v(link_v head, char *nome, int val[]) {
    link_v x;
    if (head == NULL)
        return NEW_vit(nome, val);
    for (x = head; x->next != NULL; x = x->next)
        ;
    x->next = NEW_vit(nome, val);
    return head;
}

[如果让您感到困惑,对不起,但是基本上这是我的main程序:

#include <stdlib.h> 
#include <stdio.h>
#include <string.h>
#include "Listas_ligadas2.h"
#include "FUNCOES_PROTOTIPO_AUX.h"
#include "FUNCOES_PROTOTIPO_MAIN.h"
#include "FUNCOES_AUX.h"
#include "FUNCOES_MAIN.h"

#define MAX_CHARS 1024

/*
ident: val[0]
line of stdin: val[1]
*/

int main() {
    char c;
    char nome[MAX_CHARS];
    int valores[2] = { 0, 1 };
    link_v head2 = NULL;
    link_v yf;
    while ((c = getchar())!= 'x') {
        switch (c) {
          case 'A':
            {
                scanf("%1023[^:\n]", nome);
                remove_esp(nome);
                A(nome, &head2,valores);
                valores[1]++;
                break;
            }
        }
    }
    for (yf = head2; yf != NULL; yf = yf->next) {
        delete_el_v(yf, yf->v.nome);
    }
    return 0;
}
c pointers memory-leaks heap-corruption
1个回答
0
投票

由于您未提供函数delete_el_v的代码,因此我必须推测。我的猜测是问题出在以下代码中:

for (yf = head2; yf != NULL; yf = yf->next) {
    delete_el_v(yf, yf->v.nome);
}

我假设函数delete_el_v首先释放yf->v.name,然后释放yf,因为反之亦然,其本身会导致undefined behavior

如果我的假设是正确的,则该部分代码将有效地执行以下操作:

for (yf = head2; yf != NULL; yf = yf->next) {
    free( yf->v.name );
    free( yf );
}

但是,这也会导致不确定的行为,因为在循环的每次迭代之后,您都在对表达式yf->next求值。此时,指针yfdangling pointer,因为它已被释放。因此,用表达式yf->next取消引用悬空指针会导致未定义的行为。这可能是您收到“免费使用后堆”消息的原因。

要解决此问题,建议将代码更改为以下内容:

yf = head2;
while ( yf != NULL ) {
    struct node_v *temp = yf;
    yf = yf->next;
    free( temp->v.name );
    free( temp );
}
© www.soinside.com 2019 - 2024. All rights reserved.