经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
记录一次gdb debug经历
来源:cnblogs  作者:gatsby123  时间:2019/10/29 10:32:20  对本文有异议

问题描述

今天在写代码时,运行时奔溃了。segment fault,而且是在程序退出main()函数后,才报的。
唯一的信息是:Segmentation fault (core dumped)
简直是一头雾水。

查看core文件

系统默认是不会生成core文件的,ulimit -c unlimited把core文件设为无限大。

使用gdb查看core文件

gdb ./example/sudoku_batch_test core
提示如下:

  1. Program terminated with signal SIGSEGV, Segmentation fault.
  2. #0 __GI___libc_free (mem=0x313030303030300a) at malloc.c:2951
  3. 2951 malloc.c: No such file or directory.
  4. (gdb)

可以确定崩溃发生在malloc.c中。但是提示没有malloc.c的源码。

首先安装glibc的符号表,命令如下:
sudo apt-get install libc6-dbg

再来是安装glibc的源文件,命令如下:
sudo apt-get source libc6-dev
安装完毕后在当前目录下会多出一个glibc-2.23文件夹,该文件夹包含了glibc的源码。

源码准备就绪后,接着上面,在gdb命令提示符下输入:
directory glibc-2.23/malloc/将glibc-2.23/malloc/设为gdb源码搜索目录。结果如下:

  1. warning: core file may not match specified executable file.
  2. [New LWP 24491]
  3. [Thread debugging using libthread_db enabled]
  4. Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
  5. Core was generated by `./example/sudoku_batch_test ../example/test1000 127.0.0.1 1'.
  6. Program terminated with signal SIGSEGV, Segmentation fault.
  7. #0 __GI___libc_free (mem=0x313030303030300a) at malloc.c:2951
  8. 2951 malloc.c: No such file or directory.
  9. (gdb) directory glibc-2.23/malloc/
  10. Source directories searched: /root/work/melon/build/glibc-2.23/malloc:$cdir:$cwd
  11. (gdb)

现在我们就可以在gdb中查看崩溃处的源码了,执行list

  1. (gdb) l
  2. warning: Source file is more recent than executable.
  3. 2946 if (mem == 0) /* free(0) has no effect */
  4. 2947 return;
  5. 2948
  6. 2949 p = mem2chunk (mem);
  7. 2950
  8. 2951 if (chunk_is_mmapped (p)) /* release mmapped memory. */
  9. 2952 {
  10. 2953 /* see if the dynamic brk/mmap threshold needs adjusting */
  11. 2954 if (!mp_.no_dyn_threshold
  12. 2955 && p->size > mp_.mmap_threshold
  13. (gdb)

虽然知道了崩溃发生在2951行,但是貌似没有更多有效的信息。这时我想到了是不是可以看下函数的调用栈,或许会有信息。
接着执行backtrace(或者bt):

  1. (gdb) bt
  2. #0 __GI___libc_free (mem=0x313030303030300a) at malloc.c:2951
  3. #1 0x000000000048bc9d in melon::Coroutine::~Coroutine (this=0x1fc9120, __in_chrg=<optimized out>)
  4. at /root/work/melon/src/Coroutine.cpp:56
  5. #2 0x000000000048d099 in std::_Sp_counted_ptr<melon::Coroutine*, (__gnu_cxx::_Lock_policy)2>::_M_dispose (
  6. this=0x1fc8190) at /usr/include/c++/5/bits/shared_ptr_base.h:374
  7. #3 0x00000000004630f1 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0x1fc8190)
  8. at /usr/include/c++/5/bits/shared_ptr_base.h:150
  9. #4 0x0000000000461f32 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=0x7f07f4ff1770,
  10. __in_chrg=<optimized out>) at /usr/include/c++/5/bits/shared_ptr_base.h:659
  11. #5 0x00000000004749ed in std::__shared_ptr<melon::Coroutine, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (
  12. this=0x7f07f4ff1768, __in_chrg=<optimized out>) at /usr/include/c++/5/bits/shared_ptr_base.h:925
  13. #6 0x0000000000474a39 in std::shared_ptr<melon::Coroutine>::~shared_ptr (this=0x7f07f4ff1768,
  14. __in_chrg=<optimized out>) at /usr/include/c++/5/bits/shared_ptr.h:93
  15. #7 0x00007f07f40915ff in __GI___call_tls_dtors () at cxa_thread_atexit_impl.c:155
  16. #8 0x00007f07f4090f27 in __run_exit_handlers (status=0, listp=0x7f07f441b5f8 <__exit_funcs>,
  17. run_list_atexit=run_list_atexit@entry=true) at exit.c:40
  18. #9 0x00007f07f4091045 in __GI_exit (status=<optimized out>) at exit.c:104
  19. #10 0x00007f07f4077837 in __libc_start_main (main=0x45f1c4 <main(int, char**)>, argc=4, argv=0x7ffcfb2ab218,
  20. init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7ffcfb2ab208)
  21. at ../csu/libc-start.c:325
  22. #11 0x000000000045ec89 in _start ()

这下问题找到了,首先在线程结束或者程序运行结束会调用__GI___call_tls_dtors函数来析构线程本地存储。我确实用了thread_local关键字修饰Coroutine::Ptr变量。
#1 0x000000000048bc9d in melon::Coroutine::~Coroutine可知在melon::Coroutine类的析构函数中调用了free()导致奔溃。
这下问题基本明确了,我在Coroutine析构函数中会释放stack_这个指针,

  1. 53 Coroutine::~Coroutine() {
  2. 54 LOG_DEBUG << "destroy coroutine:" << name_;
  3. 55 if (stack_) {
  4. 56 free(stack_);
  5. 57 }
  6. 58 }

有两个构造函数,其中一个如下:

  1. 39 Coroutine::Coroutine()
  2. 40 :c_id_(++t_coroutine_id),
  3. 41 name_("Main-" + std::to_string(c_id_)),
  4. 42 cb_(nullptr),
  5. 43 state_(CoroutineState::INIT) {
  6. 44
  7. 45 if (getcontext(&context_)) {
  8. 46 LOG_ERROR << "getcontext: errno=" << errno
  9. 47 << " error string:" << strerror(errno);
  10. 58 }
  11. 59 }

因为大意犯了个非常低级的错误,这个构造函数没有正确初始化statck_指针,将statck_初始化为nullptr后,问题就解决了。

总结

遇到这类问题,一般用gdb查看core文件都能定位到崩溃的位置,如果不是直接引发的,可以查看函数调用栈,一般都能找到问题原因。

原文链接:http://www.cnblogs.com/gatsby123/p/11755320.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号