【问题标题】:Interrupting a C function execution and getting back to C++ caller中断 C 函数执行并返回 C++ 调用者
【发布时间】:2011-05-07 09:53:47
【问题描述】:

我目前在使用以下配置实现以下场景时遇到问题:GCC 3.4,Linux。

我编写了一个工具(用 C++ 编写),它加载了一个共享库(用 C 编写)。这个库有一个我无法影响修复的错误。问题是它读取一些输入并写入解码输出。有时如果输入错误,这个库不做任何检查就开始解码以下内存区域。这会导致段错误。

最初我的想法是将输入放入分页内存(linux mmap-syscall)并保护(mprotect)最后一页,以防止访问。通过安装自己的 SIGSEGV 处理程序,我的 C++-App 可以抛出异常(当使用 GCC 标志 -fnon-call-exceptions 编译时)。此异常将中断 C lib 的读取。我知道这个库不会分配任何内存(或其他资源),这可能会在堆栈展开期间丢失。整个场景在我的单元测试中运行良好,其中一切都是一个 C++ 应用程序。但是现在当调用 lib 中的 C 代码时,我的应用程序刚刚终止......我是否还需要使用 -fnon-call-exceptions 标志重建这个 C-SO?我无法编译这个库,只能重新链接它,因为我只能访问 obj 文件。

这是执行环境的图片:

+------------C++ APP----------+
|                             |
| Install SIGSEGV handler     |
| code calling C SO functions |
|                             |
|   +----------C SO Functions------------+
|   |   execute producing SIGSEGV        |
|   +------------------------------------+
|                             |
| SIGSEGV Handler called      |
|   => throw Exception        |
|      to stop execution of   |
|      C function             |
+-----------------------------+

欢迎提出其他建议。

非常感谢,

欧文


附:我看到了一些建议和批评,但他们都不是一个选择。原因如下:我只有一个界面,可以链接到库。该库用于解码数据结构。问题是,如果我有一个长度为 -1 的数组,则库开始解码长度为 0xffffff 的数组(在 32 位系统上)。在我看来,等到 lib 在单独的进程中崩溃不是一个选择。首先,解码一方面会花费大量时间,另一方面会产生大量垃圾。因为我的工具需要向用户可靠地显示解码后的输出。而且他们仍然需要能够理解这些痕迹。

我看不出解决 SIGSEGV 的意义。首先,库读取数据并将其写入我之前传递的文件句柄。我可以配置如何写入该句柄(缓冲或不缓冲)。此外,我确切地知道它不会分配任何堆数据或资源。最后,它会尝试访问我的应用程序保护的内存以避免此类错误。从用户的角度来看,我无法告诉某人:抱歉,二进制跟踪只能解码一半,因为某些数据不一致。我知道这些数据不一致,并且我完全知道如何处理这种不一致。所以我可以优雅地康复。我想我会尝试使用 sigsetjmp/siglongjmp POSIX 函数,并希望它们作为例外做得更好。实际上 setjmp/longjmp 或 sigsetjmp/siglongjmp 都用于实现异常。

是的,我调试了我的应用程序,发现调用堆栈是有效的。

【问题讨论】:

  • 您是否有机会 fork 库、使用不同的库或编写自己的库?试图解决引起 SIGSEGV 的错误对我来说听起来像是一件傻事......
  • setjmp/longjmp - 我忘记了这些,但它们可能会起作用:) 但是,我不太明白你反对单独进程的论点:你的方法也必须调用库并等待让它要么完成要么崩溃。我感觉您的应用的目的还存在其他限制,但还不清楚它们是什么。
  • @Lars:你可能是对的。但是我仍然需要在单独的过程中实现内存保护等,以不产生那么多输出。这里的问题是等待进程崩溃会产生大约 200.000,00 个输出的单个消息。整个处理会变得很奇怪。我需要向进程传递一个文件名,在其中附加解码输出并等待它完成/崩溃。在崩溃的情况下等待应用程序需要打开文件并在那里写一行错误发生,关闭它,再次启动解码部分并将文件名传递给它。太复杂了

标签: c++ linux memory-management shared-libraries segmentation-fault


【解决方案1】:

很遗憾,我没有解决上述问题的答案 - 您是否尝试过在调试器下运行您的应用程序,看看它到底在哪里终止?

但是,我想到的另一种方法是将错误库的使用放入一个单独的程序中,从您的应用程序启动它并通过管道将数据传递给它。

【讨论】:

  • 我喜欢这种替代方法的声音。我认为 OP 猜测他们的 C 共享对象需要用 -fnon-call-exceptions 重新编译是正确的,但他们不能这样做。
【解决方案2】:

这可能是个愚蠢的问题,但必须检查核心文件?还是在调试器中运行您的应用程序?

【讨论】:

  • @ovanes 好的,这对我来说是新的。
【解决方案3】:

好吧,伙计们,

我用 sigsetjmp/siglongjmp 做到了。奇迹般有效。我可以将函数跳转到调用者函数的堆栈中并在那里进行错误处理。

感谢所有建议。

最好的问候,

欧文

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-01-23
    • 2013-03-10
    • 2015-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-16
    相关资源
    最近更新 更多