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