Skip to content

Commit 51493d4

Browse files
committed
Introduce zend_lookup_function()
1 parent a1b1a6c commit 51493d4

File tree

6 files changed

+81
-75
lines changed

6 files changed

+81
-75
lines changed

Zend/zend_API.c

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3842,32 +3842,11 @@ static zend_always_inline bool zend_is_callable_check_func(zval *callable, zend_
38423842
int call_via_handler = 0;
38433843
zend_class_entry *scope;
38443844
zval *zv;
3845-
ALLOCA_FLAG(use_heap)
38463845

38473846
fcc->calling_scope = NULL;
38483847

38493848
if (!ce_org) {
3850-
zend_function *func;
3851-
zend_string *lmname;
3852-
3853-
/* Check if function with given name exists.
3854-
* This may be a compound name that includes namespace name */
3855-
if (UNEXPECTED(Z_STRVAL_P(callable)[0] == '\\')) {
3856-
/* Skip leading \ */
3857-
ZSTR_ALLOCA_ALLOC(lmname, Z_STRLEN_P(callable) - 1, use_heap);
3858-
zend_str_tolower_copy(ZSTR_VAL(lmname), Z_STRVAL_P(callable) + 1, Z_STRLEN_P(callable) - 1);
3859-
func = zend_fetch_function(lmname);
3860-
ZSTR_ALLOCA_FREE(lmname, use_heap);
3861-
} else {
3862-
lmname = Z_STR_P(callable);
3863-
func = zend_fetch_function(lmname);
3864-
if (!func) {
3865-
ZSTR_ALLOCA_ALLOC(lmname, Z_STRLEN_P(callable), use_heap);
3866-
zend_str_tolower_copy(ZSTR_VAL(lmname), Z_STRVAL_P(callable), Z_STRLEN_P(callable));
3867-
func = zend_fetch_function(lmname);
3868-
ZSTR_ALLOCA_FREE(lmname, use_heap);
3869-
}
3870-
}
3849+
zend_function *func = zend_fetch_function(Z_STR_P(callable));
38713850
if (EXPECTED(func != NULL)) {
38723851
fcc->function_handler = func;
38733852
return 1;

Zend/zend_execute.c

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4211,19 +4211,19 @@ static zend_never_inline void ZEND_FASTCALL init_func_run_time_cache(zend_op_arr
42114211

42124212
ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function(zend_string *name) /* {{{ */
42134213
{
4214-
zval *zv = zend_hash_find(EG(function_table), name);
4214+
zend_function *fbc = zend_lookup_function(name);
42154215

4216-
if (EXPECTED(zv != NULL)) {
4217-
zend_function *fbc = Z_FUNC_P(zv);
4216+
if (UNEXPECTED(fbc == NULL)) {
4217+
return NULL;
4218+
}
42184219

4219-
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
4220-
init_func_run_time_cache_i(&fbc->op_array);
4221-
}
4222-
return fbc;
4220+
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
4221+
init_func_run_time_cache_i(&fbc->op_array);
42234222
}
4224-
return NULL;
4223+
return fbc;
42254224
} /* }}} */
42264225

4226+
// TODO Update or drop as this indicates a zend_call_method() without an object...
42274227
ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function_str(const char *name, size_t len) /* {{{ */
42284228
{
42294229
zval *zv = zend_hash_str_find(EG(function_table), name, len);
@@ -4814,7 +4814,6 @@ static void zend_swap_operands(zend_op *op) /* {{{ */
48144814
static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_string *function, uint32_t num_args) /* {{{ */
48154815
{
48164816
zend_function *fbc;
4817-
zval *func;
48184817
zend_class_entry *called_scope;
48194818
zend_string *lcname;
48204819
const char *colon;
@@ -4866,20 +4865,11 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_s
48664865
init_func_run_time_cache(&fbc->op_array);
48674866
}
48684867
} else {
4869-
if (ZSTR_VAL(function)[0] == '\\') {
4870-
lcname = zend_string_alloc(ZSTR_LEN(function) - 1, 0);
4871-
zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(function) + 1, ZSTR_LEN(function) - 1);
4872-
} else {
4873-
lcname = zend_string_tolower(function);
4874-
}
4875-
if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) {
4868+
if (UNEXPECTED((fbc = zend_lookup_function(function)) == NULL)) {
48764869
zend_throw_error(NULL, "Call to undefined function %s()", ZSTR_VAL(function));
4877-
zend_string_release_ex(lcname, 0);
48784870
return NULL;
48794871
}
4880-
zend_string_release_ex(lcname, 0);
48814872

4882-
fbc = Z_FUNC_P(func);
48834873
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
48844874
init_func_run_time_cache(&fbc->op_array);
48854875
}

Zend/zend_execute.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ ZEND_API void zend_execute(zend_op_array *op_array, zval *return_value);
4848
ZEND_API void execute_ex(zend_execute_data *execute_data);
4949
ZEND_API void execute_internal(zend_execute_data *execute_data, zval *return_value);
5050
ZEND_API bool zend_is_valid_class_name(zend_string *name);
51+
ZEND_API zend_function *zend_lookup_function(zend_string *name);
52+
ZEND_API zend_function *zend_lookup_function_ex(zend_string *name, zend_string *lcname, bool use_autoload);
5153
ZEND_API zend_class_entry *zend_lookup_class(zend_string *name);
5254
ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *lcname, uint32_t flags);
5355
ZEND_API zend_class_entry *zend_get_called_scope(zend_execute_data *ex);

Zend/zend_execute_API.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,6 +1142,49 @@ static const uint32_t valid_chars[8] = {
11421142
0xffffffff,
11431143
};
11441144

