diff options
author | Campbell Barton <campbell@blender.org> | 2022-01-07 08:32:01 +0300 |
---|---|---|
committer | Philipp Oeser <info@graphics-engineer.com> | 2022-01-11 12:31:04 +0300 |
commit | 3b686b823353e02a4c0b8dbfcbe176caaec2438d (patch) | |
tree | 6d20af241cfb3576516ae1fd45f7270e760b9b33 | |
parent | 4c8740a45217fc9cc5c4f668695cdf6e7d446ec1 (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.
-rw-r--r-- | source/blender/editors/include/ED_space_api.h | 2 | ||||
-rw-r--r-- | source/blender/editors/space_api/spacetypes.c | 5 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_rna_callback.c | 16 |
3 files changed, 15 insertions, 8 deletions
diff --git a/source/blender/editors/include/ED_space_api.h b/source/blender/editors/include/ED_space_api.h index 958df8f7707..5e96905a465 100644 --- a/source/blender/editors/include/ED_space_api.h +++ b/source/blender/editors/include/ED_space_api.h @@ -74,7 +74,7 @@ void *ED_region_draw_cb_activate(struct ARegionType *art, int type); void ED_region_draw_cb_draw(const struct bContext *C, struct ARegion *region, int type); void ED_region_surface_draw_cb_draw(struct ARegionType *art, int type); -void ED_region_draw_cb_exit(struct ARegionType *art, void *handle); +bool ED_region_draw_cb_exit(struct ARegionType *art, void *handle); void ED_region_draw_cb_remove_by_type(struct ARegionType *art, void *draw_fn, void (*free)(void *)); diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index 149067a94fe..24595dbeb48 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -253,15 +253,16 @@ void *ED_region_draw_cb_activate(ARegionType *art, return rdc; } -void ED_region_draw_cb_exit(ARegionType *art, void *handle) +bool ED_region_draw_cb_exit(ARegionType *art, void *handle) { LISTBASE_FOREACH (RegionDrawCB *, rdc, &art->drawcalls) { if (rdc == (RegionDrawCB *)handle) { BLI_remlink(&art->drawcalls, rdc); MEM_freeN(rdc); - return; + return true; } } + return false; } static void ed_region_draw_cb_draw(const bContext *C, ARegion *region, ARegionType *art, int type) diff --git a/source/blender/python/intern/bpy_rna_callback.c b/source/blender/python/intern/bpy_rna_callback.c index c19d9ba47b1..346b967cb97 100644 --- a/source/blender/python/intern/bpy_rna_callback.c +++ b/source/blender/python/intern/bpy_rna_callback.c @@ -380,6 +380,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"); @@ -403,7 +404,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)) { @@ -442,7 +443,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 { @@ -450,9 +451,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) { |