mirror of
https://github.com/php/php-src.git
synced 2024-11-23 18:04:36 +08:00
Refactored recursion pretection
This commit is contained in:
parent
39ea632f74
commit
cb9d81ef4f
@ -55,6 +55,9 @@ BCMath:
|
||||
5. Changed Functions
|
||||
========================================
|
||||
|
||||
. debug_zval_dump() was changed to display recursive arrays and objects
|
||||
in the same way as var_dump(). Now, it doesn't display them twice.
|
||||
|
||||
========================================
|
||||
6. New Functions
|
||||
========================================
|
||||
|
@ -11,6 +11,7 @@ PHP 7.2 INTERNALS UPGRADE NOTES
|
||||
h. valid_symbol_table removed
|
||||
i. array_init() and array_init_size()
|
||||
j. Run-time constant operand addressing
|
||||
k. Array/Object recursion protection
|
||||
|
||||
2. Build system changes
|
||||
a. Unix build system changes
|
||||
@ -70,6 +71,19 @@ PHP 7.2 INTERNALS UPGRADE NOTES
|
||||
RT_CONSTANT_EX, EX_CONSTANT should be substituted by RT_CONSTANT than now
|
||||
use "opline" (instead of "op_array") as first argument.
|
||||
|
||||
k. Protection from recursion during processing circular data structures was
|
||||
refactored. HashTable.nApplyCount and IS_OBJ_APPLY_COUNT are replaced by
|
||||
single flag GC_PROTECTED. Corresponding macros Z_OBJ_APPLY_COUNT,
|
||||
Z_OBJ_INC_APPLY_COUNT, Z_OBJ_DEC_APPLY_COUNT, ZEND_HASH_GET_APPLY_COUNT,
|
||||
ZEND_HASH_INC_APPLY_COUNT, ZEND_HASH_DEC_APPLY_COUNT are replaced with
|
||||
GC_IS_RECURSIVE, GC_PROTECT_RECURSION, GC_UNPROTECT_RECURSION,
|
||||
Z_IS_RECURSIVE, Z_PROTECT_RECURSION, Z_UNPROTECT_RECURSION.
|
||||
|
||||
HASH_FLAG_APPLY_PROTECTION flag and ZEND_HASH_APPLY_PROTECTION() macro
|
||||
are removed. All mutable arrays should use recursion protection.
|
||||
Corresponding checks should be replaced by Z_REFCOUNTED() or
|
||||
!(GC_GLAGS(p) & GC_IMMUTABLE).
|
||||
|
||||
|
||||
========================
|
||||
2. Build system changes
|
||||
|
@ -18,10 +18,7 @@ array(1) refcount(%d){
|
||||
[0]=>
|
||||
array(1) refcount(%d){
|
||||
[0]=>
|
||||
array(1) refcount(%d){
|
||||
[0]=>
|
||||
*RECURSION*
|
||||
}
|
||||
*RECURSION*
|
||||
}
|
||||
}
|
||||
array(1) refcount(%d){
|
||||
@ -30,13 +27,7 @@ array(1) refcount(%d){
|
||||
[0]=>
|
||||
array(1) refcount(%d){
|
||||
[0]=>
|
||||
array(1) refcount(%d){
|
||||
[0]=>
|
||||
array(1) refcount(%d){
|
||||
[0]=>
|
||||
*RECURSION*
|
||||
}
|
||||
}
|
||||
*RECURSION*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
42
Zend/zend.c
42
Zend/zend.c
@ -334,16 +334,17 @@ ZEND_API void zend_print_flat_zval_r(zval *expr) /* {{{ */
|
||||
switch (Z_TYPE_P(expr)) {
|
||||
case IS_ARRAY:
|
||||
ZEND_PUTS("Array (");
|
||||
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr)) &&
|
||||
++Z_ARRVAL_P(expr)->u.v.nApplyCount>1) {
|
||||
ZEND_PUTS(" *RECURSION*");
|
||||
Z_ARRVAL_P(expr)->u.v.nApplyCount--;
|
||||
return;
|
||||
if (Z_REFCOUNTED_P(expr)) {
|
||||
if (Z_IS_RECURSIVE_P(expr)) {
|
||||
ZEND_PUTS(" *RECURSION*");
|
||||
return;
|
||||
}
|
||||
Z_PROTECT_RECURSION_P(expr);
|
||||
}
|
||||
print_flat_hash(Z_ARRVAL_P(expr));
|
||||
ZEND_PUTS(")");
|
||||
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr))) {
|
||||
Z_ARRVAL_P(expr)->u.v.nApplyCount--;
|
||||
if (Z_REFCOUNTED_P(expr)) {
|
||||
Z_UNPROTECT_RECURSION_P(expr);
|
||||
}
|
||||
break;
|
||||
case IS_OBJECT:
|
||||
@ -353,7 +354,7 @@ ZEND_API void zend_print_flat_zval_r(zval *expr) /* {{{ */
|
||||
zend_printf("%s Object (", ZSTR_VAL(class_name));
|
||||
zend_string_release(class_name);
|
||||
|
||||
if (Z_OBJ_APPLY_COUNT_P(expr) > 0) {
|
||||
if (Z_IS_RECURSIVE_P(expr)) {
|
||||
ZEND_PUTS(" *RECURSION*");
|
||||
return;
|
||||
}
|
||||
@ -362,9 +363,9 @@ ZEND_API void zend_print_flat_zval_r(zval *expr) /* {{{ */
|
||||
properties = Z_OBJPROP_P(expr);
|
||||
}
|
||||
if (properties) {
|
||||
Z_OBJ_INC_APPLY_COUNT_P(expr);
|
||||
Z_PROTECT_RECURSION_P(expr);
|
||||
print_flat_hash(properties);
|
||||
Z_OBJ_DEC_APPLY_COUNT_P(expr);
|
||||
Z_UNPROTECT_RECURSION_P(expr);
|
||||
}
|
||||
ZEND_PUTS(")");
|
||||
break;
|
||||
@ -384,15 +385,16 @@ static void zend_print_zval_r_to_buf(smart_str *buf, zval *expr, int indent) /*
|
||||
switch (Z_TYPE_P(expr)) {
|
||||
case IS_ARRAY:
|
||||
smart_str_appends(buf, "Array\n");
|
||||
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr)) &&
|
||||
++Z_ARRVAL_P(expr)->u.v.nApplyCount>1) {
|
||||
smart_str_appends(buf, " *RECURSION*");
|
||||
Z_ARRVAL_P(expr)->u.v.nApplyCount--;
|
||||
return;
|
||||
if (Z_REFCOUNTED_P(expr)) {
|
||||
if (Z_IS_RECURSIVE_P(expr)) {
|
||||
smart_str_appends(buf, " *RECURSION*");
|
||||
return;
|
||||
}
|
||||
Z_PROTECT_RECURSION_P(expr);
|
||||
}
|
||||
print_hash(buf, Z_ARRVAL_P(expr), indent, 0);
|
||||
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr))) {
|
||||
Z_ARRVAL_P(expr)->u.v.nApplyCount--;
|
||||
if (Z_REFCOUNTED_P(expr)) {
|
||||
Z_UNPROTECT_RECURSION_P(expr);
|
||||
}
|
||||
break;
|
||||
case IS_OBJECT:
|
||||
@ -405,7 +407,7 @@ static void zend_print_zval_r_to_buf(smart_str *buf, zval *expr, int indent) /*
|
||||
zend_string_release(class_name);
|
||||
|
||||
smart_str_appends(buf, " Object\n");
|
||||
if (Z_OBJ_APPLY_COUNT_P(expr) > 0) {
|
||||
if (Z_IS_RECURSIVE_P(expr)) {
|
||||
smart_str_appends(buf, " *RECURSION*");
|
||||
return;
|
||||
}
|
||||
@ -413,9 +415,9 @@ static void zend_print_zval_r_to_buf(smart_str *buf, zval *expr, int indent) /*
|
||||
break;
|
||||
}
|
||||
|
||||
Z_OBJ_INC_APPLY_COUNT_P(expr);
|
||||
Z_PROTECT_RECURSION_P(expr);
|
||||
print_hash(buf, properties, indent, 1);
|
||||
Z_OBJ_DEC_APPLY_COUNT_P(expr);
|
||||
Z_UNPROTECT_RECURSION_P(expr);
|
||||
|
||||
if (is_temp) {
|
||||
zend_hash_destroy(properties);
|
||||
|
@ -727,13 +727,13 @@ static int validate_constant_array(HashTable *ht) /* {{{ */
|
||||
int ret = 1;
|
||||
zval *val;
|
||||
|
||||
ht->u.v.nApplyCount++;
|
||||
GC_PROTECT_RECURSION(ht);
|
||||
ZEND_HASH_FOREACH_VAL_IND(ht, val) {
|
||||
ZVAL_DEREF(val);
|
||||
if (Z_REFCOUNTED_P(val)) {
|
||||
if (Z_TYPE_P(val) == IS_ARRAY) {
|
||||
if (Z_REFCOUNTED_P(val)) {
|
||||
if (Z_ARRVAL_P(val)->u.v.nApplyCount > 0) {
|
||||
if (Z_IS_RECURSIVE_P(val)) {
|
||||
zend_error(E_WARNING, "Constants cannot be recursive arrays");
|
||||
ret = 0;
|
||||
break;
|
||||
@ -749,7 +749,7 @@ static int validate_constant_array(HashTable *ht) /* {{{ */
|
||||
}
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
ht->u.v.nApplyCount--;
|
||||
GC_UNPROTECT_RECURSION(ht);
|
||||
return ret;
|
||||
}
|
||||
/* }}} */
|
||||
@ -1137,7 +1137,7 @@ ZEND_FUNCTION(get_object_vars)
|
||||
|
||||
zobj = Z_OBJ_P(obj);
|
||||
|
||||
if (!zobj->ce->default_properties_count && properties == zobj->properties && !ZEND_HASH_GET_APPLY_COUNT(properties)) {
|
||||
if (!zobj->ce->default_properties_count && properties == zobj->properties && !GC_IS_RECURSIVE(properties)) {
|
||||
/* fast copy */
|
||||
if (EXPECTED(zobj->handlers == &std_object_handlers)) {
|
||||
RETURN_ARR(zend_proptable_to_symtable(properties, 0));
|
||||
|
@ -711,9 +711,9 @@ ZEND_METHOD(exception, __toString)
|
||||
zend_string_release(file);
|
||||
zval_ptr_dtor(&trace);
|
||||
|
||||
Z_OBJPROP_P(exception)->u.v.nApplyCount++;
|
||||
Z_PROTECT_RECURSION_P(exception);
|
||||
exception = GET_PROPERTY(exception, ZEND_STR_PREVIOUS);
|
||||
if (exception && Z_TYPE_P(exception) == IS_OBJECT && Z_OBJPROP_P(exception)->u.v.nApplyCount > 0) {
|
||||
if (exception && Z_TYPE_P(exception) == IS_OBJECT && Z_IS_RECURSIVE_P(exception)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -722,8 +722,8 @@ ZEND_METHOD(exception, __toString)
|
||||
exception = getThis();
|
||||
/* Reset apply counts */
|
||||
while (exception && Z_TYPE_P(exception) == IS_OBJECT && (base_ce = i_get_exception_base(exception)) && instanceof_function(Z_OBJCE_P(exception), base_ce)) {
|
||||
if (Z_OBJPROP_P(exception)->u.v.nApplyCount) {
|
||||
Z_OBJPROP_P(exception)->u.v.nApplyCount--;
|
||||
if (Z_IS_RECURSIVE_P(exception)) {
|
||||
Z_UNPROTECT_RECURSION_P(exception);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
@ -72,19 +72,6 @@ static void _zend_is_inconsistent(const HashTable *ht, const char *file, int lin
|
||||
#define SET_INCONSISTENT(n)
|
||||
#endif
|
||||
|
||||
#define HASH_PROTECT_RECURSION(ht) \
|
||||
if ((ht)->u.flags & HASH_FLAG_APPLY_PROTECTION) { \
|
||||
if (((ht)->u.flags & ZEND_HASH_APPLY_COUNT_MASK) >= (3 << ZEND_HASH_APPLY_SHIFT)) {\
|
||||
zend_error_noreturn(E_ERROR, "Nesting level too deep - recursive dependency?");\
|
||||
} \
|
||||
ZEND_HASH_INC_APPLY_COUNT(ht); \
|
||||
}
|
||||
|
||||
#define HASH_UNPROTECT_RECURSION(ht) \
|
||||
if ((ht)->u.flags & HASH_FLAG_APPLY_PROTECTION) { \
|
||||
ZEND_HASH_DEC_APPLY_COUNT(ht); \
|
||||
}
|
||||
|
||||
#define ZEND_HASH_IF_FULL_DO_RESIZE(ht) \
|
||||
if ((ht)->nNumUsed >= (ht)->nTableSize) { \
|
||||
zend_hash_do_resize(ht); \
|
||||
@ -170,11 +157,11 @@ static zend_always_inline void zend_hash_check_init(HashTable *ht, int packed)
|
||||
static const uint32_t uninitialized_bucket[-HT_MIN_MASK] =
|
||||
{HT_INVALID_IDX, HT_INVALID_IDX};
|
||||
|
||||
static zend_always_inline void _zend_hash_init_int(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent, zend_bool bApplyProtection)
|
||||
static zend_always_inline void _zend_hash_init_int(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent)
|
||||
{
|
||||
GC_REFCOUNT(ht) = 1;
|
||||
GC_TYPE_INFO(ht) = IS_ARRAY | (persistent ? 0 : (GC_COLLECTABLE << GC_FLAGS_SHIFT));
|
||||
ht->u.flags = (persistent ? HASH_FLAG_PERSISTENT : 0) | (bApplyProtection ? HASH_FLAG_APPLY_PROTECTION : 0) | HASH_FLAG_STATIC_KEYS;
|
||||
ht->u.flags = (persistent ? HASH_FLAG_PERSISTENT : 0) | HASH_FLAG_STATIC_KEYS;
|
||||
ht->nTableMask = HT_MIN_MASK;
|
||||
HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
|
||||
ht->nNumUsed = 0;
|
||||
@ -187,13 +174,13 @@ static zend_always_inline void _zend_hash_init_int(HashTable *ht, uint32_t nSize
|
||||
|
||||
ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent)
|
||||
{
|
||||
_zend_hash_init_int(ht, nSize, pDestructor, persistent, 1);
|
||||
_zend_hash_init_int(ht, nSize, pDestructor, persistent);
|
||||
}
|
||||
|
||||
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array(uint32_t nSize ZEND_FILE_LINE_DC)
|
||||
{
|
||||
HashTable *ht = emalloc(sizeof(HashTable));
|
||||
_zend_hash_init_int(ht, nSize, ZVAL_PTR_DTOR, 0, 1);
|
||||
_zend_hash_init_int(ht, nSize, ZVAL_PTR_DTOR, 0);
|
||||
return ht;
|
||||
}
|
||||
|
||||
@ -245,11 +232,6 @@ ZEND_API void ZEND_FASTCALL zend_hash_to_packed(HashTable *ht)
|
||||
pefree(old_data, (ht)->u.flags & HASH_FLAG_PERSISTENT);
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL _zend_hash_init_ex(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent, zend_bool bApplyProtection)
|
||||
{
|
||||
_zend_hash_init_int(ht, nSize, pDestructor, persistent, bApplyProtection);
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, zend_bool packed)
|
||||
{
|
||||
HT_ASSERT_RC1(ht);
|
||||
@ -317,15 +299,6 @@ ZEND_API uint32_t zend_array_count(HashTable *ht)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_set_apply_protection(HashTable *ht, zend_bool bApplyProtection)
|
||||
{
|
||||
if (bApplyProtection) {
|
||||
ht->u.flags |= HASH_FLAG_APPLY_PROTECTION;
|
||||
} else {
|
||||
ht->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API uint32_t ZEND_FASTCALL zend_hash_iterator_add(HashTable *ht, HashPosition pos)
|
||||
{
|
||||
HashTableIterator *iter = EG(ht_iterators);
|
||||
@ -1508,7 +1481,6 @@ ZEND_API void ZEND_FASTCALL zend_hash_apply(HashTable *ht, apply_func_t apply_fu
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
HASH_PROTECT_RECURSION(ht);
|
||||
for (idx = 0; idx < ht->nNumUsed; idx++) {
|
||||
p = ht->arData + idx;
|
||||
if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
|
||||
@ -1522,7 +1494,6 @@ ZEND_API void ZEND_FASTCALL zend_hash_apply(HashTable *ht, apply_func_t apply_fu
|
||||
break;
|
||||
}
|
||||
}
|
||||
HASH_UNPROTECT_RECURSION(ht);
|
||||
}
|
||||
|
||||
|
||||
@ -1534,7 +1505,6 @@ ZEND_API void ZEND_FASTCALL zend_hash_apply_with_argument(HashTable *ht, apply_f
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
HASH_PROTECT_RECURSION(ht);
|
||||
for (idx = 0; idx < ht->nNumUsed; idx++) {
|
||||
p = ht->arData + idx;
|
||||
if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
|
||||
@ -1548,7 +1518,6 @@ ZEND_API void ZEND_FASTCALL zend_hash_apply_with_argument(HashTable *ht, apply_f
|
||||
break;
|
||||
}
|
||||
}
|
||||
HASH_UNPROTECT_RECURSION(ht);
|
||||
}
|
||||
|
||||
|
||||
@ -1562,8 +1531,6 @@ ZEND_API void ZEND_FASTCALL zend_hash_apply_with_arguments(HashTable *ht, apply_
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
HASH_PROTECT_RECURSION(ht);
|
||||
|
||||
for (idx = 0; idx < ht->nNumUsed; idx++) {
|
||||
p = ht->arData + idx;
|
||||
if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;
|
||||
@ -1583,8 +1550,6 @@ ZEND_API void ZEND_FASTCALL zend_hash_apply_with_arguments(HashTable *ht, apply_
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
HASH_UNPROTECT_RECURSION(ht);
|
||||
}
|
||||
|
||||
|
||||
@ -1596,7 +1561,6 @@ ZEND_API void ZEND_FASTCALL zend_hash_reverse_apply(HashTable *ht, apply_func_t
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
HASH_PROTECT_RECURSION(ht);
|
||||
idx = ht->nNumUsed;
|
||||
while (idx > 0) {
|
||||
idx--;
|
||||
@ -1613,7 +1577,6 @@ ZEND_API void ZEND_FASTCALL zend_hash_reverse_apply(HashTable *ht, apply_func_t
|
||||
break;
|
||||
}
|
||||
}
|
||||
HASH_UNPROTECT_RECURSION(ht);
|
||||
}
|
||||
|
||||
|
||||
@ -1776,7 +1739,7 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source)
|
||||
target->pDestructor = source->pDestructor;
|
||||
|
||||
if (source->nNumUsed == 0) {
|
||||
target->u.flags = (source->u.flags & ~(HASH_FLAG_INITIALIZED|HASH_FLAG_PACKED|HASH_FLAG_PERSISTENT|ZEND_HASH_APPLY_COUNT_MASK)) | HASH_FLAG_APPLY_PROTECTION | HASH_FLAG_STATIC_KEYS;
|
||||
target->u.flags = (source->u.flags & ~(HASH_FLAG_INITIALIZED|HASH_FLAG_PACKED|HASH_FLAG_PERSISTENT)) | HASH_FLAG_STATIC_KEYS;
|
||||
target->nTableMask = HT_MIN_MASK;
|
||||
target->nNumUsed = 0;
|
||||
target->nNumOfElements = 0;
|
||||
@ -1784,7 +1747,7 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source)
|
||||
target->nInternalPointer = HT_INVALID_IDX;
|
||||
HT_SET_DATA_ADDR(target, &uninitialized_bucket);
|
||||
} else if (GC_FLAGS(source) & IS_ARRAY_IMMUTABLE) {
|
||||
target->u.flags = (source->u.flags & ~HASH_FLAG_PERSISTENT) | HASH_FLAG_APPLY_PROTECTION;
|
||||
target->u.flags = source->u.flags & ~HASH_FLAG_PERSISTENT;
|
||||
target->nTableMask = source->nTableMask;
|
||||
target->nNumUsed = source->nNumUsed;
|
||||
target->nNumOfElements = source->nNumOfElements;
|
||||
@ -1801,7 +1764,7 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source)
|
||||
target->nInternalPointer = idx;
|
||||
}
|
||||
} else if (source->u.flags & HASH_FLAG_PACKED) {
|
||||
target->u.flags = (source->u.flags & ~(HASH_FLAG_PERSISTENT|ZEND_HASH_APPLY_COUNT_MASK)) | HASH_FLAG_APPLY_PROTECTION;
|
||||
target->u.flags = source->u.flags & ~HASH_FLAG_PERSISTENT;
|
||||
target->nTableMask = source->nTableMask;
|
||||
target->nNumUsed = source->nNumUsed;
|
||||
target->nNumOfElements = source->nNumOfElements;
|
||||
@ -1824,7 +1787,7 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source)
|
||||
target->nInternalPointer = idx;
|
||||
}
|
||||
} else {
|
||||
target->u.flags = (source->u.flags & ~(HASH_FLAG_PERSISTENT|ZEND_HASH_APPLY_COUNT_MASK)) | HASH_FLAG_APPLY_PROTECTION;
|
||||
target->u.flags = source->u.flags & ~HASH_FLAG_PERSISTENT;
|
||||
target->nTableMask = source->nTableMask;
|
||||
target->nNextFreeElement = source->nNextFreeElement;
|
||||
target->nInternalPointer = source->nInternalPointer;
|
||||
@ -2402,11 +2365,28 @@ ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t co
|
||||
IS_CONSISTENT(ht1);
|
||||
IS_CONSISTENT(ht2);
|
||||
|
||||
HASH_PROTECT_RECURSION(ht1);
|
||||
HASH_PROTECT_RECURSION(ht2);
|
||||
if (ht1 == ht2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* use bitwise OR to make only one conditional jump */
|
||||
if (UNEXPECTED(GC_IS_RECURSIVE(ht1) | GC_IS_RECURSIVE(ht2))) {
|
||||
zend_error_noreturn(E_ERROR, "Nesting level too deep - recursive dependency?");
|
||||
}
|
||||
|
||||
if (!(GC_FLAGS(ht1) & GC_IMMUTABLE)) {
|
||||
GC_PROTECT_RECURSION(ht1);
|
||||
}
|
||||
if (!(GC_FLAGS(ht2) & GC_IMMUTABLE)) {
|
||||
GC_PROTECT_RECURSION(ht2);
|
||||
}
|
||||
result = zend_hash_compare_impl(ht1, ht2, compar, ordered);
|
||||
HASH_UNPROTECT_RECURSION(ht1);
|
||||
HASH_UNPROTECT_RECURSION(ht2);
|
||||
if (!(GC_FLAGS(ht1) & GC_IMMUTABLE)) {
|
||||
GC_UNPROTECT_RECURSION(ht1);
|
||||
}
|
||||
if (!(GC_FLAGS(ht2) & GC_IMMUTABLE)) {
|
||||
GC_UNPROTECT_RECURSION(ht2);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -36,7 +36,6 @@
|
||||
#define HASH_ADD_NEXT (1<<4)
|
||||
|
||||
#define HASH_FLAG_PERSISTENT (1<<0)
|
||||
#define HASH_FLAG_APPLY_PROTECTION (1<<1)
|
||||
#define HASH_FLAG_PACKED (1<<2)
|
||||
#define HASH_FLAG_INITIALIZED (1<<3)
|
||||
#define HASH_FLAG_STATIC_KEYS (1<<4) /* long and interned strings */
|
||||
@ -69,14 +68,13 @@ BEGIN_EXTERN_C()
|
||||
|
||||
/* startup/shutdown */
|
||||
ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent);
|
||||
ZEND_API void ZEND_FASTCALL _zend_hash_init_ex(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent, zend_bool bApplyProtection);
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht);
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht);
|
||||
|
||||
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent) \
|
||||
_zend_hash_init((ht), (nSize), (pDestructor), (persistent))
|
||||
#define zend_hash_init_ex(ht, nSize, pHashFunction, pDestructor, persistent, bApplyProtection) \
|
||||
_zend_hash_init_ex((ht), (nSize), (pDestructor), (persistent), (bApplyProtection))
|
||||
_zend_hash_init((ht), (nSize), (pDestructor), (persistent))
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_real_init(HashTable *ht, zend_bool packed);
|
||||
ZEND_API void ZEND_FASTCALL zend_hash_packed_to_hash(HashTable *ht);
|
||||
@ -985,16 +983,6 @@ static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht,
|
||||
_key = _p->key; \
|
||||
_val = _z;
|
||||
|
||||
#define ZEND_HASH_APPLY_PROTECTION(ht) \
|
||||
((ht)->u.flags & HASH_FLAG_APPLY_PROTECTION)
|
||||
|
||||
#define ZEND_HASH_APPLY_SHIFT 8
|
||||
#define ZEND_HASH_APPLY_COUNT_MASK 0xff00
|
||||
#define ZEND_HASH_GET_APPLY_COUNT(ht) (((ht)->u.flags & ZEND_HASH_APPLY_COUNT_MASK) >> ZEND_HASH_APPLY_SHIFT)
|
||||
#define ZEND_HASH_INC_APPLY_COUNT(ht) ((ht)->u.flags += (1 << ZEND_HASH_APPLY_SHIFT))
|
||||
#define ZEND_HASH_DEC_APPLY_COUNT(ht) ((ht)->u.flags -= (1 << ZEND_HASH_APPLY_SHIFT))
|
||||
|
||||
|
||||
/* The following macros are useful to insert a sequence of new elements
|
||||
* of packed array. They may be use insted of series of
|
||||
* zend_hash_next_index_insert_new()
|
||||
|
@ -44,18 +44,6 @@
|
||||
#define IN_UNSET (1<<2)
|
||||
#define IN_ISSET (1<<3)
|
||||
|
||||
#define Z_OBJ_PROTECT_RECURSION(zval_p) \
|
||||
do { \
|
||||
if (Z_OBJ_APPLY_COUNT_P(zval_p) >= 3) { \
|
||||
zend_error_noreturn(E_ERROR, "Nesting level too deep - recursive dependency?"); \
|
||||
} \
|
||||
Z_OBJ_INC_APPLY_COUNT_P(zval_p); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define Z_OBJ_UNPROTECT_RECURSION(zval_p) \
|
||||
Z_OBJ_DEC_APPLY_COUNT_P(zval_p)
|
||||
|
||||
/*
|
||||
__X accessors explanation:
|
||||
|
||||
@ -1444,6 +1432,9 @@ static int zend_std_compare_objects(zval *o1, zval *o2) /* {{{ */
|
||||
zobj1 = Z_OBJ_P(o1);
|
||||
zobj2 = Z_OBJ_P(o2);
|
||||
|
||||
if (zobj1 == zobj2) {
|
||||
return 0; /* the same object */
|
||||
}
|
||||
if (zobj1->ce != zobj2->ce) {
|
||||
return 1; /* different classes */
|
||||
}
|
||||
@ -1456,40 +1447,45 @@ static int zend_std_compare_objects(zval *o1, zval *o2) /* {{{ */
|
||||
p1 = zobj1->properties_table;
|
||||
p2 = zobj2->properties_table;
|
||||
end = p1 + zobj1->ce->default_properties_count;
|
||||
Z_OBJ_PROTECT_RECURSION(o1);
|
||||
Z_OBJ_PROTECT_RECURSION(o2);
|
||||
|
||||
/* use bitwise OR to make only one conditional jump */
|
||||
if (UNEXPECTED(Z_IS_RECURSIVE_P(o1) | Z_IS_RECURSIVE_P(o2))) {
|
||||
zend_error_noreturn(E_ERROR, "Nesting level too deep - recursive dependency?");
|
||||
}
|
||||
Z_PROTECT_RECURSION_P(o1);
|
||||
Z_PROTECT_RECURSION_P(o2);
|
||||
do {
|
||||
if (Z_TYPE_P(p1) != IS_UNDEF) {
|
||||
if (Z_TYPE_P(p2) != IS_UNDEF) {
|
||||
zval result;
|
||||
|
||||
if (compare_function(&result, p1, p2)==FAILURE) {
|
||||
Z_OBJ_UNPROTECT_RECURSION(o1);
|
||||
Z_OBJ_UNPROTECT_RECURSION(o2);
|
||||
Z_UNPROTECT_RECURSION_P(o1);
|
||||
Z_UNPROTECT_RECURSION_P(o2);
|
||||
return 1;
|
||||
}
|
||||
if (Z_LVAL(result) != 0) {
|
||||
Z_OBJ_UNPROTECT_RECURSION(o1);
|
||||
Z_OBJ_UNPROTECT_RECURSION(o2);
|
||||
Z_UNPROTECT_RECURSION_P(o1);
|
||||
Z_UNPROTECT_RECURSION_P(o2);
|
||||
return Z_LVAL(result);
|
||||
}
|
||||
} else {
|
||||
Z_OBJ_UNPROTECT_RECURSION(o1);
|
||||
Z_OBJ_UNPROTECT_RECURSION(o2);
|
||||
Z_UNPROTECT_RECURSION_P(o1);
|
||||
Z_UNPROTECT_RECURSION_P(o2);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (Z_TYPE_P(p2) != IS_UNDEF) {
|
||||
Z_OBJ_UNPROTECT_RECURSION(o1);
|
||||
Z_OBJ_UNPROTECT_RECURSION(o2);
|
||||
Z_UNPROTECT_RECURSION_P(o1);
|
||||
Z_UNPROTECT_RECURSION_P(o2);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
p1++;
|
||||
p2++;
|
||||
} while (p1 != end);
|
||||
Z_OBJ_UNPROTECT_RECURSION(o1);
|
||||
Z_OBJ_UNPROTECT_RECURSION(o2);
|
||||
Z_UNPROTECT_RECURSION_P(o1);
|
||||
Z_UNPROTECT_RECURSION_P(o2);
|
||||
return 0;
|
||||
} else {
|
||||
if (!zobj1->properties) {
|
||||
|
@ -607,7 +607,7 @@ try_again:
|
||||
/* fast copy */
|
||||
if (!Z_OBJCE_P(op)->default_properties_count &&
|
||||
obj_ht == Z_OBJ_P(op)->properties &&
|
||||
!ZEND_HASH_GET_APPLY_COUNT(Z_OBJ_P(op)->properties) &&
|
||||
!GC_IS_RECURSIVE(obj_ht) &&
|
||||
EXPECTED(Z_OBJ_P(op)->handlers == &std_object_handlers)) {
|
||||
arr = zend_proptable_to_symtable(obj_ht, 0);
|
||||
} else {
|
||||
|
@ -69,16 +69,6 @@ ZEND_API void _zend_ts_hash_init(TsHashTable *ht, uint32_t nSize, dtor_func_t pD
|
||||
_zend_hash_init(TS_HASH(ht), nSize, pDestructor, persistent);
|
||||
}
|
||||
|
||||
ZEND_API void _zend_ts_hash_init_ex(TsHashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent, zend_bool bApplyProtection)
|
||||
{
|
||||
#ifdef ZTS
|
||||
ht->mx_reader = tsrm_mutex_alloc();
|
||||
ht->mx_writer = tsrm_mutex_alloc();
|
||||
ht->reader = 0;
|
||||
#endif
|
||||
_zend_hash_init_ex(TS_HASH(ht), nSize, pDestructor, persistent, bApplyProtection);
|
||||
}
|
||||
|
||||
ZEND_API void zend_ts_hash_destroy(TsHashTable *ht)
|
||||
{
|
||||
begin_write(ht);
|
||||
|
@ -38,14 +38,13 @@ BEGIN_EXTERN_C()
|
||||
|
||||
/* startup/shutdown */
|
||||
ZEND_API void _zend_ts_hash_init(TsHashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent);
|
||||
ZEND_API void _zend_ts_hash_init_ex(TsHashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent, zend_bool bApplyProtection);
|
||||
ZEND_API void zend_ts_hash_destroy(TsHashTable *ht);
|
||||
ZEND_API void zend_ts_hash_clean(TsHashTable *ht);
|
||||
|
||||
#define zend_ts_hash_init(ht, nSize, pHashFunction, pDestructor, persistent) \
|
||||
_zend_ts_hash_init(ht, nSize, pDestructor, persistent)
|
||||
#define zend_ts_hash_init_ex(ht, nSize, pHashFunction, pDestructor, persistent, bApplyProtection) \
|
||||
_zend_ts_hash_init_ex(ht, nSize, pDestructor, persistent, bApplyProtection)
|
||||
_zend_ts_hash_init(ht, nSize, pDestructor, persistent)
|
||||
|
||||
|
||||
/* additions/updates/changes */
|
||||
|
@ -239,7 +239,7 @@ struct _zend_array {
|
||||
struct {
|
||||
ZEND_ENDIAN_LOHI_4(
|
||||
zend_uchar flags,
|
||||
zend_uchar nApplyCount,
|
||||
zend_uchar _unused,
|
||||
zend_uchar nIteratorsCount,
|
||||
zend_uchar consistency)
|
||||
} v;
|
||||
@ -455,7 +455,9 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
|
||||
#define GC_INFO_SHIFT 16
|
||||
#define GC_INFO_MASK 0xffff0000
|
||||
|
||||
/* zval.value->gc.u.v.flags */
|
||||
/* zval.value->gc.u.v.flags (common flags) */
|
||||
#define GC_PROTECTED (1<<0) /* used for array/object recursion detection */
|
||||
#define GC_IMMUTABLE (1<<1) /* string/array can't be canged in place */
|
||||
#define GC_COLLECTABLE (1<<7)
|
||||
|
||||
#define GC_ARRAY (IS_ARRAY | (GC_COLLECTABLE << GC_FLAGS_SHIFT))
|
||||
@ -490,37 +492,38 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
|
||||
|
||||
/* string flags (zval.value->gc.u.flags) */
|
||||
#define IS_STR_PERSISTENT (1<<0) /* allocated using malloc */
|
||||
#define IS_STR_INTERNED (1<<1) /* interned string */
|
||||
#define IS_STR_INTERNED GC_IMMUTABLE /* interned string */
|
||||
#define IS_STR_PERMANENT (1<<2) /* relives request boundary */
|
||||
|
||||
/* array flags */
|
||||
#define IS_ARRAY_IMMUTABLE (1<<1)
|
||||
#define IS_ARRAY_PROTECTED GC_PROTECTED
|
||||
#define IS_ARRAY_IMMUTABLE GC_IMMUTABLE
|
||||
|
||||
/* object flags (zval.value->gc.u.flags) */
|
||||
#define IS_OBJ_APPLY_COUNT 0x07
|
||||
#define IS_OBJ_PROTECTED GC_PROTECTED
|
||||
#define IS_OBJ_DESTRUCTOR_CALLED (1<<3)
|
||||
#define IS_OBJ_FREE_CALLED (1<<4)
|
||||
#define IS_OBJ_USE_GUARDS (1<<5)
|
||||
#define IS_OBJ_HAS_GUARDS (1<<6)
|
||||
|
||||
#define Z_OBJ_APPLY_COUNT(zval) \
|
||||
(Z_GC_FLAGS(zval) & IS_OBJ_APPLY_COUNT)
|
||||
/* Recursion protection macros must be used only for arrays and objects */
|
||||
#define GC_IS_RECURSIVE(p) \
|
||||
(GC_FLAGS(p) & GC_PROTECTED)
|
||||
|
||||
#define Z_OBJ_INC_APPLY_COUNT(zval) do { \
|
||||
Z_GC_FLAGS(zval) = \
|
||||
(Z_GC_FLAGS(zval) & ~IS_OBJ_APPLY_COUNT) | \
|
||||
((Z_GC_FLAGS(zval) & IS_OBJ_APPLY_COUNT) + 1); \
|
||||
#define GC_PROTECT_RECURSION(p) do { \
|
||||
GC_FLAGS(p) |= GC_PROTECTED; \
|
||||
} while (0)
|
||||
|
||||
#define Z_OBJ_DEC_APPLY_COUNT(zval) do { \
|
||||
Z_GC_FLAGS(zval) = \
|
||||
(Z_GC_FLAGS(zval) & ~IS_OBJ_APPLY_COUNT) | \
|
||||
((Z_GC_FLAGS(zval) & IS_OBJ_APPLY_COUNT) - 1); \
|
||||
#define GC_UNPROTECT_RECURSION(p) do { \
|
||||
GC_FLAGS(p) &= ~GC_PROTECTED; \
|
||||
} while (0)
|
||||
|
||||
#define Z_OBJ_APPLY_COUNT_P(zv) Z_OBJ_APPLY_COUNT(*(zv))
|
||||
#define Z_OBJ_INC_APPLY_COUNT_P(zv) Z_OBJ_INC_APPLY_COUNT(*(zv))
|
||||
#define Z_OBJ_DEC_APPLY_COUNT_P(zv) Z_OBJ_DEC_APPLY_COUNT(*(zv))
|
||||
#define Z_IS_RECURSIVE(zval) GC_IS_RECURSIVE(Z_COUNTED(zval))
|
||||
#define Z_PROTECT_RECURSION(zval) GC_PROTECT_RECURSION(Z_COUNTED(zval))
|
||||
#define Z_UNPROTECT_RECURSION(zval) GC_UNPROTECT_RECURSION(Z_COUNTED(zval))
|
||||
#define Z_IS_RECURSIVE_P(zv) Z_IS_RECURSIVE(*(zv))
|
||||
#define Z_PROTECT_RECURSION_P(zv) Z_PROTECT_RECURSION(*(zv))
|
||||
#define Z_UNPROTECT_RECURSION_P(zv) Z_UNPROTECT_RECURSION(*(zv))
|
||||
|
||||
/* All data types < IS_STRING have their constructor/destructors skipped */
|
||||
#define Z_CONSTANT(zval) ((Z_TYPE_FLAGS(zval) & IS_TYPE_CONSTANT) != 0)
|
||||
|
@ -503,21 +503,21 @@ static void php_zval_filter_recursive(zval *value, zend_long filter, zend_long f
|
||||
if (Z_TYPE_P(value) == IS_ARRAY) {
|
||||
zval *element;
|
||||
|
||||
if (Z_ARRVAL_P(value)->u.v.nApplyCount > 1) {
|
||||
if (Z_IS_RECURSIVE_P(value)) {
|
||||
return;
|
||||
}
|
||||
Z_PROTECT_RECURSION_P(value);
|
||||
|
||||
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(value), element) {
|
||||
ZVAL_DEREF(element);
|
||||
SEPARATE_ZVAL_NOREF(element);
|
||||
if (Z_TYPE_P(element) == IS_ARRAY) {
|
||||
Z_ARRVAL_P(element)->u.v.nApplyCount++;
|
||||
php_zval_filter_recursive(element, filter, flags, options, charset, copy);
|
||||
Z_ARRVAL_P(element)->u.v.nApplyCount--;
|
||||
} else {
|
||||
php_zval_filter(element, filter, flags, options, charset, copy);
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
Z_UNPROTECT_RECURSION_P(value);
|
||||
} else {
|
||||
php_zval_filter(value, filter, flags, options, charset, copy);
|
||||
}
|
||||
|
@ -113,17 +113,17 @@ static inline void php_json_encode_double(smart_str *buf, double d, int options)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
#define PHP_JSON_HASH_APPLY_PROTECTION_INC(_tmp_ht) \
|
||||
#define PHP_JSON_HASH_PROTECT_RECURSION(_tmp_ht) \
|
||||
do { \
|
||||
if (_tmp_ht && ZEND_HASH_APPLY_PROTECTION(_tmp_ht)) { \
|
||||
ZEND_HASH_INC_APPLY_COUNT(_tmp_ht); \
|
||||
if (_tmp_ht && !(GC_FLAGS(_tmp_ht) & GC_IMMUTABLE)) { \
|
||||
GC_PROTECT_RECURSION(_tmp_ht); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PHP_JSON_HASH_APPLY_PROTECTION_DEC(_tmp_ht) \
|
||||
#define PHP_JSON_HASH_UNPROTECT_RECURSION(_tmp_ht) \
|
||||
do { \
|
||||
if (_tmp_ht && ZEND_HASH_APPLY_PROTECTION(_tmp_ht)) { \
|
||||
ZEND_HASH_DEC_APPLY_COUNT(_tmp_ht); \
|
||||
if (_tmp_ht && !(GC_FLAGS(_tmp_ht) & GC_IMMUTABLE)) { \
|
||||
GC_UNPROTECT_RECURSION(_tmp_ht); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
@ -140,13 +140,13 @@ static int php_json_encode_array(smart_str *buf, zval *val, int options, php_jso
|
||||
r = PHP_JSON_OUTPUT_OBJECT;
|
||||
}
|
||||
|
||||
if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 0) {
|
||||
if (myht && GC_IS_RECURSIVE(myht)) {
|
||||
encoder->error_code = PHP_JSON_ERROR_RECURSION;
|
||||
smart_str_appendl(buf, "null", 4);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
PHP_JSON_HASH_APPLY_PROTECTION_INC(myht);
|
||||
PHP_JSON_HASH_PROTECT_RECURSION(myht);
|
||||
|
||||
if (r == PHP_JSON_OUTPUT_ARRAY) {
|
||||
smart_str_appendc(buf, '[');
|
||||
@ -212,13 +212,13 @@ static int php_json_encode_array(smart_str *buf, zval *val, int options, php_jso
|
||||
|
||||
if (php_json_encode_zval(buf, data, options, encoder) == FAILURE &&
|
||||
!(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
|
||||
PHP_JSON_HASH_APPLY_PROTECTION_DEC(myht);
|
||||
PHP_JSON_HASH_UNPROTECT_RECURSION(myht);
|
||||
return FAILURE;
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
||||
PHP_JSON_HASH_APPLY_PROTECTION_DEC(myht);
|
||||
PHP_JSON_HASH_UNPROTECT_RECURSION(myht);
|
||||
|
||||
if (encoder->depth > encoder->max_depth) {
|
||||
encoder->error_code = PHP_JSON_ERROR_DEPTH;
|
||||
@ -445,7 +445,7 @@ static int php_json_encode_serializable_object(smart_str *buf, zval *val, int op
|
||||
zval retval, fname;
|
||||
int return_code;
|
||||
|
||||
if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 0) {
|
||||
if (myht && GC_IS_RECURSIVE(myht)) {
|
||||
encoder->error_code = PHP_JSON_ERROR_RECURSION;
|
||||
if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
|
||||
smart_str_appendl(buf, "null", 4);
|
||||
@ -453,7 +453,7 @@ static int php_json_encode_serializable_object(smart_str *buf, zval *val, int op
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
PHP_JSON_HASH_APPLY_PROTECTION_INC(myht);
|
||||
PHP_JSON_HASH_PROTECT_RECURSION(myht);
|
||||
|
||||
ZVAL_STRING(&fname, "jsonSerialize");
|
||||
|
||||
@ -466,7 +466,7 @@ static int php_json_encode_serializable_object(smart_str *buf, zval *val, int op
|
||||
if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
|
||||
smart_str_appendl(buf, "null", 4);
|
||||
}
|
||||
PHP_JSON_HASH_APPLY_PROTECTION_DEC(myht);
|
||||
PHP_JSON_HASH_UNPROTECT_RECURSION(myht);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
@ -478,19 +478,19 @@ static int php_json_encode_serializable_object(smart_str *buf, zval *val, int op
|
||||
if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) {
|
||||
smart_str_appendl(buf, "null", 4);
|
||||
}
|
||||
PHP_JSON_HASH_APPLY_PROTECTION_DEC(myht);
|
||||
PHP_JSON_HASH_UNPROTECT_RECURSION(myht);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if ((Z_TYPE(retval) == IS_OBJECT) &&
|
||||
(Z_OBJ(retval) == Z_OBJ_P(val))) {
|
||||
/* Handle the case where jsonSerialize does: return $this; by going straight to encode array */
|
||||
PHP_JSON_HASH_APPLY_PROTECTION_DEC(myht);
|
||||
PHP_JSON_HASH_UNPROTECT_RECURSION(myht);
|
||||
return_code = php_json_encode_array(buf, &retval, options, encoder);
|
||||
} else {
|
||||
/* All other types, encode as normal */
|
||||
return_code = php_json_encode_zval(buf, &retval, options, encoder);
|
||||
PHP_JSON_HASH_APPLY_PROTECTION_DEC(myht);
|
||||
PHP_JSON_HASH_UNPROTECT_RECURSION(myht);
|
||||
}
|
||||
|
||||
zval_ptr_dtor(&retval);
|
||||
|
@ -3129,11 +3129,12 @@ MBSTRING_API HashTable *php_mb_convert_encoding_recursive(HashTable *input, cons
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (input->u.v.nApplyCount++ > 1) {
|
||||
input->u.v.nApplyCount--;
|
||||
if (GC_IS_RECURSIVE(input)) {
|
||||
GC_UNPROTECT_RECURSION(input);
|
||||
php_error_docref(NULL, E_WARNING, "Cannot convert recursively referenced values");
|
||||
return NULL;
|
||||
}
|
||||
GC_PROTECT_RECURSION(input);
|
||||
output = zend_new_array(zend_hash_num_elements(input));
|
||||
ZEND_HASH_FOREACH_KEY_VAL(input, idx, key, entry) {
|
||||
/* convert key */
|
||||
@ -3177,7 +3178,7 @@ MBSTRING_API HashTable *php_mb_convert_encoding_recursive(HashTable *input, cons
|
||||
zend_hash_index_add(output, idx, &entry_tmp);
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
input->u.v.nApplyCount--;
|
||||
GC_UNPROTECT_RECURSION(input);
|
||||
|
||||
return output;
|
||||
}
|
||||
@ -3764,11 +3765,11 @@ PHP_FUNCTION(mb_convert_variables)
|
||||
if (target_hash != NULL) {
|
||||
while ((hash_entry = zend_hash_get_current_data(target_hash)) != NULL) {
|
||||
if (Z_REFCOUNTED_P(var)) {
|
||||
if (++target_hash->u.v.nApplyCount > 1) {
|
||||
--target_hash->u.v.nApplyCount;
|
||||
if (GC_IS_RECURSIVE(target_hash)) {
|
||||
recursion_error = 1;
|
||||
goto detect_end;
|
||||
}
|
||||
GC_PROTECT_RECURSION(target_hash);
|
||||
}
|
||||
zend_hash_move_forward(target_hash);
|
||||
if (Z_TYPE_P(hash_entry) == IS_INDIRECT) {
|
||||
@ -3813,9 +3814,7 @@ detect_end:
|
||||
if (recursion_error) {
|
||||
while(stack_level-- && (var = &stack[stack_level])) {
|
||||
if (Z_REFCOUNTED_P(var)) {
|
||||
if (HASH_OF(var)->u.v.nApplyCount > 1) {
|
||||
HASH_OF(var)->u.v.nApplyCount--;
|
||||
}
|
||||
Z_UNPROTECT_RECURSION_P(var);
|
||||
}
|
||||
}
|
||||
efree(stack);
|
||||
@ -3880,11 +3879,11 @@ detect_end:
|
||||
ZVAL_DEREF(hash_entry);
|
||||
if (Z_TYPE_P(hash_entry) == IS_ARRAY || Z_TYPE_P(hash_entry) == IS_OBJECT) {
|
||||
if (Z_REFCOUNTED_P(hash_entry)) {
|
||||
if (++(HASH_OF(hash_entry)->u.v.nApplyCount) > 1) {
|
||||
--(HASH_OF(hash_entry)->u.v.nApplyCount);
|
||||
if (Z_IS_RECURSIVE_P(hash_entry)) {
|
||||
recursion_error = 1;
|
||||
goto conv_end;
|
||||
}
|
||||
Z_PROTECT_RECURSION_P(hash_entry);
|
||||
}
|
||||
if (stack_level >= stack_max) {
|
||||
stack_max += PHP_MBSTR_STACK_BLOCK_SIZE;
|
||||
@ -3933,9 +3932,7 @@ conv_end:
|
||||
if (recursion_error) {
|
||||
while(stack_level-- && (var = &stack[stack_level])) {
|
||||
if (Z_REFCOUNTED_P(var)) {
|
||||
if (HASH_OF(var)->u.v.nApplyCount > 1) {
|
||||
HASH_OF(var)->u.v.nApplyCount--;
|
||||
}
|
||||
Z_UNPROTECT_RECURSION_P(var);
|
||||
}
|
||||
}
|
||||
efree(stack);
|
||||
@ -4787,12 +4784,12 @@ MBSTRING_API int php_mb_check_encoding_recursive(HashTable *vars, const zend_str
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vars->u.v.nApplyCount++ > 1) {
|
||||
vars->u.v.nApplyCount--;
|
||||
if (GC_IS_RECURSIVE(vars)) {
|
||||
mbfl_buffer_converter_delete(convd);
|
||||
php_error_docref(NULL, E_WARNING, "Cannot not handle circular references");
|
||||
return 0;
|
||||
}
|
||||
GC_PROTECT_RECURSION(vars);
|
||||
ZEND_HASH_FOREACH_KEY_VAL(vars, idx, key, entry) {
|
||||
ZVAL_DEREF(entry);
|
||||
if (key) {
|
||||
@ -4826,7 +4823,7 @@ MBSTRING_API int php_mb_check_encoding_recursive(HashTable *vars, const zend_str
|
||||
break;
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
vars->u.v.nApplyCount--;
|
||||
GC_UNPROTECT_RECURSION(vars);
|
||||
mbfl_buffer_converter_delete(convd);
|
||||
return valid;
|
||||
}
|
||||
|
@ -49,5 +49,16 @@ array(5) {
|
||||
[3]=>
|
||||
string(21) "日本語テキスト"
|
||||
[4]=>
|
||||
*RECURSION*
|
||||
}
|
||||
&array(5) {
|
||||
[0]=>
|
||||
string(21) "日本語テキスト"
|
||||
[1]=>
|
||||
string(21) "日本語テキスト"
|
||||
[2]=>
|
||||
string(21) "日本語テキスト"
|
||||
[3]=>
|
||||
string(21) "日本語テキスト"
|
||||
[4]=>
|
||||
*RECURSION*
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ static void zend_hash_clone_constants(HashTable *ht, HashTable *source)
|
||||
ht->nNumOfElements = source->nNumOfElements;
|
||||
ht->nNextFreeElement = source->nNextFreeElement;
|
||||
ht->pDestructor = ZVAL_PTR_DTOR;
|
||||
ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED) | HASH_FLAG_APPLY_PROTECTION;
|
||||
ht->u.flags = (source->u.flags & HASH_FLAG_INITIALIZED);
|
||||
ht->nInternalPointer = source->nNumOfElements ? 0 : HT_INVALID_IDX;
|
||||
|
||||
if (!(ht->u.flags & HASH_FLAG_INITIALIZED)) {
|
||||
@ -378,7 +378,6 @@ static void zend_class_copy_ctor(zend_class_entry **pce)
|
||||
|
||||
/* constants table */
|
||||
zend_hash_clone_constants(&ce->constants_table, &old_ce->constants_table);
|
||||
ce->constants_table.u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
|
||||
|
||||
/* interfaces aren't really implemented, so we create a new table */
|
||||
if (ce->num_interfaces) {
|
||||
|
@ -305,7 +305,6 @@ static void zend_persist_zval(zval *z)
|
||||
GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
|
||||
GC_FLAGS(Z_COUNTED_P(z)) |= IS_ARRAY_IMMUTABLE;
|
||||
Z_ARRVAL_P(z)->u.flags |= HASH_FLAG_STATIC_KEYS;
|
||||
Z_ARRVAL_P(z)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -374,7 +373,6 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
|
||||
GC_REFCOUNT(op_array->static_variables) = 2;
|
||||
GC_TYPE_INFO(op_array->static_variables) = IS_ARRAY | (IS_ARRAY_IMMUTABLE << 8);
|
||||
op_array->static_variables->u.flags |= HASH_FLAG_STATIC_KEYS;
|
||||
op_array->static_variables->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -453,7 +453,7 @@ static xmlNodePtr master_to_xml_int(encodePtr encode, zval *data, int style, xml
|
||||
} else {
|
||||
if (check_class_map && SOAP_GLOBAL(class_map) && data &&
|
||||
Z_TYPE_P(data) == IS_OBJECT &&
|
||||
!ZEND_HASH_GET_APPLY_COUNT(Z_OBJPROP_P(data))) {
|
||||
!GC_IS_RECURSIVE(Z_OBJPROP_P(data))) {
|
||||
zend_class_entry *ce = Z_OBJCE_P(data);
|
||||
zval *tmp;
|
||||
zend_string *type_name;
|
||||
@ -1859,9 +1859,9 @@ static xmlNodePtr to_xml_object(encodeTypePtr type, zval *data, int style, xmlNo
|
||||
sdlType->encode->details.sdl_type->kind != XSD_TYPEKIND_LIST &&
|
||||
sdlType->encode->details.sdl_type->kind != XSD_TYPEKIND_UNION) {
|
||||
|
||||
if (prop) ZEND_HASH_INC_APPLY_COUNT(prop);
|
||||
if (prop) {GC_PROTECT_RECURSION(prop);}
|
||||
xmlParam = master_to_xml(sdlType->encode, data, style, parent);
|
||||
if (prop) ZEND_HASH_DEC_APPLY_COUNT(prop);
|
||||
if (prop) {GC_UNPROTECT_RECURSION(prop);}
|
||||
} else {
|
||||
zval rv;
|
||||
zval *tmp = get_zval_property(data, "_", &rv);
|
||||
|
@ -569,12 +569,13 @@ SPL_METHOD(SplObjectStorage, count)
|
||||
}
|
||||
|
||||
if (mode == COUNT_RECURSIVE) {
|
||||
zend_long ret = zend_hash_num_elements(&intern->storage);
|
||||
zval *element;
|
||||
zend_long ret;
|
||||
|
||||
ZEND_HASH_FOREACH_VAL(&intern->storage, element) {
|
||||
ret += php_count_recursive(element, mode);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
if (mode != COUNT_RECURSIVE) {
|
||||
ret = zend_hash_num_elements(&intern->storage);
|
||||
} else {
|
||||
ret = php_count_recursive(&intern->storage);
|
||||
}
|
||||
|
||||
RETURN_LONG(ret);
|
||||
return;
|
||||
|
@ -743,30 +743,29 @@ PHP_FUNCTION(ksort)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
PHPAPI zend_long php_count_recursive(zval *array, zend_long mode) /* {{{ */
|
||||
PHPAPI zend_long php_count_recursive(HashTable *ht) /* {{{ */
|
||||
{
|
||||
zend_long cnt = 0;
|
||||
zval *element;
|
||||
|
||||
if (Z_TYPE_P(array) == IS_ARRAY) {
|
||||
if (Z_ARRVAL_P(array)->u.v.nApplyCount > 1) {
|
||||
if (!(GC_FLAGS(ht) & GC_IMMUTABLE)) {
|
||||
if (GC_IS_RECURSIVE(ht)) {
|
||||
php_error_docref(NULL, E_WARNING, "recursion detected");
|
||||
return 0;
|
||||
}
|
||||
GC_PROTECT_RECURSION(ht);
|
||||
}
|
||||
|
||||
cnt = zend_array_count(Z_ARRVAL_P(array));
|
||||
if (mode == COUNT_RECURSIVE) {
|
||||
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(array))) {
|
||||
Z_ARRVAL_P(array)->u.v.nApplyCount++;
|
||||
}
|
||||
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array), element) {
|
||||
ZVAL_DEREF(element);
|
||||
cnt += php_count_recursive(element, COUNT_RECURSIVE);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(array))) {
|
||||
Z_ARRVAL_P(array)->u.v.nApplyCount--;
|
||||
}
|
||||
cnt = zend_array_count(ht);
|
||||
ZEND_HASH_FOREACH_VAL(ht, element) {
|
||||
ZVAL_DEREF(element);
|
||||
if (Z_TYPE_P(element) == IS_ARRAY) {
|
||||
cnt += php_count_recursive(Z_ARRVAL_P(element));
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
if (!(GC_FLAGS(ht) & GC_IMMUTABLE)) {
|
||||
GC_UNPROTECT_RECURSION(ht);
|
||||
}
|
||||
|
||||
return cnt;
|
||||
@ -794,12 +793,10 @@ PHP_FUNCTION(count)
|
||||
RETURN_LONG(0);
|
||||
break;
|
||||
case IS_ARRAY:
|
||||
cnt = zend_array_count(Z_ARRVAL_P(array));
|
||||
if (mode == COUNT_RECURSIVE) {
|
||||
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array), element) {
|
||||
ZVAL_DEREF(element);
|
||||
cnt += php_count_recursive(element, COUNT_RECURSIVE);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
if (mode != COUNT_RECURSIVE) {
|
||||
cnt = zend_array_count(Z_ARRVAL_P(array));
|
||||
} else {
|
||||
cnt = php_count_recursive(Z_ARRVAL_P(array));
|
||||
}
|
||||
RETURN_LONG(cnt);
|
||||
break;
|
||||
@ -1431,7 +1428,7 @@ static int php_array_walk(zval *array, zval *userdata, int recursive) /* {{{ */
|
||||
ZVAL_DEREF(zv);
|
||||
SEPARATE_ARRAY(zv);
|
||||
thash = Z_ARRVAL_P(zv);
|
||||
if (thash->u.v.nApplyCount > 1) {
|
||||
if (GC_IS_RECURSIVE(thash)) {
|
||||
php_error_docref(NULL, E_WARNING, "recursion detected");
|
||||
result = FAILURE;
|
||||
break;
|
||||
@ -1442,12 +1439,12 @@ static int php_array_walk(zval *array, zval *userdata, int recursive) /* {{{ */
|
||||
orig_array_walk_fci_cache = BG(array_walk_fci_cache);
|
||||
|
||||
Z_ADDREF(ref);
|
||||
thash->u.v.nApplyCount++;
|
||||
GC_PROTECT_RECURSION(thash);
|
||||
result = php_array_walk(zv, userdata, recursive);
|
||||
if (Z_TYPE_P(Z_REFVAL(ref)) == IS_ARRAY && thash == Z_ARRVAL_P(Z_REFVAL(ref))) {
|
||||
/* If the hashtable changed in the meantime, we'll "leak" this apply count
|
||||
* increment -- our reference to thash is no longer valid. */
|
||||
thash->u.v.nApplyCount--;
|
||||
GC_UNPROTECT_RECURSION(thash);
|
||||
}
|
||||
zval_ptr_dtor(&ref);
|
||||
|
||||
@ -2577,19 +2574,18 @@ static void php_compact_var(HashTable *eg_active_symbol_table, zval *return_valu
|
||||
}
|
||||
}
|
||||
} else if (Z_TYPE_P(entry) == IS_ARRAY) {
|
||||
if ((Z_ARRVAL_P(entry)->u.v.nApplyCount > 1)) {
|
||||
php_error_docref(NULL, E_WARNING, "recursion detected");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(entry))) {
|
||||
Z_ARRVAL_P(entry)->u.v.nApplyCount++;
|
||||
if (Z_REFCOUNTED_P(entry)) {
|
||||
if (Z_IS_RECURSIVE_P(entry)) {
|
||||
php_error_docref(NULL, E_WARNING, "recursion detected");
|
||||
return;
|
||||
}
|
||||
Z_PROTECT_RECURSION_P(entry);
|
||||
}
|
||||
ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(entry), value_ptr) {
|
||||
php_compact_var(eg_active_symbol_table, return_value, value_ptr);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(entry))) {
|
||||
Z_ARRVAL_P(entry)->u.v.nApplyCount--;
|
||||
if (Z_REFCOUNTED_P(entry)) {
|
||||
Z_UNPROTECT_RECURSION_P(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3636,7 +3632,7 @@ PHPAPI int php_array_merge_recursive(HashTable *dest, HashTable *src) /* {{{ */
|
||||
ZVAL_DEREF(src_zval);
|
||||
ZVAL_DEREF(dest_zval);
|
||||
thash = Z_TYPE_P(dest_zval) == IS_ARRAY ? Z_ARRVAL_P(dest_zval) : NULL;
|
||||
if ((thash && thash->u.v.nApplyCount > 1) || (src_entry == dest_entry && Z_ISREF_P(dest_entry) && (Z_REFCOUNT_P(dest_entry) % 2))) {
|
||||
if ((thash && GC_IS_RECURSIVE(thash)) || (src_entry == dest_entry && Z_ISREF_P(dest_entry) && (Z_REFCOUNT_P(dest_entry) % 2))) {
|
||||
php_error_docref(NULL, E_WARNING, "recursion detected");
|
||||
return 0;
|
||||
}
|
||||
@ -3662,12 +3658,12 @@ PHPAPI int php_array_merge_recursive(HashTable *dest, HashTable *src) /* {{{ */
|
||||
src_zval = &tmp;
|
||||
}
|
||||
if (Z_TYPE_P(src_zval) == IS_ARRAY) {
|
||||
if (thash && ZEND_HASH_APPLY_PROTECTION(thash)) {
|
||||
thash->u.v.nApplyCount++;
|
||||
if (thash && !(GC_FLAGS(thash) & GC_IMMUTABLE)) {
|
||||
GC_PROTECT_RECURSION(thash);
|
||||
}
|
||||
ret = php_array_merge_recursive(Z_ARRVAL_P(dest_zval), Z_ARRVAL_P(src_zval));
|
||||
if (thash && ZEND_HASH_APPLY_PROTECTION(thash)) {
|
||||
thash->u.v.nApplyCount--;
|
||||
if (thash && !(GC_FLAGS(thash) & GC_IMMUTABLE)) {
|
||||
GC_UNPROTECT_RECURSION(thash);
|
||||
}
|
||||
if (!ret) {
|
||||
return 0;
|
||||
@ -3761,8 +3757,8 @@ PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src) /* {{{ *
|
||||
|
||||
dest_zval = dest_entry;
|
||||
ZVAL_DEREF(dest_zval);
|
||||
if (Z_ARRVAL_P(dest_zval)->u.v.nApplyCount > 1 ||
|
||||
Z_ARRVAL_P(src_zval)->u.v.nApplyCount > 1 ||
|
||||
if (Z_IS_RECURSIVE_P(dest_zval) ||
|
||||
Z_IS_RECURSIVE_P(src_zval) ||
|
||||
(Z_ISREF_P(src_entry) && Z_ISREF_P(dest_entry) && Z_REF_P(src_entry) == Z_REF_P(dest_entry) && (Z_REFCOUNT_P(dest_entry) % 2))) {
|
||||
php_error_docref(NULL, E_WARNING, "recursion detected");
|
||||
return 0;
|
||||
@ -3772,20 +3768,20 @@ PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src) /* {{{ *
|
||||
SEPARATE_ZVAL(dest_entry);
|
||||
dest_zval = dest_entry;
|
||||
|
||||
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(dest_zval))) {
|
||||
Z_ARRVAL_P(dest_zval)->u.v.nApplyCount++;
|
||||
if (Z_REFCOUNTED_P(dest_zval)) {
|
||||
Z_PROTECT_RECURSION_P(dest_zval);
|
||||
}
|
||||
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(src_zval))) {
|
||||
Z_ARRVAL_P(src_zval)->u.v.nApplyCount++;
|
||||
if (Z_REFCOUNTED_P(src_zval)) {
|
||||
Z_PROTECT_RECURSION_P(src_zval);
|
||||
}
|
||||
|
||||
ret = php_array_replace_recursive(Z_ARRVAL_P(dest_zval), Z_ARRVAL_P(src_zval));
|
||||
|
||||
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(dest_zval))) {
|
||||
Z_ARRVAL_P(dest_zval)->u.v.nApplyCount--;
|
||||
if (Z_REFCOUNTED_P(dest_zval)) {
|
||||
Z_UNPROTECT_RECURSION_P(dest_zval);
|
||||
}
|
||||
if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(src_zval))) {
|
||||
Z_ARRVAL_P(src_zval)->u.v.nApplyCount--;
|
||||
if (Z_REFCOUNTED_P(src_zval)) {
|
||||
Z_UNPROTECT_RECURSION_P(src_zval);
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
|
@ -42,7 +42,7 @@ PHPAPI int php_url_encode_hash_ex(HashTable *ht, smart_str *formstr,
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (ht->u.v.nApplyCount > 0) {
|
||||
if (GC_IS_RECURSIVE(ht)) {
|
||||
/* Prevent recursion */
|
||||
return SUCCESS;
|
||||
}
|
||||
@ -136,12 +136,12 @@ PHPAPI int php_url_encode_hash_ex(HashTable *ht, smart_str *formstr,
|
||||
*(p++) = 'B';
|
||||
*p = '\0';
|
||||
}
|
||||
if (ZEND_HASH_APPLY_PROTECTION(ht)) {
|
||||
ht->u.v.nApplyCount++;
|
||||
if (!(GC_FLAGS(ht) & GC_IMMUTABLE)) {
|
||||
GC_PROTECT_RECURSION(ht);
|
||||
}
|
||||
php_url_encode_hash_ex(HASH_OF(zdata), formstr, NULL, 0, newprefix, newprefix_len, "%5D", 3, (Z_TYPE_P(zdata) == IS_OBJECT ? zdata : NULL), arg_sep, enc_type);
|
||||
if (ZEND_HASH_APPLY_PROTECTION(ht)) {
|
||||
ht->u.v.nApplyCount--;
|
||||
if (!(GC_FLAGS(ht) & GC_IMMUTABLE)) {
|
||||
GC_UNPROTECT_RECURSION(ht);
|
||||
}
|
||||
efree(newprefix);
|
||||
} else if (Z_TYPE_P(zdata) == IS_NULL || Z_TYPE_P(zdata) == IS_RESOURCE) {
|
||||
|
@ -107,7 +107,7 @@ PHPAPI int php_array_merge(HashTable *dest, HashTable *src);
|
||||
PHPAPI int php_array_merge_recursive(HashTable *dest, HashTable *src);
|
||||
PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src);
|
||||
PHPAPI int php_multisort_compare(const void *a, const void *b);
|
||||
PHPAPI zend_long php_count_recursive(zval *array, zend_long mode);
|
||||
PHPAPI zend_long php_count_recursive(HashTable *ht);
|
||||
|
||||
#define PHP_SORT_REGULAR 0
|
||||
#define PHP_SORT_NUMERIC 1
|
||||
|
@ -36,10 +36,6 @@ array(1) {
|
||||
|
||||
Warning: compact(): recursion detected in %s on line %d
|
||||
|
||||
Warning: compact(): recursion detected in %s on line %d
|
||||
|
||||
Warning: compact(): recursion detected in %s on line %d
|
||||
|
||||
Warning: compact(): recursion detected in %s on line %d
|
||||
array(2) {
|
||||
["a"]=>
|
||||
|
@ -35,5 +35,5 @@ int(4)
|
||||
-- $mode = 1: --
|
||||
|
||||
Warning: count(): recursion detected in %s on line %d
|
||||
int(12)
|
||||
int(4)
|
||||
Done
|
||||
|
@ -135,25 +135,7 @@ object(object_class)#%d (6) refcount(%d){
|
||||
int(3)
|
||||
}
|
||||
["object_class1"]=>
|
||||
object(object_class)#%d (6) 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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
*RECURSION*
|
||||
}
|
||||
*RECURSION*
|
||||
}
|
||||
-- Iteration 2 --
|
||||
object(no_member_class)#%d (0) refcount(%d){
|
||||
@ -184,25 +166,7 @@ object(contains_object_class)#%d (9) refcount(%d){
|
||||
int(3)
|
||||
}
|
||||
["object_class1"]=>
|
||||
object(object_class)#%d (6) 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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
*RECURSION*
|
||||
}
|
||||
*RECURSION*
|
||||
}
|
||||
["class_object2"]=>
|
||||
object(object_class)#%d (6) refcount(%d){
|
||||
@ -222,25 +186,7 @@ object(contains_object_class)#%d (9) refcount(%d){
|
||||
int(3)
|
||||
}
|
||||
["object_class1"]=>
|
||||
object(object_class)#%d (6) 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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
*RECURSION*
|
||||
}
|
||||
*RECURSION*
|
||||
}
|
||||
["class_object3":"contains_object_class":private]=>
|
||||
object(object_class)#%d (6) refcount(%d){
|
||||
@ -260,25 +206,7 @@ object(contains_object_class)#%d (9) refcount(%d){
|
||||
int(3)
|
||||
}
|
||||
["object_class1"]=>
|
||||
object(object_class)#%d (6) 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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
*RECURSION*
|
||||
}
|
||||
*RECURSION*
|
||||
}
|
||||
["class_object4":protected]=>
|
||||
object(object_class)#%d (6) refcount(%d){
|
||||
@ -298,195 +226,13 @@ object(contains_object_class)#%d (9) refcount(%d){
|
||||
int(3)
|
||||
}
|
||||
["object_class1"]=>
|
||||
object(object_class)#%d (6) 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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
*RECURSION*
|
||||
}
|
||||
*RECURSION*
|
||||
}
|
||||
["no_member_class_object"]=>
|
||||
object(no_member_class)#%d (0) refcount(%d){
|
||||
}
|
||||
["class_object5"]=>
|
||||
object(contains_object_class)#%d (9) refcount(%d){
|
||||
["p"]=>
|
||||
int(30)
|
||||
["p1":protected]=>
|
||||
int(40)
|
||||
["p2":"contains_object_class":private]=>
|
||||
int(50)
|
||||
["class_object1"]=>
|
||||
object(object_class)#%d (6) 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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
object(object_class)#%d (6) 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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
*RECURSION*
|
||||
}
|
||||
}
|
||||
["class_object2"]=>
|
||||
object(object_class)#%d (6) 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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
object(object_class)#%d (6) 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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
*RECURSION*
|
||||
}
|
||||
}
|
||||
["class_object3":"contains_object_class":private]=>
|
||||
object(object_class)#%d (6) 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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
object(object_class)#%d (6) 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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
*RECURSION*
|
||||
}
|
||||
}
|
||||
["class_object4":protected]=>
|
||||
object(object_class)#%d (6) 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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
object(object_class)#%d (6) 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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
*RECURSION*
|
||||
}
|
||||
}
|
||||
["no_member_class_object"]=>
|
||||
object(no_member_class)#%d (0) refcount(%d){
|
||||
}
|
||||
["class_object5"]=>
|
||||
*RECURSION*
|
||||
}
|
||||
*RECURSION*
|
||||
}
|
||||
-- Iteration 4 --
|
||||
object(object_class)#%d (6) refcount(%d){
|
||||
@ -506,25 +252,7 @@ object(object_class)#%d (6) refcount(%d){
|
||||
int(3)
|
||||
}
|
||||
["object_class1"]=>
|
||||
object(object_class)#%d (6) 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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
*RECURSION*
|
||||
}
|
||||
*RECURSION*
|
||||
}
|
||||
-- Iteration 5 --
|
||||
object(object_class)#%d (6) refcount(%d){
|
||||
@ -544,25 +272,7 @@ object(object_class)#%d (6) refcount(%d){
|
||||
int(3)
|
||||
}
|
||||
["object_class1"]=>
|
||||
object(object_class)#%d (6) 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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
*RECURSION*
|
||||
}
|
||||
*RECURSION*
|
||||
}
|
||||
-- Iteration 6 --
|
||||
object(no_member_class)#%d (0) refcount(%d){
|
||||
@ -587,25 +297,7 @@ object(object_class)#%d (6) refcount(%d){
|
||||
int(3)
|
||||
}
|
||||
["object_class1"]=>
|
||||
object(object_class)#%d (6) 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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
*RECURSION*
|
||||
}
|
||||
*RECURSION*
|
||||
}
|
||||
-- Iteration 9 --
|
||||
object(object_class)#%d (6) refcount(%d){
|
||||
@ -625,25 +317,7 @@ object(object_class)#%d (6) refcount(%d){
|
||||
int(3)
|
||||
}
|
||||
["object_class1"]=>
|
||||
object(object_class)#%d (6) 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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
*RECURSION*
|
||||
}
|
||||
*RECURSION*
|
||||
}
|
||||
-- Iteration 10 --
|
||||
int(30)
|
||||
@ -674,67 +348,7 @@ object(object_class)#%d (7) refcount(%d){
|
||||
int(3)
|
||||
}
|
||||
["object_class1"]=>
|
||||
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)
|
||||
}
|
||||
["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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
*RECURSION*
|
||||
["obj"]=>
|
||||
*RECURSION*
|
||||
}
|
||||
["obj"]=>
|
||||
*RECURSION*
|
||||
}
|
||||
}
|
||||
*RECURSION*
|
||||
["obj"]=>
|
||||
&object(object_class)#%d (7) refcount(%d){
|
||||
["value1"]=>
|
||||
@ -753,89 +367,9 @@ object(object_class)#%d (7) refcount(%d){
|
||||
int(3)
|
||||
}
|
||||
["object_class1"]=>
|
||||
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)
|
||||
}
|
||||
["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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
*RECURSION*
|
||||
["obj"]=>
|
||||
*RECURSION*
|
||||
}
|
||||
}
|
||||
*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)
|
||||
}
|
||||
["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)
|
||||
}
|
||||
["object_class1"]=>
|
||||
*RECURSION*
|
||||
["obj"]=>
|
||||
*RECURSION*
|
||||
}
|
||||
}
|
||||
*RECURSION*
|
||||
}
|
||||
}
|
||||
Done
|
||||
|
@ -119,10 +119,12 @@ again:
|
||||
break;
|
||||
case IS_ARRAY:
|
||||
myht = Z_ARRVAL_P(struc);
|
||||
if (level > 1 && ZEND_HASH_APPLY_PROTECTION(myht) && ++myht->u.v.nApplyCount > 1) {
|
||||
PUTS("*RECURSION*\n");
|
||||
--myht->u.v.nApplyCount;
|
||||
return;
|
||||
if (level > 1 && !(GC_FLAGS(myht) & GC_IMMUTABLE)) {
|
||||
if (GC_IS_RECURSIVE(myht)) {
|
||||
PUTS("*RECURSION*\n");
|
||||
return;
|
||||
}
|
||||
GC_PROTECT_RECURSION(myht);
|
||||
}
|
||||
count = zend_array_count(myht);
|
||||
php_printf("%sarray(%d) {\n", COMMON, count);
|
||||
@ -131,8 +133,8 @@ again:
|
||||
ZEND_HASH_FOREACH_KEY_VAL_IND(myht, num, key, val) {
|
||||
php_array_element_dump(val, num, key, level);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
if (level > 1 && ZEND_HASH_APPLY_PROTECTION(myht)) {
|
||||
--myht->u.v.nApplyCount;
|
||||
if (level > 1 && !(GC_FLAGS(myht) & GC_IMMUTABLE)) {
|
||||
GC_UNPROTECT_RECURSION(myht);
|
||||
}
|
||||
if (is_temp) {
|
||||
zend_hash_destroy(myht);
|
||||
@ -144,11 +146,11 @@ again:
|
||||
PUTS("}\n");
|
||||
break;
|
||||
case IS_OBJECT:
|
||||
if (Z_OBJ_APPLY_COUNT_P(struc) > 0) {
|
||||
if (Z_IS_RECURSIVE_P(struc)) {
|
||||
PUTS("*RECURSION*\n");
|
||||
return;
|
||||
}
|
||||
Z_OBJ_INC_APPLY_COUNT_P(struc);
|
||||
Z_PROTECT_RECURSION_P(struc);
|
||||
|
||||
myht = Z_OBJDEBUG_P(struc, is_temp);
|
||||
class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc));
|
||||
@ -172,7 +174,7 @@ again:
|
||||
php_printf("%*c", level-1, ' ');
|
||||
}
|
||||
PUTS("}\n");
|
||||
Z_OBJ_DEC_APPLY_COUNT_P(struc);
|
||||
Z_UNPROTECT_RECURSION_P(struc);
|
||||
break;
|
||||
case IS_RESOURCE: {
|
||||
const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(struc));
|
||||
@ -289,18 +291,20 @@ again:
|
||||
break;
|
||||
case IS_ARRAY:
|
||||
myht = Z_ARRVAL_P(struc);
|
||||
if (level > 1 && ZEND_HASH_APPLY_PROTECTION(myht) && myht->u.v.nApplyCount++ > 1) {
|
||||
myht->u.v.nApplyCount--;
|
||||
PUTS("*RECURSION*\n");
|
||||
return;
|
||||
if (level > 1 && !(GC_FLAGS(myht) & GC_IMMUTABLE)) {
|
||||
if (GC_IS_RECURSIVE(myht)) {
|
||||
PUTS("*RECURSION*\n");
|
||||
return;
|
||||
}
|
||||
GC_PROTECT_RECURSION(myht);
|
||||
}
|
||||
count = zend_array_count(myht);
|
||||
php_printf("%sarray(%d) refcount(%u){\n", COMMON, count, Z_REFCOUNTED_P(struc) ? Z_REFCOUNT_P(struc) : 1);
|
||||
ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) {
|
||||
zval_array_element_dump(val, index, key, level);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
if (level > 1 && ZEND_HASH_APPLY_PROTECTION(myht)) {
|
||||
myht->u.v.nApplyCount--;
|
||||
if (level > 1 && !(GC_FLAGS(myht) & GC_IMMUTABLE)) {
|
||||
GC_UNPROTECT_RECURSION(myht);
|
||||
}
|
||||
if (is_temp) {
|
||||
zend_hash_destroy(myht);
|
||||
@ -314,12 +318,11 @@ again:
|
||||
case IS_OBJECT:
|
||||
myht = Z_OBJDEBUG_P(struc, is_temp);
|
||||
if (myht) {
|
||||
if (myht->u.v.nApplyCount > 1) {
|
||||
if (GC_IS_RECURSIVE(myht)) {
|
||||
PUTS("*RECURSION*\n");
|
||||
return;
|
||||
} else {
|
||||
myht->u.v.nApplyCount++;
|
||||
}
|
||||
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));
|
||||
@ -328,7 +331,7 @@ again:
|
||||
ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) {
|
||||
zval_object_property_dump(val, index, key, level);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
myht->u.v.nApplyCount--;
|
||||
GC_UNPROTECT_RECURSION(myht);
|
||||
if (is_temp) {
|
||||
zend_hash_destroy(myht);
|
||||
efree(myht);
|
||||
@ -487,11 +490,13 @@ again:
|
||||
break;
|
||||
case IS_ARRAY:
|
||||
myht = Z_ARRVAL_P(struc);
|
||||
if (ZEND_HASH_APPLY_PROTECTION(myht) && myht->u.v.nApplyCount++ > 0) {
|
||||
myht->u.v.nApplyCount--;
|
||||
smart_str_appendl(buf, "NULL", 4);
|
||||
zend_error(E_WARNING, "var_export does not handle circular references");
|
||||
return;
|
||||
if (!(GC_FLAGS(myht) & GC_IMMUTABLE)) {
|
||||
if (GC_IS_RECURSIVE(myht)) {
|
||||
smart_str_appendl(buf, "NULL", 4);
|
||||
zend_error(E_WARNING, "var_export does not handle circular references");
|
||||
return;
|
||||
}
|
||||
GC_PROTECT_RECURSION(myht);
|
||||
}
|
||||
if (level > 1) {
|
||||
smart_str_appendc(buf, '\n');
|
||||
@ -501,8 +506,8 @@ again:
|
||||
ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) {
|
||||
php_array_element_export(val, index, key, level, buf);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
if (ZEND_HASH_APPLY_PROTECTION(myht)) {
|
||||
myht->u.v.nApplyCount--;
|
||||
if (!(GC_FLAGS(myht) & GC_IMMUTABLE)) {
|
||||
GC_UNPROTECT_RECURSION(myht);
|
||||
}
|
||||
if (level > 1) {
|
||||
buffer_append_spaces(buf, level - 1);
|
||||
@ -514,12 +519,12 @@ again:
|
||||
case IS_OBJECT:
|
||||
myht = Z_OBJPROP_P(struc);
|
||||
if (myht) {
|
||||
if (myht->u.v.nApplyCount > 0) {
|
||||
if (GC_IS_RECURSIVE(myht)) {
|
||||
smart_str_appendl(buf, "NULL", 4);
|
||||
zend_error(E_WARNING, "var_export does not handle circular references");
|
||||
return;
|
||||
} else {
|
||||
myht->u.v.nApplyCount++;
|
||||
GC_PROTECT_RECURSION(myht);
|
||||
}
|
||||
}
|
||||
if (level > 1) {
|
||||
@ -534,7 +539,7 @@ again:
|
||||
ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) {
|
||||
php_object_element_export(val, index, key, level, buf);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
myht->u.v.nApplyCount--;
|
||||
GC_UNPROTECT_RECURSION(myht);
|
||||
}
|
||||
if (level > 1) {
|
||||
buffer_append_spaces(buf, level - 1);
|
||||
@ -951,18 +956,22 @@ again:
|
||||
|
||||
/* we should still add element even if it's not OK,
|
||||
* since we already wrote the length of the array before */
|
||||
if ((Z_TYPE_P(data) == IS_ARRAY && Z_TYPE_P(struc) == IS_ARRAY && Z_ARR_P(data) == Z_ARR_P(struc))
|
||||
|| (Z_TYPE_P(data) == IS_ARRAY && Z_ARRVAL_P(data)->u.v.nApplyCount > 1)
|
||||
) {
|
||||
smart_str_appendl(buf, "N;", 2);
|
||||
if (Z_TYPE_P(data) == IS_ARRAY) {
|
||||
if (Z_TYPE_P(data) == IS_ARRAY
|
||||
&& (UNEXPECTED(Z_IS_RECURSIVE_P(data))
|
||||
|| UNEXPECTED(Z_TYPE_P(struc) == IS_ARRAY && Z_ARR_P(data) == Z_ARR_P(struc)))) {
|
||||
smart_str_appendl(buf, "N;", 2);
|
||||
} else {
|
||||
if (Z_REFCOUNTED_P(data)) {
|
||||
Z_PROTECT_RECURSION_P(data);
|
||||
}
|
||||
php_var_serialize_intern(buf, data, var_hash);
|
||||
if (Z_REFCOUNTED_P(data)) {
|
||||
Z_UNPROTECT_RECURSION_P(data);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (Z_TYPE_P(data) == IS_ARRAY && ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(data))) {
|
||||
Z_ARRVAL_P(data)->u.v.nApplyCount++;
|
||||
}
|
||||
php_var_serialize_intern(buf, data, var_hash);
|
||||
if (Z_TYPE_P(data) == IS_ARRAY && ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(data))) {
|
||||
Z_ARRVAL_P(data)->u.v.nApplyCount--;
|
||||
}
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
|
@ -640,28 +640,28 @@ void php_wddx_serialize_var(wddx_packet *packet, zval *var, zend_string *name)
|
||||
|
||||
case IS_ARRAY:
|
||||
ht = Z_ARRVAL_P(var);
|
||||
if (ht->u.v.nApplyCount > 1) {
|
||||
zend_throw_error(NULL, "WDDX doesn't support circular references");
|
||||
return;
|
||||
}
|
||||
if (ZEND_HASH_APPLY_PROTECTION(ht)) {
|
||||
ht->u.v.nApplyCount++;
|
||||
if (Z_REFCOUNTED_P(var)) {
|
||||
if (GC_IS_RECURSIVE(ht)) {
|
||||
zend_throw_error(NULL, "WDDX doesn't support circular references");
|
||||
return;
|
||||
}
|
||||
GC_PROTECT_RECURSION(ht);
|
||||
}
|
||||
php_wddx_serialize_array(packet, var);
|
||||
if (ZEND_HASH_APPLY_PROTECTION(ht)) {
|
||||
ht->u.v.nApplyCount--;
|
||||
if (Z_REFCOUNTED_P(var)) {
|
||||
GC_UNPROTECT_RECURSION(ht);
|
||||
}
|
||||
break;
|
||||
|
||||
case IS_OBJECT:
|
||||
ht = Z_OBJPROP_P(var);
|
||||
if (ht->u.v.nApplyCount > 1) {
|
||||
if (GC_IS_RECURSIVE(ht)) {
|
||||
zend_throw_error(NULL, "WDDX doesn't support circular references");
|
||||
return;
|
||||
}
|
||||
ht->u.v.nApplyCount++;
|
||||
GC_PROTECT_RECURSION(ht);
|
||||
php_wddx_serialize_object(packet, var);
|
||||
ht->u.v.nApplyCount--;
|
||||
GC_UNPROTECT_RECURSION(ht);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -691,28 +691,26 @@ static void php_wddx_add_var(wddx_packet *packet, zval *name_var)
|
||||
|
||||
target_hash = HASH_OF(name_var);
|
||||
|
||||
if (is_array && target_hash->u.v.nApplyCount > 1) {
|
||||
php_error_docref(NULL, E_WARNING, "recursion detected");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Z_REFCOUNTED_P(name_var)) {
|
||||
ZEND_HASH_FOREACH_VAL(target_hash, val) {
|
||||
php_wddx_add_var(packet, val);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
} else {
|
||||
ZEND_HASH_FOREACH_VAL(target_hash, val) {
|
||||
if (is_array) {
|
||||
target_hash->u.v.nApplyCount++;
|
||||
if (is_array) {
|
||||
if (GC_IS_RECURSIVE(target_hash)) {
|
||||
php_error_docref(NULL, E_WARNING, "recursion detected");
|
||||
return;
|
||||
}
|
||||
|
||||
GC_PROTECT_RECURSION(target_hash);
|
||||
}
|
||||
ZEND_HASH_FOREACH_VAL(target_hash, val) {
|
||||
ZVAL_DEREF(val);
|
||||
php_wddx_add_var(packet, val);
|
||||
|
||||
if (is_array) {
|
||||
target_hash->u.v.nApplyCount--;
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
if (is_array) {
|
||||
GC_UNPROTECT_RECURSION(target_hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -556,9 +556,12 @@ static XMLRPC_VALUE PHP_to_XMLRPC_worker (const char* key, zval* in_val, int dep
|
||||
XMLRPC_VECTOR_TYPE vtype;
|
||||
|
||||
ht = HASH_OF(&val);
|
||||
if (ht && ht->u.v.nApplyCount > 1) {
|
||||
zend_throw_error(NULL, "XML-RPC doesn't support circular references");
|
||||
return NULL;
|
||||
if (ht && !(GC_FLAGS(ht) & GC_IMMUTABLE)) {
|
||||
if (GC_IS_RECURSIVE(ht)) {
|
||||
zend_throw_error(NULL, "XML-RPC doesn't support circular references");
|
||||
return NULL;
|
||||
}
|
||||
GC_PROTECT_RECURSION(ht);
|
||||
}
|
||||
|
||||
ZVAL_COPY(&val_arr, &val);
|
||||
@ -569,10 +572,6 @@ static XMLRPC_VALUE PHP_to_XMLRPC_worker (const char* key, zval* in_val, int dep
|
||||
|
||||
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL(val_arr), num_index, my_key, pIter) {
|
||||
ZVAL_DEREF(pIter);
|
||||
ht = HASH_OF(pIter);
|
||||
if (ht) {
|
||||
ht->u.v.nApplyCount++;
|
||||
}
|
||||
if (my_key == NULL) {
|
||||
char *num_str = NULL;
|
||||
|
||||
@ -587,10 +586,10 @@ static XMLRPC_VALUE PHP_to_XMLRPC_worker (const char* key, zval* in_val, int dep
|
||||
} else {
|
||||
XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(ZSTR_VAL(my_key), pIter, depth++));
|
||||
}
|
||||
if (ht) {
|
||||
ht->u.v.nApplyCount--;
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
if (ht && !(GC_FLAGS(ht) & GC_IMMUTABLE)) {
|
||||
GC_UNPROTECT_RECURSION(ht);
|
||||
}
|
||||
zval_ptr_dtor(&val_arr);
|
||||
}
|
||||
break;
|
||||
|
@ -687,10 +687,12 @@ PHPDBG_API void phpdbg_xml_var_dump(zval *zv) {
|
||||
break;
|
||||
case IS_ARRAY:
|
||||
myht = Z_ARRVAL_P(zv);
|
||||
if (ZEND_HASH_APPLY_PROTECTION(myht) && ++myht->u.v.nApplyCount > 1) {
|
||||
phpdbg_xml("<recursion />");
|
||||
--myht->u.v.nApplyCount;
|
||||
break;
|
||||
if (!(GC_FLAGS(myht) & GC_IMMUTABLE)) {
|
||||
if (GC_IS_RECURSIVE(myht)) {
|
||||
phpdbg_xml("<recursion />");
|
||||
break;
|
||||
}
|
||||
GC_PROTECT_RECURSION(myht);
|
||||
}
|
||||
phpdbg_xml("<array refstatus=\"%s\" num=\"%d\">", COMMON, zend_hash_num_elements(myht));
|
||||
element_dump_func = phpdbg_xml_array_element_dump;
|
||||
@ -698,9 +700,8 @@ PHPDBG_API void phpdbg_xml_var_dump(zval *zv) {
|
||||
goto head_done;
|
||||
case IS_OBJECT:
|
||||
myht = Z_OBJDEBUG_P(zv, is_temp);
|
||||
if (myht && ++myht->u.v.nApplyCount > 1) {
|
||||
if (myht && GC_IS_RECURSIVE(myht)) {
|
||||
phpdbg_xml("<recursion />");
|
||||
--myht->u.v.nApplyCount;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -715,7 +716,7 @@ head_done:
|
||||
element_dump_func(val, key, num);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
zend_hash_apply_with_arguments(myht, (apply_func_args_t) element_dump_func, 0);
|
||||
--myht->u.v.nApplyCount;
|
||||
GC_UNPROTECT_RECURSION(myht);
|
||||
if (is_temp) {
|
||||
zend_hash_destroy(myht);
|
||||
efree(myht);
|
||||
|
Loading…
Reference in New Issue
Block a user