Commit 0df284a4fcb for php.net
commit 0df284a4fcbb80910d3c427250ef32861917a455
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Wed Jul 29 12:01:44 2026 -0400
ext/session: check the created ID before validating it
session_create_id() passes the return value of s_create_sid() straight
into s_validate_sid(). A userland create_sid() that throws makes
ps_create_sid_user() return NULL, and ps_validate_sid_user() then reaches
ZVAL_STR_COPY() with a NULL key. Stop the retry loop when no ID was
created and propagate a pending exception instead of reporting a plain
failure. The four s_create_sid() call sites in php_session_initialize()
and session_regenerate_id() already test for NULL.
Closes GH-22924
diff --git a/ext/session/session.c b/ext/session/session.c
index 6380505ae95..f03813c791d 100644
--- a/ext/session/session.c
+++ b/ext/session/session.c
@@ -2508,6 +2508,9 @@ PHP_FUNCTION(session_create_id)
int limit = 3;
while (limit--) {
new_id = PS(mod)->s_create_sid(&PS(mod_data));
+ if (!new_id) {
+ break;
+ }
if (!PS(mod)->s_validate_sid || (PS(mod_user_implemented) && Z_ISUNDEF(PS(mod_user_names).ps_validate_sid))) {
break;
} else {
@@ -2529,6 +2532,9 @@ PHP_FUNCTION(session_create_id)
zend_string_release_ex(new_id, 0);
} else {
smart_str_free(&id);
+ if (EG(exception)) {
+ RETURN_THROWS();
+ }
php_error_docref(NULL, E_WARNING, "Failed to create new ID");
RETURN_FALSE;
}
diff --git a/ext/session/tests/user_session_module/session_create_id_create_sid_throws.phpt b/ext/session/tests/user_session_module/session_create_id_create_sid_throws.phpt
new file mode 100644
index 00000000000..b65c0671d94
--- /dev/null
+++ b/ext/session/tests/user_session_module/session_create_id_create_sid_throws.phpt
@@ -0,0 +1,49 @@
+--TEST--
+session_create_id() when the create_sid handler throws
+--INI--
+session.save_handler=files
+session.name=PHPSESSID
+session.gc_probability=0
+--EXTENSIONS--
+session
+--FILE--
+<?php
+
+ob_start();
+
+class MySessionHandler extends SessionHandler
+{
+ public int $calls = 0;
+
+ public function create_sid(): string
+ {
+ if ($this->calls++ > 0) {
+ throw new Exception('create_sid failed');
+ }
+ return parent::create_sid();
+ }
+
+ public function validateId(string $id): bool
+ {
+ return false;
+ }
+}
+
+session_set_save_handler(new MySessionHandler(), true);
+session_start();
+
+try {
+ session_create_id();
+} catch (Throwable $e) {
+ echo $e::class, ": ", $e->getMessage(), PHP_EOL;
+ $previous = $e->getPrevious();
+ echo $previous::class, ": ", $previous->getMessage(), PHP_EOL;
+}
+
+var_dump(session_status() === PHP_SESSION_ACTIVE);
+
+?>
+--EXPECT--
+Error: Session id must be a string
+Exception: create_sid failed
+bool(true)