1
0
mirror of https://github.com/php/php-src.git synced 2026-04-02 13:43:02 +02:00

Explicitly print reference wrappers in debug_zval_dump()

Closes GH-6750.
This commit is contained in:
Nikita Popov
2021-03-03 16:28:39 +01:00
parent 4b59071844
commit 500b4b4945
6 changed files with 142 additions and 56 deletions

View File

@@ -107,6 +107,11 @@ PHP 8.1 UPGRADE NOTES
that ' is escaped to ' while previously it was left alone.
Additionally, malformed UTF-8 will be replaced by a Unicode substitution
character, instead of resulting in an empty string.
. debug_zval_dump() will now print reference wrappers with their refcount,
instead of only prepending a "&" to the value. This more accurately models
reference representation since PHP 7.0.
. debug_zval_dump() will not print "interned" instead of a dummy refcount of
one for interned strings and immutable arrays.
========================================
2. New Features

View File

@@ -87,51 +87,69 @@ array(7) refcount(2){
[0]=>
array(2) refcount(1){
["id"]=>
int(1)
reference refcount(1) {
int(1)
}
["label"]=>
string(1) "a" refcount(%d)
}
[1]=>
array(2) refcount(1){
["id"]=>
int(2)
reference refcount(1) {
int(2)
}
["label"]=>
string(1) "b" refcount(%d)
}
[2]=>
array(2) refcount(1){
["id"]=>
int(1)
reference refcount(1) {
int(1)
}
["label"]=>
string(1) "a" refcount(%d)
}
[3]=>
array(2) refcount(1){
["id"]=>
int(2)
reference refcount(1) {
int(2)
}
["label"]=>
string(1) "b" refcount(%d)
}
[4]=>
array(3) refcount(1){
["id"]=>
&int(3)
reference refcount(2) {
int(3)
}
["label"]=>
string(1) "a" refcount(%d)
["id2"]=>
&int(3)
reference refcount(2) {
int(3)
}
}
[5]=>
array(3) refcount(1){
["id"]=>
&int(4)
reference refcount(2) {
int(4)
}
["label"]=>
string(1) "b" refcount(%d)
["id2"]=>
&int(4)
reference refcount(2) {
int(4)
}
}
[6]=>
&object(mysqli_result)#%d (0) refcount(%d){
reference refcount(2) {
object(mysqli_result)#2 (0) refcount(1){
}
}
}
array(1) refcount(2){

View File

@@ -55,7 +55,9 @@ array(1) refcount(%d){
[0]=>
array(4) refcount(%d){
["row_ref"]=>
&NULL
reference refcount(2) {
NULL
}
["row_copy"]=>
array(2) refcount(1){
["id"]=>
@@ -64,7 +66,9 @@ array(1) refcount(%d){
string(1) "a" interned
}
["id_ref"]=>
string(1) "1" interned
reference refcount(1) {
string(1) "1" interned
}
["id_copy"]=>
string(1) "1" interned
}
@@ -73,7 +77,9 @@ array(2) refcount(%d){
[0]=>
array(4) refcount(%d){
["row_ref"]=>
&NULL
reference refcount(2) {
NULL
}
["row_copy"]=>
array(2) refcount(%d){
["id"]=>
@@ -82,18 +88,24 @@ array(2) refcount(%d){
string(1) "a" interned
}
["id_ref"]=>
string(1) "1" interned
reference refcount(1) {
string(1) "1" interned
}
["id_copy"]=>
string(1) "1" interned
}
[1]=>
array(5) refcount(%d){
["row_ref"]=>
&array(2) refcount(%d){
["id"]=>
&string(1) "2" interned
["label"]=>
string(1) "b" interned
reference refcount(2) {
array(2) refcount(1){
["id"]=>
reference refcount(2) {
string(1) "2" interned
}
["label"]=>
string(1) "b" interned
}
}
["row_copy"]=>
array(2) refcount(%d){
@@ -103,7 +115,9 @@ array(2) refcount(%d){
string(1) "b" interned
}
["id_ref"]=>
&string(1) "2" interned
reference refcount(2) {
string(1) "2" interned
}
["id_copy"]=>
string(1) "2" interned
["id_copy_mod"]=>

View File

@@ -345,26 +345,30 @@ object(object_class)#%d (7) refcount(%d){
["object_class1"]=>
*RECURSION*
["obj"]=>
&object(object_class)#%d (7) refcount(%d){
["value1"]=>
int(5)
["value2":"object_class":private]=>
int(10)
["value3":protected]=>
int(20)
["value4"]=>
int(30)
["array_var"]=>
array(2) refcount(%d){
["key1"]=>
int(1)
["key2 "]=>
int(3)
reference refcount(2) {
object(object_class)#8 (7) refcount(2){
["value1"]=>
int(5)
["value2":"object_class":private]=>
int(10)
["value3":protected]=>
int(20)
["value4"]=>
int(30)
["array_var"]=>
array(2) refcount(7){
["key1"]=>
int(1)
["key2 "]=>
int(3)
}
["object_class1"]=>
*RECURSION*
["obj"]=>
reference refcount(2) {
*RECURSION*
}
}
["object_class1"]=>
*RECURSION*
["obj"]=>
*RECURSION*
}
}
Done

View File

@@ -0,0 +1,46 @@
--TEST--
References in debug_zval_dump()
--FILE--
<?php
$r = 1;
$a = [&$r];
debug_zval_dump($a);
$a[] =& $r;
debug_zval_dump($a);
unset($a[1]);
debug_zval_dump($a);
unset($r);
// rc=1 singleton ref remains
debug_zval_dump($a);
?>
--EXPECT--
array(1) refcount(2){
[0]=>
reference refcount(2) {
int(1)
}
}
array(2) refcount(2){
[0]=>
reference refcount(3) {
int(1)
}
[1]=>
reference refcount(3) {
int(1)
}
}
array(1) refcount(2){
[0]=>
reference refcount(2) {
int(1)
}
}
array(1) refcount(2){
[0]=>
reference refcount(1) {
int(1)
}
}

View File

@@ -269,7 +269,6 @@ PHPAPI void php_debug_zval_dump(zval *struc, int level) /* {{{ */
{
HashTable *myht = NULL;
zend_string *class_name;
int is_ref = 0;
zend_ulong index;
zend_string *key;
zval *val;
@@ -279,25 +278,24 @@ PHPAPI void php_debug_zval_dump(zval *struc, int level) /* {{{ */
php_printf("%*c", level - 1, ' ');
}
again:
switch (Z_TYPE_P(struc)) {
case IS_FALSE:
php_printf("%sbool(false)\n", COMMON);
PUTS("bool(false)\n");
break;
case IS_TRUE:
php_printf("%sbool(true)\n", COMMON);
PUTS("bool(true)\n");
break;
case IS_NULL:
php_printf("%sNULL\n", COMMON);
PUTS("NULL\n");
break;
case IS_LONG:
php_printf("%sint(" ZEND_LONG_FMT ")\n", COMMON, Z_LVAL_P(struc));
php_printf("int(" ZEND_LONG_FMT ")\n", Z_LVAL_P(struc));
break;
case IS_DOUBLE:
php_printf_unchecked("%sfloat(%.*H)\n", COMMON, (int) PG(serialize_precision), Z_DVAL_P(struc));
php_printf_unchecked("float(%.*H)\n", (int) PG(serialize_precision), Z_DVAL_P(struc));
break;
case IS_STRING:
php_printf("%sstring(%zd) \"", COMMON, Z_STRLEN_P(struc));
php_printf("string(%zd) \"", Z_STRLEN_P(struc));
PHPWRITE(Z_STRVAL_P(struc), Z_STRLEN_P(struc));
if (Z_REFCOUNTED_P(struc)) {
php_printf("\" refcount(%u)\n", Z_REFCOUNT_P(struc));
@@ -318,9 +316,9 @@ again:
count = zend_hash_num_elements(myht);
if (Z_REFCOUNTED_P(struc)) {
/* -1 because of ADDREF above. */
php_printf("%sarray(%d) refcount(%u){\n", COMMON, count, Z_REFCOUNT_P(struc) - 1);
php_printf("array(%d) refcount(%u){\n", count, Z_REFCOUNT_P(struc) - 1);
} else {
php_printf("%sarray(%d) interned {\n", COMMON, count);
php_printf("array(%d) interned {\n", count);
}
ZEND_HASH_FOREACH_KEY_VAL(myht, index, key, val) {
zval_array_element_dump(val, index, key, level);
@@ -345,7 +343,7 @@ again:
GC_PROTECT_RECURSION(myht);
}
class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc));
php_printf("%sobject(%s)#%d (%d) refcount(%u){\n", COMMON, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0, Z_REFCOUNT_P(struc));
php_printf("object(%s)#%d (%d) refcount(%u){\n", ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0, Z_REFCOUNT_P(struc));
zend_string_release_ex(class_name, 0);
if (myht) {
ZEND_HASH_FOREACH_KEY_VAL(myht, index, key, val) {
@@ -372,18 +370,19 @@ again:
break;
case IS_RESOURCE: {
const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(struc));
php_printf("%sresource(%d) of type (%s) refcount(%u)\n", COMMON, Z_RES_P(struc)->handle, type_name ? type_name : "Unknown", Z_REFCOUNT_P(struc));
php_printf("resource(%d) of type (%s) refcount(%u)\n", Z_RES_P(struc)->handle, type_name ? type_name : "Unknown", Z_REFCOUNT_P(struc));
break;
}
case IS_REFERENCE:
//??? hide references with refcount==1 (for compatibility)
if (Z_REFCOUNT_P(struc) > 1) {
is_ref = 1;
php_printf("reference refcount(%u) {\n", Z_REFCOUNT_P(struc));
php_debug_zval_dump(Z_REFVAL_P(struc), level + 2);
if (level > 1) {
php_printf("%*c", level - 1, ' ');
}
struc = Z_REFVAL_P(struc);
goto again;
PUTS("}\n");
break;
default:
php_printf("%sUNKNOWN:0\n", COMMON);
PUTS("UNKNOWN:0\n");
break;
}
}