summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2017-10-06 01:34:50 +0300
committerDmitry Stogov <dmitry@zend.com>2017-10-06 01:34:50 +0300
commitcb9d81ef4f07f82835273800b0cb3d6a67816050 (patch)
treedad640422674e3eb45a2577f5b29fcd7ad9c8676 /ext
parent39ea632f7468e1001b15b9c43afc6aba9debdc9c (diff)
downloadphp-git-cb9d81ef4f07f82835273800b0cb3d6a67816050.tar.gz
Refactored recursion pretection
Diffstat (limited to 'ext')
-rw-r--r--ext/filter/filter.c6
-rw-r--r--ext/json/json_encoder.c32
-rw-r--r--ext/mbstring/mbstring.c29
-rw-r--r--ext/mbstring/tests/bug66964.phpt15
-rw-r--r--ext/opcache/zend_accelerator_util_funcs.c3
-rw-r--r--ext/opcache/zend_persist.c2
-rw-r--r--ext/soap/php_encoding.c6
-rw-r--r--ext/spl/spl_observer.c11
-rw-r--r--ext/standard/array.c92
-rw-r--r--ext/standard/http.c10
-rw-r--r--ext/standard/php_array.h2
-rw-r--r--ext/standard/tests/array/compact_variation1.phpt4
-rw-r--r--ext/standard/tests/array/count_variation3.phpt2
-rw-r--r--ext/standard/tests/general_functions/debug_zval_dump_o.phpt492
-rw-r--r--ext/standard/var.c87
-rw-r--r--ext/wddx/wddx.c44
-rw-r--r--ext/xmlrpc/xmlrpc-epi-php.c19
17 files changed, 197 insertions, 659 deletions
diff --git a/ext/filter/filter.c b/ext/filter/filter.c
index cdc5e15bb6..17fc500a9d 100644
--- a/ext/filter/filter.c
+++ b/ext/filter/filter.c
@@ -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);
}
diff --git a/ext/json/json_encoder.c b/ext/json/json_encoder.c
index 1fa2344204..2c3843fdd2 100644
--- a/ext/json/json_encoder.c
+++ b/ext/json/json_encoder.c
@@ -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);
diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c
index 0bb18e9b57..6d1103aff7 100644
--- a/ext/mbstring/mbstring.c
+++ b/ext/mbstring/mbstring.c
@@ -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;
}
diff --git a/ext/mbstring/tests/bug66964.phpt b/ext/mbstring/tests/bug66964.phpt
index e982aa2e01..c33bb67c49 100644
--- a/ext/mbstring/tests/bug66964.phpt
+++ b/ext/mbstring/tests/bug66964.phpt
@@ -49,5 +49,16 @@ array(5) {
[3]=>
string(21) "日本語テキスト"
[4]=>
- *RECURSION*
-} \ No newline at end of file
+ &array(5) {
+ [0]=>
+ string(21) "日本語テキスト"
+ [1]=>
+ string(21) "日本語テキスト"
+ [2]=>
+ string(21) "日本語テキスト"
+ [3]=>
+ string(21) "日本語テキスト"
+ [4]=>
+ *RECURSION*
+ }
+}
diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c
index 930bcceaf2..6926798ab6 100644
--- a/ext/opcache/zend_accelerator_util_funcs.c
+++ b/ext/opcache/zend_accelerator_util_funcs.c
@@ -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) {
diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c
index 2ce4c05ba3..cd4077279f 100644
--- a/ext/opcache/zend_persist.c
+++ b/ext/opcache/zend_persist.c
@@ -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;
}
}
diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c
index a88d14fb1a..6d69d81c33 100644
--- a/ext/soap/php_encoding.c
+++ b/ext/soap/php_encoding.c
@@ -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);
diff --git a/ext/spl/spl_observer.c b/ext/spl/spl_observer.c
index c6d366515b..e9dc418b53 100644
--- a/ext/spl/spl_observer.c
+++ b/ext/spl/spl_observer.c
@@ -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;
diff --git a/ext/standard/array.c b/ext/standard/array.c
index e55924c66b..18a8a2e77f 100644
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@ -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) {
diff --git a/ext/standard/http.c b/ext/standard/http.c
index e270342c7b..afbb77d1fa 100644
--- a/ext/standard/http.c
+++ b/ext/standard/http.c
@@ -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) {
diff --git a/ext/standard/php_array.h b/ext/standard/php_array.h
index 2b58db71e3..d9c5eedc18 100644
--- a/ext/standard/php_array.h
+++ b/ext/standard/php_array.h
@@ -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
diff --git a/ext/standard/tests/array/compact_variation1.phpt b/ext/standard/tests/array/compact_variation1.phpt
index ea48132857..d2b9fc45df 100644
--- a/ext/standard/tests/array/compact_variation1.phpt
+++ b/ext/standard/tests/array/compact_variation1.phpt
@@ -37,10 +37,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"]=>
int(1)
diff --git a/ext/standard/tests/array/count_variation3.phpt b/ext/standard/tests/array/count_variation3.phpt
index e11b4c2449..9c89bcd16b 100644
--- a/ext/standard/tests/array/count_variation3.phpt
+++ b/ext/standard/tests/array/count_variation3.phpt
@@ -35,5 +35,5 @@ int(4)
-- $mode = 1: --
Warning: count(): recursion detected in %s on line %d
-int(12)
+int(4)
Done
diff --git a/ext/standard/tests/general_functions/debug_zval_dump_o.phpt b/ext/standard/tests/general_functions/debug_zval_dump_o.phpt
index c06dff556d..e2c84dae9b 100644
--- a/ext/standard/tests/general_functions/debug_zval_dump_o.phpt
+++ b/ext/standard/tests/general_functions/debug_zval_dump_o.phpt
@@ -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
diff --git a/ext/standard/var.c b/ext/standard/var.c
index 0ae7991412..e28afe9177 100644
--- a/ext/standard/var.c
+++ b/ext/standard/var.c
@@ -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);
- } else {
- if (Z_TYPE_P(data) == IS_ARRAY && ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(data))) {
- Z_ARRVAL_P(data)->u.v.nApplyCount++;
+ 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 {
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();
}
diff --git a/ext/wddx/wddx.c b/ext/wddx/wddx.c
index b6af00edd7..556af05112 100644
--- a/ext/wddx/wddx.c
+++ b/ext/wddx/wddx.c
@@ -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);
+ }
}
}
}
diff --git a/ext/xmlrpc/xmlrpc-epi-php.c b/ext/xmlrpc/xmlrpc-epi-php.c
index 2b1a642c05..e20b6d6872 100644
--- a/ext/xmlrpc/xmlrpc-epi-php.c
+++ b/ext/xmlrpc/xmlrpc-epi-php.c
@@ -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;