From d5a82e2c4eebe8337ff7790db46d812af2fbcec9 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 30 Nov 2020 13:58:34 +0300 Subject: [PATCH] Disable JIT with incompatible third-party extensions --- ext/opcache/ZendAccelerator.c | 3 ++- ext/opcache/jit/zend_jit.c | 28 +++++++++++++++++++++++++--- ext/opcache/jit/zend_jit.h | 1 + ext/opcache/tests/jit/bug80426.phpt | 27 +++++++++++++++++++++++++++ ext/zend_test/test.c | 13 +++++++++++++ 5 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 ext/opcache/tests/jit/bug80426.phpt 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-- + + +--FILE-- + +===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; } -- 2.40.0