【问题标题】:C++ How to interpret gdb backtrace log in UbuntuC++ 如何在 Ubuntu 中解释 gdb 回溯日志
【发布时间】:2017-09-26 14:51:07
【问题描述】:

我编写了一个相当大的 C++ 程序。作为前言,程序每次运行都很好,除了退出错误,free() 无效指针通常会导致核心转储;除此之外,该程序每次都会执行我需要它执行的操作。该程序没有任何指针对象或初始化;尽管程序很长(大约 3000 行),但编写起来相当简单(主要是 int 变量和一些 2D 矢量数组)。我的第一个想法是某些 FOR 循环的写入超出了向量范围,因此我运行 Valgrind mems 检查以查看是否存在任何内存泄漏,但 Valgrind 返回了一个干净的报告。我的下一个倾向是使用 gdb 并查看它是否返回任何错误。它确实返回了一个 SEGABRT,所以我回溯了它,gdb 返回了以下内容,

> #0  0x00007ffff7018c37 in __GI_raise (sig=sig@entry=6)
>     at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
> #1  0x00007ffff701c028 in __GI_abort () at abort.c:89
> #2  0x00007ffff70552a4 in __libc_message (do_abort=do_abort@entry=1, 
>     fmt=fmt@entry=0x7ffff7167310 "*** Error in `%s': %s: 0x%s ***\n")
>     at ../sysdeps/posix/libc_fatal.c:175
> #3  0x00007ffff706182e in malloc_printerr (ptr=<optimized out>, 
>     str=0x7ffff716345e "free(): invalid pointer", action=1) at malloc.c:4998
> #4  _int_free (av=<optimized out>, p=<optimized out>, have_lock=0)
>     at malloc.c:3842
> #5  0x000000000040f152 in __gnu_cxx::new_allocator<int>::deallocate (
>     this=0x7fffff85cf60, __p=0x6c1f40)
>     at /usr/include/c++/4.8/ext/new_allocator.h:110
> #6  0x000000000040ef54 in std::_Vector_base<int, std::allocator<int> >::_M_deallocate (this=0x7fffff85cf60, __p=0x6c1f40, __n=32)
>     at /usr/include/c++/4.8/bits/stl_vector.h:174
> #7  0x000000000040ebc2 in std::_Vector_base<int, std::allocator<int> >::~_Vector_base (this=0x7fffff85cf60, __in_chrg=<optimized out>)
>     at /usr/include/c++/4.8/bits/stl_vector.h:160
> #8  0x000000000040e928 in std::vector<int, std::allocator<int> >::~vector (
>     this=0x7fffff85cf60, __in_chrg=<optimized out>)
>     at /usr/include/c++/4.8/bits/stl_vector.h:416
> #9  0x000000000040e3b5 in main ()

我想我的问题是这样的。我如何解释这个回溯?我只看到最后一个堆栈 #9 调用 main 函数,但它没有与之相关的其他错误。我假设的堆栈错误 #0-8 是被调用库中的故障?我可以调用 gdb 中的方法或某些选项来帮助查明错误以及它在此回溯中的来源?一般来说,我对使用 gdb 还是很陌生,所以任何建议都将不胜感激。

编辑示例代码:

for(int k = 4; k < 7; k++)
{
    if(TFNCWS[k] == 1)
    {
        TFNCWS[k] = 0;
        TIM[k] = 1;
    }
}

【问题讨论】:

  • 在运行valgrind 时使用了哪些选项?就我个人而言,在尝试从 gdb 中获取任何有用信息之前,我会朝这个方向进行更多探索。
  • gdb 回溯准确地告诉您程序崩溃时堆栈上的函数调用。它告诉你,错误发生在std::vector&lt;int&gt; 的 dtor 中。看来您获得了双重释放,其中第二个释放发生在释放std::vector 下的缓冲区时。您可能对二维数组的使用无效,或者存在一些内存损坏问题,其中一个数组覆盖了另一个数组,这是我的猜测。回溯无法为您提供比这更多的信息。 #0-2 是断言失败例程的一部分。 #3-4 是 malloc。 #5-8 是标准库。
  • 当你说双重释放时,你的意思是,分配的内存空间释放一次然后尝试再次释放,本质上是尝试释放 NULL?
  • 我在 Valgrind 中使用的选项是 --tool-memcheck --leak-check --show-reachable --num-callers=20 --track-fds 从我读到的几个地点应该涵盖了 Valgrid 可以寻找的大部分内容。

标签: c++ debugging gdb backtrace


【解决方案1】:

我如何解释这个回溯?

非常简单:您的程序在破坏向量时崩溃,该向量在您的 main 函数中的某处声明。

最可能的原因是堆栈损坏。

我运行 Valgrind mems 检查是否有任何内存泄漏

内存泄漏与您的问题无关,而且 Valgrind 在检测堆栈溢出方面非常弱。

您应该尝试Address Sanitizer(在最近的 GCC 和 Clang 中可用)。很有可能它会直接指出问题所在。

【讨论】:

  • 这可能超出了这个问题的范围,但是上面的示例代码编辑是否会导致破坏向量的问题,本质上是将值写入循环内的向量内存地址,该循环取决于是真的吗?
  • @pfe 您显示的代码没有任何问题(假设两个数组(或向量)至少有 7 个元素)。无论如何,猜测是没有意义的。要么你需要使用工具(比如Address Sanitizer),要么你需要提供stackoverflow.com/help/mcve
  • 还不错,谢谢你的推荐。我将尝试使用 Address Sanitizer 作为我通过 clang 的下一步。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-11
  • 1970-01-01
  • 2011-07-28
  • 1970-01-01
  • 1970-01-01
  • 2014-01-01
相关资源
最近更新 更多