简体   繁体   English

从Python扩展调用C ++虚拟成员时崩溃

[英]Crash calling C++ virtual member from Python extension

I'm trying to write a thin wrapper around some C++ classes to call them from Python. 我正在尝试为一些C ++类编写一个瘦包装,以从Python调用它们。 The specific problem is that if virtual is uncommented below then attempting to create a Foo() crashes the interpreter. 特定的问题是,如果在下面未注释virtual ,则尝试创建Foo()会使解释器崩溃。 I'm not interested in rewriting this code as Boost::python, SWIG or Pyxxx to solve this problem - this is an extract from a much larger system I would like to know why it happens, although if either of those libraries solves this problem I would love to know how they implement it. 我对将代码重写为Boost :: python,SWIG或Pyxxx来解决此问题不感兴趣-这是从更大的系统中提取的内容,我想知道为什么会发生,尽管这些库中的任何一个都可以解决此问题我很想知道他们是如何实施的。 If I setup an extension module and register types in the system then the calls from the Python interpreter work without any problems, either using extern "C" or just having static members in a class to register in the slots for the Python type. 如果我设置了扩展模块并在系统中注册类型,那么使用extern "C"或仅在类中使用静态成员在Python类型的插槽中注册,Python解释器的调用就可以正常工作。

If I declare a member to be virtual, then attempting to call it (within a call from the Python interpreter) causes a crash with bad memory access. 如果我声明一个成员为虚拟成员,则尝试调用它(在Python解释器的调用内)会导致崩溃,并导致错误的内存访问。 The address accessed is the offset that I get if I print out the class member as a pointer. 访问的地址是将类成员作为指针打印出来后得到的偏移量。 I have specific code to follow, but the basic question is: does something in the C runtime environment called by Python screw up the despatch of virtual class member functions? 我要遵循特定的代码,但是基本问题是:Python调用的C运行时环境中的某些内容是否破坏了虚拟类成员函数的发送? Python is v2.6.7 and the C++ extension is being compiled by GCC 4.2.1. Python是v2.6.7,G ++ 4.2.1正在编译C ++扩展。 There are related questions that suggest Boost::python supports this, are they doing it directly or simulating it through class member functions? 有一些相关的问题建议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();
  }
}

Thanks Let_Me_Be, your comment pushed me down the right track. 谢谢Let_Me_Be,您的留言使我误入歧途。 The problem is that the memory for the Foo object is being malloc'd by the Python interpreter. 问题是Python解释器正在分配Foo对象的内存。 This hasn't caused problems in my other code because it does not rely on the vtable being initialised. 这不会在我的其他代码中引起问题,因为它不依赖于初始化的vtable。 The easiest solution is to use placement-new to ensure the ctor actually gets called and then the virtual member works correctly: 最简单的解决方案是使用newplacement以确保ctor实际被调用,然后虚拟成员正常工作:

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

There is a more detailed Q&A at On VTable pointers and malloc . 关于On VTable指针和malloc,有更详细的问答。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM