[Bf-blender-cvs] [06ecdab9bc6] blender-v2.93-release: Fix T88033: Python reference memory leaks for non main data-blocks

Campbell Barton noreply at git.blender.org
Mon Aug 23 09:35:48 CEST 2021


Commit: 06ecdab9bc6a7ec43fbf7906fc6db6520a73f465
Author: Campbell Barton
Date:   Wed Aug 11 16:56:11 2021 +1000
Branches: blender-v2.93-release
https://developer.blender.org/rB06ecdab9bc6a7ec43fbf7906fc6db6520a73f465

Fix T88033: Python reference memory leaks for non main data-blocks

ID data-blocks that could be accessed from Python and weren't freed
using BKE_id_free_ex did not release the Python reference count.

Add BKE_libblock_free_data_py function to clear the Python reference
in this case.

Add asserts to ensure no Python reference is held in situations
when ID's are copied for internal use (not exposed through the RNA API),
to ensure these kinds of leaks don't go by unnoticed again.

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

M	source/blender/blenkernel/BKE_lib_id.h
M	source/blender/blenkernel/intern/gpencil.c
M	source/blender/blenkernel/intern/lib_id_delete.c
M	source/blender/blenkernel/intern/material.c
M	source/blender/blenkernel/intern/node.cc
M	source/blender/blenkernel/intern/particle_system.c
M	source/blender/blenkernel/intern/scene.c
M	source/blender/editors/space_clip/clip_editor.c
M	source/blender/gpu/intern/gpu_material.c
M	source/blender/nodes/shader/node_shader_tree.c
M	source/blender/windowmanager/intern/wm.c

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

diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h
index 6b706f3bcd0..62a39abf755 100644
--- a/source/blender/blenkernel/BKE_lib_id.h
+++ b/source/blender/blenkernel/BKE_lib_id.h
@@ -201,6 +201,8 @@ enum {
 void BKE_libblock_free_datablock(struct ID *id, const int flag) ATTR_NONNULL();
 void BKE_libblock_free_data(struct ID *id, const bool do_id_user) ATTR_NONNULL();
 
+void BKE_libblock_free_data_py(struct ID *id);
+
 void BKE_id_free_ex(struct Main *bmain, void *idv, int flag, const bool use_flag_from_idtag);
 void BKE_id_free(struct Main *bmain, void *idv);
 
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 182d06f8f72..13cee6d9e6a 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -513,6 +513,7 @@ void BKE_gpencil_eval_delete(bGPdata *gpd_eval)
 {
   BKE_gpencil_free(gpd_eval, true);
   BKE_libblock_free_data(&gpd_eval->id, false);
+  BLI_assert(!gpd_eval->id.py_instance); /* Or call #BKE_libblock_free_data_py. */
   MEM_freeN(gpd_eval);
 }
 
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index 67b2e4429d6..f17c64942d4 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -142,14 +142,7 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
     DEG_id_type_tag(bmain, type);
   }
 
-#ifdef WITH_PYTHON
-#  ifdef WITH_PYTHON_SAFETY
-  BPY_id_release(id);
-#  endif
-  if (id->py_instance) {
-    BPY_DECREF_RNA_INVALIDATE(id->py_instance);
-  }
-#endif
+  BKE_libblock_free_data_py(id);
 
   Key *key = ((flag & LIB_ID_FREE_NO_MAIN) == 0) ? BKE_key_from_id(id) : NULL;
 
@@ -406,3 +399,29 @@ size_t BKE_id_multi_tagged_delete(Main *bmain)
 {
   return id_delete(bmain, true);
 }
