diff --git a/NEWS b/NEWS index d9c1e5baf7f..d9bd26e0bde 100644 --- a/NEWS +++ b/NEWS @@ -9,12 +9,17 @@ PHP NEWS unserialize). (Nikita) . Fixed bug #74819 (wddx_deserialize() heap out-of-bound read via php_parse_date()). (Derick) - . Fixed bug #74878 (Data race in ZTS builds). (Nikita) + . Fixed bug #49649 (unserialize() doesn't handle changes in property + visibility). (pmmaga) - Date: . Fixed bug #74852 (property_exists returns true on unknown DateInterval property). (jhdxr) +- DOM: + . Implement #74837 (Implement Countable for DomNodeList and DOMNamedNodeMap). + (Andreas Treichel) + - EXIF: . Deprecated the read_exif_data() alias. (Kalle) . Fixed bug #74428 (exif_read_data(): "Illegal IFD size" warning occurs with diff --git a/UPGRADING b/UPGRADING index 7f4817ab24d..49d499b881f 100644 --- a/UPGRADING +++ b/UPGRADING @@ -224,6 +224,10 @@ See also: https://wiki.php.net/rfc/deprecations_php_7_2 . Added stream_isatty(). . Added sapi_windows_vt100_support(). +- DOM: + . DomNodeList implements Countable, added DomNodeList::count(). + . DOMNamedNodeMap implements Countable, added DOMNamedNodeMap::count(). + - GD: . Added imagesetclip() and imagegetclip(). . Added imageopenpolygon(). diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 609e8b4a515..ca8b4e2f997 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -3742,10 +3742,6 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, z break; } } - - /* Must be interned to avoid ZTS data races */ - name = zend_new_interned_string(zend_string_copy(name)); - if (access_type & ZEND_ACC_PUBLIC) { property_info->name = zend_string_copy(name); } else if (access_type & ZEND_ACC_PRIVATE) { diff --git a/ext/dom/dom_fe.h b/ext/dom/dom_fe.h index 231d8402d89..6f1035a5773 100644 --- a/ext/dom/dom_fe.h +++ b/ext/dom/dom_fe.h @@ -172,6 +172,7 @@ PHP_METHOD(domnode, getLineNo); /* domnodelist methods */ PHP_FUNCTION(dom_nodelist_item); +PHP_FUNCTION(dom_nodelist_count); /* domnamednodemap methods */ PHP_FUNCTION(dom_namednodemap_get_named_item); @@ -181,6 +182,7 @@ PHP_FUNCTION(dom_namednodemap_item); PHP_FUNCTION(dom_namednodemap_get_named_item_ns); PHP_FUNCTION(dom_namednodemap_set_named_item_ns); PHP_FUNCTION(dom_namednodemap_remove_named_item_ns); +PHP_FUNCTION(dom_namednodemap_count); /* domcharacterdata methods */ PHP_FUNCTION(dom_characterdata_substring_data); diff --git a/ext/dom/namednodemap.c b/ext/dom/namednodemap.c index 4dea7be28a9..3ed426cb8e7 100644 --- a/ext/dom/namednodemap.c +++ b/ext/dom/namednodemap.c @@ -57,6 +57,9 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_namednodemap_remove_named_item_ns, 0, 0, 0) ZEND_ARG_INFO(0, namespaceURI) ZEND_ARG_INFO(0, localName) ZEND_END_ARG_INFO(); + +ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_namednodemap_count, 0, 0, 0) +ZEND_END_ARG_INFO(); /* }}} */ /* @@ -74,6 +77,7 @@ const zend_function_entry php_dom_namednodemap_class_functions[] = { /* {{{ */ PHP_FALIAS(getNamedItemNS, dom_namednodemap_get_named_item_ns, arginfo_dom_namednodemap_get_named_item_ns) PHP_FALIAS(setNamedItemNS, dom_namednodemap_set_named_item_ns, arginfo_dom_namednodemap_set_named_item_ns) PHP_FALIAS(removeNamedItemNS, dom_namednodemap_remove_named_item_ns, arginfo_dom_namednodemap_remove_named_item_ns) + PHP_FALIAS(count, dom_namednodemap_count, arginfo_dom_namednodemap_count) PHP_FE_END }; /* }}} */ @@ -332,6 +336,24 @@ PHP_FUNCTION(dom_namednodemap_remove_named_item_ns) } /* }}} end dom_namednodemap_remove_named_item_ns */ +/* {{{ proto int|bool dom_namednodemap_count(); +*/ +PHP_FUNCTION(dom_namednodemap_count) +{ + zval *id; + dom_object *intern; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &id, dom_namednodemap_class_entry) == FAILURE) { + return; + } + + intern = Z_DOMOBJ_P(id); + if(dom_namednodemap_length_read(intern, return_value) == FAILURE) { + RETURN_FALSE; + } +} +/* }}} end dom_namednodemap_count */ + #endif /* diff --git a/ext/dom/nodelist.c b/ext/dom/nodelist.c index d469467f48a..c7fbc76fd1c 100644 --- a/ext/dom/nodelist.c +++ b/ext/dom/nodelist.c @@ -34,6 +34,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_nodelist_item, 0, 0, 1) ZEND_END_ARG_INFO(); /* }}} */ +/* {{{ arginfo */ +ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_nodelist_count, 0, 0, 0) +ZEND_END_ARG_INFO(); +/* }}} */ + /* * class DOMNodeList * @@ -43,9 +48,11 @@ ZEND_END_ARG_INFO(); const zend_function_entry php_dom_nodelist_class_functions[] = { PHP_FALIAS(item, dom_nodelist_item, arginfo_dom_nodelist_item) + PHP_FALIAS(count, dom_nodelist_count, arginfo_dom_nodelist_count) PHP_FE_END }; + /* {{{ length int readonly=yes URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#ID-203510337 @@ -96,6 +103,25 @@ int dom_nodelist_length_read(dom_object *obj, zval *retval) return SUCCESS; } + +/* {{{ proto int|bool dom_nodelist_count(); +*/ +PHP_FUNCTION(dom_nodelist_count) +{ + zval *id; + dom_object *intern; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &id, dom_nodelist_class_entry) == FAILURE) { + return; + } + + intern = Z_DOMOBJ_P(id); + if(dom_nodelist_length_read(intern, return_value) == FAILURE) { + RETURN_FALSE; + } +} +/* }}} end dom_nodelist_count */ + /* }}} */ /* {{{ proto DOMNode dom_nodelist_item(int index); @@ -170,6 +196,7 @@ PHP_FUNCTION(dom_nodelist_item) } /* }}} end dom_nodelist_item */ + #endif /* diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index 6b844ab3330..77f918ae9bf 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -706,7 +706,7 @@ PHP_MINIT_FUNCTION(dom) ce.create_object = dom_nnodemap_objects_new; dom_nodelist_class_entry = zend_register_internal_class_ex(&ce, NULL); dom_nodelist_class_entry->get_iterator = php_dom_get_iterator; - zend_class_implements(dom_nodelist_class_entry, 1, zend_ce_traversable); + zend_class_implements(dom_nodelist_class_entry, 2, zend_ce_traversable, zend_ce_countable); zend_hash_init(&dom_nodelist_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1); dom_register_prop_handler(&dom_nodelist_prop_handlers, "length", sizeof("length")-1, dom_nodelist_length_read, NULL); @@ -716,7 +716,7 @@ PHP_MINIT_FUNCTION(dom) ce.create_object = dom_nnodemap_objects_new; dom_namednodemap_class_entry = zend_register_internal_class_ex(&ce, NULL); dom_namednodemap_class_entry->get_iterator = php_dom_get_iterator; - zend_class_implements(dom_namednodemap_class_entry, 1, zend_ce_traversable); + zend_class_implements(dom_namednodemap_class_entry, 2, zend_ce_traversable, zend_ce_countable); zend_hash_init(&dom_namednodemap_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1); dom_register_prop_handler(&dom_namednodemap_prop_handlers, "length", sizeof("length")-1, dom_namednodemap_length_read, NULL); diff --git a/ext/dom/tests/DOMNamedNodeMap_count.phpt b/ext/dom/tests/DOMNamedNodeMap_count.phpt new file mode 100644 index 00000000000..656dd4859ef --- /dev/null +++ b/ext/dom/tests/DOMNamedNodeMap_count.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test count nodes in DOMNamedNodeMap +--CREDITS-- +Andreas Treichel +--SKIPIF-- + +--FILE-- +createElement('root'); +$document->appendChild($root); +for($i = 0; $i < 5; $i++) { + $root->setAttribute('attribute-' . $i, 'value-' . $i); +} +for($i = 0; $i < 7; $i++) { + $item = $document->createElement('item'); + $root->appendChild($item); +} +var_dump($root->attributes->length); +var_dump($root->attributes->count()); +var_dump(count($root->attributes)); + +?> +--EXPECTF-- +int(5) +int(5) +int(5) diff --git a/ext/dom/tests/DomNodeList_count.phpt b/ext/dom/tests/DomNodeList_count.phpt new file mode 100644 index 00000000000..3ebf4ae7d2e --- /dev/null +++ b/ext/dom/tests/DomNodeList_count.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test count nodes in DOMNodeList +--CREDITS-- +Andreas Treichel +--SKIPIF-- + +--FILE-- +createElement('root'); +$document->appendChild($root); +for($i = 0; $i < 5; $i++) { + $root->setAttribute('attribute-' . $i, 'value-' . $i); +} +for($i = 0; $i < 7; $i++) { + $item = $document->createElement('item'); + $root->appendChild($item); +} +var_dump($root->childNodes->length); +var_dump($root->childNodes->count()); +var_dump(count($root->childNodes)); + +?> +--EXPECTF-- +int(7) +int(7) +int(7) diff --git a/ext/standard/tests/serialize/bug49649.phpt b/ext/standard/tests/serialize/bug49649.phpt new file mode 100644 index 00000000000..2e0a5059301 --- /dev/null +++ b/ext/standard/tests/serialize/bug49649.phpt @@ -0,0 +1,45 @@ +--TEST-- +Bug #49649 (unserialize() doesn't handle changes in property visibility) - to public +--FILE-- + + int(3) + ["protected"]=> + int(2) + ["private"]=> + int(1) + ["notThere"]=> + string(3) "old" +} diff --git a/ext/standard/tests/serialize/bug49649_1.phpt b/ext/standard/tests/serialize/bug49649_1.phpt new file mode 100644 index 00000000000..1ca840a9b61 --- /dev/null +++ b/ext/standard/tests/serialize/bug49649_1.phpt @@ -0,0 +1,45 @@ +--TEST-- +Bug #49649 (unserialize() doesn't handle changes in property visibility) - to protected +--FILE-- + + int(3) + ["protected":protected]=> + int(2) + ["private":protected]=> + int(1) + ["notThere"]=> + string(3) "old" +} diff --git a/ext/standard/tests/serialize/bug49649_2.phpt b/ext/standard/tests/serialize/bug49649_2.phpt new file mode 100644 index 00000000000..e9fe4290de8 --- /dev/null +++ b/ext/standard/tests/serialize/bug49649_2.phpt @@ -0,0 +1,45 @@ +--TEST-- +Bug #49649 (unserialize() doesn't handle changes in property visibility) - to private +--FILE-- + + int(3) + ["protected":"Foo":private]=> + int(2) + ["private":"Foo":private]=> + int(1) + ["notThere"]=> + string(3) "old" +} diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 185e62d0f58..6e7f76fea2e 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -427,14 +427,58 @@ numeric_key: } else { if (EXPECTED(Z_TYPE(key) == IS_STRING)) { string_key: - if ((old_data = zend_hash_find(ht, Z_STR(key))) != NULL) { - if (Z_TYPE_P(old_data) == IS_INDIRECT) { - old_data = Z_INDIRECT_P(old_data); + { + zend_property_info *existing_propinfo; + zend_string *new_key, *unmangled; + const char *unmangled_class = NULL; + const char *unmangled_prop; + size_t unmangled_prop_len; + + if (UNEXPECTED(zend_unmangle_property_name_ex(Z_STR(key), &unmangled_class, &unmangled_prop, &unmangled_prop_len) == FAILURE)) { + zval_dtor(&key); + return 0; + } + + unmangled = zend_string_init(unmangled_prop, unmangled_prop_len, 0); + if (Z_TYPE_P(rval) == IS_OBJECT + && ((existing_propinfo = zend_hash_find_ptr(&Z_OBJCE_P(rval)->properties_info, unmangled)) != NULL) + && (existing_propinfo->flags & ZEND_ACC_PPP_MASK)) { + if (existing_propinfo->flags & ZEND_ACC_PROTECTED) { + new_key = zend_mangle_property_name( + "*", 1, ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), Z_OBJCE_P(rval)->type & ZEND_INTERNAL_CLASS); + zend_string_release(unmangled); + } else if (existing_propinfo->flags & ZEND_ACC_PRIVATE) { + if (unmangled_class != NULL && strcmp(unmangled_class, "*") != 0) { + new_key = zend_mangle_property_name( + unmangled_class, strlen(unmangled_class), + ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), + Z_OBJCE_P(rval)->type & ZEND_INTERNAL_CLASS); + } else { + new_key = zend_mangle_property_name( + ZSTR_VAL(existing_propinfo->ce->name), ZSTR_LEN(existing_propinfo->ce->name), + ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), + Z_OBJCE_P(rval)->type & ZEND_INTERNAL_CLASS); + } + zend_string_release(unmangled); + } else { + ZEND_ASSERT(existing_propinfo->flags & ZEND_ACC_PUBLIC); + new_key = unmangled; + } + zend_string_release(Z_STR(key)); + Z_STR(key) = new_key; + } else { + zend_string_release(unmangled); + } + + if ((old_data = zend_hash_find(ht, Z_STR(key))) != NULL) { + if (Z_TYPE_P(old_data) == IS_INDIRECT) { + old_data = Z_INDIRECT_P(old_data); + } + var_push_dtor(var_hash, old_data); + data = zend_hash_update_ind(ht, Z_STR(key), &d); + } else { + data = zend_hash_add_new(ht, Z_STR(key), &d); } - var_push_dtor(var_hash, old_data); - data = zend_hash_update_ind(ht, Z_STR(key), &d); - } else { - data = zend_hash_add_new(ht, Z_STR(key), &d); } } else if (Z_TYPE(key) == IS_LONG) { /* object properties should include no integers */