-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Fix GH-12192: SimpleXML infinite loop when getName() is called within foreach #12193
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
Conversation
…hin foreach This happens because getName() resets the iterator to the start because it overwrites the iterator data. We add a version of get_first_node that does not overwrite the iterator data.
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 don't understand why the iterator is overridden in the first place tho.
Thanks for the review. Unfortunately, I found that this patch is incomplete. I have pushed an additional commit that changes the test and fixes the code. It turns out that I missed a place where the iterator data was thrown away.
SimpleXMLElement objects (called sxe for short) have the behaviour of an iterator. For example, when we write
$xml itself has the following data in its sxe:
As a side note, I prefer the term "view" instead of iterator, because the fields are clearly used as a filtering mechanism to create a specific way to "view" a node. The internal functions of ext/simplexml all use an iterator-like API. Consequently, they are implemented in such a way that they overwrite the iterator data. As the iterator data is also used for the current item in a foreach loop, this may cause trouble as we see in this PR. So we must be careful by using the iterator functions, which is why I introduced non-destructive variants for some. So why does $xml->a->getName() use the internal iterator API? Well, we can't use |
It's also worth noting that this behaviour differs now: <?php
$xml = "<root><a>1</a><a>2</a></root>";
$xml = simplexml_load_string($xml);
$a = $xml->a;
var_dump($a->getName());
var_dump($a->current()); Previously, |
Many methods in SimpleXML reset the iterator when called. This has the consequence that mixing these operations with loops can cause infinite loops, or the loss of iteration data. Some people may however rely on the resetting behaviour. To prevent unintended breaks in stable branches, let's only apply the fix to master. This reverts GH-12193, GH-12229, GG-12247 for stable branches while keeping them on master, adding a note in UPGRADING as well.
This happens because getName() resets the iterator to the start because it overwrites the iterator data.
We add a version of get_first_node that does not overwrite the iterator data.