Commit 71096cd8738 for php.net

commit 71096cd87382c3df399a349a1ffd36f112b37aea
Author: Gina Peter Banyard <girgias@php.net>
Date:   Fri Feb 6 17:51:48 2026 +0000

    ext/session: use zend_strings for open handler

diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS
index 062e704fb7a..1d8734d9fb0 100644
--- a/UPGRADING.INTERNALS
+++ b/UPGRADING.INTERNALS
@@ -100,6 +100,10 @@ PHP 8.6 INTERNALS UPGRADE NOTES
 - ext/session:
   . php_session_flush() now returns a bool rather than a zend_result.
   . Removed session_adapt_url().
+  . PS_OPEN_ARGS is now defined as
+    `void **mod_data, zend_string *save_path, zend_string *session_name`
+    rather than
+    `void **mod_data, const char *save_path, const char *session_name`

 - ext/standard:
   . _php_error_log() now has a formal return type of zend_result.
diff --git a/ext/session/mod_files.c b/ext/session/mod_files.c
index 869bb1052c6..87bcb7e3690 100644
--- a/ext/session/mod_files.c
+++ b/ext/session/mod_files.c
@@ -369,19 +369,22 @@ PS_OPEN_FUNC(files)
 	int argc = 0;
 	size_t dirdepth = 0;
 	int filemode = 0600;
+	const char *used_save_path;

-	if (*save_path == '\0') {
+	if (ZSTR_LEN(save_path) == 0) {
 		/* if save path is an empty string, determine the temporary dir */
-		save_path = php_get_temporary_directory();
+		used_save_path = php_get_temporary_directory();

-		if (php_check_open_basedir(save_path)) {
+		if (php_check_open_basedir(used_save_path)) {
 			return FAILURE;
 		}
+	} else {
+		used_save_path = ZSTR_VAL(save_path);
 	}

 	/* split up input parameter */
-	last = save_path;
-	p = strchr(save_path, ';');
+	last = used_save_path;
+	p = strchr(used_save_path, ';');
 	while (p) {
 		argv[argc++] = last;
 		last = ++p;
@@ -407,14 +410,14 @@ PS_OPEN_FUNC(files)
 			return FAILURE;
 		}
 	}
-	save_path = argv[argc - 1];
+	used_save_path = argv[argc - 1];

 	data = ecalloc(1, sizeof(*data));

 	data->fd = -1;
 	data->dirdepth = dirdepth;
 	data->filemode = filemode;
-	data->basedir = zend_string_init(save_path, strlen(save_path), /* persistent */ false);
+	data->basedir = zend_string_init(used_save_path, strlen(used_save_path), /* persistent */ false);

 	if (PS_GET_MOD_DATA()) {
 		ps_close_files(mod_data);
diff --git a/ext/session/mod_user.c b/ext/session/mod_user.c
index 5783ca625a4..90b91926a62 100644
--- a/ext/session/mod_user.c
+++ b/ext/session/mod_user.c
@@ -83,12 +83,11 @@ PS_OPEN_FUNC(user)
 {
 	zval args[2];
 	zval retval;
-	zend_result ret = FAILURE;

 	ZEND_ASSERT(!Z_ISUNDEF(PSF(open)));

-	ZVAL_STRING(&args[0], (char*)save_path);
-	ZVAL_STRING(&args[1], (char*)session_name);
+	ZVAL_STR(&args[0], zend_string_dup(save_path, false));
+	ZVAL_STR(&args[1], zend_string_dup(session_name, false));

 	zend_try {
 		ps_call_handler(&PSF(open), 2, args, &retval);
@@ -102,7 +101,7 @@ PS_OPEN_FUNC(user)

 	PS(mod_user_implemented) = true;

-	ret = verify_bool_return_type_userland_calls(&retval);
+	zend_result ret = verify_bool_return_type_userland_calls(&retval);
 	zval_ptr_dtor(&retval);
 	return ret;
 }
diff --git a/ext/session/mod_user_class.c b/ext/session/mod_user_class.c
index 1735423e902..618cc6bd679 100644
--- a/ext/session/mod_user_class.c
+++ b/ext/session/mod_user_class.c
@@ -36,11 +36,10 @@

 PHP_METHOD(SessionHandler, open)
 {
-	char *save_path = NULL, *session_name = NULL;
-	size_t save_path_len, session_name_len;
+	zend_string *save_path, *session_name;
 	zend_result ret;

-	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &save_path, &save_path_len, &session_name, &session_name_len) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &save_path, &session_name) == FAILURE) {
 		RETURN_THROWS();
 	}

diff --git a/ext/session/php_session.h b/ext/session/php_session.h
index 3b7acf15199..8c857d29a5f 100644
--- a/ext/session/php_session.h
+++ b/ext/session/php_session.h
@@ -26,7 +26,7 @@
 #define PHP_SESSION_VERSION PHP_VERSION

 /* save handler macros */
-#define PS_OPEN_ARGS     void **mod_data, const char *save_path, const char *session_name
+#define PS_OPEN_ARGS     void **mod_data, zend_string *save_path, zend_string *session_name
 #define PS_CLOSE_ARGS    void **mod_data
 #define PS_READ_ARGS     void **mod_data, zend_string *key, zend_string **val, zend_long maxlifetime
 #define PS_WRITE_ARGS    void **mod_data, zend_string *key, zend_string *val, zend_long maxlifetime
diff --git a/ext/session/session.c b/ext/session/session.c
index 1630c76cf40..da4e57ff9a1 100644
--- a/ext/session/session.c
+++ b/ext/session/session.c
@@ -424,7 +424,7 @@ static zend_result php_session_initialize(void)
 	}

 	/* Open session handler first */
-	if (PS(mod)->s_open(&PS(mod_data), ZSTR_VAL(PS(save_path)), ZSTR_VAL(PS(session_name))) == FAILURE
+	if (PS(mod)->s_open(&PS(mod_data), PS(save_path), PS(session_name)) == FAILURE
 		/* || PS(mod_data) == NULL */ /* FIXME: open must set valid PS(mod_data) with success */
 	) {
 		php_session_abort();
@@ -2351,7 +2351,7 @@ PHP_FUNCTION(session_regenerate_id)
 	zend_string_release_ex(PS(id), false);
 	PS(id) = NULL;

-	if (PS(mod)->s_open(&PS(mod_data), ZSTR_VAL(PS(save_path)), ZSTR_VAL(PS(session_name))) == FAILURE) {
+	if (PS(mod)->s_open(&PS(mod_data), PS(save_path), PS(session_name)) == FAILURE) {
 		PS(session_status) = php_session_none;
 		if (!EG(exception)) {
 			zend_throw_error(NULL, "Failed to open session: %s (path: %s)", PS(mod)->s_name, ZSTR_VAL(PS(save_path)));