PySide6 with Python C API: EXC_BAD_ACCESS error when calling a method with inherited class from QRasterWindow
-
Environment:
Python version: 3.9.6 (default, May 7 2023, 23:32:45)
PySide6 version: 6.7.0When I create an instance of QRasterWindow, calling the metric method is ok:
Py_Initialize(); PyObject * GUI = PyImport_ImportModule("PySide6.QtGui"); if(!GUI) { printf("\nCould not import PySide6.QtGui module.\n"); return 0; } // QApplication PyObject* QGA = PyObject_GetAttrString(GUI, "QGuiApplication"); PyObject * argsqa = PyTuple_New (1); PyObject * listqa = PyList_New (1); PyList_SetItem (listqa, 0, PyUnicode_FromString ("")); PyTuple_SetItem (argsqa, 0, listqa); PyObject * res = PyObject_CallObject(QGA, argsqa); // QRasterWindow PyObject* QRW = PyObject_GetAttrString(GUI, "QRasterWindow"); if(QRW) { // Create instance PyObject * args = PyTuple_New (0); PyObject * QRW_inst = PyObject_CallObject(QRW, args); // Call metric PyObject * mm = PyObject_GetAttrString(QRW_inst, "metric"); PyObject * uu = PyObject_GetAttrString(GUI, "QPaintDevice"); PyObject * ww = PyObject_GetAttrString(uu, "PdmWidth"); PyObject * argsm = PyTuple_New (1); PyTuple_SetItem (argsm, 0, ww); PyObject * res = PyObject_CallObject(mm, argsm); int val = PyLong_AsLong(res); printf("\nQRasterWindow.metric value is %d \n", val); } else { printf("\nCould not get QRW class.\n"); }But if I create a class PCJ inherited from QRasterWindow then calling metric method gives segmentation fault EXC_BAD_ACCESS:
// Create PCJ class inherited from QRasterWindow PyType_Slot slots[] = { { Py_tp_doc, "PGJ" }, { Py_tp_base, QRW }, { Py_tp_init, QRW_init }, { 0 }, }; PyType_Spec spec = { "PCJ", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, slots }; PyTypeObject *PCJ = (PyTypeObject *)PyType_FromSpec(&spec); printf("\nPCJ value is %d \n", PCJ); // Create PCJ instance PyObject * argsj = PyTuple_New (0); PyObject * PCJ_inst = PyObject_CallObject((PyObject *) PCJ, argsj); printf("\nPCJ_inst value is %d \n", PCJ_inst); // Call metric PyObject * mm = PyObject_GetAttrString(PCJ_inst, "metric"); printf("\nmm value is %d \n", mm); PyObject * uu = PyObject_GetAttrString(GUI, "QPaintDevice"); printf("\nuu value is %d \n", uu); PyObject * ww = PyObject_GetAttrString(uu, "PdmWidth"); printf("\nww value is %d \n", ww); PyObject * argsm = PyTuple_New (1); PyTuple_SetItem (argsm, 0, ww); PyObject * resj = PyObject_CallObject(mm, argsm); // segmentation fault printf("\nresj value is %d \n", resj); int valj = PyLong_AsLong(resj); printf("\nPCJ.metric value is %d \n", valj);Output:
QRasterWindow.metric value is 0 PCJ value is 436267760 In QRW_init PCJ_inst value is 263891520 mm value is 263896816 uu value is 439183584 ww value is 263877728 zsh: segmentation faultWhat is wrong?
-
Hi and welcome to devnet,
Excuse my silly question but why go through the length of using PySide6 using Python C API ? Why not write your application directly in C++ ?
-
Hi and thanks for your welcome.
Good question, I'm trying to create Qt bindings for Ada language.
Some attempts with C++ were failing due to some C++ subtleties.
But Python provides C API which I can used easily with Ada.
I provide some very first Qt bindings for Ada.
But class inheritance is still in Python.
I wanted to make them full Ada. I'm able to instantiate a class inherited from QRasterWindow (for instance) but a call to the method metric (for instance) provoques a seg fault.
(for simplicity I post the code in C) -
With debugger, I get more information:
thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0) frame #0: libpyside6.abi3.6.7.dylib`PySide::SignalManager::retrieveMetaObject(_object*) + 80 frame #1: QtGui.abi3.so`Sbk_QRasterWindow_Init(_object*, _object*, _object*) + 1073 frame #2: example_06c`QRW_init(s=0x00000001038c16c0, a=0x000000010008b040, k=0x0000000000000000) at example_06c.c:5:25If it could help to find out what could be wrong or missing.
-
Hi and thanks for your welcome.
Good question, I'm trying to create Qt bindings for Ada language.
Some attempts with C++ were failing due to some C++ subtleties.
But Python provides C API which I can used easily with Ada.
I provide some very first Qt bindings for Ada.
But class inheritance is still in Python.
I wanted to make them full Ada. I'm able to instantiate a class inherited from QRasterWindow (for instance) but a call to the method metric (for instance) provoques a seg fault.
(for simplicity I post the code in C)@Blady said in PySide6 with Python C API: EXC_BAD_ACCESS error when calling a method with inherited class from QRasterWindow:
Hi and thanks for your welcome.
Good question, I'm trying to create Qt bindings for Ada language.
Some attempts with C++ were failing due to some C++ subtleties.I'm interested in helping figure out and fix the C++ subtleties. It would seem rather reasonable to do such bridging between C++ and Ada without having to resort to a completely-interpreted language.
-
@Blady said in PySide6 with Python C API: EXC_BAD_ACCESS error when calling a method with inherited class from QRasterWindow:
Hi and thanks for your welcome.
Good question, I'm trying to create Qt bindings for Ada language.
Some attempts with C++ were failing due to some C++ subtleties.I'm interested in helping figure out and fix the C++ subtleties. It would seem rather reasonable to do such bridging between C++ and Ada without having to resort to a completely-interpreted language.
@Ville-Voutilainen, thanks for you proposal!
Unfortunately, C++ doesn't have a defined ABI.
You have to deal with mangle names for the bindings.
Mangle names are not stable from a code release to an other.
You'll find several detail on the web, for instance: -
Update:
Configuration still:- Python version: 3.9.6 (default, May 7 2023, 23:32:45)
- PySide6 version: 6.7.0
Results:
- Inheritance with QRasterWindow and QWidget is failing.
- Inheritance with QDate is succeeding.
Further work:
- try with a more recent Python version and a more recent PySide version.
-
@Ville-Voutilainen, thanks for you proposal!
Unfortunately, C++ doesn't have a defined ABI.
You have to deal with mangle names for the bindings.
Mangle names are not stable from a code release to an other.
You'll find several detail on the web, for instance:@Blady Well.. mangled names are stable unless you have an ABI break. If you keep your ABI as-is (and Qt does), GNAT should be able to call your C++ functions directly from Ada.
And what I would seriously want to look at here is generating the Ada bindings via a generator that uses C++26 reflection on the C++ side and writes out the right kind of Ada bindings. Including the parts where a mangled name is needed, like in the pragma imports.
-
@Blady Well.. mangled names are stable unless you have an ABI break. If you keep your ABI as-is (and Qt does), GNAT should be able to call your C++ functions directly from Ada.
And what I would seriously want to look at here is generating the Ada bindings via a generator that uses C++26 reflection on the C++ side and writes out the right kind of Ada bindings. Including the parts where a mangled name is needed, like in the pragma imports.
@Ville-Voutilainen said in PySide6 with Python C API: EXC_BAD_ACCESS error when calling a method with inherited class from QRasterWindow:
And what I would seriously want to look at here is generating the Ada bindings via a generator that uses C++26 reflection on the C++ side and writes out the right kind of Ada bindings. Including the parts where a mangled name is needed, like in the pragma imports.
I don't know about C++26 reflection.
But GCC has a switch to generate binding from C++ header files, see GEM#60.
This generates all Ada code with the pragma Import and CPP_Constructor including mangle names.
I fear, if the original source code (i.e. Qt) changes then mangle names change that makes your Ada code not usable any more without an additional generation that is a pain. -
@Ville-Voutilainen said in PySide6 with Python C API: EXC_BAD_ACCESS error when calling a method with inherited class from QRasterWindow:
And what I would seriously want to look at here is generating the Ada bindings via a generator that uses C++26 reflection on the C++ side and writes out the right kind of Ada bindings. Including the parts where a mangled name is needed, like in the pragma imports.
I don't know about C++26 reflection.
But GCC has a switch to generate binding from C++ header files, see GEM#60.
This generates all Ada code with the pragma Import and CPP_Constructor including mangle names.
I fear, if the original source code (i.e. Qt) changes then mangle names change that makes your Ada code not usable any more without an additional generation that is a pain.@Blady Well, the manglings change only if there's an ABI break. That doesn't happen.
-
@Blady Well, the manglings change only if there's an ABI break. That doesn't happen.
@Ville-Voutilainen thanks for the information.
The order of declaration shall be the same in C++ and Ada.
If the order change on C++ side, you must regenerate all.I guess this also implies to get the exact source code that have been used to build Qt library which has been released.
Generating Ada code from headers needs to set judiciously all defines that may differ from an OS to another.
I don't know how to cope with that.Binding of multi-inheritance classes will be an issue too.
I would like to hope that it succeeds, but I haven't seen any new elements to that end.