Commit b7a85ee111e for php.net
commit b7a85ee111eaaeadb7f7c52b05cd3d0625b843be
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Sat Aug 29 08:15:41 2026 -0400
[intl] Fix leak of time zone wrapper in Calendar debug info
Calendar_get_debug_info() built a temporary IntlTimeZone wrapper zval
via timezone_object_construct() and never released it, leaking one
wrapper object per var_dump()/debug dump of an IntlCalendar. Release
the wrapper with zval_ptr_dtor() after its debug info has been copied.
Sibling audit: all other timezone_object_construct() call sites write
into return_value and are refcount-managed; no other intl get_debug_info
handler constructs temporary wrapper objects.
Closes GH-23503
diff --git a/NEWS b/NEWS
index 546364fbc2c..921ca372b29 100644
--- a/NEWS
+++ b/NEWS
@@ -30,6 +30,7 @@ PHP NEWS
. Fixed bug GH-19320 (FPM UID and GID overflow). (Pratik Bhujel)
- Intl:
+ . Fixed a memory leak when dumping IntlCalendar instances. (Ilia Alshanetsky)
. Fixed a memory leak when iterating IntlBreakIterator::getPartsIterator()
results. (iliaal)
. Fixed a double-free when IntlGregorianCalendar construction fails after
diff --git a/ext/intl/calendar/calendar_class.cpp b/ext/intl/calendar/calendar_class.cpp
index 97b21ff8f96..bacb549bdbc 100644
--- a/ext/intl/calendar/calendar_class.cpp
+++ b/ext/intl/calendar/calendar_class.cpp
@@ -171,6 +171,8 @@ static HashTable *Calendar_get_debug_info(zend_object *object, int *is_temp)
FREE_HASHTABLE(debug_info_tz);
zend_hash_str_update(debug_info, "timeZone", sizeof("timeZone") - 1, &ztz_debug);
+
+ zval_ptr_dtor(&ztz);
}
{
diff --git a/ext/intl/tests/calendar_get_debug_info_tz_leak.phpt b/ext/intl/tests/calendar_get_debug_info_tz_leak.phpt
new file mode 100644
index 00000000000..32b9da4368a
--- /dev/null
+++ b/ext/intl/tests/calendar_get_debug_info_tz_leak.phpt
@@ -0,0 +1,26 @@
+--TEST--
+IntlCalendar get_debug_info() must not leak the time zone wrapper object
+--EXTENSIONS--
+intl
+--FILE--
+<?php
+$cal = IntlCalendar::createInstance('UTC');
+ob_start();
+var_dump($cal);
+ob_end_clean();
+
+$o = new stdClass;
+$before = spl_object_id($o);
+unset($o);
+for ($i = 0; $i < 10; $i++) {
+ ob_start();
+ var_dump($cal);
+ ob_end_clean();
+}
+$o = new stdClass;
+$after = spl_object_id($o);
+
+var_dump($after - $before);
+?>
+--EXPECT--
+int(0)