when g++ static link pthread, cause Segmentation fault, why? - c++

#include <iostream>
#include <map>
#include <thread>
#define SIZE 1024
#define AMOUNT 100000
#define THREADS 4
class A
{
private:
char a[SIZE];
};
void test()
{
std::cout << "test start\n";
std::map<int, A*> container;
for(int i=0; i<AMOUNT; i++)
{
A* a = new A();
std::pair<int, A*>p = std::make_pair(i, a);
container.insert(p);
}
std::cout << "test release\n";
for(int i=0; i<AMOUNT; i++)
{
auto iter = container.find(i);
delete iter->second;
container.erase(iter);
}
std::cout << "test end\n";
}
int main()
{
std::thread ts[THREADS];
for(int i=0; i<THREADS; i++)
{
ts[i] = std::thread(test);
}
for(std::thread& x: ts)
{
x.join();
}
return 0;
}
Above is a simple c++ code.
compile with: g++ -pthread -o one one.cpp -Wall -std=c++11 -O3
ldd one, gots:
linux-vdso.so.1 => (0x00007ffebafce000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fb47352a000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fb473313000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fb4730f4000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb472d2a000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb472a22000)
/lib64/ld-linux-x86-64.so.2 (0x00005654c5112000)
run ./one, every thing is ok.
Then I try a static link: g++ -pthread -o one one.cpp -Wall -std=c++11 -O3 -static
ldd one, gots:
not a dynamic executable
But when I run it, some thing goes wrong...
test start
Segmentation fault (core dumped)
re-compile with -g, and the gdb shows:
wang[00:35][~/test]$ gdb one
GNU gdb (Ubuntu 7.10-1ubuntu2) 7.10
Copyright (C) 2015 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 one...done.
(gdb) run
Starting program: /home/wang/test/one
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff7ffa700 (LWP 3623)]
test start
[New Thread 0x7ffff77f8700 (LWP 3624)]
test start
[New Thread 0x7ffff6ff7700 (LWP 3625)]
test start
[New Thread 0x7ffff67f6700 (LWP 3626)]
test start
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb)
Why this ?
UPDATE
==============================
using boost::thread library (boost version: 1.60),
replace std::thread with boost::thread , and make a static link,
g++ -pthread -o one1 one.cpp -Wall -std=c++11 -O3 -I /opt/boost/include/ -L /opt/boost/lib/ -lboost_system -lboost_thread -static
no problem occurred!
confused...

First, the solution. This here will work:
Update: Since Ubuntu 18.04, you need to link also against librt (add -lrt):
g++ -o one one.cpp -Wall -std=c++11 -O3 -static -lrt -pthread \
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
(continue with original answer)
g++ -o one one.cpp -Wall -std=c++11 -O3 -static -pthread \
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
When you use -pthread, the compiler will already link against pthread (and depending on the platform, it does define extra macros like -D_REENTRANT, see this question for more details).
So if -pthread implies -lpthread, why do you need you specify -lpthread when you are linking statically? And what does Wl,--whole-archive do?
Understanding weak symbols
On Unix, the ELF file format is used, which has the concept of weak and strong symbols. To quote from the Wikipedia page:
By default, without any annotation, a symbol in an object file is strong. During linking, a strong symbol can override a weak symbol of the same name. In contrast, two strong symbols that share a name yield a link error during link-time.
There is a subtle difference when it comes to dynamic and static libraries. In static libraries, the linker will stop at the first symbol, even if it is a weak one, and stops looking for strong ones. To force it to look at all symbols (like it would have done for a dynamically linked library), ld supports the --whole-archive option.
To quote from man ld:
--whole-archive:
For each archive mentioned on the command line after the --whole-archive option, include every object file in the archive in the
link, rather than searching the archive for the required object files. This is normally used to turn an archive file into a
shared library, forcing every object to be included in the resulting shared library. This option may be used more than once.
It goes on by explaining that from gcc, you have to pass the option as -Wl,--whole-archive:
Two notes when using this option from gcc: First, gcc doesn't know about this option, so you have to use -Wl,-whole-archive.
Second, don't forget to use -Wl,-no-whole-archive after your list of archives, because gcc will add its own list of archives to
your link and you may not want this flag to affect those as well.
And it explains how to turn it off, again:
--no-whole-archive:
Turn off the effect of the --whole-archive option for subsequent archive files.
Weak symbols in pthread and libstdc++
One of the use cases of weak symbols is to be able to swap out implementations with optimized ones. Another is to use stubs, which can later to replaced if necessary.
For example, fputc (conceptionally used by printf) is required by POSIX to be thread-safe and needs to be synchronized, which is costly. In a single-threaded environment, you do not want to pay the costs. An implementation could therefore implement the synchronization functions as empty stubs, and declare the functions as weak symbols.
Later, if a multi-threading library is linked (e.g., pthread), it becomes obvious that single-thread support is not intended. When linking the multi-threading library, the linker can then replace the stubs by the real synchronization functions (defined as strong symbols and implemented by the threading-library). On the other hand, if no multi-threading library is linked, the executable will use the stubs for the synchronization function.
glibc (providing fputc) and pthreads seem to use exactly this trick. For details, refer to this question about the usage of weak symbols in glibc. The example above is taken from this answer.
nm allows you to look at it in detail, which seems consistent with the cited answer above:
$ nm /usr/lib/libc.a 2>/dev/null | grep pthread_mutex_lock
w __pthread_mutex_lock
... (repeats)
"w" stands for "weak", so the statically linked libc library contains __pthread_mutex_lock as a weak symbol. The statically linked pthread library contains it as a strong symbol:
$ nm /usr/lib/libpthread.a 2>/dev/null | grep pthread_mutex_lock
U pthread_mutex_lock
pthread_mutex_lock.o:
00000000000006a0 T __pthread_mutex_lock
00000000000006a0 T pthread_mutex_lock
0000000000000000 t __pthread_mutex_lock_full
Back to the example program
By looking at the shared library dependencies of the dynamically linked executable, I get almost the same output of ldd on my machine:
$ ldd one
linux-vdso.so.1 (0x00007fff79d6d000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007fcaaeeb3000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007fcaaeb9b000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007fcaae983000)
libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007fcaae763000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fcaae3bb000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcaaf23b000)
Printing out the library calls with ltrace, leads to the following output:
$ ltrace -C ./one
std::ios_base::Init::Init()(0x563ab8df71b1, 0x7ffdc483cae8, 0x7ffdc483caf8, 160) = 0
__cxa_atexit(0x7fab3023bc20, 0x563ab8df71b1, 0x563ab8df7090, 6) = 0
operator new(unsigned long)(16, 0x7ffdc483cae8, 0x7ffdc483caf8, 192) = 0x563ab918bc20
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80) = 0
operator new(unsigned long)(16, 0x7fab2f6a1fb0, 0, 0x800000) = 0x563ab918bd70
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80) = 0
operator new(unsigned long)(16, 0x7fab2eea0fb0, 0, 0x800000) = 0x563ab918bec0
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80test start
) = 0
operator new(unsigned long)(16, 0x7fab2e69ffb0, 0, 0x800000) = 0x563ab918c010
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80test start
test start
) = 0
std::thread::join()(0x7ffdc483c9a0, 0x7fab2de9efb0, 0, 0x800000test start
test release
test release
test release
test release
test end
test end
test end
test end
) = 0
std::thread::join()(0x7ffdc483c9a8, 0x7fab2eea19c0, 0x7fab2f6a2700, 0) = 0
std::thread::join()(0x7ffdc483c9b0, 0x7fab2e6a09c0, 0x7fab2eea1700, 0) = 0
std::thread::join()(0x7ffdc483c9b8, 0x7fab2de9f9c0, 0x7fab2e6a0700, 0) = 0
+++ exited (status 0) +++
As an example, std::thread::join is called, which will most likely use pthread_join internally. That symbol can be found in the (dynamically linked) libraries listed in the ldd ouput, namely in libstdc++.so.6 and libpthread.so.0:
$ nm /usr/lib/libstdc++.so.6 | grep pthread_join
w pthread_join
$ nm /usr/lib/libpthread.so.0 | grep pthread_join
0000000000008280 T pthread_join
In the dynamically linked executable, the linker will replace weak symbols by strong symbols. In this example, we have to enforce the same semantic for the statically linked libraries. That is why -Wl,--whole-archive -lpthread -Wl,--no-whole-archive is needed.
Finding it out is a bit trial-and-error. At least, I found no clear documentation on that subject. I assume it is because static linking on Linux has become rather an edge case, whereas dynamic linking is often the canonical approach on how to use the libraries (for a comparison, see Static linking vs dynamic linking). The most extreme example that I have seen and personally struggled with a while to get it working is to link TBB statically.
Appendix: Workaround for Autotools
If you are using autotools as a build system, you need a workaround, as automake does not let you set options in the in LDADD. Unfortunately, you cannot write:
(Makefile.am)
mytarget_LDADD = -Wl,--whole-archive -lpthread -Wl,--no-whole-archive
As a workaround, you can avoid the check by defining the flags in configure.ac, and using them like this:
(configure.ac)
WL_WHOLE_ARCHIVE_HACK="-Wl,--whole-archive"
WL_NO_WHOLE_ARCHIVE_HACK="-Wl,--no-whole-archive"
AC_SUBST(WL_WHOLE_ARCHIVE_HACK)
AC_SUBST(WL_NO_WHOLE_ARCHIVE_HACK)
(Makefile.am)
mytarget_LDADD = #WL_WHOLE_ARCHIVE_HACK# -lpthread #WL_NO_WHOLE_ARCHIVE_HACK#

