[Bf-blender-cvs] [e72b86d3cba] blender-v3.2-release: Fix T98469: Crash trying to add an object to a linked collection that is linked to multiple scenes.

Bastien Montagne noreply at git.blender.org
Wed Jun 1 15:04:39 CEST 2022


Commit: e72b86d3cba8c7366bee2e92162f3b07bf367f3d
Author: Bastien Montagne
Date:   Wed Jun 1 12:44:11 2022 +0200
Branches: blender-v3.2-release
https://developer.blender.org/rBe72b86d3cba8c7366bee2e92162f3b07bf367f3d

Fix T98469: Crash trying to add an object to a linked collection that is linked to multiple scenes.

Crash happened because code could not find a valid base in current scene
after adding the object, added some checks for that.

Root of the issue was wrong assumptions in `BKE_object_add` logic, which
would pick the first valid ancestor collection in case initially
selected collection was not editable. In some case, this could pick a
collection not instanced in the current scene's view layer, leading to
not getting a valid base for the newly added object.

Addressed this by adding a new variant of `BKE_collection_object_add`,
`BKE_collection_viewlayer_object_add`, which ensures final collection is
in given viewlayer.

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

M	source/blender/blenkernel/BKE_collection.h
M	source/blender/blenkernel/intern/collection.c
M	source/blender/blenkernel/intern/object.cc
M	source/blender/editors/object/object_add.cc

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

diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
index a3bbcc8687a..41d369ae9b2 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -115,6 +115,18 @@ bool BKE_collection_is_empty(const struct Collection *collection);
 bool BKE_collection_object_add(struct Main *bmain,
                                struct Collection *collection,
                                struct Object *ob);
+
+/**
+ * Add object to given collection, similar to #BKE_collection_object_add.
+ *
+ * However, it additionnally ensures that the selected collection is also part of the given
+ * `view_layer`, if non-NULL. Otherwise, the object is not added to any collection.
+ */
+bool BKE_collection_viewlayer_object_add(struct Main *bmain,
+                                         const struct ViewLayer *view_layer,
+                                         struct Collection *collection,
+                                         struct Object *ob);
+
 /**
  * Same as #BKE_collection_object_add, but unconditionally adds the object to the given collection.
  *
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 76c6dc1d5e7..b71bcef229a 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -996,9 +996,11 @@ static void collection_tag_update_parent_recursive(Main *bmain,
   }
 }
 
-static Collection *collection_parent_editable_find_recursive(Collection *collection)
+static Collection *collection_parent_editable_find_recursive(const ViewLayer *view_layer,
+                                                             Collection *collection)
 {
-  if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY(collection)) {
+  if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY(collection) &&
+      (view_layer == NULL || BKE_view_layer_has_collection(view_layer, collection))) {
     return collection;
   }
 
@@ -1009,10 +1011,16 @@ static Collection *collection_parent_editable_find_recursive(Collection *collect
   LISTBASE_FOREACH (CollectionParent *, collection_parent, &collection->parents) {
     if (!ID_IS_LINKED(collection_parent->collection) &&
         !ID_IS_OVERRIDE_LIBRARY(collection_parent->collection)) {
+      if (view_layer != NULL &&
+          !BKE_view_layer_has_collection(view_layer, collection_parent->collection)) {
+        /* In case this parent collection is not in given view_layer, there is no point in
+         * searching in its ancestors either, we can skip that whole parenting branch. */
+        continue;
+      }
       return collection_parent->collection;
     }
     Collection *editable_collection = collection_parent_editable_find_recursive(
-        collection_parent->collection);
+        view_layer, collection_parent->collection);
     if (editable_collection != NULL) {
       return editable_collection;
     }
@@ -1109,12 +1117,24 @@ bool BKE_collection_object_add_notest(Main *bmain, Collection *collection, Objec
 }
 
 bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
+{
+  return BKE_collection_viewlayer_object_add(bmain, NULL, collection, ob);
+}
+
+bool BKE_collection_viewlayer_object_add(Main *bmain,
+                                         const ViewLayer *view_layer,
+                                         Collection *collection,
+                                         Object *ob)
 {
   if (collection == NULL) {
     return false;
   }
 
-  collection = collection_parent_editable_find_recursive(collection);
+  collection = collection_parent_editable_find_recursive(view_layer, collection);
+
+  if (collection == NULL) {
+    return false;
+  }
 
   return BKE_collection_object_add_notest(bmain, collection, ob);
 }
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index 2a25d73ed87..0bc092bec4f 100644
--- a/source/blender/blenkernel/intern/object.cc
+++ b/source/blender/blenkernel/intern/object.cc
@@ -2271,10 +2271,14 @@ Object *BKE_object_add(Main *bmain, ViewLayer *view_layer, int type, const char
   Object *ob = object_add_common(bmain, view_layer, type, name);
 
   LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
-  BKE_collection_object_add(bmain, layer_collection->collection, ob);
+  BKE_collection_viewlayer_object_add(bmain, view_layer, layer_collection->collection, ob);
 
+  /* Note: There is no way to be sure that #BKE_collection_viewlayer_object_add will actually
+   * manage to find a valid collection in given `view_layer` to add the new object to. */
   Base *base = BKE_view_layer_base_find(view_layer, ob);
-  BKE_view_layer_base_select_and_set_active(view_layer, base);
+  if (base != nullptr) {
+    BKE_view_layer_base_select_and_set_active(view_layer, base);
+  }
 
   return ob;
 }
diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc
index 20b9844ac89..e486d606e91 100644
--- a/source/blender/editors/object/object_add.cc
+++ b/source/blender/editors/object/object_add.cc
@@ -621,9 +621,16 @@ Object *ED_object_add_type_with_obdata(bContext *C,
   else {
     ob = BKE_object_add(bmain, view_layer, type, name);
   }
-  BASACT(view_layer)->local_view_bits = local_view_bits;
-  /* editor level activate, notifiers */
-  ED_object_base_activate(C, view_layer->basact);
+
+  Base *ob_base_act = BASACT(view_layer);
+  /* While not getting a valid base is not a good thing, it can happen in convoluted corner cases,
+   * better not crash on it in releases. */
+  BLI_assert(ob_base_act != nullptr);
+  if (ob_base_act != nullptr) {
+    ob_base_act->local_view_bits = local_view_bits;
+    /* editor level activate, notifiers */
+    ED_object_base_activate(C, ob_base_act);
+  }
 
   /* more editor stuff */
   ED_object_base_init_transform_on_add(ob, loc, rot);



More information about the Bf-blender-cvs mailing list