Dangling Pointers----悬挂指针

1. Dangling Pointers---悬挂指针

如果指针在被释放后,仍然引用原来的内存,就叫做悬挂指针。该指针不指向任何有效的对象。有时称为过早释放。

使用悬挂指针能导致几种不同的问题,包括:

  • 不可预知的行为,如果访问内存
  • 分段错误,当内存不再是可访问
  • 潜在的安全风险
如下情况将产生这些错误:
  • 释放后访问内存
  • 一个指针返回到前一个函数调用的自动变量
2. 悬挂指针举例
下面是一个简单的例子,我们使用malloc函数给一个整形变量分配内存,接着使用free函数释放内存:
int *pi = (int*) malloc(sizeof(int));
*pi = 5;
printf("*pi: %d\n", *pi);
free(pi);
变量pi仍然指向分配的整形地址。不过,这块内存可能被堆管理器重新使用,可能存放不是整形的数据。下图说明了程序在执行free函数前后的状态。变量pi假定是main函数的一部分,被分配到地址100处。用malloc分配的内存指向地址500处.


当执行free函数,地址500被收回,并且不应当被使用。不过,很多实时系统不能阻止后续的访问和修改。我们可能还会试图去给这块区域赋值,如下代码所示。这个行为的结果是不可预知的。
free(pi);
*pi = 10;

一个更具有欺骗性的例子是多个指针引用同一片内存,而其中一个被释放了。如下所示,p1和p2引用了同一块内存区域,称为指针别名。不过,p1已经被释放了:
int *p1 = (int*) malloc(sizeof(int));
*p1 = 5;
...
int *p2;
p2 = p1;
...
free(p1);
...
*p2 = 10;  // Dangling pointer
下图说明了内存分配情况,虚框代表已经释放的内存。


当使用块语句是,将发生一个细小的问题,如下代码所示。pi指向变量tmp的地址。变量pi可能是一个全局或者局部变量。然而,当tmp的封闭块弹出程序堆栈后,该地址不再有效了:
int *pi;
...
{
int tmp = 5;
pi = &tmp;
}
// pi is now a dangling pointer
foo();
很多编译器会认为块语句是一个栈帧。变量tmp分配在栈帧上,紧接着在块语句退出后弹出栈。现在指针pi指向的内存区域可能最终被不同的活动记录修改,例如函数foo。下图说明了这种情况:


3. 处理悬挂指针
有时很难解决指针产生的问题。存在某些解决悬挂指针的方法,包括:
  • 释放后将指针置为NULL。继续使用该指针将导致程序终止。然而,如果有多个指针副本存在,问题可能持续发生。因为赋值只影响其中一个副本。
  • 编写特殊的函数代替free函数
  • 某些系统(实时/调试器),当指针释放后,会重写数据(例如)xDEADBEEF - Visual Studio会使用0xCC,0xCD,或者0xDD,依赖释放的是什么)。
  • 使用第三方工具检测悬挂指针和其他问题。
显示指针的值有助于调试悬挂指针,但如何显示指针的值需要谨慎对待。assert宏也是很有效的工具。
4. 调试版本帮助检测内存泄露
借助调试工具检测内存泄露


翻译自Understanding and Using C Pointers

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值