I had similar issue when linking a pre-built C++ .a archive that uses pthread. In my case I needed in addition to -Wl,--whole-archive -lpthread -Wl,--no-whole-archive also do -Wl,-u,... for each weak symbol.
My symptom was crashes at runtime and when using gdb to disassemble I could see that the crash was just after a callq 0x0 which seemed suspicious. Did some seaching and found that others had seen this with static pthread linking.
I figured out which symbols to force resolve by using nm and look for w symbols. After linking I could then see that the callq 0x0 instructions had been updated with various symbol addresses to pthread_mutex_lock etc.

Related

std::thread.join() crashes with trivial malloc wrap via ld --wrap=malloc [duplicate]

#include <iostream>
#include <map>
#include <thread>
#define SIZE 1024
#define AMOUNT 100000
#define THREADS 4
class A
{
private:
char a[SIZE];
};
void test()
{
std::cout << "test start\n";
std::map<int, A*> container;
for(int i=0; i<AMOUNT; i++)
{
A* a = new A();
std::pair<int, A*>p = std::make_pair(i, a);
container.insert(p);
}
std::cout << "test release\n";
for(int i=0; i<AMOUNT; i++)
{
auto iter = container.find(i);
delete iter->second;
container.erase(iter);
}
std::cout << "test end\n";
}
int main()
{
std::thread ts[THREADS];
for(int i=0; i<THREADS; i++)
{
ts[i] = std::thread(test);
}
for(std::thread& x: ts)
{
x.join();
}
return 0;
}
Above is a simple c++ code.
compile with: g++ -pthread -o one one.cpp -Wall -std=c++11 -O3
ldd one, gots:
linux-vdso.so.1 => (0x00007ffebafce000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fb47352a000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fb473313000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fb4730f4000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb472d2a000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb472a22000)
/lib64/ld-linux-x86-64.so.2 (0x00005654c5112000)
run ./one, every thing is ok.
Then I try a static link: g++ -pthread -o one one.cpp -Wall -std=c++11 -O3 -static
ldd one, gots:
not a dynamic executable
But when I run it, some thing goes wrong...
test start
Segmentation fault (core dumped)
re-compile with -g, and the gdb shows:
wang[00:35][~/test]$ gdb one
GNU gdb (Ubuntu 7.10-1ubuntu2) 7.10
Copyright (C) 2015 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 one...done.
(gdb) run
Starting program: /home/wang/test/one
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff7ffa700 (LWP 3623)]
test start
[New Thread 0x7ffff77f8700 (LWP 3624)]
test start
[New Thread 0x7ffff6ff7700 (LWP 3625)]
test start
[New Thread 0x7ffff67f6700 (LWP 3626)]
test start
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb)
Why this ?
UPDATE
==============================
using boost::thread library (boost version: 1.60),
replace std::thread with boost::thread , and make a static link,
g++ -pthread -o one1 one.cpp -Wall -std=c++11 -O3 -I /opt/boost/include/ -L /opt/boost/lib/ -lboost_system -lboost_thread -static
no problem occurred!
confused...
First, the solution. This here will work:
Update: Since Ubuntu 18.04, you need to link also against librt (add -lrt):
g++ -o one one.cpp -Wall -std=c++11 -O3 -static -lrt -pthread \
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
(continue with original answer)
g++ -o one one.cpp -Wall -std=c++11 -O3 -static -pthread \
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
When you use -pthread, the compiler will already link against pthread (and depending on the platform, it does define extra macros like -D_REENTRANT, see this question for more details).
So if -pthread implies -lpthread, why do you need you specify -lpthread when you are linking statically? And what does Wl,--whole-archive do?
Understanding weak symbols
On Unix, the ELF file format is used, which has the concept of weak and strong symbols. To quote from the Wikipedia page:
By default, without any annotation, a symbol in an object file is strong. During linking, a strong symbol can override a weak symbol of the same name. In contrast, two strong symbols that share a name yield a link error during link-time.
There is a subtle difference when it comes to dynamic and static libraries. In static libraries, the linker will stop at the first symbol, even if it is a weak one, and stops looking for strong ones. To force it to look at all symbols (like it would have done for a dynamically linked library), ld supports the --whole-archive option.
To quote from man ld:
--whole-archive:
For each archive mentioned on the command line after the --whole-archive option, include every object file in the archive in the
link, rather than searching the archive for the required object files. This is normally used to turn an archive file into a
shared library, forcing every object to be included in the resulting shared library. This option may be used more than once.
It goes on by explaining that from gcc, you have to pass the option as -Wl,--whole-archive:
Two notes when using this option from gcc: First, gcc doesn't know about this option, so you have to use -Wl,-whole-archive.
Second, don't forget to use -Wl,-no-whole-archive after your list of archives, because gcc will add its own list of archives to
your link and you may not want this flag to affect those as well.
And it explains how to turn it off, again:
--no-whole-archive:
Turn off the effect of the --whole-archive option for subsequent archive files.
Weak symbols in pthread and libstdc++
One of the use cases of weak symbols is to be able to swap out implementations with optimized ones. Another is to use stubs, which can later to replaced if necessary.
For example, fputc (conceptionally used by printf) is required by POSIX to be thread-safe and needs to be synchronized, which is costly. In a single-threaded environment, you do not want to pay the costs. An implementation could therefore implement the synchronization functions as empty stubs, and declare the functions as weak symbols.
Later, if a multi-threading library is linked (e.g., pthread), it becomes obvious that single-thread support is not intended. When linking the multi-threading library, the linker can then replace the stubs by the real synchronization functions (defined as strong symbols and implemented by the threading-library). On the other hand, if no multi-threading library is linked, the executable will use the stubs for the synchronization function.
glibc (providing fputc) and pthreads seem to use exactly this trick. For details, refer to this question about the usage of weak symbols in glibc. The example above is taken from this answer.
nm allows you to look at it in detail, which seems consistent with the cited answer above:
$ nm /usr/lib/libc.a 2>/dev/null | grep pthread_mutex_lock
w __pthread_mutex_lock
... (repeats)
"w" stands for "weak", so the statically linked libc library contains __pthread_mutex_lock as a weak symbol. The statically linked pthread library contains it as a strong symbol:
$ nm /usr/lib/libpthread.a 2>/dev/null | grep pthread_mutex_lock
U pthread_mutex_lock
pthread_mutex_lock.o:
00000000000006a0 T __pthread_mutex_lock
00000000000006a0 T pthread_mutex_lock
0000000000000000 t __pthread_mutex_lock_full
Back to the example program
By looking at the shared library dependencies of the dynamically linked executable, I get almost the same output of ldd on my machine:
$ ldd one
linux-vdso.so.1 (0x00007fff79d6d000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007fcaaeeb3000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007fcaaeb9b000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007fcaae983000)
libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007fcaae763000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fcaae3bb000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcaaf23b000)
Printing out the library calls with ltrace, leads to the following output:
$ ltrace -C ./one
std::ios_base::Init::Init()(0x563ab8df71b1, 0x7ffdc483cae8, 0x7ffdc483caf8, 160) = 0
__cxa_atexit(0x7fab3023bc20, 0x563ab8df71b1, 0x563ab8df7090, 6) = 0
operator new(unsigned long)(16, 0x7ffdc483cae8, 0x7ffdc483caf8, 192) = 0x563ab918bc20
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80) = 0
operator new(unsigned long)(16, 0x7fab2f6a1fb0, 0, 0x800000) = 0x563ab918bd70
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80) = 0
operator new(unsigned long)(16, 0x7fab2eea0fb0, 0, 0x800000) = 0x563ab918bec0
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80test start
) = 0
operator new(unsigned long)(16, 0x7fab2e69ffb0, 0, 0x800000) = 0x563ab918c010
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80test start
test start
) = 0
std::thread::join()(0x7ffdc483c9a0, 0x7fab2de9efb0, 0, 0x800000test start
test release
test release
test release
test release
test end
test end
test end
test end
) = 0
std::thread::join()(0x7ffdc483c9a8, 0x7fab2eea19c0, 0x7fab2f6a2700, 0) = 0
std::thread::join()(0x7ffdc483c9b0, 0x7fab2e6a09c0, 0x7fab2eea1700, 0) = 0
std::thread::join()(0x7ffdc483c9b8, 0x7fab2de9f9c0, 0x7fab2e6a0700, 0) = 0
+++ exited (status 0) +++
As an example, std::thread::join is called, which will most likely use pthread_join internally. That symbol can be found in the (dynamically linked) libraries listed in the ldd ouput, namely in libstdc++.so.6 and libpthread.so.0:
$ nm /usr/lib/libstdc++.so.6 | grep pthread_join
w pthread_join
$ nm /usr/lib/libpthread.so.0 | grep pthread_join
0000000000008280 T pthread_join
In the dynamically linked executable, the linker will replace weak symbols by strong symbols. In this example, we have to enforce the same semantic for the statically linked libraries. That is why -Wl,--whole-archive -lpthread -Wl,--no-whole-archive is needed.
Finding it out is a bit trial-and-error. At least, I found no clear documentation on that subject. I assume it is because static linking on Linux has become rather an edge case, whereas dynamic linking is often the canonical approach on how to use the libraries (for a comparison, see Static linking vs dynamic linking). The most extreme example that I have seen and personally struggled with a while to get it working is to link TBB statically.
Appendix: Workaround for Autotools
If you are using autotools as a build system, you need a workaround, as automake does not let you set options in the in LDADD. Unfortunately, you cannot write:
(Makefile.am)
mytarget_LDADD = -Wl,--whole-archive -lpthread -Wl,--no-whole-archive
As a workaround, you can avoid the check by defining the flags in configure.ac, and using them like this:
(configure.ac)
WL_WHOLE_ARCHIVE_HACK="-Wl,--whole-archive"
WL_NO_WHOLE_ARCHIVE_HACK="-Wl,--no-whole-archive"
AC_SUBST(WL_WHOLE_ARCHIVE_HACK)
AC_SUBST(WL_NO_WHOLE_ARCHIVE_HACK)
(Makefile.am)
mytarget_LDADD = #WL_WHOLE_ARCHIVE_HACK# -lpthread #WL_NO_WHOLE_ARCHIVE_HACK#
I had similar issue when linking a pre-built C++ .a archive that uses pthread. In my case I needed in addition to -Wl,--whole-archive -lpthread -Wl,--no-whole-archive also do -Wl,-u,... for each weak symbol.
My symptom was crashes at runtime and when using gdb to disassemble I could see that the crash was just after a callq 0x0 which seemed suspicious. Did some seaching and found that others had seen this with static pthread linking.
I figured out which symbols to force resolve by using nm and look for w symbols. After linking I could then see that the callq 0x0 instructions had been updated with various symbol addresses to pthread_mutex_lock etc.

