malloc/free触发Signal 6错误:栈实现代码的内存越界问题排查
你的栈实现触发Abort的原因与修复方案
嘿,我来帮你搞定这个问题——你的栈代码里的pop函数藏着个内存越界的坑,直接破坏了堆内存结构,才导致glibc在free的时候炸出invalid pointer错误,最终触发Signal 6(abort)。
问题出在哪?
先看pop里的缩容逻辑:
int *arr2 = (int*)malloc(sizeof(int) * size / 2); for ( i = 0; i < size; i++) arr2[i] = arr[i];
你申请了只有原数组一半大小的新内存(size/2),但循环却硬要把原数组的size个元素全复制过去!这就导致新数组的后半段是不属于它的内存,写入这些位置会直接破坏malloc用来管理堆的元数据。这种堆损坏不会立刻报错,但等你调用free(arr)的时候,glibc的堆检测机制发现内存块的管理信息被篡改,就直接触发abort终止程序了。
另外还有个小隐患:你没判断栈是否为空,如果top已经是0还调用pop,--top会变成负数,访问arr[负数索引]又是一次越界。
修复后的完整代码
#include <stdlib.h> int *arr; int size = 2; int top = 0; int pop() { // 先检查栈是否为空,避免空栈pop导致越界 if (top == 0) { // 这里可以根据需求返回错误码,或者直接终止,示例用abort abort(); } // 先取出要返回的值,再处理缩容 int popped_val = arr[--top]; // 缩容条件:栈元素不到当前容量的1/4,且容量大于2(避免缩到0) if (top <= size / 4 && size > 2) { int new_size = size / 2; int *arr2 = (int*)malloc(sizeof(int) * new_size); // 只复制栈里的有效元素(共top个),不是原数组的全部size个 for (int i = 0; i < top; i++) { arr2[i] = arr[i]; } free(arr); arr = arr2; size = new_size; } return popped_val; } void push(int a) { if (top >= size) { int new_size = size * 2; int *arr2 = (int*)malloc(sizeof(int) * new_size); // push扩容时复制原数组全部size个元素是对的,因为原数组全是有效元素 for (int i = 0; i < size; i++) { arr2[i] = arr[i]; } free(arr); arr = arr2; size = new_size; } arr[top++] = a; }
关键修复点说明
- 修正缩容时的复制范围:缩容只需要复制当前栈里的
top个有效元素(而不是原数组的size个),既避免了越界写,也没必要复制那些已经弹出的无效数据。 - 添加空栈判断:防止
pop空栈时出现负数索引的越界访问,避免后续更隐蔽的内存问题。 - 限制缩容下限:加了
size > 2的判断,避免数组被缩到0,导致后续push时无法正常扩容。
为什么之前的报错指向free?
堆内存的管理信息(比如内存块的大小、前后块指针)是存在内存块周围的,你越界写入新数组时,刚好覆盖了这些信息。当你调用free(arr)时,glibc会检查这些管理信息是否合法,发现被篡改后就直接触发abort,所以报错看起来是free的问题,但根源是之前的越界写。
内容的提问来源于stack exchange,提问作者roll
相关产品推荐
相关产品推荐

