From 9d64180d30e2e2064c0129f088d1f85e8dacc455 Mon Sep 17 00:00:00 2001 From: lazerg Date: Thu, 22 Oct 2026 06:21:10 +0500 Subject: [PATCH 1/2] Fix GH-24491: Static method stream error handler replaces pending exception --- Zend/tests/gh24491.phpt | 24 +++++++++++++++++++ Zend/zend_API.c | 3 +++ ext/standard/tests/streams/gh24491.phpt | 31 +++++++++++++++++++++++++ main/streams/stream_errors.c | 4 +++- 4 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/gh24491.phpt create mode 100644 ext/standard/tests/streams/gh24491.phpt diff --git a/Zend/tests/gh24491.phpt b/Zend/tests/gh24491.phpt new file mode 100644 index 000000000000..ec6e77198350 --- /dev/null +++ b/Zend/tests/gh24491.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-24491: Callable error string leaks when an exception is thrown during zpp +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECT-- +Use of "self" in callables is deprecated diff --git a/Zend/zend_API.c b/Zend/zend_API.c index d83ea43add1b..28439b6e3015 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1096,6 +1096,9 @@ static zend_result zend_parse_arg(uint32_t arg_num, zval *arg, va_list *va, cons zend_expected_type expected_type = zend_parse_arg_impl(arg, va, spec, &error, arg_num); if (expected_type != Z_EXPECTED_LAST) { if (EG(exception)) { + if (error && (expected_type == Z_EXPECTED_FUNC || expected_type == Z_EXPECTED_FUNC_OR_NULL)) { + efree(error); + } return FAILURE; } diff --git a/ext/standard/tests/streams/gh24491.phpt b/ext/standard/tests/streams/gh24491.phpt new file mode 100644 index 000000000000..86a07d566621 --- /dev/null +++ b/ext/standard/tests/streams/gh24491.phpt @@ -0,0 +1,31 @@ +--TEST-- +GH-24491 (Stream error_handler given as 'Class::method' turns the real exception into a TypeError) +--FILE-- + $options])); + } catch (Throwable $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; + var_dump($e->getPrevious()); + } +} + +run(['error_mode' => StreamErrorMode::Exception, 'error_handler' => 'H::handle']); + +set_error_handler(function (int $errno, string $errstr) { + throw new ErrorException($errstr); +}); +run(['error_handler' => ['H', 'handle']]); +?> +--EXPECT-- +StreamException: Failed to open stream: No such file or directory +NULL +ErrorException: fopen(): Failed to open stream: No such file or directory +NULL diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index e2dfa310e614..211cf4df025a 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -370,7 +370,9 @@ static void php_stream_call_error_handler(const zval *handler, zval *errors_arra char *is_callable_error = NULL; if (!zend_is_callable(handler, &fcc, &is_callable_error)) { - zend_type_error("stream error handler must be a valid callback, %s", is_callable_error); + if (!EG(exception)) { + zend_type_error("stream error handler must be a valid callback, %s", is_callable_error); + } efree(is_callable_error); return; } From 43b60ed0600e637773b46220f923f1cd2781ef44 Mon Sep 17 00:00:00 2001 From: lazerg Date: Fri, 23 Oct 2026 23:07:22 +0500 Subject: [PATCH 2/2] Move GH-24491 Zend test to zpp subfolder --- Zend/tests/{ => zpp}/gh24491.phpt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Zend/tests/{ => zpp}/gh24491.phpt (100%) diff --git a/Zend/tests/gh24491.phpt b/Zend/tests/zpp/gh24491.phpt similarity index 100% rename from Zend/tests/gh24491.phpt rename to Zend/tests/zpp/gh24491.phpt