diff --git a/NEWS b/NEWS index 9a21a84e19917..7adc874c818fc 100644 --- a/NEWS +++ b/NEWS @@ -34,6 +34,8 @@ PHP NEWS - Standard: . Passing strings which are not one byte long to ord() is now deprecated. (Girgias) + . Fixed bug GH-19801 (leaks in var_dump() and debug_zval_dump()). + (alexandre-daubois) - URI: . Fixed bug GH-19780 (InvalidUrlException should check $errors argument). 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 0000000000000..cf2f1d444f1dc --- /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-- +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) packed 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 0000000000000..f0522916de4e6 --- /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-- +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 9363065483d16..cff865055e7df 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -153,7 +153,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, ' '); @@ -354,7 +354,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, ' ');