#問題 最近在查程序的內存問題,包括前一篇文章也是與此相關《snprintf/_snprintf 在不一樣平臺間函數差別》。 先看一段簡單的程序:php
<!-- lang: cpp --> int main() { for(int i=0; i<5; i++) { char k[4]; char *p = k; char b[] = "123456789"; memcpy(p, b, sizeof(b)); cout << "in loop" << endl; } cout << "end" << endl; return 0; }
輸出以下: in loop endhtml
爲什麼循環4次只輸出一次呢?使用gdb查看,發現因爲memcpy越界,直接把變量「i」改爲了一個極大的值。因此一次就結束了。 這段程序極爲兇險的是memcpy越界編譯沒有報錯,執行沒有core dump(若是將數組b改成超大如1000等就可能會dump),而是結果錯誤。設想一下,若是memcpy改了別的什麼內存位置的值,程序如何執行就進入了一個未知的狀況,再加上多線程等複雜的業務場景,就是一顆定時炸彈,平時好好的,而不知什麼時候,就「啵」的爆炸了。而這種狀況查看犯罪現場的core文件,使用bt獲得的已經不是真正問題的所在,而是因爲以前的內存越界致使的正常代碼留下的屍體。java
在複雜的業務邏輯中使用memcpy、strcmp等這種較爲底層的函數,自己就是自討苦吃。代碼量大,開發難度大,通常人寫出的代碼質量不高,出了問題很差查……因此難怪從java到python、php等大行其道。python
使用Valgrind 動態工具,只支持linux系列,不支持windows。參見《應用 Valgrind 發現 Linux 程序的內存問題》。 實測發現memcpy拷貝的內容長度超過了目的數組的長度時,Valgrind檢查不出來。 使用方便,直接 valgrind [args] program program_argslinux
使用cppcheck 靜態檢查工具。支持linux、windows。 實測發現能夠發現memcpy拷貝的內容長度超過了目的數組的長度溢出問題。 使用也很方便,cppcheck xxx.cppwindows
這兩個工具要配合使用。數組
ps:cppcheck默認安裝會報錯以下:多線程
(information) Failed to load std.cfg. Your Cppcheck installation is broken, please re-install. The Cppcheck binary was compiled without CFGDIR set. Either the std.cfg should be available in cfg or the CFGDIR should be configured.函數
解決方法: cppcheck的linux安裝須要在make時候對參數CFGDIR配置,設置爲絕對路徑,如:make CFGDIR=/usr/bin/cfg 安裝時候也帶上此參數:make install CFGDIR=/usr/bin/cfg工具