nio*_*sus 0 python sublimetext libclang sublimetext3 sublime-text-plugin
我为Sublime Text 3开发了一个插件,我的python代码使用c类型绑定来实现clang.有时调用libclang会出现段错误libclang: crash detected during reparsing(我还不明白原因,但这与这个问题无关).这会导致插件主机崩溃.
所以问题是:在python中有什么方法可以从底层c绑定中的失败中恢复?我很乐意在这个遇到崩溃的特定文件中跳过这个动作.
谢谢!
UPD:评论中有一个简短的讨论,有必要进一步阐述缺乏一个适当的小型可重复的例子.这并不是因为我的懒惰,我尽量让它尽可能容易地理解我希望得到帮助的人的问题.但在这种情况下,这真的很难.最初的问题是由libclang segfaulting导致的一些奇怪的情况,我还没有确定.它可能与一个没有c ++ 11支持编译的库有关,另一个在使用c ++ 11支持编译时使用它,但我想强调 - 这与问题无关.这里的问题是python正在调用的东西中有一个段错误,这个段错误导致Sublime Text plugin_host退出.所以这里有一个简单的例子,但不是缺乏尝试.如果你有如何构建一个想法,我也愿意接受建议.抱歉这个问题的质量很差,这是目前我最好的.
小智 5
使用我所拥有的细节,我有理由相信你的问题归结为"Python可以处理使用外部函数接口时发生的错误."
我很确定答案是"不",我将以下测试场景放在一起解释原因:
这是我们的测试C++模块(有一些C用于名称修改)将会在我们面前爆炸,test.cc:
#include <iostream>
#include <signal.h>
class Test{
public:
void test(){
std::cout << "stackoverflow" << std::endl;
// this will crash us. shouldn't really matter what SIG as long as it crashes Python
raise (SIGABRT);
}
};
extern "C" {
Test* Test_new(){ return new Test(); }
void Test_example(Test* test){ test->test(); }
}
clang -shared -undefined dynamic_lookup -o test.so test.cc
Run Code Online (Sandbox Code Playgroud)
我们的调用脚本test.py:
from ctypes import cdll
test_so = cdll.LoadLibrary("test.so")
class PyTest:
def __init__(self):
self.obj = test_so.Test_new()
def output(self):
test_so.Test_example(self.obj)
if __name__ == "__main__":
p = PyTest()
p.output()
Run Code Online (Sandbox Code Playgroud)
叫它:
? /tmp/29_may ? python test.py
stackoverflow
[1] 55992 abort python test.py
Run Code Online (Sandbox Code Playgroud)
这会使Python崩溃,并在OS X上生成一个很好的"报告错误"细节:
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libsystem_kernel.dylib 0x00007fff95bf48ea __kill + 10
1 test.so 0x0000000110285006 Test::test() + 70
2 test.so 0x0000000110284fb5 Test_example + 21
3 _ctypes.so 0x000000011026d7c7 ffi_call_unix64 + 79
4 _ctypes.so 0x000000011026dfe6 ffi_call + 818
5 _ctypes.so 0x000000011026970b _ctypes_callproc + 867
6 _ctypes.so 0x0000000110263b91 PyCFuncPtr_call + 1100
7 org.python.python 0x000000010fd18ad7 PyObject_Call + 99
8 org.python.python 0x000000010fd94e7f PyEval_EvalFrameEx + 11417
9 org.python.python 0x000000010fd986d1 fast_function + 262
10 org.python.python 0x000000010fd95553 PyEval_EvalFrameEx + 13165
11 org.python.python 0x000000010fd91fb4 PyEval_EvalCodeEx + 1387
12 org.python.python 0x000000010fd91a43 PyEval_EvalCode + 54
13 org.python.python 0x000000010fdb1816 run_mod + 53
14 org.python.python 0x000000010fdb18b9 PyRun_FileExFlags + 133
15 org.python.python 0x000000010fdb13f9 PyRun_SimpleFileExFlags + 711
16 org.python.python 0x000000010fdc2e09 Py_Main + 3057
17 libdyld.dylib 0x00007fff926d15ad start + 1
Run Code Online (Sandbox Code Playgroud)
我复制并粘贴了这个,因为它比一个strace更干净/更容易解析(也是,我很懒;).打电话__kill是我们坠毁的地方; 我们永远不会看到回归Python,这意味着它不受我们的控制.
为了证明这一点,修改我们test.py进入test_handle_exception.py尝试捕获异常:
from ctypes import cdll
test_so = cdll.LoadLibrary("test.so")
class PyTest:
def __init__(self):
self.obj = test_so.Test_new()
def output(self):
test_so.Test_example(self.obj)
if __name__ == "__main__":
p = PyTest()
try:
p.output()
except:
print("If you're reading this, we survived somehow.")
Run Code Online (Sandbox Code Playgroud)
并再次运行:
? /tmp/29_may ? python test_handle_exception.py
stackoverflow
[1] 56297 abort python test_handle_exception.py
Run Code Online (Sandbox Code Playgroud)
不幸的是,据我所知,我们无法捕获Python层的异常/崩溃,因为它发生在字节码控制的"下方".非特定Exception子句将尝试捕获发生的任何异常,其中以下语句是捕获异常时采取的操作.If you're reading this, we survived somehow.从未被发送到stdout,我们崩溃了,这意味着Python没有机会做出反应.
如果可以,请在C++代码中处理此异常.您可能能够创造性地使用多处理来分叉进入可能崩溃的进程而不会占用主进程,但我对此表示怀疑.