你的C/C++程序为什么无法运行?揭秘Segmentation fault (2)

转载自:http://blog.csdn.net/gsky1986/article/details/45371051

目录(?)[+]

什么让你对C/C++如此恐惧?

本篇将继续上一篇来讨论段错误(Segmentation fault)。 
上一篇: 
你的C/C++程序为什么无法运行?揭秘Segmentation fault(1)

追溯段错误

如果你觉得你已经理解了段错误的根源,也知道了如何防止段错误,那么可以到此为止。否则,下面的内容或许对你有所启发。

malloc

我们开始为指针所指向的地址分配内存: 
这里写图片描述

注意,(*dest) = (char*)malloc(sizeof(char)*n);的右边已经执行,但尚未将分配出的地址赋给指针*dest

接下来,我们的主角段错误的前夕:

这里写图片描述

上面的图告诉我们一些信息:

红线勾勒出的内容是: 
从函数func1的局部变量中取出指针dest(char ** 型)指向的地址,正确的代码中地址是0x7fffffffddc0,而错误的代码中地址则是0x0.

下一步即将执行黄线勾勒出的内容

<code class="hljs css has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*
 注意这里的rax在错误的代码中为0x0
 而rdx的值为malloc出的内存地址0x602010
*/</span>
<span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">mov</span>    <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">QWORD</span> <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">PTR</span> <span class="hljs-attr_selector" style="color: rgb(0, 136, 0); box-sizing: border-box;">[rax]</span>,<span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">rdx</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

那么,当执行上面的代码时,错误的代码试图将malloc分配出的在堆上的内存地址当作值放在指针dest指向的地址中。

<code class="hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;">地址:0x0 值:0x602010</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

那么就出现了上篇所说的,0x0是不能被访问的地址,也就不可能完成赋值操作。所以就会出现段错误: 
这里写图片描述

什么是段错误

对于很多人来讲。上面的分析比第一篇要深入一些,也许看得到真相前的每一步才能让人踏实。

现在,我们来看看什么是段错误。

下图是一个进程地址空间的描述,这是一个旧图,网上到处都是,但可以用来理解VMA: 
这里写图片描述

上面这幅图会告诉我们什么呢?

内核虚拟内存空间,你肯定访问不了. 
用户栈,用户进程启动就会有这样一个结构,你超过它的上界就到了内核虚拟内存空间,就会出现段错误. 
内存映射mmp区域. 
堆,malloc、calloc就在这里找地址分配.(事实上不仅如此) 
代码、数据段 包括全局变量、静态变量、代码、数据等等.

如果你访问了内核虚拟内存空间(就是比ebp大的空间,1都不行)、代码段、数据段都会引发段错误。

在上篇的例子中,是由于访问了图中红色圈出的保留区域造成的段错误

补充一下x86_64的VMA-layout:

这里写图片描述 

找到代码中的段错误

方法有很多。我也只会1个,毕竟我不写C/C++,更不是这方面的老手。 
利用coredump+gdb来做。 
获取coredump的方法:

<code class="hljs autohotkey has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>.在shell中<span class="hljs-escape" style="box-sizing: border-box;">`u</span>limit -c unlimited<span class="hljs-escape" style="box-sizing: border-box;">`
</span><span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>.运行你发生了段错误的程序</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>

有了coredump,就可以拿gdb来掰掰了gdb xx xxcoredump
这里写图片描述 
上图有几个信息:

1.signal 11,是什么呢? 
这里写图片描述 
2.Segmentation fualt 段错误 
3.stack2.c中的第8行出现错误. 
4.细心观察还会看到函数func1的参数dest=0x0.

我想,对于这样一个简单的c程序,上面的信息足够了. 
这里写图片描述

其它

也许后面还想看看mmap、mm的fault处理、页异常处理还有signal的一些东西. 
但本篇,就此结束.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值