Fix #119384: Outliner mode column crash with shared object data #119745

Closed
Hans Goudey wants to merge 3 commits from HooglyBoogly:fix-outliner-mode-switch-crash into blender-v4.1-release

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
Member

The outliner is meant to check whether each object's data is currently
in the active mode when choosing whether to use "extend" behavior for
the mode switching column. That check worked for when the object data
is shared with the active object, but not any other object currently
in the active mode. The incorrect check caused the "extend" behavior
to turn off, making it exit edit mode for the object data without
handing the other objects using the data.

The simplest way of checking whether an object's data is in the active
mode is putting all the object data in a Set. Storing the set once
when building the outliner view context also avoids quadratic cost,
since the state needs to be checked for every object.

This does raise some questions about whether the mode is a property of
the object or the object data in practice. Also, I find the way the
outliner's callback is always "toggle" rather than "enter" or "exit" is
a bit weak. And the fact that the mode switching API allows this is
unfortunate as well. But this is the most clearly correct non-invasive
change to avoid the crash.

The outliner is meant to check whether each object's data is currently in the active mode when choosing whether to use "extend" behavior for the mode switching column. That check worked for when the object data is shared with the active object, but not any other object currently in the active mode. The incorrect check caused the "extend" behavior to turn off, making it exit edit mode for the object data without handing the other objects using the data. The simplest way of checking whether an object's data is in the active mode is putting all the object data in a Set. Storing the set once when building the outliner view context also avoids quadratic cost, since the state needs to be checked for every object. This does raise some questions about whether the mode is a property of the object or the object data in practice. Also, I find the way the outliner's callback is always "toggle" rather than "enter" or "exit" is a bit weak. And the fact that the mode switching API allows this is unfortunate as well. But this is the most clearly correct non-invasive change to avoid the crash.
Hans Goudey added 1 commit 2024-03-21 14:47:19 +01:00
buildbot/vexp-code-patch-lint Build done. Details
buildbot/vexp-code-patch-linux-x86_64 Build done. Details
buildbot/vexp-code-patch-darwin-x86_64 Build done. Details
buildbot/vexp-code-patch-darwin-arm64 Build done. Details
buildbot/vexp-code-patch-windows-amd64 Build done. Details
buildbot/vexp-code-patch-coordinator Build done. Details
a91b5ab8ad
Fix #119384: Outliner mode column crash with shared object data
The outliner is meant to check whether each object's data is currently
in the active mode when choosing whether to use "extend" behavior for
the mode switching column. That check worked for when the object data
is shared with the active object, but not any other object currently
in the active mode. The incorrect check caused the "extend" behavior
to turn off, making it exit edit mode for the object data without
handing the other objects using the data.

The simplest way of checking whether an object's data is in the active
mode is putting all the object data in a Set. Storing the set once
when building the outliner view context also avoids quadratic cost,
since the state needs to be checked for every object.

This does raise some questions about whether the mode is a property of
the object or the object data in practice. Also, I find the way the
outliner's callback is always "toggle" rather than "enter" or "exit" is
a bit weak. And the fact that the mode switching API allows this is
unfortunate as well. But this is the most clearly correct non-invasive
change to avoid the crash.
Hans Goudey requested review from Philipp Oeser 2024-03-21 14:47:39 +01:00
Hans Goudey requested review from Julian Eisel 2024-03-21 14:47:39 +01:00
Hans Goudey added this to the 4.1 milestone 2024-03-21 14:47:45 +01:00
Hans Goudey added this to the User Interface project 2024-03-21 14:47:51 +01:00
Author
Member

@blender-bot build

@blender-bot build
Member

Seems fine functionality wise.

I was a bit confused why it uses BKE_view_layer_array_from_objects_in_mode_unique_data (instead of something like BKE_view_layer_array_from_objects_in_mode_params), since unique data is actually not what we want here?

OTOH, that function does not seem to actually exclude objects sharing the same data from the returned Vector (but just adjusts what is tagged LIB_TAG_DOIT -- and we are not relying on that here...). My confusion might not be justified, this is just from first glance.

