Skip to content

Commit 006dcb5

Browse files
committed
fix: guard InstanceWrapper during cleanup and Py_Finalize
During interpreter shutdown, Python objects may still invoke wrapper methods after `PythonQt::cleanup()` has nullified internals, leading to "heap-use-after-free". This commit adds guards and fallbacks.
1 parent bfc5b5c commit 006dcb5

File tree

1 file changed

+29
-0
lines changed

1 file changed

+29
-0
lines changed

src/PythonQtInstanceWrapper.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,10 @@ int PythonQtInstanceWrapper_init(PythonQtInstanceWrapper * self, PyObject * args
223223

224224
static PyObject *PythonQtInstanceWrapper_richcompare(PythonQtInstanceWrapper* wrapper, PyObject* other, int code)
225225
{
226+
if (PythonQt::self() == nullptr || PythonQt::priv() == nullptr) {
227+
Py_INCREF(Py_NotImplemented);
228+
return Py_NotImplemented;
229+
}
226230
bool validPtrs = false;
227231
bool areSamePtrs = false;
228232
if (PyObject_TypeCheck((PyObject*)wrapper, &PythonQtInstanceWrapper_Type)) {
@@ -339,6 +343,10 @@ static PyObject *PythonQtInstanceWrapper_classname(PythonQtInstanceWrapper* obj)
339343

340344
PyObject *PythonQtInstanceWrapper_inherits(PythonQtInstanceWrapper* obj, PyObject *args)
341345
{
346+
if (PythonQt::self() == nullptr || PythonQt::priv() == nullptr) {
347+
PyErr_SetString(PyExc_RuntimeError, "PythonQt is not initialized (or has been finalized)");
348+
return nullptr;
349+
}
342350
char *name = nullptr;
343351
if (!PyArg_ParseTuple(args, "s:PythonQtInstanceWrapper.inherits",&name)) {
344352
return nullptr;
@@ -348,11 +356,19 @@ PyObject *PythonQtInstanceWrapper_inherits(PythonQtInstanceWrapper* obj, PyObjec
348356

349357
static PyObject *PythonQtInstanceWrapper_help(PythonQtInstanceWrapper* obj)
350358
{
359+
if (PythonQt::self() == nullptr || PythonQt::priv() == nullptr) {
360+
Py_INCREF(Py_None);
361+
return Py_None;
362+
}
351363
return PythonQt::self()->helpCalled(obj->classInfo());
352364
}
353365

354366
PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self)
355367
{
368+
if (PythonQt::self() == nullptr || PythonQt::priv() == nullptr) {
369+
Py_INCREF(Py_None);
370+
return Py_None;
371+
}
356372
PythonQtMemberInfo deleteSlot = self->classInfo()->member("py_delete");
357373
if (deleteSlot._type == PythonQtMemberInfo::Slot) {
358374
// call the py_delete slot instead of internal C++ destructor...
@@ -385,6 +401,9 @@ static PyMethodDef PythonQtInstanceWrapper_methods[] = {
385401

386402
static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
387403
{
404+
if (PythonQt::self() == nullptr || PythonQt::priv() == nullptr) {
405+
return PyObject_GenericGetAttr(obj, name);
406+
}
388407
const char *attributeName;
389408
PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
390409

@@ -617,6 +636,10 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
617636

618637
static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
619638
{
639+
if (PythonQt::self() == nullptr || PythonQt::priv() == nullptr) {
640+
PyErr_SetString(PyExc_AttributeError, "PythonQt is not initialized (or has been finalized); cannot set attributes on this wrapper");
641+
return -1;
642+
}
620643
QString error;
621644
const char *attributeName;
622645
PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
@@ -769,6 +792,9 @@ static QString getStringFromObject(PythonQtInstanceWrapper* wrapper) {
769792

770793
static PyObject * PythonQtInstanceWrapper_str(PyObject * obj)
771794
{
795+
if (PythonQt::self() == nullptr || PythonQt::priv() == nullptr) {
796+
return PyUnicode_New(0, 0);
797+
}
772798
PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
773799

774800
// QByteArray should be directly returned as a str
@@ -814,6 +840,9 @@ static PyObject * PythonQtInstanceWrapper_str(PyObject * obj)
814840

815841
static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj)
816842
{
843+
if (PythonQt::self() == nullptr || PythonQt::priv() == nullptr) {
844+
return PyUnicode_New(0, 0);
845+
}
817846
PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
818847
const char* typeName = obj->ob_type->tp_name;
819848

0 commit comments

Comments
 (0)