Skip to content

Commit 438c290

Browse files
committed
Extend zend guards to allow recursion protection
1 parent dc368d3 commit 438c290

File tree

4 files changed

+30
-13
lines changed

4 files changed

+30
-13
lines changed

Zend/zend_API.c

+1
Original file line numberDiff line numberDiff line change
@@ -2746,6 +2746,7 @@ ZEND_API void zend_add_magic_method(zend_class_entry *ce, zend_function *fptr, z
27462746
ce->__tostring = fptr;
27472747
} else if (zend_string_equals_literal(lcname, ZEND_DEBUGINFO_FUNC_NAME)) {
27482748
ce->__debugInfo = fptr;
2749+
ce->ce_flags |= ZEND_ACC_USE_GUARDS;
27492750
} else if (zend_string_equals_literal(lcname, "__serialize")) {
27502751
ce->__serialize = fptr;
27512752
} else if (zend_string_equals_literal(lcname, "__unserialize")) {

Zend/zend_object_handlers.c

+10-10
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@
3636
#define ZEND_WRONG_PROPERTY_OFFSET 0
3737

3838
/* guard flags */
39-
#define IN_GET (1<<0)
40-
#define IN_SET (1<<1)
41-
#define IN_UNSET (1<<2)
42-
#define IN_ISSET (1<<3)
39+
#define IN_GET ZEND_GUARD_PROPERTY_GET
40+
#define IN_SET ZEND_GUARD_PROPERTY_SET
41+
#define IN_UNSET ZEND_GUARD_PROPERTY_UNSET
42+
#define IN_ISSET ZEND_GUARD_PROPERTY_ISSET
4343

4444
/*
4545
__X accessors explanation:
@@ -555,17 +555,17 @@ ZEND_API uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *membe
555555
if (EXPECTED(str == member) ||
556556
/* str and member don't necessarily have a pre-calculated hash value here */
557557
EXPECTED(zend_string_equal_content(str, member))) {
558-
return &Z_PROPERTY_GUARD_P(zv);
559-
} else if (EXPECTED(Z_PROPERTY_GUARD_P(zv) == 0)) {
558+
return &Z_GUARD_P(zv);
559+
} else if (EXPECTED(Z_GUARD_P(zv) == 0)) {
560560
zval_ptr_dtor_str(zv);
561561
ZVAL_STR_COPY(zv, member);
562-
return &Z_PROPERTY_GUARD_P(zv);
562+
return &Z_GUARD_P(zv);
563563
} else {
564564
ALLOC_HASHTABLE(guards);
565565
zend_hash_init(guards, 8, NULL, zend_property_guard_dtor, 0);
566566
/* mark pointer as "special" using low bit */
567567
zend_hash_add_new_ptr(guards, str,
568-
(void*)(((uintptr_t)&Z_PROPERTY_GUARD_P(zv)) | 1));
568+
(void*)(((uintptr_t)&Z_GUARD_P(zv)) | 1));
569569
zval_ptr_dtor_str(zv);
570570
ZVAL_ARR(zv, guards);
571571
}
@@ -579,8 +579,8 @@ ZEND_API uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *membe
579579
} else {
580580
ZEND_ASSERT(Z_TYPE_P(zv) == IS_UNDEF);
581581
ZVAL_STR_COPY(zv, member);
582-
Z_PROPERTY_GUARD_P(zv) = 0;
583-
return &Z_PROPERTY_GUARD_P(zv);
582+
Z_GUARD_P(zv) &= ~ZEND_GUARD_PROPERTY_MASK;
583+
return &Z_GUARD_P(zv);
584584
}
585585
/* we have to allocate uint32_t separately because ht->arData may be reallocated */
586586
ptr = (uint32_t*)emalloc(sizeof(uint32_t));

Zend/zend_types.h

+12-3
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ struct _zval_struct {
336336
uint32_t num_args; /* arguments number for EX(This) */
337337
uint32_t fe_pos; /* foreach position */
338338
uint32_t fe_iter_idx; /* foreach iterator index */
339-
uint32_t property_guard; /* single property guard */
339+
uint32_t guard; /* recursion and single property guard */
340340
uint32_t constant_flags; /* constant flags */
341341
uint32_t extra; /* not further specified */
342342
} u2;
@@ -610,6 +610,15 @@ struct _zend_ast_ref {
610610
#define _IS_BOOL 18
611611
#define _IS_NUMBER 19
612612

613+
/* guard flags */
614+
#define ZEND_GUARD_PROPERTY_GET (1<<0)
615+
#define ZEND_GUARD_PROPERTY_SET (1<<1)
616+
#define ZEND_GUARD_PROPERTY_UNSET (1<<2)
617+
#define ZEND_GUARD_PROPERTY_ISSET (1<<3)
618+
#define ZEND_GUARD_PROPERTY_MASK 15
619+
#define ZEND_GUARD_RECURSION_DEBUG (1<<4)
620+
#define ZEND_GUARD_RECURSION_JSON (1<<5)
621+
613622
static zend_always_inline uint8_t zval_get_type(const zval* pz) {
614623
return pz->u1.v.type;
615624
}
@@ -650,8 +659,8 @@ static zend_always_inline uint8_t zval_get_type(const zval* pz) {
650659
#define Z_FE_ITER(zval) (zval).u2.fe_iter_idx
651660
#define Z_FE_ITER_P(zval_p) Z_FE_ITER(*(zval_p))
652661

653-
#define Z_PROPERTY_GUARD(zval) (zval).u2.property_guard
654-
#define Z_PROPERTY_GUARD_P(zval_p) Z_PROPERTY_GUARD(*(zval_p))
662+
#define Z_GUARD(zval) (zval).u2.guard
663+
#define Z_GUARD_P(zval_p) Z_GUARD(*(zval_p))
655664

656665
#define Z_CONSTANT_FLAGS(zval) (zval).u2.constant_flags
657666
#define Z_CONSTANT_FLAGS_P(zval_p) Z_CONSTANT_FLAGS(*(zval_p))

ext/json/json.c

+7
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,17 @@ PHP_JSON_API zend_class_entry *php_json_exception_ce;
3737

3838
PHP_JSON_API ZEND_DECLARE_MODULE_GLOBALS(json)
3939

40+
static int php_json_implement_json_serializable(zend_class_entry *interface, zend_class_entry *class_type)
41+
{
42+
class_type->ce_flags |= ZEND_ACC_USE_GUARDS;
43+
return SUCCESS;
44+
}
45+
4046
/* {{{ MINIT */
4147
static PHP_MINIT_FUNCTION(json)
4248
{
4349
php_json_serializable_ce = register_class_JsonSerializable();
50+
php_json_serializable_ce->interface_gets_implemented = php_json_implement_json_serializable;
4451

4552
php_json_exception_ce = register_class_JsonException(zend_ce_exception);
4653

0 commit comments

Comments
 (0)