[Bf-blender-cvs] [cbc671947a3] master: Fix T88033: Python reference memory leaks for non main data-blocks

Campbell Barton noreply at git.blender.org
Wed Aug 11 09:38:53 CEST 2021


Commit: cbc671947a3baca3da7d6c5a2980a86b7f6a7055
Author: Campbell Barton
Date:   Wed Aug 11 16:56:11 2021 +1000
Branches: master
https://developer.blender.org/rBcbc671947a3baca3da7d6c5a2980a86b7f6a7055

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 fac5dc8c010..5de669cb620 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 38397f8f307..f566e18fb2f 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -521,6 +521,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 a9407860c06..43afac5a376 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 4f0b2a718ed..ca57038f1c4 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -1802,6 +1802,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 1bf95369794..bd22f049a8b 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -3194,6 +3194,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 f592b0f97ea..60edb78f8ba 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -4761,6 +4761,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 c55185c0f2a..5ecd9b7283e 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -446,6 +446,7 @@ static void scene_free_data(ID *id)
    * collections in the scene need to do it too? */
   if (scene->master_collection) {
     BKE_collection_free_data(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 67b4fd61d38..834ef847069 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 37089785e0e..56e72fbeca9 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 7367f73d171..98edc133a1d 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -531,6 +531,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 9657f8aa03c..e11ef52eb84 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