C迷途指针

在计算机编程领域中,迷途指针,或称悬空指针野指针,指的是不指向任何合法的对象的指针。

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

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

欢迎关注我的个人博客:www.wuyudong.com, 更多精彩文章与您分享

迷途指针的成因

在很多编程语言中(如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 现在变成了一个悬空指针 */
    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指针被覆盖了,因此可能会访问一个不同的地址(指向被利用的代码)。或者,如果该指针用来写入内
存,其它的数据结构就有可能损坏了。一旦该指针成为迷途指针,即使这段内存是只读的,仍然会导致信息的泄露(如果感兴趣的数据放在下一个数据结构里面,恰
好分配在这段内存之中)或者访问权限的增加(如果现在不可使用的内存恰恰被用来安全检测).

避免迷途指针的错误

避免迷途指针,有一种受欢迎的方法——即使用智能指针(Smart pointer)。智能指针使用引用计数来回收对象。一些其它的技术包括tombstone法和locks-and-keys法。

另外,可以使用 DieHard 内存分配器,它虚拟消除了类似其它内存错误(不合法或者两次释放内存)的迷途指针错误。

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

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

迷途指针的检测

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

一些调试器会自动地用特定的模式来覆盖已经释放的数据,如0xDEADBEEF (Microsoft's Visual C/C++ 调试器,例如,根据哪种类型被释放采用 0xCC0xCD 或者 0xDD)。这种方法通过将数据无用化,来防止已经释放的数据重新被使用。这种方法的作用是非常显著的 (该模式可以帮助程序来区分哪些内存是刚刚释放的)。

某些工具,如Valgrind, Mudflap或者 LLVM可以用来检测迷途指针的使用。

时间: 2024-10-28 02:28:39

C迷途指针的相关文章

C迷途指针详解_C 语言

本文较为详尽的讲述了C语言的迷途指针,分析了其概念.原理与检测方法.分享给大家供大家参考.具体如下: 一般来说,在计算机编程领域中,迷途指针,或称悬空指针.野指针,指的是不指向任何合法的对象的指针. 当所指向的对象被释放或者收回,但是对该指针没有作任何的修改,以至于该指针仍旧指向已经回收的内存地址,此情况下该指针便称迷途指针.若操作系统将这部分已经释放的内存重新分配给另外一个进程,而原来的程序重新引用现在的迷途指针,则将产生无法预料的后果.因为此时迷途指针所指向的内存现在包含的已经完全是不同的数

迷途指针 new delete

编程中有一种很难发现的错误是迷途指针.迷途指针也叫悬浮指针.失控指针,是党对一个指针进行delete操作后--这样会释放它所指向的内存--并没有把它设置为空时产生的.而后,如果你没有重新赋值就试图再次使用该指针,引起的结果是不可预料的.   空指针和迷途指针的区别? 当delete一个指针的时候,实际上仅是让编译器释放内存,但指针本身依然存在.这时它就是一个迷途指针. 当使用以下语句时,可以把迷途指针改为空指针: myPtr=0; 通常,如果在删除一个指针后又把它删除一次,程序就会变得非常不稳定

C安全问题与指针误用

指针的声明与初始化 1.不恰当的指针声明 考虑如下的声明: int* ptr1, ptr2; // ptr1为指针,ptr2为整数 正确的写法如下: int* ptr1, *ptr2; 用类型定义代替宏定义是一个好的习惯,类型定义允许编译器检查作用域规则,而宏定义不一定会. 使用宏定义辅助声明变量,如下所示: #define PINT int* PINT ptr1, ptr2; 不过结果和前面所说的一致,更好的方法是使用下面的类型定义: typedef int* PINT; PINT ptr1,

C语言指针的长度和类型

如果考虑应用程序的兼容性和可移植性,指针的长度就是一个问题,在大部分现代平台上,数据指针的长度通常是一样的,与指针类型无关,尽管C标准没有规定所有类型指针的长度相同,但是通常实际情况就是这样.但是函数指针长度可能与数据指针的长度不同. 指针的长度取决于使用的机器和编译器,例如:在现代windows上,指针是32位或是64位长 测试代码: #include<stdio.h> #include<math.h> #include<stdlib.h> #include<s

指向多维数组的指针变量

问题描述 指向多维数组的指针变量 #include int main() { int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; int *p; for(p=a[0];p<a[0]+12;p++) { if((p-a[0])%4==0) printf(" "); printf("%4d",*p); } } 把for(p=a[0];p<a[0]+12;p++)改成for(p=a[0];p<a+3;p++)为什么是正确的

指针-c语言中字符数组初始化问题

问题描述 c语言中字符数组初始化问题 字符数组初始化1: char str[]=""123"";//不报错2: char str[4]; str=""123"";//不能将const char[4] to char[4]字符指针初始化1: char *str=""123"";//不报错2: char *str; str=""123"";//不报错求

Ubuntu系统鼠标指针上下跳动该怎么办?

  可能不少网友都遇到了这个问题,就是鼠标指针一闪一闪的,一会而消失一会儿出现的样子.这个经验告诉你怎么做可以消除这个问题,保证99.5%有效率. 1.打开系统设置 2.点击显示 3.然后切换到"未知显示器",你会发现未知显示器是开启的状态 4.现在你只需要把未知显示器设置为"关闭"状态就可以了.然后点击应用,系统会提示你是否保存设置,注意别点错了.

C#定义鼠标指针形状

在Windows应用程序中,通过设置控件的Cursor属性可以定义鼠标的显示形状.控件(如Button控件)的Cursor属性用于设置鼠标指针的类型,默认为Default. 语法: public virtual Cursor Cursor { get; set; } 属性值:一个Cursor,表示当鼠标指针位于控件上时显示的光标. Cursor:是一个值,该属性值如表所示. 表 Cursor属性的值 值 说明 AppStarting 获取在应用程序启动时显示的光标 Arrow 获取箭头光标 Cr

fgets函数执行完成后,文件指针如何移动?

用fgets执行之后,读取了文件中的一行,这时文件位置指针是自动指向文件的下一行的开头吗,还是指向当前行的结尾?如果一行的字符串没读取完会怎样? 实例结果: 如果一行的字符串没读取完会,下一次会接着上一次读取: 如果读完了,直接从下一行开头开始. 百度百科: 从文件结构体指针stream中读取数据,每次读取一行. 读取的数据保存在buf指向的字符数组中,每次最多读取bufsize-1个字符(第bufsize个字符赋'\0'),如果文件中的该行,不足bufsize个字符,则读完该行就结束. 如若该