Skip to content

Commit 6ecbb88

Browse files
committed
Introduce zend_lookup_function()
1 parent 2f309de commit 6ecbb88

File tree

6 files changed

+96
-75
lines changed

6 files changed

+96
-75
lines changed

Zend/zend_API.c

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3579,32 +3579,11 @@ static zend_always_inline bool zend_is_callable_check_func(zval *callable, zend_
35793579
int call_via_handler = 0;
35803580
zend_class_entry *scope;
35813581
zval *zv;
3582-
ALLOCA_FLAG(use_heap)
35833582

35843583
fcc->calling_scope = NULL;
35853584

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

Zend/zend_execute.c

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

39983998
ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function(zend_string *name) /* {{{ */
39993999
{
4000-
zval *zv = zend_hash_find(EG(function_table), name);
4000+
zend_function *fbc = zend_lookup_function(name);
40014001

4002-
if (EXPECTED(zv != NULL)) {
4003-
zend_function *fbc = Z_FUNC_P(zv);
4002+
if (UNEXPECTED(fbc == NULL)) {
4003+
return NULL;
4004+
}
40044005

4005-
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
4006-
init_func_run_time_cache_i(&fbc->op_array);
4007-
}
4008-
return fbc;
4006+
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
4007+
init_func_run_time_cache_i(&fbc->op_array);
40094008
}
4010-
return NULL;
4009+
return fbc;
40114010
} /* }}} */
40124011

4012+
// TODO Update or drop as this indicates a zend_call_method() without an object...
40134013
ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function_str(const char *name, size_t len) /* {{{ */
40144014
{
40154015
zval *zv = zend_hash_str_find(EG(function_table), name, len);
@@ -4596,7 +4596,6 @@ static void zend_swap_operands(zend_op *op) /* {{{ */
45964596
static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_string *function, uint32_t num_args) /* {{{ */
45974597
{
45984598
zend_function *fbc;
4599-
zval *func;
46004599
zend_class_entry *called_scope;
46014600
zend_string *lcname;
46024601
const char *colon;
@@ -4648,20 +4647,11 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_s
46484647
init_func_run_time_cache(&fbc->op_array);
46494648
}
46504649
} else {
4651-
if (ZSTR_VAL(function)[0] == '\\') {
4652-
lcname = zend_string_alloc(ZSTR_LEN(function) - 1, 0);
4653-
zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(function) + 1, ZSTR_LEN(function) - 1);
4654-
} else {
4655-
lcname = zend_string_tolower(function);
4656-
}
4657-
if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) {
4650+
if (UNEXPECTED((fbc = zend_lookup_function(function)) == NULL)) {
46584651
zend_throw_error(NULL, "Call to undefined function %s()", ZSTR_VAL(function));
4659-
zend_string_release_ex(lcname, 0);
46604652
return NULL;
46614653
}
4662-
zend_string_release_ex(lcname, 0);
46634654

4664-
fbc = Z_FUNC_P(func);
46654655
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
46664656
init_func_run_time_cache(&fbc->op_array);
46674657
}

Zend/zend_execute.h

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

Zend/zend_execute_API.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,64 @@ static const uint32_t valid_chars[8] = {
11031103
0xffffffff,
11041104
};
11051105

