summaryrefslogtreecommitdiff
path: root/ext/standard
diff options
context:
space:
mode:
authorXinchen Hui <laruence@gmail.com>2018-02-17 16:33:39 +0800
committerXinchen Hui <laruence@gmail.com>2018-02-17 16:33:39 +0800
commit26dda8999ceca1d4d33a51723d77d5a73b05b926 (patch)
tree261683c8ba1e302face3b462d145c1a66c6eb6a9 /ext/standard
parent0674d677bc82d448395f57e5612fc7280a2f5846 (diff)
parent94e9d0a2ae76bad712495d820d3962e401085fef (diff)
downloadphp-git-26dda8999ceca1d4d33a51723d77d5a73b05b926.tar.gz
Merge branch 'PHP-7.1' into PHP-7.2
* PHP-7.1: Fixed bug #75961 (Strange references behavior)
Diffstat (limited to 'ext/standard')
-rw-r--r--ext/standard/array.c30
-rw-r--r--ext/standard/tests/array/bug75961.phpt18
2 files changed, 37 insertions, 11 deletions
diff --git a/ext/standard/array.c b/ext/standard/array.c
index 91ffe08f7d..72a7813aa8 100644
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@ -1393,6 +1393,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) {
@@ -1408,6 +1409,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);
@@ -1425,14 +1428,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;
}
@@ -1441,15 +1446,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;
@@ -1465,12 +1470,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;
}
diff --git a/ext/standard/tests/array/bug75961.phpt b/ext/standard/tests/array/bug75961.phpt
new file mode 100644
index 0000000000..15484ab16f
--- /dev/null
+++ b/ext/standard/tests/array/bug75961.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Bug #75961 (Strange references behavior)
+--FILE--
+<?php
+$arr = [[1]];
+
+array_walk($arr, function(){});
+array_map('array_shift', $arr);
+var_dump($arr);
+?>
+--EXPECT--
+array(1) {
+ [0]=>
+ array(1) {
+ [0]=>
+ int(1)
+ }
+}