【问题标题】:Why does linking with pthread cause a segmentation fault?为什么与 pthread 链接会导致分段错误?
【发布时间】:2015-06-29 10:30:29
【问题描述】:

我有一个带有静态变量('abc.cpp')的简单程序:

#include <iostream>

int main(int, char**)
{
  static const std::string a("123");
  std::cout << "Hello world" << std::endl;
  return 0;
}

我编译它并且它可以工作:

> g++ -ggdb abc.cpp -o abc
> ./abc
Hello world

但是,如果我在 pthread 库中链接......

> g++ -ggdb -lpthread abc.cpp -o abc
> ./abc
Segmentation fault (core dumped)

> gdb abc
(gdb) run
Starting program: abc

Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) where
#0  0x0000000000000000 in ?? ()
#1  0x00007ffff7b01681 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#2  0x00007ffff7b016c3 in std::locale::locale() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3  0x00007ffff7afe244 in std::ios_base::Init::Init() ()
   from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4  0x0000000000400d03 in __static_initialization_and_destruction_0 (__initialize_p=1,
    __priority=65535) at /usr/include/c++/4.9/iostream:74
#5  0x0000000000400d2c in _GLOBAL__sub_I_main () at abc.cpp:8
#6  0x0000000000400d7d in __libc_csu_init ()
#7  0x00007ffff74a6e55 in __libc_start_main (main=0x400c06 <main(int, char**)>, argc=1,
    argv=0x7fffffffdb58, init=0x400d30 <__libc_csu_init>, fini=<optimised out>,
    rtld_fini=<optimised out>, stack_end=0x7fffffffdb48) at libc-start.c:246
#8  0x0000000000400b39 in _start ()

我知道它在这里不使用线程,但在实际的非精简程序中,它链接到一个使用线程的库。感觉链接到 pthread 应该没问题,即使实际上没有使用线程。

有趣的是,添加消毒剂使其不会崩溃(不确定这是否是“未定义”/不稳定的修复...)。

> g++ -ggdb -fsanitize=undefined -lpthread abc.cpp -o abc
> ./abc
Hello world

为什么会导致段错误?

旁注:Clang 有效。

> clang++ -ggdb -lpthread abc.cpp -o abc
> ./abc
Hello world

版本信息:

> g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.9/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.9.2-0ubuntu1~14.04' --with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.9 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.9 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.9.2 (Ubuntu 4.9.2-0ubuntu1~14.04)

