summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2020-11-30 13:58:34 +0300
committerDmitry Stogov <dmitry@zend.com>2020-11-30 13:58:34 +0300
commitd5a82e2c4eebe8337ff7790db46d812af2fbcec9 (patch)
tree0e55172bfbde4e27b4a5d76d50c9f6ac009e4df0
parent15073d8e1da5f7c140acbed0bee0c09439a1cfac (diff)
downloadphp-git-d5a82e2c4eebe8337ff7790db46d812af2fbcec9.tar.gz
Disable JIT with incompatible third-party extensions
-rw-r--r--ext/opcache/ZendAccelerator.c3
-rw-r--r--ext/opcache/jit/zend_jit.c28
-rw-r--r--ext/opcache/jit/zend_jit.h1
-rw-r--r--ext/opcache/tests/jit/bug80426.phpt27
-rw-r--r--ext/zend_test/test.c13
5 files changed, 68 insertions, 4 deletions
diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c
index 7eee9819ce..4fbc60bd74 100644
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@ -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
diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c
index 9d17f17474..60086403aa 100644
--- a/ext/opcache/jit/zend_jit.c
+++ b/ext/opcache/jit/zend_jit.c
@@ -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) {
diff --git a/ext/opcache/jit/zend_jit.h b/ext/opcache/jit/zend_jit.h
index ed0dc29a6c..fffac1edc2 100644
--- a/ext/opcache/jit/zend_jit.h
+++ b/ext/opcache/jit/zend_jit.h
@@ -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
index 0000000000..04599ed1fc
--- /dev/null
+++ b/ext/opcache/tests/jit/bug80426.phpt
@@ -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===
diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c
index b6f848c5b7..c44fdb481f 100644
--- a/ext/zend_test/test.c
+++ b/ext/zend_test/test.c
@@ -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;
}