Skip to content

Commit 8d49a83

Browse files
committed
Introduce zend_lookup_function()
1 parent 6c532df commit 8d49a83

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
@@ -3578,32 +3578,11 @@ static zend_always_inline bool zend_is_callable_check_func(zval *callable, zend_
35783578
int call_via_handler = 0;
35793579
zend_class_entry *scope;
35803580
zval *zv;
3581-
ALLOCA_FLAG(use_heap)
35823581

35833582
fcc->calling_scope = NULL;
35843583

35853584
if (!ce_org) {
3586-
zend_function *func;
3587-
zend_string *lmname;
3588-
3589-
/* Check if function with given name exists.
3590-
* This may be a compound name that includes namespace name */
3591-
if (UNEXPECTED(Z_STRVAL_P(callable)[0] == '\\')) {
3592-
/* Skip leading \ */
3593-
ZSTR_ALLOCA_ALLOC(lmname, Z_STRLEN_P(callable) - 1, use_heap);
3594-
zend_str_tolower_copy(ZSTR_VAL(lmname), Z_STRVAL_P(callable) + 1, Z_STRLEN_P(callable) - 1);
3595-
func = zend_fetch_function(lmname);
3596-
ZSTR_ALLOCA_FREE(lmname, use_heap);
3597-
} else {
3598-
lmname = Z_STR_P(callable);
3599-
func = zend_fetch_function(lmname);
3600-
if (!func) {
3601-
ZSTR_ALLOCA_ALLOC(lmname, Z_STRLEN_P(callable), use_heap);
3602-
zend_str_tolower_copy(ZSTR_VAL(lmname), Z_STRVAL_P(callable), Z_STRLEN_P(callable));
3603-
func = zend_fetch_function(lmname);
3604-
ZSTR_ALLOCA_FREE(lmname, use_heap);
3605-
}
3606-
}
3585+
zend_function *func = zend_fetch_function(Z_STR_P(callable));
36073586
if (EXPECTED(func != NULL)) {
36083587
fcc->function_handler = func;
36093588
return 1;

Zend/zend_execute.c

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

40024002
ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function(zend_string *name) /* {{{ */
40034003
{
4004-
zval *zv = zend_hash_find(EG(function_table), name);
4004+
zend_function *fbc = zend_lookup_function(name);
40054005

4006-
if (EXPECTED(zv != NULL)) {
4007-
zend_function *fbc = Z_FUNC_P(zv);
4006+
if (UNEXPECTED(fbc == NULL)) {
4007+
return NULL;
4008+
}
40084009

4009-
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
4010-
init_func_run_time_cache_i(&fbc->op_array);
4011-
}
4012-
return fbc;
4010+
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
4011+
init_func_run_time_cache_i(&fbc->op_array);
40134012
}
4014-
return NULL;
4013+
return fbc;
40154014
} /* }}} */
40164015

4016+
// TODO Update or drop as this indicates a zend_call_method() without an object...
40174017
ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function_str(const char *name, size_t len) /* {{{ */
40184018
{
40194019
zval *zv = zend_hash_str_find(EG(function_table), name, len);
@@ -4600,7 +4600,6 @@ static void zend_swap_operands(zend_op *op) /* {{{ */
46004600
static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_string *function, uint32_t num_args) /* {{{ */
46014601
{
46024602
zend_function *fbc;
4603-
zval *func;
46044603
zend_class_entry *called_scope;
46054604
zend_string *lcname;
46064605
const char *colon;
@@ -4652,20 +4651,11 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_s
46524651
init_func_run_time_cache(&fbc->op_array);
46534652
}
46544653
} else {
4655-
if (ZSTR_VAL(function)[0] == '\\') {
4656-
lcname = zend_string_alloc(ZSTR_LEN(function) - 1, 0);
4657-
zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(function) + 1, ZSTR_LEN(function) - 1);
4658-
} else {
4659-
lcname = zend_string_tolower(function);
4660-
}
4661-
if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) {
4654+
if (UNEXPECTED((fbc = zend_lookup_function(function)) == NULL)) {
46624655
zend_throw_error(NULL, "Call to undefined function %s()", ZSTR_VAL(function));
4663-
zend_string_release_ex(lcname, 0);
46644656
return NULL;
46654657
}
4666-
zend_string_release_ex(lcname, 0);
46674658

4668-
fbc = Z_FUNC_P(func);
46694659
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
46704660
init_func_run_time_cache(&fbc->op_array);
46714661
}

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
@@ -1100,6 +1100,49 @@ static const uint32_t valid_chars[8] = {
11001100
0xffffffff,
11011101
};
11021102