Seems fine functionality wise. I was a bit confused why it uses `BKE_view_layer_array_from_objects_in_mode_unique_data` (instead of something like `BKE_view_layer_array_from_objects_in_mode_params`), since **unique data** is actually not what we want here? OTOH, that function does not seem to actually exclude objects sharing the same data from the returned Vector (but just adjusts what is tagged `LIB_TAG_DOIT` -- and we are not relying on that here...). My confusion might not be justified, this is just from first glance.
Author
Member

since unique data is actually not what we want here?

Are you sure about that? I am putting the object data IDs in a Set anyway, which means they will be unique in the end.

OTOH, that function does not seem to actually exclude objects sharing the same data from the returned Vector

I was pretty sure if only have a single object with each object data ID. If it's not working that way, I'm fairly sure it would cause bugs with other areas in Blender.

>since unique data is actually not what we want here? Are you sure about that? I am putting the object data IDs in a `Set` anyway, which means they will be unique in the end. >OTOH, that function does not seem to actually exclude objects sharing the same data from the returned Vector I was pretty sure if only have a single object with each object data ID. If it's not working that way, I'm fairly sure it would cause bugs with other areas in Blender.
Member

since unique data is actually not what we want here?

Are you sure about that? I am putting the object data IDs in a Set anyway, which means they will be unique in the end.

Oops, OK the set contains object data, not objects, should be fine then, sorry for the noise

OTOH, that function does not seem to actually exclude objects sharing the same data from the returned Vector

I was pretty sure if only have a single object with each object data ID. If it's not working that way, I'm fairly sure it would cause bugs with other areas in Blender.

Need to double-check

> >since unique data is actually not what we want here? > > Are you sure about that? I am putting the object data IDs in a `Set` anyway, which means they will be unique in the end. Oops, OK the set contains object **data**, not **objects**, should be fine then, sorry for the noise > >OTOH, that function does not seem to actually exclude objects sharing the same data from the returned Vector > > I was pretty sure if only have a single object with each object data ID. If it's not working that way, I'm fairly sure it would cause bugs with other areas in Blender. Need to double-check
Member

OTOH, that function does not seem to actually exclude objects sharing the same data from the returned Vector

I was pretty sure if only have a single object with each object data ID. If it's not working that way, I'm fairly sure it would cause bugs with other areas in Blender.

Yeah, only one object per object data. Probably cant read code well enough, might be missing something in the (iter) macros.
Would have been surprising indeed.

So only noise from my side so far (sorry for this), except I can say for this PR it is working as expected :) So +1 from me

> >OTOH, that function does not seem to actually exclude objects sharing the same data from the returned Vector > > I was pretty sure if only have a single object with each object data ID. If it's not working that way, I'm fairly sure it would cause bugs with other areas in Blender. Yeah, only one object per object data. Probably cant read code well enough, might be missing something in the (iter) macros. Would have been surprising indeed. So only noise from my side so far (sorry for this), except I can say for this PR it is working as expected :) So +1 from me
Philipp Oeser approved these changes 2024-03-21 16:18:01 +01:00
Member

First, I should say this is a way better approach than mine.

But seeing some change in behavior in normal cases.

Starting with default scene, add a monkey, so no sharing of data. Put monkey into edit mode. The outliner now properly shows the monkey with the "edit" icon and Cube shows a dot. Ctrl-click on cube's dot and they are both in the edit set and both properly show the edit icon. But ctrl-click again on cube and IT will then be only thing in edit mode (and is now the active object).

Actually with multiple objects in edit mode you can't take any single item out of the edit set.

First, I should say this is a way better approach than mine. But seeing some change in behavior in normal cases. Starting with default scene, add a monkey, so no sharing of data. Put monkey into edit mode. The outliner now properly shows the monkey with the "edit" icon and Cube shows a dot. Ctrl-click on cube's dot and they are both in the edit set and both properly show the edit icon. But ctrl-click again on cube and IT will then be only thing in edit mode (and is now the active object). Actually with multiple objects in edit mode you can't take any single item out of the edit set.
Hans Goudey added 2 commits 2024-03-21 18:36:31 +01:00
Author
Member

