sublime text 3插件主机崩溃恢复

时间:2016-05-19 11:05:06

标签: python sublimetext3 sublimetext sublime-text-plugin libclang

我为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退出。所以这里有一个简单的例子,但不是缺乏尝试。如果你有如何构建一个想法,我也愿意接受建议。抱歉这个问题的质量很差,这是我最好的。

1 个答案:

答案 0 :(得分: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

我们的调用脚本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()

称之为:

Ξ /tmp/29_may → python test.py
stackoverflow
[1]    55992 abort      python test.py

这会使Python按预期崩溃并生成一个很好的&#34;报告错误&#34; 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

我复制并粘贴了这个,因为它比一个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.")

再次运行:

Ξ /tmp/29_may → python test_handle_exception.py
stackoverflow
[1]    56297 abort      python test_handle_exception.py

不幸的是,据我所知,我们无法在Python层捕获异常/崩溃,因为它发生在&#34;下面&#34;字节码的控制。非特定的Exception子句将尝试捕获发生的任何异常,其中以下语句是捕获异常时采取的操作。 If you're reading this, we survived somehow.从未被发送到stdout,我们崩溃了,这意味着Python没有机会做出反应。

如果可以,请在C ++代码中处理此异常。您可能会发挥创意并使用multiprocessing分叉进入可能会崩溃而不会取消主要流程的流程,但我对此表示怀疑。