迷途指针

在计算机编程领域中，迷途指针（），或称悬空指针，跟野指针（），皆是一種不指向任何合法的对象的指针。在更一般化形式中，迷途參照（）與野參照（）是指無法解析出合法所在的參照。

当所指向的对象被释放或者收回，但是对该指针没有作任何的修改，以至于该指针仍旧指向已经回收的内存地址，此情况下该指针便称迷途指针。若操作系统将这部分已经释放的内存重新分配给另外一个进程，而原来的程序重新引用现在的迷途指针，则将产生无法预料的后果。因为此时迷途指针所指向的内存现在包含的已经完全是不同的数据。通常来说，若原来的程序继续往迷途指针所指向的内存地址写入数据，这些和原来程序不相关的数据将被损坏，进而导致不可预料的程序错误。这种类型的程序错误，不容易找到问题的原因，通常会导致記憶體區段錯誤（Linux系统中）和一般保护错误（Windows系统中）。如果操作系统的内存分配器将已经被覆盖的数据区域再分配，就可能会影响系统的稳定性。

某些编程语言允许未初始化的指针的存在，而这类指针即为野指针。野指针所导致的错误和迷途指针非常相似，但野指针的问题更容易被发现。

 迷途指针的成因 

在很多编程语言中（如C语言）从内存中删除一个对象或者返回时删除栈帧后，并不会改变相关的指针的值。该指针仍然指向原来的内存地址，即使引用已经删除，现在也可能已经被其它进程使用了。

一个直接的例子，如下所示:
{
   char *cp = NULL;
   /* ... */
   {
       char c;
       cp = &c;
   } /* c 超出了有效范围 */
     /* cp 现在是迷途指针 */
}
上述问题的解决方法是在该部分程序退出之前立即给CP赋0值（NULL）。另一个办法是保证CP在没有初始化之前，将不再被使用。

迷途指针经常出现在混杂使用malloc() 和 free() 库调用: 当指针指向的内存释放了，这时该指针就是迷途的。和前面的例子一样，一个避免这个错误的方法是在释放它的引用后将该指针的值重置为NULL，如下所示：
#include <stdlib.h>
{
    char *cp = malloc ( A_CONST );
    /* ... */
    free ( cp );      /* cp 现在变成了迷途指针 */
    cp = NULL;        /* cp 不再是迷途指针 */
    /* ... */
}
有个常见的错误是当返回一个基于栈分配的局部变量的地址时，一旦调用的函数返回，分配给这些变量的空间将被回收，此时它们拥有的是"垃圾值"。
int * func ( void )
{
    int num = 1234;
    /* ... */
    return &num;
}
在调用func之后一段时间，尝试从该指针中读取num的值，可能仍然能够返回正确的值（1234），但是任何接下来的函数调用会覆盖原来的栈为num分配的空间。这时，再从该指针读取num的值就不正确了。如果要使一个指向num的指针都返回正确的num值，则需要将该变量声明为static。

 野指针的产生 

野指针指的是还没有初始化的指针。严格地说，编程语言中每个指针在初始化前都是野指针。

一般于未初始化时便使用指针就会产生问题。大多数的编译器都能检测到这一问题并警告用户。

int f(int i)
{
    char* cp;    //cp 是野指针
    static char* scp;  //scp 不是野指针：静态变量一开始会被初始化为 0
                       //并在之后保留其最后一次调用的值。
                       //如果不添加注释，使用此功能可能会被视为不好的方法
}

 迷途指针导致的安全漏洞 

如同缓存溢出错误，迷途指针/野指针这类错误经常会导致安全漏洞。 例如，如果一个指针用来调用一个虚函数，由于vtable指针被覆盖了，因此可能会访问一个不同的地址（指向被利用的代码）。或者，如果该指针用来写入内存，其它的数据结构就有可能损坏了。一旦该指针成为迷途指针，即使这段内存是只读的，仍然会导致信息的泄露（如果感兴趣的数据放在下一个数据结构里面，恰好分配在这段内存之中）或者访问权限的增加（如果现在不可使用的内存恰恰被用来安全检测）。

 避免迷途指针的错误 

避免迷途指针，有一种受欢迎的方法——即使用智能指针（）。智能指针使用引用计数来回收对象。一些其它的技术包括法和法。

另外，可以使用 DieHard 内存分配器E. Berger and B. Zorn, DieHard: Probabilistic Memory Safety for Unsafe Languages  (DieHard website )，它虚拟消除了类似其它内存错误（不合法或者两次释放内存）的迷途指针错误。

还有一种办法是貝姆垃圾收集器，一种保守的垃圾回收方法，能够替代C和C++中标准内存分配函数。这种方法完全消除了迷途指针的错误，通过去除内存释放的函数代之以垃圾回收器完成对象的回收。

像Java语言，迷途指针这样的错误是不会发生的，因为Java中没有明确地重新分配内存的机制。而且垃圾回收器只会在对象的引用数为零时重新分配内存。

 迷途指针的检测 

为了能发现迷途指针，一种普遍的编程技术——一旦指针指向的内存空间被释放，就立即把该指针置为空指针或者为一个非法的地址。当空指针被重新引用时，此时程序将会立即停止，这将避免数据损坏或者某些无法预料的后果。这将使接下来的编程过程产生的错误变得容易发现和解决了。这种技术在该指针有多个复制时就无法起到应有的作用了。

一些调试器会自动地用特定的模式来覆盖已经释放的数据，如 （Microsoft's Visual C/C++ 调试器，例如，根据哪种类型被释放采用 0xCC，0xCD 或者 0xDD）。这种方法通过将数据无用化，来防止已经释放的数据重新被使用。这种方法的作用是非常显著的（该模式可以帮助程序来区分哪些内存是刚刚释放的）。
 值  名字  描述 0xCD  Clean Memory  用malloc或是new分配，應用程式尚未寫入的記憶體。  0xDD  Dead Memory  已被delete或free釋放的記憶體，用來偵測用迷途指標寫入的問題。 0xFD  Fence Memory  也稱為「無人島」，用來放在已分配的記憶體前後，偵測陣列索引超過範圍，或是超過已分配記憶體範圍的存取（特別是寫入）。 0xCC    若程式碼是用/GZ選項編譯，沒有初始化的變數會在每個位元組填入此數值。0xAB 用LocalAlloc()分配的記憶體 0xBAADF00D   Bad Food 用LocalAlloc()配合LMEM_FIXED所分配，但沒有被寫入的記憶體。  0xFEEEFEEE   作業系統填充heap memory，而此區域沒有被HeapAlloc()或LocalAlloc()所分配，或是已被HeapFree()釋放的記憶體。 
某些工具，如Valgrind， Mudflap 或者 LLVMDhurjati, D. and Adve, V. Efficiently Detecting All Dangling Pointer Uses in Production Servers  可以用来检测迷途指针的使用。

相關條目
Wild branch

 外部链接 
Pointers and Arrays (C99)
Topics on Pointers and Arrays
Dangling Pointer New Hacking Technique (Security)
Dangling pointers

 参考文献 

Mituzhizhen
Category:安全