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