Commit 4868dd4e020 for php.net
commit 4868dd4e0205658c5397bfb23073151514078cdb
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Mon Aug 24 13:30:00 2026 -0400
ext/session: Abort strict-mode re-creation when create_sid() fails
When a save handler rejects the session ID under session.use_strict_mode,
php_session_initialize() papered over a failing s_create_sid() by generating
an internal ID and carrying on, so reset_id()'s Set-Cookie and SID side
effects ran for a session that never started, and a second failure left
PS(id) NULL. Mirror the primary no-ID branch: abort the session, throw when
no exception is pending, and return FAILURE. Sibling sites audited,
session_regenerate_id() and session_create_id() already NULL-check with
their own error paths.
Closes GH-23847
diff --git a/NEWS b/NEWS
index 4450776530c..6235628cbb1 100644
--- a/NEWS
+++ b/NEWS
@@ -68,6 +68,10 @@ PHP NEWS
. Fixed a heap over-read in the interactive shell prompt when cli.prompt is
set to an empty string. (Ilia Alshanetsky)
+- Session:
+ . Fixed session_start() continuing after a failed create_sid() when
+ session.use_strict_mode rejects the supplied ID. (Ilia Alshanetsky)
+
- Sockets:
. Fixed socket_select() silently truncating sets larger than FD_SETSIZE on
Windows. (David Carlier)
diff --git a/ext/session/session.c b/ext/session/session.c
index 2073ea55fe1..bed25c2ebba 100644
--- a/ext/session/session.c
+++ b/ext/session/session.c
@@ -465,7 +465,11 @@ static zend_result php_session_initialize(void) /* {{{ */
}
PS(id) = PS(mod)->s_create_sid(&PS(mod_data));
if (!PS(id)) {
- PS(id) = php_session_create_id(NULL);
+ php_session_abort();
+ if (!EG(exception)) {
+ zend_throw_error(NULL, "Failed to create session ID: %s (path: %s)", PS(mod)->s_name, PS(save_path));
+ }
+ return FAILURE;
}
if (PS(use_cookies)) {
PS(send_cookie) = 1;
diff --git a/ext/session/tests/user_session_module/session_start_strict_recreate_create_sid_fails.phpt b/ext/session/tests/user_session_module/session_start_strict_recreate_create_sid_fails.phpt
new file mode 100644
index 00000000000..3c3ac1dea32
--- /dev/null
+++ b/ext/session/tests/user_session_module/session_start_strict_recreate_create_sid_fails.phpt
@@ -0,0 +1,49 @@
+--TEST--
+session_start() strict mode re-creation must abort when create_sid fails
+--INI--
+session.use_trans_sid=1
+session.use_only_cookies=0
+error_reporting=E_ALL & ~E_DEPRECATED
+--EXTENSIONS--
+session
+--FILE--
+<?php
+
+class FailingHandler implements SessionHandlerInterface, SessionIdInterface, SessionUpdateTimestampHandlerInterface
+{
+ public function open($path, $name): bool { return true; }
+ public function close(): bool { return true; }
+ public function read($id): string|false { return ''; }
+ public function write($id, $data): bool { return true; }
+ public function destroy($id): bool { return true; }
+ public function gc($max_lifetime): int|false { return 0; }
+ public function updateTimestamp($id, $data): bool { return true; }
+
+ public function create_sid(): string
+ {
+ throw new RuntimeException('create_sid failed');
+ }
+
+ public function validateId($id): bool
+ {
+ return false;
+ }
+}
+
+session_set_save_handler(new FailingHandler(), true);
+session_id(str_repeat('a', 32));
+
+try {
+ var_dump(session_start(['use_strict_mode' => true]));
+} catch (Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+}
+
+var_dump(session_status() === PHP_SESSION_ACTIVE);
+var_dump(defined('SID'));
+
+?>
+--EXPECT--
+Error: Session id must be a string
+bool(false)
+bool(false)