Thanks for the testing. Good point about the changed behavior. I can't think of a good way to fix it without splitting up the "toggle" into "enter" and "exit" each with separate "extend" behavior that properly handles shared object data.

I'm still inclined to go with this PR as-is for 4.1 so we can get the crash out of the way. The "reverse extend" behavior with the mode icon isn't documented in the tooltip, while it is for the dot.

If that sounds okay to you, we could move forward with this and I can refactor this area and fix the change in behavior for main.

Thanks for the testing. Good point about the changed behavior. I can't think of a good way to fix it without splitting up the "toggle" into "enter" and "exit" each with separate "extend" behavior that properly handles shared object data. I'm still inclined to go with this PR as-is for 4.1 so we can get the crash out of the way. The "reverse extend" behavior with the mode icon isn't documented in the tooltip, while it is for the dot. If that sounds okay to you, we could move forward with this and I can refactor this area and fix the change in behavior for `main`.
Member

Digging deeper, this is what I see now...

We load that sample file, and see that "Suzanne.001" has "dot" icon but it is sharing a mesh with "Suzanne" which is shown as already in edit mode.

If we expand both objects to show their meshes, we see that the display of the meshes is correct, both showing as being in edit mode. It is really just a very simple bug that "Suzanne.01" is showing the wrong icon. Let's imagine simply changing that icon so it shows the edit icon.

Ctrl-click on "Suzanne.001"'s icon and it does the correct thing, which is take it OUT of edit mode. do_outliner_item_editmode_toggle works as it is supposed to, and only crashes when we get to ED_undo_push. But that crash is not related to "Suzanne.001" but to ""Suzanne".

What happens is we are changing the edit mode of "Suzanne.001", and afterward that object is no longer in mode OB_MODE_EDIT and it's data->edit_mesh becomes null.

But "Suzanne" is still in OB_MODE_EDIT, but its edit_mesh is now null. Functions like ED_undo_editmode_objects_from_view_layer just check that mode. So in ED_undo_push it ends up with a list containing an object that should be editable but has no mesh.

I can make this work as we expect if in do_outliner_item_editmode_toggle and exiting edit mode we go through all the objects, and for any that have the same data we remove OB_MODE_EDIT. And add that if we are entering edit mode.

Digging deeper, this is what I see now... We load that sample file, and see that "Suzanne.001" has "dot" icon but it is sharing a mesh with "Suzanne" which is shown as already in edit mode. If we expand both objects to show their meshes, we see that the display of the meshes is correct, both showing as being in edit mode. It is really just a very simple bug that "Suzanne.01" is showing the wrong icon. Let's imagine simply changing that icon so it shows the edit icon. Ctrl-click on "Suzanne.001"'s icon and it does the correct thing, which is take it OUT of edit mode. do_outliner_item_editmode_toggle works as it is supposed to, and only crashes when we get to `ED_undo_push`. But that crash is not related to "Suzanne.001" but to ""Suzanne". What happens is we are changing the edit mode of "Suzanne.001", and afterward that object is no longer in mode OB_MODE_EDIT and it's data->edit_mesh becomes null. But "Suzanne" is still in OB_MODE_EDIT, but its edit_mesh is now null. Functions like ED_undo_editmode_objects_from_view_layer just check that mode. So in ED_undo_push it ends up with a list containing an object that should be editable but has no mesh. I can make this work as we expect if in do_outliner_item_editmode_toggle and exiting edit mode we go through all the objects, and for any that have the same data we remove OB_MODE_EDIT. And add that if we are entering edit mode.
Author
Member

Looks like #119759 is better than this one.

Looks like #119759 is better than this one.
Hans Goudey closed this pull request 2024-03-21 20:28:38 +01:00

Pull request closed

Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
3 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#119745
No description provided.