Linux 可执行文件通过 dlopen 在emplace_back崩溃打开共享库
Linux executable opening shared library through dlopen crashing on emplace_back
我创建了一个共享库(OSX上的"dylib",Ubuntu上的"so"(和一个加载此库的可执行文件。如果我只是将共享库链接到可执行文件(在 cmake 中link_libraries(,一切正常。
现在我不链接它,而是用dlopen/dlsym打开库。在OSX上可以正常工作,可执行文件可以顺利运行,但在Linux上,它会在特定点崩溃。这是瓦尔格林德的痕迹:
==7253== Jump to the invalid address stated on the next line
==7253== at 0x0: ???
==7253== by 0x61DB539: void __gnu_cxx::new_allocator<std::thread>::construct<std::thread, ThreadPool::ThreadPool(unsigned long)::{lambda()#1}>(std::thread*, ThreadPool::ThreadPool(unsigned long)::{lambda()#1}&&) (new_allocator.h:136)
==7253== by 0x61D7780: void std::allocator_traits<std::allocator<std::thread> >::construct<std::thread, ThreadPool::ThreadPool(unsigned long)::{lambda()#1}>(std::allocator<std::thread>&, std::thread*, ThreadPool::ThreadPool(unsigned long)::{lambda()#1}&&) (alloc_traits.h:475)
==7253== by 0x61D7840: void std::vector<std::thread, std::allocator<std::thread> >::_M_realloc_insert<ThreadPool::ThreadPool(unsigned long)::{lambda()#1}>(__gnu_cxx::__normal_iterator<std::thread*, std::vector<std::thread, std::allocator<std::thread> > >, ThreadPool::ThreadPool(unsigned long)::{lambda()#1}&&) (vector.tcc:415)
==7253== by 0x61D371D: void std::vector<std::thread, std::allocator<std::thread> >::emplace_back<ThreadPool::ThreadPool(unsigned long)::{lambda()#1}>(ThreadPool::ThreadPool(unsigned long)::{lambda()#1}&&) (vector.tcc:105)
==7253== by 0x61D19F5: ThreadPool::ThreadPool(unsigned long) (ThreadPool.h:38)
==7253== by 0x112545: main (testexecutable.cpp:216)
==7253== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==7253== Process terminating with default action of signal 11 (SIGSEGV)
==7253== Bad permissions for mapped region at address 0x0
==7253== at 0x0: ???
==7253== by 0x61DB539: void __gnu_cxx::new_allocator<std::thread>::construct<std::thread, ThreadPool::ThreadPool(unsigned long)::{lambda()#1}>(std::thread*, ThreadPool::ThreadPool(unsigned long)::{lambda()#1}&&) (new_allocator.h:136)
==7253== by 0x61D7780: void std::allocator_traits<std::allocator<std::thread> >::construct<std::thread, ThreadPool::ThreadPool(unsigned long)::{lambda()#1}>(std::allocator<std::thread>&, std::thread*, ThreadPool::ThreadPool(unsigned long)::{lambda()#1}&&) (alloc_traits.h:475)
==7253== by 0x61D7840: void std::vector<std::thread, std::allocator<std::thread> >::_M_realloc_insert<ThreadPool::ThreadPool(unsigned long)::{lambda()#1}>(__gnu_cxx::__normal_iterator<std::thread*, std::vector<std::thread, std::allocator<std::thread> > >, ThreadPool::ThreadPool(unsigned long)::{lambda()#1}&&) (vector.tcc:415)
==7253== by 0x61D371D: void std::vector<std::thread, std::allocator<std::thread> >::emplace_back<ThreadPool::ThreadPool(unsigned long)::{lambda()#1}>(ThreadPool::ThreadPool(unsigned long)::{lambda()#1}&&) (vector.tcc:105)
==7253== by 0x61D19F5: ThreadPool::ThreadPool(unsigned long) (ThreadPool.h:38)
==7253== by 0x112545: main (testexecutable.cpp:216)
代码实际上是这样的:
...
// need to keep track of threads so we can join them
std::vector< std::thread > workers;
// the task queue
std::queue< std::function<void()> > tasks;
...
// the constructor just launches some amount of workers
inline ThreadPool::ThreadPool(size_t threads)
: stop(false)
{
for (size_t i = 0; i<threads; ++i)
workers.emplace_back(
[this]
{
...
而崩溃正是在emplace_back电话中。知道为什么会这样吗?GCC 是 7.3.0,Ubuntu 是 18.04。
编辑 1
链接到带有代码的 github 存储库
编辑 2
好的,这是解决方案的一部分。我的同事指出,这可能是由于将函数指针(lambdas(放置在可执行文件和共享库的不同堆栈上,从而导致混乱 - 我还无法验证,但这是我发现的:
ldd test
linux-vdso.so.1 (0x00007ffd6bdc7000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fd8766de000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fd876350000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd875f5f000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd876ae5000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fd875bc1000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fd8759a9000)
不将 pthread(pthread(显示为必需库。但是,共享库引用 pthread。
ldd liblibrary.so
linux-vdso.so.1 (0x00007ffc97b74000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007efce4d30000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007efce49a2000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007efce478a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007efce4399000)
/lib64/ld-linux-x86-64.so.2 (0x00007efce515f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007efce3ffb000)
尽管它被引用,但对共享库中需要pthread的函数的任何调用都会导致应用程序崩溃 - 看起来,pthread库根本没有加载。
如果我调用线程到 main,即
void dummyfunction() {}
int main(int argc, char* argv[]) {
std::thread dummy(&dummyfunction);
dummy.join();
...
// dlopen/dlsym here...
...
initFunction();
...
// dlclose
return 0;
}
pthread被添加到库列表中,
ldd test
linux-vdso.so.1 (0x00007ffdc7bd0000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f5d13777000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f5d13573000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f5d131e5000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f5d12fcd000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5d12bdc000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5d13b9c000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f5d1283e000)
它被加载,一切都在共享库中工作。
但是为什么 pthread 库没有从共享库加载呢?
还尝试在pthread上的共享库中使用dlopen
,但这不起作用。
感谢@o11c指出这一点。解决此问题的一种方法是向可执行文件的链接器添加一个标志,并将pthread显式添加到库列表中
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-as-needed")
target_link_libraries(test pthread dl)
相关文章:
- 当回溯以零开始时,如何调试崩溃
- 内联映射初始化的动态atexit析构函数崩溃
- 执行函数时导致崩溃的变量
- 程序崩溃并显示"std::out_of_range"错误
- CoInitialize()在单独的线程上崩溃而不返回
- 使用调试/崩溃报告将应用程序部署到客户端
- 为什么所有C++编译器都会崩溃或挂起此代码
- 为什么lambda在clang上崩溃而不是在gcc上崩溃
- 为什么我的多线程作业队列崩溃
- ExtractIconEx:可以工作,但偶尔会崩溃
- 为什么引用传递会导致此崩溃(C++)
- 试图创建流或fopen时程序崩溃
- 类对象数组的问题会导致崩溃
- 排序时无法执行交换操作.我做的时候它会崩溃.为什么
- 为什么要增加导致崩溃的指针
- 在虚幻引擎中删除NXOpen对象时崩溃
- 为什么它只打印双链接列表的第一个值,而我的程序却崩溃了
- 应用程序崩溃并显示"symbol _ZdlPvm, version Qt_5 not defined in file libQt5Core.so.5 with link time reference"
- Visual Studio在尝试读取resource.txt文件时崩溃
- 为什么对std::vector::back()的调用会使我的程序崩溃