summaryrefslogtreecommitdiff
path: root/ext/standard/array.c
diff options
context:
space:
mode:
authorXinchen Hui <laruence@gmail.com>2018-02-17 16:31:59 +0800
committerXinchen Hui <laruence@gmail.com>2018-02-17 16:33:15 +0800
commit94e9d0a2ae76bad712495d820d3962e401085fef (patch)
tree6de92db37e22c7af7bd054bbfcfd1ff3c33039e7 /ext/standard/array.c
parent372bf8a9231a58ef8d1d2f0d9b560167495e215e (diff)
downloadphp-git-94e9d0a2ae76bad712495d820d3962e401085fef.tar.gz
Fixed bug #75961 (Strange references behavior)
Diffstat (limited to 'ext/standard/array.c')
-rw-r--r--ext/standard/array.c30
1 files changed, 19 insertions, 11 deletions
diff --git a/ext/standard/array.c b/ext/standard/array.c
index 07db375440..d7fa94e52c 100644
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@ -1380,6 +1380,7 @@ static int php_array_walk(zval *array, zval *userdata, int recursive) /* {{{ */
/* Iterate through hash */
do {
+ zend_bool was_ref;
/* Retrieve value */
zv = zend_hash_get_current_data_ex(target_hash, &pos);
if (zv == NULL) {
@@ -1395,6 +1396,8 @@ static int php_array_walk(zval *array, zval *userdata, int recursive) /* {{{ */
}
}
+ was_ref = Z_ISREF_P(zv);
+
/* Ensure the value is a reference. Otherwise the location of the value may be freed. */
ZVAL_MAKE_REF(zv);
@@ -1412,14 +1415,16 @@ static int php_array_walk(zval *array, zval *userdata, int recursive) /* {{{ */
HashTable *thash;
zend_fcall_info orig_array_walk_fci;
zend_fcall_info_cache orig_array_walk_fci_cache;
- zval ref;
- ZVAL_COPY_VALUE(&ref, zv);
+ zval rv;
- ZVAL_DEREF(zv);
- SEPARATE_ARRAY(zv);
- thash = Z_ARRVAL_P(zv);
+ SEPARATE_ARRAY(Z_REFVAL_P(zv));
+ ZVAL_COPY_VALUE(&rv, Z_REFVAL_P(zv));
+ thash = Z_ARRVAL(rv);
if (thash->u.v.nApplyCount > 1) {
php_error_docref(NULL, E_WARNING, "recursion detected");
+ if (!was_ref) {
+ ZVAL_UNREF(zv);
+ }
result = FAILURE;
break;
}
@@ -1428,15 +1433,15 @@ static int php_array_walk(zval *array, zval *userdata, int recursive) /* {{{ */
orig_array_walk_fci = BG(array_walk_fci);
orig_array_walk_fci_cache = BG(array_walk_fci_cache);
- Z_ADDREF(ref);
+ Z_ADDREF(rv);
thash->u.v.nApplyCount++;
- result = php_array_walk(zv, userdata, recursive);
- if (Z_TYPE_P(Z_REFVAL(ref)) == IS_ARRAY && thash == Z_ARRVAL_P(Z_REFVAL(ref))) {
+ result = php_array_walk(&rv, userdata, recursive);
+ if (Z_TYPE_P(Z_REFVAL_P(zv)) == IS_ARRAY && thash == Z_ARRVAL_P(Z_REFVAL_P(zv))) {
/* 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--;
}
- zval_ptr_dtor(&ref);
+ zval_ptr_dtor(&rv);
/* restore the fcall info and cache */
BG(array_walk_fci) = orig_array_walk_fci;
@@ -1452,12 +1457,15 @@ static int php_array_walk(zval *array, zval *userdata, int recursive) /* {{{ */
zval_ptr_dtor(&args[0]);
}
-
if (Z_TYPE(args[1]) != IS_UNDEF) {
zval_ptr_dtor(&args[1]);
ZVAL_UNDEF(&args[1]);
}
-
+ if (!was_ref && Z_ISREF_P(zv)) {
+ if (Z_REFCOUNT_P(zv) == 1) {
+ ZVAL_UNREF(zv);
+ }
+ }
if (result == FAILURE) {
break;
}