author: hjjdebug
date: Thu Jul 17 13:57:31 CST 2014
--------------------------------------------------------------------------------
1. 症状。 segment fault . 死在第三方库里
--------------------------------------------------------------------------------
调试程序,segment fault 是较难处理的一类,死在自己的代码里还好说,死在别人的代码里
我们看不懂, 也不能指责别人的代码, 今天,就遇见了一个:
程序崩溃了,死在了一个第三方代码库里--libevent.
我们不用怀疑libevent, 但我也没有时间精力去跟踪libevent.代码。那么到底是什么原因触发它死掉呢?
先看看bug 是什么条件下产生的。
--------------------------------------------------------------------------------
2. 产生背景: 特定的条件下, 不符合逻辑的死亡
--------------------------------------------------------------------------------
一个server 可以连接很多client ,当client 初次连接server 时,一切工作正常, 退出client, 再重新
连接server 时,在一定条件下, 就会出现segment fault, 而且查看是死在libevent 中。 检查server.
似乎在内存管理上,在建立与client 会话上看不出明显的内存管理缺陷。
死亡是没有道理的。伴随着种种疑问和不解。
不符合逻辑和非常规的地方。
1. 发送这条指令不死,发送另一条指令就死了。 逻辑上它们走的几乎是没有差别的。
2. 如果代码写得有问题,死在自己的代码里好了,为什么死在第三方库里 ?
3. 要死为什么第一次连接时不死, 而必须是断开以后第二次连接时会死亡?
--------------------------------------------------------------------------------
3. 解决过程: 修改返回值,改变逻辑及二分法,屏蔽代码
--------------------------------------------------------------------------------
别无他法,我只能屏蔽复杂逻辑,简化代码,看看到底是什么直接引起的第三方库崩溃。
我知道这有可能是竹篮子打水一场空,因为对于一些肯定是逻辑正确的代码, 也不得不屏蔽和怀疑。
因为我必须要尊重事实, 可能把它们屏蔽了,就暂时不死机了。
终于,出现了不同的死法,这次死在我们的代码里。 当然还是segment fault, 看得很清楚,是内存访问
指针被破坏了。
那么,是谁破坏了这个指针呢?
gdb 单步跟踪, 监视上这个内存变量(display). 发现,在调用evtimer_add 时修改了这个变量。
马上意识到是timer 的问题。 关掉这句话及相关的timer 设置,再玩, 程序不会再崩溃了。
细细观察代码,发现在关断连接释放资源时,原来设定的timer 没有关断, 而这个event 变量所在的内存
是被释放掉了的。这就是说,旧的timer 还在使用这个已经被释放的内存。
接下来。 client 第二次进行连接,当走到向libevent 注册timer 时,它会进行将新timer 加入链表的
以后谁访问这个被破坏的变量,谁就不会有好结果。
到底是死在第三方库里,还是死在自己的代码里, 跟程序的代码长度,内存占用有关系。就看谁分配占用了这块危险内存
至此,上面的种种疑问都已烟消云散。
--------------------------------------------------------------------------------
4. 最后结论: 隐形杀手--谁用了这块内存,就让谁死。
--------------------------------------------------------------------------------
segment fault , 是程序使用了非法内存。
1. 内存越界是一种非法使用。
2. 已经被释放的内存,你又来使用,容易引起意想不到的错误。其错误的出现,是不已常规逻辑进行的。
因为这块内存将来会分配给别的变量, 你如果修改了内容,别的变量就遭殃了.
如果修改的是个指针内容,就会引起segment fault 错误。如果是数据,别人也拿不到正确结果了。
date: Thu Jul 17 13:57:31 CST 2014
--------------------------------------------------------------------------------
1. 症状。 segment fault . 死在第三方库里
--------------------------------------------------------------------------------
调试程序,segment fault 是较难处理的一类,死在自己的代码里还好说,死在别人的代码里
我们看不懂, 也不能指责别人的代码, 今天,就遇见了一个:
程序崩溃了,死在了一个第三方代码库里--libevent.
我们不用怀疑libevent, 但我也没有时间精力去跟踪libevent.代码。那么到底是什么原因触发它死掉呢?
先看看bug 是什么条件下产生的。
--------------------------------------------------------------------------------
2. 产生背景: 特定的条件下, 不符合逻辑的死亡
--------------------------------------------------------------------------------
一个server 可以连接很多client ,当client 初次连接server 时,一切工作正常, 退出client, 再重新
连接server 时,在一定条件下, 就会出现segment fault, 而且查看是死在libevent 中。 检查server.
似乎在内存管理上,在建立与client 会话上看不出明显的内存管理缺陷。
死亡是没有道理的。伴随着种种疑问和不解。
不符合逻辑和非常规的地方。
1. 发送这条指令不死,发送另一条指令就死了。 逻辑上它们走的几乎是没有差别的。
2. 如果代码写得有问题,死在自己的代码里好了,为什么死在第三方库里 ?
3. 要死为什么第一次连接时不死, 而必须是断开以后第二次连接时会死亡?
--------------------------------------------------------------------------------
3. 解决过程: 修改返回值,改变逻辑及二分法,屏蔽代码
--------------------------------------------------------------------------------
别无他法,我只能屏蔽复杂逻辑,简化代码,看看到底是什么直接引起的第三方库崩溃。
我知道这有可能是竹篮子打水一场空,因为对于一些肯定是逻辑正确的代码, 也不得不屏蔽和怀疑。
因为我必须要尊重事实, 可能把它们屏蔽了,就暂时不死机了。
终于,出现了不同的死法,这次死在我们的代码里。 当然还是segment fault, 看得很清楚,是内存访问
指针被破坏了。
那么,是谁破坏了这个指针呢?
gdb 单步跟踪, 监视上这个内存变量(display). 发现,在调用evtimer_add 时修改了这个变量。
马上意识到是timer 的问题。 关掉这句话及相关的timer 设置,再玩, 程序不会再崩溃了。
细细观察代码,发现在关断连接释放资源时,原来设定的timer 没有关断, 而这个event 变量所在的内存
是被释放掉了的。这就是说,旧的timer 还在使用这个已经被释放的内存。
接下来。 client 第二次进行连接,当走到向libevent 注册timer 时,它会进行将新timer 加入链表的
操作,因而会访问和修改上个timer 的结构变量, bug 触发条件已经到来,上个timer 变量,已经被释放了,
这块内存,可能给了别的变量了
这一改, 就把内存改乱了。 留下了祸患
,以后谁访问这个被破坏的变量,谁就不会有好结果。
到底是死在第三方库里,还是死在自己的代码里, 跟程序的代码长度,内存占用有关系。就看谁分配占用了这块危险内存
至此,上面的种种疑问都已烟消云散。
--------------------------------------------------------------------------------
4. 最后结论: 隐形杀手--谁用了这块内存,就让谁死。
--------------------------------------------------------------------------------
segment fault , 是程序使用了非法内存。
1. 内存越界是一种非法使用。
2. 已经被释放的内存,你又来使用,容易引起意想不到的错误。其错误的出现,是不已常规逻辑进行的。
因为这块内存将来会分配给别的变量, 你如果修改了内容,别的变量就遭殃了.
如果修改的是个指针内容,就会引起segment fault 错误。如果是数据,别人也拿不到正确结果了。
使用已经释放的内存,等于使用不属于自己的内存,这种做法会使别人遭殃, 谁用了这个(或这块)内存,谁就没有好结果。
如何保证释放了的内存不被访问, 如何快速报告出这种bug, 及如何发现内存使用上的bug, valgrand 给出了答案.