在計算機編程領域中,迷途指針,或稱懸空指針、野指針,指的是不指向任何合法的對象的指針。
基本介紹
- 中文名:迷途指針
- 別稱:野(wild)指針
- 特點:對指針使用delete後不要再使用它
- 套用:程式編寫
- 使用注意:把其設定為空,便解除了它的武裝
- 學科:計算機
簡介,成因,安全漏洞,避免迷途指針的錯誤,迷途指針的檢測,
簡介
在計算機編程領域中,迷途指針,或稱懸空指針、野指針,指的是不指向任何合法的對象的指針。
當所指向的對象被釋放或者收回,但是對該指針沒有作任何的修改,以至於該指針仍舊指向已經回收的記憶體地址,此情況下該指針便稱迷途指針。若作業系統將這部分已經釋放的記憶體重新分配給另外一個進程,而原來的程式重新引用現在的迷途指針,則將產生無法預料的後果。因為此時迷途指針所指向的記憶體現在包含的已經完全是不同的數據。通常來說,若原來的程式繼續往迷途指針所指向的記憶體地址寫入數據,這些和原來程式不相關的數據將被損壞,進而導致不可預料的程式錯誤。這種類型的程式錯誤,不容易找到問題的原因,通常會導致存儲器區塊錯誤(Linux系統中)和一般保護錯誤(Windows系統中)。如果作業系統的記憶體分配器將已經被覆蓋的數據區域再分配,就可能會影響系統的穩定性。
某些程式語言允許未初始化的指針的存在,而這類指針即為野指針。野指針所導致的錯誤和迷途指針非常相似,但野指針的問題更容易被發現。
成因
在很多程式語言中(如C語言)從記憶體中刪除一個對象或者返回時刪除棧幀後,並不會改變相關的指針的值。該指針仍然指向原來的記憶體地址,即使引用已經刪除,現在也可能已經被其它進程使用了。
一個直接的例子,如下所示:
{ char *cp = NULL; /* ... */ { char c; cp = &c; } /* c falls out of scope */ /* cp is now a dangling pointer */}
上述問題的解決方法是在該部分程式退出之前立即給CP賦0值(NULL)。另一個辦法是保證CP在沒有初始化之前,將不再被使用。
迷途指針經常出現在混雜使用malloc()和free()庫調用: 當指針指向的記憶體釋放了,這時該指針就是迷途的。和前面的例子一樣,一個避免這個錯誤的方法是在釋放它的引用後將該指針的值重置為NULL,如下所示:
#include <stdlib.h>{ char *cp = malloc ( A_CONST ); /* ... */ free ( cp ); /* cp now becomes a dangling pointer */ cp = NULL; /* cp is no longer dangling */ /* ... */}
有個常見的錯誤是當返回一個基於棧分配的局部變數的地址時,一旦調用的函式返回,分配給這些變數的空間將被回收,此時它們擁有的是"垃圾值"。
int * func ( void ){ int num = 1234; /* ... */ return #}
在調用func之後一段時間,嘗試從該指針中讀取num的值,可能仍然能夠返回正確的值(1234),但是任何接下來的函式調用會覆蓋原來的棧為num分配的空間。這時,再從該指針讀取num的值就不正確了。如果要使一個指向num的指針都返回正確的num值,則需要將該變數聲明為static。
安全漏洞
如同快取溢出錯誤,迷途指針/野指針這類錯誤經常會導致安全漏洞。 例如,如果一個指針用來調用一個虛函式,由於vtable指針被覆蓋了,因此可能會訪問一個不同的地址(指向被利用的代碼)。或者,如果該指針用來寫入記憶體,其它的數據結構就有可能損壞了。一旦該指針成為迷途指針,即使這段記憶體是唯讀的,仍然會導致信息的泄露(如果感興趣的數據放在下一個數據結構裡面,恰好分配在這段記憶體之中)或者訪問許可權的增加(如果現在不可使用的記憶體恰恰被用來安全檢測)。
避免迷途指針的錯誤
另外,可以使用 DieHard 記憶體分配器,它虛擬消除了類似其它記憶體錯誤(不合法或者兩次釋放記憶體)的迷途指針錯誤。
像Java語言,迷途指針這樣的錯誤是不會發生的,因為Java中沒有明確地重新分配記憶體的機制。而且垃圾回收器只會在對象的引用數為零時重新分配記憶體。
迷途指針的檢測
為了能發現迷途指針,一種普遍的編程技術——一旦指針指向的記憶體空間被釋放,就立即把該指針置為空指針或者為一個非法的地址。當空指針被重新引用時,此時程式將會立即停止,這將避免數據損壞或者某些無法預料的後果。這將使接下來的編程過程產生的錯誤變得容易發現和解決了。這種技術在該指針有多個複製時就無法起到應有的作用了。
一些調試器會自動地用特定的模式來覆蓋已經釋放的數據,如0xDEADBEEF(Microsoft's Visual C/C++ 調試器,例如,根據哪種類型被釋放採用0xCC,0xCD或者0xDD)。這種方法通過將數據無用化,來防止已經釋放的數據重新被使用。這種方法的作用是非常顯著的(該模式可以幫助程式來區分哪些記憶體是剛剛釋放的)。