-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Prevent infinite loop in revealing algorithms #11457
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: main
Are you sure you want to change the base?
Conversation
The ancestor details revealing algorithm and the hidden until found revealing algorithm may both get stuck in infinite loops because they iterate the flat tree while firing synchronous events. If the page were to listen to these events and change the flat tree in response, then the algorithm could theoretically never end. Fixes whatwg#11436
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.
Editorially LGTM, although some implementer review from @nt1m and/or @jnjaeschke would be appreciated.
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 think going through every single ancestor twice is very unefficient. The second loop should only go through relevant elements, rather than all of the ancestors again. I know it may result in some behavior difference in some very specific edge cases, but I'd rather have an efficient algorithm here.
Yeah, this seems like the right time to combine these algorithms so we only do a single tree walk. That's an observable change in behavior due to the events, but I think it's very much an acceptable one. And if we ever add more cases we care about we don't end up with ever more ancestor walks. |
Just to be clear, I was pointing out that the current PR collects all the ancestors into a list for both algorithms, instead of only the relevant ones for each algorithm, which is different from what Anne mentioned in the previous comment. (But having 1 reveal algorithm instead of 2 separate ones as Anne suggests wouldn't be something I'm opposed to, if the change in order of events/revealing makes sense for web developers) |
@nt1m and I discussed this some more and while in theory you could do a single ancestor walk and collect the nodes to dispatch events on in separate lists depending on the feature, my suspicion is that it would be more useful for web developers if the events are also collapsed into a single reverse-tree-ordered list. |
Thanks, I combined the algorithms and only stored relevant nodes for the second traversal. How does it look? |
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.
After we fire the first event, do we want to check for each node we go through that it's still connected?
And maybe check that the pre-conditions are still valid?
And maybe that if any of that is no longer true, we return early as we're no longer sure what we're dealing with.
I added checks to make sure that each ancestor to reveal is still connected and still has the open attribute if its a details or still has hidden=until-found otherwise, and stop the algorithm if any of those are not true |
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.
Looks pretty good. Couple of nits.
source
Outdated
<li><p>If <var>ancestorToReveal</var> does not have the <code | ||
data-x="attr-details-open">open</code> attribute, then return.</p></li> |
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 think you mean "If ancestorToReveal has the open attribute", though I don't think you want to early return either way 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.
Why would we not want to return early if the circumstances have changed since we started collecting the nodes?
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.
Returning early means bailing out of the whole algorithm, including other details & hidden=until-found ancestors (e.g. not just the current details element).
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.
Yeah I know. I suggested that above. I don't see a reason to continue if web developers have started mutating the tree to this extent.
<li> | ||
<p>If <var>currentNode</var> has the <code data-x="attr-hidden">hidden</code> attribute in the | ||
<span data-x="attr-hidden-until-found-state">Hidden Until Found</span> state, then:</p> | ||
<p>Otherwise:</p> |
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.
Not sure if Otherwise is right here, What if the details element also has the hidden=until-found attribute?
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.
Ok, I changed the otherwise and some other conditions to account for this. How does it look?
The ancestor details revealing algorithm and the hidden until found revealing algorithm may both get stuck in infinite loops because they iterate the flat tree while firing synchronous events. If the page were to listen to these events and change the flat tree in response, then the algorithm could theoretically never end.
Fixes #11436
(See WHATWG Working Mode: Changes for more details.)
/browsing-the-web.html ( diff )
/interaction.html ( diff )
/interactive-elements.html ( diff )