共享库中的内部异常终止最终用户应用程序

Internal exceptions in shared library terminate end user application

本文关键字:用户 应用程序 异常终止 内部 共享      更新时间:2023-10-16

我正在构建一个内部使用Boost.thread的共享库。因此,Boost.system也被使用,因为Boost.thread依赖于它。我的共享库导出了一个C接口,所以我想向最终用户隐藏我所有的内部异常处理和线程使用等。可以这么说,它应该是一个黑盒子。然而,当我链接到客户端应用程序时,当程序运行良好时——只要到了通过调用库函数来停止处理的时候,我就会得到:

在抛出"boost::thread_interrupted"的实例后调用terminate

我在库内部捕获了这个异常,所以我不知道为什么它实际上没有被捕获。最终用户的程序并不意味着以任何方式了解或处理Boost异常。在构建共享库时,我对Boost.thread和Boost.system都使用静态链接,所以外界永远不会看到它们。我在Ubuntu 12上使用GCC 4.7。在Windows上,我没有这样的问题(MSVC和MinGw都没有)。

(编辑)

根据评论中的要求,我正在编辑这个问题,以展示一个重现问题的极简主义例子。

这里首先是testlib.cpp和testlib.h的代码。

testlib.cpp:

#包括<boost/thread/thread.hpp>void thread_func(){而(1){boost::this_thread::interruption_point();}}作废do_processing(){//启动一个线程来执行上面的函数。boost::线程工作者(thread_func);//出于本例的目的,我们假设线程已正确启动。//现在让我们中断线程。worker.interrupt();//现在让我们等待它结束。worker.join();}

现在是testlib.h:

#ifndef TESTLIB_H#定义TESTLIB_Hvoid do_processing();#endif

我用以下命令将其构建到一个共享库中:

g++-static libgcc-static-s-DNDEBUG-I/usr/boost_1_54_0-L/usr/boost_1 _54_0/stage/lib-Wall-shared-fPIC-o libtestlib.so testlib.cpp-lbost_thread-lbostrongystem-lpthread-O3

然后,我有了一个琐碎客户端程序的代码,如下所示:

#包括"testlib.h"#包括<cstdio>int main(){do_processing();printf("执行已正确完成。\n");返回0;}

我构建客户端如下:

g++-DNDEBUG-I/usr/boost_1_54_0-L./-Wall-o客户端.cpp-ltestlib-O3

当我运行客户端时,我得到:

在抛出"boost::thread_interrupted"的实例后调用terminate
中止(堆芯转储)

我没有明确地捕捉线程中断异常,但根据Boost文档,Boost.thread会这样做,并仅终止给定的线程。我尝试从thread_func函数中显式捕获异常,但没有什么区别。

(编辑结束)

(编辑2)

值得注意的是,即使启用了-fexceptions,问题仍然存在。此外,我尝试抛出并捕获一个异常,该异常与捕获并抛出它的代码在同一翻译单元中定义,但没有任何改进。简而言之,在共享库中,所有异常似乎都是未捕获的,尽管我确实为它们提供了捕获处理程序。当我将客户端文件和testlib文件作为单个程序的一部分进行编译时,也就是说,在不将testlib制作成共享库的情况下,一切都能按预期进行。

(第2版结束)

有什么建议吗?

我终于弄明白了。当指定-shared时,永远不应该指定-static标志。我认为它只是告诉链接器更喜欢它链接的库的静态版本,但它却使生成的动态库不适合动态链接,这有点讽刺。但事实就是这样。删除静态解决了我所有的问题,我能够在我的动态库中很好地静态链接Boost,它完美地处理了异常。

也许是这样?

如果你有一个抛出E的库L,那么L和应用程序A必须链接到X,该库包含E.的定义

也尝试将可执行文件链接到boost。

一个本身包括静态链接库的共享库不是一个好主意,我认为GNU工具链中不太支持这种场景。

我认为您的特定问题源于选项-static-libgcc,但我无法使用您的选项在我的机器中编译它。静态链接到libpthread.so听起来也不是一个好主意。。。如果主可执行文件想要创建自己的线程,会发生什么?它会用-pthread编译吗?如果是,那么您将链接两次线程函数;如果没有,它将具有函数,但没有预编译器宏或线程安全库函数。

我的建议是不要静态编译库,这不是Linux的方式。

事实上,这应该不是一个真正的问题,即使你不想依赖boost的分发版本:根据共享的boost库编译你的程序,并将所有这些文件(libboost_thread.so.1.54.0libboost_system.so.1.54.0libtestlib.so)部署到同一目录中。然后使用LD_LIBRARY_PATH=<path-to-so-files>运行您的程序。由于客户端不打算直接使用boost,因此它不需要boost头,也不需要在编译器命令中链接它们。你仍然有你的黑盒,但现在它是由3*so文件组成的,而不是只有1个。