Commit 6f6964b5b30 for php
commit 6f6964b5b30c97a829b7a8ff2d0e9e5c22baa72a
Author: Yuma Kakei <yumasansansan@gmail.com>
Date: Tue Oct 27 03:21:39 2026 +0900
Fix JIT fuzzers never enabling the JIT (#24717)
Since the default of opcache.jit changed from "tracing" to "disable"
(c16ad918ba3, RFC jit_config_defaults), JIT_G(enabled) is false after
startup and zend_jit_config() rejects every runtime change of
opcache.jit. The function-jit and tracing-jit fuzzers turn the JIT on
at runtime without checking the result, so since PHP 8.4 they have only
been running the VM. The OSS-Fuzz coverage report of 2026-10-24 shows
0.04% line coverage (40/103166) for ext/opcache/jit/.
Start with opcache.jit=off, which keeps the JIT available, and abort if
switching the JIT mode fails, so that this cannot regress silently.
diff --git a/sapi/fuzzer/fuzzer-execute-common.h b/sapi/fuzzer/fuzzer-execute-common.h
index 4febd88fafb..7fb9ef1598d 100644
--- a/sapi/fuzzer/fuzzer-execute-common.h
+++ b/sapi/fuzzer/fuzzer-execute-common.h
@@ -146,3 +146,12 @@ ZEND_ATTRIBUTE_UNUSED static void opcache_invalidate(void) {
zval_ptr_dtor(&retval);
EG(exception) = exception;
}
+
+ZEND_ATTRIBUTE_UNUSED static void set_jit_option(zend_string *jit_option, const char *value) {
+ if (zend_alter_ini_entry_chars(
+ jit_option, value, strlen(value), PHP_INI_USER, PHP_INI_STAGE_RUNTIME) == FAILURE) {
+ /* Fail loudly instead of silently fuzzing without the JIT. */
+ fprintf(stderr, "Failed to set opcache.jit=%s\n", value);
+ abort();
+ }
+}
diff --git a/sapi/fuzzer/fuzzer-function-jit.c b/sapi/fuzzer/fuzzer-function-jit.c
index d949995f8a2..7b3b18db12b 100644
--- a/sapi/fuzzer/fuzzer-function-jit.c
+++ b/sapi/fuzzer/fuzzer-function-jit.c
@@ -27,15 +27,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
* we bail out here, as the JIT code may loop infinitely. */
steps_left = MAX_STEPS;
bailed_out = false;
- zend_alter_ini_entry_chars(
- jit_option, "off", sizeof("off")-1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
+ set_jit_option(jit_option, "off");
fuzzer_do_request_from_buffer(
FILE_NAME, (const char *) Data, Size, /* execute */ 1, opcache_invalidate);
if (!bailed_out) {
steps_left = MAX_STEPS;
- zend_alter_ini_entry_chars(jit_option,
- "function", sizeof("function")-1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
+ set_jit_option(jit_option, "function");
zend_execute_ex = orig_execute_ex;
fuzzer_do_request_from_buffer(
FILE_NAME, (const char *) Data, Size, /* execute */ 1, opcache_invalidate);
@@ -50,6 +48,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
int LLVMFuzzerInitialize(int *argc, char ***argv) {
char ini_buf[512];
snprintf(ini_buf, sizeof(ini_buf),
+ /* The default opcache.jit=disable does not allow enabling the JIT at runtime. */
+ "opcache.jit=off\n"
"opcache.validate_timestamps=0\n"
"opcache.file_update_protection=0\n"
"opcache.jit_buffer_size=128M\n"
diff --git a/sapi/fuzzer/fuzzer-tracing-jit.c b/sapi/fuzzer/fuzzer-tracing-jit.c
index e15f5b4bac5..d5691322239 100644
--- a/sapi/fuzzer/fuzzer-tracing-jit.c
+++ b/sapi/fuzzer/fuzzer-tracing-jit.c
@@ -27,15 +27,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
* we bail out here, as the JIT code may loop infinitely. */
steps_left = MAX_STEPS;
bailed_out = false;
- zend_alter_ini_entry_chars(
- jit_option, "off", sizeof("off")-1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
+ set_jit_option(jit_option, "off");
fuzzer_do_request_from_buffer(
FILE_NAME, (const char *) Data, Size, /* execute */ 1, opcache_invalidate);
if (!bailed_out) {
steps_left = MAX_STEPS;
- zend_alter_ini_entry_chars(jit_option,
- "tracing", sizeof("tracing")-1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
+ set_jit_option(jit_option, "tracing");
zend_execute_ex = orig_execute_ex;
/* Trace & compile */
fuzzer_do_request_from_buffer(
@@ -54,6 +52,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
int LLVMFuzzerInitialize(int *argc, char ***argv) {
char ini_buf[512];
snprintf(ini_buf, sizeof(ini_buf),
+ /* The default opcache.jit=disable does not allow enabling the JIT at runtime. */
+ "opcache.jit=off\n"
"opcache.validate_timestamps=0\n"
"opcache.file_update_protection=0\n"
"opcache.memory_consumption=1024\n"