Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix panic: invalid SlotMap key used #13990

Merged
merged 1 commit into from
Jun 24, 2024

Conversation

eidloi
Copy link

@eidloi eidloi commented Jun 23, 2024

Objective

Tight, in-frame generation, re-parenting, despawning, etc., UI operations could sometime lead taffy to panic (invalid SlotMap key used) when an entity with an invalid state later despawned.

Fixes #12403

Solution

Move the remove_entities call after children updates.

Testing

sickle_ui had a case that always caused the panic. Tested before this change, after this change, and before the change again to make sure the error is there without the fix. The fix worked. Test steps and used commit described in issue #12403.

I have also ran every bevy UI example, though none of them deal with entity re-parenting or removal. No regression detected on them.

Tested on Windows only.

Copy link
Contributor

Welcome, new contributor!

Please make sure you've read our contributing guide and we look forward to reviewing your pull request shortly ✨

@eidloi
Copy link
Author

eidloi commented Jun 23, 2024

Wish I had the time to create a proper test suite for this.

@alice-i-cecile alice-i-cecile added this to the 0.14 milestone Jun 23, 2024
@alice-i-cecile alice-i-cecile added C-Bug An unexpected or incorrect behavior A-UI Graphical user interfaces, styles, layouts, and widgets S-Needs-Review Needs reviewer attention (from anyone!) to move forward A-Rendering Drawing game state to the screen labels Jun 23, 2024
@brandon-reinhart
Copy link
Contributor

Looks good to me.

Copy link
Member

@mockersf mockersf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not absolutely confident this doesn't have side effects, but I can't think of any and it makes sense to me

@eidloi
Copy link
Author

eidloi commented Jun 23, 2024

@nicoburns perhaps has a strong opinion?

@nicoburns
Copy link
Contributor

nicoburns commented Jun 23, 2024

I do not have strong opinions on this. My disposition is similar to:

not absolutely confident this doesn't have side effects, but I can't think of any and it makes sense to me

@StrikeForceZero
Copy link
Contributor

StrikeForceZero commented Jun 23, 2024

No longer relavent ~~so this is likely the offending area triggering the crash https://github.com/bevyengine/bevy/blob/158ccc6d6a45eb048cc3f40388f9cff0fc633375/crates/bevy_ui/src/layout/ui_surface.rs#L128-L131~~

Because we are unwrapping the internalmap/taffy result with the parent entity who would have already been removed by the line this PR is moving.

I did a little sanity check to double check:

Index: crates/bevy_ui/src/layout/mod.rs
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/crates/bevy_ui/src/layout/mod.rs b/crates/bevy_ui/src/layout/mod.rs
--- a/crates/bevy_ui/src/layout/mod.rs	(revision Staged)
+++ b/crates/bevy_ui/src/layout/mod.rs	(date 1719178048091)
@@ -276,7 +276,8 @@
     }
 
     // clean up removed nodes
-    ui_surface.remove_entities(removed_components.removed_nodes.read());
+    let removed_nodes = removed_components.removed_nodes.read().collect::<HashSet<_>>();
+    ui_surface.remove_entities(removed_nodes.clone().into_iter());
 
     // clean up removed cameras
     ui_surface.remove_camera_entities(removed_components.removed_cameras.read());
@@ -298,6 +299,9 @@
     }
     for (entity, children) in &children_query {
         if children.is_changed() {
+            if removed_nodes.contains(&entity) {
+                continue;
+            }
             ui_surface.update_children(entity, &children);
         }
     }

and this does in fact prevent the crash as well, but obviously (or at least imo) moving the line down below makes more sense.

~~The part that confuses me is the tests I made for this specific condition fail when run on main but pass in my PR, yet don't prevent the crash in your reproduction example..

So, I'm inclined to believe there is some kind of race condition or alternative behavior I'm not aware of triggering this, and

I think moving the line is the way to go for 14.0.

If we want to have a test suite that covers some of this, I can extract my regression tests mentioned above into their own PR after this gets merged.


Edit: I need to walk away from the computer for a bit, but I think I've cleared my confusion. I will confirm later tonight when I have more time.

@StrikeForceZero
Copy link
Contributor

I can't create a regression test that mimics the slotkey error. It's likely related to moving a UI node to a new parent and despawning the old one.

Regardless, this is a good fix. Intuitively, you'd need to perform operations on all the children and ensure they are in sync on the taffy's side before removing the UI node.

IMO it's highly unlikely this will introduce any negative side effects. Especially considering how the layout system is already omitting the handling of other hierarchy changes that I've been meaning to open tickets for 🙃

@eidloi
Copy link
Author

eidloi commented Jun 24, 2024

it does bother me to no end that I don't have the bare basic broken test case myself, but the slotmap ends up in the erroneous state way earlier than when the despawn trips it.

@janhohenheim janhohenheim added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jun 24, 2024
@mockersf mockersf added this pull request to the merge queue Jun 24, 2024
Merged via the queue into bevyengine:main with commit 87fa69b Jun 24, 2024
33 checks passed
mockersf pushed a commit that referenced this pull request Jun 25, 2024
# Objective

Tight, in-frame generation, re-parenting, despawning, etc., UI
operations could sometime lead taffy to panic (invalid SlotMap key used)
when an entity with an invalid state later despawned.

Fixes #12403 

## Solution

Move the `remove_entities` call after children updates.

## Testing

`sickle_ui` had a case that always caused the panic. Tested before this
change, after this change, and before the change again to make sure the
error is there without the fix. The fix worked. Test steps and used
commit described in issue #12403.

I have also ran every bevy UI example, though none of them deal with
entity re-parenting or removal. No regression detected on them.

Tested on Windows only.
@eidloi eidloi deleted the fix_invalid_slotmap_key_used_panic branch June 27, 2024 19:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen A-UI Graphical user interfaces, styles, layouts, and widgets C-Bug An unexpected or incorrect behavior S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Despawned UI Nodes' parents' children need to be updated in UiSurface BEFORE despawn
7 participants