Python在加载C++编写的扩展模块时接收SIGSEGV

dyo*_*mas 6 c++ python unix

正确的代码示例:

#include "Python.h"
#include <string>

extern const int someConstant;

void some_function()
{
  const char *begin = NULL;
  const char *end = NULL;

  std::string s(begin, end);
  const int v = someConstant;
}

static PyMethodDef _G_methods[] =
{
    {NULL, NULL, 0, NULL}        /* Sentinel */
};

PyMODINIT_FUNC initsf()
{
  PyObject *module;

  if (!(module = Py_InitModule("sf", _G_methods)))
  {
    return;
  }

  PyObject *pyerror = PyErr_NewException("fs.error", NULL, NULL);
  Py_INCREF(pyerror);


  PyModule_AddObject(module, "error", pyerror);
}
Run Code Online (Sandbox Code Playgroud)

这是扩展模块草案.尽可能简单.它有一个空的方法表和从原始docpage复制的初始化函数.它包含2(2)个故意错误:

  • 变量some​​Constant声明但从未定义;

  • 函数some_function定义,但从未调用过;

如果由dlopen/dlsym编译和打开:

sf.so: undefined symbol: someConstant
Run Code Online (Sandbox Code Playgroud)

按要求.但如果由Python解释器加载:

>>> from sf import *
Segmentation fault (core dumped)
Run Code Online (Sandbox Code Playgroud)

最奇怪的是从core-file转储的python的backtrace:

#0  0x00000bd6 in ?? ()
#1  0xb775c057 in char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) () from /usr/local/lib/python2.7/dist-packages/sf.so
#2  0xb6f9abb6 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#3  0xb6c3fe30 in pkgInitConfig(Configuration&) () from /usr/lib/i386-linux-gnu/libapt-pkg.so.4.12
#4  0xb6cf959e in ?? () from /usr/lib/python2.7/dist-packages/apt_pkg.so
#5  0x081949c1 in PyEval_EvalFrameEx ()
#6  0x0819af70 in PyEval_EvalCodeEx ()
#7  0x0819bb03 in PyImport_ExecCodeModuleEx ()
#8  0x0814bd40 in ?? ()
#9  0x080a38c2 in ?? ()
#10 0x0814c6d4 in ?? ()
#11 0x081031ae in ?? ()
...
Run Code Online (Sandbox Code Playgroud)

看来,Python的加载器调用了std :: string构造函数:-).

所以,堆栈已损坏.它在加载无效模块时或在处理错误后卸载时发生.如果示例代码几乎没有改变,它就不会发生.在Python 2.7.3/Linux Ubuntu 10/gcc 4.6.3上已经观察到这种行为,并且绝对没有在Python 2.7.1/FreeBSD 8.1/gcc 4.2.1上显示.

题:

  1. 它是Python的错误还是我的示例代码有错误?

Die*_*Epp 3

让我们再次查看堆栈跟踪

#0 0x00000bd6 在 ?? ()
#1 0xb775c057 in char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) () 来自 /usr/local/lib /python2.7/dist-packages/sf.so
#2 0xb6f9abb6 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) () 来自 /usr/ lib/i386-linux-gnu/libstdc++.so.6
#3 0xb6c3fe30 in pkgInitConfig(Configuration&) () 来自 /usr/lib/i386-linux-gnu/libapt-pkg.so.4.12
#4 0xb6cf959e 在 ?? () 来自 /usr/lib/python2.7/dist-packages/apt_pkg.so

因此,函数中的函数libapt-pkg.so调用了模块中的函数,libstdc++.so而函数中的函数又调用了模块中的函数。

你的函数永远不会被调用。但是,您的代码使用std::string并实例化了 的一些函数std::string,这些函数被包含到您的 中*.so,覆盖完全不同的 所使用的函数*.so,并由于某种原因崩溃,我不完全确定为什么。

我的直觉告诉我,你过去常常gcc创建你的*.so而不是g++. 您在链接时不会收到错误,因为链接共享对象不能以这种方式工作。您在加载时不会收到错误,因为碰巧libstdc++已经加载了。

您正在使用gccg++链接吗?尝试使用g++.