Skip to content

Conversation

@lawnjelly
Copy link
Member

@lawnjelly lawnjelly commented May 25, 2023

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

  • For the MRP the recheck of the idx only need to be pushed after the call to _set_tree(nullptr), but just in case any of the other calls affects the index, I've moved immediately prior to data.children.remove(idx).
  • The second ERR_FAIL message is subtly different, to enable us to distinguish between the two cases.

@lawnjelly lawnjelly added this to the 3.6 milestone May 25, 2023
@lawnjelly lawnjelly marked this pull request as ready for review May 25, 2023 18:47
@lawnjelly lawnjelly requested a review from a team as a code owner May 25, 2023 18:47
@lawnjelly lawnjelly force-pushed the fix_remove_child_idx branch from 04ab028 to b0d0bba Compare May 25, 2023 18:59
Copy link
Member

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?

Copy link
Member Author

@lawnjelly lawnjelly May 29, 2023

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.

Copy link
Member Author

@lawnjelly lawnjelly May 29, 2023

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.

Copy link
Member Author

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.
@lawnjelly lawnjelly force-pushed the fix_remove_child_idx branch from b0d0bba to 5790513 Compare May 29, 2023 09:28
@YuriSizov YuriSizov changed the title Node::remove_child() fix idx out of sync Fix index being out of sync in Node::remove_child May 29, 2023
@akien-mga akien-mga requested a review from hpvb June 7, 2023 12:29
@akien-mga akien-mga changed the title Fix index being out of sync in Node::remove_child [3.x] Fix index being out of sync in Node::remove_child Jun 7, 2023
// Child count could have changed.
child_count = data.children.size();

if ((p_child->data.pos != idx) || (idx >= child_count) || (data.children[idx] != p_child)) {
Copy link
Member Author

@lawnjelly lawnjelly Jun 12, 2023

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 providing idx < child_count in the previous)

(The first could possibly be omitted, but its cheap to check)

@lawnjelly lawnjelly modified the milestones: 3.6, 3.7 Sep 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants