[php-src] master: Merge branch 'PHP-8.4' into PHP-8.5

Ilia Alshanetsky <[email protected]>
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: Ilia Alshanetsky (iliaal)
Date: 2026-08-26T16:14:58-04:00

Commit: https://github.com/php/php-src/commit/e32b7877cdf64c8c8a71173a9ae51d4c56236039
Raw diff: https://github.com/php/php-src/commit/e32b7877cdf64c8c8a71173a9ae51d4c56236039.diff

Merge branch 'PHP-8.4' into PHP-8.5

* PHP-8.4:
  [intl] fix leak when iterating IntlBreakIterator parts iterators

Changed paths:
  A  ext/intl/tests/breakiter_parts_iterator_current_leak.phpt
  M  ext/intl/breakiterator/breakiterator_iterators.cpp
  M  ext/intl/common/common_enum.cpp


Diff:

diff --git a/ext/intl/breakiterator/breakiterator_iterators.cpp b/ext/intl/breakiterator/breakiterator_iterators.cpp
index 34176bf90e52..d6fc5669f3db 100644
--- a/ext/intl/breakiterator/breakiterator_iterators.cpp
+++ b/ext/intl/breakiterator/breakiterator_iterators.cpp
@@ -242,7 +242,7 @@ void IntlIterator_from_BreakIterator_parts(zval *break_iter_zv,
 	ii->iterator->index = 0;
 
 	((zoi_with_current*)ii->iterator)->destroy_it = _breakiterator_parts_destroy_it;
-	ZVAL_OBJ_COPY(&((zoi_with_current*)ii->iterator)->wrapping_obj, Z_OBJ_P(object));
+	ZVAL_UNDEF(&((zoi_with_current*)ii->iterator)->wrapping_obj);
 	ZVAL_UNDEF(&((zoi_with_current*)ii->iterator)->current);
 
 	((zoi_break_iter_parts*)ii->iterator)->bio = Z_INTL_BREAKITERATOR_P(break_iter_zv);
diff --git a/ext/intl/common/common_enum.cpp b/ext/intl/common/common_enum.cpp
index 8cf9796717f4..25545a1bf994 100644
--- a/ext/intl/common/common_enum.cpp
+++ b/ext/intl/common/common_enum.cpp
@@ -39,6 +39,8 @@ zend_object_handlers IntlIterator_handlers;
 void zoi_with_current_dtor(zend_object_iterator *iter)
 {
 	zoi_with_current *zoiwc = (zoi_with_current*)iter;
+	iter->funcs->invalidate_current(iter);
+	zoiwc->destroy_it(iter);
 	zval_ptr_dtor(&zoiwc->wrapping_obj);
 	ZVAL_UNDEF(&zoiwc->wrapping_obj);
 }
@@ -149,7 +151,6 @@ static void IntlIterator_objects_dtor(zend_object *object)
 {
 	IntlIterator_object	*ii = php_intl_iterator_fetch_object(object);
 	if (ii->iterator) {
-		((zoi_with_current*)ii->iterator)->destroy_it(ii->iterator);
 		OBJ_RELEASE(&ii->iterator->std);
 		ii->iterator = NULL;
 	}
diff --git a/ext/intl/tests/breakiter_parts_iterator_current_leak.phpt b/ext/intl/tests/breakiter_parts_iterator_current_leak.phpt
new file mode 100644
index 000000000000..a006d7f2f792
--- /dev/null
+++ b/ext/intl/tests/breakiter_parts_iterator_current_leak.phpt
@@ -0,0 +1,31 @@
+--TEST--
+IntlPartsIterator must not leak, and a temporary one must not dangle
+--EXTENSIONS--
+intl
+--FILE--
+<?php
+function parts(): IntlPartsIterator {
+    $bi = IntlBreakIterator::createWordInstance('en');
+    $bi->setText('hello world');
+    return $bi->getPartsIterator();
+}
+
+foreach (parts() as $part) {
+    echo "[$part]\n";
+}
+
+$bi = IntlBreakIterator::createWordInstance('en');
+$bi->setText('hello world foo bar baz');
+$m0 = memory_get_usage();
+for ($i = 0; $i < 20000; $i++) {
+    foreach ($bi->getPartsIterator() as $v) {
+        break;
+    }
+}
+var_dump(memory_get_usage() - $m0 < 1024 * 1024);
+?>
+--EXPECT--
+[hello]
+[ ]
+[world]
+bool(true)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.