Segmentation Fault while using Static Linking using C++ Threads [duplicate]

#include <iostream>
#include <map>
#include <thread>
#define SIZE 1024
#define AMOUNT 100000
#define THREADS 4
class A
{
private:
char a[SIZE];
};
void test()
{
std::cout << "test start\n";
std::map<int, A*> container;
for(int i=0; i<AMOUNT; i++)
{
A* a = new A();
std::pair<int, A*>p = std::make_pair(i, a);
container.insert(p);
}
std::cout << "test release\n";
for(int i=0; i<AMOUNT; i++)
{
auto iter = container.find(i);
delete iter->second;
container.erase(iter);
}
std::cout << "test end\n";
}
int main()
{
std::thread ts[THREADS];
for(int i=0; i<THREADS; i++)
{
ts[i] = std::thread(test);
}
for(std::thread& x: ts)
{
x.join();
}
return 0;
}
Above is a simple c++ code.
compile with: g++ -pthread -o one one.cpp -Wall -std=c++11 -O3
ldd one, gots:
linux-vdso.so.1 => (0x00007ffebafce000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fb47352a000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fb473313000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fb4730f4000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb472d2a000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb472a22000)
/lib64/ld-linux-x86-64.so.2 (0x00005654c5112000)
run ./one, every thing is ok.
Then I try a static link: g++ -pthread -o one one.cpp -Wall -std=c++11 -O3 -static
ldd one, gots:
not a dynamic executable
But when I run it, some thing goes wrong...
test start
Segmentation fault (core dumped)
re-compile with -g, and the gdb shows:
wang[00:35][~/test]$ gdb one
GNU gdb (Ubuntu 7.10-1ubuntu2) 7.10
Copyright (C) 2015 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 one...done.
(gdb) run
Starting program: /home/wang/test/one
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff7ffa700 (LWP 3623)]
test start
[New Thread 0x7ffff77f8700 (LWP 3624)]
test start
[New Thread 0x7ffff6ff7700 (LWP 3625)]
test start
[New Thread 0x7ffff67f6700 (LWP 3626)]
test start
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb)
Why this ?
UPDATE
==============================
using boost::thread library (boost version: 1.60),
replace std::thread with boost::thread , and make a static link,
g++ -pthread -o one1 one.cpp -Wall -std=c++11 -O3 -I /opt/boost/include/ -L /opt/boost/lib/ -lboost_system -lboost_thread -static
no problem occurred!
confused...
First, the solution. This here will work:
Update: Since Ubuntu 18.04, you need to link also against librt (add -lrt):
g++ -o one one.cpp -Wall -std=c++11 -O3 -static -lrt -pthread \
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
(continue with original answer)
g++ -o one one.cpp -Wall -std=c++11 -O3 -static -pthread \
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
When you use -pthread, the compiler will already link against pthread (and depending on the platform, it does define extra macros like -D_REENTRANT, see this question for more details).
So if -pthread implies -lpthread, why do you need you specify -lpthread when you are linking statically? And what does Wl,--whole-archive do?
Understanding weak symbols
On Unix, the ELF file format is used, which has the concept of weak and strong symbols. To quote from the Wikipedia page:
By default, without any annotation, a symbol in an object file is strong. During linking, a strong symbol can override a weak symbol of the same name. In contrast, two strong symbols that share a name yield a link error during link-time.
There is a subtle difference when it comes to dynamic and static libraries. In static libraries, the linker will stop at the first symbol, even if it is a weak one, and stops looking for strong ones. To force it to look at all symbols (like it would have done for a dynamically linked library), ld supports the --whole-archive option.
To quote from man ld:
--whole-archive:
For each archive mentioned on the command line after the --whole-archive option, include every object file in the archive in the
link, rather than searching the archive for the required object files. This is normally used to turn an archive file into a
shared library, forcing every object to be included in the resulting shared library. This option may be used more than once.
It goes on by explaining that from gcc, you have to pass the option as -Wl,--whole-archive:
Two notes when using this option from gcc: First, gcc doesn't know about this option, so you have to use -Wl,-whole-archive.
Second, don't forget to use -Wl,-no-whole-archive after your list of archives, because gcc will add its own list of archives to
your link and you may not want this flag to affect those as well.
And it explains how to turn it off, again:
--no-whole-archive:
Turn off the effect of the --whole-archive option for subsequent archive files.
Weak symbols in pthread and libstdc++
One of the use cases of weak symbols is to be able to swap out implementations with optimized ones. Another is to use stubs, which can later to replaced if necessary.
For example, fputc (conceptionally used by printf) is required by POSIX to be thread-safe and needs to be synchronized, which is costly. In a single-threaded environment, you do not want to pay the costs. An implementation could therefore implement the synchronization functions as empty stubs, and declare the functions as weak symbols.
Later, if a multi-threading library is linked (e.g., pthread), it becomes obvious that single-thread support is not intended. When linking the multi-threading library, the linker can then replace the stubs by the real synchronization functions (defined as strong symbols and implemented by the threading-library). On the other hand, if no multi-threading library is linked, the executable will use the stubs for the synchronization function.
glibc (providing fputc) and pthreads seem to use exactly this trick. For details, refer to this question about the usage of weak symbols in glibc. The example above is taken from this answer.
nm allows you to look at it in detail, which seems consistent with the cited answer above:
$ nm /usr/lib/libc.a 2>/dev/null | grep pthread_mutex_lock
w __pthread_mutex_lock
... (repeats)
"w" stands for "weak", so the statically linked libc library contains __pthread_mutex_lock as a weak symbol. The statically linked pthread library contains it as a strong symbol:
$ nm /usr/lib/libpthread.a 2>/dev/null | grep pthread_mutex_lock
U pthread_mutex_lock
pthread_mutex_lock.o:
00000000000006a0 T __pthread_mutex_lock
00000000000006a0 T pthread_mutex_lock
0000000000000000 t __pthread_mutex_lock_full
Back to the example program
By looking at the shared library dependencies of the dynamically linked executable, I get almost the same output of ldd on my machine:
$ ldd one
linux-vdso.so.1 (0x00007fff79d6d000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007fcaaeeb3000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007fcaaeb9b000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007fcaae983000)
libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007fcaae763000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fcaae3bb000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcaaf23b000)
Printing out the library calls with ltrace, leads to the following output:
$ ltrace -C ./one
std::ios_base::Init::Init()(0x563ab8df71b1, 0x7ffdc483cae8, 0x7ffdc483caf8, 160) = 0
__cxa_atexit(0x7fab3023bc20, 0x563ab8df71b1, 0x563ab8df7090, 6) = 0
operator new(unsigned long)(16, 0x7ffdc483cae8, 0x7ffdc483caf8, 192) = 0x563ab918bc20
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80) = 0
operator new(unsigned long)(16, 0x7fab2f6a1fb0, 0, 0x800000) = 0x563ab918bd70
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80) = 0
operator new(unsigned long)(16, 0x7fab2eea0fb0, 0, 0x800000) = 0x563ab918bec0
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80test start
) = 0
operator new(unsigned long)(16, 0x7fab2e69ffb0, 0, 0x800000) = 0x563ab918c010
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80test start
test start
) = 0
std::thread::join()(0x7ffdc483c9a0, 0x7fab2de9efb0, 0, 0x800000test start
test release
test release
test release
test release
test end
test end
test end
test end
) = 0
std::thread::join()(0x7ffdc483c9a8, 0x7fab2eea19c0, 0x7fab2f6a2700, 0) = 0
std::thread::join()(0x7ffdc483c9b0, 0x7fab2e6a09c0, 0x7fab2eea1700, 0) = 0
std::thread::join()(0x7ffdc483c9b8, 0x7fab2de9f9c0, 0x7fab2e6a0700, 0) = 0
+++ exited (status 0) +++
As an example, std::thread::join is called, which will most likely use pthread_join internally. That symbol can be found in the (dynamically linked) libraries listed in the ldd ouput, namely in libstdc++.so.6 and libpthread.so.0:
$ nm /usr/lib/libstdc++.so.6 | grep pthread_join
w pthread_join
$ nm /usr/lib/libpthread.so.0 | grep pthread_join
0000000000008280 T pthread_join
In the dynamically linked executable, the linker will replace weak symbols by strong symbols. In this example, we have to enforce the same semantic for the statically linked libraries. That is why -Wl,--whole-archive -lpthread -Wl,--no-whole-archive is needed.
Finding it out is a bit trial-and-error. At least, I found no clear documentation on that subject. I assume it is because static linking on Linux has become rather an edge case, whereas dynamic linking is often the canonical approach on how to use the libraries (for a comparison, see Static linking vs dynamic linking). The most extreme example that I have seen and personally struggled with a while to get it working is to link TBB statically.
Appendix: Workaround for Autotools
If you are using autotools as a build system, you need a workaround, as automake does not let you set options in the in LDADD. Unfortunately, you cannot write:
(Makefile.am)
mytarget_LDADD = -Wl,--whole-archive -lpthread -Wl,--no-whole-archive
As a workaround, you can avoid the check by defining the flags in configure.ac, and using them like this:
(configure.ac)
WL_WHOLE_ARCHIVE_HACK="-Wl,--whole-archive"
WL_NO_WHOLE_ARCHIVE_HACK="-Wl,--no-whole-archive"
AC_SUBST(WL_WHOLE_ARCHIVE_HACK)
AC_SUBST(WL_NO_WHOLE_ARCHIVE_HACK)
(Makefile.am)
mytarget_LDADD = #WL_WHOLE_ARCHIVE_HACK# -lpthread #WL_NO_WHOLE_ARCHIVE_HACK#
I had similar issue when linking a pre-built C++ .a archive that uses pthread. In my case I needed in addition to -Wl,--whole-archive -lpthread -Wl,--no-whole-archive also do -Wl,-u,... for each weak symbol.
My symptom was crashes at runtime and when using gdb to disassemble I could see that the crash was just after a callq 0x0 which seemed suspicious. Did some seaching and found that others had seen this with static pthread linking.
I figured out which symbols to force resolve by using nm and look for w symbols. After linking I could then see that the callq 0x0 instructions had been updated with various symbol addresses to pthread_mutex_lock etc.

