From ec0971110100adfa819848f29baba54049c17fd3 Mon Sep 17 00:00:00 2001 From: Andrei Zmievski Date: Wed, 15 Jun 2005 20:51:33 +0000 Subject: [PATCH] Fix FCI cache for array_walk and user array compare functions. Bug #33286. (Patch from m.bretz@metropolis-ag.de) --- ext/standard/array.c | 104 ++++++++++++++++++++------------- ext/standard/basic_functions.c | 1 - ext/standard/basic_functions.h | 1 - 3 files changed, 62 insertions(+), 44 deletions(-) diff --git a/ext/standard/array.c b/ext/standard/array.c index 2e0909633f..1fca66a4a3 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -610,43 +610,66 @@ static int array_user_compare(const void *a, const void *b TSRMLS_DC) } } -/* check is comparison function is valid */ +/* check if comparison function is valid */ #define PHP_ARRAY_CMP_FUNC_CHECK(func_name) \ if (!zend_is_callable(*func_name, 0, NULL)) { \ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid comparison function."); \ + BG(user_compare_fci_cache) = old_user_compare_fci_cache; \ BG(user_compare_func_name) = old_compare_func; \ RETURN_FALSE; \ } \ + /* clear FCI cache otherwise : for example the same or other array with + (partly) the same key values has been sorted with uasort() or + other sorting function the comparison is cached, however the the name + of the function for comparison is not respected. see bug #28739 AND #33295 + + following defines will assist in backup / restore values. + */ + +#define PHP_ARRAY_CMP_FUNC_VARS \ + zval **old_compare_func; \ + zend_fcall_info_cache old_user_compare_fci_cache; \ + +#define PHP_ARRAY_CMP_FUNC_BACKUP() \ + old_compare_func = BG(user_compare_func_name); \ + old_user_compare_fci_cache = BG(user_compare_fci_cache); \ + BG(user_compare_fci_cache) = empty_fcall_info_cache; \ + +#define PHP_ARRAY_CMP_FUNC_RESTORE() \ + BG(user_compare_fci_cache) = old_user_compare_fci_cache; \ + BG(user_compare_func_name) = old_compare_func; \ + + /* {{{ proto bool usort(array array_arg, string cmp_function) Sort an array by values using a user-defined comparison function */ PHP_FUNCTION(usort) { zval **array; - zval **old_compare_func; HashTable *target_hash; + PHP_ARRAY_CMP_FUNC_VARS; + + PHP_ARRAY_CMP_FUNC_BACKUP(); - old_compare_func = BG(user_compare_func_name); - BG(user_compare_fci_cache) = empty_fcall_info_cache; if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &array, &BG(user_compare_func_name)) == FAILURE) { - BG(user_compare_func_name) = old_compare_func; + PHP_ARRAY_CMP_FUNC_RESTORE(); WRONG_PARAM_COUNT; } target_hash = HASH_OF(*array); if (!target_hash) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array"); - BG(user_compare_func_name) = old_compare_func; + PHP_ARRAY_CMP_FUNC_RESTORE(); RETURN_FALSE; } PHP_ARRAY_CMP_FUNC_CHECK(BG(user_compare_func_name)) if (zend_hash_sort(target_hash, zend_qsort, array_user_compare, 1 TSRMLS_CC) == FAILURE) { - BG(user_compare_func_name) = old_compare_func; + PHP_ARRAY_CMP_FUNC_RESTORE(); RETURN_FALSE; } - BG(user_compare_func_name) = old_compare_func; + PHP_ARRAY_CMP_FUNC_RESTORE(); RETURN_TRUE; } /* }}} */ @@ -656,29 +679,30 @@ PHP_FUNCTION(usort) PHP_FUNCTION(uasort) { zval **array; - zval **old_compare_func; HashTable *target_hash; + PHP_ARRAY_CMP_FUNC_VARS; + + PHP_ARRAY_CMP_FUNC_BACKUP(); - old_compare_func = BG(user_compare_func_name); - BG(user_compare_fci_cache) = empty_fcall_info_cache; if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &array, &BG(user_compare_func_name)) == FAILURE) { - BG(user_compare_func_name) = old_compare_func; + PHP_ARRAY_CMP_FUNC_RESTORE(); WRONG_PARAM_COUNT; } target_hash = HASH_OF(*array); if (!target_hash) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array"); - BG(user_compare_func_name) = old_compare_func; + PHP_ARRAY_CMP_FUNC_RESTORE(); RETURN_FALSE; } PHP_ARRAY_CMP_FUNC_CHECK(BG(user_compare_func_name)) if (zend_hash_sort(target_hash, zend_qsort, array_user_compare, 0 TSRMLS_CC) == FAILURE) { - BG(user_compare_func_name) = old_compare_func; + PHP_ARRAY_CMP_FUNC_RESTORE(); RETURN_FALSE; } - BG(user_compare_func_name) = old_compare_func; + PHP_ARRAY_CMP_FUNC_RESTORE(); + RETURN_TRUE; } /* }}} */ @@ -735,28 +759,33 @@ static int array_user_key_compare(const void *a, const void *b TSRMLS_DC) PHP_FUNCTION(uksort) { zval **array; - zval **old_compare_func; HashTable *target_hash; + PHP_ARRAY_CMP_FUNC_VARS; + + + PHP_ARRAY_CMP_FUNC_BACKUP(); - old_compare_func = BG(user_compare_func_name); if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &array, &BG(user_compare_func_name)) == FAILURE) { - BG(user_compare_func_name) = old_compare_func; + PHP_ARRAY_CMP_FUNC_RESTORE(); WRONG_PARAM_COUNT; } target_hash = HASH_OF(*array); if (!target_hash) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array"); - BG(user_compare_func_name) = old_compare_func; + PHP_ARRAY_CMP_FUNC_RESTORE(); + RETURN_FALSE; } PHP_ARRAY_CMP_FUNC_CHECK(BG(user_compare_func_name)) if (zend_hash_sort(target_hash, zend_qsort, array_user_key_compare, 0 TSRMLS_CC) == FAILURE) { - BG(user_compare_func_name) = old_compare_func; + PHP_ARRAY_CMP_FUNC_RESTORE(); + RETURN_FALSE; } - BG(user_compare_func_name) = old_compare_func; + + PHP_ARRAY_CMP_FUNC_RESTORE(); RETURN_TRUE; } /* }}} */ @@ -1030,6 +1059,7 @@ static int php_array_walk(HashTable *target_hash, zval **userdata, int recursive uint string_key_len; ulong num_key; HashPosition pos; + zend_fcall_info_cache array_walk_fci_cache = empty_fcall_info_cache; /* Set up known arguments */ args[1] = &key; @@ -1073,7 +1103,7 @@ static int php_array_walk(HashTable *target_hash, zval **userdata, int recursive fci.no_separation = 0; /* Call the userland function */ - if (zend_call_function(&fci, &BG(array_walk_fci_cache) TSRMLS_CC) == SUCCESS) { + if (zend_call_function(&fci, &array_walk_fci_cache TSRMLS_CC) == SUCCESS) { if (retval_ptr) { zval_ptr_dtor(&retval_ptr); } @@ -1115,7 +1145,6 @@ PHP_FUNCTION(array_walk) HashTable *target_hash; argc = ZEND_NUM_ARGS(); - BG(array_walk_fci_cache) = empty_fcall_info_cache; old_walk_func_name = BG(array_walk_func_name); if (argc < 2 || argc > 3 || zend_get_parameters_ex(argc, &array, &BG(array_walk_func_name), &userdata) == FAILURE) { @@ -1152,7 +1181,6 @@ PHP_FUNCTION(array_walk_recursive) argc = ZEND_NUM_ARGS(); old_walk_func_name = BG(array_walk_func_name); - BG(array_walk_fci_cache) = empty_fcall_info_cache; if (argc < 2 || argc > 3 || zend_get_parameters_ex(argc, &array, &BG(array_walk_func_name), &userdata) == FAILURE) { @@ -2830,7 +2858,8 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int Bucket ***lists, **list, ***ptrs, *p; char *callback_name; - zval **old_compare_func; + PHP_ARRAY_CMP_FUNC_VARS; + int (*intersect_key_compare_func)(const void *, const void * TSRMLS_DC); int (*intersect_data_compare_func)(const void *, const void * TSRMLS_DC); @@ -2844,13 +2873,7 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int WRONG_PARAM_COUNT; } - old_compare_func = BG(user_compare_func_name); - /* clear FCI cache otherwise : for example the same or other array with - (partly) the same key values has been sorted with uasort() or - other sorting function the comparison is cached, however the the name - of the function for comparison is not respected. see bug #28739 - */ - BG(user_compare_fci_cache) = empty_fcall_info_cache; + PHP_ARRAY_CMP_FUNC_BACKUP(); if (behavior == INTERSECT_NORMAL) { intersect_key_compare_func = array_key_compare; @@ -3121,7 +3144,8 @@ out: pefree(lists[i], hash->persistent); } - BG(user_compare_func_name) = old_compare_func; + PHP_ARRAY_CMP_FUNC_RESTORE(); + efree(ptrs); efree(lists); @@ -3210,7 +3234,8 @@ static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_ Bucket ***lists, **list, ***ptrs, *p; char *callback_name; - zval **old_compare_func; + PHP_ARRAY_CMP_FUNC_VARS; + int (*diff_key_compare_func)(const void *, const void * TSRMLS_DC); int (*diff_data_compare_func)(const void *, const void * TSRMLS_DC); @@ -3224,13 +3249,7 @@ static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_ WRONG_PARAM_COUNT; } - old_compare_func = BG(user_compare_func_name); - /* clear FCI cache otherwise : for example the same or other array with - (partly) the same key values has been sorted with uasort() or - other sorting function the comparison is cached, however the the name - of the function for comparison is not respected. see bug #28739 - */ - BG(user_compare_fci_cache) = empty_fcall_info_cache; + PHP_ARRAY_CMP_FUNC_BACKUP(); if (behavior == DIFF_NORMAL) { diff_key_compare_func = array_key_compare; @@ -3499,7 +3518,8 @@ out: pefree(lists[i], hash->persistent); } - BG(user_compare_func_name) = old_compare_func; + PHP_ARRAY_CMP_FUNC_RESTORE(); + efree(ptrs); efree(lists); diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index c1c49ed1a8..9ad9f9d705 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -955,7 +955,6 @@ static void basic_globals_ctor(php_basic_globals *basic_globals_p TSRMLS_DC) BG(user_tick_functions) = NULL; BG(user_filter_map) = NULL; BG(user_compare_fci_cache) = empty_fcall_info_cache; - /*BG(array_walk_fci_cache) = empty_fcall_info_cache;*/ zend_hash_init(&BG(sm_protected_env_vars), 5, NULL, NULL, 1); BG(sm_allowed_env_vars) = NULL; diff --git a/ext/standard/basic_functions.h b/ext/standard/basic_functions.h index 58e1f024fc..9cb1245278 100644 --- a/ext/standard/basic_functions.h +++ b/ext/standard/basic_functions.h @@ -160,7 +160,6 @@ typedef struct _php_basic_globals { ulong strtok_len; char str_ebuf[40]; zval **array_walk_func_name; - zend_fcall_info_cache array_walk_fci_cache; zval **user_compare_func_name; zend_fcall_info_cache user_compare_fci_cache; zend_llist *user_tick_functions; -- 2.50.1