首先介紹一下自己的程式出錯的原因,然後總結一下什麼時候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),向申請的記憶體中拷貝了過多的資料。
注:由於知識有限,本文所講必定有缺陷之處,請謹慎參考,如有錯誤,歡迎批評指正!