Commit 0acde119451 for php.net

commit 0acde1194513ff69c491f3c1ebe103c3774dc7fd
Author: Gina Peter Banyard <girgias@php.net>
Date:   Sat Mar 7 13:27:04 2026 +0000

    ext/session: Fix memory leak due to multiple exception happening during session abort

    Closes GH-21200

    Co-authored-by: arshidkv12 <arshidkv12@gmail.com>

diff --git a/NEWS b/NEWS
index 5ccf063672d..abe3cc9efb8 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,10 @@ PHP                                                                        NEWS
   . Fixed re-entrancy issue on php_pcre_match_impl, php_pcre_replace_impl,
     php_pcre_split_impl, and php_pcre_grep_impl. (David Carlier)

+- Session:
+  . Fix memory leak due to multiple exception happening during session abort.
+    (arshidkv12)
+
 - SNMP:
   . Fixed bug GH-21336 (SNMP::setSecurity() undefined behavior with
     NULL arguments). (David Carlier)
diff --git a/ext/session/session.c b/ext/session/session.c
index 70e1673d87f..f8d963b4894 100644
--- a/ext/session/session.c
+++ b/ext/session/session.c
@@ -41,6 +41,7 @@
 #include "ext/standard/url_scanner_ex.h"
 #include "ext/standard/info.h"
 #include "zend_smart_str.h"
+#include "zend_exceptions.h"
 #include "ext/standard/url.h"
 #include "ext/standard/basic_functions.h"
 #include "ext/standard/head.h"
@@ -1743,8 +1744,16 @@ PHPAPI php_session_status php_get_session_status(void)
 static zend_result php_session_abort(void) /* {{{ */
 {
 	if (PS(session_status) == php_session_active) {
-		if (PS(mod_data) || PS(mod_user_implemented)) {
+		if ((PS(mod_data) || PS(mod_user_implemented)) && PS(mod)->s_close) {
+			zend_object *old_exception = EG(exception);
+			EG(exception) = NULL;
+
 			PS(mod)->s_close(&PS(mod_data));
+			if (!EG(exception)) {
+				EG(exception) = old_exception;
+			} else if (old_exception) {
+				zend_exception_set_previous(EG(exception), old_exception);
+			}
 		}
 		PS(session_status) = php_session_none;
 		return SUCCESS;
diff --git a/ext/session/tests/sessionhandler_validateid_return_type.phpt b/ext/session/tests/sessionhandler_validateid_return_type.phpt
new file mode 100644
index 00000000000..a1006945882
--- /dev/null
+++ b/ext/session/tests/sessionhandler_validateid_return_type.phpt
@@ -0,0 +1,35 @@
+--TEST--
+SessionHandler::validateId must return bool
+--INI--
+session.use_strict_mode=1
+--EXTENSIONS--
+session
+--SKIPIF--
+<?php include('skipif.inc'); ?>
+--FILE--
+<?php
+class MySession extends SessionHandler {
+    public function validateId($key) {
+        return null;
+    }
+}
+
+$handler = new MySession();
+
+try {
+    session_set_save_handler($handler);
+    session_start();
+} catch (TypeError $e) {
+    echo $e->getMessage(), "\n";
+}
+
+session_write_close();
+
+try {
+    session_start();
+} catch (Throwable $e) {
+    echo $e->getMessage(), "\n";
+}
+?>
+--EXPECTF--
+Session id must be a string
diff --git a/ext/session/tests/user_session_module/session_set_save_handler_class_012.phpt b/ext/session/tests/user_session_module/session_set_save_handler_class_012.phpt
index f96206efbb6..a532dff7f82 100644
--- a/ext/session/tests/user_session_module/session_set_save_handler_class_012.phpt
+++ b/ext/session/tests/user_session_module/session_set_save_handler_class_012.phpt
@@ -43,6 +43,8 @@ public function read($key): string|false {
 --EXPECTF--
 *** Testing session_set_save_handler() : incorrect arguments for existing handler open ***
 Open:
+
+Warning: SessionHandler::close(): Parent session handler is not open in %s on line %d
 SessionHandler::open() expects exactly 2 arguments, 0 given

 Warning: Undefined global variable $_SESSION in %s on line %d