diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2019-04-16 10:40:01 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2019-04-16 10:40:01 +0200 |
commit | 772a158d7a2fd67a7ccae1f87b0abf4ead73561b (patch) | |
tree | f49b77d9ea8ac3dce2619ea076efd83cb3c23ac1 | |
parent | 9e62ba1533504a32ce5cfea01e2f11fb27a4abb1 (diff) | |
parent | 32fb2d93431aa5d5b111051db998501a8d7117ee (diff) | |
download | php-git-772a158d7a2fd67a7ccae1f87b0abf4ead73561b.tar.gz |
Merge branch 'PHP-7.4'
-rw-r--r-- | Zend/tests/foreach_by_ref_repacking_insert.phpt | 18 | ||||
-rw-r--r-- | Zend/zend_hash.c | 67 | ||||
-rw-r--r-- | ext/spl/tests/bug77903.phpt | 52 | ||||
-rw-r--r-- | php.ini-development | 4 | ||||
-rw-r--r-- | php.ini-production | 4 |
5 files changed, 94 insertions, 51 deletions
diff --git a/Zend/tests/foreach_by_ref_repacking_insert.phpt b/Zend/tests/foreach_by_ref_repacking_insert.phpt new file mode 100644 index 0000000000..1a2f9c7068 --- /dev/null +++ b/Zend/tests/foreach_by_ref_repacking_insert.phpt @@ -0,0 +1,18 @@ +--TEST-- +Perform a packed to hash insert when the iterator is at the end of the array +--FILE-- + +<?php +$a = []; +$a[1] = 1; +foreach ($a as $k => &$v) { + var_dump($v); + if ($k == 1) $a[4] = 4; + if ($k == 4) $a[2] = 2; +} + +?> +--EXPECT-- +int(1) +int(4) +int(2) diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index c6ad84ae2d..bee425c05f 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -400,10 +400,8 @@ ZEND_API uint32_t zend_array_count(HashTable *ht) } /* }}} */ -static zend_always_inline HashPosition _zend_hash_get_first_pos(const HashTable *ht) +static zend_always_inline HashPosition _zend_hash_get_valid_pos(const HashTable *ht, HashPosition pos) { - HashPosition pos = 0; - while (pos < ht->nNumUsed && Z_ISUNDEF(ht->arData[pos].val)) { pos++; } @@ -412,12 +410,7 @@ static zend_always_inline HashPosition _zend_hash_get_first_pos(const HashTable static zend_always_inline HashPosition _zend_hash_get_current_pos(const HashTable *ht) { - HashPosition pos = ht->nInternalPointer; - - if (pos == 0) { - pos = _zend_hash_get_first_pos(ht); - } - return pos; + return _zend_hash_get_valid_pos(ht, ht->nInternalPointer); } ZEND_API HashPosition ZEND_FASTCALL zend_hash_get_current_pos(const HashTable *ht) @@ -1168,6 +1161,7 @@ ZEND_API int ZEND_FASTCALL zend_hash_rehash(HashTable *ht) p++; } while (++i < ht->nNumUsed); } else { + uint32_t old_num_used = ht->nNumUsed; do { if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) { uint32_t j = i; @@ -1224,6 +1218,12 @@ ZEND_API int ZEND_FASTCALL zend_hash_rehash(HashTable *ht) HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(i); p++; } while (++i < ht->nNumUsed); + + /* Migrate pointer to one past the end of the array to the new one past the end, so that + * newly inserted elements are picked up correctly. */ + if (UNEXPECTED(HT_HAS_ITERATORS(ht))) { + _zend_hash_iterators_update(ht, old_num_used, ht->nNumUsed); + } } return SUCCESS; } @@ -2241,7 +2241,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_reset_ex(HashTable *ht, H { IS_CONSISTENT(ht); HT_ASSERT(ht, &ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1); - *pos = _zend_hash_get_first_pos(ht); + *pos = _zend_hash_get_valid_pos(ht, 0); } @@ -2269,19 +2269,13 @@ ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_end_ex(HashTable *ht, Has ZEND_API int ZEND_FASTCALL zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos) { - uint32_t idx = *pos; + uint32_t idx; IS_CONSISTENT(ht); HT_ASSERT(ht, &ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1); + idx = _zend_hash_get_valid_pos(ht, *pos); if (idx < ht->nNumUsed) { - if (idx == 0) { - idx = _zend_hash_get_first_pos(ht); - if (idx >= ht->nNumUsed) { - *pos = idx; - return SUCCESS; - } - } while (1) { idx++; if (idx >= ht->nNumUsed) { @@ -2324,17 +2318,12 @@ ZEND_API int ZEND_FASTCALL zend_hash_move_backwards_ex(HashTable *ht, HashPositi /* This function should be made binary safe */ ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_ex(const HashTable *ht, zend_string **str_index, zend_ulong *num_index, HashPosition *pos) { - uint32_t idx = *pos; + uint32_t idx; Bucket *p; IS_CONSISTENT(ht); + idx = _zend_hash_get_valid_pos(ht, *pos); if (idx < ht->nNumUsed) { - if (idx == 0) { - idx = _zend_hash_get_first_pos(ht); - if (idx >= ht->nNumUsed) { - return HASH_KEY_NON_EXISTENT; - } - } p = ht->arData + idx; if (p->key) { *str_index = p->key; @@ -2349,20 +2338,14 @@ ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_ex(const HashTable *ht, zen ZEND_API void ZEND_FASTCALL zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos) { - uint32_t idx = *pos; + uint32_t idx; Bucket *p; IS_CONSISTENT(ht); + idx = _zend_hash_get_valid_pos(ht, *pos); if (idx >= ht->nNumUsed) { ZVAL_NULL(key); } else { - if (idx == 0) { - idx = _zend_hash_get_first_pos(ht); - if (idx >= ht->nNumUsed) { - ZVAL_NULL(key); - return; - } - } p = ht->arData + idx; if (p->key) { ZVAL_STR_COPY(key, p->key); @@ -2374,17 +2357,12 @@ ZEND_API void ZEND_FASTCALL zend_hash_get_current_key_zval_ex(const HashTable *h ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos) { - uint32_t idx = *pos; + uint32_t idx; Bucket *p; IS_CONSISTENT(ht); + idx = _zend_hash_get_valid_pos(ht, *pos); if (idx < ht->nNumUsed) { - if (idx == 0) { - idx = _zend_hash_get_first_pos(ht); - if (idx >= ht->nNumUsed) { - return HASH_KEY_NON_EXISTENT; - } - } p = ht->arData + idx; if (p->key) { return HASH_KEY_IS_STRING; @@ -2398,17 +2376,12 @@ ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_type_ex(HashTable *ht, Hash ZEND_API zval* ZEND_FASTCALL zend_hash_get_current_data_ex(HashTable *ht, HashPosition *pos) { - uint32_t idx = *pos; + uint32_t idx; Bucket *p; IS_CONSISTENT(ht); + idx = _zend_hash_get_valid_pos(ht, *pos); if (idx < ht->nNumUsed) { - if (idx == 0) { - idx = _zend_hash_get_first_pos(ht); - if (idx >= ht->nNumUsed) { - return NULL; - } - } p = ht->arData + idx; return &p->val; } else { diff --git a/ext/spl/tests/bug77903.phpt b/ext/spl/tests/bug77903.phpt new file mode 100644 index 0000000000..842de9cca2 --- /dev/null +++ b/ext/spl/tests/bug77903.phpt @@ -0,0 +1,52 @@ +--TEST-- +Bug #77903: ArrayIterator stops iterating after offsetSet call +--FILE-- +<?php +$a = new ArrayIterator(); +$a->rewind(); +var_dump($a->valid()); // false +var_dump($a->current()); // null +$a->offsetSet(1,1); +var_dump($a->valid()); // true +var_dump($a->current()); // 1 +$a->next(); +var_dump($a->valid()); // false +var_dump($a->current()); // null +$a->offsetSet(4,4); +var_dump($a->valid()); // true +var_dump($a->current()); // 4 +$a->next(); +var_dump($a->valid()); // false +var_dump($a->current()); // null +$a->next(); +var_dump($a->valid()); // false +var_dump($a->current()); // null +$a->offsetSet(2,2); +var_dump($a->valid()); // true +var_dump($a->current()); // 2 +$a->next(); +var_dump($a->valid()); // false +var_dump($a->current()); // null +$a->next(); +var_dump($a->valid()); // false +var_dump($a->current()); // null +?> +--EXPECT-- +bool(false) +NULL +bool(true) +int(1) +bool(false) +NULL +bool(true) +int(4) +bool(false) +NULL +bool(false) +NULL +bool(true) +int(2) +bool(false) +NULL +bool(false) +NULL diff --git a/php.ini-development b/php.ini-development index 374d26cc44..4329bfae1f 100644 --- a/php.ini-development +++ b/php.ini-development @@ -1176,11 +1176,11 @@ mysqli.default_port = 3306 ; http://php.net/mysqli.default-socket mysqli.default_socket = -; Default host for mysql_connect() (doesn't apply in safe mode). +; Default host for mysqli_connect() (doesn't apply in safe mode). ; http://php.net/mysqli.default-host mysqli.default_host = -; Default user for mysql_connect() (doesn't apply in safe mode). +; Default user for mysqli_connect() (doesn't apply in safe mode). ; http://php.net/mysqli.default-user mysqli.default_user = diff --git a/php.ini-production b/php.ini-production index fecff7c473..c8bf73950c 100644 --- a/php.ini-production +++ b/php.ini-production @@ -1176,11 +1176,11 @@ mysqli.default_port = 3306 ; http://php.net/mysqli.default-socket mysqli.default_socket = -; Default host for mysql_connect() (doesn't apply in safe mode). +; Default host for mysql_iconnect() (doesn't apply in safe mode). ; http://php.net/mysqli.default-host mysqli.default_host = -; Default user for mysql_connect() (doesn't apply in safe mode). +; Default user for mysql_iconnect() (doesn't apply in safe mode). ; http://php.net/mysqli.default-user mysqli.default_user = |