[Bf-blender-cvs] [3b686b82335] blender-v3.0-release: Fix T94708: negative reference count error with Python API callbacks

Campbell Barton noreply at git.blender.org
Tue Jan 11 10:38:39 CET 2022


Commit: 3b686b823353e02a4c0b8dbfcbe176caaec2438d
Author: Campbell Barton
Date:   Fri Jan 7 16:32:01 2022 +1100
Branches: blender-v3.0-release
https://developer.blender.org/rB3b686b823353e02a4c0b8dbfcbe176caaec2438d

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.

===================================================================

M	source/blender/editors/include/ED_space_api.h
M	source/blender/editors/space_api/spacetypes.c
M	source/blender/python/intern/bpy_rna_callback.c

===================================================================

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) {



More information about the Bf-blender-cvs mailing list