c++ using condition_variable as class member for a class that spawns threads [duplicate]

#include <iostream>
#include <map>
#include <thread>
#define SIZE 1024
#define AMOUNT 100000
#define THREADS 4
class A
{
private:
char a[SIZE];
};
void test()
{
std::cout << "test start\n";
std::map<int, A*> container;
for(int i=0; i<AMOUNT; i++)
{
A* a = new A();
std::pair<int, A*>p = std::make_pair(i, a);
container.insert(p);
}
std::cout << "test release\n";
for(int i=0; i<AMOUNT; i++)
{
auto iter = container.find(i);
delete iter->second;
container.erase(iter);
}
std::cout << "test end\n";
}
int main()
{
std::thread ts[THREADS];
for(int i=0; i<THREADS; i++)
{
ts[i] = std::thread(test);
}
for(std::thread& x: ts)
{
x.join();
}
return 0;
}
Above is a simple c++ code.
compile with: g++ -pthread -o one one.cpp -Wall -std=c++11 -O3
ldd one, gots:
linux-vdso.so.1 => (0x00007ffebafce000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fb47352a000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fb473313000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fb4730f4000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb472d2a000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb472a22000)
/lib64/ld-linux-x86-64.so.2 (0x00005654c5112000)
run ./one, every thing is ok.
Then I try a static link: g++ -pthread -o one one.cpp -Wall -std=c++11 -O3 -static
ldd one, gots:
not a dynamic executable
But when I run it, some thing goes wrong...
test start
Segmentation fault (core dumped)
re-compile with -g, and the gdb shows:
wang[00:35][~/test]$ gdb one
GNU gdb (Ubuntu 7.10-1ubuntu2) 7.10
Copyright (C) 2015 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 one...done.
(gdb) run
Starting program: /home/wang/test/one
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff7ffa700 (LWP 3623)]
test start
[New Thread 0x7ffff77f8700 (LWP 3624)]
test start
[New Thread 0x7ffff6ff7700 (LWP 3625)]
test start
[New Thread 0x7ffff67f6700 (LWP 3626)]
test start
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb)
Why this ?
UPDATE
==============================
using boost::thread library (boost version: 1.60),
replace std::thread with boost::thread , and make a static link,
g++ -pthread -o one1 one.cpp -Wall -std=c++11 -O3 -I /opt/boost/include/ -L /opt/boost/lib/ -lboost_system -lboost_thread -static
no problem occurred!
confused...
First, the solution. This here will work:
Update: Since Ubuntu 18.04, you need to link also against librt (add -lrt):
g++ -o one one.cpp -Wall -std=c++11 -O3 -static -lrt -pthread \
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
(continue with original answer)
g++ -o one one.cpp -Wall -std=c++11 -O3 -static -pthread \
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
When you use -pthread, the compiler will already link against pthread (and depending on the platform, it does define extra macros like -D_REENTRANT, see this question for more details).
So if -pthread implies -lpthread, why do you need you specify -lpthread when you are linking statically? And what does Wl,--whole-archive do?
Understanding weak symbols
On Unix, the ELF file format is used, which has the concept of weak and strong symbols. To quote from the Wikipedia page:
By default, without any annotation, a symbol in an object file is strong. During linking, a strong symbol can override a weak symbol of the same name. In contrast, two strong symbols that share a name yield a link error during link-time.
There is a subtle difference when it comes to dynamic and static libraries. In static libraries, the linker will stop at the first symbol, even if it is a weak one, and stops looking for strong ones. To force it to look at all symbols (like it would have done for a dynamically linked library), ld supports the --whole-archive option.
To quote from man ld:
--whole-archive:
For each archive mentioned on the command line after the --whole-archive option, include every object file in the archive in the
link, rather than searching the archive for the required object files. This is normally used to turn an archive file into a
shared library, forcing every object to be included in the resulting shared library. This option may be used more than once.
It goes on by explaining that from gcc, you have to pass the option as -Wl,--whole-archive:
Two notes when using this option from gcc: First, gcc doesn't know about this option, so you have to use -Wl,-whole-archive.
Second, don't forget to use -Wl,-no-whole-archive after your list of archives, because gcc will add its own list of archives to
your link and you may not want this flag to affect those as well.
And it explains how to turn it off, again:
--no-whole-archive:
Turn off the effect of the --whole-archive option for subsequent archive files.
Weak symbols in pthread and libstdc++
One of the use cases of weak symbols is to be able to swap out implementations with optimized ones. Another is to use stubs, which can later to replaced if necessary.
For example, fputc (conceptionally used by printf) is required by POSIX to be thread-safe and needs to be synchronized, which is costly. In a single-threaded environment, you do not want to pay the costs. An implementation could therefore implement the synchronization functions as empty stubs, and declare the functions as weak symbols.
Later, if a multi-threading library is linked (e.g., pthread), it becomes obvious that single-thread support is not intended. When linking the multi-threading library, the linker can then replace the stubs by the real synchronization functions (defined as strong symbols and implemented by the threading-library). On the other hand, if no multi-threading library is linked, the executable will use the stubs for the synchronization function.
glibc (providing fputc) and pthreads seem to use exactly this trick. For details, refer to this question about the usage of weak symbols in glibc. The example above is taken from this answer.
nm allows you to look at it in detail, which seems consistent with the cited answer above:
$ nm /usr/lib/libc.a 2>/dev/null | grep pthread_mutex_lock
w __pthread_mutex_lock
... (repeats)
"w" stands for "weak", so the statically linked libc library contains __pthread_mutex_lock as a weak symbol. The statically linked pthread library contains it as a strong symbol:
$ nm /usr/lib/libpthread.a 2>/dev/null | grep pthread_mutex_lock
U pthread_mutex_lock
pthread_mutex_lock.o:
00000000000006a0 T __pthread_mutex_lock
00000000000006a0 T pthread_mutex_lock
0000000000000000 t __pthread_mutex_lock_full
Back to the example program
By looking at the shared library dependencies of the dynamically linked executable, I get almost the same output of ldd on my machine:
$ ldd one
linux-vdso.so.1 (0x00007fff79d6d000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007fcaaeeb3000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007fcaaeb9b000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007fcaae983000)
libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007fcaae763000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fcaae3bb000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcaaf23b000)
Printing out the library calls with ltrace, leads to the following output:
$ ltrace -C ./one
std::ios_base::Init::Init()(0x563ab8df71b1, 0x7ffdc483cae8, 0x7ffdc483caf8, 160) = 0
__cxa_atexit(0x7fab3023bc20, 0x563ab8df71b1, 0x563ab8df7090, 6) = 0
operator new(unsigned long)(16, 0x7ffdc483cae8, 0x7ffdc483caf8, 192) = 0x563ab918bc20
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80) = 0
operator new(unsigned long)(16, 0x7fab2f6a1fb0, 0, 0x800000) = 0x563ab918bd70
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80) = 0
operator new(unsigned long)(16, 0x7fab2eea0fb0, 0, 0x800000) = 0x563ab918bec0
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80test start
) = 0
operator new(unsigned long)(16, 0x7fab2e69ffb0, 0, 0x800000) = 0x563ab918c010
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80test start
test start
) = 0
std::thread::join()(0x7ffdc483c9a0, 0x7fab2de9efb0, 0, 0x800000test start
test release
test release
test release
test release
test end
test end
test end
test end
) = 0
std::thread::join()(0x7ffdc483c9a8, 0x7fab2eea19c0, 0x7fab2f6a2700, 0) = 0
std::thread::join()(0x7ffdc483c9b0, 0x7fab2e6a09c0, 0x7fab2eea1700, 0) = 0
std::thread::join()(0x7ffdc483c9b8, 0x7fab2de9f9c0, 0x7fab2e6a0700, 0) = 0
+++ exited (status 0) +++
As an example, std::thread::join is called, which will most likely use pthread_join internally. That symbol can be found in the (dynamically linked) libraries listed in the ldd ouput, namely in libstdc++.so.6 and libpthread.so.0:
$ nm /usr/lib/libstdc++.so.6 | grep pthread_join
w pthread_join
$ nm /usr/lib/libpthread.so.0 | grep pthread_join
0000000000008280 T pthread_join
In the dynamically linked executable, the linker will replace weak symbols by strong symbols. In this example, we have to enforce the same semantic for the statically linked libraries. That is why -Wl,--whole-archive -lpthread -Wl,--no-whole-archive is needed.
Finding it out is a bit trial-and-error. At least, I found no clear documentation on that subject. I assume it is because static linking on Linux has become rather an edge case, whereas dynamic linking is often the canonical approach on how to use the libraries (for a comparison, see Static linking vs dynamic linking). The most extreme example that I have seen and personally struggled with a while to get it working is to link TBB statically.
Appendix: Workaround for Autotools
If you are using autotools as a build system, you need a workaround, as automake does not let you set options in the in LDADD. Unfortunately, you cannot write:
(Makefile.am)
mytarget_LDADD = -Wl,--whole-archive -lpthread -Wl,--no-whole-archive
As a workaround, you can avoid the check by defining the flags in configure.ac, and using them like this:
(configure.ac)
WL_WHOLE_ARCHIVE_HACK="-Wl,--whole-archive"
WL_NO_WHOLE_ARCHIVE_HACK="-Wl,--no-whole-archive"
AC_SUBST(WL_WHOLE_ARCHIVE_HACK)
AC_SUBST(WL_NO_WHOLE_ARCHIVE_HACK)
(Makefile.am)
mytarget_LDADD = #WL_WHOLE_ARCHIVE_HACK# -lpthread #WL_NO_WHOLE_ARCHIVE_HACK#
I had similar issue when linking a pre-built C++ .a archive that uses pthread. In my case I needed in addition to -Wl,--whole-archive -lpthread -Wl,--no-whole-archive also do -Wl,-u,... for each weak symbol.
My symptom was crashes at runtime and when using gdb to disassemble I could see that the crash was just after a callq 0x0 which seemed suspicious. Did some seaching and found that others had seen this with static pthread linking.
I figured out which symbols to force resolve by using nm and look for w symbols. After linking I could then see that the callq 0x0 instructions had been updated with various symbol addresses to pthread_mutex_lock etc.

