From f3e26c847b6ba0924cfd02641345164c54234425 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 11 Aug 2021 17:29:26 +1000 Subject: PyAPI: report unreleased ID's with WITH_PYTHON_SAFETY enabled This would have made T88033 more straightforward to track down. --- source/blender/python/intern/bpy.c | 3 -- source/blender/python/intern/bpy_interface.c | 7 +++- source/blender/python/intern/bpy_rna.c | 53 ++++++++++++++++------------ source/blender/python/intern/bpy_rna.h | 1 + 4 files changed, 38 insertions(+), 26 deletions(-) (limited to 'source/blender') diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 30a61067c9e..0e0f431cb19 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -417,9 +417,6 @@ void BPy_init_modules(struct bContext *C) PyDict_SetItemString(PyImport_GetModuleDict(), "_bpy", mod); Py_DECREF(mod); - /* run first, initializes rna types */ - BPY_rna_init(); - /* needs to be first so bpy_types can run */ PyModule_AddObject(mod, "types", BPY_rna_types()); diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 35450e3eaad..945933dd8b7 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -502,7 +502,10 @@ void BPY_python_start(bContext *C, int argc, const char **argv) } #endif - /* bpy.* and lets us import it */ + /* Run first, initializes RNA types. */ + BPY_rna_init(); + + /* Defines `bpy.*` and lets us import it. */ BPy_init_modules(C); pyrna_alloc_types(); @@ -541,6 +544,8 @@ void BPY_python_end(void) /* free other python data. */ pyrna_free_types(); + BPY_rna_exit(); + /* clear all python data from structs */ bpy_intern_string_exit(); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index b83c13e1974..17cbf8e4569 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -181,23 +181,13 @@ static PyMethodDef id_free_weakref_cb_def = { /* Adds a reference to the list, remember to decref. */ static GHash *id_weakref_pool_get(ID *id) { - GHash *weakinfo_hash = NULL; - - if (id_weakref_pool) { - weakinfo_hash = BLI_ghash_lookup(id_weakref_pool, (void *)id); - } - else { - /* First time, allocate pool. */ - id_weakref_pool = BLI_ghash_ptr_new("rna_global_pool"); - weakinfo_hash = NULL; - } - + GHash *weakinfo_hash = BLI_ghash_lookup(id_weakref_pool, (void *)id); if (weakinfo_hash == NULL) { - /* We use a ghash as a set, we could use libHX's HXMAP_SINGULAR, but would be an extra dep. */ + /* This could be a set, values are used to keep a reference back to the ID + * (all of them are the same). */ weakinfo_hash = BLI_ghash_ptr_new("rna_id"); BLI_ghash_insert(id_weakref_pool, id, weakinfo_hash); } - return weakinfo_hash; } @@ -283,14 +273,6 @@ static void id_release_weakref_list(struct ID *id, GHash *weakinfo_hash) BLI_ghash_remove(id_weakref_pool, (void *)id, NULL, NULL); BLI_ghash_free(weakinfo_hash, NULL, NULL); - - if (BLI_ghash_len(id_weakref_pool) == 0) { - BLI_ghash_free(id_weakref_pool, NULL, NULL); - id_weakref_pool = NULL; -# ifdef DEBUG_RNA_WEAKREF - printf("id_release_weakref freeing pool\n"); -# endif - } } static void id_release_weakref(struct ID *id) @@ -310,7 +292,8 @@ void BPY_id_release(struct ID *id) #endif #ifdef USE_PYRNA_INVALIDATE_WEAKREF - if (id_weakref_pool) { + /* Check for NULL since this may run before Python has been started. */ + if (id_weakref_pool != NULL) { PyGILState_STATE gilstate = PyGILState_Ensure(); id_release_weakref(id); @@ -7776,6 +7759,32 @@ void BPY_rna_init(void) return; } #endif + +#ifdef USE_PYRNA_INVALIDATE_WEAKREF + BLI_assert(id_weakref_pool == NULL); + id_weakref_pool = BLI_ghash_ptr_new("rna_global_pool"); +#endif +} + +void BPY_rna_exit(void) +{ +#ifdef USE_PYRNA_INVALIDATE_WEAKREF + /* This can help track down which kinds of data were not released. + * If they were in fact freed by Blender, printing their names + * will crash giving a useful error with address sanitizer. The likely cause + * for this list not being empty is a missing call to: #BKE_libblock_free_data_py. */ + const int id_weakref_pool_len = BLI_ghash_len(id_weakref_pool); + if (id_weakref_pool_len != id_weakref_pool_len) { + printf("Found %d unreleased ID's\n", id_weakref_pool_len); + GHashIterator gh_iter; + GHASH_ITER (gh_iter, id_weakref_pool) { + ID *id = BLI_ghashIterator_getKey(&gh_iter); + printf("ID: %s\n", id->name); + } + } + BLI_ghash_free(id_weakref_pool, NULL, NULL); + id_weakref_pool = NULL; +#endif } /* 'bpy.data' from Python. */ diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h index 24dbad53eb3..fd468bed470 100644 --- a/source/blender/python/intern/bpy_rna.h +++ b/source/blender/python/intern/bpy_rna.h @@ -181,6 +181,7 @@ StructRNA *srna_from_self(PyObject *self, const char *error_prefix); StructRNA *pyrna_struct_as_srna(PyObject *self, const bool parent, const char *error_prefix); void BPY_rna_init(void); +void BPY_rna_exit(void); PyObject *BPY_rna_module(void); void BPY_update_rna_module(void); // PyObject *BPY_rna_doc(void); -- cgit v1.2.3