diff options
Diffstat (limited to 'ext/standard/array.c')
-rw-r--r-- | ext/standard/array.c | 301 |
1 files changed, 170 insertions, 131 deletions
diff --git a/ext/standard/array.c b/ext/standard/array.c index eb4cd6b417..7b6fca0647 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 7 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2018 The PHP Group | + | Copyright (c) The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -28,11 +28,7 @@ #include <math.h> #include <time.h> #include <stdio.h> -#if HAVE_STRING_H #include <string.h> -#else -#include <strings.h> -#endif #ifdef PHP_WIN32 #include "win32/unistd.h" #endif @@ -174,7 +170,7 @@ static int php_array_key_compare(const void *a, const void *b) /* {{{ */ } } } - return l1 > l2 ? 1 : (l1 < l2 ? -1 : 0); + return ZEND_NORMALIZE_BOOL(l1 - l2); } /* }}} */ @@ -982,7 +978,7 @@ static int php_array_user_compare(const void *a, const void *b) /* {{{ */ zval_ptr_dtor(&retval); zval_ptr_dtor(&args[1]); zval_ptr_dtor(&args[0]); - return ret < 0 ? -1 : ret > 0 ? 1 : 0; + return ZEND_NORMALIZE_BOOL(ret); } else { zval_ptr_dtor(&args[1]); zval_ptr_dtor(&args[0]); @@ -1105,7 +1101,7 @@ static int php_array_user_key_compare(const void *a, const void *b) /* {{{ */ zval_ptr_dtor(&args[0]); zval_ptr_dtor(&args[1]); - return result < 0 ? -1 : result > 0 ? 1 : 0; + return ZEND_NORMALIZE_BOOL(result); } /* }}} */ @@ -1790,9 +1786,11 @@ static zend_long php_extract_if_exists(zend_array *arr, zend_array *symbol_table zend_throw_error(NULL, "Cannot re-assign $this"); return -1; } - ZVAL_DEREF(orig_var); - zval_ptr_dtor(orig_var); - ZVAL_COPY_DEREF(orig_var, entry); + ZVAL_DEREF(entry); + ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); + if (UNEXPECTED(EG(exception))) { + return -1; + } count++; } } ZEND_HASH_FOREACH_END(); @@ -1873,9 +1871,11 @@ static zend_long php_extract_overwrite(zend_array *arr, zend_array *symbol_table if (zend_string_equals_literal(var_name, "GLOBALS")) { continue; } - ZVAL_DEREF(orig_var); - zval_ptr_dtor(orig_var); - ZVAL_COPY_DEREF(orig_var, entry); + ZVAL_DEREF(entry); + ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); + if (UNEXPECTED(EG(exception))) { + return -1; + } } else { ZVAL_DEREF(entry); Z_TRY_ADDREF_P(entry); @@ -1975,9 +1975,11 @@ static zend_long php_extract_prefix_if_exists(zend_array *arr, zend_array *symbo if (Z_TYPE_P(orig_var) == IS_INDIRECT) { orig_var = Z_INDIRECT_P(orig_var); } - ZVAL_DEREF(orig_var); - zval_ptr_dtor(orig_var); - ZVAL_COPY(orig_var, entry); + ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); + if (UNEXPECTED(EG(exception))) { + zend_string_release_ex(Z_STR(final_name), 0); + return -1; + } } else { Z_TRY_ADDREF_P(entry); zend_hash_add_new(symbol_table, Z_STR(final_name), entry); @@ -2101,9 +2103,11 @@ static zend_long php_extract_prefix_same(zend_array *arr, zend_array *symbol_tab if (Z_TYPE_P(orig_var) == IS_INDIRECT) { orig_var = Z_INDIRECT_P(orig_var); } - ZVAL_DEREF(orig_var); - zval_ptr_dtor(orig_var); - ZVAL_COPY(orig_var, entry); + ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); + if (UNEXPECTED(EG(exception))) { + zend_string_release_ex(Z_STR(final_name), 0); + return -1; + } } else { Z_TRY_ADDREF_P(entry); zend_hash_add_new(symbol_table, Z_STR(final_name), entry); @@ -2206,9 +2210,11 @@ static zend_long php_extract_prefix_all(zend_array *arr, zend_array *symbol_tabl if (Z_TYPE_P(orig_var) == IS_INDIRECT) { orig_var = Z_INDIRECT_P(orig_var); } - ZVAL_DEREF(orig_var); - zval_ptr_dtor(orig_var); - ZVAL_COPY(orig_var, entry); + ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); + if (UNEXPECTED(EG(exception))) { + zend_string_release_ex(Z_STR(final_name), 0); + return -1; + } } else { Z_TRY_ADDREF_P(entry); zend_hash_add_new(symbol_table, Z_STR(final_name), entry); @@ -2313,9 +2319,11 @@ static zend_long php_extract_prefix_invalid(zend_array *arr, zend_array *symbol_ if (Z_TYPE_P(orig_var) == IS_INDIRECT) { orig_var = Z_INDIRECT_P(orig_var); } - ZVAL_DEREF(orig_var); - zval_ptr_dtor(orig_var); - ZVAL_COPY(orig_var, entry); + ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); + if (UNEXPECTED(EG(exception))) { + zend_string_release_ex(Z_STR(final_name), 0); + return -1; + } } else { Z_TRY_ADDREF_P(entry); zend_hash_add_new(symbol_table, Z_STR(final_name), entry); @@ -3732,102 +3740,142 @@ PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src) /* {{{ * } /* }}} */ -static inline void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive, int replace) /* {{{ */ +static zend_always_inline void php_array_replace_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive) /* {{{ */ { zval *args = NULL; zval *arg; int argc, i; + HashTable *dest; ZEND_PARSE_PARAMETERS_START(1, -1) Z_PARAM_VARIADIC('+', args, argc) ZEND_PARSE_PARAMETERS_END(); - if (replace) { - HashTable *dest; - - for (i = 0; i < argc; i++) { - zval *arg = args + i; + for (i = 0; i < argc; i++) { + zval *arg = args + i; - if (Z_TYPE_P(arg) != IS_ARRAY) { - php_error_docref(NULL, E_WARNING, "Expected parameter %d to be an array, %s given", i + 1, zend_zval_type_name(arg)); - RETURN_NULL(); - } + if (Z_TYPE_P(arg) != IS_ARRAY) { + php_error_docref(NULL, E_WARNING, "Expected parameter %d to be an array, %s given", i + 1, zend_zval_type_name(arg)); + RETURN_NULL(); } + } - /* copy first array */ - arg = args; - dest = zend_array_dup(Z_ARRVAL_P(arg)); - ZVAL_ARR(return_value, dest); - if (recursive) { - for (i = 1; i < argc; i++) { - arg = args + i; - php_array_replace_recursive(dest, Z_ARRVAL_P(arg)); - } - } else { - for (i = 1; i < argc; i++) { - arg = args + i; - zend_hash_merge(dest, Z_ARRVAL_P(arg), zval_add_ref, 1); - } + /* copy first array */ + arg = args; + dest = zend_array_dup(Z_ARRVAL_P(arg)); + ZVAL_ARR(return_value, dest); + if (recursive) { + for (i = 1; i < argc; i++) { + arg = args + i; + php_array_replace_recursive(dest, Z_ARRVAL_P(arg)); } } else { - zval *src_entry; - HashTable *src, *dest; - uint32_t count = 0; + for (i = 1; i < argc; i++) { + arg = args + i; + zend_hash_merge(dest, Z_ARRVAL_P(arg), zval_add_ref, 1); + } + } +} +/* }}} */ - for (i = 0; i < argc; i++) { - zval *arg = args + i; +static zend_always_inline void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive) /* {{{ */ +{ + zval *args = NULL; + zval *arg; + int argc, i; + zval *src_entry; + HashTable *src, *dest; + uint32_t count = 0; - if (Z_TYPE_P(arg) != IS_ARRAY) { - php_error_docref(NULL, E_WARNING, "Expected parameter %d to be an array, %s given", i + 1, zend_zval_type_name(arg)); - RETURN_NULL(); - } - count += zend_hash_num_elements(Z_ARRVAL_P(arg)); - } - - arg = args; - src = Z_ARRVAL_P(arg); - /* copy first array */ - array_init_size(return_value, count); - dest = Z_ARRVAL_P(return_value); - if (HT_FLAGS(src) & HASH_FLAG_PACKED) { - zend_hash_real_init_packed(dest); - ZEND_HASH_FILL_PACKED(dest) { - ZEND_HASH_FOREACH_VAL(src, src_entry) { - if (UNEXPECTED(Z_ISREF_P(src_entry) && - Z_REFCOUNT_P(src_entry) == 1)) { - src_entry = Z_REFVAL_P(src_entry); + ZEND_PARSE_PARAMETERS_START(1, -1) + Z_PARAM_VARIADIC('+', args, argc) + ZEND_PARSE_PARAMETERS_END(); + + for (i = 0; i < argc; i++) { + zval *arg = args + i; + + if (Z_TYPE_P(arg) != IS_ARRAY) { + php_error_docref(NULL, E_WARNING, "Expected parameter %d to be an array, %s given", i + 1, zend_zval_type_name(arg)); + RETURN_NULL(); + } + count += zend_hash_num_elements(Z_ARRVAL_P(arg)); + } + + if (argc == 2) { + zval *ret = NULL; + + if (zend_hash_num_elements(Z_ARRVAL(args[0])) == 0) { + ret = &args[1]; + } else if (zend_hash_num_elements(Z_ARRVAL(args[1])) == 0) { + ret = &args[0]; + } + if (ret) { + if (HT_FLAGS(Z_ARRVAL_P(ret)) & HASH_FLAG_PACKED) { + if (HT_IS_WITHOUT_HOLES(Z_ARRVAL_P(ret))) { + ZVAL_COPY(return_value, ret); + return; + } + } else { + zend_bool copy = 1; + zend_string *string_key; + + ZEND_HASH_FOREACH_STR_KEY(Z_ARRVAL_P(ret), string_key) { + if (!string_key) { + copy = 0; + break; } - Z_TRY_ADDREF_P(src_entry); - ZEND_HASH_FILL_ADD(src_entry); } ZEND_HASH_FOREACH_END(); - } ZEND_HASH_FILL_END(); - } else { - zend_string *string_key; - zend_hash_real_init_mixed(dest); - ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) { + if (copy) { + ZVAL_COPY(return_value, ret); + return; + } + } + } + } + + arg = args; + src = Z_ARRVAL_P(arg); + /* copy first array */ + array_init_size(return_value, count); + dest = Z_ARRVAL_P(return_value); + if (HT_FLAGS(src) & HASH_FLAG_PACKED) { + zend_hash_real_init_packed(dest); + ZEND_HASH_FILL_PACKED(dest) { + ZEND_HASH_FOREACH_VAL(src, src_entry) { if (UNEXPECTED(Z_ISREF_P(src_entry) && Z_REFCOUNT_P(src_entry) == 1)) { src_entry = Z_REFVAL_P(src_entry); } Z_TRY_ADDREF_P(src_entry); - if (EXPECTED(string_key)) { - _zend_hash_append(dest, string_key, src_entry); - } else { - zend_hash_next_index_insert_new(dest, src_entry); - } + ZEND_HASH_FILL_ADD(src_entry); } ZEND_HASH_FOREACH_END(); - } - if (recursive) { - for (i = 1; i < argc; i++) { - arg = args + i; - php_array_merge_recursive(dest, Z_ARRVAL_P(arg)); + } ZEND_HASH_FILL_END(); + } else { + zend_string *string_key; + zend_hash_real_init_mixed(dest); + ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) { + if (UNEXPECTED(Z_ISREF_P(src_entry) && + Z_REFCOUNT_P(src_entry) == 1)) { + src_entry = Z_REFVAL_P(src_entry); } - } else { - for (i = 1; i < argc; i++) { - arg = args + i; - php_array_merge(dest, Z_ARRVAL_P(arg)); + Z_TRY_ADDREF_P(src_entry); + if (EXPECTED(string_key)) { + _zend_hash_append(dest, string_key, src_entry); + } else { + zend_hash_next_index_insert_new(dest, src_entry); } + } ZEND_HASH_FOREACH_END(); + } + if (recursive) { + for (i = 1; i < argc; i++) { + arg = args + i; + php_array_merge_recursive(dest, Z_ARRVAL_P(arg)); + } + } else { + for (i = 1; i < argc; i++) { + arg = args + i; + php_array_merge(dest, Z_ARRVAL_P(arg)); } } } @@ -3837,7 +3885,7 @@ static inline void php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAMETE Merges elements from passed arrays into one array */ PHP_FUNCTION(array_merge) { - php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0); + php_array_merge_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ @@ -3845,7 +3893,7 @@ PHP_FUNCTION(array_merge) Recursively merges elements from passed arrays into one array */ PHP_FUNCTION(array_merge_recursive) { - php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0); + php_array_merge_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ @@ -3853,7 +3901,7 @@ PHP_FUNCTION(array_merge_recursive) Replaces elements from passed arrays into one array */ PHP_FUNCTION(array_replace) { - php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1); + php_array_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ @@ -3861,7 +3909,7 @@ PHP_FUNCTION(array_replace) Recursively replaces elements from passed arrays into one array */ PHP_FUNCTION(array_replace_recursive) { - php_array_merge_or_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 1); + php_array_replace_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ @@ -4099,10 +4147,6 @@ static inline zval *array_column_fetch_prop(zval *data, zval *name, zval *rv) /* zval *prop = NULL; if (Z_TYPE_P(data) == IS_OBJECT) { - if (!Z_OBJ_HANDLER_P(data, has_property) || !Z_OBJ_HANDLER_P(data, read_property)) { - return NULL; - } - /* The has_property check is first performed in "exists" mode (which returns true for * properties that are null but exist) and then in "has" mode to handle objects that * implement __isset (which is not called in "exists" mode). */ @@ -4589,7 +4633,7 @@ static int zval_user_compare(zval *a, zval *b) /* {{{ */ if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) { zend_long ret = zval_get_long(&retval); zval_ptr_dtor(&retval); - return ret < 0 ? -1 : ret > 0 ? 1 : 0; + return ZEND_NORMALIZE_BOOL(ret); } else { return 0; } @@ -6137,7 +6181,7 @@ PHP_FUNCTION(array_map) ZVAL_COPY(&arg, zv); ret = zend_call_function(&fci, &fci_cache); - i_zval_ptr_dtor(&arg ZEND_FILE_LINE_CC); + i_zval_ptr_dtor(&arg); if (ret != SUCCESS || Z_TYPE(result) == IS_UNDEF) { zend_array_destroy(Z_ARR_P(return_value)); RETURN_NULL(); @@ -6250,34 +6294,38 @@ PHP_FUNCTION(array_map) Checks if the given key or index exists in the array */ PHP_FUNCTION(array_key_exists) { - zval *key; /* key to check for */ - HashTable *array; /* array to check in */ + zval *key; + zval *array; + HashTable *ht; ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_ZVAL(key) - Z_PARAM_ARRAY_OR_OBJECT_HT(array) + Z_PARAM_ARRAY_OR_OBJECT(array) ZEND_PARSE_PARAMETERS_END(); + if (EXPECTED(Z_TYPE_P(array) == IS_ARRAY)) { + ht = Z_ARRVAL_P(array); + } else { + ht = zend_get_properties_for(array, ZEND_PROP_PURPOSE_ARRAY_CAST); + } + switch (Z_TYPE_P(key)) { case IS_STRING: - if (zend_symtable_exists_ind(array, Z_STR_P(key))) { - RETURN_TRUE; - } - RETURN_FALSE; + RETVAL_BOOL(zend_symtable_exists_ind(ht, Z_STR_P(key))); + break; case IS_LONG: - if (zend_hash_index_exists(array, Z_LVAL_P(key))) { - RETURN_TRUE; - } - RETURN_FALSE; + RETVAL_BOOL(zend_hash_index_exists(ht, Z_LVAL_P(key))); + break; case IS_NULL: - if (zend_hash_exists_ind(array, ZSTR_EMPTY_ALLOC())) { - RETURN_TRUE; - } - RETURN_FALSE; - + RETVAL_BOOL(zend_hash_exists_ind(ht, ZSTR_EMPTY_ALLOC())); + break; default: php_error_docref(NULL, E_WARNING, "The first argument should be either a string or an integer"); - RETURN_FALSE; + RETVAL_FALSE; + } + + if (Z_TYPE_P(array) != IS_ARRAY) { + zend_release_properties(ht); } } /* }}} */ @@ -6404,12 +6452,3 @@ PHP_FUNCTION(array_combine) } ZEND_HASH_FOREACH_END(); } /* }}} */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ |