Skip to content

Commit 58408d4

Browse files
committed
Introduce zend_lookup_function()
1 parent 4ae1f08 commit 58408d4

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
@@ -3548,32 +3548,11 @@ static zend_always_inline bool zend_is_callable_check_func(zval *callable, zend_
35483548
int call_via_handler = 0;
35493549
zend_class_entry *scope;
35503550
zval *zv;
3551-
ALLOCA_FLAG(use_heap)
35523551

35533552
fcc->calling_scope = NULL;
35543553

35553554
if (!ce_org) {
3556-
zend_function *func;
3557-
zend_string *lmname;
3558-
3559-
/* Check if function with given name exists.
3560-
* This may be a compound name that includes namespace name */
3561-
if (UNEXPECTED(Z_STRVAL_P(callable)[0] == '\\')) {
3562-
/* Skip leading \ */
3563-
ZSTR_ALLOCA_ALLOC(lmname, Z_STRLEN_P(callable) - 1, use_heap);
3564-
zend_str_tolower_copy(ZSTR_VAL(lmname), Z_STRVAL_P(callable) + 1, Z_STRLEN_P(callable) - 1);
3565-
func = zend_fetch_function(lmname);
3566-
ZSTR_ALLOCA_FREE(lmname, use_heap);
3567-
} else {
3568-
lmname = Z_STR_P(callable);
3569-
func = zend_fetch_function(lmname);
3570-
if (!func) {
3571-
ZSTR_ALLOCA_ALLOC(lmname, Z_STRLEN_P(callable), use_heap);
3572-
zend_str_tolower_copy(ZSTR_VAL(lmname), Z_STRVAL_P(callable), Z_STRLEN_P(callable));
3573-
func = zend_fetch_function(lmname);
3574-
ZSTR_ALLOCA_FREE(lmname, use_heap);
3575-
}
3576-
}
3555+
zend_function *func = zend_fetch_function(Z_STR_P(callable));
35773556
if (EXPECTED(func != NULL)) {
35783557
fcc->function_handler = func;
35793558
return 1;

Zend/zend_execute.c

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

39513951
ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function(zend_string *name) /* {{{ */
39523952
{
3953-
zval *zv = zend_hash_find(EG(function_table), name);
3953+
zend_function *fbc = zend_lookup_function(name);
39543954

3955-
if (EXPECTED(zv != NULL)) {
3956-
zend_function *fbc = Z_FUNC_P(zv);
3955+
if (UNEXPECTED(fbc == NULL)) {
3956+
return NULL;
3957+
}
39573958

3958-
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
3959-
init_func_run_time_cache_i(&fbc->op_array);
3960-
}
3961-
return fbc;
3959+
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
3960+
init_func_run_time_cache_i(&fbc->op_array);
39623961
}
3963-
return NULL;
3962+
return fbc;
39643963
} /* }}} */
39653964

3965+
// TODO Update or drop as this indicates a zend_call_method() without an object...
39663966
ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function_str(const char *name, size_t len) /* {{{ */
39673967
{
39683968
zval *zv = zend_hash_str_find(EG(function_table), name, len);
@@ -4460,7 +4460,6 @@ static void zend_swap_operands(zend_op *op) /* {{{ */
44604460
static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_string *function, uint32_t num_args) /* {{{ */
44614461
{
44624462
zend_function *fbc;
4463-
zval *func;
44644463
zend_class_entry *called_scope;
44654464
zend_string *lcname;
44664465
const char *colon;
@@ -4512,20 +4511,11 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_s
45124511
init_func_run_time_cache(&fbc->op_array);
45134512
}
45144513
} else {
4515-
if (ZSTR_VAL(function)[0] == '\\') {
4516-
lcname = zend_string_alloc(ZSTR_LEN(function) - 1, 0);
4517-
zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(function) + 1, ZSTR_LEN(function) - 1);
4518-
} else {
4519-
lcname = zend_string_tolower(function);
4520-
}
4521-
if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) {
4514+
if (UNEXPECTED((fbc = zend_lookup_function(function)) == NULL)) {
45224515
zend_throw_error(NULL, "Call to undefined function %s()", ZSTR_VAL(function));
4523-
zend_string_release_ex(lcname, 0);
45244516
return NULL;
45254517
}
4526-
zend_string_release_ex(lcname, 0);
45274518

4528-
fbc = Z_FUNC_P(func);
45294519
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
45304520
init_func_run_time_cache(&fbc->op_array);
45314521
}

Zend/zend_execute.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ ZEND_API void zend_execute(zend_op_array *op_array, zval *return_value);
4646
ZEND_API void execute_ex(zend_execute_data *execute_data);
4747
ZEND_API void execute_internal(zend_execute_data *execute_data, zval *return_value);
4848
ZEND_API bool zend_is_valid_class_name(zend_string *name);
49+
ZEND_API zend_function *zend_lookup_function(zend_string *name);
50+
ZEND_API zend_function *zend_lookup_function_ex(zend_string *name, zend_string *lcname, bool use_autoload);
4951
ZEND_API zend_class_entry *zend_lookup_class(zend_string *name);
5052
ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *lcname, uint32_t flags);
5153
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
@@ -1085,6 +1085,64 @@ static const uint32_t valid_chars[8] = {
10851085
0xffffffff,
10861086
};
10871087

1088+
ZEND_API zend_function *zend_lookup_function_ex(zend_string *name, zend_string *lc_key, bool use_autoload)
1089+
{
1090+
zend_function *fbc = NULL;
1091+
zval *func;
1092+
zend_string *lc_name;
1093+
zend_string *autoload_name;
1094+
1095+
if (lc_key) {
1096+
lc_name = lc_key;
1097+
} else {
1098+
if (name == NULL || !ZSTR_LEN(name)) {
1099+
return NULL;
1100+
}
1101+
1102+
if (ZSTR_VAL(name)[0] == '\\') {
1103+
lc_name = zend_string_alloc(ZSTR_LEN(name) - 1, 0);
1104+
zend_str_tolower_copy(ZSTR_VAL(lc_name), ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1);
1105+
} else {
1106+
lc_name = zend_string_tolower(name);
1107+
}
1108+
}
1109+
1110+
func = zend_hash_find(EG(function_table), lc_name);
1111+
1112+
if (EXPECTED(func)) {
1113+
if (!lc_key) {
1114+
zend_string_release_ex(lc_name, 0);
1115+
}
1116+
fbc = Z_FUNC_P(func);
1117+
return fbc;
1118+
}
1119+
1120+
/* The compiler is not-reentrant. Make sure we autoload only during run-time. */
1121+
if (!use_autoload || zend_is_compiling()) {
1122+
if (!lc_key) {
1123+
zend_string_release_ex(lc_name, 0);
1124+
}
1125+
return NULL;
1126+
}
1127+
1128+
if (!zend_autoload) {
1129+
if (!lc_key) {
1130+
zend_string_release_ex(lc_name, 0);
1131+
}
1132+
return NULL;
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+
10881146
ZEND_API bool zend_is_valid_class_name(zend_string *name) {
10891147
for (size_t i = 0; i < ZSTR_LEN(name); i++) {
10901148
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
@@ -3706,17 +3706,16 @@ ZEND_VM_HOT_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT)
37063706
{
37073707
USE_OPLINE
37083708
zend_function *fbc;
3709-
zval *function_name, *func;
37103709
zend_execute_data *call;
37113710

37123711
fbc = CACHED_PTR(opline->result.num);
37133712
if (UNEXPECTED(fbc == NULL)) {
3714-
function_name = (zval*)RT_CONSTANT(opline, opline->op2);
3715-
func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(function_name+1));
3716-
if (UNEXPECTED(func == NULL)) {
3713+
zval *function_name = (zval*)RT_CONSTANT(opline, opline->op2);
3714+
/* Fetch lowercase name stored in the next literal slot */
3715+
fbc = zend_lookup_function_ex(Z_STR_P(function_name), Z_STR_P(function_name+1), /* use_autoload */ true);
3716+
if (UNEXPECTED(fbc == NULL)) {
37173717
ZEND_VM_DISPATCH_TO_HELPER(zend_undefined_function_helper);
37183718
}
3719-
fbc = Z_FUNC_P(func);
37203719
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
37213720
init_func_run_time_cache(&fbc->op_array);
37223721
}
@@ -3848,22 +3847,21 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
38483847
ZEND_VM_HOT_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT)
38493848
{
38503849
USE_OPLINE
3851-
zval *func_name;
3852-
zval *func;
38533850
zend_function *fbc;
38543851
zend_execute_data *call;
38553852

38563853
fbc = CACHED_PTR(opline->result.num);
38573854
if (UNEXPECTED(fbc == NULL)) {
3858-
func_name = (zval *)RT_CONSTANT(opline, opline->op2);
3859-
func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(func_name + 1));
3860-
if (func == NULL) {
3861-
func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(func_name + 2));
3862-
if (UNEXPECTED(func == NULL)) {
3855+
zval *function_name = (zval *)RT_CONSTANT(opline, opline->op2);
3856+
/* Fetch lowercase name stored in the next literal slot */
3857+
fbc = zend_lookup_function_ex(Z_STR_P(function_name), Z_STR_P(function_name+1), /* use_autoload */ true);
3858+
if (UNEXPECTED(fbc == NULL)) {
3859+
/* Fallback onto global namespace, by fetching the unqualified lowercase name stored in the second literal slot */
3860+
fbc = zend_lookup_function_ex(Z_STR_P(function_name+2), Z_STR_P(function_name+2), /* use_autoload */ true);
3861+
if (fbc == NULL) {
38633862
ZEND_VM_DISPATCH_TO_HELPER(zend_undefined_function_helper);
38643863
}
38653864
}
3866-
fbc = Z_FUNC_P(func);
38673865
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
38683866
init_func_run_time_cache(&fbc->op_array);
38693867
}
@@ -3881,15 +3879,13 @@ ZEND_VM_HOT_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT)
38813879
ZEND_VM_HOT_HANDLER(61, ZEND_INIT_FCALL, NUM, CONST, NUM|CACHE_SLOT)
38823880
{
38833881
USE_OPLINE
3884-
zval *fname;
3885-
zval *func;
38863882
zend_function *fbc;
38873883
zend_execute_data *call;
38883884

38893885
fbc = CACHED_PTR(opline->result.num);
38903886
if (UNEXPECTED(fbc == NULL)) {
3891-
fname = (zval*)RT_CONSTANT(opline, opline->op2);
3892-
func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(fname));
3887+
zval *fname = (zval*)RT_CONSTANT(opline, opline->op2);
3888+
zval *func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(fname));
38933889
ZEND_ASSERT(func != NULL && "Function existence must be checked at compile time");
38943890
fbc = Z_FUNC_P(func);
38953891
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)