]> granicus.if.org Git - php/commitdiff
Fixed bug #73896 (spl_autoload() crashes when calls magic _call())
authorDmitry Stogov <dmitry@zend.com>
Mon, 9 Jan 2017 12:11:33 +0000 (15:11 +0300)
committerDmitry Stogov <dmitry@zend.com>
Mon, 9 Jan 2017 12:11:33 +0000 (15:11 +0300)
NEWS
ext/spl/php_spl.c
ext/spl/tests/bug73896.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 75b850933a927a342ce262605c92afc4c34d5df7..3a8919aece56a3f91c718d88bfcfa4614d14a3c2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -22,6 +22,9 @@ PHP                                                                        NEWS
 - Session:
   . Fixed bug #69582 (session not readable by root in CLI). (EvgeniySpinov)
 
+- SPL:
+  . Fixed bug #73896 (spl_autoload() crashes when calls magic _call()). (Dmitry)
+
 - Standard:
   . Fixed bug #69442 (closing of fd incorrect when PTS enabled). (jaytaph)
   . Fixed bug #47021 (SoapClient stumbles over WSDL delivered with
index 4a63ebcf5ed0cc85257a5befc9adfb07ebba10bb..aab10e568a65dc10632f759771e7f4123527a3ea 100644 (file)
@@ -381,6 +381,11 @@ static void autoload_func_info_dtor(zval *element)
        if (!Z_ISUNDEF(alfi->closure)) {
                zval_ptr_dtor(&alfi->closure);
        }
+       if (alfi->func_ptr &&
+               UNEXPECTED(alfi->func_ptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
+               zend_string_release(alfi->func_ptr->common.function_name);
+               zend_free_trampoline(alfi->func_ptr);
+       }
        efree(alfi);
 }
 
@@ -406,7 +411,15 @@ PHP_FUNCTION(spl_autoload_call)
                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);
-                       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);
+                       if (UNEXPECTED(alfi->func_ptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
+                               zend_function *copy = emalloc(sizeof(zend_op_array));
+
+                               memcpy(copy, alfi->func_ptr, sizeof(zend_op_array));
+                               copy->op_array.function_name = zend_string_copy(alfi->func_ptr->op_array.function_name);
+                               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);
+                       } else {
+                               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);
+                       }
                        zend_exception_save();
                        if (retval) {
                                zval_ptr_dtor(retval);
@@ -568,6 +581,13 @@ PHP_FUNCTION(spl_autoload_register)
                        }
                }
 
+               if (UNEXPECTED(alfi.func_ptr == &EG(trampoline))) {
+                       zend_function *copy = emalloc(sizeof(zend_op_array));
+
+                       memcpy(copy, alfi.func_ptr, sizeof(zend_op_array));
+                       alfi.func_ptr->common.function_name = NULL;
+                       alfi.func_ptr = copy;
+               }
                if (zend_hash_add_mem(SPL_G(autoload_functions), lc_name, &alfi, sizeof(autoload_func_info)) == NULL) {
                        if (obj_ptr && !(alfi.func_ptr->common.fn_flags & ZEND_ACC_STATIC)) {
                                Z_DELREF(alfi.obj);
@@ -575,6 +595,10 @@ PHP_FUNCTION(spl_autoload_register)
                        if (!Z_ISUNDEF(alfi.closure)) {
                                Z_DELREF(alfi.closure);
                        }
+                       if (UNEXPECTED(alfi.func_ptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
+                               zend_string_release(alfi.func_ptr->common.function_name);
+                               zend_free_trampoline(alfi.func_ptr);
+                       }
                }
                if (prepend && SPL_G(autoload_functions)->nNumOfElements > 1) {
                        /* Move the newly created element to the head of the hashtable */
diff --git a/ext/spl/tests/bug73896.phpt b/ext/spl/tests/bug73896.phpt
new file mode 100644 (file)
index 0000000..08d8f1e
--- /dev/null
@@ -0,0 +1,38 @@
+--TEST--
+Bug #73896 (spl_autoload() crashes when calls magic _call())
+--FILE--
+<?php
+class Registrator {
+    public static function call($callable, array  $args) {
+        return call_user_func_array($callable, [$args]);
+    }
+}
+
+class teLoader {
+    public function __construct() {
+        Registrator::call('spl_autoload_register', [$this, 'autoload']);
+    }
+
+    public function __call($method, $args) {
+        $this->doSomething();
+    }
+
+    protected function autoload($class) {
+       die("Protected autoload() called!\n");
+    }
+
+    public function doSomething() {
+        throw new teException();
+    }
+}
+
+$teLoader = new teLoader();
+
+try {
+       new teChild();
+} catch (Throwable $e) {
+       echo "Exception: ", $e->getMessage() , "\n";
+}
+?>
+--EXPECT--
+Exception: Class 'teException' not found