[php-src] PR #23822: Fix GH-22844: Io\Poll watchers after the watched stream is closed
| From: | bukka | Date: | Mon, 21 Sep 2026 13:02:05 +0000 |
| Subject: | [php-src] PR #23822: Fix GH-22844: Io\Poll watchers after the watched stream is closed | ||
| Groups: | php.git-pulls | ||
| Request: | Send a blank email to git-pulls+get-38671@lists.php.net to get a copy of this message | ||
Pull Request: https://github.com/php/php-src/pull/23822
Author: bukka
A StreamPollHandle keeps a reference to the stream resource, but an explicit fclose() still closes
the stream underneath the watcher. The watcher could then no longer resolve its fd, so its backend
registration was left behind: a recycled fd number confused the registry and the poll backend, and
on epoll a duplicated fd could keep the interest alive and hand a freed watcher back from wait().
Streams now keep a list of their watchers and notify them from php_stream_free() before the fd is
closed, so every watcher is unregistered while the fd is still valid. The Context registry is keyed
by the registered fd, which the watcher caches, so remove() no longer depends on the stream and an
fd number reused after a close is detected on add(). A watcher retired by the close reports inactive
and its remove() becomes a no-op. modifyEvents() re-adds a fired one-shot registration that the
backend dropped, and the kqueue backend drops its tracking entry when there is nothing left to
delete.
I tried couple of approaches but ended up following the approach from GH-22848 by @iliaal. It
differs a bit and fixes few more things but the main idea is from there.