SGCheck:一个实验堆栈和全局数组溢出检测器
目錄
11.1。概觀11.2。SGCheck命令行選項11.3。SGCheck如何工作11.4。與Memcheck進行比較11.5。限制11.6。仍然要做:用戶可見的功能11.7。仍然要做:實施整頓要使用此工具,必須--tool=exp-sgcheck在Valgrind命令行上指定?。
11.1。概觀
SGCheck是一種查找堆棧和全局數組超量的工具。它通過使用從關于堆棧和全局數組訪問的可能形式的觀察得出的啟發式方法來工作。
11.2。SGCheck命令行選項
目前沒有SGCheck特定的命令行選項。
11.3。SGCheck如何工作
當源文件編譯時-g,編譯器將附加DWARF3調試信息,該信息描述文件中所有堆棧和全局數組的位置。
如果編譯器也可以告訴我們每個內存引用指令應該訪問哪個數組(如果有的話),則對這樣的數組的訪問的檢查將是相對簡單的。不幸的是,DWARF3調試格式不能提供一種表示這些信息的方法,所以我們必須采用啟發式技術來近似它。關鍵的觀察結果是,?如果存儲器引用指令訪問堆棧或全局數組一次,則很可能總是訪問相同的數組。
要看看這可能有用,請考慮以下buggy片段:
{int i,a [10]; //都是自動變量for(i = 0; i <= 10; i ++)a [i] = 42;}在運行時,我們將知道a[]堆棧的精確地址,因此我們可以觀察到由a[i] = 42寫入產生的第一個存儲a[],并且我們將(正確地)假設該指令始終被訪問a[]。然后,在第11次迭代中,它訪問其他地方,可能是不同的本地,可能是未占用堆棧的區域(例如,溢出槽),因此SGCheck報告錯誤。
有一個重要的警告。
想象一下這樣的功能,memcpy用于在程序的整個生命周期中讀取和寫入許多不同的內存區域。如果我們堅持在其內存復制循環中的讀寫指令只訪問一個特定的堆棧或全局變量,那么我們將被調用導致錯誤?memcpy。
為了避免這個問題,SGCheck會為函數的每個條目實例化新的可能的目標記錄,并在退出時將其丟棄。這允許檢測(例如)memcpy?對于任何特定呼叫的源或目的地緩沖器溢出的情況,但是不會從一個呼叫到下一個呼叫的任何限制。實際上,多線程可以進行多個同時調用(例如)memcpy而不會相互干擾。
需要注意的是該協會之間進行是很重要的二進制指令和陣列中,?第一次這個二進制指令訪問一個函數調用中的數組。當在相同的函數調用期間再次執行相同的指令時,如果這些進一步的執行沒有訪問相同的數組,則SGCheck可能會報告問題。該技術在SGCheck中引起了一些限制,請參閱?限制。
11.4。與Memcheck進行比較
SGCheck和Memcheck是互補的:它們的功能不重疊。Memcheck對堆數組執行邊界檢查和免用后檢查。它還可以使用由堆或堆棧分配創建的未初始化值。但是它不會對堆棧或全局數組執行邊界檢查。
另一方面,SGCheck確實會檢查堆棧或全局數組,但是它不做任何其他操作。
11.5。限制
這是一個實驗工具,它依賴于對正確程序行為的一些不那么強硬的假設。你應該注意到一些限制。
-
虛假的否定(錯誤的錯誤):從上面的描述(SGCheck Works)可以看出,存儲器引用指令到堆棧或全局數組的第一次訪問會創建該指令與數組之間的關聯,后者將在后續訪問中檢查該指令,直到包含函數退出。因此,由于SGCheck將其用作后續訪問應該行為的“示例”,所以不會檢查對數組(在任何給定的函數實例化中)的指令的首次訪問。
這也意味著在只執行一次的指令中將不會發現錯誤(例如,因為該指令不在循環中,或循環僅執行一次)。
-
虛假的錯誤(錯誤的錯誤):同樣,更嚴重的是,很可能寫出合法的代碼片斷,破壞了檢查算法所依賴的基本假設。例如:
{int a [10],b [10],* p,i;for(i = 0; i <10; i ++){p = / *任意條件* /?&a [i]:&b [i];* p = 42;}}在這種情況下,商店有時會訪問a[],有時會訪問b[],但是在任何情況下,尋址的陣列都將超載。然而,目標的變化將導致報告錯誤。
很難看出如何解決這個問題。唯一的緩解因素是,這樣的結構看起來非常罕見,至少從使用該工具的結果到目前為止。這樣的一個建筑在Valgrind的源頭(在Valgrind運行Valgrind)只會出現一次,也許在Firefox的啟動和退出兩三次。可以做的最好的是抑制錯誤。
-
性能:SGCheck必須讀取可執行文件及其共享對象上的所有DWARF3類型和變量信息。這在計算上是昂貴的,使得啟動相當緩慢。對于OpenOffice大小的應用程序,在2.4 GHz Core 2機器上,您可以期待debuginfo讀取時間在一分鐘的時間內。讀這個信息也需要很多的記憶。為了使其可行,SGCheck在壓縮DWARF3數據的內存中的表示方面遇到了相當大的麻煩,這就是讀取過程看起來慢的原因。
-
性能:SGCheck運行速度比Memcheck慢。這部分是由于缺乏調整,但部分是由于算法困難。堆棧和全局檢查有時可能需要對每個存儲器訪問進行多個范圍檢查,并且盡管作出了相當大的努力,但這些難以短路。重新設計和重新實現可能會使其更快。
-
覆蓋:堆棧和全局檢查是脆弱的。如果共享對象沒有附加調試信息,則SGCheck將無法確定該共享對象中定義的任何堆棧或全局數組的邊界,因此無法檢查對它們的訪問。即使從使用調試信息編譯的其他共享對象訪問這些數組時,也是如此。
目前,SGCheck接受缺少debuginfo的對象,無需注釋。這是危險的,因為它會導致SGCheck靜默地跳過堆棧和全局檢查這些對象。最好在這種情況下打印警告。
-
覆蓋范圍:SGCheck不檢查系統調用讀或寫的區域是否覆蓋堆棧或全局數組。這很容易添加。
-
平臺:堆棧/全局檢查在PowerPC,ARM或S390X平臺上無法正常工作,僅在X86和AMD64目標上。這是因為堆棧和全局檢查需要跟蹤函數調用并可靠地退出,并且在使用鏈接寄存器進行函數返回的ABI上沒有明顯的方法。
-
魯棒性:與前一點相關。X86和AMD64的函數調用/退出跟蹤被認為即使在同一個堆棧中存在longjmps也能正常工作(盡管尚未測試)。然而,切換堆棧的代碼可能會導致破壞/混亂。
11.6。仍然要做:用戶可見的功能
-
擴展系統調用檢查以在堆棧和全局數組上工作。
-
如果共享對象沒有附加調試信息,或者由于某種原因無法找到或讀取調試信息,則打印警告。
-
添加一些啟發式過濾,消除明顯的誤報。這很容易做到。例如,從堆到堆棧對象的訪問幾乎肯定不是一個錯誤,所以不應該向用戶報告。
11.7。仍然要做:實施整頓
標記為“臨界”的項目對于正確性被認為是重要的:不確定它們可能導致實際使用中的崩潰或斷言失敗。
-
sg_main.c:重新設計并重新實現基本檢查算法。它可以比它快得多 - 目前的實現不是很好。
-
sg_main.c:通過執行一些前期過濾來提高堆棧/全局檢查的性能,以忽略“顯然”不能是堆棧或全局變量的區域中的引用。這將需要使用m_aspacemgr知道地址空間布局的信息。
-
sg_main.c:修復compute_II_hash,使ppc32 / 64目標更加明智(除了sg_不適用于ppc32 / 64目標,所以這在目前有點學術)。
-
總結
以上是生活随笔為你收集整理的SGCheck:一个实验堆栈和全局数组溢出检测器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BZOJ 4259 FFT
- 下一篇: js的时间函数实现一个电子表