Skip to content

Commit add4f43

Browse files
committed
Merge branch 'PHP-7.0' of git.php.net:/php-src into PHP-7.0
* 'PHP-7.0' of git.php.net:/php-src: Fixed bug #73896 (spl_autoload() crashes when calls magic _call())
2 parents ef7e5e0 + 4f1b24d commit add4f43

File tree

3 files changed

+66
-1
lines changed

3 files changed

+66
-1
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ PHP NEWS
2222
- Session:
2323
. Fixed bug #69582 (session not readable by root in CLI). (EvgeniySpinov)
2424

25+
- SPL:
26+
. Fixed bug #73896 (spl_autoload() crashes when calls magic _call()). (Dmitry)
27+
2528
- Standard:
2629
. Fixed bug #69442 (closing of fd incorrect when PTS enabled). (jaytaph)
2730
. Fixed bug #47021 (SoapClient stumbles over WSDL delivered with

ext/spl/php_spl.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,11 @@ static void autoload_func_info_dtor(zval *element)
381381
if (!Z_ISUNDEF(alfi->closure)) {
382382
zval_ptr_dtor(&alfi->closure);
383383
}
384+
if (alfi->func_ptr &&
385+
UNEXPECTED(alfi->func_ptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
386+
zend_string_release(alfi->func_ptr->common.function_name);
387+
zend_free_trampoline(alfi->func_ptr);
388+
}
384389
efree(alfi);
385390
}
386391

@@ -406,7 +411,15 @@ PHP_FUNCTION(spl_autoload_call)
406411
zend_hash_internal_pointer_reset_ex(SPL_G(autoload_functions), &pos);
407412
while (zend_hash_get_current_key_ex(SPL_G(autoload_functions), &func_name, &num_idx, &pos) == HASH_KEY_IS_STRING) {
408413
alfi = zend_hash_get_current_data_ptr_ex(SPL_G(autoload_functions), &pos);
409-
zend_call_method(Z_ISUNDEF(alfi->obj)? NULL : &alfi->obj, alfi->ce, &alfi->func_ptr, ZSTR_VAL(func_name), ZSTR_LEN(func_name), retval, 1, class_name, NULL);
414+
if (UNEXPECTED(alfi->func_ptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
415+
zend_function *copy = emalloc(sizeof(zend_op_array));
416+
417+
memcpy(copy, alfi->func_ptr, sizeof(zend_op_array));
418+
copy->op_array.function_name = zend_string_copy(alfi->func_ptr->op_array.function_name);
419+
zend_call_method(Z_ISUNDEF(alfi->obj)? NULL : &alfi->obj, alfi->ce, &copy, ZSTR_VAL(func_name), ZSTR_LEN(func_name), retval, 1, class_name, NULL);
420+
} else {
421+
zend_call_method(Z_ISUNDEF(alfi->obj)? NULL : &alfi->obj, alfi->ce, &alfi->func_ptr, ZSTR_VAL(func_name), ZSTR_LEN(func_name), retval, 1, class_name, NULL);
422+
}
410423
zend_exception_save();
411424
if (retval) {
412425
zval_ptr_dtor(retval);
@@ -568,13 +581,24 @@ PHP_FUNCTION(spl_autoload_register)
568581
}
569582
}
570583

584+
if (UNEXPECTED(alfi.func_ptr == &EG(trampoline))) {
585+
zend_function *copy = emalloc(sizeof(zend_op_array));
586+
587+
memcpy(copy, alfi.func_ptr, sizeof(zend_op_array));
588+
alfi.func_ptr->common.function_name = NULL;
589+
alfi.func_ptr = copy;
590+
}
571591
if (zend_hash_add_mem(SPL_G(autoload_functions), lc_name, &alfi, sizeof(autoload_func_info)) == NULL) {
572592
if (obj_ptr && !(alfi.func_ptr->common.fn_flags & ZEND_ACC_STATIC)) {
573593
Z_DELREF(alfi.obj);
574594
}
575595
if (!Z_ISUNDEF(alfi.closure)) {
576596
Z_DELREF(alfi.closure);
577597
}
598+
if (UNEXPECTED(alfi.func_ptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
599+
zend_string_release(alfi.func_ptr->common.function_name);
600+
zend_free_trampoline(alfi.func_ptr);
601+
}
578602
}
579603
if (prepend && SPL_G(autoload_functions)->nNumOfElements > 1) {
580604
/* Move the newly created element to the head of the hashtable */

ext/spl/tests/bug73896.phpt

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
Bug #73896 (spl_autoload() crashes when calls magic _call())
3+
--FILE--
4+
<?php
5+
class Registrator {
6+
public static function call($callable, array $args) {
7+
return call_user_func_array($callable, [$args]);
8+
}
9+
}
10+
11+
class teLoader {
12+
public function __construct() {
13+
Registrator::call('spl_autoload_register', [$this, 'autoload']);
14+
}
15+
16+
public function __call($method, $args) {
17+
$this->doSomething();
18+
}
19+
20+
protected function autoload($class) {
21+
die("Protected autoload() called!\n");
22+
}
23+
24+
public function doSomething() {
25+
throw new teException();
26+
}
27+
}
28+
29+
$teLoader = new teLoader();
30+
31+
try {
32+
new teChild();
33+
} catch (Throwable $e) {
34+
echo "Exception: ", $e->getMessage() , "\n";
35+
}
36+
?>
37+
--EXPECT--
38+
Exception: Class 'teException' not found

0 commit comments

Comments
 (0)