From 3931d77ceb13dbd5901a776ae1d904d763c04fae Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Tue, 27 Jan 2026 11:31:37 +0800 Subject: [PATCH] =?UTF-8?q?fix(php):=20=E4=BF=AE=E5=A4=8DPHP=E5=B5=8C?= =?UTF-8?q?=E5=85=A5=E6=A8=A1=E5=BC=8F=E4=B8=8B=E7=9A=84=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E5=92=8C=E5=AD=97=E7=AC=A6=E4=B8=B2=E9=87=8A?= =?UTF-8?q?=E6=94=BE=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在模块注册失败时返回错误码255而不是继续执行 - 在模块启动失败时返回错误码255而不是继续执行 - 添加注释解释PHP内部字符串处理的bug - 在请求关闭时手动从模块表中删除内部字符串以防止重复释放 - 防止use-after-free内存安全问题的发生 --- src/cpp/main.cc | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/cpp/main.cc b/src/cpp/main.cc index 2db6d092..65b4708d 100644 --- a/src/cpp/main.cc +++ b/src/cpp/main.cc @@ -20,13 +20,15 @@ int main(int cpp_argc, char **cpp_argv) { zend_throw_exception_hook = throw_exception; zend_module_entry *module = php_embed_get_module(); - if (zend_register_module_ex(module, MODULE_PERSISTENT) == NULL) { + if (zend_register_module_ex(module, MODULE_PERSISTENT) == NULL) { zend_error(E_ERROR, "Failed to register module [%s]", module->name); - } + return 255; + } - if (zend_startup_module_ex(module) == FAILURE) { + if (zend_startup_module_ex(module) == FAILURE) { zend_error(E_ERROR, "Failed to startup module [%s]", module->name); - } + return 255; + } int rc = 0; #if PPROF_ON @@ -50,10 +52,15 @@ int main(int cpp_argc, char **cpp_argv) { php_app_clean(); php::request_shutdown(); + /** + * There is a bug in PHP's handling of internal strings. All interned strings are released in the request shutdown + * function, but then released again in the php_embed_shutdown function, resulting in a use-after-free issue. These + * must be manually removed from the module table to prevent double release. + */ auto name_len = strlen(module->name); - auto lcname = zend_string_alloc(name_len, module->type == MODULE_PERSISTENT); - zend_str_tolower_copy(ZSTR_VAL(lcname), module->name, name_len); - zend_hash_del(&module_registry, lcname); + auto lcname = zend_string_alloc(name_len, module->type == MODULE_PERSISTENT); + zend_str_tolower_copy(ZSTR_VAL(lcname), module->name, name_len); + zend_hash_del(&module_registry, lcname); php_embed_shutdown();