Details
Description
I have to do Py_Initialize() and Py_Finalize() several times in my C++ application during process execution.
But the 2nd call to Py_Finalize() causes a crash if there is the PySide.QtCore module imported.
The shortest example:
#include <iostream> #include <Python.h> using namespace std; void test() { Py_Initialize(); PyObject * module = PyImport_ImportModule("PySide.QtCore"); cout << module << endl; // module is not a null pointer Py_Finalize(); } int main(int, char**) { test(); test(); // << crash test(); test(); test(); test(); test(); test(); return 0; }
> python27.dll!visit_decref(_object * op=0x00000000026d39f0, void * data=0x0000000000000000) Line 360 + 0x3d bytes C
python27.dll!dict_traverse(_object * op=0x00000000027331a8, int (_object , void *) visit=0x000000001e06baf0, void * arg=0x0000000000000000) Line 2114 + 0x16 bytes C
python27.dll!subtract_refs(_gc_head * containers=0x000000001e3894c0) Line 388 C
python27.dll!collect(int generation=2) Line 933 C
python27.dll!PyGC_Collect() Line 1440 + 0xa bytes C
python27.dll!Py_Finalize() Line 459 C
The actual crash occurs on gcmodule.c:360
if (PyObject_IS_GC(op)) {
The op's type is likely to be inconsistent, as op->ob_type->tp_is_gc equals to 0xfbfbfbfbfb007075
I've tried the same for PyQt4.QtCore and it does not crash.
UPD:
Got a similar error on Debian Linux (gcc (Debian 5.3.1-12), Python 2.7.6, PySide 1.2.1, Py_Finalize() crashes on the 4th call to it but there is a bit different callstack:
type_dealloc() at typeobject.c:2 643 0x7ffff7a8a3c4
dict_dealloc() at dictobject.c:1 010 0x7ffff7a6a14f
dict_dealloc() at dictobject.c:1 010 0x7ffff7a6a14f
_PyImport_Fini() at import.c:272 0x7ffff7af332a
Py_Finalize() at pythonrun.c:481 0x7ffff7b07ff5
test() at main.cpp:12 0x400a5e
main() at main.cpp:20 0x400a79
The actual crash occurs on typeobject.c:2643
_PyObject_GC_UNTRACK(type);
Looks familiar, as there something went wrong in the garbage collector code.
UPD2:
Having reduced the initialization code of PySide.QtCore, I found that PySide::init(module); causes the issue. If I comment it out, it will work.
Went deeper, found that if I comment out MetaFunction::init(module); inside the PySide::init implementation this also will work fine. Found there in contrast to the other init function implementation (ClassInfo::init, Signal::init, Slot::init, Property::init), it DOES NOT incref a counter of its type (PySideMetaFunctionType).
I have fixed the issue on Linux. There is an error inside MetaFunction::init
void init(PyObject* module) { if (PyType_Ready(&PySideMetaFunctionType) < 0) return; Py_INCREF(&PySideMetaFunctionType); // <<< I added this line and it does not crash anymore. PyModule_AddObject(module, "MetaFunction", ((PyObject*)&PySideMetaFunctionType)); }
UPD3:
Unfortunately, that fix didn't help to fix the crash on Windows.
I used the same approach to locate the problematic code on Windows. What I've found is that any call to Shiboken::Enum::createGlobalEnumItem inside the PySide.QtCore initialization function causes the following crash.
I'm not sure whether it's a proper fix (may lead to memory leaks) but:
static PyObject* createEnumItem(PyTypeObject* enumType, const char* itemName, long itemValue) { PyObject* enumItem = newItem(enumType, itemValue, itemName); if (PyDict_SetItemString(enumType->tp_dict, itemName, enumItem) < 0) return 0; Py_DECREF(enumItem); return enumItem; } bool createGlobalEnumItem(PyTypeObject* enumType, PyObject* module, const char* itemName, long itemValue) { PyObject* enumItem = createEnumItem(enumType, itemName, itemValue); if (enumItem) { if (PyModule_AddObject(module, itemName, enumItem) < 0) return false; Py_DECREF(enumItem); return true; } return false; }
There are two possible calls to Py_DECREF, that it calls decref twice for a single object. So that, I commented Py_DECREF out in the createGlobalEnumItem function, now it doesn't crash.
UPD4:
Phew!
Another one issue that leads to an assertion failure on typeobject.c:2642
assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE);
Of course, type there is the PySideMetaFunctionType instance.
Comparing to the similar types (such as the PySideSlotType), discovered that the tp_base of the PySideMetaFunctionType is NULL. PySideSlotType->tp_base is &PyType_Type.
Did the same for the PySideMetaFunctionType, now it's OK. I hope so. The code is so erratic!
Attachments
Issue Links
- duplicates
-
PYSIDE-219 QTableView.setItemDelegateForColumn breaks software
- Closed
- relates to
-
PYSIDE-488 Incorrect Enum memory management leads to crash on exit
- Open