Commit 75217c16c89 for php.net

commit 75217c16c89639fe3b01e43d1cdc4a701063347d
Author: Alexandre Daubois <2144837+alexandre-daubois@users.noreply.github.com>
Date:   Tue Sep 16 15:05:45 2025 +0200

    Fix GH-19801: address leak when calling var_dump() with recursion in __debugInfo() (#19837)

diff --git a/NEWS b/NEWS
index 0891acce266..b3cdd047e50 100644
--- a/NEWS
+++ b/NEWS
@@ -29,6 +29,8 @@ PHP                                                                        NEWS
   . Fixed bug GH-12265 (Cloning an object breaks serialization recursion).
     (nielsdos)
   . Fixed bug GH-19701 (Serialize/deserialize loses some data). (nielsdos)
+  . Fixed bug GH-19801 (leaks in var_dump() and debug_zval_dump()).
+    (alexandre-daubois)

 - Zip:
   . Fixed bug GH-19688 (Remove pattern overflow in zip addGlob()). (nielsdos)
diff --git a/ext/standard/tests/general_functions/debug_zval_dump_gh19801_memory_leak.phpt b/ext/standard/tests/general_functions/debug_zval_dump_gh19801_memory_leak.phpt
new file mode 100644
index 00000000000..8d65cd6d185
--- /dev/null
+++ b/ext/standard/tests/general_functions/debug_zval_dump_gh19801_memory_leak.phpt
@@ -0,0 +1,32 @@
+--TEST--
+GH-19801 (debug_zval_dump() leak with __debugInfo() that modifies circular references)
+--FILE--
+<?php
+
+$a = [
+    new class {
+        function __debugInfo() {
+            global $b;
+            $b->a = null;
+            gc_collect_cycles();
+            return [];
+        }
+    },
+];
+
+$b = new stdClass;
+$b->a = &$a;
+
+debug_zval_dump($b);
+?>
+--EXPECTF--
+object(stdClass)#2 (1) refcount(%d){
+  ["a"]=>
+  reference refcount(%d) {
+    array(1) refcount(%d){
+      [0]=>
+      object(class@anonymous)#1 (0) refcount(%d){
+      }
+    }
+  }
+}
diff --git a/ext/standard/tests/general_functions/var_dump_gh19801_memory_leak.phpt b/ext/standard/tests/general_functions/var_dump_gh19801_memory_leak.phpt
new file mode 100644
index 00000000000..f0522916de4
--- /dev/null
+++ b/ext/standard/tests/general_functions/var_dump_gh19801_memory_leak.phpt
@@ -0,0 +1,30 @@
+--TEST--
+GH-19801 (var_dump() memory leak with __debugInfo() that modifies circular references)
+--FILE--
+<?php
+
+$a = [
+    new class {
+        function __debugInfo() {
+            global $b;
+            $b->a = null;
+            gc_collect_cycles();
+            return [];
+        }
+    },
+];
+
+$b = new stdClass;
+$b->a = &$a;
+
+var_dump($b);
+?>
+--EXPECTF--
+object(stdClass)#2 (1) {
+  ["a"]=>
+  &array(1) {
+    [0]=>
+    object(class@anonymous)#1 (0) {
+    }
+  }
+}
diff --git a/ext/standard/var.c b/ext/standard/var.c
index c6e280d15ab..795fb366c60 100644
--- a/ext/standard/var.c
+++ b/ext/standard/var.c
@@ -139,7 +139,7 @@ PHPAPI void php_var_dump(zval *struc, int level) /* {{{ */
 			} ZEND_HASH_FOREACH_END();
 			if (!(GC_FLAGS(myht) & GC_IMMUTABLE)) {
 				GC_UNPROTECT_RECURSION(myht);
-				GC_DELREF(myht);
+				GC_DTOR_NO_REF(myht);
 			}
 			if (level > 1) {
 				php_printf("%*c", level-1, ' ');
@@ -336,7 +336,7 @@ PHPAPI void php_debug_zval_dump(zval *struc, int level) /* {{{ */
 		} ZEND_HASH_FOREACH_END();
 		if (!(GC_FLAGS(myht) & GC_IMMUTABLE)) {
 			GC_UNPROTECT_RECURSION(myht);
-			GC_DELREF(myht);
+			GC_DTOR_NO_REF(myht);
 		}
 		if (level > 1) {
 			php_printf("%*c", level - 1, ' ');