C ++堆栈和堆损坏

时间:2014-10-04 12:32:14

标签: c++ heap-corruption stack-corruption

我最近在阅读有关堆栈& amp; C& C中的堆腐败C ++。该网站的作者使用以下示例演示了堆栈损坏。

#include<stdio.h> 
 int main(void) 
 { 
     int b = 10; 
     int a[3]; 
     a[0] = 1; 
     a[1] = 2; 
     a[2] = 3; 

     printf(" b = %d \n",b); 
     a[3] = 12; // oops it is invalid, behaviour is undefined
     printf(" b = %d \n",b); 
     printf("address of b= %x\n",&b);
     printf("address of a[3]= %x\n",&a[3]);
     return 0; 
 }

我在visual studio 2010编译器(VC ++)上测试了以上程序&amp;它给我的运行时错误说:

  

围绕变量a的堆栈被破坏

现在我的问题是:堆栈是否已终生损坏,或者仅在上述错误程序执行期间?

同样,我知道两次删除相同的指针可能会造成堆损坏等非常糟糕的事情。 以下代码:

int* p=new int();
delete p;
delete p;  // oops disaster here, undefined behaviour

当上述代码片段执行时,VC ++在运行时显示堆损坏错误。

3 个答案:

答案 0 :(得分:7)

未定义的行为。如果你做“禁止”的事情,你无法知道会发生什么。您无法保证您的计划能够正常运作。

答案 1 :(得分:6)

你必须小心这里的术语。堆栈是否会被损坏&#34;你节目的剩余时间?它可能是;它可能不是。在这种情况下,您只会损坏当前堆栈框架中的数据,因此一旦您退出该函数调用,实际上您的&#34;损坏&#34;会消失的。

但这并非完整的故事。既然你已经覆盖了一个不应该存在字节的变量,你的程序可能会产生什么连锁反应呢?如果您通过网络连接发送此数据且数据不再符合预期,则此内存损坏的后果可能会逻辑传递到其他功能范围,甚至其他计算机上形成。 (通常,您的数据协议将内置安全功能,以检测和丢弃意外形式的数据;但是,这取决于您。)

堆损坏也是如此。每当你覆盖不应该被覆盖的东西的字节时,以及任何时候使用任意不可知数据,你都有可能带来灾难性后果的风险这可能在逻辑上持续超过你的程序的生命周期。

在C ++作为一种语言的范围内,这个条件总结为一个特定的短语: undefined behavior 。它表明,在你的内存损坏之后,你根本不能依赖任何东西。一旦你调用了UB,所有的赌注都会被取消。

您通常在实践中保证的一个保证是您的操作系统不允许您直接覆盖任何不属于您的程序的内存。也就是说,破坏其他进程或操作系统本身的内存非常困难。现代操作系统的内存模型是故意设计的,以便保持程序隔离并防止破坏的程序和/或病毒造成这种损害。

答案 2 :(得分:0)

C ++以及C没有数组边界上溢或下溢检查。但是,您可以抽象出来,您可以使用重载索引运算符(operator [])定义一个数组,您可以在其中检查数组索引是否超出范围并相应地执行操作。当您使用delete ptr删除指针时(当通过new分配ptr时),之前分配的空间将返回到堆空间,但指针的值将变为与之前相同。所以,它是一个很好的编程习惯,你应该在删除后使ptr为NULL,例如

int* p=new int();
...
if (p) {
  delete p;
  p = (int *) NULL;
}
// double deletion is prevented, and ptr us not dangling any more 
if (p) {
  delete p;
  p = (int *) NULL;
}

但是,堆栈或堆损坏(如果有的话)仅限于程序空间内,当程序正常或异常终止时,所有内存占用都将释放回操作系统