Skip to content

Fix negative SimpleXML offsets aliasing the first element - #23068

Open
iliaal wants to merge 1 commit into
php:PHP-8.4from
iliaal:fix/sxe-negative-offset
Open

Fix negative SimpleXML offsets aliasing the first element#23068
iliaal wants to merge 1 commit into
php:PHP-8.4from
iliaal:fix/sxe-negative-offset

Conversation

@iliaal

Copy link
Copy Markdown
Contributor

sxe_get_element_by_offset scans with nodendx <= offset, which is already false on the first iteration for a negative offset, so it returns the node it was given. $xml->item[-1] therefore reports isset() true and reads the first item. Assigning to it overwrites $xml->item[0]. Negative offsets now miss, and writing to one warns like an out-of-range positive offset instead of creating an element.

sxe_get_element_by_offset scanned with nodendx <= offset, so a negative
offset skipped the loop and returned the node it started from. Reads and
isset() reported the first element, and a write overwrote it. Negative
offsets now miss, and writing to one warns like an out-of-range positive
offset instead of creating a node.
ClosesphpGH-23068
@devnexen

Copy link
Copy Markdown
Member

is a bug indeed, however can the following test being added ?

--TEST--
Integer offsets that cannot resolve must never alias or mutate a node
--EXTENSIONS--
simplexml
--FILE--
<?phpfunctionfresh(): SimpleXMLElement {
returnsimplexml_load_string('<r a="1" b="2"><item>a</item><item>b</item><item>c</item></r>');
}
functionstate(SimpleXMLElement $x): string {
returntrim(strstr($x->asXML(), '<r'));
}
echo'== element list ==', PHP_EOL;
$x = fresh();
var_dump(isset($x->item[-1]));
var_dump($x->item[-1]);
$x->item[-1] = 'Z';
echostate($x), PHP_EOL;
unset($x->item[-1]);
echostate($x), PHP_EOL;
echo'== single element (SXE_ITER_NONE) ==', PHP_EOL;
$x = fresh();
$n = $x->item[0];
var_dump(isset($n[-1]));
var_dump($n[-1]);
$n[-1] = 'Z';
echostate($x), PHP_EOL;
$n[5] = 'Y';
echostate($x), PHP_EOL;
unset($n[-1]);
echostate($x), PHP_EOL;
echo'== nested write ==', PHP_EOL;
$x = fresh();
try {
$x->item[-1]->kid = 'K';
} catch (Throwable$e) {
echoget_class($e), ': ', $e->getMessage(), PHP_EOL;
}
echostate($x), PHP_EOL;
echo'== attributes ==', PHP_EOL;
$x = fresh();
$at = $x->attributes();
var_dump(isset($at[-1]));
var_dump($at[-1]);
$at[-1] = 'z';
echostate($x), PHP_EOL;
?>
--EXPECTF--
== element list ==
bool(false)
NULL
Warning: main(): Cannot add element item number -1 when only 3 such elements exist in %s on line %d
<r a="1" b="2"><item>a</item><item>b</item><item>c</item></r>
<r a="1" b="2"><item>a</item><item>b</item><item>c</item></r>
== single element (SXE_ITER_NONE) ==
bool(false)
NULL
Warning: main(): Cannot add element item number -1 when only 0 such %d
<r a="1" b="2"><item>a</item><item>b</item><item>c</item></r>
Warning: main(): Cannot add element item number 5 when only 0 such elements exist in %s on line %d
<r a="1" b="2"><item>a</item><item>b</item><item>c</item></r>
<r a="1" b="2"><item>a</item><item>b</item><item>c</item></r>
== nested write ==
ValueError: Cannot use a negative offset
<r a="1" b="2"><item>a</item><item>b</item><item>c</item></r>
== attributes ==
bool(false)
NULL

Sign up for freeto 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

@iliaal@devnexen