Skip to content

Commit abc457f

Browse files
committed
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.
1 parent ed808c5 commit abc457f

File tree

4 files changed

+45
-4
lines changed

4 files changed

+45
-4
lines changed

Zend/zend_API.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2907,7 +2907,7 @@ static int zend_is_callable_check_class(zend_string *name, zend_class_entry *sco
29072907
}
29082908
/* }}} */
29092909

2910-
static void free_fcc(zend_fcall_info_cache *fcc) {
2910+
ZEND_API void zend_release_fcall_info_cache(zend_fcall_info_cache *fcc) {
29112911
if (fcc->function_handler &&
29122912
((fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) ||
29132913
fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
@@ -2918,6 +2918,7 @@ static void free_fcc(zend_fcall_info_cache *fcc) {
29182918
}
29192919
zend_free_trampoline(fcc->function_handler);
29202920
}
2921+
fcc->function_handler = NULL;
29212922
}
29222923

29232924
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 @@ static zend_always_inline zend_bool zend_is_callable_impl(zval *callable, zend_o
32833284
check_func:
32843285
ret = zend_is_callable_check_func(check_flags, callable, fcc, strict_class, error);
32853286
if (fcc == &fcc_local) {
3286-
free_fcc(fcc);
3287+
zend_release_fcall_info_cache(fcc);
32873288
}
32883289
return ret;
32893290

@@ -3352,7 +3353,7 @@ static zend_always_inline zend_bool zend_is_callable_impl(zval *callable, zend_o
33523353
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) {
33533354
fcc->called_scope = fcc->calling_scope;
33543355
if (fcc == &fcc_local) {
3355-
free_fcc(fcc);
3356+
zend_release_fcall_info_cache(fcc);
33563357
}
33573358
return 1;
33583359
}
@@ -3394,7 +3395,7 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zend_string **callable_nam
33943395
add_next_index_str(callable, zend_string_copy(fcc.calling_scope->name));
33953396
add_next_index_str(callable, zend_string_copy(fcc.function_handler->common.function_name));
33963397
}
3397-
free_fcc(&fcc);
3398+
zend_release_fcall_info_cache(&fcc);
33983399
return 1;
33993400
}
34003401
return 0;

Zend/zend_API.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ ZEND_API ZEND_COLD void zend_wrong_param_count(void);
302302

303303
#define IS_CALLABLE_STRICT (IS_CALLABLE_CHECK_IS_STATIC)
304304

305+
ZEND_API void zend_release_fcall_info_cache(zend_fcall_info_cache *fcc);
305306
ZEND_API zend_string *zend_get_callable_name_ex(zval *callable, zend_object *object);
306307
ZEND_API zend_string *zend_get_callable_name(zval *callable);
307308
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);

ext/standard/array.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,7 @@ static int php_array_user_compare(const void *a, const void *b) /* {{{ */
10131013
BG(user_compare_fci_cache) = empty_fcall_info_cache; \
10141014

10151015
#define PHP_ARRAY_CMP_FUNC_RESTORE() \
1016+
zend_release_fcall_info_cache(&BG(user_compare_fci_cache)); \
10161017
BG(user_compare_fci) = old_user_compare_fci; \
10171018
BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
10181019

@@ -1502,6 +1503,7 @@ PHP_FUNCTION(array_walk)
15021503
);
15031504

15041505
php_array_walk(array, userdata, 0);
1506+
zend_release_fcall_info_cache(&BG(array_walk_fci_cache));
15051507
BG(array_walk_fci) = orig_array_walk_fci;
15061508
BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
15071509
RETURN_TRUE;
@@ -1532,6 +1534,7 @@ PHP_FUNCTION(array_walk_recursive)
15321534
);
15331535

15341536
php_array_walk(array, userdata, 1);
1537+
zend_release_fcall_info_cache(&BG(array_walk_fci_cache));
15351538
BG(array_walk_fci) = orig_array_walk_fci;
15361539
BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
15371540
RETURN_TRUE;
@@ -6017,6 +6020,7 @@ PHP_FUNCTION(array_reduce)
60176020

60186021
if (zend_hash_num_elements(htbl) == 0) {
60196022
ZVAL_COPY_VALUE(return_value, &result);
6023+
zend_release_fcall_info_cache(&fci_cache);
60206024
return;
60216025
}
60226026

@@ -6040,6 +6044,7 @@ PHP_FUNCTION(array_reduce)
60406044
}
60416045
} ZEND_HASH_FOREACH_END();
60426046

6047+
zend_release_fcall_info_cache(&fci_cache);
60436048
RETVAL_ZVAL(&result, 1, 1);
60446049
}
60456050
/* }}} */
@@ -6069,6 +6074,7 @@ PHP_FUNCTION(array_filter)
60696074

60706075
array_init(return_value);
60716076
if (zend_hash_num_elements(Z_ARRVAL_P(array)) == 0) {
6077+
zend_release_fcall_info_cache(&fci_cache);
60726078
return;
60736079
}
60746080

@@ -6130,6 +6136,8 @@ PHP_FUNCTION(array_filter)
61306136
}
61316137
zval_add_ref(operand);
61326138
} ZEND_HASH_FOREACH_END();
6139+
6140+
zend_release_fcall_info_cache(&fci_cache);
61336141
}
61346142
/* }}} */
61356143

@@ -6167,6 +6175,7 @@ PHP_FUNCTION(array_map)
61676175
/* Short-circuit: if no callback and only one array, just return it. */
61686176
if (!ZEND_FCI_INITIALIZED(fci) || !maxlen) {
61696177
ZVAL_COPY(return_value, &arrays[0]);
6178+
zend_release_fcall_info_cache(&fci_cache);
61706179
return;
61716180
}
61726181

@@ -6192,6 +6201,8 @@ PHP_FUNCTION(array_map)
61926201
zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, &result);
61936202
}
61946203
} ZEND_HASH_FOREACH_END();
6204+
6205+
zend_release_fcall_info_cache(&fci_cache);
61956206
} else {
61966207
uint32_t *array_pos = (HashPosition *)ecalloc(n_arrays, sizeof(HashPosition));
61976208

@@ -6284,6 +6295,7 @@ PHP_FUNCTION(array_map)
62846295
}
62856296

62866297
efree(params);
6298+
zend_release_fcall_info_cache(&fci_cache);
62876299
}
62886300
efree(array_pos);
62896301
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
Bug #74345: Call trampoline leaked if callback not invoked
3+
--FILE--
4+
<?php
5+
6+
class Test {
7+
public function __call($name, $args) {
8+
echo "__call()\n";
9+
}
10+
}
11+
12+
$name = "foo" . ($x = "bar");
13+
$cb = [new Test, $name];
14+
array_map($cb, []);
15+
array_map($cb, [], []);
16+
array_filter([], $cb);
17+
array_reduce([], $cb);
18+
19+
$array = [];
20+
array_walk($array, $cb);
21+
array_walk_recursive($array, $cb);
22+
usort($array, $cb);
23+
24+
?>
25+
===DONE===
26+
--EXPECT--
27+
===DONE===

0 commit comments

Comments
 (0)