From: Nikita Popov Date: Wed, 20 Mar 2019 11:03:45 +0000 (+0100) Subject: Fixed bug #74345 X-Git-Tag: php-7.4.0alpha1~700 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=abc457fe1ddba07b1574744593f81ce1005025cd;p=php Fixed bug #74345 Export zend_release_fcall_info_cache(). It is only necessary to call it if the fcc may not have been used -- if it is passed to zend_call_function() and friends, then they will take care of freeing trampolines. --- diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 80a975252d..881ee27a03 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2907,7 +2907,7 @@ static int zend_is_callable_check_class(zend_string *name, zend_class_entry *sco } /* }}} */ -static void free_fcc(zend_fcall_info_cache *fcc) { +ZEND_API void zend_release_fcall_info_cache(zend_fcall_info_cache *fcc) { if (fcc->function_handler && ((fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) || fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY || @@ -2918,6 +2918,7 @@ static void free_fcc(zend_fcall_info_cache *fcc) { } zend_free_trampoline(fcc->function_handler); } + fcc->function_handler = NULL; } static zend_always_inline int zend_is_callable_check_func(int check_flags, zval *callable, zend_fcall_info_cache *fcc, int strict_class, char **error) /* {{{ */ @@ -3283,7 +3284,7 @@ again: check_func: ret = zend_is_callable_check_func(check_flags, callable, fcc, strict_class, error); if (fcc == &fcc_local) { - free_fcc(fcc); + zend_release_fcall_info_cache(fcc); } return ret; @@ -3352,7 +3353,7 @@ check_func: if (Z_OBJ_HANDLER_P(callable, get_closure) && Z_OBJ_HANDLER_P(callable, get_closure)(callable, &fcc->calling_scope, &fcc->function_handler, &fcc->object) == SUCCESS) { fcc->called_scope = fcc->calling_scope; if (fcc == &fcc_local) { - free_fcc(fcc); + zend_release_fcall_info_cache(fcc); } return 1; } @@ -3394,7 +3395,7 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zend_string **callable_nam add_next_index_str(callable, zend_string_copy(fcc.calling_scope->name)); add_next_index_str(callable, zend_string_copy(fcc.function_handler->common.function_name)); } - free_fcc(&fcc); + zend_release_fcall_info_cache(&fcc); return 1; } return 0; diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 21ba965000..00a39f6624 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -302,6 +302,7 @@ ZEND_API ZEND_COLD void zend_wrong_param_count(void); #define IS_CALLABLE_STRICT (IS_CALLABLE_CHECK_IS_STATIC) +ZEND_API void zend_release_fcall_info_cache(zend_fcall_info_cache *fcc); ZEND_API zend_string *zend_get_callable_name_ex(zval *callable, zend_object *object); ZEND_API zend_string *zend_get_callable_name(zval *callable); ZEND_API zend_bool zend_is_callable_ex(zval *callable, zend_object *object, uint32_t check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error); diff --git a/ext/standard/array.c b/ext/standard/array.c index 297b0c0f38..2658ad68f5 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -1013,6 +1013,7 @@ static int php_array_user_compare(const void *a, const void *b) /* {{{ */ BG(user_compare_fci_cache) = empty_fcall_info_cache; \ #define PHP_ARRAY_CMP_FUNC_RESTORE() \ + zend_release_fcall_info_cache(&BG(user_compare_fci_cache)); \ BG(user_compare_fci) = old_user_compare_fci; \ BG(user_compare_fci_cache) = old_user_compare_fci_cache; \ @@ -1502,6 +1503,7 @@ PHP_FUNCTION(array_walk) ); php_array_walk(array, userdata, 0); + zend_release_fcall_info_cache(&BG(array_walk_fci_cache)); BG(array_walk_fci) = orig_array_walk_fci; BG(array_walk_fci_cache) = orig_array_walk_fci_cache; RETURN_TRUE; @@ -1532,6 +1534,7 @@ PHP_FUNCTION(array_walk_recursive) ); php_array_walk(array, userdata, 1); + zend_release_fcall_info_cache(&BG(array_walk_fci_cache)); BG(array_walk_fci) = orig_array_walk_fci; BG(array_walk_fci_cache) = orig_array_walk_fci_cache; RETURN_TRUE; @@ -6017,6 +6020,7 @@ PHP_FUNCTION(array_reduce) if (zend_hash_num_elements(htbl) == 0) { ZVAL_COPY_VALUE(return_value, &result); + zend_release_fcall_info_cache(&fci_cache); return; } @@ -6040,6 +6044,7 @@ PHP_FUNCTION(array_reduce) } } ZEND_HASH_FOREACH_END(); + zend_release_fcall_info_cache(&fci_cache); RETVAL_ZVAL(&result, 1, 1); } /* }}} */ @@ -6069,6 +6074,7 @@ PHP_FUNCTION(array_filter) array_init(return_value); if (zend_hash_num_elements(Z_ARRVAL_P(array)) == 0) { + zend_release_fcall_info_cache(&fci_cache); return; } @@ -6130,6 +6136,8 @@ PHP_FUNCTION(array_filter) } zval_add_ref(operand); } ZEND_HASH_FOREACH_END(); + + zend_release_fcall_info_cache(&fci_cache); } /* }}} */ @@ -6167,6 +6175,7 @@ PHP_FUNCTION(array_map) /* Short-circuit: if no callback and only one array, just return it. */ if (!ZEND_FCI_INITIALIZED(fci) || !maxlen) { ZVAL_COPY(return_value, &arrays[0]); + zend_release_fcall_info_cache(&fci_cache); return; } @@ -6192,6 +6201,8 @@ PHP_FUNCTION(array_map) zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, &result); } } ZEND_HASH_FOREACH_END(); + + zend_release_fcall_info_cache(&fci_cache); } else { uint32_t *array_pos = (HashPosition *)ecalloc(n_arrays, sizeof(HashPosition)); @@ -6284,6 +6295,7 @@ PHP_FUNCTION(array_map) } efree(params); + zend_release_fcall_info_cache(&fci_cache); } efree(array_pos); } diff --git a/ext/standard/tests/array/bug74345.phpt b/ext/standard/tests/array/bug74345.phpt new file mode 100644 index 0000000000..144d257f55 --- /dev/null +++ b/ext/standard/tests/array/bug74345.phpt @@ -0,0 +1,27 @@ +--TEST-- +Bug #74345: Call trampoline leaked if callback not invoked +--FILE-- + +===DONE=== +--EXPECT-- +===DONE===