記錄一次C語言中free(p)失敗

天健湖旁的一隻考拉發表於2021-09-18

首先介紹一下自己的程式出錯的原因,然後總結一下什麼時候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),向申請的記憶體中拷貝了過多的資料。

 

注:由於知識有限,本文所講必定有缺陷之處,請謹慎參考,如有錯誤,歡迎批評指正!

相關文章