Segfault on declaring a variable of type vector<shared_ptr<int>>

Code
Here is the program that gives the segfault.
#include <iostream>
#include <vector>
#include <memory>
int main()
{
std::cout << "Hello World" << std::endl;
std::vector<std::shared_ptr<int>> y {};
std::cout << "Hello World" << std::endl;
}
Of course, there is absolutely nothing wrong in the program itself. The root cause of the segfault depends on the environment in which its built and ran.
Background
We, at Amazon, use a build system which builds and deploys the binaries (lib and bin) in an almost machine independent way. For our case, that basically means it deploys the executable (built from the above program) into $project_dir/build/bin/ and almost all its dependencies (i.e the shared libraries) into $project_dir/build/lib/. Why I used the phrase "almost" is because for shared libraries such libc.so, libm.so, ld-linux-x86-64.so.2 and possibly few others, the executable picks from the system (i.e from /lib64 ). Note that it is supposed to pick libstdc++ from $project_dir/build/lib though.
Now I run it as follows:
$ LD_LIBRARY_PATH=$project_dir/build/lib ./build/bin/run
segmentation fault
However if I run it, without setting the LD_LIBRARY_PATH. It runs fine.
Diagnostics
1. ldd
Here are ldd informations for both cases (please note that I've edited the output to mention the full version of the libraries wherever there is difference)
$ LD_LIBRARY_PATH=$project_dir/build/lib ldd ./build/bin/run
linux-vdso.so.1 => (0x00007ffce19ca000)
libstdc++.so.6 => $project_dir/build/lib/libstdc++.so.6.0.20
libgcc_s.so.1 => $project_dir/build/lib/libgcc_s.so.1
libc.so.6 => /lib64/libc.so.6
libm.so.6 => /lib64/libm.so.6
/lib64/ld-linux-x86-64.so.2 (0x0000562ec51bc000)
and without LD_LIBRARY_PATH:
$ ldd ./build/bin/run
linux-vdso.so.1 => (0x00007fffcedde000)
libstdc++.so.6 => /usr/lib64/libstdc++.so.6.0.16
libgcc_s.so.1 => /lib64/libgcc_s-4.4.6-20110824.so.1
libc.so.6 => /lib64/libc.so.6
libm.so.6 => /lib64/libm.so.6
/lib64/ld-linux-x86-64.so.2 (0x0000560caff38000)
2. gdb when it segfaults
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7dea45c in _dl_fixup () from /lib64/ld-linux-x86-64.so.2
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.209.62.al12.x86_64
(gdb) bt
#0 0x00007ffff7dea45c in _dl_fixup () from /lib64/ld-linux-x86-64.so.2
#1 0x00007ffff7df0c55 in _dl_runtime_resolve () from /lib64/ld-linux-x86-64.so.2
#2 0x00007ffff7b1dc41 in std::locale::_S_initialize() () from $project_dir/build/lib/libstdc++.so.6
#3 0x00007ffff7b1dc85 in std::locale::locale() () from $project_dir/build/lib/libstdc++.so.6
#4 0x00007ffff7b1a574 in std::ios_base::Init::Init() () from $project_dir/build/lib/libstdc++.so.6
#5 0x0000000000400fde in _GLOBAL__sub_I_main () at $project_dir/build/gcc-4.9.4/include/c++/4.9.4/iostream:74
#6 0x00000000004012ed in __libc_csu_init ()
#7 0x00007ffff7518cb0 in __libc_start_main () from /lib64/libc.so.6
#8 0x0000000000401021 in _start ()
(gdb)
3. LD_DEBUG=all
I also tried to see the linker information by enabling LD_DEBUG=all for the segfault case. I found something suspicious, as it searches for pthread_once symbol, and when it unable to find this, it gives segfault (that is my interpretation of the following output snippet BTW):
initialize program: $project_dir/build/bin/run
symbol=_ZNSt8ios_base4InitC1Ev; lookup in file=$project_dir/build/bin/run [0]
symbol=_ZNSt8ios_base4InitC1Ev; lookup in file=$project_dir/build/lib/libstdc++.so.6 [0]
binding file $project_dir/build/bin/run [0] to $project_dir/build/lib/libstdc++.so.6 [0]: normal symbol `_ZNSt8ios_base4InitC1Ev' [GLIBCXX_3.4]
symbol=_ZNSt6localeC1Ev; lookup in file=$project_dir/build/bin/run [0]
symbol=_ZNSt6localeC1Ev; lookup in file=$project_dir/build/lib/libstdc++.so.6 [0]
binding file $project_dir/build/lib/libstdc++.so.6 [0] to $project_dir/build/lib/libstdc++.so.6 [0]: normal symbol `_ZNSt6localeC1Ev' [GLIBCXX_3.4]
symbol=pthread_once; lookup in file=$project_dir/build/bin/run [0]
symbol=pthread_once; lookup in file=$project_dir/build/lib/libstdc++.so.6 [0]
symbol=pthread_once; lookup in file=$project_dir/build/lib/libgcc_s.so.1 [0]
symbol=pthread_once; lookup in file=/lib64/libc.so.6 [0]
symbol=pthread_once; lookup in file=/lib64/libm.so.6 [0]
symbol=pthread_once; lookup in file=/lib64/ld-linux-x86-64.so.2 [0]
But I dont see any pthread_once for the case when it runs successfully!
Questions
I know that its very difficult to debug like this and probably I've not given a lot of informations about the environments and all. But still, my question is: what could be the possible root-cause for this segfault? How to debug further and find that? Once I find the issue, fix would be easy.
Compiler and Platform
I'm using GCC 4.9 on RHEL5.
Experiments
E#1
If I comment the following line:
std::vector<std::shared_ptr<int>> y {};
It compiles and runs fine!
E#2
I just included the following header to my program:
#include <boost/filesystem.hpp>
and linked accordingly. Now it works without any segfault. So it seems by having a dependency on libboost_system.so.1.53.0., some requirements are met, or the problem is circumvented!
E#3
Since I saw it working when I made the executable to be linked against libboost_system.so.1.53.0, so I did the following things step by step.
Instead of using #include <boost/filesystem.hpp> in the code itself, I use the original code and ran it by preloading libboost_system.so using LD_PRELOAD as follows:
$ LD_PRELOAD=$project_dir/build/lib/libboost_system.so $project_dir/build/bin/run
and it ran successfully!
Next I did ldd on the libboost_system.so which gave a list of libs, two of which were:
/lib64/librt.so.1
/lib64/libpthread.so.0
So instead of preloading libboost_system, I preload librt and libpthread separately:
$ LD_PRELOAD=/lib64/librt.so.1 $project_dir/build/bin/run
$ LD_PRELOAD=/lib64/libpthread.so.0 $project_dir/build/bin/run
In both cases, it ran successfully.
Now my conclusion is that by loading either librt or libpthread (or both ), some requirements are met or the problem is circumvented! I still dont know the root cause of the issue, though.
Compilation and Linking Options
Since the build system is complex and there are lots of options which are there by default. So I tried to explicitly add -lpthread using CMake's set command, then it worked, as we have already seen that by preloading libpthread it works!
In order to see the build difference between these two cases (when-it-works and when-it-gives-segfault), I built it in verbose mode by passing -v to GCC, to see the compilation stages and the options it actually passes to cc1plus (compiler) and collect2 (linker).
(Note that paths has been edited for brevity, using dollar-sign and dummy paths.)
$/gcc-4.9.4/cc1plus -quiet -v -I /a/include -I /b/include -iprefix
$/gcc-4.9.4/ -MMD main.cpp.d -MF main.cpp.o.d -MT main.cpp.o
-D_GNU_SOURCE -D_REENTRANT -D __USE_XOPEN2K8 -D _LARGEFILE_SOURCE -D _FILE_OFFSET_BITS=64 -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -D NDEBUG $/lab/main.cpp -quiet -dumpbase main.cpp -msse -mfpmath=sse -march=core2 -auxbase-strip main.cpp.o -g -O3 -Wall -Wextra -std=gnu++1y -version -fdiagnostics-color=auto -ftemplate-depth=128 -fno-operator-names -o /tmp/ccxfkRyd.s
Irrespective of whether it works or not, the command-line arguments to cc1plus are exactly the same. No difference at all. That does not seem to be very helpful.
The difference, however, is at the linking time. Here is what I see, for the case when it works:
$/gcc-4.9.4/collect2 -plugin $/gcc-4.9.4/liblto_plugin.so
-plugin-opt=$/gcc-4.9.4/lto-wrapper -plugin-opt=-fresolution=/tmp/cchl8RtI.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lpthread -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --eh-frame-hdr -m elf_x86_64 -export-dynamic -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o run /usr/lib/../lib64/crt1.o
/usr/lib/../lib64/crti.o $/gcc-4.9.4/crtbegin.o -L/a/lib -L/b/lib
-L/c/lib
-lpthread --as-needed main.cpp.o -lboost_timer -lboost_wave -lboost_chrono -lboost_filesystem -lboost_graph -lboost_locale -lboost_thread -lboost_wserialization -lboost_atomic -lboost_context -lboost_date_time -lboost_iostreams -lboost_math_c99 -lboost_math_c99f -lboost_math_c99l -lboost_math_tr1 -lboost_math_tr1f -lboost_math_tr1l -lboost_mpi -lboost_prg_exec_monitor -lboost_program_options -lboost_random -lboost_regex -lboost_serialization -lboost_signals -lboost_system -lboost_unit_test_framework -lboost_exception -lboost_test_exec_monitor -lbz2 -licui18n -licuuc -licudata -lz -rpath /a/lib:/b/lib:/c/lib: -lstdc++ -lm -lgcc_s -lgcc -lpthread -lc -lgcc_s -lgcc $/gcc-4.9.4/crtend.o /usr/lib/../lib64/crtn.o
As you can see, -lpthread is mentioned twice! The first -lpthread (which is followed by --as-needed) is missing for the case when it gives segfault. That is the only difference between these two cases.
Output of nm -C in both cases
Interestingly, the output of nm -C in both cases is identical (if you ignore the integer values in the first columns).
0000000000402580 d _DYNAMIC
0000000000402798 d _GLOBAL_OFFSET_TABLE_
0000000000401000 t _GLOBAL__sub_I_main
0000000000401358 R _IO_stdin_used
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
U _Unwind_Resume
0000000000401150 W std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_destroy()
0000000000401170 W std::vector<std::shared_ptr<int>, std::allocator<std::shared_ptr<int> > >::~vector()
0000000000401170 W std::vector<std::shared_ptr<int>, std::allocator<std::shared_ptr<int> > >::~vector()
0000000000401250 W std::vector<std::unique_ptr<int, std::default_delete<int> >, std::allocator<std::unique_ptr<int, std::default_delete<int> > > >::~vector()
0000000000401250 W std::vector<std::unique_ptr<int, std::default_delete<int> >, std::allocator<std::unique_ptr<int, std::default_delete<int> > > >::~vector()
U std::ios_base::Init::Init()
U std::ios_base::Init::~Init()
0000000000402880 B std::cout
U std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)
0000000000402841 b std::__ioinit
U std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
U operator delete(void*)
U operator new(unsigned long)
0000000000401510 r __FRAME_END__
0000000000402818 d __JCR_END__
0000000000402818 d __JCR_LIST__
0000000000402820 d __TMC_END__
0000000000402820 d __TMC_LIST__
0000000000402838 A __bss_start
U __cxa_atexit
0000000000402808 D __data_start
0000000000401100 t __do_global_dtors_aux
0000000000402820 t __do_global_dtors_aux_fini_array_entry
0000000000402810 d __dso_handle
0000000000402828 t __frame_dummy_init_array_entry
w __gmon_start__
U __gxx_personality_v0
0000000000402838 t __init_array_end
0000000000402828 t __init_array_start
00000000004012b0 T __libc_csu_fini
00000000004012c0 T __libc_csu_init
U __libc_start_main
w __pthread_key_create
0000000000402838 A _edata
0000000000402990 A _end
000000000040134c T _fini
0000000000400e68 T _init
0000000000401028 T _start
0000000000401054 t call_gmon_start
0000000000402840 b completed.6661
0000000000402808 W data_start
0000000000401080 t deregister_tm_clones
0000000000401120 t frame_dummy
0000000000400f40 T main
00000000004010c0 t register_tm_clones
Given the point of crash, and the fact that preloading libpthread seems to fix it, I believe that the execution of the two cases diverges at locale_init.cc:315. Here is an extract of the code:
void
locale::_S_initialize()
{
#ifdef __GTHREADS
if (__gthread_active_p())
__gthread_once(&_S_once, _S_initialize_once);
#endif
if (!_S_classic)
_S_initialize_once();
}
__gthread_active_p() returns true if your program is linked against pthread, specifically it checks if pthread_key_create is available. On my system, this symbol is defined in "/usr/include/c++/7.2.0/x86_64-pc-linux-gnu/bits/gthr-default.h" as static inline, hence it is a potential source of ODR violation.
Notice that LD_PRELOAD=libpthread,so will always cause __gthread_active_p() to return true.
__gthread_once is another inlined symbol that should always forward to pthread_once.
It's hard to guess what's going on without debugging, but I suspect that you are hitting the true branch of __gthread_active_p() even when it shouldn't, and the program then crashes because there is no pthread_once to call.
EDIT:
So I did some experiments, the only way I see to get a crash in std::locale::_S_initialize is if __gthread_active_p returns true, but pthread_once is not linked in.
libstdc++ does not link directly against pthread, but it imports half of pthread_xx as weak objects, which means they can be undefined and not cause a linker error.
Obviously linking pthread will make the crash disappear, but if I am right, the main issue is that your libstdc++ thinks that it is inside a multi-threaded executable even if we did not link pthread in.
Now, __gthread_active_p uses __pthread_key_create to decide if we have threads or no. This is defined in your executable as a weak object (can be nullptr and still be fine). I am 99% sure that the symbol is there because of shared_ptr (remove it and check nm again to be sure).
So, somehow __pthread_key_create gets bound to a valid address, maybe because of that last -lpthread in your linker flags.
You can verify this theory by putting a breakpoint at locale_init.cc:315 and checking which branch you take.
EDIT2:
Summary of the comments, the issue is only reproducible if we have all of the following:
Use ld.gold instead of ld.bfd
Use --as-needed
Forcing a weak definition of __pthread_key_create, in this case via instantiation of std::shared_ptr.
Not linking to pthread, or linking pthread after --as-needed.
To answer the questions in the comments:
Why does it use gold by default?
By default it uses /usr/bin/ld, which on most distro is a symlink to either /usr/bin/ld.bfd or /usr/bin/ld.gold. Such default can be manipulated using update-alternatives. I am not sure why in your case it is ld.gold, as far as I understand RHEL5 ships with ld.bfd as default.
And why does gold not add pthread.so dependency to the binary if it is needed?
Because the definition of what is needed is somehow shady. man ld says (emphasis mine):
--as-needed
--no-as-needed
This option affects ELF DT_NEEDED tags for dynamic libraries mentioned on the command line after the --as-needed option.
Normally the linker will add a DT_NEEDED
tag for each dynamic library mentioned on the command line, regardless of whether the library is actually needed or not.
--as-needed causes a DT_NEEDED tag to
only be emitted for a library that at that point in the link satisfies a non-weak undefined symbol reference from a regular
object file or, if the library is not
found in the DT_NEEDED lists of other needed libraries, a non-weak undefined symbol reference from another needed dynamic
library. Object files or libraries
appearing on the command line after the library in question do not affect whether the library is seen as needed. This is similar
to the rules for extraction of
object files from archives. --no-as-needed restores the default behaviour.
Now, according to this bug report, gold is honoring the "non weak undefined symbol" part, while ld.bfd sees weak symbols as needed. TBH I do not have a full understanding on this, and there is some discussion on that link as to whether this is to be considered a ld.gold bug, or a libstdc++ bug.
Why do I need to mention -pthread and -lpthread both? (-pthread is
passed by default by our build system, and I've pass -lpthread to make
it work with gold is used).
-pthread and -lpthread do different things (see pthread vs lpthread). It is my understanding that the former should imply the latter.
Regardless, you can probably pass -lpthread only once, but you need to do it before --as-needed, or use --no-as-needed after the last library and before -lpthread.
It is also worth mentioning that I was not able to reproduce this issue on my system (GCC 7.2), even using the gold linker.
So I suspect that it has been fixed in a more recent version libstdc++, which might also explain why it does not segfault if you use the system standard library.
This is likely a problem caused by subtle mismatches between libstdc++ ABIs. GCC 4.9 is not the system compiler on Red Hat Enterprise Linux 5, so it's not quite clear what you are using there (DTS 3?).
The locale implementation is known to be quite sensitive to ABI mismatches. See this thread on the gcc-help list:
Binary compatibility between an old static libstdc++ and a new dynamic one
plus follow-ups in the next month
Your best bet is to figure out which bits of libstdc++ where linked where, and somehow achieve consistency (either by hiding symbols, or recompiling things so that they are compatible).
It may also be useful to investigate the hybrid linkage model used for libstdc++ in Red Hat's Developer Toolset (where newer bits are linked statically, but the bulk of the C++ standard library uses the existing system DSO), but the system libstdc++ in Red hat Enterprise Linux 5 might be too old for that if you need support for current language features.

