二次调用内存释放函数触发段错误问题排查
问题场景与代码
定义的结构体如下:
typedef struct TrapAttribute { char name[16]; uint8_t type; } TrapAttribute; typedef struct TrapBlockType { uint16_t id; char name[16]; SDL_Texture **textures; uint8_t texturesCount; TrapAttribute **attributes; uint8_t attributesCount; } TrapBlockType;
对应的内存释放函数:
void TrapFreeAttributesList(TrapBlockType *type, uint8_t count){ for (int i = 0; i < count; i++){ free(type->attributes[i]); } free(type->attributes); } void TrapFreeTexturesList(TrapBlockType *type, uint8_t count); //本问题无需完整代码 void TrapFreeBlockType(TrapBlockType *type){ TrapFreeAttributesList(type, type->attributesCount); TrapFreeTexturesList(type, type->texturesCount); free(type); }
执行释放操作时,第一个结构体释放正常,第二个触发段错误:
TrapBlockType **list; //此处省略完整代码,该列表包含两个TrapBlockType * TrapFreeBlockType(list[0]); printf("Block type number 0 successfully freed\n"); TrapFreeBlockType(list[1]); //此处触发段错误 printf("Block type number 1 successfully freed\n");
经测试,段错误出现在TrapFreeAttributesList的循环条件判断处:
void TrapFreeAttributesList(TrapBlockType *type, uint8_t count){ for (int i = 0; i < count; i++){ //第二次调用时在此处触发段错误 free(type->attributes[i]); } free(type->attributes); }
将TrapFreeAttributesList的代码直接移入TrapFreeBlockType执行,问题依旧。
根本原因分析
1. 野指针/重复释放
如果两个TrapBlockType实例共享了同一个attributes数组,或者其中的某个TrapAttribute指针,第一次释放会将这些内存归还给系统。第二次释放时,访问的是已经失效的野指针,直接触发段错误。
2. 结构体初始化错误
第二个TrapBlockType的attributes指针未正确初始化(比如为NULL但attributesCount不为0),或者attributes数组内的元素是未分配内存的野指针。第一次释放未触发错误只是巧合,第二次操作刚好命中非法内存区域。
3. 内存越界污染
在创建或使用list的过程中,存在内存写越界操作,覆盖了第二个TrapBlockType的attributes指针或attributesCount的值。比如第一次释放时的内存操作越界,破坏了第二个结构体的关键字段,导致第二次释放时循环条件(i < count)中的count变成非法值,或type->attributes指向了无效内存。
针对循环条件触发错误的具体说明
段错误出现在i < count判断时,大概率是count(即type->attributesCount)被非法修改为一个极大值,导致i递增后访问了超出栈或数组范围的内存;或者type本身就是野指针(比如list[1]已被意外释放或覆盖)。
排查建议
- 检查
list的填充逻辑,确保两个TrapBlockType的attributes、attributesCount都是独立分配、正确初始化的,不存在指针共享。 - 创建
TrapBlockType时,确保未分配attributes数组时,attributesCount设为0;每个attributes[i]都通过malloc等函数分配了合法内存。 - 使用内存检测工具(如Valgrind),直接定位非法内存访问的具体位置和原因。
内容的提问来源于stack exchange,提问作者Hobbes

