Skip to content

Commit fd5bd37

Browse files
committed
Revert "Fixed bug #75961 (Strange references behavior)"
This reverts commit 94e9d0a. This code needs to be mindful about modifications to the array happening during callback execution. It was written in a way that only accessed the reference, which is guaranteed not to move. The changed implementation instead accesses the array slot, leading to use-after-free. Run ext/standard/tests/array/bug61967.phpt under valgrind to see the issue.
1 parent 27a603e commit fd5bd37

File tree

2 files changed

+11
-37
lines changed

2 files changed

+11
-37
lines changed

ext/standard/array.c

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,7 +1380,6 @@ static int php_array_walk(zval *array, zval *userdata, int recursive) /* {{{ */
13801380

13811381
/* Iterate through hash */
13821382
do {
1383-
zend_bool was_ref;
13841383
/* Retrieve value */
13851384
zv = zend_hash_get_current_data_ex(target_hash, &pos);
13861385
if (zv == NULL) {
@@ -1396,8 +1395,6 @@ static int php_array_walk(zval *array, zval *userdata, int recursive) /* {{{ */
13961395
}
13971396
}
13981397

1399-
was_ref = Z_ISREF_P(zv);
1400-
14011398
/* Ensure the value is a reference. Otherwise the location of the value may be freed. */
14021399
ZVAL_MAKE_REF(zv);
14031400

@@ -1415,16 +1412,14 @@ static int php_array_walk(zval *array, zval *userdata, int recursive) /* {{{ */
14151412
HashTable *thash;
14161413
zend_fcall_info orig_array_walk_fci;
14171414
zend_fcall_info_cache orig_array_walk_fci_cache;
1418-
zval rv;
1415+
zval ref;
1416+
ZVAL_COPY_VALUE(&ref, zv);
14191417

1420-
SEPARATE_ARRAY(Z_REFVAL_P(zv));
1421-
ZVAL_COPY_VALUE(&rv, Z_REFVAL_P(zv));
1422-
thash = Z_ARRVAL(rv);
1418+
ZVAL_DEREF(zv);
1419+
SEPARATE_ARRAY(zv);
1420+
thash = Z_ARRVAL_P(zv);
14231421
if (thash->u.v.nApplyCount > 1) {
14241422
php_error_docref(NULL, E_WARNING, "recursion detected");
1425-
if (!was_ref) {
1426-
ZVAL_UNREF(zv);
1427-
}
14281423
result = FAILURE;
14291424
break;
14301425
}
@@ -1433,15 +1428,15 @@ static int php_array_walk(zval *array, zval *userdata, int recursive) /* {{{ */
14331428
orig_array_walk_fci = BG(array_walk_fci);
14341429
orig_array_walk_fci_cache = BG(array_walk_fci_cache);
14351430

1436-
Z_ADDREF(rv);
1431+
Z_ADDREF(ref);
14371432
thash->u.v.nApplyCount++;
1438-
result = php_array_walk(&rv, userdata, recursive);
1439-
if (Z_TYPE_P(Z_REFVAL_P(zv)) == IS_ARRAY && thash == Z_ARRVAL_P(Z_REFVAL_P(zv))) {
1433+
result = php_array_walk(zv, userdata, recursive);
1434+
if (Z_TYPE_P(Z_REFVAL(ref)) == IS_ARRAY && thash == Z_ARRVAL_P(Z_REFVAL(ref))) {
14401435
/* If the hashtable changed in the meantime, we'll "leak" this apply count
14411436
* increment -- our reference to thash is no longer valid. */
14421437
thash->u.v.nApplyCount--;
14431438
}
1444-
zval_ptr_dtor(&rv);
1439+
zval_ptr_dtor(&ref);
14451440

14461441
/* restore the fcall info and cache */
14471442
BG(array_walk_fci) = orig_array_walk_fci;
@@ -1457,15 +1452,12 @@ static int php_array_walk(zval *array, zval *userdata, int recursive) /* {{{ */
14571452

14581453
zval_ptr_dtor(&args[0]);
14591454
}
1455+
14601456
if (Z_TYPE(args[1]) != IS_UNDEF) {
14611457
zval_ptr_dtor(&args[1]);
14621458
ZVAL_UNDEF(&args[1]);
14631459
}
1464-
if (!was_ref && Z_ISREF_P(zv)) {
1465-
if (Z_REFCOUNT_P(zv) == 1) {
1466-
ZVAL_UNREF(zv);
1467-
}
1468-
}
1460+
14691461
if (result == FAILURE) {
14701462
break;
14711463
}

ext/standard/tests/array/bug75961.phpt

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)