From 529b1ca4cead2a5e6202940fcf498e9713514ead Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sun, 19 Jul 2026 18:16:22 +0100 Subject: [PATCH 1/6] main: convert unserialize_callback_func global to zend_string* This prevents a reallocation --- ext/standard/var_unserializer.re | 4 ++-- main/main.c | 2 +- main/php_globals.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 4a9b278c116c..c411f4a0eb2d 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -1253,14 +1253,14 @@ object ":" uiv ":" ["] { } /* Check for unserialize callback */ - if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) { + if (PG(unserialize_callback_func) == NULL) { incomplete_class = 1; ce = PHP_IC_ENTRY; break; } /* Call unserialize callback */ - ZVAL_STRING(&user_func, PG(unserialize_callback_func)); + ZVAL_STR(&user_func, PG(unserialize_callback_func)); ZVAL_STR(&args[0], class_name); BG(serialize_lock)++; diff --git a/main/main.c b/main/main.c index e29770a909eb..9a7c64084d28 100644 --- a/main/main.c +++ b/main/main.c @@ -823,7 +823,7 @@ PHP_INI_BEGIN() STD_PHP_INI_BOOLEAN("auto_globals_jit", "1", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, auto_globals_jit, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("short_open_tag", DEFAULT_SHORT_OPEN_TAG, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, short_tags, zend_compiler_globals, compiler_globals) - STD_PHP_INI_ENTRY("unserialize_callback_func", NULL, PHP_INI_ALL, OnUpdateString, unserialize_callback_func, php_core_globals, core_globals) + STD_PHP_INI_ENTRY("unserialize_callback_func", NULL, PHP_INI_ALL, OnUpdateStrNotEmpty, unserialize_callback_func, php_core_globals, core_globals) STD_PHP_INI_ENTRY("serialize_precision", "-1", PHP_INI_ALL, OnSetSerializePrecision, serialize_precision, php_core_globals, core_globals) STD_PHP_INI_ENTRY("arg_separator.output", "&", PHP_INI_ALL, OnUpdateStrNotEmpty, arg_separator.output, php_core_globals, core_globals) STD_PHP_INI_ENTRY("arg_separator.input", "&", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateStrNotEmpty, arg_separator.input, php_core_globals, core_globals) diff --git a/main/php_globals.h b/main/php_globals.h index 0bab9fc95c14..537e1cfd2dc7 100644 --- a/main/php_globals.h +++ b/main/php_globals.h @@ -67,7 +67,7 @@ struct _php_core_globals { char *output_handler; - char *unserialize_callback_func; + zend_string *unserialize_callback_func; zend_long serialize_precision; zend_long memory_limit; From f72377a2c1cd704360bd75ac7a6e6cea35e57582 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sun, 19 Jul 2026 18:22:38 +0100 Subject: [PATCH 2/6] main: convert last_error_lineno global to type uint32_t As this is the expected type for lineno everywhere else in the engine --- ext/standard/basic_functions.c | 2 +- main/main.c | 2 +- main/php_globals.h | 2 +- sapi/cli/php_cli_server.c | 2 +- sapi/phpdbg/phpdbg_info.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index e81050323754..f8fcc01bf5bb 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -1434,7 +1434,7 @@ PHP_FUNCTION(error_get_last) ZVAL_STR_COPY(&tmp, PG(last_error_file)); zend_hash_update(Z_ARR_P(return_value), ZSTR_KNOWN(ZEND_STR_FILE), &tmp); - ZVAL_LONG(&tmp, PG(last_error_lineno)); + ZVAL_LONG(&tmp, (zend_long)PG(last_error_lineno)); zend_hash_update(Z_ARR_P(return_value), ZSTR_KNOWN(ZEND_STR_LINE), &tmp); if (!Z_ISUNDEF(EG(last_fatal_error_backtrace))) { diff --git a/main/main.c b/main/main.c index 9a7c64084d28..81734370628f 100644 --- a/main/main.c +++ b/main/main.c @@ -1344,7 +1344,7 @@ static ZEND_COLD void php_error_cb(int orig_type, zend_string *error_filename, c * be NULL if PG(last_error_message) is not NULL */ if (!zend_string_equals(PG(last_error_message), message) || (!PG(ignore_repeated_source) - && ((PG(last_error_lineno) != (int)error_lineno) + && ((PG(last_error_lineno) != error_lineno) || !zend_string_equals(PG(last_error_file), error_filename)))) { display = 1; } else { diff --git a/main/php_globals.h b/main/php_globals.h index 537e1cfd2dc7..5e6b7a30e85b 100644 --- a/main/php_globals.h +++ b/main/php_globals.h @@ -136,7 +136,7 @@ struct _php_core_globals { bool report_zend_debug; int last_error_type; - int last_error_lineno; + uint32_t last_error_lineno; zend_string *last_error_message; zend_string *last_error_file; diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index 797979b67305..08019f28ca21 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -1219,7 +1219,7 @@ static void php_cli_server_log_response(php_cli_server_client *client, int statu /* error */ if (append_error_message) { - spprintf(&error_buf, 0, " - %s in %s on line %d", + spprintf(&error_buf, 0, " - %s in %s on line %" PRIu32, ZSTR_VAL(PG(last_error_message)), ZSTR_VAL(PG(last_error_file)), PG(last_error_lineno)); if (!error_buf) { efree(basic_buf); diff --git a/sapi/phpdbg/phpdbg_info.c b/sapi/phpdbg/phpdbg_info.c index ee579e81df02..2100d6e7dca4 100644 --- a/sapi/phpdbg/phpdbg_info.c +++ b/sapi/phpdbg/phpdbg_info.c @@ -81,7 +81,7 @@ PHPDBG_INFO(error) /* {{{ */ { if (PG(last_error_message)) { phpdbg_try_access { - phpdbg_writeln("Last error: %s at %s line %d", + phpdbg_writeln("Last error: %s at %s line %" PRIu32, ZSTR_VAL(PG(last_error_message)), ZSTR_VAL(PG(last_error_file)), PG(last_error_lineno)); From 1dd15ec651e2328febca19d764b9fdf75d5a56b7 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sun, 19 Jul 2026 18:23:52 +0100 Subject: [PATCH 3/6] main: group Windows globals together --- main/php_globals.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/main/php_globals.h b/main/php_globals.h index 5e6b7a30e85b..333daab69ff6 100644 --- a/main/php_globals.h +++ b/main/php_globals.h @@ -158,12 +158,10 @@ struct _php_core_globals { bool in_error_log; bool allow_url_include; -#ifdef PHP_WIN32 - bool com_initialized; -#endif bool in_user_include; #ifdef PHP_WIN32 + bool com_initialized; bool windows_show_crt_warning; #endif From f5abb11ac1fa65fcd6d42c581f98ea3b503ab674 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sun, 19 Jul 2026 18:48:03 +0100 Subject: [PATCH 4/6] main: convert doc_root global to zend_string* This remove a strlen() computation. While at it clarify path concatenation code by using the zend_string_concat{2|3} APIs rather than a memcpy and strncpy calls --- main/fopen_wrappers.c | 47 ++++++++++++++++++++++++++++------------- main/main.c | 2 +- main/php_globals.h | 2 +- sapi/cgi/cgi_main.c | 2 +- sapi/fpm/fpm/fpm_main.c | 2 +- 5 files changed, 36 insertions(+), 19 deletions(-) diff --git a/main/fopen_wrappers.c b/main/fopen_wrappers.c index c0f88ad3b5ba..562cf1c63b96 100644 --- a/main/fopen_wrappers.c +++ b/main/fopen_wrappers.c @@ -359,7 +359,6 @@ PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle) char *path_info; zend_string *filename = NULL; zend_string *resolved_path = NULL; - size_t length; bool orig_display_errors; memset(file_handle, 0, sizeof(zend_file_handle)); @@ -372,7 +371,7 @@ PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle) if (s) { /* if there is no path name after the file, do not bother */ char user[32]; /* to try open the directory */ - length = s - (path_info + 2); + size_t length = s - (path_info + 2); if (length > sizeof(user) - 1) { length = sizeof(user) - 1; } @@ -421,19 +420,37 @@ PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle) } } else #endif - if (PG(doc_root) && path_info && (length = strlen(PG(doc_root))) && - IS_ABSOLUTE_PATH(PG(doc_root), length)) { - size_t path_len = strlen(path_info); - filename = zend_string_alloc(length + path_len + 2, 0); - memcpy(ZSTR_VAL(filename), PG(doc_root), length); - if (!IS_SLASH(ZSTR_VAL(filename)[length - 1])) { /* length is never 0 */ - ZSTR_VAL(filename)[length++] = PHP_DIR_SEPARATOR; - } - if (IS_SLASH(path_info[0])) { - length--; - } - strncpy(ZSTR_VAL(filename) + length, path_info, path_len + 1); - ZSTR_LEN(filename) = length + path_len; + if (PG(doc_root) && path_info && IS_ABSOLUTE_PATH(ZSTR_VAL(PG(doc_root)), ZSTR_LEN(PG(doc_root)))) { + const size_t path_len = strlen(path_info); + + /* We need to concatenate two paths together, there are 3 situations: + * - No trailing slash AND no leading slash + * - Trailing slash AND leading slash + * - Either a trailing slash OR a leading slash + * In the first case we need to add a slash, in the second one we need to skip the leading slash, + * and in the third we can just concatenate them together */ + const unsigned int nb_slashes = IS_SLASH(ZSTR_VAL(PG(doc_root))[ZSTR_LEN(PG(doc_root)) - 1]) + IS_SLASH(path_info[0]); + switch (nb_slashes) { + case 0: + filename = zend_string_concat3( + ZSTR_VAL(PG(doc_root)), ZSTR_LEN(PG(doc_root)), + ZEND_STRL("/"), + path_info, path_len + ); + break; + case 1: + filename = zend_string_concat2( + ZSTR_VAL(PG(doc_root)), ZSTR_LEN(PG(doc_root)), + path_info, path_len + ); + break; + case 2: + filename = zend_string_concat2( + ZSTR_VAL(PG(doc_root)), ZSTR_LEN(PG(doc_root)), + path_info + 1, path_len -1 + ); + break; + } } else if (SG(request_info).path_translated) { filename = zend_string_init(SG(request_info).path_translated, strlen(SG(request_info).path_translated), 0); diff --git a/main/main.c b/main/main.c index 81734370628f..aa0fbee68850 100644 --- a/main/main.c +++ b/main/main.c @@ -830,7 +830,7 @@ PHP_INI_BEGIN() STD_PHP_INI_ENTRY("auto_append_file", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateString, auto_append_file, php_core_globals, core_globals) STD_PHP_INI_ENTRY("auto_prepend_file", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateString, auto_prepend_file, php_core_globals, core_globals) - STD_PHP_INI_ENTRY("doc_root", NULL, PHP_INI_SYSTEM, OnUpdateStringUnempty, doc_root, php_core_globals, core_globals) + STD_PHP_INI_ENTRY("doc_root", NULL, PHP_INI_SYSTEM, OnUpdateStrNotEmpty, doc_root, php_core_globals, core_globals) STD_PHP_INI_ENTRY("default_charset", PHP_DEFAULT_CHARSET, PHP_INI_ALL, OnUpdateDefaultCharset, default_charset, sapi_globals_struct, sapi_globals) STD_PHP_INI_ENTRY("default_mimetype", SAPI_DEFAULT_MIMETYPE, PHP_INI_ALL, OnUpdateDefaultMimeTye, default_mimetype, sapi_globals_struct, sapi_globals) STD_PHP_INI_ENTRY("internal_encoding", NULL, PHP_INI_ALL, OnUpdateInternalEncoding, internal_encoding, php_core_globals, core_globals) diff --git a/main/php_globals.h b/main/php_globals.h index 333daab69ff6..74639ffe0d47 100644 --- a/main/php_globals.h +++ b/main/php_globals.h @@ -76,7 +76,7 @@ struct _php_core_globals { char *error_log; - char *doc_root; + zend_string *doc_root; char *user_dir; char *include_path; char *open_basedir; diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c index 7efd8f159d59..22a3c2e83e97 100644 --- a/sapi/cgi/cgi_main.c +++ b/sapi/cgi/cgi_main.c @@ -1221,7 +1221,7 @@ static void init_request_info(fcgi_request *request) size_t script_path_translated_len; if (!env_document_root && PG(doc_root)) { - env_document_root = CGI_PUTENV("DOCUMENT_ROOT", PG(doc_root)); + env_document_root = CGI_PUTENV("DOCUMENT_ROOT", ZSTR_VAL(PG(doc_root))); /* fix docroot */ TRANSLATE_SLASHES(env_document_root); } diff --git a/sapi/fpm/fpm/fpm_main.c b/sapi/fpm/fpm/fpm_main.c index 3a8435f9e6cc..c25de4b06759 100644 --- a/sapi/fpm/fpm/fpm_main.c +++ b/sapi/fpm/fpm/fpm_main.c @@ -1083,7 +1083,7 @@ static void init_request_info(void) int script_path_translated_len; if (!env_document_root && PG(doc_root)) { - env_document_root = FCGI_PUTENV(request, "DOCUMENT_ROOT", PG(doc_root)); + env_document_root = FCGI_PUTENV(request, "DOCUMENT_ROOT", ZSTR_VAL(PG(doc_root))); } if (!apache_was_here && env_path_translated != NULL && env_redirect_url != NULL && From ba64232dab808492198135e5a42f7ceaf98e8f16 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sun, 19 Jul 2026 18:29:28 +0100 Subject: [PATCH 5/6] main: convert error_log global to zend_string* Allows us to convert a strcmp() call to zend_string_equals_literal() which is less confusing --- main/main.c | 9 +++++---- main/php_globals.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/main/main.c b/main/main.c index aa0fbee68850..82905a564765 100644 --- a/main/main.c +++ b/main/main.c @@ -706,8 +706,9 @@ static PHP_INI_MH(OnUpdateErrorLog) return FAILURE; } } - char **p = ZEND_INI_GET_ADDR(); - *p = new_value && ZSTR_LEN(new_value) > 0 ? ZSTR_VAL(new_value) : NULL; + + zend_string **p = ZEND_INI_GET_ADDR(); + *p = new_value && ZSTR_LEN(new_value) > 0 ? new_value : NULL; return SUCCESS; } /* }}} */ @@ -940,7 +941,7 @@ PHPAPI ZEND_COLD void php_log_err_with_severity(const char *log_message, int sys int error_log_mode; #ifdef HAVE_SYSLOG_H - if (!strcmp(PG(error_log), "syslog")) { + if (zend_string_equals_literal(PG(error_log), "syslog")) { php_syslog(syslog_type_int, "%s", log_message); PG(in_error_log) = 0; return; @@ -953,7 +954,7 @@ PHPAPI ZEND_COLD void php_log_err_with_severity(const char *log_message, int sys error_log_mode = PG(error_log_mode); } - fd = VCWD_OPEN_MODE(PG(error_log), O_CREAT | O_APPEND | O_WRONLY, error_log_mode); + fd = VCWD_OPEN_MODE(ZSTR_VAL(PG(error_log)), O_CREAT | O_APPEND | O_WRONLY, error_log_mode); if (fd != -1) { char *tmp; size_t len; diff --git a/main/php_globals.h b/main/php_globals.h index 74639ffe0d47..45a1b0e44bf5 100644 --- a/main/php_globals.h +++ b/main/php_globals.h @@ -74,7 +74,7 @@ struct _php_core_globals { zend_long max_memory_limit; zend_long max_input_time; - char *error_log; + zend_string *error_log; zend_string *doc_root; char *user_dir; From 41e2f2a8def2cbf6c1dfc04711ebe5c52052c2bf Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sun, 19 Jul 2026 18:14:44 +0100 Subject: [PATCH 6/6] main: convert output_handler global to zend_string* This prevents a reallocation --- main/main.c | 6 +++--- main/php_globals.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/main/main.c b/main/main.c index 82905a564765..f97039a7d3e1 100644 --- a/main/main.c +++ b/main/main.c @@ -819,7 +819,7 @@ PHP_INI_BEGIN() STD_PHP_INI_BOOLEAN("report_memleaks", "1", PHP_INI_ALL, OnUpdateReportMemleaks, report_memleaks, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("report_zend_debug", "0", PHP_INI_ALL, OnUpdateBool, report_zend_debug, php_core_globals, core_globals) STD_PHP_INI_ENTRY("output_buffering", "0", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateLong, output_buffering, php_core_globals, core_globals) - STD_PHP_INI_ENTRY("output_handler", NULL, PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateString, output_handler, php_core_globals, core_globals) + STD_PHP_INI_ENTRY("output_handler", NULL, PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateStrNotEmpty, output_handler, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("register_argc_argv", "0", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, register_argc_argv, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("auto_globals_jit", "1", PHP_INI_PERDIR|PHP_INI_SYSTEM, OnUpdateBool, auto_globals_jit, php_core_globals, core_globals) STD_PHP_INI_BOOLEAN("short_open_tag", DEFAULT_SHORT_OPEN_TAG, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateBool, short_tags, zend_compiler_globals, compiler_globals) @@ -1915,10 +1915,10 @@ zend_result php_request_startup(void) sapi_add_header(SAPI_PHP_VERSION_HEADER, sizeof(SAPI_PHP_VERSION_HEADER)-1, 1); } - if (PG(output_handler) && PG(output_handler)[0]) { + if (PG(output_handler)) { zval oh; - ZVAL_STRING(&oh, PG(output_handler)); + ZVAL_STR_COPY(&oh, PG(output_handler)); php_output_start_user(&oh, 0, PHP_OUTPUT_HANDLER_STDFLAGS); zval_ptr_dtor(&oh); } else if (PG(output_buffering)) { diff --git a/main/php_globals.h b/main/php_globals.h index 45a1b0e44bf5..e3cfe38a63fd 100644 --- a/main/php_globals.h +++ b/main/php_globals.h @@ -65,7 +65,7 @@ struct _php_core_globals { bool ignore_repeated_source; bool report_memleaks; - char *output_handler; + zend_string *output_handler; zend_string *unserialize_callback_func; zend_long serialize_precision;