Crash从Python扩展中调用C ++虚拟成员

时间:2012-08-02 11:43:53

标签: c++ python python-extensions

我正在尝试围绕一些C ++类编写一个瘦包装器来从Python调用它们。具体问题是,如果virtual在下面取消注释,则尝试创建Foo()会导致解释程序崩溃。我不想将这个代码重写为Boost :: python,SWIG或Pyxxx来解决这个问题 - 这是一个更大系统的摘录我想知道它为什么会发生,尽管如果这些库中的任何一个解决了这个问题我很想知道他们是如何实现它的。如果我在系统中设置扩展模块和寄存器类型,那么来自Python解释器的调用没有任何问题,使用extern "C"或只是在类中使用静态成员来注册Python类型的插槽。 / p>

如果我声明一个成员是虚拟的,那么尝试调用它(在Python解释器的调用中)会导致内存访问不良导致崩溃。访问的地址是我打印出类成员作为指针时得到的偏移量。我有特定的代码要遵循,但基本的问题是:Python调用的C运行时环境中的某些东西搞砸了虚拟类成员函数的发送吗? Python是v2.6.7,C ++扩展由GCC 4.2.1编译。有一些相关的问题表明Boost :: python支持这个,他们是直接做的还是通过类成员函数来模拟它?

// PythonType is a class that inherits from PyTypeObject and fills in defaults ...

extern "C" int initHook(PyObject *self, PyObject *args, PyObject *kwds);
class Foo
{
public:
static PythonType thePyType;
  static void registerType(PyObject *module)
  {
    thePyType.tp_init = initHook;
    PyType_Ready(&thePyType);
    PyModule_AddObject(module, thePyType.tp_name, (PyObject*)&thePyType);
  }

  /*virtual*/ void insert()
  {
    printf("Inserted\n");
  }
};
PythonType Foo::thePyType("Foo",sizeof(Foo));
extern "C" {
  int initHook(PyObject *self, PyObject *args, PyObject *kwds)
  {
    ((Foo*)self)->insert();
  }
}

1 个答案:

答案 0 :(得分:0)

谢谢Let_Me_Be,你的评论让我走上正轨。问题是Foo对象的内存由Python解释器进行malloc化。这并没有在我的其他代码中引起问题,因为它不依赖于初始化的vtable。最简单的解决方案是使用placement-new来确保实际调用ctor,然后虚拟成员正常工作:

 int initHook(PyObject *self, PyObject *args, PyObject *kwds)
 {
    new(self) Foo();
    ((Foo*)self)->insert();
 }

On VTable pointers and malloc有一个更详细的问答A.