PyAPI: report unreleased ID's with WITH_PYTHON_SAFETY enabled

This would have made T88033 more straightforward to track down.
This commit is contained in:
2021-08-11 17:29:26 +10:00
parent cbc671947a
commit f3e26c847b
4 changed files with 38 additions and 26 deletions

View File

@@ -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());

View File

@@ -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();

View File

@@ -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. */

View File

@@ -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);