C - 从内存泄漏派生的释放后的堆使用



所以我正在测试一个函数,我让它工作,但出于某种原因,当我fsantize与 valgrind 一起使用时,我在自由后得到了一个堆使用,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;
}

由于您没有提供函数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,因为反过来做本身会导致未定义的行为。

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

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

但是,这也会导致未定义的行为,因为在循环的每次迭代之后,您都会计算表达式yf->next。此时,指针yf是一个悬空指针,因为它已被释放。因此,使用表达式取消引用该悬空指针yf->next导致未定义的行为。这可能是您收到"释放后堆使用"消息的原因。

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

yf = head2;
while ( yf != NULL ) {
struct node_v *temp = yf;
yf = yf->next;
free( temp->v.name );
free( temp );
}

另外,您的线路

valores[3] = 0;

通过越界写入数组而导致未定义的行为。数组的大小为 2 个元素,但您正在写入其不存在的第 4 个元素。

最新更新