[php-src] master: Merge branch 'PHP-8.3' into PHP-8.4
Author: David Carlier (devnexen)
Date: 2025-05-17T11:20:39+01:00
Commit: https://github.com/php/php-src/commit/a7884250b163def509cbfc1066d6638f2804c346
Raw diff: https://github.com/php/php-src/commit/a7884250b163def509cbfc1066d6638f2804c346.diff
Merge branch 'PHP-8.3' into PHP-8.4
Changed paths:
A Zend/tests/gh18572.phpt
M NEWS
M Zend/zend_object_handlers.c
Diff:
diff --git a/NEWS b/NEWS
index 5e26e2bc7ff3..93d636716181 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,8 @@ PHP NEWS
- Core:
. Fixed GH-18480 (array_splice with large values for offset/length arguments).
(nielsdos/David Carlier)
+ . Partially fixed GH-18572 (nested object comparisons leading to stack overflow).
+ (David Carlier)
- Curl:
. Fixed GH-18460 (curl_easy_setopt with CURLOPT_USERPWD/CURLOPT_USERNAME/
diff --git a/Zend/tests/gh18572.phpt b/Zend/tests/gh18572.phpt
new file mode 100644
index 000000000000..46361abe9664
--- /dev/null
+++ b/Zend/tests/gh18572.phpt
@@ -0,0 +1,39 @@
+--TEST--
+GH-18572: Nested object comparison leading to stack overflow
+--SKIPIF--
+<?php
+if (getenv('SKIP_ASAN')) die('skip as it fatally crash');
+?>
+--FILE--
+<?php
+
+#[AllowDynamicProperties]
+class Node {
+ public $next;
+ // forcing dynamic property creation is key
+}
+
+$first = new Node();
+$first->previous = $first;
+$first->next = $first;
+
+$cur = $first;
+
+for ($i = 0; $i < 50000; $i++) {
+ $new = new Node();
+ $new->previous = $cur;
+ $cur->next = $new;
+ $new->next = $first;
+ $first->previous = $new;
+ $cur = $new;
+}
+
+try {
+ // Force comparison manually to trigger zend_hash_compare
+ $first == $cur;
+} catch(Error $e) {
+ echo $e->getMessage(). PHP_EOL;
+}
+?>
+--EXPECTREGEX--
+(Maximum call stack size reached during object comparison|Fatal error: Nesting level too deep -
recursive dependency?.+)
diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
index 4aea3501cf26..0def95fc8522 100644
--- a/Zend/zend_object_handlers.c
+++ b/Zend/zend_object_handlers.c
@@ -46,6 +46,15 @@
#define IN_ISSET ZEND_GUARD_PROPERTY_ISSET
#define IN_HOOK ZEND_GUARD_PROPERTY_HOOK
+static zend_always_inline bool zend_objects_check_stack_limit(void)
+{
+#ifdef ZEND_CHECK_STACK_LIMIT
+ return zend_call_stack_overflowed(EG(stack_limit));
+#else
+ return false;
+#endif
+}
+
/*
__X accessors explanation:
@@ -2120,6 +2129,11 @@ ZEND_API int zend_std_compare_objects(zval *o1, zval *o2) /* {{{ */
{
zend_object *zobj1, *zobj2;
+ if (zend_objects_check_stack_limit()) {
+ zend_throw_error(NULL, "Maximum call stack size reached during object comparison");
+ return ZEND_UNCOMPARABLE;
+ }
+
if (Z_TYPE_P(o1) != Z_TYPE_P(o2)) {
/* Object and non-object */
zval *object;
Thread (1 message)
- David Carlier