diff --git a/ext/opcache/tests/gh17770_jit_file_cache_write.phpt b/ext/opcache/tests/gh17770_jit_file_cache_write.phpt new file mode 100644 index 0000000000000..f372d98468076 --- /dev/null +++ b/ext/opcache/tests/gh17770_jit_file_cache_write.phpt @@ -0,0 +1,83 @@ +--TEST-- +GH-17770: opcache.file_cache writes with JIT enabled +--SKIPIF-- + +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=tracing +opcache.jit_buffer_size=16M +opcache.file_cache="{PWD}/gh17770_cache" +opcache.file_cache_consistency_checks=0 +--FILE-- +isDir()) { + @rmdir($entry->getRealPath()); + } else { + @unlink($entry->getRealPath()); + } + } + + @rmdir($dir); +} + +$cacheDir = ini_get('opcache.file_cache'); +removeDirRecursive($cacheDir); +@mkdir($cacheDir, 0777, true); + +$tmpPhpFile = __DIR__ . '/gh17770-opcache-target.php'; +file_put_contents($tmpPhpFile, " +--CLEAN-- +isDir()) { + @rmdir($entry->getRealPath()); + } else { + @unlink($entry->getRealPath()); + } + } + + @rmdir($dir); +} + +removeDirRecursive(__DIR__ . '/gh17770_cache'); +@unlink(__DIR__ . '/gh17770-opcache-target.php'); +?> +--EXPECT-- +OK diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index 3114e5b92712c..4c92c7723a5b9 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -637,6 +637,10 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra /* relative extended_value don't have to be changed */ break; } +#endif +#ifdef HAVE_JIT + /* Re-normalize handlers before serializing to avoid storing JIT runtime handlers. */ + ZEND_VM_SET_OPCODE_HANDLER(opline); #endif zend_serialize_opcode_handler(opline); opline++; @@ -1152,15 +1156,19 @@ int zend_file_cache_script_store(zend_persistent_script *script, bool in_shm) char *filename; zend_file_cache_metainfo info; void *mem, *buf; - #ifdef HAVE_JIT - /* FIXME: dump jited codes out to file cache? */ - if (JIT_G(on)) { - return FAILURE; + bool orig_jit_on = JIT_G(on); + + /* File cache stores bytecode/metadata only; JIT code is rebuilt at runtime. */ + if (orig_jit_on) { + JIT_G(on) = 0; } #endif if (ZCG(accel_directives).file_cache_read_only) { +#ifdef HAVE_JIT + JIT_G(on) = orig_jit_on; +#endif return FAILURE; } @@ -1169,6 +1177,9 @@ int zend_file_cache_script_store(zend_persistent_script *script, bool in_shm) if (zend_file_cache_mkdir(filename, strlen(ZCG(accel_directives).file_cache)) != SUCCESS) { zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot create directory for file '%s', %s\n", filename, strerror(errno)); efree(filename); +#ifdef HAVE_JIT + JIT_G(on) = orig_jit_on; +#endif return FAILURE; } @@ -1178,12 +1189,18 @@ int zend_file_cache_script_store(zend_persistent_script *script, bool in_shm) zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot create file '%s', %s\n", filename, strerror(errno)); } efree(filename); +#ifdef HAVE_JIT + JIT_G(on) = orig_jit_on; +#endif return FAILURE; } if (zend_file_cache_flock(fd, LOCK_EX) != 0) { close(fd); efree(filename); +#ifdef HAVE_JIT + JIT_G(on) = orig_jit_on; +#endif return FAILURE; } @@ -1227,6 +1244,9 @@ int zend_file_cache_script_store(zend_persistent_script *script, bool in_shm) efree(mem); zend_file_cache_unlink(filename); efree(filename); +#ifdef HAVE_JIT + JIT_G(on) = orig_jit_on; +#endif return FAILURE; } @@ -1237,6 +1257,9 @@ int zend_file_cache_script_store(zend_persistent_script *script, bool in_shm) } close(fd); efree(filename); +#ifdef HAVE_JIT + JIT_G(on) = orig_jit_on; +#endif return SUCCESS; }