From 207dcb95746ccc318654a1994b653736bcd6392a Mon Sep 17 00:00:00 2001 From: lazerg Date: Mon, 26 Oct 2026 14:21:06 +0500 Subject: [PATCH 1/3] Fix GH-24731: Assertion failure on bailout in header_register_callback() --- NEWS | 3 +++ main/SAPI.c | 5 ++++- tests/basic/gh24731.phpt | 22 ++++++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/basic/gh24731.phpt diff --git a/NEWS b/NEWS index 5ea9ecbafb0b..c4ef8c48fbc1 100644 --- a/NEWS +++ b/NEWS @@ -30,6 +30,9 @@ PHP NEWS for grouping. (Klaas Skelte van der Werf) . Fixed bug GH-24265 (Unwind/GracefulExit discarded in zend_fiber_execute()). (David Carlier) + . Fixed bug GH-24731 (Assertion failure in zend_objects_store_del() when a + bailout interrupts releasing the header_register_callback() callback). + (lazerg) - Date: . Fixed bug GH-20503 (Assertion failure with ext/date DateInterval property diff --git a/main/SAPI.c b/main/SAPI.c index 4b6b7b0c90e6..7a91f164ce49 100644 --- a/main/SAPI.c +++ b/main/SAPI.c @@ -118,8 +118,11 @@ PHP_FUNCTION(header_register_callback) } if (Z_TYPE(SG(callback_func)) != IS_UNDEF) { - zval_ptr_dtor(&SG(callback_func)); + zval cb; + ZVAL_COPY_VALUE(&cb, &SG(callback_func)); + ZVAL_UNDEF(&SG(callback_func)); SG(fci_cache) = empty_fcall_info_cache; + zval_ptr_dtor(&cb); } /* Don't store callback if headers have already been sent: diff --git a/tests/basic/gh24731.phpt b/tests/basic/gh24731.phpt new file mode 100644 index 000000000000..3aaf1bb4fa88 --- /dev/null +++ b/tests/basic/gh24731.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-24731 (Assertion failure when a bailout interrupts releasing the previous header_register_callback() callback) +--FILE-- + +--EXPECTF-- +Fatal error: Cannot redeclare function f() (previously declared in %s:%d) in %s : eval()'d code on line %d From 26b2a1416f0de6dbc9b198c98145de2a5d6e33b5 Mon Sep 17 00:00:00 2001 From: lazerg Date: Tue, 27 Oct 2026 06:02:09 +0500 Subject: [PATCH 2/3] Release the old header callback after storing the new one A destructor of the old callback may register a new one, which was then overwritten and leaked. --- main/SAPI.c | 14 +++++++------- tests/basic/gh24731.phpt | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/main/SAPI.c b/main/SAPI.c index 7a91f164ce49..32388ddd8abb 100644 --- a/main/SAPI.c +++ b/main/SAPI.c @@ -117,13 +117,10 @@ PHP_FUNCTION(header_register_callback) RETURN_THROWS(); } - if (Z_TYPE(SG(callback_func)) != IS_UNDEF) { - zval cb; - ZVAL_COPY_VALUE(&cb, &SG(callback_func)); - ZVAL_UNDEF(&SG(callback_func)); - SG(fci_cache) = empty_fcall_info_cache; - zval_ptr_dtor(&cb); - } + zval old_cb; + ZVAL_COPY_VALUE(&old_cb, &SG(callback_func)); + ZVAL_UNDEF(&SG(callback_func)); + SG(fci_cache) = empty_fcall_info_cache; /* Don't store callback if headers have already been sent: * It won't get used and we won't have a chance to release it. */ @@ -131,6 +128,9 @@ PHP_FUNCTION(header_register_callback) ZVAL_COPY(&SG(callback_func), &fci.function_name); } + /* Release the old callback last, its destructor may register a new one or bail out. */ + zval_ptr_dtor(&old_cb); + RETURN_TRUE; } /* }}} */ diff --git a/tests/basic/gh24731.phpt b/tests/basic/gh24731.phpt index 3aaf1bb4fa88..fd29a9fc047e 100644 --- a/tests/basic/gh24731.phpt +++ b/tests/basic/gh24731.phpt @@ -15,7 +15,7 @@ $cl = function () use ($c) {}; unset($c); header_register_callback($cl); unset($cl); -header_register_callback('str_repeat'); +header_register_callback(function () {}); echo "Unreachable\n"; ?> --EXPECTF-- From f2470065521e22d567c3efa23788e9e5c338c9ea Mon Sep 17 00:00:00 2001 From: lazerg Date: Tue, 27 Oct 2026 06:56:18 +0500 Subject: [PATCH 3/3] Drop NEWS entry --- NEWS | 3 --- 1 file changed, 3 deletions(-) diff --git a/NEWS b/NEWS index aaf2e85b1d26..60b978e801d3 100644 --- a/NEWS +++ b/NEWS @@ -32,9 +32,6 @@ PHP NEWS zend_fiber_execute()). (David Carlier) . Fixed unmapping of an unrelated range when the aligned chunk mmap fails (Marti2203). - . Fixed bug GH-24731 (Assertion failure in zend_objects_store_del() when a - bailout interrupts releasing the header_register_callback() callback). - (lazerg) - CLI: . Fixed bug GH-24697 (PHP_HTTP_PARSER_STRICT build option doesn't work).