Commit 6da7eabab46 for php.net

commit 6da7eabab46d6324eda6702a03fa2a58e85f1519
Merge: 5467b514f00 28e41a9c475
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date:   Wed Sep 23 12:22:24 2026 -0400

    Merge branch 'PHP-8.5' into PHP-8.6

    * PHP-8.5:
      ext/session: Preserve exceptions thrown by create_sid()

diff --cc NEWS
index b3d2e7ebd6e,a23aba2642b..785273bed94
--- a/NEWS
+++ b/NEWS
@@@ -91,11 -76,9 +91,13 @@@ PH
  - Session:
    . Fixed session_start() continuing after a failed create_sid() when
      session.use_strict_mode rejects the supplied ID. (Ilia Alshanetsky)
+   . Fixed exceptions from user-defined create_sid() handlers being replaced
+     by return-value validation errors. (Ilia Alshanetsky)

 +- SPL:
 +  . Fixed bug GH-23385 (SplDoublyLinkedList::serialize() use-after-free when
 +    __serialize() removes an element). (David Carlier)
 +
  - SQLite:
    . Fixed a crash when SQLite3::close() is called from a userland callback.
      (Ilia Alshanetsky)
diff --cc ext/session/mod_user.c
index 5c6fe557771,61db72b4cf1..174a0e4822e
--- a/ext/session/mod_user.c
+++ b/ext/session/mod_user.c
@@@ -232,15 -243,14 +232,17 @@@ PS_CREATE_SID_FUNC(user
  			return NULL;
  		}

 -		if (!id) {
 +		if (UNEXPECTED(Z_TYPE(retval) != IS_STRING)) {
 +			/* Will no longer be needed in PHP 9 as the interface return type will be in effect */
- 			zend_throw_error(zend_ce_type_error, "Session id must be of type string, %s given", zend_zval_type_name(&retval));
+ 			if (!EG(exception)) {
 -				zend_throw_error(NULL, "Session id must be a string");
++				zend_throw_error(zend_ce_type_error, "Session id must be of type string, %s given", zend_zval_type_name(&retval));
+ 			}
 +			zval_ptr_dtor(&retval);
  			return NULL;
  		}
 +		ZEND_ASSERT(Z_TYPE(retval) == IS_STRING);

 -		return id;
 +		return Z_STR(retval);
  	}

  	/* function as defined by PS_MOD */
diff --cc ext/session/tests/user_session_module/session_create_sid_return_destructor_throws.phpt
index 00000000000,18bb97779e0..7c8c9b1fdc7
mode 000000,100644..100644
--- a/ext/session/tests/user_session_module/session_create_sid_return_destructor_throws.phpt
+++ b/ext/session/tests/user_session_module/session_create_sid_return_destructor_throws.phpt
@@@ -1,0 -1,37 +1,38 @@@
+ --TEST--
+ Exceptions from destruction of an invalid create_sid() return value are preserved
+ --EXTENSIONS--
+ session
+ --FILE--
+ <?php
+
+ class FailingHandler implements SessionHandlerInterface, SessionIdInterface
+ {
+     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 validateId($id): bool { return true; }
+
+     #[ReturnTypeWillChange]
+     public function create_sid()
+     {
+         return new class {
+             public function __destruct()
+             {
+                 throw new RuntimeException('destructor failed');
+             }
+         };
+     }
+ }
+
+ session_set_save_handler(new FailingHandler());
+ try {
+     session_start();
+ } catch (Throwable $e) {
+     echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+ }
+ ?>
+ --EXPECT--
+ RuntimeException: destructor failed