段错误造成的常见诡异宕机情况总结(中)

   上面一种情况是自己内存写超了,写到了用户态别的结构所在的内存,特点就是core文件显示 别处对象的内容乱七八糟,且一般是在对象析构时发生,这次讲解一下,自己把自己写坏的情况。
  1 /**
  2  *\author peakflys 
  3  *\brief 堆栈崩溃问题
  4  
*/
  5 #include <iostream>
  6 using namespace std;
  7 
  8 struct Temp
  9 {
 10     int a;
 11     unsigned char b[4];
 12 };
 13 
 14 class Test
 15 {
 16 public:
 17     void temp();
 18 private:
 19     void fill(unsigned char *data);
 20     Temp tt;
 21 };
 22 void Test::fill(unsigned char *data)
 23 {
 24     for(int i=0;i<20;++i)
 25     {
 26         data[i] = i;
 27         cout<<"data["<<i<<"]:\t"<<(void *)&data[i]<<endl;
 28     }
 29 }
 30 void Test::temp()
 31 {
 32     Temp t;
 33     fill((unsigned char *)&t);
 34 }
 35 
 36 int main()
 37 {
 38     Test *pt = new Test();
 39     pt->temp();
 40     delete pt;
 41     return 0;
 42 }
运行结果:
data[0]:        0x7fffa4a38c60
data[1]:        0x7fffa4a38c61
data[2]:        0x7fffa4a38c62
data[3]:        0x7fffa4a38c63
data[4]:        0x7fffa4a38c64
data[5]:        0x7fffa4a38c65
data[6]:        0x7fffa4a38c66
data[7]:        0x7fffa4a38c67
data[8]:        0x7fffa4a38c68
data[9]:        0x7fffa4a38c69
data[10]:       0x7fffa4a38c6a
data[11]:       0x7fffa4a38c6b
data[12]:       0x7fffa4a38c6c
data[13]:       0x7fffa4a38c6d
data[14]:       0x7fffa4a38c6e
data[15]:       0x7fffa4a38c6f
data[16]:       0x7fffa4a38c70
data[17]:       0x7fffa4a38c71
data[18]:       0x7fffa4a38c72
data[19]:       0x7fffa4a38c73
段错误 (core dumped)
堆栈情况:
Program terminated with signal 11, Segmentation fault.
[New process 18836]
#0  0x0000000000400a3e in main ()
(gdb) bt
#0  0x0000000000400a3e in main ()
(gdb) 
总结:temp成员函数在调用fill成员函数时通过thiscall方式调用,gcc具体实现是把this指针像普通参数一样入栈传过去,而VS是在定参的情况下,this指针通过ECX传入,这个就是这次悲剧的祸根,通过gdb打印出来的情况是:
(gdb) info fr
Stack level 0, frame at 0x7fff49980a50:
 rip = 0x400975 in Test::fill(unsigned char*) (test.cpp:22); saved rip 0x400a56
 called by frame at 0x7fff49980a80
 source language c++.
 Arglist at 0x7fff49980a40, args: this=0x601280, data=0x3d9da611a0 "\203�\001\031�f\203;"
 Locals at 0x7fff49980a40, Previous frame's sp is 0x7fff49980a50
 Saved registers:
  rbp at 0x7fff49980a40, rip at 0x7fff49980a48
(gdb) p &this
$7 = (Test * const *) 0x7fff49980a20
(gdb) p &data
$8 = (unsigned char **) 0x7fff49980a18
通过对data的持续写最终导致栈地址写到了this指针所在的栈内存,这样再从那块地址取this指针时,取的就不是this指针,最终从未知的“that指针”取数据,十有八九程序就挂了。
   这种情况出现在linux服务器上(确切的说是使用GCC编译器编译的程序上),特点就是 发生在类函数里,宕机位置不一定,每一次宕机 查看 类体对象内容也是错乱的,并且 关键是 this指针发生了改变,打印其地址时很可能是无法访问,预防方法还是边界访问检查。
    结合上一例子来看,段错误宕机重点嫌疑对象就是数组!排查的时候首先在空间近邻或者时间近邻上查找。实际应用中这类错误可能会很隐蔽,例如内存写超的代码发生在某些库代码里,这种情况就要求 写代码时对自己所调用的库函数 要大致了解 实现方法。总之,数组或者数组类指针是我们重点排查对象。
   未完待续……  peakflys

posted on 2012-09-21 13:32 peakflys 阅读(3944) 评论(2)  编辑 收藏 引用 所属分类: 服务器

评论

# re: 段错误造成的常见诡异宕机情况总结(中) 2012-09-21 16:29 zuhd

这种情况比较有意思  回复  更多评论   

# re: 段错误造成的常见诡异宕机情况总结(中) 2014-05-08 11:35 samjiao

这个地址可能给你误解了
(gdb) p &data
$8 = (unsigned char **) 0x7fff49980a18
这是指向地址的地址,往data写内容是是写到 0x7fff49980a18存放的地址上去,因此破坏的不是this指针。
这种情况下如果有多重调用,破坏的是上级的堆栈结构。因此导致segment fault。
你说的额数组是最大嫌疑非常有启发。  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2012年10月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

导航

统计

公告

人不淡定的时候,就爱表现出来,敲代码如此,偶尔的灵感亦如此……

常用链接

留言簿(4)

随笔分类

随笔档案

文章档案

搜索

最新评论

阅读排行榜

评论排行榜