Commit 7ffbf30cfcc for php
commit 7ffbf30cfcceb4b47b1ec31cac1a7ea32b6af40d
Author: Heath Dutton🕴️ <heathdutton@gmail.com>
Date: Thu Oct 15 13:28:35 2026 -0400
Fix GH-20503: Assertion failure with ext/date DateInterval property hash (#20720)
diff --git a/ext/date/php_date.c b/ext/date/php_date.c
index 6773fa939e6..c455b226c34 100644
--- a/ext/date/php_date.c
+++ b/ext/date/php_date.c
@@ -2265,6 +2265,12 @@ static HashTable *date_object_get_properties_interval(zend_object *object) /* {{
return props;
}
+ /* The table may still be held elsewhere (e.g. json_encode() walking a cycle), so separate it before writing */
+ if (UNEXPECTED(GC_REFCOUNT(props) > 1)) {
+ GC_TRY_DELREF(props);
+ props = object->properties = zend_array_dup(props);
+ }
+
date_interval_object_to_hash(intervalobj, props);
return props;
diff --git a/ext/date/tests/bug-gh20503.phpt b/ext/date/tests/bug-gh20503.phpt
new file mode 100644
index 00000000000..468afb3d124
--- /dev/null
+++ b/ext/date/tests/bug-gh20503.phpt
@@ -0,0 +1,33 @@
+--TEST--
+GH-20503 (Assertion failure with ext/date DateInterval property hash construction)
+--SKIPIF--
+<?php
+if (ini_get('zend.max_allowed_stack_size') === false) {
+ die('skip No stack limit support');
+}
+if (getenv('SKIP_ASAN')) {
+ die('skip ASAN needs different stack limit setting due to more stack space usage');
+}
+?>
+--INI--
+zend.max_allowed_stack_size=512K
+--FILE--
+<?php
+$obj = new DateInterval('P1W');
+$obj->prop3 = $obj;
+var_dump(json_encode($obj));
+var_dump(json_last_error_msg());
+
+$obj2 = new DateInterval('P1D');
+$obj2->prop = [$obj2];
+var_dump(json_encode($obj2));
+var_dump(json_last_error_msg());
+?>
+--EXPECTF--
+Deprecated: Creation of dynamic property DateInterval::$prop3 is deprecated in %s on line %d
+bool(false)
+string(28) "Maximum stack depth exceeded"
+
+Deprecated: Creation of dynamic property DateInterval::$prop is deprecated in %s on line %d
+bool(false)
+string(18) "Recursion detected"