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

Ubuntu下C语言项目出现free(): invalid pointer错误排查求助

链表内存释放时出现free(): invalid pointer错误的排查与修复

问题场景

我有一个约2000行代码的C语言项目,使用链表存储程序数据。程序结束时调用自定义的freeSymbolTable函数释放链表内存,却触发如下错误:

free(): invalid pointer
Aborted (code dumped)

所有链表节点均通过insertSymbol函数在堆内存上分配,链表相关代码如下:

SymbolTable.h 文件内容

#ifndef SYMBOL_TABLE_H
#define SYMBOL_TABLE_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "constants.h"

/**
 *  a struct holding the SymbolTable information
*/
typedef struct SymbolTable {
    char* symbol;
    unsigned int identifier:2;
    int value;
    struct SymbolTable *next;
} SymbolTable;

extern SymbolTable* symbol_table;

/**
 * Function insertSymbol
 * ---------------------
 * gets the symbol information (e.g. symbol name, identefier and value)
 * and insert it to the symbol table
 * 
 * @param symbol: string holding the symbol name
 * @param identerfier: an integer holding the id of the symbol (e.g. .code, .mdefine or .data)
 * @param value: the value of the symbol in the memory
*/
void insertSymbol(const char* symbol, const int identifier, const int value);

/**
 * Function lookupSymbol
 * ----------------------
 * searching a symbol in the symbol table
 * 
 * @param symbol: a string holding the symbol name to search
 * 
 * @return a pointer to the symbol matching the name passed as an argument
*/
SymbolTable* lookupSymbol(const char* symbol);

/**
 * Function freeSymbolTable
 * ------------------------
 * releasing the memory that was allocated to the symbol_table data structure
*/
void freeSymbolTable();

#endif

对应源文件内容

#include "../headers/symbolTable.h"

SymbolTable* symbol_table = NULL;

void insertSymbol(const char *symbol, const int identifier, const int value)
{
    SymbolTable **temp = &symbol_table;
    while (*temp != NULL) {
        temp = &(*temp)->next;
    }
    *temp = (SymbolTable*)calloc(1, sizeof(SymbolTable));
    (*temp)->symbol = (char*)calloc(strlen(symbol) + 1, sizeof(char));
    strcpy((*temp)->symbol, symbol);
    (*temp)->identifier = identifier;
    (*temp)->value = value;
    (*temp)->next = NULL;
}

SymbolTable* lookupSymbol(const char *symbol)
{
    SymbolTable *temp = symbol_table;

    /* iterating over the symbol table and returning a pointer to the symbol if it was found otherwise returning null */
    while (temp != NULL) {
        if (strcmp(temp->symbol, symbol) == 0) {
            return temp;
        }
        temp = temp->next;
    }
    return NULL;
}

void freeSymbolTable()
{
    /* iterating over the symbol table and releasing the memory that was allocated for it */
    SymbolTable *temp = NULL;
    while (symbol_table != NULL)
    {
        temp = symbol_table;
        symbol_table = symbol_table->next;
        free(temp);
        temp = NULL;
    }
}

注:项目中所有添加节点的操作均通过调用insertSymbol函数完成,未自行添加节点,问题应出在上述代码中。


问题根源

  1. 未释放节点内的堆内存:每个SymbolTable节点的symbol字段是通过calloc单独分配的堆内存,但freeSymbolTable只释放了节点结构体本身,没有释放symbol指向的内存。这会导致内存泄漏,且如果后续代码中意外访问或释放这些未被清理的指针,就会触发invalid pointer错误。
  2. 全局变量操作风险:freeSymbolTable直接修改全局变量symbol_table,如果释放过程中有其他代码(比如多线程场景)修改该变量,会导致指针混乱;另外,若有其他地方保存了旧的节点指针,释放后再访问也会引发错误。

修复方案

修正后的freeSymbolTable函数

void freeSymbolTable()
{
    SymbolTable *current = symbol_table;
    SymbolTable *next_node = NULL;
    
    while (current != NULL)
    {
        next_node = current->next;
        // 先释放节点内的symbol字符串内存
        free(current->symbol);
        // 再释放节点结构体本身
        free(current);
        current = next_node;
    }
    // 最后将全局表头置空,避免野指针
    symbol_table = NULL;
}

额外优化建议

  • 添加内存分配检查:insertSymbol中未检查calloc的返回值,若内存分配失败会导致空指针操作,建议添加错误处理:
    *temp = (SymbolTable*)calloc(1, sizeof(SymbolTable));
    if (!*temp) {
        perror("Failed to allocate symbol table node");
        exit(EXIT_FAILURE);
    }
    (*temp)->symbol = (char*)calloc(strlen(symbol) + 1, sizeof(char));
    if (!(*temp)->symbol) {
        perror("Failed to allocate symbol string");
        free(*temp);
        exit(EXIT_FAILURE);
    }
    
  • 避免重复插入:insertSymbol未检查符号是否已存在,重复插入会导致冗余节点,建议插入前调用lookupSymbol确认:
    if (lookupSymbol(symbol)) {
        // 符号已存在,可选择报错或跳过
        fprintf(stderr, "Symbol %s already exists\n", symbol);
        return;
    }
    
  • 减少全局变量依赖:尽量将链表表头作为参数传递给相关函数,降低全局变量带来的耦合和副作用。

内容的提问来源于stack exchange,提问作者roee

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 06:43:12