1. 程式人生 > >使用CMAKE過程中碰到的棧溢位問題總結

使用CMAKE過程中碰到的棧溢位問題總結

最近在Linux開發中使用CMKE自動生成makefile,程式執行中碰到了棧溢位的問題(實際還不太確定是不是stack overflow problem導致),於是花了很多時間細細研究了記憶體劃分及分配等相關機制,感覺瞭解比以前透徹了不少,在此做一下先總結一下問題及解決方法以及還存在的疑問。

碰到的問題

先說一下碰到的問題:我們在Linux下寫的程式,是一個龐大的系統,一個程序下啟用了超過30個執行緒同時執行,某個執行緒中一個函式體內聲明瞭一個大概8KB大小的陣列。在原先自己寫的Makefile編譯執行都正常,但是採用Cmake的方式自動生成makefile,編譯通過,執行的時候每次都會出現segmentation fault,backtrace顯示被呼叫函式的入參都為0,但是上一級函式傳入引數的時候,所有引數都是有值的。一進入被呼叫函式,就出現了core dump,gdb backtrace顯示程式掛在了被呼叫函式的第一行。

解決辦法

碰到該問題,現象有些詭異,函式呼叫前的入參都是有值的,一進入函式,就都變成了0。經過長時間的debug,最後確定是函式內申請的8KB陣列導致的segfault。因此推斷是陣列導致棧溢位,覆蓋了入參的值(不確定是否最終原因)。但是Linux系統預設的程序棧大小為8MB,嘗試用ulimit -s 調整棧大小為16MB,仍然沒有解決問題,按理說,8KB的陣列並不大,但是如果將8KB分配在棧上的陣列改成malloc動態分配的方式,segfault就消失了。所以解決辦法就是將函式中超過1KB的陣列都該成從堆上分配空間。

但是改解決辦法雖然解決了出現的問題,但是還是無法解釋心中的疑問:

1. 為什麼8KB的陣列會導致segmentation fault?

2. 如果8KB的陣列造成了棧溢位從而導致segmentation fault,為何調整棧大小為原來的兩倍,遠遠超過陣列大小時,仍然沒解決問題?

3. 另外就是CMAKE生成的makefile,gcc引數幾乎跟自己寫的makefile上的引數一樣,但是原來的makfile下build的程式能夠正常的執行,通過CMAKE生成makefile並build的程式卻通不過,CMAKE是否有預設的設定導致程式使用的棧更小?

重新分析源程式,上面的問題又更清晰一些了。

出現segmentation fault的函式是線上程中執行的,而執行緒擁有自己獨立的棧,共享程序所擁有的資源,這裡需要區分一下執行緒棧與程序棧兩個概念,雖然執行緒共享程序的資源(程序虛擬地址空間等

,但是執行緒棧跟程序棧並不是同一塊區域,執行緒棧所佔用的空間是由系統(管理執行緒的程序)通過malloc動態分配堆空間所獲取到的記憶體區域。使用ulimit -s修改的是程序的棧空間大小,但是不影響執行緒棧大小,執行緒棧大小線上程建立的時候進行設定,並且不能超過一定的大小。所以這就解釋了為什麼ulimit -s調整stack size為原來兩倍仍然沒有解決stack overflow的問題。因為pthread stack大小並沒有變化。

至於使用CMAKE與不使用CMAKE自動生成makefile所build 的程式執行結果為什麼不同,只能猜測也許有個別引數的差異導致兩者分別build出的程式執行緒棧大小有差異吧,希望有CMAKE專家指點迷津。