为什么悬空指针deferences会使程序崩溃

时间:2016-03-22 06:26:44

标签: c++ c pointers memory memory-management

我多次听说悬挂指针取消引用会导致程序崩溃,但我不知道为什么。有人可以向我解释一下吗?

据我所知,在C / C ++中,在我们通过指针o释放内存对象p之后,p成为一个指向语义无效的内存地址的悬空指针{{ 1}}。也许稍后addr被内存分配器重新分配给另一个内存对象。无论是否发生这种情况,操作系统都会认为addr仍然是一个合法的访问地址,因为内存分配器只从os请求内存并且永远不会将内存返回给操作系统。所以应该没有崩溃。有人可以告诉我,我的理解是错误的吗?

3 个答案:

答案 0 :(得分:4)

  

无论是否发生这种情况,操作系统都会认为addr仍然是访问的合法地址

不,事实并非如此,恰恰相反。一旦你free()内存,无论它是否真的被解除分配,它被认为是非法的(甚至再次尝试free() )。

由于每次非法内存访问都会调用undefined behavior,因此这样做会产生副作用并导致分段错误。

答案 1 :(得分:1)

悬空指针可以指向任何东西,有时程序可能会继续 因为它得到的值似乎是正确的,这可能会多次传播 直到某些事情出现故障或更糟。

foo *bar = malloc(sizeof(foo));
void * dangling = &bar;
free(bar);

悬空现在指向什么?或者将堆栈分配的结构作为a返回 指针即

char * foo() {
  char string[10] = "Boom";
  return string;
}   

基本上程序无法检测到正在使用的项目是否有效 直到使用,有时即使使用它仍然没有检测到它。检测可以按严重程度排列如下......

  1. 编译器会发现双重释放或者您正在返回对堆栈分配对象的引用。或者你试图释放它从未实际分配的对象。

  2. 您尝试访问在进程地址空间外分配的内存的OS点,即访问冲突/分段错误/总线错误等。

  3. 你的程序开始表现得很奇怪,最终会爆炸或有人重新启动你的应用程序,或者内存不足等。

  4. 在我的情况下你的分配器即malloc可以从区域分配内存,即预分配的内存块,它具有起始和结束地址。任何释放其中一个范围之外的区域的请求都是错误的,在这种情况下您可能会遇到分段错误。这是分配器可以检测到的一个错误,它无法检测到您已经对已经解除分配的内存区域(即现在是垃圾)进行了引用。然后你尝试使用垃圾和随后的混乱。

答案 2 :(得分:1)

关于未定义行为的语言规则,释放内存可能会很好地将内存返回给操作系统。直接在调用free时或者稍后,当OS耗尽内存本身并要求应用程序返回未使用的块时。

当您意外覆盖其他数据时,悬空指针也会间接导致崩溃,例如数组的长度或函数的返回地址