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