Skip to content

Commit 3a33711

Browse files
committed
Use zend guard for debug printing if possible
1 parent e5b8fe8 commit 3a33711

File tree

5 files changed

+51
-16
lines changed

5 files changed

+51
-16
lines changed

Zend/zend.c

+4-3
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,7 @@ static void zend_print_zval_r_to_buf(smart_str *buf, zval *expr, int indent) /*
546546
HashTable *properties;
547547

548548
zend_object *zobj = Z_OBJ_P(expr);
549+
uint32_t *guard = zend_get_recursion_guard(zobj);
549550
zend_string *class_name = Z_OBJ_HANDLER_P(expr, get_class_name)(zobj);
550551
smart_str_appends(buf, ZSTR_VAL(class_name));
551552
zend_string_release_ex(class_name, 0);
@@ -561,7 +562,7 @@ static void zend_print_zval_r_to_buf(smart_str *buf, zval *expr, int indent) /*
561562
smart_str_appendc(buf, '\n');
562563
}
563564

564-
if (GC_IS_RECURSIVE(Z_OBJ_P(expr))) {
565+
if (ZEND_GUARD_OR_GC_IS_RECURSIVE(guard, DEBUG, zobj)) {
565566
smart_str_appends(buf, " *RECURSION*");
566567
return;
567568
}
@@ -571,9 +572,9 @@ static void zend_print_zval_r_to_buf(smart_str *buf, zval *expr, int indent) /*
571572
break;
572573
}
573574

574-
GC_PROTECT_RECURSION(Z_OBJ_P(expr));
575+
ZEND_GUARD_OR_GC_PROTECT_RECURSION(guard, DEBUG, zobj);
575576
print_hash(buf, properties, indent, 1);
576-
GC_UNPROTECT_RECURSION(Z_OBJ_P(expr));
577+
ZEND_GUARD_OR_GC_UNPROTECT_RECURSION(guard, DEBUG, zobj);
577578

578579
zend_release_properties(properties);
579580
break;

Zend/zend_object_handlers.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,6 @@ static void zend_property_guard_dtor(zval *el) /* {{{ */ {
544544

545545
static zend_always_inline zval *zend_get_guard_value(zend_object *zobj)
546546
{
547-
ZEND_ASSERT(zobj->ce->ce_flags & ZEND_ACC_USE_GUARDS);
548547
return zobj->properties_table + zobj->ce->default_properties_count;
549548
}
550549

@@ -554,6 +553,8 @@ ZEND_API uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *membe
554553
zval *zv;
555554
uint32_t *ptr;
556555

556+
557+
ZEND_ASSERT(zobj->ce->ce_flags & ZEND_ACC_USE_GUARDS);
557558
zv = zend_get_guard_value(zobj);
558559
if (EXPECTED(Z_TYPE_P(zv) == IS_STRING)) {
559560
zend_string *str = Z_STR_P(zv);
@@ -596,6 +597,9 @@ ZEND_API uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *membe
596597

597598
ZEND_API uint32_t *zend_get_recursion_guard(zend_object *zobj)
598599
{
600+
if (!(zobj->ce->ce_flags & ZEND_ACC_USE_GUARDS)) {
601+
return NULL;
602+
}
599603
zval *zv = zend_get_guard_value(zobj);
600604
return &Z_GUARD_P(zv);
601605
}

Zend/zend_types.h

+21
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,8 @@ struct _zend_ast_ref {
625625
#define ZEND_GUARD_PROTECT_RECURSION(pg, t) *pg |= ZEND_GUARD_RECURSION_TYPE(t)
626626
#define ZEND_GUARD_UNPROTECT_RECURSION(pg, t) *pg &= ~ZEND_GUARD_RECURSION_TYPE(t)
627627

628+
#define ZEND_RECURSION
629+
628630
static zend_always_inline uint8_t zval_get_type(const zval* pz) {
629631
return pz->u1.v.type;
630632
}
@@ -865,6 +867,25 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) {
865867
#define Z_PROTECT_RECURSION_P(zv) Z_PROTECT_RECURSION(*(zv))
866868
#define Z_UNPROTECT_RECURSION_P(zv) Z_UNPROTECT_RECURSION(*(zv))
867869

870+
#define ZEND_GUARD_OR_GC_IS_RECURSIVE(pg, t, zobj) \
871+
pg ? ZEND_GUARD_IS_RECURSIVE(pg, t) : GC_IS_RECURSIVE(zobj)
872+
873+
#define ZEND_GUARD_OR_GC_PROTECT_RECURSION(pg, t, zobj) do { \
874+
if (pg) { \
875+
ZEND_GUARD_PROTECT_RECURSION(pg, t); \
876+
} else { \
877+
GC_PROTECT_RECURSION(zobj); \
878+
} \
879+
} while(0)
880+
881+
#define ZEND_GUARD_OR_GC_UNPROTECT_RECURSION(pg, t, zobj) do { \
882+
if (pg) { \
883+
ZEND_GUARD_UNPROTECT_RECURSION(pg, t); \
884+
} else { \
885+
GC_UNPROTECT_RECURSION(zobj); \
886+
} \
887+
} while(0)
888+
868889
/* All data types < IS_STRING have their constructor/destructors skipped */
869890
#define Z_CONSTANT(zval) (Z_TYPE(zval) == IS_CONSTANT_AST)
870891
#define Z_CONSTANT_P(zval_p) Z_CONSTANT(*(zval_p))

ext/json/json_encoder.c

+2
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,8 @@ static zend_result php_json_encode_serializable_object(smart_str *buf, zval *val
536536
zval retval, fname;
537537
zend_result return_code;
538538

539+
ZEND_ASSERT(guard != NULL);
540+
539541
if (ZEND_GUARD_IS_RECURSIVE(guard, JSON)) {
540542
encoder->error_code = PHP_JSON_ERROR_RECURSION;
541543
if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {

ext/standard/var.c

+19-12
Original file line numberDiff line numberDiff line change
@@ -153,12 +153,13 @@ PHPAPI void php_var_dump(zval *struc, int level) /* {{{ */
153153
php_printf("%senum(%s::%s)\n", COMMON, ZSTR_VAL(ce->name), Z_STRVAL_P(case_name_zval));
154154
return;
155155
}
156-
157-
if (Z_IS_RECURSIVE_P(struc)) {
156+
zend_object *zobj = Z_OBJ_P(struc);
157+
uint32_t *guard = zend_get_recursion_guard(zobj);
158+
if (ZEND_GUARD_OR_GC_IS_RECURSIVE(guard, DEBUG, zobj)) {
158159
PUTS("*RECURSION*\n");
159160
return;
160161
}
161-
Z_PROTECT_RECURSION_P(struc);
162+
ZEND_GUARD_OR_GC_PROTECT_RECURSION(guard, DEBUG, zobj);
162163

163164
myht = zend_get_properties_for(struc, ZEND_PROP_PURPOSE_DEBUG);
164165
class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc));
@@ -190,7 +191,7 @@ PHPAPI void php_var_dump(zval *struc, int level) /* {{{ */
190191
php_printf("%*c", level-1, ' ');
191192
}
192193
PUTS("}\n");
193-
Z_UNPROTECT_RECURSION_P(struc);
194+
ZEND_GUARD_OR_GC_UNPROTECT_RECURSION(guard, DEBUG, zobj);
194195
break;
195196
}
196197
case IS_RESOURCE: {
@@ -342,16 +343,18 @@ PHPAPI void php_debug_zval_dump(zval *struc, int level) /* {{{ */
342343
}
343344
PUTS("}\n");
344345
break;
345-
case IS_OBJECT:
346+
case IS_OBJECT: {
346347
/* Check if this is already recursing on the object before calling zend_get_properties_for,
347348
* to allow infinite recursion detection to work even if classes return temporary arrays,
348349
* and to avoid the need to update the properties table in place to reflect the state
349350
* if the result won't be used. (https://github.com/php/php-src/issues/8044) */
350-
if (Z_IS_RECURSIVE_P(struc)) {
351+
zend_object *zobj = Z_OBJ_P(struc);
352+
uint32_t *guard = zend_get_recursion_guard(zobj);
353+
if (ZEND_GUARD_OR_GC_IS_RECURSIVE(guard, DEBUG, zobj)) {
351354
PUTS("*RECURSION*\n");
352355
return;
353356
}
354-
Z_PROTECT_RECURSION_P(struc);
357+
ZEND_GUARD_OR_GC_PROTECT_RECURSION(guard, DEBUG, zobj);
355358

356359
myht = zend_get_properties_for(struc, ZEND_PROP_PURPOSE_DEBUG);
357360
class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc));
@@ -378,8 +381,9 @@ PHPAPI void php_debug_zval_dump(zval *struc, int level) /* {{{ */
378381
php_printf("%*c", level - 1, ' ');
379382
}
380383
PUTS("}\n");
381-
Z_UNPROTECT_RECURSION_P(struc);
384+
ZEND_GUARD_OR_GC_UNPROTECT_RECURSION(guard, DEBUG, zobj);
382385
break;
386+
}
383387
case IS_RESOURCE: {
384388
const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(struc));
385389
php_printf("resource(" ZEND_LONG_FMT ") of type (%s) refcount(%u)\n", Z_RES_P(struc)->handle, type_name ? type_name : "Unknown", Z_REFCOUNT_P(struc));
@@ -553,17 +557,19 @@ PHPAPI void php_var_export_ex(zval *struc, int level, smart_str *buf) /* {{{ */
553557

