diff options
| author | Dmitry Stogov <dmitry@php.net> | 2008-08-01 14:22:03 +0000 |
|---|---|---|
| committer | Dmitry Stogov <dmitry@php.net> | 2008-08-01 14:22:03 +0000 |
| commit | 37a769353f986167171a8cff333d7c401d6e298c (patch) | |
| tree | 2bf393b365e82119544043013ecfc03c70d15394 | |
| parent | 4e5280a7a2d0b097d217511041d46257c28a8e63 (diff) | |
| download | php-git-37a769353f986167171a8cff333d7c401d6e298c.tar.gz | |
Fixed bug #44100 (Inconsistent handling of static array declarations with duplicate keys).
| -rw-r--r-- | NEWS | 2 | ||||
| -rwxr-xr-x | Zend/tests/bug28072.phpt | 2 | ||||
| -rw-r--r-- | Zend/zend_execute_API.c | 8 | ||||
| -rw-r--r-- | Zend/zend_hash.c | 62 | ||||
| -rw-r--r-- | Zend/zend_hash.h | 16 |
5 files changed, 78 insertions, 12 deletions
@@ -1,6 +1,8 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? 200?, PHP 5.3.0 Alpha 2 +- Fixed bug #44100 (Inconsistent handling of static array declarations with + duplicate keys). (Dmitry) 01 Aug 2008, PHP 5.3.0 Alpha 1 - Upgraded bundled PCRE to version 7.7 (Nuno) diff --git a/Zend/tests/bug28072.phpt b/Zend/tests/bug28072.phpt index 7959a1c4da..76208733f8 100755 --- a/Zend/tests/bug28072.phpt +++ b/Zend/tests/bug28072.phpt @@ -41,6 +41,6 @@ Array ) Array ( - [a] => 111 + [a] => 222 [c] => 444 ) diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index b5cea12fc1..21c5c8b525 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -599,17 +599,17 @@ ZEND_API int zval_update_constant_ex(zval **pp, void *arg, zend_class_entry *sco switch (Z_TYPE(const_value)) { case IS_STRING: - zend_symtable_update_current_key(Z_ARRVAL_P(p), Z_STRVAL(const_value), Z_STRLEN(const_value) + 1); + zend_symtable_update_current_key(Z_ARRVAL_P(p), Z_STRVAL(const_value), Z_STRLEN(const_value) + 1, HASH_UPDATE_KEY_IF_BEFORE); break; case IS_BOOL: case IS_LONG: - zend_hash_update_current_key(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, 0, Z_LVAL(const_value)); + zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, 0, Z_LVAL(const_value), HASH_UPDATE_KEY_IF_BEFORE, NULL); break; case IS_DOUBLE: - zend_hash_update_current_key(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, 0, (long)Z_DVAL(const_value)); + zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_LONG, NULL, 0, (long)Z_DVAL(const_value), HASH_UPDATE_KEY_IF_BEFORE, NULL); break; case IS_NULL: - zend_hash_update_current_key(Z_ARRVAL_P(p), HASH_KEY_IS_STRING, "", 1, 0); + zend_hash_update_current_key_ex(Z_ARRVAL_P(p), HASH_KEY_IS_STRING, "", 1, 0, HASH_UPDATE_KEY_IF_BEFORE, NULL); break; } zend_hash_move_forward(Z_ARRVAL_P(p)); diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index fe3757cadb..b4c8e7a794 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -1170,7 +1170,7 @@ 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, const char *str_index, uint str_length, ulong num_index, HashPosition *pos) +ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const char *str_index, uint str_length, ulong num_index, int mode, HashPosition *pos) { Bucket *p; @@ -1184,12 +1184,72 @@ ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const if (!p->nKeyLength && p->h == num_index) { return SUCCESS; } + + if (mode != HASH_UPDATE_KEY_ANYWAY) { + Bucket *q = ht->arBuckets[num_index & ht->nTableMask]; + int found = 0; + + while (q != NULL) { + if (q == p) { + found = 1; + } else if (!q->nKeyLength && q->h == num_index) { + if (found) { + if (mode & HASH_UPDATE_KEY_IF_BEFORE) { + break; + } else { + zend_hash_index_del(ht, p->h); + return FAILURE; + } + } else { + if (mode & HASH_UPDATE_KEY_IF_AFTER) { + break; + } else { + zend_hash_index_del(ht, p->h); + return FAILURE; + } + } + } + q = q->pNext; + } + } + 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; } + + if (mode != HASH_UPDATE_KEY_ANYWAY) { + ulong h = zend_inline_hash_func(str_index, str_length); + Bucket *q = ht->arBuckets[h & ht->nTableMask]; + int found = 0; + + while (q != NULL) { + if (q == p) { + found = 1; + } else if (q->h == h && q->nKeyLength == str_length && + memcmp(q->arKey, str_index, str_length) == 0) { + if (found) { + if (mode & HASH_UPDATE_KEY_IF_BEFORE) { + break; + } else { + zend_hash_del(ht, p->arKey, p->nKeyLength); + return FAILURE; + } + } else { + if (mode & HASH_UPDATE_KEY_IF_AFTER) { + break; + } else { + zend_hash_del(ht, p->arKey, p->nKeyLength); + return FAILURE; + } + } + } + q = q->pNext; + } + } + zend_hash_del(ht, str_index, str_length); } else { return FAILURE; diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index 2ec2c5b0f2..c05da51bb1 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -37,6 +37,11 @@ #define HASH_DEL_INDEX 1 #define HASH_DEL_KEY_QUICK 2 +#define HASH_UPDATE_KEY_IF_NONE 0 +#define HASH_UPDATE_KEY_IF_BEFORE 1 +#define HASH_UPDATE_KEY_IF_AFTER 2 +#define HASH_UPDATE_KEY_ANYWAY 3 + typedef ulong (*hash_func_t)(const char *arKey, uint nKeyLength); typedef int (*compare_func_t)(const void *, const void * TSRMLS_DC); typedef void (*sort_func_t)(void *, size_t, register size_t, compare_func_t TSRMLS_DC); @@ -124,7 +129,6 @@ ZEND_API int zend_hash_add_empty_element(HashTable *ht, const char *arKey, uint #define ZEND_HASH_APPLY_REMOVE 1<<0 #define ZEND_HASH_APPLY_STOP 1<<1 - typedef int (*apply_func_t)(void *pDest TSRMLS_DC); typedef int (*apply_func_arg_t)(void *pDest, void *argument TSRMLS_DC); typedef int (*apply_func_args_t)(void *pDest TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key); @@ -177,7 +181,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, const char *str_index, uint str_length, ulong num_index, HashPosition *pos); +ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const char *str_index, uint str_length, ulong num_index, int mode, HashPosition *pos); typedef struct _HashPointer { HashPosition pos; @@ -204,7 +208,7 @@ ZEND_API int zend_hash_set_pointer(HashTable *ht, const HashPointer *ptr); #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) + zend_hash_update_current_key_ex(ht, key_type, str_index, str_length, num_index, HASH_UPDATE_KEY_ANYWAY, NULL) /* Copying, merging and sorting */ ZEND_API void zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size); @@ -364,10 +368,10 @@ static inline int zend_symtable_exists(HashTable *ht, const char *arKey, uint nK return zend_hash_exists(ht, arKey, nKeyLength); } -static inline int zend_symtable_update_current_key(HashTable *ht, const char *arKey, uint nKeyLength) +static inline int zend_symtable_update_current_key(HashTable *ht, const char *arKey, uint nKeyLength, int mode) { - ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_update_current_key(ht, HASH_KEY_IS_LONG, NULL, 0, idx)); - return zend_hash_update_current_key(ht, HASH_KEY_IS_STRING, arKey, nKeyLength, 0); + ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_update_current_key_ex(ht, HASH_KEY_IS_LONG, NULL, 0, idx, mode, NULL)); + return zend_hash_update_current_key_ex(ht, HASH_KEY_IS_STRING, arKey, nKeyLength, 0, mode, NULL); } #endif /* ZEND_HASH_H */ |