> dpkg -l 'libstdc++6*'
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                Version        Architecture   Description
+++-===================-==============-==============-===========================================
ii  libstdc++6:amd64    5-20150329-1ub amd64          GNU Standard C++ Library v3
un  libstdc++6-4.0-dbg  <none>         <none>         (no description available)
un  libstdc++6-4.1-dbg  <none>         <none>         (no description available)
un  libstdc++6-4.2-dbg  <none>         <none>         (no description available)
un  libstdc++6-4.3-dbg  <none>         <none>         (no description available)
un  libstdc++6-4.4-dbg  <none>         <none>         (no description available)
un  libstdc++6-4.5-dbg  <none>         <none>         (no description available)
un  libstdc++6-4.6-dbg  <none>         <none>         (no description available)
un  libstdc++6-4.7-dbg  <none>         <none>         (no description available)
un  libstdc++6-4.8-dbg  <none>         <none>         (no description available)
ii  libstdc++6-4.9-dbg: 4.9.2-0ubuntu1 amd64          GNU Standard C++ Library v3 (debugging file
un  libstdc++6-5-dbg    <none>         <none>         (no description available)
un  libstdc++6-dbg      <none>         <none>         (no description available)

这是用于 gcc 构建的 ldd abc

linux-vdso.so.1 => (0x00007ffef8f2f000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f87b167c000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f87b1465000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f87b109f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f87b0d99000)
/lib64/ld-linux-x86-64.so.2 (0x00007f87b1a11000)

还有用于 clang 构建的 ldd abc(注意此处的 pthread 而不是 gcc):

linux-vdso.so.1 => (0x00007fffa4cc7000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fab1f10d000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fab1ed94000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fab1ea8d000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fab1e876000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fab1e4b1000)
/lib64/ld-linux-x86-64.so.2 (0x00007fab1f347000)

对于它的价值,我的语言环境:

> locale
LANG=en_AU.UTF-8
LANGUAGE=en_AU:en
LC_CTYPE="en_AU.UTF-8"
LC_NUMERIC="en_AU.UTF-8"
LC_TIME="en_AU.UTF-8"
LC_COLLATE="en_AU.UTF-8"
LC_MONETARY="en_AU.UTF-8"
LC_MESSAGES="en_AU.UTF-8"
LC_PAPER="en_AU.UTF-8"
LC_NAME="en_AU.UTF-8"
LC_ADDRESS="en_AU.UTF-8"
LC_TELEPHONE="en_AU.UTF-8"
LC_MEASUREMENT="en_AU.UTF-8"
LC_IDENTIFICATION="en_AU.UTF-8"
LC_ALL=

设置默认语言环境会产生相同的结果(以及相同的堆栈跟踪):

> LC_ALL=C ./abc
Segmentation fault (core dumped)

【问题讨论】:

  • 所有迹象都指向 GCC 中的错误,除非另有证明。
  • 您能告诉我们您实际链接的库是什么吗?
  • @Jeff:哦!确认会很好。另外确认它在 5.0 中得到修复会很好。
  • @duskwuff:我自己做的,在这里几乎不相关。
  • 由于在libstdc++中看起来像空指针崩溃,也可以安装debug package,那么堆栈跟踪应该会提供更多信息。这只会添加外部调试信息文件,因此不会更改您的 libstdc++ 库文件。

标签: c++ linux gcc segmentation-fault pthreads


【解决方案1】:

这个问题实际上是您的系统可能默认使用的黄金链接器中的一个错误。检查 ld --version 打印的名称。 该错误似乎仍然存在: https://sourceware.org/bugzilla/show_bug.cgi?id=16417

使用标准 bfd 链接器不会显示此问题。使用的链接器由gcc -fuse-ld=gold/usr/bin/ld 中的符号链接定义

【讨论】:

  • 默认情况下它不使用黄金 - 我在使用 /usr/bin/ld 符号链接时让它使用黄金。我需要黄金用于 Clang 的 LTO。谢谢,它看起来很相似,但我不完全确定......它只是导致它的编译器/链接器的组合,而不是与不同编译器的其他组合?请记住,虽然仍然使用相同的黄金链接器,但 Clang 和 GCC 5.1 都运行良好....我也(不认为?)我正在使用 -Wl,--as-needed 标志,就像他们似乎需要的那样他们的错误。
  • 当 ld 符号链接指向默认使用的黄金时。 --as-needed 在标准 ubuntu 链接器中默认使用,它在 gcc 规范 ubuntu 中硬编码。虽然可能存在一些交互,但我还没有使用该配置测试过 5.1。
【解决方案2】:

您安装的libstdc++6 软件包甚至不在 Ubuntu 中!

ii  libstdc++6:amd64  5-20150329-1ubuntu11 amd64    GNU Standard C++ Library v3

来自packages.ubuntu.com

trusty (14.04LTS) (libs): GNU Standard C++ Library v3
    4.8.2-19ubuntu1: amd64 i386
utopic (libs): GNU Standard C++ Library v3
    4.9.1-16ubuntu6: amd64 i386
vivid (libs): GNU Standard C++ Library v3
    4.9.2-10ubuntu13: amd64 i386 

我建议检查您的/etc/apt/sources.list 并删除导致安装包的行。我想可能是ppa:ubuntu-toolchain-r/test,一个用于“Toolchain test builds”的 PPA...

然后您可以尝试 downgrade 您的 libstdc++6 软件包以恢复正常版本(适用于您安装的 Ubuntu 版本)。当您使用它时,您应该仔细检查其他软件包是否也受到影响。您不想在核心库的测试版本上运行您的系统。

顺便说一句,这也解释了为什么 gdb 没有找到调试符号,它们是用于另一个版本的库。

【讨论】:

  • 正确!我确实从launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test 获得了我的 GCC 版本。 Ubuntu 14.04 LTS (4.8) 中包含的那个对我来说太旧了。诸如this(旧,但同样的原则适用)和this 之类的页面似乎表明这是一件可以做的事情。我认为它与实际的 4.9.2 版本足够接近。我更喜欢 4.9 或 5.1,所以我什至可以在某个时候尝试 5.1...
  • 您可以使用来自 utopic 的gcc 4.9ubuntu-toolchain-r 比生动更前沿,它是一个不受支持的测试包。就个人而言,我不会开发它,因为你永远不会知道崩溃是你的错还是工具链的错。 gcc 5 的特性不值得遇到这样的问题。
  • Utopic (14.10) 不是 LTS,我需要使用 LTS 版本。啊,坚实的支撑和切削刃之间的张力。 GCC 4.9 和 5.1 是从 4.​​8 向前迈出的一大步,所以我不愿意倒退。 GCC 4.9 是一年前发布的,所以很遗憾它仍然没有在最前沿的“测试”版本中得到修复。它与官方 4.9.2 版本非常接近是有意义的。
  • 已确认:GCC 5.1(来自 ubuntu-toolchain-r/test:gcc version 5.1.0 (Ubuntu 5.1.0-0ubuntu11~14.04.1))确实修复了这个 seg 错误。那挺好的。所以那个版本的 libstdc++ 是罪魁祸首。
  • 我将其标记为解决方案,尽管我不喜欢它的语气。您能否通过说明 seg 错误是由 libstdc++ 中的错误引起的来改进它,这是一个非官方的不受支持的版本?您可以参考我的 GCC 5.1 测试作为已修复此错误的证明。然后,您可以在此之后放置如何返回官方 GCC 包的步骤。
【解决方案3】:

原来是 GCC 编译器或 libstdc++ 出现错误/损坏。与 pthread 链接不应导致段错误。

Clang 没有使用相同的 libstdc++ 的段错误,因此这表明它可能是编译器。我用gcc version 5.1.0 (Ubuntu 5.1.0-0ubuntu11~14.04.1) 进行了测试,发现它有效,因此它确认了 GCC/libstdc++ 错误。

使用的原始 GCC 4.9 来自非官方的测试编译器存储库 (https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test) - 不是官方的 Ubuntu 存储库。然而,经过测试的 GCC 5.1 也来自同一个存储库,因此至少在那里修复了错误。目前尚不清楚官方的 Ubuntu GCC 4.8 是否会导致此段错误。

【讨论】:

    【解决方案4】:
    $ man gcc
    

    是你的朋友。使用线程库不仅仅是在链接步骤中包含该库:文件也应该使用“-pthread”开关进行编译。

    【讨论】:

    • GCC 文档也是你的朋友:gcc.gnu.org/onlinedocs/gcc-4.9.2/gcc/… 搜索“-pthread”选项会在“RS/6000 和 PowerPC 选项”和“Solaris 2 选项”部分显示它。我使用的是 x86_64,所以我觉得这个选项与我的平台无关。这不正确吗?
    • 我的编译和链接是在一个命令中完成的。我确实尝试过,用“-pthread”替换“-lpthread”会导致完全相同的分段错误。
    • 至少对于 C11,该标志不再是必需的。据我所知,GCC 已经遵循 C11 内存模型大约十年了。
    • 而且,正如我所怀疑的,-pthread 编译选项对 Mac x86_64 上的 GCC 4.9.2 代码生成绝对没有任何影响,使用程序集输出进行测量。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-18
    • 2020-04-15
    • 1970-01-01
    • 2011-07-07
    • 1970-01-01
    • 2020-10-28
    • 1970-01-01
    相关资源
    最近更新 更多