Skip to content

Commit e74e592

Browse files
committed
Fix phpGH-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 phpGH-8294
1 parent 29f0f4e commit e74e592

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

ext/spl/php_spl.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,16 @@ static autoload_func_info *autoload_func_info_from_fci(
402402

403403
static bool autoload_func_info_equals(
404404
const autoload_func_info *alfi1, const autoload_func_info *alfi2) {
405+
if (UNEXPECTED(
406+
(alfi1->func_ptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) &&
407+
(alfi2->func_ptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)
408+
)) {
409+
return alfi1->obj == alfi2->obj
410+
&& alfi1->ce == alfi2->ce
411+
&& alfi1->closure == alfi2->closure
412+
&& zend_string_equals(alfi1->func_ptr->common.function_name, alfi2->func_ptr->common.function_name)
413+
;
414+
}
405415
return alfi1->func_ptr == alfi2->func_ptr
406416
&& alfi1->obj == alfi2->obj
407417
&& alfi1->ce == alfi2->ce
@@ -580,6 +590,13 @@ PHP_FUNCTION(spl_autoload_unregister)
580590
RETURN_TRUE;
581591
}
582592

593+
if (!fcc.function_handler) {
594+
/* Call trampoline has been cleared by zpp. Refetch it, because we want to deal
595+
* with it outselves. It is important that it is not refetched on every call,
596+
* because calls may occur from different scopes. */
597+
zend_is_callable_ex(&fci.function_name, NULL, 0, NULL, &fcc, NULL);
598+
}
599+
583600
autoload_func_info *alfi = autoload_func_info_from_fci(&fci, &fcc);
584601
Bucket *p = spl_find_registered_function(alfi);
585602
autoload_func_info_destroy(alfi);

ext/spl/tests/gh10011.phpt

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
--TEST--
2+
Bug GH-10011 (Trampoline autoloader will get reregistered and cannot be unregistered)
3+
--FILE--
4+
<?php
5+
6+
class TrampolineTest {
7+
public function __call(string $name, array $arguments) {
8+
echo 'Trampoline for ', $name, PHP_EOL;
9+
}
10+
}
11+
$o = new TrampolineTest();
12+
$callback1 = [$o, 'trampoline1'];
13+
$callback2 = [$o, 'trampoline2'];
14+
15+
spl_autoload_register($callback1);
16+
spl_autoload_register($callback2);
17+
spl_autoload_register($callback1); // 2nd call ignored
18+
19+
var_dump(spl_autoload_functions());
20+
21+
var_dump(class_exists("TestClass", true));
22+
23+
echo "Unregister trampoline:\n";
24+
var_dump(spl_autoload_unregister($callback1));
25+
var_dump(spl_autoload_unregister($callback1));
26+
var_dump(spl_autoload_unregister($callback2));
27+
28+
var_dump(spl_autoload_functions());
29+
var_dump(class_exists("TestClass", true));
30+
?>
31+
--EXPECT--
32+
array(2) {
33+
[0]=>
34+
array(2) {
35+
[0]=>
36+
object(TrampolineTest)#1 (0) {
37+
}
38+
[1]=>
39+
string(11) "trampoline1"
40+
}
41+
[1]=>
42+
array(2) {
43+
[0]=>
44+
object(TrampolineTest)#1 (0) {
45+
}
46+
[1]=>
47+
string(11) "trampoline2"
48+
}
49+
}
50+
Trampoline for trampoline1
51+
Trampoline for trampoline2
52+
bool(false)
53+
Unregister trampoline:
54+
bool(true)
55+
bool(false)
56+
bool(true)
57+
array(0) {
58+
}
59+
bool(false)

0 commit comments

Comments
 (0)