中断 C 函数执行并返回到 C++呼叫者
我目前在使用以下配置实现以下场景时遇到问题:GCC 3.4,Linux。
我编写了一个工具(用 C++)加载共享库(用 C 编写)。这个库有一个我无法修复的错误。问题是它读取一些输入并写入解码的输出。有时,如果输入错误,该库会在不进行任何检查的情况下开始解码以下内存区域。这会导致段错误。
最初我的想法是将输入放入分页内存(linux mmap-syscall)并保护(mprotect)最后一页,防止访问。通过安装自己的 SIGSEGV 处理程序,我的 C++ 应用程序可以抛出异常(当使用 GCC 标志 -fnon-call-exceptions 进行编译时)。该异常会中断C lib 的读取。我知道这个库不分配任何内存(或其他资源),这些内存可能在堆栈展开期间丢失。整个场景在我的单元测试中运行良好,所有内容都是一个 C++ 应用程序。但是现在,当调用库中的 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 位系统上)。在我看来,等到库在单独的进程中崩溃并不是一个选择。首先,解码一方面会花费大量时间,另一方面会产生大量垃圾。因为我的工具需要向用户可靠地显示解码的输出。他们仍然需要能够理解这些痕迹。
我不认为这里有必要解决 SIGSEGV 问题。首先,库读取数据并将其写入我之前传递的文件句柄。我可以配置如何写入该句柄(缓冲或不缓冲)。此外,我确切地知道它不会分配任何堆数据或资源。最后,它尝试访问我的应用程序保护的内存以避免此类错误。从用户的角度来看,我无法告诉某人:抱歉,二进制跟踪只有一半可解码,因为某些数据不一致。我知道这些数据不一致,并且我完全知道如何处理这种不一致。这样我就可以优雅地康复了。我想我会尝试使用 sigsetjmp/siglongjmp POSIX 函数,并希望它们作为例外会做得更好。实际上,setjmp/longjmp 或 sigsetjmp/siglongjmp 都用于实现异常。
是的,我调试了我的应用程序并看到调用堆栈是有效的。
I currently have a problem implementing the following scenario using the following configuration: GCC 3.4, Linux.
I have written a tool (in C++) which loads a shared library (written in C). This library has a bug which I cannot influence to fix. The problem is that it reads some input and writes decoded output. Sometimes if the input is wrong, this library without doing any checks starts decoding of the following memory regions. That causes a segfault.
Initially my idea was to put the input into the paged memory (linux mmap-syscall) and protect (mprotect) the last page, against access. By installing an own SIGSEGV handler my C++-App can throw an exception (when compiled with GCC flag -fnon-call-exceptions). This exception will interrupt the C lib's reading. I known that this lib does not allocate any memory (or other resources), which might be lost during stack-unwinding. The whole scenario worked fine in my unit tests, where everything was a single C++ app. But now when the C code from the lib is called my app just terminates... Do I need to rebuild this C-SO with -fnon-call-exceptions flag as well? I can't compile this lib, but only re-link it, since I have access to obj files only.
Here is the picture of the execution environment:
+------------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 |
+-----------------------------+
Other suggestions are welcome.
Many thanks,
Ovanes
P.S. I see some suggestions and critics but they are all not an optin. Here is why: I only have one interface, where I can link to the library. The library is used to decode data structures. The problem is that if I have an array with the length -1 the library starts to decode the array of length 0xffffff (on a 32 bit system). Waiting until the lib crashes in a separate process is not an option in my opinion. First of all decoding will take a considarable ammount of time on one hand and will produce lots of trash on the other. Since my tool needs to show the decoded output reliably to the users. And they still need to be able to understand the traces.
I don't see the point here to work around a SIGSEGV. First of all, the library reads data and writes it to the file handle which I passed before. I can configure how to write to that handle (buffered or not). Furthermore, I know exactly that it does not allocate any heap data or resources. And finally, it tries to access memory which my app protected to avoid such errors. From the user's perspective I can't tell to someone: Sorry the binary trace was only half decodable, because some data was inconsistent. I know that this data was inconstent and I exactly know how to deal with this inconsistency. So I can gracefully recover. I think I will try to use sigsetjmp/siglongjmp POSIX functions and hope they will do better as exception. Indeed either setjmp/longjmp or sigsetjmp/siglongjmp are used to implement exceptions.
Yes, I debugged my application and see that the call stack is valid.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
好的,伙计们,
我用 sigsetjmp/siglongjmp 做到了。就像魅力一样。我可以跳过函数进入调用者函数的堆栈并在那里进行错误处理。
感谢您的所有建议。
最好的问候,
奥瓦内斯
Ok Guys,
I did it with sigsetjmp/siglongjmp. Works like a charm. I can jump over the function into the stack of the caller function and do error handling there.
Thanks for all the suggestions.
Best Regards,
Ovanes
不幸的是,我没有上述问题的答案 - 您是否尝试过在调试器下运行应用程序,以查看它到底在哪里终止?
然而,我想到的另一种方法是将错误库的使用放入一个单独的程序中,从您的应用程序启动它并通过管道传递数据。
Unfortunately I don't have an answer for the problem as stated - have you tried running your application under a debugger, to see where exactly it terminates?
However, an alternative approach which came to my mind would be to put the usage of the faulty library into a separate program, launch it from your app and pass it the data via a pipe.
这可能是一个愚蠢的问题,但必须检查核心文件吗?或者在调试器中运行您的应用程序?
This might be stupid question, but have to examined core file? Or run your application in debugger?