From c9a4abadcc27c97f6e6206e3943a946f878459c7 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 14 Sep 2024 22:47:24 +0200 Subject: [PATCH] Fix unsetting DOM properties This never did anything in lower versions, but on master this crashes because the virtual properties don't have backing storage. Just forbid it since it was useless to begin with. Closes GH-15891. --- NEWS | 1 + ext/dom/php_dom.c | 13 ++++++++++ ext/dom/tests/unsetting_properties.phpt | 32 +++++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 ext/dom/tests/unsetting_properties.phpt diff --git a/NEWS b/NEWS index bff8b8964ea..d0d23a4dd05 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,7 @@ PHP NEWS . Fix XML serializer errata: xmlns="" serialization should be allowed. (nielsdos) . Fixed bug GH-15910 (Assertion failure in ext/dom/element.c). (nielsdos) + . Fix unsetting DOM properties. (nielsdos) - MBString: . Fixed bug GH-15824 (mb_detect_encoding(): Argument $encodings contains diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index 8198afe5b8b..346436a5627 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -478,6 +478,18 @@ static int dom_property_exists(zend_object *object, zend_string *name, int check } /* }}} */ +static void dom_unset_property(zend_object *object, zend_string *member, void **cache_slot) +{ + dom_object *obj = php_dom_obj_from_obj(object); + + if (obj->prop_handler != NULL && zend_hash_exists(obj->prop_handler, member)) { + zend_throw_error(NULL, "Cannot unset %s::$%s", ZSTR_VAL(object->ce->name), ZSTR_VAL(member)); + return; + } + + zend_std_unset_property(object, member, cache_slot); +} + static HashTable* dom_get_debug_info_helper(zend_object *object, int *is_temp) /* {{{ */ { dom_object *obj = php_dom_obj_from_obj(object); @@ -755,6 +767,7 @@ PHP_MINIT_FUNCTION(dom) dom_object_handlers.read_property = dom_read_property; dom_object_handlers.write_property = dom_write_property; dom_object_handlers.get_property_ptr_ptr = dom_get_property_ptr_ptr; + dom_object_handlers.unset_property = dom_unset_property; dom_object_handlers.clone_obj = dom_objects_store_clone_obj; dom_object_handlers.has_property = dom_property_exists; dom_object_handlers.get_debug_info = dom_get_debug_info; diff --git a/ext/dom/tests/unsetting_properties.phpt b/ext/dom/tests/unsetting_properties.phpt new file mode 100644 index 00000000000..ec309c18bf5 --- /dev/null +++ b/ext/dom/tests/unsetting_properties.phpt @@ -0,0 +1,32 @@ +--TEST-- +Unsetting properties +--EXTENSIONS-- +dom +--FILE-- +registerNodeClass('DOMElement', 'MyElement'); +$dom->loadXML('foo'); +$root = $dom->documentElement; + +unset($root->myProp); +try { + $root->myProp; +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +try { + unset($root->textContent); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Typed property MyElement::$myProp must not be accessed before initialization +Cannot unset MyElement::$textContent