diff --git a/NEWS b/NEWS index 98c8d3b3106b..92b6ffc6e8fa 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,8 @@ PHP NEWS the null namespace in spec-following mode. (Ilia Alshanetsky) . Fixed stale getElementsByClassName() and other node list caches after className/classList writes and attribute removals. (Ilia Alshanetsky) + . Fixed a reference cycle through DOMXPath php:function callback + arguments not being collectable. (Ilia Alshanetsky) - Hash: . Fixed hash_file() reporting argument #1 ($algo) instead of argument #2 diff --git a/ext/dom/tests/DOMXPath_callback_node_list_gc.phpt b/ext/dom/tests/DOMXPath_callback_node_list_gc.phpt new file mode 100644 index 000000000000..7e68224e390e --- /dev/null +++ b/ext/dom/tests/DOMXPath_callback_node_list_gc.phpt @@ -0,0 +1,28 @@ +--TEST-- +DOMXPath callback node list is reported to the cycle collector +--EXTENSIONS-- +dom +--FILE-- +loadXML(''); +$xp = new DOMXPath($doc); +$xp->registerNamespace('php', 'http://php.net/xpath'); +$xp->registerPhpFunctions(); + +function cb($n) { + @$n[0]->back = $GLOBALS['the_xp']; + return true; +} + +$GLOBALS['the_xp'] = $xp; +$wr = WeakReference::create($xp); +$xp->query('/r/a[php:function("cb", .)]'); + +unset($xp, $GLOBALS['the_xp']); +gc_collect_cycles(); + +var_dump($wr->get() === null); +?> +--EXPECT-- +bool(true) diff --git a/ext/dom/xpath_callbacks.c b/ext/dom/xpath_callbacks.c index 349c304c9f25..76c5bef7c51c 100644 --- a/ext/dom/xpath_callbacks.c +++ b/ext/dom/xpath_callbacks.c @@ -100,6 +100,12 @@ static void php_dom_xpath_callback_ns_get_gc(php_dom_xpath_callback_ns *ns, zend PHP_DOM_EXPORT void php_dom_xpath_callbacks_get_gc(php_dom_xpath_callbacks *registry, zend_get_gc_buffer *gc_buffer) { + if (registry->node_list) { + zval *entry; + ZEND_HASH_FOREACH_VAL(registry->node_list, entry) { + zend_get_gc_buffer_add_zval(gc_buffer, entry); + } ZEND_HASH_FOREACH_END(); + } if (registry->php_ns) { php_dom_xpath_callback_ns_get_gc(registry->php_ns, gc_buffer); } @@ -113,7 +119,7 @@ PHP_DOM_EXPORT void php_dom_xpath_callbacks_get_gc(php_dom_xpath_callbacks *regi PHP_DOM_EXPORT HashTable *php_dom_xpath_callbacks_get_gc_for_whole_object(php_dom_xpath_callbacks *registry, zend_object *object, zval **table, int *n) { - if (registry->php_ns || registry->namespaces) { + if (registry->php_ns || registry->namespaces || registry->node_list) { zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create(); php_dom_xpath_callbacks_get_gc(registry, gc_buffer); zend_get_gc_buffer_use(gc_buffer, table, n);