Description
Disclaimer: I encountered this issue using a threading extension. Well aware this may not be the best source of truth on issues like this, especially due to the difficulty of reproducing.
With the following INI:
opcache.jit=tracing
opcache.jit_buffer_size=0
the following happens:
- INI is loaded on the main thread and sets
JIT_G(enabled) = 1 and JIT_G(on) = 1
accel_post_startup() is called during process init, and overrides thread-locals here to force-disable JIT:
|
JIT_G(enabled) = false; |
|
JIT_G(on) = false; |
dasm_buf is therefore null because zend_jit_startup() wasn't called due to jit_buffer_size=0:
|
if (JIT_G(enabled)) { |
|
if (JIT_G(buffer_size) == 0) { |
|
JIT_G(enabled) = false; |
|
JIT_G(on) = false; |
|
} else if (!ZSMMG(reserved)) { |
|
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: could not use reserved buffer!"); |
|
} else { |
|
zend_jit_startup(ZSMMG(reserved), jit_size, reattached); |
|
} |
|
} |
&
- when a second thread is started, INI is loaded again, setting
JIT_G(enabled) = 1 and JIT_G(on) = 1, but this time accel_post_startup() does not override these settings
- finally, the following calls fail on Windows with errors like
VirtualProtect() failed [87] The parameter is incorrect during zend_accel_persist_script() because dasm_buf is NULL - this is because JIT_G(on) = 1 although it was supposed to be forcibly disabled:
|
if (JIT_G(on) && for_shm) { |
|
zend_jit_unprotect(); |
|
} |
&
|
if (JIT_G(on) && for_shm) { |
|
if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_SCRIPT) { |
|
zend_jit_script(&script->script); |
|
} |
|
zend_jit_protect(); |
|
} |
Proposed solution
JIT_G(enabled) needs to become a true global
zend_jit_config() needs to respect the existing value of JIT_G(enabled) (or its replacement true global) instead of overwriting it like it currently does
JIT_G(enabled) (or its replacement true global) should be set to true in accel_post_startup() after zend_jit_startup() returns a success code
PHP Version
8.1, 8.2, 8.3, 8.4, master
Operating System
Windows
Description
Disclaimer: I encountered this issue using a threading extension. Well aware this may not be the best source of truth on issues like this, especially due to the difficulty of reproducing.
With the following INI:
the following happens:
JIT_G(enabled) = 1andJIT_G(on) = 1accel_post_startup()is called during process init, and overrides thread-locals here to force-disable JIT:php-src/ext/opcache/ZendAccelerator.c
Lines 3279 to 3280 in 6dec6a6
dasm_bufis therefore null becausezend_jit_startup()wasn't called due tojit_buffer_size=0:php-src/ext/opcache/ZendAccelerator.c
Lines 3277 to 3286 in 6dec6a6
php-src/ext/opcache/jit/zend_jit.c
Line 3675 in 6dec6a6
JIT_G(enabled) = 1andJIT_G(on) = 1, but this timeaccel_post_startup()does not override these settingsVirtualProtect() failed [87] The parameter is incorrectduringzend_accel_persist_script()becausedasm_bufisNULL- this is becauseJIT_G(on) = 1although it was supposed to be forcibly disabled:php-src/ext/opcache/zend_persist.c
Lines 1384 to 1386 in 6dec6a6
php-src/ext/opcache/zend_persist.c
Lines 1419 to 1424 in 6dec6a6
Proposed solution
JIT_G(enabled)needs to become a true globalzend_jit_config()needs to respect the existing value ofJIT_G(enabled)(or its replacement true global) instead of overwriting it like it currently doesJIT_G(enabled)(or its replacement true global) should be set totrueinaccel_post_startup()afterzend_jit_startup()returns a success codePHP Version
8.1, 8.2, 8.3, 8.4, master
Operating System
Windows