为什么与 pthread 链接会导致分段错误?

Why does linking with pthread cause a segmentation fault?

我有一个带有静态变量的精简简单程序 ('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

但是,如果我 link 在 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 ()

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

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

> 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)
$ man gcc

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

您安装的 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,一个用于“工具链测试构建”的 PPA...

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

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

原来是GCC编译器或者libstdc++才是buggy/broken。与 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 是否会导致此段错误。

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

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

中的符号链接定义