1145+
ZEND_API zend_function *zend_lookup_function_ex(zend_string *name, zend_string *lc_key, bool use_autoload)
1146+
{
1147+
zend_function *fbc = NULL;
1148+
zval *func;
1149+
zend_string *lc_name;
1150+
zend_string *autoload_name;
1151+
1152+
if (lc_key) {
1153+
lc_name = lc_key;
1154+
} else {
1155+
if (name == NULL || !ZSTR_LEN(name)) {
1156+
return NULL;
1157+
}
1158+
1159+
if (ZSTR_VAL(name)[0] == '\\') {
1160+
lc_name = zend_string_alloc(ZSTR_LEN(name) - 1, 0);
1161+
zend_str_tolower_copy(ZSTR_VAL(lc_name), ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1);
1162+
} else {
1163+
lc_name = zend_string_tolower(name);
1164+
}
1165+
}
1166+
1167+
func = zend_hash_find(EG(function_table), lc_name);
1168+
1169+
if (EXPECTED(func)) {
1170+
if (!lc_key) {
1171+
zend_string_release_ex(lc_name, 0);
1172+
}
1173+
fbc = Z_FUNC_P(func);
1174+
return fbc;
1175+
}
1176+
1177+
if (!lc_key) {
1178+
zend_string_release_ex(lc_name, 0);
1179+
}
1180+
return NULL;
1181+
}
1182+
1183+
ZEND_API zend_function *zend_lookup_function(zend_string *name) /* {{{ */
1184+
{
1185+
return zend_lookup_function_ex(name, NULL, 0);
1186+
}
1187+
11451188
ZEND_API bool zend_is_valid_class_name(zend_string *name) {
11461189
for (size_t i = 0; i < ZSTR_LEN(name); i++) {
11471190
unsigned char c = ZSTR_VAL(name)[i];

Zend/zend_vm_def.h

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3818,17 +3818,16 @@ ZEND_VM_HOT_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT)
38183818
{
38193819
USE_OPLINE
38203820
zend_function *fbc;
3821-
zval *function_name, *func;
38223821
zend_execute_data *call;
38233822

38243823
fbc = CACHED_PTR(opline->result.num);
38253824
if (UNEXPECTED(fbc == NULL)) {
3826-
function_name = (zval*)RT_CONSTANT(opline, opline->op2);
3827-
func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(function_name+1));
3828-
if (UNEXPECTED(func == NULL)) {
3825+
zval *function_name = (zval*)RT_CONSTANT(opline, opline->op2);
3826+
/* Fetch lowercase name stored in the next literal slot */
3827+
fbc = zend_lookup_function_ex(Z_STR_P(function_name), Z_STR_P(function_name+1), /* use_autoload */ true);
3828+
if (UNEXPECTED(fbc == NULL)) {
38293829
ZEND_VM_DISPATCH_TO_HELPER(zend_undefined_function_helper);
38303830
}
3831-
fbc = Z_FUNC_P(func);
38323831
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
38333832
init_func_run_time_cache(&fbc->op_array);
38343833
}
@@ -3960,22 +3959,21 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
39603959
ZEND_VM_HOT_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT)
39613960
{
39623961
USE_OPLINE
3963-
zval *func_name;
3964-
zval *func;
39653962
zend_function *fbc;
39663963
zend_execute_data *call;
39673964

39683965
fbc = CACHED_PTR(opline->result.num);
39693966
if (UNEXPECTED(fbc == NULL)) {
3970-
func_name = (zval *)RT_CONSTANT(opline, opline->op2);
3971-
func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(func_name + 1));
3972-
if (func == NULL) {
3973-
func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(func_name + 2));
3974-
if (UNEXPECTED(func == NULL)) {
3967+
zval *function_name = (zval *)RT_CONSTANT(opline, opline->op2);
3968+
/* Fetch lowercase name stored in the next literal slot */
3969+
fbc = zend_lookup_function_ex(Z_STR_P(function_name), Z_STR_P(function_name+1), /* use_autoload */ true);
3970+
if (UNEXPECTED(fbc == NULL)) {
3971+
/* Fallback onto global namespace, by fetching the unqualified lowercase name stored in the second literal slot */
3972+
fbc = zend_lookup_function_ex(Z_STR_P(function_name+2), Z_STR_P(function_name+2), /* use_autoload */ true);
3973+
if (fbc == NULL) {
39753974
ZEND_VM_DISPATCH_TO_HELPER(zend_undefined_function_helper);
39763975
}
39773976
}
3978-
fbc = Z_FUNC_P(func);
39793977
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
39803978
init_func_run_time_cache(&fbc->op_array);
39813979
}
@@ -3993,15 +3991,13 @@ ZEND_VM_HOT_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT)
39933991
ZEND_VM_HOT_HANDLER(61, ZEND_INIT_FCALL, NUM, CONST, NUM|CACHE_SLOT)
39943992
{
39953993
USE_OPLINE
3996-
zval *fname;
3997-
zval *func;
39983994
zend_function *fbc;
39993995
zend_execute_data *call;
40003996

40013997
fbc = CACHED_PTR(opline->result.num);
40023998
if (UNEXPECTED(fbc == NULL)) {
4003-
fname = (zval*)RT_CONSTANT(opline, opline->op2);
4004-
func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(fname));
3999+
zval *fname = (zval*)RT_CONSTANT(opline, opline->op2);
4000+
zval *func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(fname));
40054001
ZEND_ASSERT(func != NULL && "Function existence must be checked at compile time");
40064002
fbc = Z_FUNC_P(func);
40074003
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {

Zend/zend_vm_execute.h

Lines changed: 13 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)