Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <campbell@blender.org>2022-01-07 08:32:01 +0300
committerCampbell Barton <campbell@blender.org>2022-01-07 09:48:54 +0300
commitf24854005d8688fb86cf41bd62a63580c63f818d (patch)
tree2c348e4453a199ebb54db26dba3db8ed1bce5526
parent164202831032164ed52108b4a365b9ff9ca4ac84 (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.h2
-rw-r--r--source/blender/editors/space_api/spacetypes.c5
-rw-r--r--source/blender/python/intern/bpy_rna_callback.c16
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 f4a69737da1..fb76b36baef 100644
--- a/source/blender/editors/include/ED_space_api.h
+++ b/source/blender/editors/include/ED_space_api.h
@@ -86,7 +86,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 93d023c8bb4..f8adba30547 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -248,15 +248,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 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) {