C++动态库沙箱化

3
我想知道是否可以通过dlopen和相关工具来沙盒动态链接库。目的是在库内部发生错误时恢复,而不会导致整个应用程序崩溃,例如SEGFAULT等。有人在这方面有经验吗?
3个回答

4

在调用库之前,你可以使用fork()创建一个子进程,然后将结果传递给主进程。让主进程等待来自子进程的数据,或在子进程崩溃时报告错误。


谢谢您的时间。我曾考虑过这种方法,但这是一种相当笨重的方法,我希望能找到更优雅的解决方案。 - Ben Crowhurst
2
当你链接库代码时,你与它共享内存,这意味着它的错误不仅会导致段错误,还会用垃圾覆盖你的内存。如果你想防范这种情况,进程分离确实是最好的方法。 - che
使用fork不是合适的方法,因为它创建了一个全新的上下文(即使它本质上是相同的,它仍然是一个副本)。像增加你所喜欢的库的使用计数这样简单的操作都是“不同”的。 - Elf King
当然,如果您有一个带有一些运行时上下文(或更糟糕的是,线程)的应用程序,您不应该分叉并继续运行整个应用程序。子进程应该exec()一些最小的存根,只获取库调用所需的必要数据,执行调用并传递结果。 - che

2

好的,一般来说,异常处理高度依赖于操作系统。我将做出一些假设并尝试提供一些通用指导。请知道,这绝不是详尽无遗的回复,但应该作为一个起点。

我将假设:

  1. 在大多数情况下,你对防止内存泄漏感兴趣。

  2. 你不关心Windows(它是完全不同的东西),因为你提到了dlopen(否则你会说LoadLibrary)

  3. 你已经意识到链接C++符号的细微差别。如果你没有,请在dlopen c ++ mini howto上阅读相关内容

一般来说

没有一般解决方案可以解决所描述的问题,而不涉及专门提供数据和代码段沙箱的操作系统。有可信系统和专业操作系统内核可以实现此功能,但我假设您想在旧的*nix或Windows环境中执行此操作。

编译器的东西进一步复杂化了问题(你的C++编译器默认生成弱符号吗?通常会这样做)。这会影响try-catch中发生异常的方式。

简单的操作系统异常处理引发信号(SIGSEGV,SIGFPE等):

在支持sigaction的POSIX系统下...

假设您想保护通用事项,例如错误的内存寻址。在dlopen库之前使用sigaction捕获SIGSEG(以保护.init函数),然后在调用库中的函数之前进行信号检查。考虑使用SA_STACK确保您的处理程序跳转到您完全控制的堆栈中,并使用SA_SIGINFO确保您的处理程序获取有关源的信息。

一个很好的起点是GNU libc手册上的信号处理

在C++中:使用包装器和try-catch捕获软件异常

try { foo(); } catch() { // do something }

其中foo是指向dll中函数的弱符号。请参见c ++ dlopen mini-howto以获取更多示例和有关加载类等的详细信息。

如果您有更具体的需求,请发布它们,我会看看是否可以提供更多信息。

干杯


0
你如何区分应用程序和相关动态库的段错误?创建一个单独的进程来隔离库,正如Che所描述的那样,似乎是最好的方法。
编辑:
发现this相关问题,指向CERT建议,如果您需要可移植性,请不要从SIGSEGV处理程序返回。

使用sigaction SA_SIGINFO,您可以确定发送信号的上下文,这意味着您实际上可以通过编程回溯找出引发信号的函数,并确定它是否是库内部的函数。由于您正在捕获信号,因此可以正确地恢复。执行fork()不是确定库弹性的好方法... - Elf King

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接