]> granicus.if.org Git - php/commitdiff
Fix FCI cache for array_walk and user array compare functions. Bug
authorAndrei Zmievski <andrei@php.net>
Wed, 15 Jun 2005 20:51:33 +0000 (20:51 +0000)
committerAndrei Zmievski <andrei@php.net>
Wed, 15 Jun 2005 20:51:33 +0000 (20:51 +0000)
#33286. (Patch from m.bretz@metropolis-ag.de)

ext/standard/array.c
ext/standard/basic_functions.c
ext/standard/basic_functions.h

index 2e0909633f6528a77c051c61fffc68029558ce0e..1fca66a4a337ab98531b4adc9ae43ba22f573978 100644 (file)
@@ -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);
index c1c49ed1a8d2fd428c576cc9776a001bb15d5071..9ad9f9d70556390c7deec7a60267625145b25a3d 100644 (file)
@@ -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;
 
index 58e1f024fcf161b87a14c8476c1141c4d9a3586f..9cb1245278a75f84de6ccc6a5453f376411255c0 100644 (file)
@@ -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;