diff options
author | Dmitry Stogov <dmitry@php.net> | 2005-07-07 15:16:57 +0000 |
---|---|---|
committer | Dmitry Stogov <dmitry@php.net> | 2005-07-07 15:16:57 +0000 |
commit | d9c1a380ad0b073c8750f130a412229aeaed9a1b (patch) | |
tree | c4df575424a1d4ebe3413ca22dbd4193d02eb62e /Zend | |
parent | 3c5b9a6e6a1cb7462c5e2ffec23bea34f29a18dd (diff) | |
download | php-git-d9c1a380ad0b073c8750f130a412229aeaed9a1b.tar.gz |
Fixed bug #28072 (static array with some constant keys will be incorrectly ordered).
Diffstat (limited to 'Zend')
-rwxr-xr-x | Zend/tests/bug28072.phpt | 46 | ||||
-rw-r--r-- | Zend/zend_execute_API.c | 24 | ||||
-rw-r--r-- | Zend/zend_hash.c | 87 | ||||
-rw-r--r-- | Zend/zend_hash.h | 3 |
4 files changed, 156 insertions, 4 deletions
diff --git a/Zend/tests/bug28072.phpt b/Zend/tests/bug28072.phpt new file mode 100755 index 0000000000..7959a1c4da --- /dev/null +++ b/Zend/tests/bug28072.phpt @@ -0,0 +1,46 @@ +--TEST-- +Bug #28072 (static array with some constant keys will be incorrectly ordered) +--FILE-- +<?php +define("FIRST_KEY", "a"); +define("THIRD_KEY", "c"); + + +function test() +{ + static $arr = array( + FIRST_KEY => "111", + "b" => "222", + THIRD_KEY => "333", + "d" => "444" + ); + print_r($arr); +} + +function test2() +{ + static $arr = array( + FIRST_KEY => "111", + "a" => "222", + "c" => "333", + THIRD_KEY => "444" + ); + print_r($arr); +} + +test(); +test2(); +?> +--EXPECT-- +Array +( + [a] => 111 + [b] => 222 + [c] => 333 + [d] => 444 +) +Array +( + [a] => 111 + [c] => 444 +) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 5272718ddc..adda863112 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -490,17 +490,33 @@ ZEND_API int zval_update_constant(zval **pp, void *arg TSRMLS_DC) /* preserve this bit for inheritance */ Z_TYPE_PP(element) |= IS_CONSTANT_INDEX; + zval_ptr_dtor(element); + *element = new_val; switch (const_value.type) { - case IS_STRING: - zend_symtable_update(p->value.ht, const_value.value.str.val, const_value.value.str.len+1, &new_val, sizeof(zval *), NULL); + case IS_STRING: { + long lval; + double dval; + + if (is_numeric_string(const_value.value.str.val, const_value.value.str.len, &lval, &dval, 0) == IS_LONG) { + zend_hash_update_current_key(p->value.ht, HASH_KEY_IS_LONG, NULL, 0, lval); + } else { + zend_hash_update_current_key(p->value.ht, HASH_KEY_IS_STRING, const_value.value.str.val, const_value.value.str.len+1, 0); + } break; + } case IS_BOOL: case IS_LONG: - zend_hash_index_update(p->value.ht, const_value.value.lval, &new_val, sizeof(zval *), NULL); + zend_hash_update_current_key(p->value.ht, HASH_KEY_IS_LONG, NULL, 0, const_value.value.lval); + break; + case IS_DOUBLE: + zend_hash_update_current_key(p->value.ht, HASH_KEY_IS_LONG, NULL, 0, (long)const_value.value.dval); + break; + case IS_NULL: + zend_hash_update_current_key(p->value.ht, HASH_KEY_IS_STRING, "", 1, 0); break; } - zend_hash_del(p->value.ht, str_index, str_index_len); + zend_hash_move_forward(p->value.ht); zval_dtor(&const_value); } zend_hash_apply_with_argument(p->value.ht, (apply_func_arg_t) zval_update_constant, (void *) 1 TSRMLS_CC); diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index ec75fb6446..9d78e54392 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -1106,6 +1106,93 @@ ZEND_API int zend_hash_get_current_data_ex(HashTable *ht, void **pData, HashPosi } } +/* This function changes key of currevt element without changing elements' + * order. If element with target key already exists, it will be deleted first. + */ +ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, char *str_index, uint str_length, ulong num_index, HashPosition *pos) +{ + Bucket *p; + + p = pos ? (*pos) : ht->pInternalPointer; + + IS_CONSISTENT(ht); + + if (p) { + if (key_type == HASH_KEY_IS_LONG) { + str_length = 0; + if (!p->nKeyLength && p->h == num_index) { + return SUCCESS; + } + zend_hash_index_del(ht, num_index); + } else if (key_type == HASH_KEY_IS_STRING) { + if (p->nKeyLength == str_length && + memcmp(p->arKey, str_index, str_length) == 0) { + return SUCCESS; + } + zend_hash_del(ht, str_index, str_length); + } else { + return FAILURE; + } + + HANDLE_BLOCK_INTERRUPTIONS(); + + if (p->pNext) { + p->pNext->pLast = p->pLast; + } + if (p->pLast) { + p->pLast->pNext = p->pNext; + } else{ + ht->arBuckets[p->h & ht->nTableMask] = p->pNext; + } + + if (p->nKeyLength != str_length) { + Bucket *q = (Bucket *) pemalloc(sizeof(Bucket) - 1 + str_length, ht->persistent); + + q->nKeyLength = str_length; + if (p->pData == &p->pDataPtr) { + q->pData = &q->pDataPtr; + } else { + q->pData = p->pData; + } + q->pDataPtr = p->pDataPtr; + q->pListNext = p->pListNext; + q->pListLast = p->pListLast; + if (q->pListNext) { + p->pListNext->pListLast = q; + } else { + ht->pListTail = q; + } + if (q->pListLast) { + p->pListLast->pListNext = q; + } else { + ht->pListHead = q; + } + if (ht->pInternalPointer == p) { + ht->pInternalPointer = q; + } + if (pos) { + *pos = q; + } + pefree(p, ht->persistent); + p = q; + } + + if (key_type == HASH_KEY_IS_LONG) { + p->h = num_index; + } else { + memcpy(p->arKey, str_index, str_length); + p->h = zend_inline_hash_func(str_index, str_length); + } + + CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[p->h & ht->nTableMask]); + ht->arBuckets[p->h & ht->nTableMask] = p; + HANDLE_UNBLOCK_INTERRUPTIONS(); + + return SUCCESS; + } else { + return FAILURE; + } +} ZEND_API int zend_hash_sort(HashTable *ht, sort_func_t sort_func, compare_func_t compar, int renumber TSRMLS_DC) diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index 0b6dbb8288..292f9747f4 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -174,6 +174,7 @@ ZEND_API int zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos) ZEND_API int zend_hash_get_current_data_ex(HashTable *ht, void **pData, HashPosition *pos); ZEND_API void zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos); ZEND_API void zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos); +ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, char *str_index, uint str_length, ulong num_index, HashPosition *pos); #define zend_hash_has_more_elements(ht) \ zend_hash_has_more_elements_ex(ht, NULL) @@ -191,6 +192,8 @@ ZEND_API void zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos zend_hash_internal_pointer_reset_ex(ht, NULL) #define zend_hash_internal_pointer_end(ht) \ zend_hash_internal_pointer_end_ex(ht, NULL) +#define zend_hash_update_current_key(ht, key_type, str_index, str_length, num_index) \ + zend_hash_update_current_key_ex(ht, key_type, str_index, str_length, num_index, NULL) /* Copying, merging and sorting */ ZEND_API void zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size); |