使用valgrind检测ATS插件中的内存泄露
一.內存錯誤出現的場景
這幾天在重構ATS插件代碼的過程中遇到了煩人的內存泄露問題, 周五周六連續兩天通過走查代碼的方法,未能看出明顯的導致內存錯誤的代碼, 同時也覺得C和C++混合編程得到一個動態庫, 在一個.cpp主文件中,即用new又用malloc來動態分配內存, 可能會導致內存錯誤.后來網上調研和查資料發現, new和malloc混用還是允許的,因為C++兼容C.雖然這種混用方式不提倡, 但絕對不會導致內存堆棧錯亂的情況.
這里之所以采用C和C++混合編程,是因為業務需要. ATS插件目前設計為一個transform主框架, 外加若干子模塊, 一個子模塊一個動態庫,后者可以根據不同業務需要進行擴展,而transform類型的插件框架一般不變, 它只完成通常的transform變換流程就可以了. 這個主框架是使用C++開發的, 它提供了業務實現接口, 供每個業務動態庫實現.因為接口入參中用到了stl的map結構來在主框架和子模塊之間傳遞參數,所以接口的實現必須是C++方式的. 但是我的一個業務插件原來是使用純c編寫的, 引用了幾個第三方庫,比如JSON, libz, pcre庫等, 它們原來已經用C編寫好了,并且經過測試發現是可靠的, 如果再換為C++實現一般不太現實, 也沒有必要. 這樣造成的局面就是, 目前只能C和C++進行混合編程, 對C提供的接口, 要在h文件中使用 extern "C"聲明, 并將實現存放在對應的c文件中.(這里必須要分離成兩個文件, 如果以前只有一個h文件就搞定的, 現在要分為h和c文件).在編譯出一個so時, 同時要外鏈其他的第三方基礎庫時, Makefile的編寫通常有些技巧的, 請參見我的博文
C和C++混合編程的Makefile的編寫!
這種情況下, 對C那部分的調用,我采用malloc和free來分配和釋放內存, 對上層接口那部分, 我在主cpp文件中使用new和delete來分配內存.這里明顯使得內存的使用更加復雜化了,但是不管怎樣,按理說這種做法還是行得通的.
但是在調試過程中,我卻發現了一個內存越界的錯誤, 每次提示的錯誤都不一樣, 但是顯示出錯的位置又沒有明顯的錯誤, 真是讓人摸不到頭腦, 搞不定了, 郁悶, 失敗至極.....
二.內存錯誤出現的表象
兩天的搜索無果, 讓我只能尋求內存檢測軟件的幫助. 我以前用過tcmalloc, 就是google的gperftools里面的一個工具,它會將系統默認的內存分配釋放函數替換為自己的函數再進行檢測,但是在這里不方便施展, 因為這里new和malloc都用上了, 所以我決定使用valgrind來檢測. 具體安裝使用方法,請參見
在Ubuntu 14.04 64bit上安裝Valgrind并檢查內存泄露
下面是ATS插件運行中崩潰時valgrind檢測的幾個錯誤截圖
該截圖告訴我們, pool_alloc(在mem_manage.c第17行)調用malloc分配了1813字節內存, find_replace_html(位于main.cpp第484行)函數使用memcpy從1808處開始要復制8個字節, 而事實上只能復制4字節,這會內存越界,導致非法的8字節寫入(越界寫入).
該截圖告訴我們,??pool_alloc(在mem_manage.c第17行)調用malloc分配了1813字節內存,pcre_exec(在?regex_lookup.h第45行)在1813字節后面越界讀取了1個字節.
該截圖告訴我們, 在分配的1813字節內部的1808字節處, 要非法讀取8字節內存(越界讀取)
三.內存錯誤的分析和確定
上面的截圖分析, 很明確地傳遞出內存越界讀取和越界寫入的錯誤, 但是我查看內存分配的地方, 沒有看到明顯的錯誤.但是多次調試顯示的內存錯誤大多顯示到memset這樣的地方, 將部分memset代碼注釋掉后, 程序能運行, 但是運行一段時間后,它還是會有段錯誤, 看來找到的位置不對, 而且上面截圖顯示的都是造成錯誤的表現, 不是真正造成內存出錯的地方.最后經過認真理解valgrind的錯誤提示, 和仔細地分析代碼, 終于定位到內存錯誤的真正地方不是malloc長度那里, 而是memset那里, 初始化內存的那個指針只能是一個void*或char*, 不能是一個結構體, 這就是內存錯誤的真正地方.
參見下面的截圖, 有內存錯誤的源碼截圖
改正內存錯誤的源碼截圖
改正后, 重新編譯調試, 一切正常, 運行很長時間, 都沒有再崩掉, 再次印證修改是正確的.而這個錯誤, 是一個大家看起來很可笑的問題, 所要大家編寫代碼時還是要提高修養和注意力,千萬不要馬虎寫代碼,否則會害死自己的.
四.回顧反思
bug不可怕, 犯錯不可恥, 但是仔細分析導致bug的原因, 吸取教訓并避免再犯才是最重要的. 另外一點是, 排錯的鍛煉和快速定位是一項職業素養, 越修bug越有收獲越能提高, 經歷越豐富自信心越強, 所以bug來了,我們還是得從容面對.
總結
以上是生活随笔為你收集整理的使用valgrind检测ATS插件中的内存泄露的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在Ubuntu 14.04 64bit上
- 下一篇: Ubuntu 14.04 64bit上升