C语言调用free触发double free或corruption错误的问题排查
问题原因排查
核心根因
内存分配时的类型大小计算错误,导致堆内存越界写入,破坏了malloc/free维护的堆元数据,是触发free报错的核心原因。
具体错误点
在init_and_set_v1函数中,你为foo1类型的数组分配内存时,错误使用了foo2的大小计算:
// 错误写法:用了foo2的大小计算foo1数组的内存需求 (*myfoo2)->myfoo1s = malloc( (*myfoo2)->num_foo1 * sizeof(foo2) );
myfoo1s是指向foo1结构体数组的指针,应该按foo1的大小分配内存,推荐两种修正写法:
// 写法1:直接指定foo1类型 (*myfoo2)->myfoo1s = malloc( (*myfoo2)->num_foo1 * sizeof(foo1) ); // 写法2:用指针指向的类型计算,避免写错类型名,适配后续类型变更 (*myfoo2)->myfoo1s = malloc( (*myfoo2)->num_foo1 * sizeof(*((*myfoo2)->myfoo1s)) );
错误触发原理
64位系统下foo1的大小是3个double共24字节,foo2对齐后的大小是16字节。你申请10个元素的数组时,错误写法仅分配了160字节,实际需要240字节,后续给v2、v3赋值时,写入范围超过了申请的内存边界,直接覆盖了堆上紧邻的、用来记录内存块大小/空闲状态的元数据,调用free时系统校验元数据发现被篡改,就会抛出corrupted size vs. prev_size、信号6的错误。
额外注意事项
- 不要在注释标注的location1、location2位置释放
myfoo1s,这两个位置释放后,后续代码还会访问已释放的内存,会触发野指针访问错误,仅需在所有逻辑都使用完myfoo1s的location3位置释放即可 - 代码还漏了
myfoo2本身的释放,用完后要先free(myfoo2->myfoo1s),再free(myfoo2),避免内存泄漏 - 排查这类内存问题时,编译可添加
-g -Wall -fsanitize=address参数,GCC的地址消毒工具会直接定位到越界写入的位置,大幅提升排查效率
内容的提问来源于stack exchange,提问作者ahi
相关产品推荐
相关产品推荐

