gdb demangler 加载符号时出现段错误

gdb demangler segfault on loading symbols

最近,我开始在使用 GDB 调试我的产品时遇到问题。 我找到了问题的根源,但还没有解决方法。

我的代码是用 C++11 编写的,广泛使用了元编程。 为了捕获和修复可能的崩溃,它使用调试信息进行编译,用于在 SIGSEGV 处理程序上进行 demangling。

扩展项目使一些元组变得相当大。

我将问题缩小为:取消注释一个元组中的一种类型,并在加载符号时在 gdb 中捕获段错误。

谷歌搜索这似乎是一项乏味的任务。 使用 gdb 调试 gdb 也没有带来更多的洞察力。 我发现的唯一东西 - 是 similar bug,但该跟踪器声明它已修复并确认已在我的 gdb (7.7.1) 版本中修复

我使用 Ubuntu 14.04 作为开发箱,Centos7 作为生产服务器,这里是 "gdb --args gdb ":

的输出
xxx@xxx$ gdb --args gdb ./epayworker
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from gdb...(no debugging symbols found)...done.
(gdb) run
Starting program: /usr/bin/gdb ./epayworker
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./epayworker...
Program received signal SIGSEGV, Segmentation fault.
0x0000000000719da1 in cplus_demangle_print_callback ()
(gdb) bt -25
#0  0x0000000000719da1 in cplus_demangle_print_callback ()
#1  0x0000000000719fb4 in ?? ()
#2  0x000000000071a0c7 in ?? ()
#3  0x000000000071a26e in cplus_demangle_v3 ()
#4  0x000000000070c3c6 in cplus_demangle ()
#5  0x000000000068fdbb in bfd_demangle ()
#6  0x000000000055f269 in symbol_set_names ()
#7  0x00000000005cb985 in prim_record_minimal_symbol_full ()
#8  0x00000000004f82ba in ?? ()
#9  0x00000000004f8b95 in ?? ()
#10 0x000000000056a8d9 in ?? ()
#11 0x000000000056a459 in ?? ()
#12 0x000000000056a9b4 in symbol_file_add ()
#13 0x000000000056aa15 in ?? ()
#14 0x00000000005921be in catch_command_errors_const ()
#15 0x0000000000594da5 in ?? ()
#16 0x000000000059205a in catch_errors ()
#17 0x0000000000595244 in gdb_main ()
#18 0x000000000045391e in main ()
(gdb) 

现阶段我对更改生产服务器核心的编译器并不感到兴奋。错误对架构造成限制也不是最好的事情。

所以我的问题是: 我是否缺少某种类型的标志来克服 gdb 中的某些内部限制?或者这只是 gdb 中的一个错误?或者也许我不应该害怕并迁移到更新的编译器版本?

感谢您对我的困惑的任何帮助。

更新:

这似乎是一个相当不错的死局。 最近我一直在玩元组,似乎问题与某些特定符号无关,而是与某种缓冲区溢出有关。 因为来回交换类型、重命名它们、缩短名称长度并没有什么不同,但在元组中的类型数量达到一定阈值后,就会出现崩溃。

我发现的最大元组类型名长度是 ~77600 个字符(再添加一种类型 - gdb 崩溃)

旁注是 Netbeans 8.0.2 也存在错误:在调用堆栈 window 中,在名称长度较大的类型名称上,经过某个阈值后,它开始进行某种包装,并打印出不同的内容同一行顶部的相同类型名称的部分,使其完全不可读。在一些更大的阈值之后,typename 就消失了,使行变空。

我将提交错误。 但出于显而易见的原因,我无法将我的代码发布到 public。 所以我将尝试提取造成这种混乱的部分,并用它构建一个测试应用程序。 该部分是:用于构建反射的元函数,如 meta-for_each 等。

抱歉,现在截止日期很紧,所以尽快会有更多时间。

demangler 可能有点令人惊讶,它是一个复杂的软件。而且,随着 C++ 的发展,修饰方案变得更加复杂,因此分解器也变得更加复杂。有时会有错误。

一般来说这没什么大不了的。但是,为了提供良好的用户体验(部分原因是编译器 DWARF 生成的历史问题),gdb 急切地分解符号。如果一个这样的符号触发了 demangler 错误——砰!

这就是你所经历的。

去年,一个补丁使用 SEGV 捕捉器包装了对 demangler 的调用。通过这种方式,gdb 至少可以在一定程度上免受 demangler 错误的影响——它会打印出有问题的符号并尝试继续前进。

您的 gdb 可能已被修补以修复 demangler 以解决一些特定的已知错误,但可能还没有 SEGV 捕获补丁。所以我建议你升级 gdb。这应该有所帮助。

此外,我建议您在此处遵循 Gary 的错误报告说明:https://sourceware.org/bugzilla/show_bug.cgi?id=14963#c35。也就是说,如果您知道该符号,请提交 GCC 错误;否则向复制者提交 gdb 错误,然后有人会对其进行分类。

据我所知,此错误没有合理 解决方法。这就是 SEGV 捕捉器进入的原因。然而,有一个不合理的解决方法——编辑二进制文件以重命名有问题的符号以避免 demangler 崩溃。但是,实际上,构建自己的 gdb 更简单、更安全。