+
+/* -------------------------------------------------------------------- */
+/** \name Python Data Handling
+ * \{ */
+
+/**
+ * In most cases #BKE_id_free_ex handles this, when lower level functions are called directly
+ * this function will need to be called too, if Python has access to the data.
+ *
+ * ID data-blocks such as #Material.nodetree are not stored in #Main.
+ */
+void BKE_libblock_free_data_py(ID *id)
+{
+#ifdef WITH_PYTHON
+#  ifdef WITH_PYTHON_SAFETY
+  BPY_id_release(id);
+#  endif
+  if (id->py_instance) {
+    BPY_DECREF_RNA_INVALIDATE(id->py_instance);
+  }
+#else
+  UNUSED_VARS(id);
+#endif
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 8e80a4bc9ae..b3e68f97e21 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -1662,6 +1662,7 @@ void BKE_material_copybuf_free(void)
 {
   if (matcopybuf.nodetree) {
     ntreeFreeLocalTree(matcopybuf.nodetree);
+    BLI_assert(!matcopybuf.nodetree->id.py_instance); /* Or call #BKE_libblock_free_data_py. */
     MEM_freeN(matcopybuf.nodetree);
     matcopybuf.nodetree = NULL;
   }
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 68ae6963a3e..bb1c3b30880 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -3020,6 +3020,7 @@ void ntreeFreeEmbeddedTree(bNodeTree *ntree)
 {
   ntreeFreeTree(ntree);
   BKE_libblock_free_data(&ntree->id, true);
+  BKE_libblock_free_data_py(&ntree->id);
 }
 
 void ntreeFreeLocalTree(bNodeTree *ntree)
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index c727a144c87..4260f4fc5e3 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -4764,6 +4764,7 @@ static void particle_settings_free_local(ParticleSettings *particle_settings)
 {
   BKE_libblock_free_datablock(&particle_settings->id, 0);
   BKE_libblock_free_data(&particle_settings->id, false);
+  BLI_assert(!particle_settings->id.py_instance); /* Or call #BKE_libblock_free_data_py. */
   MEM_freeN(particle_settings);
 }
 
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index a4ab64a8a02..66d4b18fb83 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -444,6 +444,7 @@ static void scene_free_data(ID *id)
    * collections in the scene need to do it too? */
   if (scene->master_collection) {
     BKE_collection_free(scene->master_collection);
+    BKE_libblock_free_data_py(&scene->master_collection->id);
     MEM_freeN(scene->master_collection);
     scene->master_collection = NULL;
   }
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 2da13646a8b..01211c3ac90 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -1037,6 +1037,7 @@ static void prefetch_freejob(void *pjv)
   if (clip_local != NULL) {
     BKE_libblock_free_datablock(&clip_local->id, 0);
     BKE_libblock_free_data(&clip_local->id, false);
+    BLI_assert(!clip_local->id.py_instance); /* Or call #BKE_libblock_free_data_py. */
     MEM_freeN(clip_local);
   }
 
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 675036b31c3..29ca89b630e 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -758,6 +758,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene,
   /* Only free after GPU_pass_shader_get where GPUUniformBuf
    * read data from the local tree. */
   ntreeFreeLocalTree(localtree);
+  BLI_assert(!localtree->id.py_instance); /* Or call #BKE_libblock_free_data_py. */
   MEM_freeN(localtree);
 
   /* note that even if building the shader fails in some way, we still keep
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index 83f476884e6..8250f9accdb 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -523,6 +523,7 @@ static void ntree_shader_groups_flatten(bNodeTree *localtree)
       bNodeTree *ngroup = (bNodeTree *)node->id;
       ntreeFreeLocalNode(localtree, node);
       ntreeFreeTree(ngroup);
+      BLI_assert(!ngroup->id.py_instance); /* Or call #BKE_libblock_free_data_py. */
       MEM_freeN(ngroup);
     }
     else {
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 46e47ae95c4..b6d19847002 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -628,6 +628,7 @@ void wm_close_and_free_all(bContext *C, ListBase *wmlist)
     wm_close_and_free(C, wm);
     BLI_remlink(wmlist, wm);
     BKE_libblock_free_data(&wm->id, true);
+    BKE_libblock_free_data_py(&wm->id);
     MEM_freeN(wm);
   }
 }



More information about the Bf-blender-cvs mailing list