最近在调试代码的时候闹人的segmentation-fault段错误,又来烦人了,不过代码都是自己写的 ,有事也是作茧自缚,自作自受,先自责下。
来看看在串口段错误给了我们什么信息:
可以看出 Fault addr=0x328,出错的地址在 0x328,这个哪 啊?可惜backtrace没有给出execution path,哎,也不知道出在哪行代码了。得,自己发掘吧。
这里我们可以先用addr2line工具看看能否找出出错行,
只给出几个问号,鸡毛都没有,这可能有两种情况,一是编译的时候没加-g选项,另一个原因是0x328可能是系统函数的调用地址?反正就是没有什么信息。
那么还是编译的时候先把-g加上吧,然后把gdb请出来。我们使用的是嵌入式环境,需要使用交叉编译的gdb工具,这个过程就不说了,可以看另外一篇文章。
http://blog.csdn.net/mantis_1984/article/details/27494579
在target端用gdbserver 把应用程序挂起,监控:
./arm-arago-linux-gnueabi-gdbserver 192.168.1.100:2000 ./my_app &
然后在server端启动gdb:
然后重复刚才出错的时的操作,看看GDB会抓到什么错误信息:
好,gdb捕捉到了这个段错误信息,接下来看看栈回溯信息:
frame 0貌似没有什么信息展示出来,那么看看frame 1
可以看到frame 1调用栈在代码memcpy处进入的下一级 frame 0, 然后出错,那基本上可以锁定就是“
memcpy();这一行代码出现的问题,分别把变量dst和pst 打印出来,此时发现pst是不能访问的内存,且此地址正是0x328,也就是前面所说串口包段错误的地址。
这句代码貌似没什么问题,此时分析问题就要结合代码的上下文以及其调用关系了。我们通过栈回溯可以追查到到底哪里调用的这段代码。
代码太长,截取一段说明问题出在哪里,调用log_list_get_one_log后,获取一条日志在oneNode里,但是链表中的oneNode->next也被获取出来了,
下面在创建本地链表时给pst->next=NULL本没有问题,可以后面的memcpy后把oneNode->next也赋值给了pst->next,这是我们不愿意看到的,因为当本地释放
pst后,会将glb_h_alarm_log中的那个next指针所指向的内存也释放掉了,所以再次用获取glb_h_alarm_log时会出现内存不可访问的段错误(上面的0x328)不能
访问,因为在外面已经被释放。
所以说在使用链表,尤其是复制别的链表时,一定要小心处理这个next指针,很危险的。所以上面代码应该改成 memcpy这一行与pst->next=NULL交换,就没有问题了。
问题比较隐蔽,没有gdb,这个问题估计很难发现。