From f5eb19febedf5663b3ba9617ecc03cdf94b6df9c Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 16 Aug 2026 11:23:11 +0100 Subject: [PATCH 1/4] ext/opcache: opcache.interned_strings_buffer per FPM pool crashed on restart. Fix #23288 The directive was still accepted once the shared interned string table had been sized from the master php.ini, so a diverging pool value made the next restart run accel_interned_strings_restore_state() against a table that was never allocated. Reject post-startup changes like opcache.memory_consumption and gate the restore on the shared table state instead of the per-process directive. --- ext/opcache/ZendAccelerator.c | 2 +- ext/opcache/zend_accelerator_module.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index a2d964c15070..70f3d8313638 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -2715,7 +2715,7 @@ ZEND_RINIT_FUNCTION(zend_accelerator) zend_reset_cache_vars(); zend_accel_hash_clean(&ZCSG(hash)); - if (ZCG(accel_directives).interned_strings_buffer) { + if (ZCSG(interned_strings).saved_top) { accel_interned_strings_restore_state(); } diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index ffa09aaf9e67..2fb7e775bb34 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -93,6 +93,11 @@ static ZEND_INI_MH(OnUpdateMemoryConsumption) static ZEND_INI_MH(OnUpdateInternedStringsBuffer) { + if (accel_startup_ok) { + zend_accel_error(ACCEL_LOG_WARNING, "opcache.interned_strings_buffer cannot be changed when OPcache is already set up."); + return FAILURE; + } + zend_long *p = (zend_long *) ZEND_INI_GET_ADDR(); zend_long size = zend_ini_parse_quantity_warn(new_value, entry->name); From cede67419a61a39fbc1e4a0b5cba486f43e916a1 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 16 Aug 2026 12:13:13 +0100 Subject: [PATCH 2/4] add fpm test --- ...-opcache-interned-strings-buffer-pool.phpt | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 sapi/fpm/tests/gh23288-opcache-interned-strings-buffer-pool.phpt diff --git a/sapi/fpm/tests/gh23288-opcache-interned-strings-buffer-pool.phpt b/sapi/fpm/tests/gh23288-opcache-interned-strings-buffer-pool.phpt new file mode 100644 index 000000000000..b64e919b105b --- /dev/null +++ b/sapi/fpm/tests/gh23288-opcache-interned-strings-buffer-pool.phpt @@ -0,0 +1,53 @@ +--TEST-- +FPM: GH-23288 - opcache.interned_strings_buffer overridden per pool must not crash on restart +--EXTENSIONS-- +opcache +--SKIPIF-- + +--FILE-- +start(iniEntries: [ + 'opcache.enable' => '1', + 'opcache.enable_cli' => '1', + 'opcache.interned_strings_buffer' => '0', +]); +$tester->expectLogStartNotices(); +$tester->request()->expectBody('ok'); +$tester->request()->expectBody('ok'); +$tester->request()->expectBody('ok'); +$tester->terminate(); +$tester->expectLogTerminatingNotices(); +$tester->close(); + +?> +Done +--EXPECT-- +Done +--CLEAN-- + From bfab8efe8d0c8acde9edf499bb3f3fcc9904e284 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 16 Aug 2026 12:37:04 +0100 Subject: [PATCH 3/4] fix test attempt --- .../gh23288-opcache-interned-strings-buffer-pool.phpt | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/sapi/fpm/tests/gh23288-opcache-interned-strings-buffer-pool.phpt b/sapi/fpm/tests/gh23288-opcache-interned-strings-buffer-pool.phpt index b64e919b105b..8f48b3a8c209 100644 --- a/sapi/fpm/tests/gh23288-opcache-interned-strings-buffer-pool.phpt +++ b/sapi/fpm/tests/gh23288-opcache-interned-strings-buffer-pool.phpt @@ -16,8 +16,6 @@ error_log = {{FILE:LOG}} listen = {{ADDR}} pm = static pm.max_children = 1 -php_admin_value[opcache.enable] = 1 -php_admin_value[opcache.enable_cli] = 1 php_admin_value[opcache.interned_strings_buffer] = 8 EOT; @@ -28,12 +26,11 @@ opcache_reset(); echo "ok"; EOT; +$opcache = ini_get('extension_dir') . DIRECTORY_SEPARATOR . 'opcache.' . PHP_SHLIB_SUFFIX; +$extraArgs = is_file($opcache) ? ['-dzend_extension=' . $opcache] : []; + $tester = new FPM\Tester($cfg, $code); -$tester->start(iniEntries: [ - 'opcache.enable' => '1', - 'opcache.enable_cli' => '1', - 'opcache.interned_strings_buffer' => '0', -]); +$tester->start($extraArgs, iniEntries: ['opcache.interned_strings_buffer' => '0']); $tester->expectLogStartNotices(); $tester->request()->expectBody('ok'); $tester->request()->expectBody('ok'); From 86b042463737605e55aa731457cc16ca47314d3b Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 18 Aug 2026 18:02:24 +0100 Subject: [PATCH 4/4] apply @TimWolla suggestion --- ext/opcache/ZendAccelerator.c | 2 ++ ext/opcache/zend_accelerator_module.c | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 70f3d8313638..221cc55d9f6d 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -3444,6 +3444,8 @@ void accel_shutdown(void) if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), "include_path", sizeof("include_path")-1)) != NULL) { ini_entry->on_modify = orig_include_path_on_modify; } + + accel_startup_ok = false; } void zend_accel_schedule_restart(zend_accel_restart_reason reason) diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index 2fb7e775bb34..9bc15f45c4b9 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -94,7 +94,11 @@ static ZEND_INI_MH(OnUpdateMemoryConsumption) static ZEND_INI_MH(OnUpdateInternedStringsBuffer) { if (accel_startup_ok) { - zend_accel_error(ACCEL_LOG_WARNING, "opcache.interned_strings_buffer cannot be changed when OPcache is already set up."); + if (strcmp(sapi_module.name, "fpm-cgi") == 0) { + zend_accel_error(ACCEL_LOG_WARNING, "opcache.interned_strings_buffer cannot be changed when OPcache is already set up. Are you using php_admin_value[opcache.interned_strings_buffer] in an individual pool's configuration?\n"); + } else { + zend_accel_error(ACCEL_LOG_WARNING, "opcache.interned_strings_buffer cannot be changed when OPcache is already set up."); + } return FAILURE; }