Skip to content

Commit 8389d3f

Browse files
jcfrmrbean-bremen
authored andcommitted
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 331ad3b commit 8389d3f

File tree

1 file changed

+26
-0
lines changed

1 file changed

+26
-0
lines changed

src/PythonQtInstanceWrapper.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,9 @@ 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_RETURN_NOTIMPLEMENTED;
228+
}
226229
bool validPtrs = false;
227230
bool areSamePtrs = false;
228231
if (PyObject_TypeCheck((PyObject*)wrapper, &PythonQtInstanceWrapper_Type)) {
@@ -335,6 +338,10 @@ static PyObject *PythonQtInstanceWrapper_classname(PythonQtInstanceWrapper* obj)
335338

336339
PyObject *PythonQtInstanceWrapper_inherits(PythonQtInstanceWrapper* obj, PyObject *args)
337340
{
341+
if (PythonQt::self() == nullptr || PythonQt::priv() == nullptr) {
342+
PyErr_SetString(PyExc_RuntimeError, "PythonQt is not initialized (or has been finalized)");
343+
return nullptr;
344+
}
338345
char *name = nullptr;
339346
if (!PyArg_ParseTuple(args, "s:PythonQtInstanceWrapper.inherits",&name)) {
340347
return nullptr;
@@ -344,11 +351,17 @@ PyObject *PythonQtInstanceWrapper_inherits(PythonQtInstanceWrapper* obj, PyObjec
344351

345352
static PyObject *PythonQtInstanceWrapper_help(PythonQtInstanceWrapper* obj)
346353
{
354+
if (PythonQt::self() == nullptr || PythonQt::priv() == nullptr) {
355+
Py_RETURN_NONE;
356+
}
347357
return PythonQt::self()->helpCalled(obj->classInfo());
348358
}
349359

350360
PyObject *PythonQtInstanceWrapper_delete(PythonQtInstanceWrapper * self)
351361
{
362+
if (PythonQt::self() == nullptr || PythonQt::priv() == nullptr) {
363+
Py_RETURN_NONE;
364+
}
352365
PythonQtMemberInfo deleteSlot = self->classInfo()->member("py_delete");
353366
if (deleteSlot._type == PythonQtMemberInfo::Slot) {
354367
// call the py_delete slot instead of internal C++ destructor...
@@ -380,6 +393,9 @@ static PyMethodDef PythonQtInstanceWrapper_methods[] = {
380393

381394
static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
382395
{
396+
if (PythonQt::self() == nullptr || PythonQt::priv() == nullptr) {
397+
return PyObject_GenericGetAttr(obj, name);
398+
}
383399
const char *attributeName;
384400
PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
385401

@@ -611,6 +627,10 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
611627

612628
static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObject *value)
613629
{
630+
if (PythonQt::self() == nullptr || PythonQt::priv() == nullptr) {
631+
PyErr_SetString(PyExc_AttributeError, "PythonQt is not initialized (or has been finalized); cannot set attributes on this wrapper");
632+
return -1;
633+
}
614634
QString error;
615635
const char *attributeName;
616636
PythonQtInstanceWrapper *wrapper = (PythonQtInstanceWrapper *)obj;
@@ -763,6 +783,9 @@ static QString getStringFromObject(PythonQtInstanceWrapper* wrapper) {
763783

764784
static PyObject * PythonQtInstanceWrapper_str(PyObject * obj)
765785
{
786+
if (PythonQt::self() == nullptr || PythonQt::priv() == nullptr) {
787+
return PyUnicode_New(0, 0);
788+
}
766789
PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
767790

768791
// QByteArray should be directly returned as a str
@@ -808,6 +831,9 @@ static PyObject * PythonQtInstanceWrapper_str(PyObject * obj)
808831

809832
static PyObject * PythonQtInstanceWrapper_repr(PyObject * obj)
810833
{
834+
if (PythonQt::self() == nullptr || PythonQt::priv() == nullptr) {
835+
return PyUnicode_New(0, 0);
836+
}
811837
PythonQtInstanceWrapper* wrapper = (PythonQtInstanceWrapper*)obj;
812838
const char* typeName = obj->ob_type->tp_name;
813839

0 commit comments

Comments
 (0)