程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 為什麼重復free()比內存洩漏危害更大

為什麼重復free()比內存洩漏危害更大

編輯:C++入門知識

C程序設計中,內存操作相關的錯誤可以說是最常見,同時也是非常隱蔽的一類錯誤。這類錯誤往往導致程序莫名其妙地崩潰、耗盡系統資源,或是形成嚴重的安全弱點。

在 FreeBSD,以及多數其他 BSD 派生的系統中,重復 free() 在默認情況下都會導致 C 函數庫調用 abort() 終止程序。除了 malloc(3) 函數族本身的設計之外,這也是一項非常重要的安全特性。與此相反,包括 *BSD 在內的多數系統的 C 函數庫並不對堆進行審計,也就是說,從 API 設計者的觀點來看,內存洩漏並不被認為是非常嚴重的程序設計問題。

為什麼會有這樣的區別呢?事實上,內存洩漏同樣可以導致比較嚴重的問題,例如響應速度變慢、進程由於占用的資源太多而被 OS 殺掉導致 DoS 等等。為了回答這個問題,我們來觀察一下兩種問題出現的場景。

內存洩漏 是指這樣一種場景:程序分配了一塊內存,但已經不再持有引用這塊內存的對象通常是指針)。從 OS 的角度,它知道進程持有的內存數量;然而,從進程的角度,它可能並不完全知道自己持有哪些內存。

換言之,內存洩漏就是通過遍歷進程內所有可以從棧上,或以靜態變量形式存於堆上的指針及其後繼,無法到達所有全部已分配內存的情形。

如果程序不存在其他問題例如緩沖區溢出),此時程序訪問內存時,任何時候都不會在無意中覆寫超出范圍的數據。即,將數據覆寫到程序其他部分保存數據的內存單元。

而 重復釋放 則指這樣一種場景:程序分配一塊內存之後,經過使用將這塊內存釋放,但並沒有將指向這塊內存的所有指針抹零或回收,並在其他部分再次將指向同一塊內存單元的指針交給內存分配器去進行釋放操作。這種情況下,我們可以斷言:

1、程序邏輯並不清楚這塊內存已經被釋放;

2、有理由相信,對這塊內存進行的寫操作,可能已經影響了程序其他部分的行為,因為這塊內存可能已經分配作為其他用途。
因此,這應被看作立即停止程序運行的一項致命錯誤,因為程序行為已經出現了異常,而C函數庫擁有的信息不足以糾正這種異常行為,而另一方面,程序可能已經發生了堆緩沖區溢出。

為了削弱這類問題帶來的實質性安全影響,現代的內存分配器往往會將尺寸接近的內存塊放在一起這樣做還能夠抑制內存碎片的產生,並提高CPU的數據緩存命中率,因為通常程序會傾向於一次性地訪問相近的內存結構)。

從而能夠在一定程度上減輕由於向已經釋放的內存塊繼續寫數據導致的損害因為這些內存很可能被分配給同樣的數據結構,這類寫操作的危害往往會低於向其他類型的數據結構寫數據,特別是當這些數據中包含一部分用戶輸入的時候)。

當然,徹底消除這類問題,需要為程序設計語言增加一些新的基礎設施例如強類型、托管內存等)。現代程序設計語言如Java、Python和.net系列等,都采用了避免這類問題的措施。然而,也正因為如此,通過這些語言入門並准備撰寫 C 程序的開發人員就更需要注意這類問題。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved