]> granicus.if.org Git - php/commitdiff
Disable JIT with incompatible third-party extensions
authorDmitry Stogov <dmitry@zend.com>
Mon, 30 Nov 2020 10:58:34 +0000 (13:58 +0300)
committerDmitry Stogov <dmitry@zend.com>
Mon, 30 Nov 2020 10:58:34 +0000 (13:58 +0300)
ext/opcache/ZendAccelerator.c
ext/opcache/jit/zend_jit.c
ext/opcache/jit/zend_jit.h
ext/opcache/tests/jit/bug80426.phpt [new file with mode: 0644]
ext/zend_test/test.c

index 7eee9819cee622c6bc10ec3d4683ce8c2bfbb531..4fbc60bd74d6ecae7e05e886cc16b42111b9e34b 100644 (file)
@@ -2970,7 +2970,8 @@ static zend_result accel_post_startup(void)
                size_t jit_size = 0;
                zend_bool reattached = 0;
 
-               if (JIT_G(enabled) && JIT_G(buffer_size)) {
+               if (JIT_G(enabled) && JIT_G(buffer_size)
+                && zend_jit_check_support() == SUCCESS) {
                        size_t page_size;
 
 # ifdef _WIN32
index 9d17f174740bc586dc7b8c65f776c1ece01b7e1d..60086403aab5307e9c21b67873952a2117909d0a 100644 (file)
@@ -4164,17 +4164,39 @@ ZEND_EXT_API void zend_jit_init(void)
 #endif
 }
 
-ZEND_EXT_API int zend_jit_startup(void *buf, size_t size, zend_bool reattached)
+ZEND_EXT_API int zend_jit_check_support(void)
 {
-       int ret;
+       int i;
 
        zend_jit_vm_kind = zend_vm_kind();
        if (zend_jit_vm_kind != ZEND_VM_KIND_CALL &&
            zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
-               // TODO: error reporting and cleanup ???
+               zend_error(E_WARNING, "JIT is compatible only with CALL and HYBRID VM. JIT disabled.");
+               JIT_G(enabled) = 0;
                return FAILURE;
        }
 
+       if (zend_execute_ex != execute_ex) {
+               zend_error(E_WARNING, "JIT is incompatible with third party extensions that override zend_execute_ex(). JIT disabled.");
+               JIT_G(enabled) = 0;
+               return FAILURE;
+       }
+
+       for (i = 0; i <= 256; i++) {
+               if (zend_get_user_opcode_handler(i) != NULL) {
+                       zend_error(E_WARNING, "JIT is incompatible with third party extensions that setup user opcode handlers. JIT disabled.");
+                       JIT_G(enabled) = 0;
+                       return FAILURE;
+               }
+       }
+
+       return SUCCESS;
+}
+
+ZEND_EXT_API int zend_jit_startup(void *buf, size_t size, zend_bool reattached)
+{
+       int ret;
+
        zend_jit_halt_op = zend_get_halt_op();
 
        if (zend_jit_setup() != SUCCESS) {
index ed0dc29a6c82b0931f73c49b54b6c6ad13d21556..fffac1edc2a9f643a5050baffde876c65a9a08bf 100644 (file)
@@ -136,6 +136,7 @@ ZEND_EXT_API void zend_jit_protect(void);
 ZEND_EXT_API void zend_jit_init(void);
 ZEND_EXT_API int  zend_jit_config(zend_string *jit_options, int stage);
 ZEND_EXT_API int  zend_jit_debug_config(zend_long old_val, zend_long new_val, int stage);
+ZEND_EXT_API int  zend_jit_check_support(void);
 ZEND_EXT_API int  zend_jit_startup(void *jit_buffer, size_t size, zend_bool reattached);
 ZEND_EXT_API void zend_jit_shutdown(void);
 ZEND_EXT_API void zend_jit_activate(void);
diff --git a/ext/opcache/tests/jit/bug80426.phpt b/ext/opcache/tests/jit/bug80426.phpt
new file mode 100644 (file)
index 0000000..04599ed
--- /dev/null
@@ -0,0 +1,27 @@
+--TEST--
+Bug #80426: Crash when using JIT and an extension replacing zend_execute_ex with custom
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.jit_buffer_size=1M
+zend_test.replace_zend_execute_ex=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+<?php if (!extension_loaded('zend-test')) die('skip: zend-test extension required'); ?>
+--FILE--
+<?php
+
+function compute() {
+    if (true) {
+    }
+}
+
+for ($i = 0; $i <= 64; $i++) {
+    compute();
+}
+
+?>
+===DONE===
+--EXPECT--
+Warning: JIT is incompatible with third party extensions that override zend_execute_ex(). JIT disabled. in Unknown on line 0
+===DONE===
index b6f848c5b7c5afb64bce3cfbca3fd9c76391c9d6..c44fdb481f3546ad4afbd682ab5c0822b2b6c9b1 100644 (file)
@@ -39,6 +39,7 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test)
        int observer_show_init_backtrace;
        int observer_show_opcode;
        int observer_nesting_depth;
+       int replace_zend_execute_ex;
 ZEND_END_MODULE_GLOBALS(zend_test)
 
 ZEND_DECLARE_MODULE_GLOBALS(zend_test)
@@ -332,10 +333,17 @@ PHP_INI_BEGIN()
        STD_PHP_INI_BOOLEAN("zend_test.observer.show_return_value", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_return_value, zend_zend_test_globals, zend_test_globals)
        STD_PHP_INI_BOOLEAN("zend_test.observer.show_init_backtrace", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_init_backtrace, zend_zend_test_globals, zend_test_globals)
        STD_PHP_INI_BOOLEAN("zend_test.observer.show_opcode", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_opcode, zend_zend_test_globals, zend_test_globals)
+       STD_PHP_INI_BOOLEAN("zend_test.replace_zend_execute_ex", "0", PHP_INI_SYSTEM, OnUpdateBool, replace_zend_execute_ex, zend_zend_test_globals, zend_test_globals)
 PHP_INI_END()
 
 static zend_observer_fcall_handlers observer_fcall_init(zend_execute_data *execute_data);
 
+void (*old_zend_execute_ex)(zend_execute_data *execute_data);
+static void custom_zend_execute_ex(zend_execute_data *execute_data)
+{
+       old_zend_execute_ex(execute_data);
+}
+
 PHP_MINIT_FUNCTION(zend_test)
 {
        zend_class_entry class_entry;
@@ -431,6 +439,11 @@ PHP_MINIT_FUNCTION(zend_test)
                (void)ini_entries;
        }
 
+       if (ZT_G(replace_zend_execute_ex)) {
+               old_zend_execute_ex = zend_execute_ex;
+               zend_execute_ex = custom_zend_execute_ex;
+       }
+
        return SUCCESS;
 }