From 896ac47a51f2c3c9db6a81e6815a68d2fc25f106 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 9 Jun 2020 17:36:36 +0200 Subject: [PATCH 1/2] Cleanup SPL autoload implementation --- Zend/tests/bug49908.phpt | 8 +- Zend/tests/generators/bug65161.phpt | 7 +- .../variance/loading_exception1.phpt | 5 +- .../variance/loading_exception2.phpt | 5 +- Zend/tests/use_unlinked_class.phpt | 5 +- Zend/zend_execute.h | 3 + Zend/zend_execute_API.c | 45 +--- Zend/zend_globals.h | 1 - ext/spl/php_spl.c | 245 +++++++----------- ext/spl/php_spl.stub.php | 5 +- ext/spl/php_spl_arginfo.h | 7 +- ext/spl/tests/spl_autoload_002.phpt | 13 +- ext/spl/tests/spl_autoload_012.phpt | 5 +- 13 files changed, 136 insertions(+), 218 deletions(-) diff --git a/Zend/tests/bug49908.phpt b/Zend/tests/bug49908.phpt index e108918b13ddb..e545a0858cab6 100644 --- a/Zend/tests/bug49908.phpt +++ b/Zend/tests/bug49908.phpt @@ -29,9 +29,7 @@ string(3) "Bar" Fatal error: Uncaught Exception: Bar in %s:%d Stack trace: -#0 [internal function]: {closure}('Bar') -#1 %s(%d): spl_autoload_call('Bar') -#2 [internal function]: {closure}('Foo') -#3 %s(%d): spl_autoload_call('Foo') -#4 {main} +#0 %s(%d): {closure}('Bar') +#1 %s(%d): {closure}('Foo') +#2 {main} thrown in %s on line %d diff --git a/Zend/tests/generators/bug65161.phpt b/Zend/tests/generators/bug65161.phpt index ea0d65a857247..63c915b885b9c 100644 --- a/Zend/tests/generators/bug65161.phpt +++ b/Zend/tests/generators/bug65161.phpt @@ -19,8 +19,7 @@ foreach (testGenerator() as $i); --EXPECTF-- Fatal error: Uncaught Error: Call to undefined function foo() in %s:%d Stack trace: -#0 [internal function]: autoload('SyntaxError') -#1 %s(%d): spl_autoload_call('SyntaxError') -#2 %s(%d): testGenerator() -#3 {main} +#0 %s(%d): autoload('SyntaxError') +#1 %s(%d): testGenerator() +#2 {main} thrown in %s on line %d diff --git a/Zend/tests/type_declarations/variance/loading_exception1.phpt b/Zend/tests/type_declarations/variance/loading_exception1.phpt index 89aeaf3c12229..b535e49112542 100644 --- a/Zend/tests/type_declarations/variance/loading_exception1.phpt +++ b/Zend/tests/type_declarations/variance/loading_exception1.phpt @@ -44,6 +44,5 @@ Class A does not exist Fatal error: During inheritance of B with variance dependencies: Uncaught Exception: Class A does not exist in %s:%d Stack trace: -#0 [internal function]: {closure}('A') -#1 %s(%d): spl_autoload_call('A') -#2 {main} in %s on line %d +#0 %s(%d): {closure}('A') +#1 {main} in %s on line %d diff --git a/Zend/tests/type_declarations/variance/loading_exception2.phpt b/Zend/tests/type_declarations/variance/loading_exception2.phpt index 2b46c183c24d0..f29264325855f 100644 --- a/Zend/tests/type_declarations/variance/loading_exception2.phpt +++ b/Zend/tests/type_declarations/variance/loading_exception2.phpt @@ -46,6 +46,5 @@ Class I does not exist Fatal error: During inheritance of B with variance dependencies: Uncaught Exception: Class I does not exist in %s:%d Stack trace: -#0 [internal function]: {closure}('I') -#1 %s(%d): spl_autoload_call('I') -#2 {main} in %s on line %d +#0 %s(%d): {closure}('I') +#1 {main} in %s on line %d diff --git a/Zend/tests/use_unlinked_class.phpt b/Zend/tests/use_unlinked_class.phpt index e85f97821fcde..46ef2afd40d98 100644 --- a/Zend/tests/use_unlinked_class.phpt +++ b/Zend/tests/use_unlinked_class.phpt @@ -15,7 +15,6 @@ class A implements I { Fatal error: Uncaught ReflectionException: Class A does not exist in %s:%d Stack trace: #0 %s(%d): ReflectionClass->__construct('A') -#1 [internal function]: {closure}('I') -#2 %s(%d): spl_autoload_call('I') -#3 {main} +#1 %s(%d): {closure}('I') +#2 {main} thrown in %s on line %d diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 58e1bbc2a9ef3..0aa959d11f57b 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -31,6 +31,9 @@ struct _zend_fcall_info; ZEND_API extern void (*zend_execute_ex)(zend_execute_data *execute_data); ZEND_API extern void (*zend_execute_internal)(zend_execute_data *execute_data, zval *return_value); +/* The lc_name may be stack allocated! */ +ZEND_API extern zend_class_entry *(*zend_autoload)(zend_string *name, zend_string *lc_name); + void init_executor(void); void shutdown_executor(void); void shutdown_destructors(void); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index b650444d1c394..117eea7d6648f 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -44,6 +44,7 @@ ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data); ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data, zval *return_value); +ZEND_API zend_class_entry *(*zend_autoload)(zend_string *name, zend_string *lc_name); /* true globals */ ZEND_API const zend_fcall_info empty_fcall_info = {0}; @@ -140,7 +141,6 @@ void init_executor(void) /* {{{ */ EG(class_table) = CG(class_table); EG(in_autoload) = NULL; - EG(autoload_func) = NULL; EG(error_handling) = EH_NORMAL; EG(flags) = EG_FLAGS_INITIAL; @@ -913,11 +913,9 @@ ZEND_API void zend_call_known_instance_method_with_2_params( ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *key, uint32_t flags) /* {{{ */ { zend_class_entry *ce = NULL; - zval args[1], *zv; - zval local_retval; + zval *zv; zend_string *lc_name; - zend_fcall_info fcall_info; - zend_fcall_info_cache fcall_cache; + zend_string *autoload_name; if (key) { lc_name = key; @@ -952,9 +950,7 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string * return ce; } - /* The compiler is not-reentrant. Make sure we __autoload() only during run-time - * (doesn't impact functionality of __autoload() - */ + /* The compiler is not-reentrant. Make sure we autoload only during run-time. */ if ((flags & ZEND_FETCH_CLASS_NO_AUTOLOAD) || zend_is_compiling()) { if (!key) { zend_string_release_ex(lc_name, 0); @@ -962,15 +958,14 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string * return NULL; } - if (!EG(autoload_func)) { + if (!zend_autoload) { if (!key) { zend_string_release_ex(lc_name, 0); } return NULL; - } - /* Verify class name before passing it to __autoload() */ + /* Verify class name before passing it to the autoloader. */ if (!key && strspn(ZSTR_VAL(name), "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377\\") != ZSTR_LEN(name)) { zend_string_release_ex(lc_name, 0); return NULL; @@ -988,39 +983,19 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string * return NULL; } - ZVAL_UNDEF(&local_retval); - if (ZSTR_VAL(name)[0] == '\\') { - ZVAL_STRINGL(&args[0], ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1); + autoload_name = zend_string_init(ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1, 0); } else { - ZVAL_STR_COPY(&args[0], name); + autoload_name = zend_string_copy(name); } - fcall_info.size = sizeof(fcall_info); - ZVAL_STR_COPY(&fcall_info.function_name, EG(autoload_func)->common.function_name); - fcall_info.retval = &local_retval; - fcall_info.param_count = 1; - fcall_info.params = args; - fcall_info.object = NULL; - fcall_info.no_separation = 1; - - fcall_cache.function_handler = EG(autoload_func); - fcall_cache.called_scope = NULL; - fcall_cache.object = NULL; - zend_exception_save(); - if ((zend_call_function(&fcall_info, &fcall_cache) == SUCCESS) && !EG(exception)) { - ce = zend_hash_find_ptr(EG(class_table), lc_name); - } + ce = zend_autoload(autoload_name, lc_name); zend_exception_restore(); - zval_ptr_dtor(&args[0]); - zval_ptr_dtor_str(&fcall_info.function_name); - + zend_string_release_ex(autoload_name, 0); zend_hash_del(EG(in_autoload), lc_name); - zval_ptr_dtor(&local_retval); - if (!key) { zend_string_release_ex(lc_name, 0); } diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 049800a32d414..a91833cd85010 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -176,7 +176,6 @@ struct _zend_executor_globals { uint32_t persistent_classes_count; HashTable *in_autoload; - zend_function *autoload_func; zend_bool full_tables_cleanup; /* for extended information support */ diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index 324dbe4b7213e..3a0072556b9fd 100644 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -47,16 +47,13 @@ ZEND_DECLARE_MODULE_GLOBALS(spl) #define SPL_DEFAULT_FILE_EXTENSIONS ".inc,.php" -static zend_function *spl_autoload_fn = NULL; -static zend_function *spl_autoload_call_fn = NULL; - /* {{{ PHP_GINIT_FUNCTION */ static PHP_GINIT_FUNCTION(spl) { - spl_globals->autoload_extensions = NULL; - spl_globals->autoload_functions = NULL; - spl_globals->autoload_running = 0; + spl_globals->autoload_extensions = NULL; + spl_globals->autoload_functions = NULL; + spl_globals->autoload_running = 0; } /* }}} */ @@ -394,104 +391,92 @@ static void autoload_func_info_dtor(zval *element) efree(alfi); } -/* {{{ proto void spl_autoload_call(string class_name) - Try all registered autoload function to load the requested class */ -PHP_FUNCTION(spl_autoload_call) -{ - zend_string *class_name, *lc_name, *func_name; - autoload_func_info *alfi; - zval retval, params[1]; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &class_name) == FAILURE) { - RETURN_THROWS(); +static zend_class_entry *spl_perform_autoload(zend_string *class_name, zend_string *lc_name) { + if (!SPL_G(autoload_functions)) { + return NULL; } + HashPosition pos; + zend_ulong num_idx; + zend_function *func; + zend_fcall_info fci; + zend_fcall_info_cache fcic; + zval params[1]; + zval retval; + zend_string *func_name; + zend_class_entry *called_scope = zend_get_called_scope(EG(current_execute_data)); + int l_autoload_running = SPL_G(autoload_running); + + SPL_G(autoload_running) = 1; + + fci.size = sizeof(fci); + fci.retval = &retval; + fci.param_count = 1; + fci.params = params; + fci.no_separation = 1; ZVAL_STR(¶ms[0], class_name); - if (SPL_G(autoload_functions)) { - HashPosition pos; - zend_ulong num_idx; - zend_function *func; - zend_fcall_info fci; - zend_fcall_info_cache fcic; - zend_class_entry *called_scope = zend_get_called_scope(execute_data); - int l_autoload_running = SPL_G(autoload_running); - - SPL_G(autoload_running) = 1; - lc_name = zend_string_tolower(class_name); - - fci.size = sizeof(fci); - fci.retval = &retval; - fci.param_count = 1; - fci.params = params; - fci.no_separation = 1; - - ZVAL_UNDEF(&fci.function_name); /* Unused */ - - zend_hash_internal_pointer_reset_ex(SPL_G(autoload_functions), &pos); - while (zend_hash_get_current_key_ex(SPL_G(autoload_functions), &func_name, &num_idx, &pos) == HASH_KEY_IS_STRING) { - alfi = zend_hash_get_current_data_ptr_ex(SPL_G(autoload_functions), &pos); - func = alfi->func_ptr; - if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { - func = emalloc(sizeof(zend_op_array)); - memcpy(func, alfi->func_ptr, sizeof(zend_op_array)); - zend_string_addref(func->op_array.function_name); - } - ZVAL_UNDEF(&retval); - fcic.function_handler = func; - if (Z_ISUNDEF(alfi->obj)) { - fci.object = NULL; - fcic.object = NULL; - if (alfi->ce && - (!called_scope || - !instanceof_function(called_scope, alfi->ce))) { - fcic.called_scope = alfi->ce; - } else { - fcic.called_scope = called_scope; - } + ZVAL_UNDEF(&fci.function_name); /* Unused */ + + zend_hash_internal_pointer_reset_ex(SPL_G(autoload_functions), &pos); + while (zend_hash_get_current_key_ex(SPL_G(autoload_functions), &func_name, &num_idx, &pos) == HASH_KEY_IS_STRING) { + autoload_func_info *alfi = + zend_hash_get_current_data_ptr_ex(SPL_G(autoload_functions), &pos); + func = alfi->func_ptr; + if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + func = emalloc(sizeof(zend_op_array)); + memcpy(func, alfi->func_ptr, sizeof(zend_op_array)); + zend_string_addref(func->op_array.function_name); + } + ZVAL_UNDEF(&retval); + fcic.function_handler = func; + if (Z_ISUNDEF(alfi->obj)) { + fci.object = NULL; + fcic.object = NULL; + if (alfi->ce && + (!called_scope || + !instanceof_function(called_scope, alfi->ce))) { + fcic.called_scope = alfi->ce; } else { - fci.object = Z_OBJ(alfi->obj); - fcic.object = Z_OBJ(alfi->obj); - fcic.called_scope = Z_OBJCE(alfi->obj); + fcic.called_scope = called_scope; } + } else { + fci.object = Z_OBJ(alfi->obj); + fcic.object = Z_OBJ(alfi->obj); + fcic.called_scope = Z_OBJCE(alfi->obj); + } - zend_call_function(&fci, &fcic); - zval_ptr_dtor(&retval); - - if (EG(exception)) { - break; - } + zend_call_function(&fci, &fcic); + zval_ptr_dtor(&retval); - if (pos + 1 == SPL_G(autoload_functions)->nNumUsed || - zend_hash_exists(EG(class_table), lc_name)) { - break; - } - zend_hash_move_forward_ex(SPL_G(autoload_functions), &pos); + if (EG(exception)) { + break; } - zend_string_release_ex(lc_name, 0); - SPL_G(autoload_running) = l_autoload_running; - } else { - /* do not use or overwrite &EG(autoload_func) here */ - zend_fcall_info fcall_info; - zend_fcall_info_cache fcall_cache; - ZVAL_UNDEF(&retval); + zend_class_entry *ce = zend_hash_find_ptr(EG(class_table), lc_name); + if (ce) { + return ce; + } - fcall_info.size = sizeof(fcall_info); - ZVAL_UNDEF(&fcall_info.function_name); - fcall_info.retval = &retval; - fcall_info.param_count = 1; - fcall_info.params = params; - fcall_info.object = NULL; - fcall_info.no_separation = 1; + zend_hash_move_forward_ex(SPL_G(autoload_functions), &pos); + } + SPL_G(autoload_running) = l_autoload_running; + return NULL; +} - fcall_cache.function_handler = spl_autoload_fn; - fcall_cache.called_scope = NULL; - fcall_cache.object = NULL; +/* {{{ proto void spl_autoload_call(string class_name) + Try all registered autoload function to load the requested class */ +PHP_FUNCTION(spl_autoload_call) +{ + zend_string *class_name; - zend_call_function(&fcall_info, &fcall_cache); - zval_ptr_dtor(&retval); + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &class_name) == FAILURE) { + RETURN_THROWS(); } + + zend_string *lc_name = zend_string_tolower(class_name); + spl_perform_autoload(class_name, lc_name); + zend_string_release(lc_name); } /* }}} */ #define HT_MOVE_TAIL_TO_HEAD(ht) \ @@ -511,7 +496,6 @@ PHP_FUNCTION(spl_autoload_register) zend_string *lc_name; zend_bool do_throw = 1; zend_bool prepend = 0; - zend_function *spl_func_ptr; autoload_func_info alfi; zend_object *obj_ptr; zend_fcall_info fci = {0}; @@ -529,6 +513,11 @@ PHP_FUNCTION(spl_autoload_register) "spl_autoload_register() will always throw"); } + if (!SPL_G(autoload_functions)) { + ALLOC_HASHTABLE(SPL_G(autoload_functions)); + zend_hash_init(SPL_G(autoload_functions), 1, NULL, autoload_func_info_dtor, 0); + } + /* If first arg is not null */ if (ZEND_FCI_INITIALIZED(fci)) { alfi.ce = fcc.calling_scope; @@ -561,7 +550,7 @@ PHP_FUNCTION(spl_autoload_register) } zend_string_release(func_name); - if (SPL_G(autoload_functions) && zend_hash_exists(SPL_G(autoload_functions), lc_name)) { + if (zend_hash_exists(SPL_G(autoload_functions), lc_name)) { if (!Z_ISUNDEF(alfi.closure)) { Z_DELREF_P(&alfi.closure); } @@ -579,28 +568,6 @@ PHP_FUNCTION(spl_autoload_register) ZVAL_UNDEF(&alfi.obj); } - if (!SPL_G(autoload_functions)) { - ALLOC_HASHTABLE(SPL_G(autoload_functions)); - zend_hash_init(SPL_G(autoload_functions), 1, NULL, autoload_func_info_dtor, 0); - } - - spl_func_ptr = spl_autoload_fn; - - if (EG(autoload_func) == spl_func_ptr) { /* registered already, so we insert that first */ - autoload_func_info spl_alfi; - - spl_alfi.func_ptr = spl_func_ptr; - ZVAL_UNDEF(&spl_alfi.obj); - ZVAL_UNDEF(&spl_alfi.closure); - spl_alfi.ce = NULL; - zend_hash_add_mem(SPL_G(autoload_functions), spl_autoload_fn->common.function_name, - &spl_alfi, sizeof(autoload_func_info)); - if (prepend && SPL_G(autoload_functions)->nNumOfElements > 1) { - /* Move the newly created element to the head of the hashtable */ - HT_MOVE_TAIL_TO_HEAD(SPL_G(autoload_functions)); - } - } - if (UNEXPECTED(alfi.func_ptr == &EG(trampoline))) { zend_function *copy = emalloc(sizeof(zend_op_array)); @@ -626,12 +593,19 @@ PHP_FUNCTION(spl_autoload_register) } skip: zend_string_release_ex(lc_name, 0); - } - - if (SPL_G(autoload_functions)) { - EG(autoload_func) = spl_autoload_call_fn; } else { - EG(autoload_func) = spl_autoload_fn; + autoload_func_info spl_alfi; + spl_alfi.func_ptr = zend_hash_str_find_ptr( + CG(function_table), "spl_autoload", sizeof("spl_autoload") - 1); + ZVAL_UNDEF(&spl_alfi.obj); + ZVAL_UNDEF(&spl_alfi.closure); + spl_alfi.ce = NULL; + zend_hash_add_mem(SPL_G(autoload_functions), spl_alfi.func_ptr->common.function_name, + &spl_alfi, sizeof(autoload_func_info)); + if (prepend && SPL_G(autoload_functions)->nNumOfElements > 1) { + /* Move the newly created element to the head of the hashtable */ + HT_MOVE_TAIL_TO_HEAD(SPL_G(autoload_functions)); + } } RETURN_TRUE; @@ -646,7 +620,6 @@ PHP_FUNCTION(spl_autoload_unregister) zend_string *lc_name; zval *zcallable; int success = FAILURE; - zend_function *spl_func_ptr; zend_object *obj_ptr; zend_fcall_info_cache fcc; @@ -686,13 +659,12 @@ PHP_FUNCTION(spl_autoload_unregister) zend_string_release_ex(func_name, 0); if (SPL_G(autoload_functions)) { - if (zend_string_equals(lc_name, spl_autoload_call_fn->common.function_name)) { + if (zend_string_equals_literal(lc_name, "spl_autoload_call")) { /* remove all */ if (!SPL_G(autoload_running)) { zend_hash_destroy(SPL_G(autoload_functions)); FREE_HASHTABLE(SPL_G(autoload_functions)); SPL_G(autoload_functions) = NULL; - EG(autoload_func) = NULL; } else { zend_hash_clean(SPL_G(autoload_functions)); } @@ -707,14 +679,6 @@ PHP_FUNCTION(spl_autoload_unregister) success = zend_hash_del(SPL_G(autoload_functions), lc_name); } } - } else if (zend_string_equals(lc_name, spl_autoload_fn->common.function_name)) { - /* register single spl_autoload() */ - spl_func_ptr = spl_autoload_fn; - - if (EG(autoload_func) == spl_func_ptr) { - success = SUCCESS; - EG(autoload_func) = NULL; - } } zend_string_release_ex(lc_name, 0); @@ -725,21 +689,14 @@ PHP_FUNCTION(spl_autoload_unregister) Return all registered autoloader functions */ PHP_FUNCTION(spl_autoload_functions) { - zend_function *fptr; autoload_func_info *alfi; if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); } - if (!EG(autoload_func)) { - RETURN_FALSE; - } - - fptr = spl_autoload_call_fn; - - if (EG(autoload_func) == fptr) { - array_init(return_value); + array_init(return_value); + if (SPL_G(autoload_functions)) { ZEND_HASH_FOREACH_PTR(SPL_G(autoload_functions), alfi) { if (!Z_ISUNDEF(alfi->closure)) { Z_ADDREF(alfi->closure); @@ -760,11 +717,7 @@ PHP_FUNCTION(spl_autoload_functions) add_next_index_str(return_value, zend_string_copy(alfi->func_ptr->common.function_name)); } } ZEND_HASH_FOREACH_END(); - return; } - - array_init(return_value); - add_next_index_str(return_value, zend_string_copy(EG(autoload_func)->common.function_name)); } /* }}} */ /* {{{ proto string spl_object_hash(object obj) @@ -859,6 +812,8 @@ PHP_MINFO_FUNCTION(spl) */ PHP_MINIT_FUNCTION(spl) { + zend_autoload = spl_perform_autoload; + PHP_MINIT(spl_exceptions)(INIT_FUNC_ARGS_PASSTHRU); PHP_MINIT(spl_iterators)(INIT_FUNC_ARGS_PASSTHRU); PHP_MINIT(spl_array)(INIT_FUNC_ARGS_PASSTHRU); @@ -868,10 +823,6 @@ PHP_MINIT_FUNCTION(spl) PHP_MINIT(spl_fixedarray)(INIT_FUNC_ARGS_PASSTHRU); PHP_MINIT(spl_observer)(INIT_FUNC_ARGS_PASSTHRU); - spl_autoload_fn = zend_hash_str_find_ptr(CG(function_table), "spl_autoload", sizeof("spl_autoload") - 1); - spl_autoload_call_fn = zend_hash_str_find_ptr(CG(function_table), "spl_autoload_call", sizeof("spl_autoload_call") - 1); - ZEND_ASSERT(spl_autoload_fn != NULL && spl_autoload_call_fn != NULL); - return SUCCESS; } /* }}} */ diff --git a/ext/spl/php_spl.stub.php b/ext/spl/php_spl.stub.php index b2c570b5f1359..a4c6b2ab2290d 100755 --- a/ext/spl/php_spl.stub.php +++ b/ext/spl/php_spl.stub.php @@ -10,12 +10,11 @@ function class_uses($what, bool $autoload = true): array|false {} function spl_autoload(string $class_name, ?string $file_extensions = null): void {} -// This silently ignores non-string class names -function spl_autoload_call($class_name): void {} +function spl_autoload_call(string $class_name): void {} function spl_autoload_extensions(?string $file_extensions = null): string {} -function spl_autoload_functions(): array|false {} +function spl_autoload_functions(): array {} function spl_autoload_register(?callable $autoload_function = null, bool $throw = true, bool $prepend = false): bool {} diff --git a/ext/spl/php_spl_arginfo.h b/ext/spl/php_spl_arginfo.h index 01d881d7407d0..abe9392071faf 100644 --- a/ext/spl/php_spl_arginfo.h +++ b/ext/spl/php_spl_arginfo.h @@ -18,14 +18,14 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_spl_autoload, 0, 1, IS_VOID, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_spl_autoload_call, 0, 1, IS_VOID, 0) - ZEND_ARG_INFO(0, class_name) + ZEND_ARG_TYPE_INFO(0, class_name, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_spl_autoload_extensions, 0, 0, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, file_extensions, IS_STRING, 1, "null") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_spl_autoload_functions, 0, 0, MAY_BE_ARRAY|MAY_BE_FALSE) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_spl_autoload_functions, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_spl_autoload_register, 0, 0, _IS_BOOL, 0) @@ -38,8 +38,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_spl_autoload_unregister, 0, 1, _ ZEND_ARG_INFO(0, autoload_function) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_spl_classes, 0, 0, IS_ARRAY, 0) -ZEND_END_ARG_INFO() +#define arginfo_spl_classes arginfo_spl_autoload_functions ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_spl_object_hash, 0, 1, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, obj, IS_OBJECT, 0) diff --git a/ext/spl/tests/spl_autoload_002.phpt b/ext/spl/tests/spl_autoload_002.phpt index 98ba09dad870b..1a67baabd0b3c 100644 --- a/ext/spl/tests/spl_autoload_002.phpt +++ b/ext/spl/tests/spl_autoload_002.phpt @@ -1,9 +1,5 @@ --TEST-- SPL: spl_autoload_functions() ---SKIPIF-- - --FILE-- --EXPECT-- -bool(false) +array(0) { +} array(1) { [0]=> string(12) "spl_autoload" @@ -59,9 +56,11 @@ array(2) { [1]=> string(16) "SplAutoloadTest2" } -bool(false) +array(0) { +} array(1) { [0]=> string(12) "spl_autoload" } -bool(false) +array(0) { +} diff --git a/ext/spl/tests/spl_autoload_012.phpt b/ext/spl/tests/spl_autoload_012.phpt index 7b13b7105a16b..218d3e800ff23 100644 --- a/ext/spl/tests/spl_autoload_012.phpt +++ b/ext/spl/tests/spl_autoload_012.phpt @@ -47,7 +47,6 @@ autoload_first Fatal error: Uncaught Exception: first in %sspl_autoload_012.php:%d Stack trace: #0 [internal function]: autoload_first('ThisClassDoesNo...') -#1 [internal function]: spl_autoload_call('ThisClassDoesNo...') -#2 %sspl_autoload_012.php(%d): class_exists('ThisClassDoesNo...') -#3 {main} +#1 %sspl_autoload_012.php(%d): class_exists('ThisClassDoesNo...') +#2 {main} thrown in %s on line %d From ef9bf62fa2720636a61e6cd40c1949b64701452f Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 9 Jun 2020 18:05:39 +0200 Subject: [PATCH 2/2] Add test for bug #71236 --- ext/spl/tests/bug71236.phpt | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 ext/spl/tests/bug71236.phpt diff --git a/ext/spl/tests/bug71236.phpt b/ext/spl/tests/bug71236.phpt new file mode 100644 index 0000000000000..55c7cb88fef75 --- /dev/null +++ b/ext/spl/tests/bug71236.phpt @@ -0,0 +1,23 @@ +--TEST-- +Bug #71236: Second call of spl_autoload_register() does nothing if it has no arguments +--FILE-- + +--EXPECT-- +array(2) { + [0]=> + object(Closure)#1 (1) { + ["parameter"]=> + array(1) { + ["$class"]=> + string(10) "" + } + } + [1]=> + string(12) "spl_autoload" +}