Skip to content

Commit e5b8fe8

Browse files
committed
Extend and integrate zend guard recursion protection to json
1 parent 438c290 commit e5b8fe8

File tree

4 files changed

+31
-9
lines changed

4 files changed

+31
-9
lines changed

Zend/zend_object_handlers.c

+13-2
Original file line numberDiff line numberDiff line change
@@ -542,14 +542,19 @@ static void zend_property_guard_dtor(zval *el) /* {{{ */ {
542542
}
543543
/* }}} */
544544

545+
static zend_always_inline zval *zend_get_guard_value(zend_object *zobj)
546+
{
547+
ZEND_ASSERT(zobj->ce->ce_flags & ZEND_ACC_USE_GUARDS);
548+
return zobj->properties_table + zobj->ce->default_properties_count;
549+
}
550+
545551
ZEND_API uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *member) /* {{{ */
546552
{
547553
HashTable *guards;
548554
zval *zv;
549555
uint32_t *ptr;
550556

551-
ZEND_ASSERT(zobj->ce->ce_flags & ZEND_ACC_USE_GUARDS);
552-
zv = zobj->properties_table + zobj->ce->default_properties_count;
557+
zv = zend_get_guard_value(zobj);
553558
if (EXPECTED(Z_TYPE_P(zv) == IS_STRING)) {
554559
zend_string *str = Z_STR_P(zv);
555560
if (EXPECTED(str == member) ||
@@ -589,6 +594,12 @@ ZEND_API uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *membe
589594
}
590595
/* }}} */
591596

597+
ZEND_API uint32_t *zend_get_recursion_guard(zend_object *zobj)
598+
{
599+
zval *zv = zend_get_guard_value(zobj);
600+
return &Z_GUARD_P(zv);
601+
}
602+
592603
ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int type, void **cache_slot, zval *rv) /* {{{ */
593604
{
594605
zval *retval;

Zend/zend_object_handlers.h

+4
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,10 @@ ZEND_API zend_function *zend_get_call_trampoline_func(const zend_class_entry *ce
241241

242242
ZEND_API uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *member);
243243

244+
ZEND_API uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *member);
245+
246+
ZEND_API uint32_t *zend_get_recursion_guard(zend_object *zobj);
247+
244248
/* Default behavior for get_properties_for. For use as a fallback in custom
245249
* get_properties_for implementations. */
246250
ZEND_API HashTable *zend_std_get_properties_for(zend_object *obj, zend_prop_purpose purpose);

Zend/zend_types.h

+6
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,12 @@ struct _zend_ast_ref {
619619
#define ZEND_GUARD_RECURSION_DEBUG (1<<4)
620620
#define ZEND_GUARD_RECURSION_JSON (1<<5)
621621

622+
#define ZEND_GUARD_RECURSION_TYPE(t) ZEND_GUARD_RECURSION_ ## t
623+
624+
#define ZEND_GUARD_IS_RECURSIVE(pg, t) ((*pg & ZEND_GUARD_RECURSION_TYPE(t)) != 0)
625+
#define ZEND_GUARD_PROTECT_RECURSION(pg, t) *pg |= ZEND_GUARD_RECURSION_TYPE(t)
626+
#define ZEND_GUARD_UNPROTECT_RECURSION(pg, t) *pg &= ~ZEND_GUARD_RECURSION_TYPE(t)
627+
622628
static zend_always_inline uint8_t zval_get_type(const zval* pz) {
623629
return pz->u1.v.type;
624630
}

ext/json/json_encoder.c

+8-7
Original file line numberDiff line numberDiff line change
@@ -531,19 +531,20 @@ zend_result php_json_escape_string(
531531
static zend_result php_json_encode_serializable_object(smart_str *buf, zval *val, int options, php_json_encoder *encoder) /* {{{ */
532532
{
533533
zend_class_entry *ce = Z_OBJCE_P(val);
534-
HashTable* myht = Z_OBJPROP_P(val);
534+
zend_object *obj = Z_OBJ_P(val);
535+
uint32_t *guard = zend_get_recursion_guard(obj);
535536
zval retval, fname;
536537
zend_result return_code;
537538

538-
if (myht && GC_IS_RECURSIVE(myht)) {
539+
if (ZEND_GUARD_IS_RECURSIVE(guard, JSON)) {
539540
encoder->error_code = PHP_JSON_ERROR_RECURSION;
540541
if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
541542
smart_str_appendl(buf, "null", 4);
542543
}
543544
return FAILURE;
544545
}
545546

546-
PHP_JSON_HASH_PROTECT_RECURSION(myht);
547+
ZEND_GUARD_PROTECT_RECURSION(guard, JSON);
547548

548549
ZVAL_STRING(&fname, "jsonSerialize");
549550

@@ -556,7 +557,7 @@ static zend_result php_json_encode_serializable_object(smart_str *buf, zval *val
556557
if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
557558
smart_str_appendl(buf, "null", 4);
558559
}
559-
PHP_JSON_HASH_UNPROTECT_RECURSION(myht);
560+
ZEND_GUARD_UNPROTECT_RECURSION(guard, JSON);
560561
return FAILURE;
561562
}
562563

@@ -568,19 +569,19 @@ static zend_result php_json_encode_serializable_object(smart_str *buf, zval *val
568569
if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
569570
smart_str_appendl(buf, "null", 4);
570571
}
571-
PHP_JSON_HASH_UNPROTECT_RECURSION(myht);
572+
ZEND_GUARD_UNPROTECT_RECURSION(guard, JSON);
572573
return FAILURE;
573574
}
574575

575576
if ((Z_TYPE(retval) == IS_OBJECT) &&
576577
(Z_OBJ(retval) == Z_OBJ_P(val))) {
577578
/* Handle the case where jsonSerialize does: return $this; by going straight to encode array */
578-
PHP_JSON_HASH_UNPROTECT_RECURSION(myht);
579+
ZEND_GUARD_UNPROTECT_RECURSION(guard, JSON);
579580
return_code = php_json_encode_array(buf, &retval, options, encoder);
580581
} else {
581582
/* All other types, encode as normal */
582583
return_code = php_json_encode_zval(buf, &retval, options, encoder);
583-
PHP_JSON_HASH_UNPROTECT_RECURSION(myht);
584+
ZEND_GUARD_UNPROTECT_RECURSION(guard, JSON);
584585
}
585586

586587
zval_ptr_dtor(&retval);

0 commit comments

Comments
 (0)