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

From: Date: Sat, 17 May 2025 10:32:29 +0000
Subject: [php-src] master: Merge branch 'PHP-8.3' into PHP-8.4
Groups: php.cvs 
Request: Send a blank email to [email protected] to get a copy of this message
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
« previous php.cvs (#134134) next »