From d96579371fdef2c0358fba670926772180573d89 Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Tue, 14 Apr 2026 08:36:04 +0200 Subject: [PATCH 1/5] ext/session: fix missing zval_ptr_dtor for retval in PS_GC_FUNC(user) PS_GC_FUNC(user) did not call zval_ptr_dtor() on the return value of the user GC callback, leaking memory when the callback returned a reference-counted value. All other user handlers (write, destroy, validate_sid, update_timestamp) already free retval correctly. Closes GH-21747 --- NEWS | 4 +++ ext/session/mod_user.c | 1 + .../gh_gc_retval_leak.phpt | 33 +++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 ext/session/tests/user_session_module/gh_gc_retval_leak.phpt diff --git a/NEWS b/NEWS index 881a1765b883..d3031f011961 100644 --- a/NEWS +++ b/NEWS @@ -56,6 +56,10 @@ PHP NEWS . Fixed bug GH-21731 (Random\Engine\Xoshiro256StarStar::__unserialize() accepts all-zero state). (iliaal) +- Session: + . Fixed memory leak when session GC callback return a refcounted value. + (jorgsowa) + - SPL: . Fixed bug GH-21499 (RecursiveArrayIterator getChildren UAF after parent free). (Girgias) diff --git a/ext/session/mod_user.c b/ext/session/mod_user.c index 168c5c7f1d44..78fb6260540a 100644 --- a/ext/session/mod_user.c +++ b/ext/session/mod_user.c @@ -218,6 +218,7 @@ PS_GC_FUNC(user) /* Anything else is some kind of error */ *nrdels = -1; // Error } + zval_ptr_dtor(&retval); return *nrdels; } diff --git a/ext/session/tests/user_session_module/gh_gc_retval_leak.phpt b/ext/session/tests/user_session_module/gh_gc_retval_leak.phpt new file mode 100644 index 000000000000..f04f36c2276b --- /dev/null +++ b/ext/session/tests/user_session_module/gh_gc_retval_leak.phpt @@ -0,0 +1,33 @@ +--TEST-- +session_gc(): user handler returning non-bool/non-int does not leak memory +--INI-- +session.gc_probability=0 +session.save_handler=files +--EXTENSIONS-- +session +--FILE-- + +--EXPECTF-- + +Deprecated: session_set_save_handler(): Providing individual callbacks instead of an object implementing SessionHandlerInterface is deprecated in %s on line %d +bool(false) From 701d8a66d327beae2b83d6c7d53711717bec14fb Mon Sep 17 00:00:00 2001 From: Weilin Du <108666168+LamentXU123@users.noreply.github.com> Date: Tue, 21 Apr 2026 20:37:59 +0800 Subject: [PATCH 2/5] ext/standard: Throw a ValueError when the parameter includes NUL bytes in `putenv` and `getenv` (#21817) --- NEWS | 2 ++ UPGRADING | 2 ++ ext/standard/basic_functions.c | 4 +-- .../putenv_and_getenv_reject_null_bytes.phpt | 35 +++++++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 ext/standard/tests/general_functions/putenv_and_getenv_reject_null_bytes.phpt diff --git a/NEWS b/NEWS index 73a2b3d6637c..22762f98c2ca 100644 --- a/NEWS +++ b/NEWS @@ -170,6 +170,8 @@ PHP NEWS argument value is passed. (Girgias) . linkinfo() now raises a ValueError when the argument is an empty string. (Weilin Du) + . getenv() and putenv() now raises a ValueError when the first argument + contains null bytes. (Weilin Du) - Streams: . Added so_keepalive, tcp_keepidle, tcp_keepintvl and tcp_keepcnt stream diff --git a/UPGRADING b/UPGRADING index 9c3d5a2b29a7..869e265af8a2 100644 --- a/UPGRADING +++ b/UPGRADING @@ -88,6 +88,8 @@ PHP 8.6 UPGRADE NOTES argument value is passed. . array_change_key_case() now raises a ValueError when an invalid $case argument value is passed. + . getenv() and putenv() now raises a ValueError when the first argument + contains null bytes. . linkinfo() now raises a ValueError when the $path argument is empty. . pathinfo() now raises a ValueError when an invalid $flag argument value is passed. diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index ece7f1278f7e..5c6b1ce1d1d1 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -696,7 +696,7 @@ PHP_FUNCTION(getenv) ZEND_PARSE_PARAMETERS_START(0, 2) Z_PARAM_OPTIONAL - Z_PARAM_STRING_OR_NULL(str, str_len) + Z_PARAM_PATH_OR_NULL(str, str_len) Z_PARAM_BOOL(local_only) ZEND_PARSE_PARAMETERS_END(); @@ -739,7 +739,7 @@ PHP_FUNCTION(putenv) #endif ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_STRING(setting, setting_len) + Z_PARAM_PATH(setting, setting_len) ZEND_PARSE_PARAMETERS_END(); if (setting_len == 0 || setting[0] == '=') { diff --git a/ext/standard/tests/general_functions/putenv_and_getenv_reject_null_bytes.phpt b/ext/standard/tests/general_functions/putenv_and_getenv_reject_null_bytes.phpt new file mode 100644 index 000000000000..28a346237338 --- /dev/null +++ b/ext/standard/tests/general_functions/putenv_and_getenv_reject_null_bytes.phpt @@ -0,0 +1,35 @@ +--TEST-- +getenv() and putenv() reject null bytes +--FILE-- +getMessage() . "\n"; + } +} + +$var_name = 'PHP_PUTENV_NUL_TEST'; + +foreach ([ + $var_name . "\0SUFFIX=value", + $var_name . "=va\0lue", +] as $assignment) { + try { + putenv($assignment); + } catch (ValueError $exception) { + echo $exception->getMessage() . "\n"; + } +} + +var_dump(getenv($var_name)); + +?> +--EXPECT-- +getenv(): Argument #1 ($name) must not contain any null bytes +getenv(): Argument #1 ($name) must not contain any null bytes +putenv(): Argument #1 ($assignment) must not contain any null bytes +putenv(): Argument #1 ($assignment) must not contain any null bytes +bool(false) From 8b6b4a6f4b6b2bb48a5643c947c0043abfd38860 Mon Sep 17 00:00:00 2001 From: lamentxu <1372449351@qq.com> Date: Mon, 20 Apr 2026 09:38:28 +0800 Subject: [PATCH 3/5] [skip ci] Tweak paths-ignore Closes GH-21813 --- .github/workflows/test.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 69ba4c0e4865..1c2943c5502c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,12 +3,15 @@ on: push: paths-ignore: &ignore_paths - docs/** + - EXTENSIONS + - LICENSE - NEWS - UPGRADING - UPGRADING.INTERNALS - - '**/README.*' - - CONTRIBUTING.md - - CODING_STANDARDS.md + - '**/*.md' + - '**/*.rst' + - .github/CODEOWNERS + - .github/ISSUE_TEMPLATE/** - .cirrus.yml - .circleci/** branches: From 19598f3a6a3dcb5747ca40324d4ca6730eb49a88 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 21 Apr 2026 14:45:28 +0200 Subject: [PATCH 4/5] [skip ci] Sort paths-ignore and remove cirrus --- .github/workflows/test.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1c2943c5502c..eafedec5eafa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,18 +2,17 @@ name: Test on: push: paths-ignore: &ignore_paths + - .circleci/** + - .github/CODEOWNERS + - .github/ISSUE_TEMPLATE/** + - '**/*.md' + - '**/*.rst' - docs/** - EXTENSIONS - LICENSE - NEWS - UPGRADING - UPGRADING.INTERNALS - - '**/*.md' - - '**/*.rst' - - .github/CODEOWNERS - - .github/ISSUE_TEMPLATE/** - - .cirrus.yml - - .circleci/** branches: - PHP-8.2 - PHP-8.3 From d60e7a18eda1127e22bc430c1accfe07d8cdfc1e Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 21 Apr 2026 15:07:24 +0200 Subject: [PATCH 5/5] [skip ci] Mark curl/bug71523.phpt as online test --- ext/curl/tests/bug71523.phpt | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/curl/tests/bug71523.phpt b/ext/curl/tests/bug71523.phpt index 2cf2477409da..1a01209dbb8b 100644 --- a/ext/curl/tests/bug71523.phpt +++ b/ext/curl/tests/bug71523.phpt @@ -4,6 +4,7 @@ Bug #71523 (Copied handle with new option CURLOPT_HTTPHEADER crashes while curl_ curl --SKIPIF--