1. 程式人生 > >記憶體寫越界導致破環堆結構引起的崩潰問題定位經驗[如報錯malloc(): memory corruption或free(): invalid next size]

記憶體寫越界導致破環堆結構引起的崩潰問題定位經驗[如報錯malloc(): memory corruption或free(): invalid next size]

 前段時間開發的一個後端C模組上線後,線上出core,初始時,由於訪問壓力不大,所以崩潰是上線3天左右出現的。當時用gdb跟進呼叫堆疊並檢查原始碼,發現出core位置的程式碼沒有啥問題。由於當時開發任務較重,且該模組不儲存狀態(崩潰重啟不影響對外服務),所以沒有深入跟進。後來隨著客戶端版本逐漸放量導致訪問壓力上升,噩夢開始了。。。
        該模組會不定時core掉,而且幾乎每次崩潰時的呼叫堆疊都不一樣,關鍵是最後幾層堆疊很多都位於幾乎不可能出問題的程式碼中,比如庫函式或廠裡的公共庫。
        好在在眾多core檔案中發現規律:每次基本都是在對記憶體動態操作時掛掉,比如malloc/realloc/free/new/delete都引起了崩潰。而且幸運的是,崩潰程序還是輸出了一些關鍵資訊,比如下面這些(這些是在不同的崩潰時刻分別輸出的):
*** glibc detected *** malloc(): memory corruption: 0x0000002a95c1ff10 ***
*** glibc detected *** double free or corruption (out): 0x0000000000f0d910 ***
*** glibc detected *** free(): invalid next size (normal): 0x0000002a96103b00 ***
*** glibc detected *** free(): invalid next size (fast): 0x0000000000f349d0 ***
*** glibc detected *** corrupted double-linked list: 0x0000002a95f062e0 ***
        從上面的日誌也可以看到,每次引起崩潰的直接原因都可能不同。用gdb又仔細檢視core檔案發現,有時程序是收到SIGABRT訊號後退出,有時又是收到SIGSEGV訊號後退出。
        由此,基本定位了崩潰原因:記憶體訪問越界導致破壞了heap的資料結構。
用valgrind線上下環境啟動程序,試圖重現崩潰或定位越界訪問的程式碼,遺憾的是,指令碼壓了1個小時也沒出現崩潰,而valgrind的輸出報告也沒有越界程式碼位置的提示。
        最終,仔細檢查原始碼後發現,在某個回撥函式中,new出來的buffer接收完通過http post方式傳送過來的2進位制資料後,我又多寫了1行程式碼,類似於:recv_buf[data_len] = '\0',導致越界多寫1個位元組,最終引起各種莫名其妙的記憶體崩潰。