From e74e5923a6e406bf7a9d748dcc89f85c56f7b16b Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Fri, 2 Dec 2022 01:23:48 +0000 Subject: [PATCH] Fix GH-10011 (Trampoline autoloader will get reregistered and cannot be unregistered) There are two issues to resolve: 1. The FCC is not refetch when trying to unregister a trampoline 2. Comparing the function pointer of trampolines is meaningless as they are reallocated, thus we need to compare the name of the function Found while working on GH-8294 --- ext/spl/php_spl.c | 17 +++++++++++ ext/spl/tests/gh10011.phpt | 59 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 ext/spl/tests/gh10011.phpt diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c index 46dd62db7cb60..86eb9d8d21554 100644 --- a/ext/spl/php_spl.c +++ b/ext/spl/php_spl.c @@ -402,6 +402,16 @@ static autoload_func_info *autoload_func_info_from_fci( static bool autoload_func_info_equals( const autoload_func_info *alfi1, const autoload_func_info *alfi2) { + if (UNEXPECTED( + (alfi1->func_ptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) && + (alfi2->func_ptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) + )) { + return alfi1->obj == alfi2->obj + && alfi1->ce == alfi2->ce + && alfi1->closure == alfi2->closure + && zend_string_equals(alfi1->func_ptr->common.function_name, alfi2->func_ptr->common.function_name) + ; + } return alfi1->func_ptr == alfi2->func_ptr && alfi1->obj == alfi2->obj && alfi1->ce == alfi2->ce @@ -580,6 +590,13 @@ PHP_FUNCTION(spl_autoload_unregister) RETURN_TRUE; } + if (!fcc.function_handler) { + /* Call trampoline has been cleared by zpp. Refetch it, because we want to deal + * with it outselves. It is important that it is not refetched on every call, + * because calls may occur from different scopes. */ + zend_is_callable_ex(&fci.function_name, NULL, 0, NULL, &fcc, NULL); + } + autoload_func_info *alfi = autoload_func_info_from_fci(&fci, &fcc); Bucket *p = spl_find_registered_function(alfi); autoload_func_info_destroy(alfi); diff --git a/ext/spl/tests/gh10011.phpt b/ext/spl/tests/gh10011.phpt new file mode 100644 index 0000000000000..3603011f70bc6 --- /dev/null +++ b/ext/spl/tests/gh10011.phpt @@ -0,0 +1,59 @@ +--TEST-- +Bug GH-10011 (Trampoline autoloader will get reregistered and cannot be unregistered) +--FILE-- + +--EXPECT-- +array(2) { + [0]=> + array(2) { + [0]=> + object(TrampolineTest)#1 (0) { + } + [1]=> + string(11) "trampoline1" + } + [1]=> + array(2) { + [0]=> + object(TrampolineTest)#1 (0) { + } + [1]=> + string(11) "trampoline2" + } +} +Trampoline for trampoline1 +Trampoline for trampoline2 +bool(false) +Unregister trampoline: +bool(true) +bool(false) +bool(true) +array(0) { +} +bool(false)