Merge branch 'PHP-7.4'

This commit is contained in:
Nikita Popov 2019-04-16 10:40:01 +02:00
commit 772a158d7a
5 changed files with 94 additions and 51 deletions

View file

@ -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)

View file

@ -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 {

View file

@ -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

View file

@ -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 =

View file

@ -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 =