[php-src] master: Merge branch '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:19:11-04:00

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

Merge branch 'PHP-8.5'

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

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


Diff:

diff --git a/NEWS b/NEWS
index 50c3346e17a3..41ee6be929d6 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,8 @@ PHP                                                                        NEWS
     100-continue flow control). (Sjoerd Langkemper)
 
 - Intl:
+  . Fixed a memory leak when iterating IntlBreakIterator::getPartsIterator()
+    results. (iliaal)
   . Fixed a leak in Locale::getKeywords() when a keyword value cannot be
     read. (iliaal)
 
diff --git a/ext/intl/breakiterator/breakiterator_iterators.cpp b/ext/intl/breakiterator/breakiterator_iterators.cpp
index d792a6367139..def0fa9d9fc5 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 4260e3cce57f..16c892074915 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.