Chinaunix首页 | 论坛 | 博客
  • 博客访问: 195407
  • 博文数量: 71
  • 博客积分: 3000
  • 博客等级: 中校
  • 技术积分: 450
  • 用 户 组: 普通用户
  • 注册时间: 2007-11-29 21:28
个人简介

思考人生、专注技术

文章分类

全部博文(71)

文章存档

2015年(1)

2009年(2)

2008年(11)

2007年(57)

我的朋友

分类: C/C++

2015-08-27 09:54:12

人总是会犯错,所以程序也就有bug;这里我们就简单说说Linux下几种用户态程序内存相关异常。
首先需要了解的是Linux进程内存空间布局,如图:
                       
1、内核空间3~4G,由于CPU有运行级别限制,用户态程序没有权限修改内核地址空间,我们只需要考虑用户态空间0~3G;
2、0~3G空间,被划分为不同的段,Linux系统在进程刚创建的时候,就已经将“0~128M空间”以及“程序文件.text”段保护起来,用户程序指令无法修改;
3、“用户栈”空间,主要是指程序运行过程中保存函数调用链的地方,如果函数调用过深或是局部变量过大,则会出现栈溢出;另外如果某级函数里面局部变量越界,会造成函数栈空间破坏;
4、“.data”、“.bss”、“heap”等空间,因为我们会操作这些内存空间,比如malloc一块内存,然后进行写操作,一个不小心,可能会写越界,从而覆盖其它内存空间;

    通过以上分析,我们可以得出以下几种内存异常:

    一:非法地址访问
               
               
    这种类型的段错误,比较好处理,只要gdb上去看下是哪一行哪个变量,基本就可以解决(需要说明的是如果编译进行了优化,比如“-O2”选项,需要能阅读基本的汇编指令,才可以定位出哪一行)。

    二:栈溢出
               
                
    这里main文件调用一个递归函数,该递归函数里面有个比较大的局部变量,256K大小,我们可以看到递归到第八次栈就溢出,那么基本可以判定该进程栈空间大小约为4M(MAC系统)。

    三:全局变量越界
                          
               
               
                
    对于全局变量或是堆变量越界,基本上需要将该变量所在地址空间前面一段内存打印出来,查看是哪一块内存越界;对于全局变量,gdb下可以直接翻译出符号,很容易识别一段内存区域属于哪个全局变量;但是堆内存约为是动态分配,如果没有经过封装,将内存申请调用栈记录在内存头上,我们很难知道这块内存在哪里申请的,只能根据内存内容大概猜测一下。

    四:栈破坏
        首先,我们来看下进程的栈空间布局:

                    

 
    根据不同的CPU体系、不同的编译器及优化级别,形成的栈也有所区别,不过上图大致反映了Linux C/C++进程的栈布局。如图一段代码,如下图:
                  
                  
    gdb上去,如图:
                  
                  
    找到rbp、rsp两个寄存器值,然后打印栈内容:
                      
    从被破坏的栈里面找出残余信息,如图:
1、被破坏的内容是蓝色矩形框住的部分;
2、红色箭头表示的即是函数栈帧的链表,栈最上面存储的是一个指针,指向调用者的栈顶,后面紧接着存储的是调用者的返回地址;
3、绿色矩形框住的就是函数返回地址,通过gdb可以找到对应的函数就是func_c和func_b;
    至此就分析出异常发生前的函数调用链。

阅读(1922) | 评论(0) | 转发(0) |
0

上一篇:linux char device driver

下一篇:没有了

给主人留下些什么吧!~~