1106+
ZEND_API zend_function *zend_lookup_function_ex(zend_string *name, zend_string *lc_key, bool use_autoload)
1107+
{
1108+
zend_function *fbc = NULL;
1109+
zval *func;
1110+
zend_string *lc_name;
1111+
zend_string *autoload_name;
1112+
1113+
if (lc_key) {
1114+
lc_name = lc_key;
1115+
} else {
1116+
if (name == NULL || !ZSTR_LEN(name)) {
1117+
return NULL;
1118+
}
1119+
1120+
if (ZSTR_VAL(name)[0] == '\\') {
1121+
lc_name = zend_string_alloc(ZSTR_LEN(name) - 1, 0);
1122+
zend_str_tolower_copy(ZSTR_VAL(lc_name), ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1);
1123+
} else {
1124+
lc_name = zend_string_tolower(name);
1125+
}
1126+
}
1127+
1128+
func = zend_hash_find(EG(function_table), lc_name);
1129+
1130+
if (EXPECTED(func)) {
1131+
if (!lc_key) {
1132+
zend_string_release_ex(lc_name, 0);
1133+
}
1134+
fbc = Z_FUNC_P(func);
1135+
return fbc;
1136+
}
1137+
1138+
/* The compiler is not-reentrant. Make sure we autoload only during run-time. */
1139+
if (!use_autoload || zend_is_compiling()) {
1140+
if (!lc_key) {
1141+
zend_string_release_ex(lc_name, 0);
1142+
}
1143+
return NULL;
1144+
}
1145+
1146+
if (!zend_autoload) {
1147+
if (!lc_key) {
1148+
zend_string_release_ex(lc_name, 0);
1149+
}
1150+
return NULL;
1151+
}
1152+
1153+
if (!lc_key) {
1154+
zend_string_release_ex(lc_name, 0);
1155+
}
1156+
return NULL;
1157+
}
1158+
1159+
ZEND_API zend_function *zend_lookup_function(zend_string *name) /* {{{ */
1160+
{
1161+
return zend_lookup_function_ex(name, NULL, 0);
1162+
}
1163+
11061164
ZEND_API bool zend_is_valid_class_name(zend_string *name) {
11071165
for (size_t i = 0; i < ZSTR_LEN(name); i++) {
11081166
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
@@ -3719,17 +3719,16 @@ ZEND_VM_HOT_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT)
37193719
{
37203720
USE_OPLINE
37213721
zend_function *fbc;
3722-
zval *function_name, *func;
37233722
zend_execute_data *call;
37243723

37253724
fbc = CACHED_PTR(opline->result.num);
37263725
if (UNEXPECTED(fbc == NULL)) {
3727-
function_name = (zval*)RT_CONSTANT(opline, opline->op2);
3728-
func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(function_name+1));
3729-
if (UNEXPECTED(func == NULL)) {
3726+
zval *function_name = (zval*)RT_CONSTANT(opline, opline->op2);
3727+
/* Fetch lowercase name stored in the next literal slot */
3728+
fbc = zend_lookup_function_ex(Z_STR_P(function_name), Z_STR_P(function_name+1), /* use_autoload */ true);
3729+
if (UNEXPECTED(fbc == NULL)) {
37303730
ZEND_VM_DISPATCH_TO_HELPER(zend_undefined_function_helper);
37313731
}
3732-
fbc = Z_FUNC_P(func);
37333732
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
37343733
init_func_run_time_cache(&fbc->op_array);
37353734
}
@@ -3861,22 +3860,21 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
38613860
ZEND_VM_HOT_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT)
38623861
{
38633862
USE_OPLINE
3864-
zval *func_name;
3865-
zval *func;
38663863
zend_function *fbc;
38673864
zend_execute_data *call;
38683865

38693866
fbc = CACHED_PTR(opline->result.num);
38703867
if (UNEXPECTED(fbc == NULL)) {
3871-
func_name = (zval *)RT_CONSTANT(opline, opline->op2);
3872-
func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(func_name + 1));
3873-
if (func == NULL) {
3874-
func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(func_name + 2));
3875-
if (UNEXPECTED(func == NULL)) {
3868+
zval *function_name = (zval *)RT_CONSTANT(opline, opline->op2);
3869+
/* Fetch lowercase name stored in the next literal slot */
3870+
fbc = zend_lookup_function_ex(Z_STR_P(function_name), Z_STR_P(function_name+1), /* use_autoload */ true);
3871+
if (UNEXPECTED(fbc == NULL)) {
3872+
/* Fallback onto global namespace, by fetching the unqualified lowercase name stored in the second literal slot */
3873+
fbc = zend_lookup_function_ex(Z_STR_P(function_name+2), Z_STR_P(function_name+2), /* use_autoload */ true);
3874+
if (fbc == NULL) {
38763875
ZEND_VM_DISPATCH_TO_HELPER(zend_undefined_function_helper);
38773876
}
38783877
}
3879-
fbc = Z_FUNC_P(func);
38803878
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
38813879
init_func_run_time_cache(&fbc->op_array);
38823880
}
@@ -3894,15 +3892,13 @@ ZEND_VM_HOT_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT)
38943892
ZEND_VM_HOT_HANDLER(61, ZEND_INIT_FCALL, NUM, CONST, NUM|CACHE_SLOT)
38953893
{
38963894
USE_OPLINE
3897-
zval *fname;
3898-
zval *func;
38993895
zend_function *fbc;
39003896
zend_execute_data *call;
39013897

39023898
fbc = CACHED_PTR(opline->result.num);
39033899
if (UNEXPECTED(fbc == NULL)) {
3904-
fname = (zval*)RT_CONSTANT(opline, opline->op2);
3905-
func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(fname));
3900+
zval *fname = (zval*)RT_CONSTANT(opline, opline->op2);
3901+
zval *func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(fname));
39063902
ZEND_ASSERT(func != NULL && "Function existence must be checked at compile time");
39073903
fbc = Z_FUNC_P(func);
39083904
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)