1103+
ZEND_API zend_function *zend_lookup_function_ex(zend_string *name, zend_string *lc_key, bool use_autoload)
1104+
{
1105+
zend_function *fbc = NULL;
1106+
zval *func;
1107+
zend_string *lc_name;
1108+
zend_string *autoload_name;
1109+
1110+
if (lc_key) {
1111+
lc_name = lc_key;
1112+
} else {
1113+
if (name == NULL || !ZSTR_LEN(name)) {
1114+
return NULL;
1115+
}
1116+
1117+
if (ZSTR_VAL(name)[0] == '\\') {
1118+
lc_name = zend_string_alloc(ZSTR_LEN(name) - 1, 0);
1119+
zend_str_tolower_copy(ZSTR_VAL(lc_name), ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1);
1120+
} else {
1121+
lc_name = zend_string_tolower(name);
1122+
}
1123+
}
1124+
1125+
func = zend_hash_find(EG(function_table), lc_name);
1126+
1127+
if (EXPECTED(func)) {
1128+
if (!lc_key) {
1129+
zend_string_release_ex(lc_name, 0);
1130+
}
1131+
fbc = Z_FUNC_P(func);
1132+
return fbc;
1133+
}
1134+
1135+
if (!lc_key) {
1136+
zend_string_release_ex(lc_name, 0);
1137+
}
1138+
return NULL;
1139+
}
1140+
1141+
ZEND_API zend_function *zend_lookup_function(zend_string *name) /* {{{ */
1142+
{
1143+
return zend_lookup_function_ex(name, NULL, 0);
1144+
}
1145+
11031146
ZEND_API bool zend_is_valid_class_name(zend_string *name) {
11041147
for (size_t i = 0; i < ZSTR_LEN(name); i++) {
11051148
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
@@ -3751,17 +3751,16 @@ ZEND_VM_HOT_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT)
37513751
{
37523752
USE_OPLINE
37533753
zend_function *fbc;
3754-
zval *function_name, *func;
37553754
zend_execute_data *call;
37563755

37573756
fbc = CACHED_PTR(opline->result.num);
37583757
if (UNEXPECTED(fbc == NULL)) {
3759-
function_name = (zval*)RT_CONSTANT(opline, opline->op2);
3760-
func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(function_name+1));
3761-
if (UNEXPECTED(func == NULL)) {
3758+
zval *function_name = (zval*)RT_CONSTANT(opline, opline->op2);
3759+
/* Fetch lowercase name stored in the next literal slot */
3760+
fbc = zend_lookup_function_ex(Z_STR_P(function_name), Z_STR_P(function_name+1), /* use_autoload */ true);
3761+
if (UNEXPECTED(fbc == NULL)) {
37623762
ZEND_VM_DISPATCH_TO_HELPER(zend_undefined_function_helper);
37633763
}
3764-
fbc = Z_FUNC_P(func);
37653764
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
37663765
init_func_run_time_cache(&fbc->op_array);
37673766
}
@@ -3893,22 +3892,21 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
38933892
ZEND_VM_HOT_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT)
38943893
{
38953894
USE_OPLINE
3896-
zval *func_name;
3897-
zval *func;
38983895
zend_function *fbc;
38993896
zend_execute_data *call;
39003897

39013898
fbc = CACHED_PTR(opline->result.num);
39023899
if (UNEXPECTED(fbc == NULL)) {
3903-
func_name = (zval *)RT_CONSTANT(opline, opline->op2);
3904-
func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(func_name + 1));
3905-
if (func == NULL) {
3906-
func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(func_name + 2));
3907-
if (UNEXPECTED(func == NULL)) {
3900+
zval *function_name = (zval *)RT_CONSTANT(opline, opline->op2);
3901+
/* Fetch lowercase name stored in the next literal slot */
3902+
fbc = zend_lookup_function_ex(Z_STR_P(function_name), Z_STR_P(function_name+1), /* use_autoload */ true);
3903+
if (UNEXPECTED(fbc == NULL)) {
3904+
/* Fallback onto global namespace, by fetching the unqualified lowercase name stored in the second literal slot */
3905+
fbc = zend_lookup_function_ex(Z_STR_P(function_name+2), Z_STR_P(function_name+2), /* use_autoload */ true);
3906+
if (fbc == NULL) {
39083907
ZEND_VM_DISPATCH_TO_HELPER(zend_undefined_function_helper);
39093908
}
39103909
}
3911-
fbc = Z_FUNC_P(func);
39123910
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
39133911
init_func_run_time_cache(&fbc->op_array);
39143912
}
@@ -3926,15 +3924,13 @@ ZEND_VM_HOT_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT)
39263924
ZEND_VM_HOT_HANDLER(61, ZEND_INIT_FCALL, NUM, CONST, NUM|CACHE_SLOT)
39273925
{
39283926
USE_OPLINE
3929-
zval *fname;
3930-
zval *func;
39313927
zend_function *fbc;
39323928
zend_execute_data *call;
39333929

39343930
fbc = CACHED_PTR(opline->result.num);
39353931
if (UNEXPECTED(fbc == NULL)) {
3936-
fname = (zval*)RT_CONSTANT(opline, opline->op2);
3937-
func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(fname));
3932+
zval *fname = (zval*)RT_CONSTANT(opline, opline->op2);
3933+
zval *func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(fname));
39383934
ZEND_ASSERT(func != NULL && "Function existence must be checked at compile time");
39393935
fbc = Z_FUNC_P(func);
39403936
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)