554558
break;
555559

556-
case IS_OBJECT:
560+
case IS_OBJECT: {
557561
/* Check if this is already recursing on the object before calling zend_get_properties_for,
558562
* to allow infinite recursion detection to work even if classes return temporary arrays,
559563
* and to avoid the need to update the properties table in place to reflect the state
560564
* if the result won't be used. (https://github.com/php/php-src/issues/8044) */
561-
if (Z_IS_RECURSIVE_P(struc)) {
565+
zend_object *zobj = Z_OBJ_P(struc);
566+
uint32_t *guard = zend_get_recursion_guard(zobj);
567+
if (ZEND_GUARD_OR_GC_IS_RECURSIVE(guard, DEBUG, zobj)) {
562568
smart_str_appendl(buf, "NULL", 4);
563569
zend_error(E_WARNING, "var_export does not handle circular references");
564570
return;
565571
}
566-
Z_PROTECT_RECURSION_P(struc);
572+
ZEND_GUARD_OR_GC_PROTECT_RECURSION(guard, DEBUG, zobj);
567573
myht = zend_get_properties_for(struc, ZEND_PROP_PURPOSE_VAR_EXPORT);
568574
if (level > 1) {
569575
smart_str_appendc(buf, '\n');
@@ -597,7 +603,7 @@ PHPAPI void php_var_export_ex(zval *struc, int level, smart_str *buf) /* {{{ */
597603
}
598604
zend_release_properties(myht);
599605
}
600-
Z_UNPROTECT_RECURSION_P(struc);
606+
ZEND_GUARD_OR_GC_UNPROTECT_RECURSION(guard, DEBUG, zobj);
601607
if (level > 1 && !is_enum) {
602608
buffer_append_spaces(buf, level - 1);
603609
}
@@ -608,6 +614,7 @@ PHPAPI void php_var_export_ex(zval *struc, int level, smart_str *buf) /* {{{ */
608614
}
609615

610616
break;
617+
}
611618
case IS_REFERENCE:
612619
struc = Z_REFVAL_P(struc);
613620
goto again;

0 commit comments

Comments
 (0)