You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

输入非空行后按回车触发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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 08:11:27