]> granicus.if.org Git - php/commitdiff
Improved fix for bug (count on symbol table)
authorXinchen Hui <laruence@gmail.com>
Mon, 23 Nov 2015 14:12:03 +0000 (06:12 -0800)
committerXinchen Hui <laruence@gmail.com>
Mon, 23 Nov 2015 14:12:03 +0000 (06:12 -0800)
Zend/zend_hash.c
Zend/zend_hash.h
ext/standard/array.c
ext/standard/var.c

index c324f1dfa8b4b951b9e73c39703c2ed7f9e2e63e..283ceb8c18dd361d2046508dfbf1d609a0d056e3 100644 (file)
@@ -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);
index 6ce37a909bde184aa3fdcca8cc861d06bf43c0a8..9fe99ac919a2f18ec4d846799ea6ce5612fd4211 100644 (file)
@@ -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);
index df9cc563ac32d03fff53568956052ea6cba1a60a..79c9ab6207ad5c8600c62a9a80f75c562a6f7ce4 100644 (file)
@@ -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 */
index 72b2dd5ed5dfdd4374d62a8a39c4f90a413c6e4f..7ae9fcf105b4657c15b7d726677b8b33a5207461 100644 (file)
 #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;
                                }