From 0f563a232187e98068d41f4b7fd65025b195ed1b Mon Sep 17 00:00:00 2001 From: Edmond <1571649+edmonddantes@users.noreply.github.com> Date: Sun, 23 Aug 2026 17:30:57 +0000 Subject: [PATCH] reactor: the write-failure report is unconditional php-src and this extension move together, so the flag is always there: the #ifdef around it only hid a build that cannot happen. --- CHANGELOG.md | 2 +- libuv_reactor.c | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 337fbfc..0a42b65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- **A write submitted without an awaiter reports its failure on the handle.** `io_pipe_write_cb` and `io_pipe_writev_cb` know the libuv status, but on that path the request is freed here and its `free_cb` takes no status, so the error object was built and released without anyone seeing it — a consumer could only infer the failure from the read side, where a peer that shut its write half down looks exactly like one that is gone. Both callbacks now set `ZEND_ASYNC_IO_WRITE_FAILED` on the io handle, which the reactor never clears. Needs php-src carrying that flag (TrueAsync ABI 0.26.0); against an older one the report is compiled out. +- **A write submitted without an awaiter reports its failure on the handle.** `io_pipe_write_cb` and `io_pipe_writev_cb` know the libuv status, but on that path the request is freed here and its `free_cb` takes no status, so the error object was built and released without anyone seeing it — a consumer could only infer the failure from the read side, where a peer that shut its write half down looks exactly like one that is gone. Both callbacks now set `ZEND_ASYNC_IO_WRITE_FAILED` on the io handle, which the reactor never clears. Needs php-src carrying that flag (TrueAsync ABI 0.26.0). ### Fixed diff --git a/libuv_reactor.c b/libuv_reactor.c index a9ef812..efeac85 100644 --- a/libuv_reactor.c +++ b/libuv_reactor.c @@ -4926,13 +4926,10 @@ static void io_pipe_write_cb(uv_write_t *write_request, int status) async_new_exception(async_ce_input_output_exception, "Pipe write error: %s", uv_strerror(status)); /* The handle carries the verdict because the request may not: a - * fire-and-forget write is freed here, and its free_cb takes no status. - * Guarded because php-src carries the flag only from ABI 0.26.0. */ -#ifdef ZEND_ASYNC_IO_WRITE_FAILED + * fire-and-forget write is freed here, and its free_cb takes no status. */ if (io != NULL) { io->base.state |= ZEND_ASYNC_IO_WRITE_FAILED; } -#endif } req->base.completed = true; @@ -5005,11 +5002,9 @@ static void io_pipe_writev_cb(uv_write_t *write_request, int status) /* See io_pipe_write_cb: the handle keeps the verdict for a caller whose * completion carries none. */ -#ifdef ZEND_ASYNC_IO_WRITE_FAILED if (req->io != NULL) { req->io->base.state |= ZEND_ASYNC_IO_WRITE_FAILED; } -#endif } req->base.completed = true;