输入非空行后按回车触发double free detected in tcache 2错误原因排查
问题分析:双重释放错误的根源
核心问题1:未初始化的链表头指针sf
在set_foo函数中,sf是局部指针变量,仅在输入非空字符的分支里被赋值为链表头节点。当你输入空行(仅按回车)时,if条件不成立,sf没有被初始化,此时返回的是一个随机的野指针。
当free_foo接收这个野指针后,会尝试释放它指向的内存——而这个内存大概率是之前已经释放过的链表节点内存,直接触发double free错误。
核心问题2:链表尾节点的p指针未置空
构建链表时,最后一个节点的p成员没有被设置为NULL,导致free_foo遍历链表时,最后一次f = f->p会得到野指针,后续循环的判断和释放操作会产生未定义行为,进一步加剧内存问题。
修复方案
1. 初始化sf为NULL
在set_foo函数开头给sf赋初始值,确保无论是否输入字符,返回的指针都是合法的:
struct foo* set_foo() { char c; struct foo* f; struct foo* sf = NULL; // 初始化sf为NULL if ((c = getchar()) != '\n' && c != EOF) { f = malloc(sizeof(struct foo)); f->c = c; sf = f; while ((c = getchar()) != '\n' && c != EOF) { f->p = malloc(sizeof(struct foo)); f->p->c = c; f = f->p; } f->p = NULL; // 给尾节点的p置空 } return sf; }
2. 给链表尾节点的p置空
在构建完链表后,必须将最后一个节点的p成员设为NULL,让free_foo的遍历能正确终止,避免访问野指针。
3. 简化free_foo(可选)
由于循环条件已经判断f != NULL,内部的sf != NULL判断属于冗余操作,可以直接删除:
void free_foo(struct foo* f) { struct foo* sf; while (f != NULL) { sf = f; f = f->p; free(sf); } }
修复后验证
- 仅按回车键:返回
NULL,free_foo直接跳过循环,无异常; - 逐行输入内容:链表尾节点
p为NULL,遍历释放流程正常; - 输入非空行后按回车键:第二次调用
set_foo返回NULL,不会触发非法释放,程序稳定运行。
内容的提问来源于stack exchange,提问作者user3225777
相关产品推荐
相关产品推荐

