内存损坏问题的演示样例及分析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内存损坏问题的演示样例及分析相关的知识,希望对你有一定的参考价值。

原文以演示样例代码系统的讲述了三种内存损坏的情况: 全局内存、栈损坏及堆损坏, 以及它们产生的原因。

粗略整理例如以下。


Global Memory Corruption

即全局变量的内存使用出了问题,主要还是越界。

例如以下代码:

#include <stdio.h>
#define MAX 6
int arrdata[MAX];
int endval;
int main()
{
   int i = 0;
   endval = 12;
   for (i = MAX; (endval) && (i >= 0) ; i--, endval--)
   {
      arrdata[i] = endval * endval;
   }

   printf("Values are \n");
   for (i = 0; i < MAX; i++)
   {
      printf("\t %d\n", arrdata[i]);
   }
   return 0;
}


编译运行,输出的结果是:

Values are
19044
19321
19600
19881
20164
20449


走查代码,你能够发现第一个循环里i的初值是MAX, 应该是MAX-1。

正是这个越界,改写了endval的值。

那个全局变量在内存里是邻居(译注:在我的Mac OS上的输出结果):

(gdb) p &endval
$2 = (int *) 0x100001038
(gdb) p &arrdata
$3 = (int (*)[6]) 0x100001020


所以arrdat[MAX]的赋值操作,实际变成了对endval的赋值。


这种破坏操作能够概括为两种:

  •  数组越界,向上或向下(负值).
  •  通过指针訪问了错误的地址。


Stack Corruption

在*nix系的系统里,Stack会用来存储局部变量, 函数參数以及返回值。栈损坏经常导致未知的行为及崩溃。


栈损坏有两种情况:

  • 内存越界操作。
  • 栈溢出(stack overflow)。


内存越界

越界的情况和之前类似,仅仅是发生在了栈存储的数据上。比方以下的代码 :

#include <stdio.h>
#include <string.h>
#define LEN 6

void cpyPrint(char *str)
{
   char aBuf[LEN];
   strcpy(aBuf, str);

   printf("String is %s\n", aBuf);
}

int main()
{
   char *aStr = "MyLinux";

   cpyPrint(aStr);

   return 0;
}


编译运行就会崩溃。

以下是在我的Mac OS上的结果:

(gdb) r
Starting program: /Volumes/Development/Project/Testing/stackcorrupt
Reading symbols for shared libraries +.............................. done

Program received signal SIGABRT, Aborted.
0x00007fff88815d46 in __kill ()
(gdb) bt
#0  0x00007fff88815d46 in __kill ()
#1  0x00007fff8602d053 in __abort ()
#2  0x00007fff85fee74d in __chk_fail ()
#3  0x00007fff85feea1f in __strcpy_chk ()
#4  0x0000000100000ea6 in cpyPrint (str=0x100000f3e "MyLinux") at stackcorrupt.c:8
#5  0x0000000100000ef3 in main () at stackcorrupt.c:17


原因在cpyPrint函数中的局部变量大小为6,却要放进去8个字符(包含一个结束符)。


栈溢出

以下是栈溢出问题的演示样例代码:

#include <stdio.h>
int recur(long int var)
{
   if (var > 0)
   {
       recur (var--);
   }

   printf("the var is %ld\n", var);
   return var;
}

int main()
{
   recur (3000);
   return 0;
}


这段代码什么时候崩。还要看在运行的系统里的栈大小的设置,能够使用以下的指令直接查到:

$ulimit -s

默认情况下会是8192 (KBytes)。


Heap Corruption


出现堆错误。会报臭名昭著的Segment Fault错误。产生的原因有三种:

  • 尝试向已经释放的内存写入数据。

  • 越界操作 (的确是最常见的原因)。
  • 尝试向尚未分配的内存写入数据。


以下是一个演示样例:

#include <stdio.h>
#include <stdlib.h>
int main()
{
   int *pData = NULL;
   int num = 12;
   pData = (int*) malloc (num * sizeof (int));
   //...do stuff use the memory
   free(pData);

   pData[0] = -1;
   pData = (int*) malloc (num * sizeof (int));
   //...do stuff use the memory
   free(pData);
   return 0;
}


要想排查内存问题,首选工具自然是Valgrind了,不多做介绍了。


原因链接: http://mylinuxbook.com/memory-corruption-in-linux-programming/

 


以上是关于内存损坏问题的演示样例及分析的主要内容,如果未能解决你的问题,请参考以下文章

基于turtle库的七段数码管绘制

损坏的顶点和片段着色器

Shell编程入门

ThreadLocal 内存泄漏 代码演示 实例演示

linux下分析Java程序内存汇总

JAVA|一步一步带你看清,关于ThreadLocal内存溢出代码演示和原因分析!