diff options
author | Campbell Barton <campbell@blender.org> | 2022-01-07 08:32:01 +0300 |
---|---|---|
committer | Campbell Barton <campbell@blender.org> | 2022-01-07 09:48:54 +0300 |
commit | f24854005d8688fb86cf41bd62a63580c63f818d (patch) | |
tree | 2c348e4453a199ebb54db26dba3db8ed1bce5526 /source/blender/python | |
parent | 164202831032164ed52108b4a365b9ff9ca4ac84 (diff) |
Fix T94708: negative reference count error with Python API callbacks
Regression in 7972785d7b90771f50534fe3e1101d8adb615fa3 that caused
Python callback arguments to be de-referenced twice - potentially
accessing freed memory. Making a new-file with a circle-select
tool active triggered this (for example).
Now arguments aren't de-referenced when Blender it's self has already
removed the callback handle.
Diffstat (limited to 'source/blender/python')
-rw-r--r-- | source/blender/python/intern/bpy_rna_callback.c | 16 |
1 files changed, 11 insertions, 5 deletions
diff --git a/source/blender/python/intern/bpy_rna_callback.c b/source/blender/python/intern/bpy_rna_callback.c index 16968cebab4..16ea4bf3e5e 100644 --- a/source/blender/python/intern/bpy_rna_callback.c +++ b/source/blender/python/intern/bpy_rna_callback.c @@ -383,6 +383,7 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar void *handle; StructRNA *srna; bool capsule_clear = false; + bool handle_removed = false; if (PyTuple_GET_SIZE(args) < 2) { PyErr_SetString(PyExc_ValueError, "callback_remove(handler): expected at least 2 args"); @@ -406,7 +407,7 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar args, "OO!:WindowManager.draw_cursor_remove", &cls, &PyCapsule_Type, &py_handle)) { return NULL; } - WM_paint_cursor_end(handle); + handle_removed = WM_paint_cursor_end(handle); capsule_clear = true; } else if (RNA_struct_is_a(srna, &RNA_Space)) { @@ -445,7 +446,7 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar params.region_type_enum.value_orig); return NULL; } - ED_region_draw_cb_exit(art, handle); + handle_removed = ED_region_draw_cb_exit(art, handle); capsule_clear = true; } else { @@ -453,9 +454,14 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar return NULL; } - /* The handle has been removed, so decrement its customdata. */ - PyObject *handle_args = PyCapsule_GetContext(py_handle); - Py_DECREF(handle_args); + /* When `handle_removed == false`: Blender has already freed the data + * (freeing screen data when loading a new file for example). + * This will have already decremented the user, so don't decrement twice. */ + if (handle_removed == true) { + /* The handle has been removed, so decrement its custom-data. */ + PyObject *handle_args = PyCapsule_GetContext(py_handle); + Py_DECREF(handle_args); + } /* don't allow reuse */ if (capsule_clear) { |