From 6313e16a0472d42a2056364b1aacd7798d500b75 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Mon, 23 Nov 2015 06:12:03 -0800 Subject: [PATCH] Improved fix for bug (count on symbol table) --- Zend/zend_hash.c | 36 +++++++++++++++++++++++++ Zend/zend_hash.h | 1 + ext/standard/array.c | 41 +++------------------------- ext/standard/var.c | 63 ++++++-------------------------------------- 4 files changed, 48 insertions(+), 93 deletions(-) diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index c324f1dfa8..283ceb8c18 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -283,6 +283,40 @@ ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, zend } } +static uint32_t zend_array_recalc_elements(HashTable *ht) +{ + zval *val; + uint32_t num = ht->nNumOfElements; + + ZEND_HASH_FOREACH_VAL(ht, val) { + if (Z_TYPE_P(val) == IS_UNDEF) continue; + if (Z_TYPE_P(val) == IS_INDIRECT) { + if (UNEXPECTED(Z_TYPE_P(Z_INDIRECT_P(val)) == IS_UNDEF)) { + num--; + } + } + } ZEND_HASH_FOREACH_END(); + return num; +} +/* }}} */ + +ZEND_API uint32_t zend_array_count(HashTable *ht) +{ + uint32_t num; + if (UNEXPECTED(ht->u.v.flags & HASH_FLAG_HAS_EMPTY_IND)) { + num = zend_array_recalc_elements(ht); + if (UNEXPECTED(ht->nNumOfElements == num)) { + ht->u.v.flags &= ~HASH_FLAG_HAS_EMPTY_IND; + } + } else if (UNEXPECTED(ht == &EG(symbol_table))) { + num = zend_array_recalc_elements(ht); + } else { + num = zend_hash_num_elements(ht); + } + return num; +} +/* }}} */ + ZEND_API void ZEND_FASTCALL zend_hash_set_apply_protection(HashTable *ht, zend_bool bApplyProtection) { if (bApplyProtection) { @@ -1056,6 +1090,7 @@ ZEND_API int ZEND_FASTCALL zend_hash_del_ind(HashTable *ht, zend_string *key) } else { ZVAL_UNDEF(data); } + ht->u.v.flags |= HASH_FLAG_HAS_EMPTY_IND; } } else { _zend_hash_del_el_ex(ht, idx, p, prev); @@ -1099,6 +1134,7 @@ ZEND_API int ZEND_FASTCALL zend_hash_str_del_ind(HashTable *ht, const char *str, ht->pDestructor(data); } ZVAL_UNDEF(data); + ht->u.v.flags |= HASH_FLAG_HAS_EMPTY_IND; } } else { _zend_hash_del_el_ex(ht, idx, p, prev); diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index 6ce37a909b..9fe99ac919 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -216,6 +216,7 @@ ZEND_API zval* ZEND_FASTCALL zend_hash_minmax(const HashTable *ht, compare_func_ ZEND_API int ZEND_FASTCALL zend_hash_rehash(HashTable *ht); +ZEND_API uint32_t zend_array_count(HashTable *ht); ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source); ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht); ZEND_API void ZEND_FASTCALL zend_symtable_clean(HashTable *ht); diff --git a/ext/standard/array.c b/ext/standard/array.c index df9cc563ac..79c9ab6207 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -757,41 +757,6 @@ PHP_FUNCTION(ksort) } /* }}} */ -static uint32_t php_array_recalc_elements(HashTable *ht) /* {{{ */ -{ - zval *val; - uint32_t num = ht->nNumOfElements; - - ZEND_HASH_FOREACH_VAL(ht, val) { - if (Z_TYPE_P(val) == IS_UNDEF) continue; - if (Z_TYPE_P(val) == IS_INDIRECT) { - if (Z_TYPE_P(Z_INDIRECT_P(val)) == IS_UNDEF) { - num--; - } - } - } ZEND_HASH_FOREACH_END(); - return num; -} -/* }}} */ - -static uint32_t php_array_num_elements(zval *arr) /* {{{ */ -{ - uint32_t num; - HashTable *ht = Z_ARRVAL_P(arr); - if (UNEXPECTED(Z_SYMBOLTABLE_P(arr))) { - num = php_array_recalc_elements(ht); - } else if (UNEXPECTED(ht->u.v.flags & HASH_FLAG_HAS_EMPTY_IND)) { - num = php_array_recalc_elements(ht); - if (UNEXPECTED(ht->nNumOfElements == num)) { - ht->u.v.flags &= ~HASH_FLAG_HAS_EMPTY_IND; - } - } else { - num = zend_hash_num_elements(ht); - } - return num; -} -/* }}} */ - PHPAPI zend_long php_count_recursive(zval *array, zend_long mode) /* {{{ */ { zend_long cnt = 0; @@ -803,7 +768,7 @@ PHPAPI zend_long php_count_recursive(zval *array, zend_long mode) /* {{{ */ return 0; } - cnt = php_array_num_elements(array); + cnt = zend_array_count(Z_ARRVAL_P(array)); if (mode == COUNT_RECURSIVE) { if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(array))) { Z_ARRVAL_P(array)->u.v.nApplyCount++; @@ -848,7 +813,7 @@ PHP_FUNCTION(count) RETURN_LONG(0); break; case IS_ARRAY: - cnt = php_array_num_elements(array); + cnt = zend_array_count(Z_ARRVAL_P(array)); if (mode == COUNT_RECURSIVE) { ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array), element) { ZVAL_DEREF(element); @@ -5193,7 +5158,7 @@ PHP_FUNCTION(array_filter) } } - ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_key, string_key, operand) { + ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(array), num_key, string_key, operand) { if (have_callback) { if (use_type) { /* Set up the key */ diff --git a/ext/standard/var.c b/ext/standard/var.c index 72b2dd5ed5..7ae9fcf105 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -35,37 +35,6 @@ #define COMMON (is_ref ? "&" : "") /* }}} */ -static uint32_t php_array_recalc_elements(HashTable *ht) /* {{{ */ -{ - zval *val; - uint32_t num = ht->nNumOfElements; - - ZEND_HASH_FOREACH_VAL(ht, val) { - if (Z_TYPE_P(val) == IS_UNDEF) continue; - if (Z_TYPE_P(val) == IS_INDIRECT) { - if (Z_TYPE_P(Z_INDIRECT_P(val)) == IS_UNDEF) { - num--; - } - } - } ZEND_HASH_FOREACH_END(); - return num; -} -/* }}} */ - -static uint32_t php_array_num_elements(HashTable *ht) /* {{{ */ -{ - uint32_t num = ht->nNumOfElements; - - if (UNEXPECTED(ht->u.v.flags & HASH_FLAG_HAS_EMPTY_IND)) { - num = php_array_recalc_elements(ht); - if (UNEXPECTED(ht->nNumOfElements == num)) { - ht->u.v.flags &= ~HASH_FLAG_HAS_EMPTY_IND; - } - } - return num; -} -/* }}} */ - static void php_array_element_dump(zval *zv, zend_ulong index, zend_string *key, int level) /* {{{ */ { if (key == NULL) { /* numeric key */ @@ -150,11 +119,7 @@ again: --myht->u.v.nApplyCount; return; } - if (UNEXPECTED(Z_SYMBOLTABLE_P(struc))) { - count = php_array_recalc_elements(myht); - } else { - count = php_array_num_elements(myht); - } + count = zend_array_count(myht); php_printf("%sarray(%d) {\n", COMMON, count); is_temp = 0; @@ -182,7 +147,7 @@ again: myht = Z_OBJDEBUG_P(struc, is_temp); class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc)); - php_printf("%sobject(%s)#%d (%d) {\n", COMMON, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? php_array_num_elements(myht) : 0); + php_printf("%sobject(%s)#%d (%d) {\n", COMMON, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0); zend_string_release(class_name); if (myht) { @@ -324,11 +289,7 @@ again: PUTS("*RECURSION*\n"); return; } - if (UNEXPECTED(Z_SYMBOLTABLE_P(struc))) { - count = php_array_recalc_elements(myht); - } else { - count = php_array_num_elements(myht); - } + count = zend_array_count(myht); php_printf("%sarray(%d) refcount(%u){\n", COMMON, count, Z_REFCOUNTED_P(struc) ? Z_REFCOUNT_P(struc) : 1); ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) { zval_array_element_dump(val, index, key, level); @@ -356,7 +317,7 @@ again: } } class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc)); - php_printf("%sobject(%s)#%d (%d) refcount(%u){\n", COMMON, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? php_array_num_elements(myht) : 0, Z_REFCOUNT_P(struc)); + php_printf("%sobject(%s)#%d (%d) refcount(%u){\n", COMMON, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0, Z_REFCOUNT_P(struc)); zend_string_release(class_name); if (myht) { ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) { @@ -707,14 +668,10 @@ static void php_var_serialize_class(smart_str *buf, zval *struc, zval *retval_pt * changes the count if the variable is incomplete class */ if (Z_TYPE_P(retval_ptr) == IS_ARRAY) { ht = Z_ARRVAL_P(retval_ptr); - if (UNEXPECTED(Z_SYMBOLTABLE_P(struc))) { - count = php_array_recalc_elements(ht); - } else { - count = php_array_num_elements(ht); - } + count = zend_array_count(ht); } else if (Z_TYPE_P(retval_ptr) == IS_OBJECT) { ht = Z_OBJPROP_P(retval_ptr); - count = php_array_num_elements(ht); + count = zend_array_count(ht); if (incomplete_class) { --count; } @@ -935,17 +892,13 @@ again: if (Z_TYPE_P(struc) == IS_ARRAY) { smart_str_appendl(buf, "a:", 2); myht = Z_ARRVAL_P(struc); - if (UNEXPECTED(Z_SYMBOLTABLE_P(struc))) { - i = php_array_recalc_elements(myht); - } else { - i = php_array_num_elements(myht); - } + i = zend_array_count(myht); } else { incomplete_class = php_var_serialize_class_name(buf, struc); myht = Z_OBJPROP_P(struc); /* count after serializing name, since php_var_serialize_class_name * changes the count if the variable is incomplete class */ - i = php_array_num_elements(myht); + i = zend_array_count(myht); if (i > 0 && incomplete_class) { --i; } -- 2.40.0