Make NodePath copy-on-write, to avoid it changing accidentally (through copies)#113204
Make NodePath copy-on-write, to avoid it changing accidentally (through copies)#113204Ivorforce wants to merge 1 commit into
NodePath copy-on-write, to avoid it changing accidentally (through copies)#113204Conversation
|
For reference, |
|
As said in RC my thoughts are, that in a way it would be nicer to make it fully But if that is difficult then COW should work. |
|
This looks good to me, but there does appear to be a caller to |
Funny, that was added after the PR was created. I added it back. |
This changes
NodePathto copy-on-write on mutation, protecting owners ofNodePaththat assume it'sconst/ pass-by-value (which is likely all owners).Effectively, this might fix a few obscure
NodePathrelated bugs (explained later), at no cost to reading, and little cost to writing.Explanation
NodePathhas no exposed mutating function. By all accounts, it could be assumed thatNodePathis completelyconst. It is also passed by reference internally (NodePathis a pointer to a payload).However,
NodePathis not fullyconst, because there are two internal functions (effectively 3, foreshadowing...) that mutate it in-place:simplify()andprepend_period. Coupled with the pass-by-reference semantics, this means that anyNodePathyou own could change under you without you knowing, just because you accepted (or passed out) a copy of it, which was actually a reference. For example,Node::path_cachecould be accidentally mutated, which would leave it with an incorrect path cache, leading to obscure bugs.simplify()is called in only two places on newly createdNodePathinstances, so it should be safe.(called once now). This means we're safe, right?prepend_period()is not called at all.Nope, because
simplify()is actually used in the implementation ofsimplified(). This means that every call tosimplified()actually modifies the calleeNodePathin-place, even though it's marked asconst. The function is called in 7 places inresource_format_text, all of which might be affected by this (rather obscure) bug. On the bright side, theNodePathwould at worst only be simplified, not changed, but it still is unexpected.We discussed the situation in a core meeting, and decided to make
NodePathfullyconstto fix this issue.However, looking at the implementation, i have decided
CoWis actually more appropriate after all. The reason is that this approach was both simpler to implement and more efficient to execute.Note that
constandcopy-on-writeare the same thing in implementation, except thatcopy-on-writehas mutating methods (that only affect the held instance).Note
I removed
prepend_periodbecause it has no callers. If there's desire to keep it (like for modules?) we could add a_copy_on_writecall to it instead and keep it.