-
-
Notifications
You must be signed in to change notification settings - Fork 23.5k
[3.x] Fix index being out of sync in Node::remove_child
#77483
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
base: 3.x
Are you sure you want to change the base?
Conversation
04ab028 to
b0d0bba
Compare
scene/main/node.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this safe in this context? I might be misunderstanding this change, it seems that if we mess this up we can't really be sure that p_child is still pointing to what we think it is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
p_child is still pointing to the correct child, the issue is that the idx of the child (i.e. position in the childlist) can change during the pre-deletion, which is the mechanism of the bug in the issue.
The ERR_FAIL here should not happen unless something really bad is going on, like p_child is being removed as a child during the pre-delete. This is very likely not possible, but this ERR_FAIL is more a fail safe to prevent a crash in this scenario, and indicate where the problem is occurring. As this if clause should be pretty rare anyway, there's no cost to adding an ERR_FAIL here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah there is a potential bug here though, I forgot to reget child_count as it could have changed. Will fix. 👍
DONE.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to reiterate, p_child will still point to the same child in the same area of memory, as children are non-relocatable - it is only the index that may change.
In rare circumstances, the index of the child to be removed can get out of sync during the routine. We detect this scenario and recalculate the index, preventing corruption of the children.
b0d0bba to
5790513
Compare
Node::remove_child
Node::remove_childNode::remove_child
| // Child count could have changed. | ||
| child_count = data.children.size(); | ||
|
|
||
| if ((p_child->data.pos != idx) || (idx >= child_count) || (data.children[idx] != p_child)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't write a comment here, but just to make it clear for review, there are three possibilities here (for detecting a change to p_child's index):
- The child itself knows that its index has changed
- The previous index is now outside the range of the new child count
- The child of the parent given by the index is no longer
p_child(this can be checked providingidx < child_countin the previous)
(The first could possibly be omitted, but its cheap to check)
In rare circumstances, the index of the child to be removed can get out of sync during the routine. We detect this scenario and recalculate the index, preventing corruption of the children.
Fixes #77480
Notes
_set_tree(nullptr), but just in case any of the other calls affects the index, I've moved immediately prior todata.children.remove(idx).ERR_FAILmessage is subtly different, to enable us to distinguish between the two cases.