为何写入some_data[some_data_size]会导致free()调用时程序崩溃?
问题分析:内存越界写入导致free()崩溃的原因
这段C代码中,执行some_data[some_data_size] = '\0';后调用free()会触发崩溃,移除该行则崩溃消失。以下是针对该问题的具体分析:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { FILE* fd = fopen("junk.txt", "r"); int buffer_size = 42; //random number just for this example if (fd != NULL) { char* data = calloc(buffer_size, sizeof(uint8_t)); if (data != NULL) { uint32_t read_size = fread(data, 1, buffer_size, fd); if (read_size == buffer_size) { char* some_data = strstr(data, "DATA:"); if (some_data != NULL) { uint32_t some_data_size = some_data - data; char* stuff = calloc(some_data_size + 1, sizeof(uint8_t)); if (stuff != NULL) { some_data[some_data_size] = '\0'; // removing this line prevents a crash //... doing stuff with the data memcpy(stuff, some_data + 6, some_data_size); free(stuff); } } } fclose(fd); free(data); } } return 0; }
1. 核心问题:非法的内存越界写入
some_data_size的计算逻辑是some_data - data,得到的是"DATA:"在data数组中的起始偏移量(从data开头到some_data的字节数)。some_data[some_data_size]等价于*(some_data + some_data_size),也就是*(data + (some_data - data) + some_data_size),最终指向data + 2*some_data_size的位置。- 由于
data的总大小只有buffer_size(示例中是42),只要2*some_data_size > buffer_size,这个写入操作就会直接越界,访问data分配内存之外的区域。即使2*some_data_size刚好小于等于buffer_size,这个位置也不属于"DATA:"对应的有效内容范围,同样可能覆盖后续的有效数据或堆元数据。
2. 越界写入为何会导致free()崩溃?
- 堆内存分配函数(
malloc/calloc)会在分配的内存块前后维护元数据,比如块的大小、下一个空闲块的指针等,用于管理堆空间的分配与释放。 - 越界写入会直接破坏这些元数据,当
free()尝试读取元数据来回收内存时,会遇到非法内存访问、堆结构损坏等问题,最终触发程序崩溃。 - 移除
some_data[some_data_size] = '\0';后,没有破坏堆的元数据,free()就能正常执行堆内存的回收操作。
3. 正确的处理方式
如果需要给some_data指向的内容添加终止符,必须确保写入位置在data的合法内存范围内:
- 先计算
some_data到data末尾的剩余空间:size_t remaining = buffer_size - (some_data - data); - 确保写入终止符的位置(比如
some_data + offset)小于data + buffer_size,例如如果要在"DATA:"之后处理字符串,需要保证终止符写入的位置不超过data的边界。
内容的提问来源于stack exchange,提问作者BaldDude
相关产品推荐
相关产品推荐

