C編寫的程序可能產生的主要缺陷

摘自:軟件靜態分析工具評析 王 凱,孔祥營

空指針引用、懸空指針、資源泄露、函數返回值、使用未初始化變量、無限循環、死亡代碼、緩衝區溢出、野指針等。

1)空指針引用

空指針引用會導致程序崩潰。空指針引用的情況包括:
①忘記對指針爲NULL 的情況進行判斷;
②雖然對指針是否爲NULL 進行了判斷,但沒能正確處理好。

2)緩衝區溢出

緩衝區溢出是最常見的安全漏洞,包括靜態溢出和動態溢出。靜態溢出主要指數組或指針的索引爲常量情況下的越界,導致內存衝突,給黑客攻擊提供了可乘之機,主要包括棧溢出、堆溢出、數據段溢出、BSS 溢出和共享內存溢出;動態溢出主要是數組或指針的索引在動態訪問內存的時候越界,由於C 語言固有的不安全性,數組或指針的索引不會自動去做邊界檢查,因此緩衝區溢出的情況非常普遍,所以程序員在用C 語言編寫代碼時有必要檢查索引是否在有效區
間內,但在複雜的函數調用和數據流傳遞中,這項工作變得異常複雜。

3)懸空指針

懸空指針是由於使用了已經釋放的內存資源造成的。引用已釋放的指針是非常危險的,因爲指針的值不確定或者指針指向任意內存的位置。爲了避免懸空指針,必須在最後的引用釋放後再刪除對象。

4)資源泄漏

資源泄漏是程序離開了指針的作用域後,仍沒有釋放指針佔用的資源造成的。資源泄漏包括內存泄漏、文件句柄泄漏和網絡套接字泄漏。
嚴重的內存泄漏能導致進程崩潰,即便是很小的內存泄漏,在系統長時間運行沒有重啓後,也會產生錯誤。文件句柄或者網絡套接字的泄漏會導致程序崩潰、拒絕服務攻擊或者打開其他文件或套接字失敗。操作系統通常會限制進程的文件句柄和套接字個數。當達到限制的最大值時,進程要申請新的資源時,首先要關閉一些已打開的資源。如果進程中存在資源泄
漏,進程自己將沒有辦法回收這些資源,除非強行終止該進程。
多數情況下,這些泄漏通常發生在某個錯誤的路徑,比如說,某個異常處理的分支。這種情況下,正確的做法應該是將程序跳轉到該函數的出口,出口處應釋放這些資源。

5)函數返回值

函數返回值錯誤主要包括函數遺漏返回值和函數返回值可能爲空或爲局部變量的地址或爲負整數。函數返回值使用前,一定對其值進行判斷。如果爲空,對其非法引用將會導致程序崩潰;如果爲負整數,在作爲數組索引、循環標誌變量、申請內存大小的參數等情況下要檢查函數返回值的正確性,負整數的錯誤使用會導致如死循環、數組越界(內存衝突)、變量溢出等嚴重的問題;如果是局部變量的地址,在C 語言中,當被調用函數執行完畢,其所有的局部變量就
不再有效,因此將會引起內存衝突和不確定的行爲;在返回類型爲非void 的函數中,值沒有被返回,比較常見的情況是,在不同的分支要返回不同的值,結果有一個分支漏了返回值。

6)使用未初始化變量

變量在使用前沒有初始化。堆棧中的變量如果沒有初始化,將沒有固定的數值。使用了沒有初始化的變量會導致不可預測的行爲,或安全漏洞。

7)無限循環

程序中有不能終止的循環,會導致程序掛起或者崩潰。當然在多任務的程序中,故意設計的“死循環”除外。

8)不可達代碼

由於條件判斷總是TRUE 或FALSE,導致一個分支內的代碼永遠執行不到,這些永遠都執行不到的代碼稱爲不可達代碼。不可達代碼一般是由邏輯錯誤引起的。在情況嚴重時,這些邏輯錯誤可能導致重要的代碼永遠不能執行,造成嚴重的後果。

9)野指針

野指針不是NULL 指針,是指向“垃圾”內存的指針。產生野指針主要有兩個方面的原因:
①指針變量未被初始化。任何指針剛創建時不會自動成爲NNLL 指針,而是隨機的,它會亂指一氣。故指針創建時應當初始化,要麼將指針設置爲NULL,要麼讓它指向合法的內存。
②指針p 被free 或delete 後,沒有設置爲NULL。這樣讓人誤以爲p 是合法的指針,其實free 或delete僅把p 所指向的內存釋放掉,但並沒把指針p 本身釋放(仍指向原來的地址)。通常用if(p!=NULL)進行防錯處理,但是很遺憾,此if 語句根本起不到防錯的作用,因爲即使p 不是NULL,它也不指向合法的內存塊。
另外不要將指針或引用指向棧內存,因爲棧內存
在函數結束時會被釋放。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章