Skip to content

Fix bug #80332 Completely broken array access functionality with DOMNamedNodeMap #10829

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

Closed
wants to merge 1 commit into from

Conversation

NathanFreeman
Copy link
Contributor

@NathanFreeman NathanFreeman commented Mar 11, 2023

https://bugs.php.net/bug.php?id=80332

The function zval_get_long will always return 0 if the offset is string, resulting in always pointing to the first element of the array.

@NathanFreeman
Copy link
Contributor Author

Can you help me review this pr? @cmb69 @Girgias @devnexen @nielsdos

@devnexen
Copy link
Member

Thanks for confidence but I know too little about the dom extension 🙂.

@NathanFreeman
Copy link
Contributor Author

Thanks for confidence but I know too little about the dom extension 🙂.

Thank you!

@NathanFreeman
Copy link
Contributor Author

cc @beberlei
Do you have a minute to review it?

@Girgias
Copy link
Member

Girgias commented Mar 13, 2023

Can you help me review this pr? @cmb69 @Girgias @devnexen @nielsdos

Sadly I don't know anything either about DOM :/

@NathanFreeman
Copy link
Contributor Author

NathanFreeman commented Mar 14, 2023

Is there any other developer who know more about extension dom? 😭 @Girgias

@nielsdos
Copy link
Member

I'm also not the best person to review this as I only did 2/3 fixes to XML/DOM in the past. Usually Christoph seems to review these DOM/XML changes but he seems quite busy. I could take a look this weekend to see if it kinda makes sense or if there are obvious mistakes, but won't be able to approve it due to my lack of expertise in this area.

@NathanFreeman
Copy link
Contributor Author

#10682
If possible, can you review this pr together? @nielsdos

Copy link
Member

@nielsdos nielsdos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So as I previously said, I'm not a DOM expert.
I checked the original bug report and there the reporter complained that non-numeric strings are silently converted to 0. This patch attempts to fix it by special casing numeric strings, but in doing so it unfortunately breaks some existing use cases.
Still, I think the general idea behind this patch makes sense, just the approach needs some additional work to fix the newly introduced issues.

I also wonder how much of a BC break fixing this is, even with my remarks fixed.

@@ -21,6 +21,7 @@
#endif

#include "php.h"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't do unrelated whitespace changes.

} else if (Z_TYPE_P(offset) == IS_STRING && is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), &lval, NULL, false) == IS_LONG) {
ZVAL_LONG(&offset_copy, lval);
} else {
return NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can't just return NULL here, because in that case read_dimension() expects to get an exception.
i.e. the following code (from the bug report) will crash PHP with an assertion failure in debug mode:

<?php

$doc = new DOMDocument;
$doc->loadHTML('<a href="https://example.com">hi!</a>');
$a = (new DOMXPath($doc))->query('//a')[0];
$a->attributes['href']->nodeValue = 'https://example.net';
print $doc->saveHTML();

zend_long lval;
if (Z_TYPE_P(offset) == IS_LONG) {
ZVAL_LONG(&offset_copy, Z_LVAL_P(offset));
} else if (Z_TYPE_P(offset) == IS_STRING && is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), &lval, NULL, false) == IS_LONG) {
Copy link
Member

@nielsdos nielsdos Mar 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a pretty big behavioural change, and a BC break.
Offsets like 0.0, false, null previously worked and would all implicitly convert to 0. Now it would result in a NULL element. Similarly, true would be converted to 1 but now it also always results in NULL. In particular it's also dangerous that floating point numbers that don't have a decimal part will now break silently.

I think you need to place the numeric string check first, and only then fall back using zval_get_long which will do these kind of converts for you.
Perhaps an even better solution is just adding proper support for using $a->attributes["my_attribute_name_here"], which is what the original bug report complained about. But I think that's not the expected API, so the current idea to check for numeric strings might be fine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the ZPP (something like zend_parse_parameter_long() in Zend_API.h) API might make a lot of sense for this use case as it will already handle those weird cases. Another possible function, which is not a public API is zendi_try_get_long() defined in zend_operators.c

@nielsdos
Copy link
Member

nielsdos commented Nov 1, 2023

No longer relevant as I fixed this in another way some months ago. Thanks for your interest anyway!

@nielsdos nielsdos closed this Nov 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants