记录一次C语言中free(p)失败

首先介绍一下自己的程序出错的原因,然后总结一下什么时候free会失败。

1.程序伪代码

// 已知payload已经指向一部分内存数据
char * payload;
int payload_len; //payload的长度

char * front_pkt="xxxxxxxxx";

// 申请内存
char * temp_ptr=(char *)malloc(payload_len+strlen(front_pkt)+1);// 多申请一位放\0
memset(temp_ptr,0,payload_len+strlen(front_pkt)+1);

// 拷贝
strcat(temp_ptr,front_pkt);
strcat(temp_ptr,payload); // 错误原因就发生在这里
...

// 释放
free(temp_ptr);//报错的地方

定位过程:

由于是和别的程序联调,首先定位出事free()函数时报的错。然后就开始从为指针申请内存的地方开始定位,最后发现,在strcat(temp_ptr,payload)之后,指针temp_ptr指向的数据竟然比我申请的内存要大,尾部有一部分杂数据。至此,发现是内存越界了。

为什么会越界呢?因为payload并不能保证是字符串,即不能保证是符号'\0'结尾的。在使用strcat追加拷贝字符串时是根据'\0'符号来判断拷贝结束的。所以非常有可能发生内存越界的行为。

修改方案:使用strncat()函数,指定拷贝的长度。

定位心得:

1.在使用C语言的字符串函数时,str开头的,一定要确保指针指向的内存是字符串,即'\0'结尾。

2.尽量使用带n的函数,指定内存、字符串拷贝等的长度,可以避免不必要的麻烦。

总结:什么时候free(p)会报错?

1.如果p不是NULL指针,对p连续操作两次就导致程序运行错误

2.内存越界,指针初始值被修改掉,和别的区块内存重叠,分配的这段内存的“门牌号”被改掉了,free就会失败。比如上边的例子。

引申:free的原理

free(p)释放p指向的内存时,并不需要提供要释放内存的大小,这是因为在p附近的某个位置存放有维护该内存区域的数据,这是由内存申请函数malloc等产生的。实际上在p之前有个结构体,记录了该块内存的信息。如果程序因为内存越界修改了结构体,则会导致free()函数报错返回,并不释放任何内存。

以上边的例子,strcat(temp_ptr,payload),向申请的内存中拷贝了过多的数据。

 

注:由于知识有限,本文所讲必定有缺陷之处,请谨慎参考,如有错误,欢迎批评指正!

posted @ 2021-09-18 10:39  一只奋斗的考拉  阅读(1729)  评论(0编辑  收藏  举报