diff options
author | Xinchen Hui <laruence@gmail.com> | 2018-02-17 16:33:39 +0800 |
---|---|---|
committer | Xinchen Hui <laruence@gmail.com> | 2018-02-17 16:33:39 +0800 |
commit | 26dda8999ceca1d4d33a51723d77d5a73b05b926 (patch) | |
tree | 261683c8ba1e302face3b462d145c1a66c6eb6a9 /ext/standard | |
parent | 0674d677bc82d448395f57e5612fc7280a2f5846 (diff) | |
parent | 94e9d0a2ae76bad712495d820d3962e401085fef (diff) | |
download | php-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.c | 30 | ||||
-rw-r--r-- | ext/standard/tests/array/bug75961.phpt | 18 |
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) + } +} |