C++0x thread static linking problem

I am having some issues trying to statically link programs using c++0x thread features. Code looks this: (Compiler is gcc 4.6.1 on Debian x86_64 testing)
#include <iostream>
#include <thread>
static void foo() {
std::cout << "FOO BAR\n";
}
int main() {
std::thread t(foo);
t.join();
return 0;
}
I link it with:
g++ -static -pthread -o t-static t.cpp -std=c++0x
When I execute the program, I have the following error:
terminate called after throwing an instance of 'std::system_error'
what(): Operation not permitted
Aborted
GDB Debug output looks like this:
Debugger finished
Current directory is ~/testspace/thread/
GNU gdb (GDB) 7.2-debian
Copyright (C) 2010 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".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/will/testspace/thread/t-static...done.
(gdb) list -
1 #include <iostream>
(gdb) b 1
Breakpoint 1 at 0x4007c8: file t.cpp, line 1.
(gdb) r
Starting program: /home/will/testspace/thread/t-static
terminate called after throwing an instance of 'std::system_error'
what(): Operation not permitted
Program received signal SIGABRT, Aborted.
0x00000000004a8e65 in raise ()
(gdb) bt
#0 0x00000000004a8e65 in raise ()
#1 0x000000000045df90 in abort ()
#2 0x000000000044570d in __gnu_cxx::__verbose_terminate_handler() ()
#3 0x0000000000442fb6 in __cxxabiv1::__terminate(void (*)()) ()
#4 0x0000000000442fe3 in std::terminate() ()
#5 0x0000000000443cbe in __cxa_throw ()
#6 0x0000000000401fe4 in std::__throw_system_error(int) ()
#7 0x00000000004057e7 in std::thread::_M_start_thread(std::shared_ptr<std::thread::_Impl_base>) ()
#8 0x0000000000400b18 in std::thread::thread<void (&)()> (this=0x7fffffffe540, __f=#0x4007c4) at /usr/include/c++/4.6/thread:135
#9 0x00000000004007f3 in main () at t.cpp:11
(gdb)
Update:
Linking with static libstdc++ could (possibly) make this error disappear, and the compiled C++0x programs can run on systems without gcc 4.6 libs:
g++ -static-libgcc -pthread -L.-o t thread.cpp -std=c++0x
But first, we should make a symbolic link to 'libstdc++.a' at current directory:
ln -s `g++ -print-file-name=libstdc++.a`
(Reference: http://www.trilithium.com/johan/2005/06/static-libstdc/)
you can use -u to resolve the problem (test in gcc version 4.6.3/(Ubuntu EGLIBC 2.15-0ubuntu10.4) 2.15 , gcc version 4.8.1/(Ubuntu EGLIBC 2.15-0ubuntu10.5~ppa1) 2.15)
-Wl,-u,pthread_cancel,-u,pthread_cond_broadcast,-u,pthread_cond_destroy,-u,pthread_cond_signal,-u,pthread_cond_wait,-u,pthread_create,-u,pthread_detach,-u,pthread_cond_signal,-u,pthread_equal,-u,pthread_join,-u,pthread_mutex_lock,-u,pthread_mutex_unlock,-u,pthread_once,-u,pthread_setcancelstate
1. reproduce the bug
g++ -g -O0 -static -std=c++11 t.cpp -lpthread
./a.out
terminate called after throwing an instance of 'std::system_error'
what(): Enable multithreading to use std::thread: Operation not permitted
Aborted (core dumped)
nm a.out | egrep "\bpthread_.*"
w pthread_cond_broadcast
w pthread_cond_destroy
w pthread_cond_signal
w pthread_cond_wait
w pthread_create
w pthread_detach
w pthread_equal
w pthread_join
w pthread_mutex_lock
w pthread_mutex_unlock
w pthread_once
w pthread_setcancelstate
2. resolve the bug
g++ -g -O0 -static -std=c++11 t.cpp -lpthread -Wl,-u,pthread_join,-u,pthread_equal
./a.out
FOO BAR
nm a.out | egrep "\bpthread_.*"
0000000000406320 T pthread_cancel
w pthread_cond_broadcast
w pthread_cond_destroy
w pthread_cond_signal
w pthread_cond_wait
0000000000404970 W pthread_create
w pthread_detach
00000000004033e0 T pthread_equal
00000000004061a0 T pthread_getspecific
0000000000403270 T pthread_join
0000000000406100 T pthread_key_create
0000000000406160 T pthread_key_delete
00000000004057b0 T pthread_mutex_lock
00000000004059c0 T pthread_mutex_trylock
0000000000406020 T pthread_mutex_unlock
00000000004063b0 T pthread_once
w pthread_setcancelstate
0000000000406220 T pthread_setspecific
For reasons exactly unknown to me (I consider this a bug) you can not use std::thread on gcc 4.6 when linking statically, since the function __ghtread_active_p() will be inlined as returning false (look at the assembly of _M_start_thread), causing this exception to be thrown. It might be that they require weak symbols for the pthread_create function there and when statically linking they are not there, but why they don't do it otherwise is beyond me (Note that the assembly later contains things like callq 0x0, there seems to be going something very wrong).
For now I personally use boost::threads since I am using boost anyways...
You should make sure you're linking against pthread library, otherwise you'll get the "Operation not permitted" message.
For instance, to compile your source code, I'd use this:
g++ -Wall -fexceptions -std=c++0x -g -c file.cpp -o file.o
Then linking with this:
g++ -o file file.o -lpthread
When doing it without object files, you could try something like this:
g++ -Wall -fexceptions -std=c++0x -g main.cpp -o file -lpthread
Remember to leave libraries at the end, since they'll be used on the linking process only.
My previous answer was deleted and I wrote detailed answer.
In common cases this issue happens due incomplete linking of the libpthread. I found information about this here https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52590
You can try link you app with the following flags:
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
Also you could look at this questions with the similar problem:
What is the correct link options to use std::thread in GCC under linux?
Starting a std::thread with static linking causes segmentation fault