Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Montagne <bastien@blender.org>2021-04-23 13:28:54 +0300
committerBastien Montagne <bastien@blender.org>2021-04-23 15:34:47 +0300
commit9afa738542881cf69aa89fd893351200324c107f (patch)
tree6bf979900fd5a7712e261c2a52da6ea70df116b3 /source/blender/blenkernel/intern/collection.c
parent5441f5fc90c600aa5bbd08c8cd212fb0734f86cc (diff)
Fix bug/crash in ID bulk deletion code.
This is complex situation. Tagged ID deletion (used to delete several data-blocks at once) removes IDs to be deleted from Main. But when we remove deleted IDs' usages of other IDs (using `BKE_libblock_relink_ex`), some specific post-process is required on some types, like Collections. Those post-processes would in some cases rely on data actually being in Main. That failing condition would lead in existing code on missing processing the very ID (collection) we were working on, leading to missing removing some child collection pointers, leading to the crash (later on in LayerCollection resync process). For now we go with an optimization & fix that avoids processing all collections in Main when we actually know which one we are working one (case of `BKE_libblock_relink_ex`, but not of `BKE_libblock_remap_locked`). This is however yet another demonstration of the need to rework that whole collection/layer resync process, since it is not only extremely inneficient currently, but it also requires valid Main/ID state way too deep into the remapping code. NOTE: This fix may very well not catch/address all possible fail cases here, dealing with the double parent/child relationships of collections is challenging... Issue reported by @eyecandy from the studio, thanks.
Diffstat (limited to 'source/blender/blenkernel/intern/collection.c')
-rw-r--r--source/blender/blenkernel/intern/collection.c49
1 files changed, 29 insertions, 20 deletions
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 89bb7b36406..b29dd007c51 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -1302,41 +1302,50 @@ static void collection_missing_parents_remove(Collection *collection)
*
* \note caller must ensure #BKE_main_collection_sync_remap() is called afterwards!
*
- * \param collection: may be \a NULL,
+ * \param parent_collection: The collection owning the pointers that were remapped. May be \a NULL,
+ * in which case whole \a bmain database of collections is checked.
+ * \param child_collection: The collection that was remapped to another pointer. May be \a NULL,
* in which case whole \a bmain database of collections is checked.
*/
-void BKE_collections_child_remove_nulls(Main *bmain, Collection *collection)
-{
- if (collection == NULL) {
- /* We need to do the checks in two steps when more than one collection may be involved,
- * otherwise we can miss some cases...
- * Also, master collections are not in bmain, so we also need to loop over scenes.
- */
- for (collection = bmain->collections.first; collection != NULL;
- collection = collection->id.next) {
- collection_null_children_remove(collection);
- }
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
- collection_null_children_remove(scene->master_collection);
+void BKE_collections_child_remove_nulls(Main *bmain,
+ Collection *parent_collection,
+ Collection *child_collection)
+{
+ if (child_collection == NULL) {
+ if (parent_collection != NULL) {
+ collection_null_children_remove(parent_collection);
+ }
+ else {
+ /* We need to do the checks in two steps when more than one collection may be involved,
+ * otherwise we can miss some cases...
+ * Also, master collections are not in bmain, so we also need to loop over scenes.
+ */
+ for (child_collection = bmain->collections.first; child_collection != NULL;
+ child_collection = child_collection->id.next) {
+ collection_null_children_remove(child_collection);
+ }
+ for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ collection_null_children_remove(scene->master_collection);
+ }
}
- for (collection = bmain->collections.first; collection != NULL;
- collection = collection->id.next) {
- collection_missing_parents_remove(collection);
+ for (child_collection = bmain->collections.first; child_collection != NULL;
+ child_collection = child_collection->id.next) {
+ collection_missing_parents_remove(child_collection);
}
for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
collection_missing_parents_remove(scene->master_collection);
}
}
else {
- for (CollectionParent *parent = collection->parents.first, *parent_next; parent;
+ for (CollectionParent *parent = child_collection->parents.first, *parent_next; parent;
parent = parent_next) {
parent_next = parent->next;
collection_null_children_remove(parent->collection);
- if (!collection_find_child(parent->collection, collection)) {
- BLI_freelinkN(&collection->parents, parent);
+ if (!collection_find_child(parent->collection, child_collection)) {
+ BLI_freelinkN(&child_collection->parents, parent);
}
}
}