[Bf-blender-cvs] [0a34fec56a2] master: Fix T86561: Edit-mode crash with multiple objects sharing a mesh

Campbell Barton noreply at git.blender.org
Tue Mar 16 09:34:48 CET 2021


Commit: 0a34fec56a2f8d051a1348d4e82049e063ffcc37
Author: Campbell Barton
Date:   Tue Mar 16 18:36:34 2021 +1100
Branches: master
https://developer.blender.org/rB0a34fec56a2f8d051a1348d4e82049e063ffcc37

Fix T86561: Edit-mode crash with multiple objects sharing a mesh

Use a for loop that always begins with the active object,
instead of moving the active object in the array,
which failed when it's data already being handled.

While the existing logic could have been fixed,
it's simpler to change the loop order.

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

M	source/blender/editors/undo/ed_undo.c

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

diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index 7d8f72f3779..989863b34af 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -911,9 +911,7 @@ void ED_undo_object_editmode_restore_helper(struct bContext *C,
  * and local collections may be used.
  * \{ */
 
-static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer,
-                                                         Object *obact,
-                                                         int *r_active_index)
+static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer, Object *obact)
 {
   const short object_type = obact->type;
 
@@ -929,9 +927,6 @@ static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer,
   LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
     Object *ob = base->object;
     if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
-      if (ob == obact) {
-        *r_active_index = len;
-      }
       ID *id = ob->data;
       if ((id->tag & LIB_TAG_DOIT) == 0) {
         len += 1;
@@ -944,16 +939,18 @@ static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer,
 
 Object **ED_undo_editmode_objects_from_view_layer(ViewLayer *view_layer, uint *r_len)
 {
-  Object *obact = OBACT(view_layer);
-  if ((obact == NULL) || (obact->mode & OB_MODE_EDIT) == 0) {
+  Base *baseact = BASACT(view_layer);
+  if ((baseact == NULL) || (baseact->object->mode & OB_MODE_EDIT) == 0) {
     return MEM_mallocN(0, __func__);
   }
-  int active_index = 0;
-  const int len = undo_editmode_objects_from_view_layer_prepare(view_layer, obact, &active_index);
-  const short object_type = obact->type;
+  const int len = undo_editmode_objects_from_view_layer_prepare(view_layer, baseact->object);
+  const short object_type = baseact->object->type;
   int i = 0;
   Object **objects = MEM_malloc_arrayN(len, sizeof(*objects), __func__);
-  LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
+  /* Base iteration, starting with the active-base to ensure it's the first item in the array.
+   * Looping over the active-base twice is OK as the tag check prevents it being handled twice. */
+  for (Base *base = baseact, *base_next = FIRSTBASE(view_layer); base;
+       base = base_next, base_next = base_next ? base_next->next : NULL) {
     Object *ob = base->object;
     if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
       ID *id = ob->data;
@@ -964,25 +961,25 @@ Object **ED_undo_editmode_objects_from_view_layer(ViewLayer *view_layer, uint *r
     }
   }
   BLI_assert(i == len);
-  if (active_index > 0) {
-    SWAP(Object *, objects[0], objects[active_index]);
-  }
+  BLI_assert(objects[0] == baseact->object);
   *r_len = len;
   return objects;
 }
 
 Base **ED_undo_editmode_bases_from_view_layer(ViewLayer *view_layer, uint *r_len)
 {
-  Object *obact = OBACT(view_layer);
-  if ((obact == NULL) || (obact->mode & OB_MODE_EDIT) == 0) {
+  Base *baseact = BASACT(view_layer);
+  if ((baseact == NULL) || (baseact->object->mode & OB_MODE_EDIT) == 0) {
     return MEM_mallocN(0, __func__);
   }
-  int active_index = 0;
-  const int len = undo_editmode_objects_from_view_layer_prepare(view_layer, obact, &active_index);
-  const short object_type = obact->type;
+  const int len = undo_editmode_objects_from_view_layer_prepare(view_layer, baseact->object);
+  const short object_type = baseact->object->type;
   int i = 0;
   Base **base_array = MEM_malloc_arrayN(len, sizeof(*base_array), __func__);
-  LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
+  /* Base iteration, starting with the active-base to ensure it's the first item in the array.
+   * Looping over the active-base twice is OK as the tag check prevents it being handled twice. */
+  for (Base *base = BASACT(view_layer), *base_next = FIRSTBASE(view_layer); base;
+       base = base_next, base_next = base_next ? base_next->next : NULL) {
     Object *ob = base->object;
     if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
       ID *id = ob->data;
@@ -992,10 +989,9 @@ Base **ED_undo_editmode_bases_from_view_layer(ViewLayer *view_layer, uint *r_len
       }
     }
   }
+
   BLI_assert(i == len);
-  if (active_index > 0) {
-    SWAP(Base *, base_array[0], base_array[active_index]);
-  }
+  BLI_assert(base_array[0] == baseact);
   *r_len = len;
   return base_array;
 }



More information about the Bf-blender-cvs mailing list