From ff8774b5ce3f6b37e5152d0dc06ae46b7a36d1da Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Thu, 28 May 2026 10:43:37 +0300 Subject: close_range: honor last bound and CLOSE_RANGE_CLOEXEC flag close_range was captured as a single-fd fd_event carrying only first, so the runtime evicted every tracked fd >= first, ignoring the last upper bound and the flags. Bounded calls wrongly dropped still-open higher fds, and CLOSE_RANGE_CLOEXEC (which keeps fds open) was treated as a full close. Reclassify close_range to the two_fd_event kind, mapping fd_a/fd_b/extra to first/last/flags. The runtime now closes only the inclusive [first, last] range (a negative last from ~0U means unbounded) and skips eviction when CLOSE_RANGE_CLOEXEC is set or the syscall fails. Co-Authored-By: Claude Opus 4.7 --- internal/eventloop_state.go | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'internal/eventloop_state.go') diff --git a/internal/eventloop_state.go b/internal/eventloop_state.go index a277e31..40e11c2 100644 --- a/internal/eventloop_state.go +++ b/internal/eventloop_state.go @@ -58,11 +58,19 @@ func (t *fdTracker) delete(fd int32) { delete(t.files, fd) } -func (t *fdTracker) closeRangeFrom(first int32) { +// closeRange removes all tracked fds in the inclusive range [first, last], as +// closed by close_range(2). A negative last means "no upper bound": close_range's +// last argument is an unsigned int, so the common close-everything form ~0U +// arrives here as a negative __s32 and must close every tracked fd >= first. +func (t *fdTracker) closeRange(first, last int32) { for fd := range t.files { - if fd >= first { - delete(t.files, fd) + if fd < first { + continue } + if last >= 0 && fd > last { + continue + } + delete(t.files, fd) } } @@ -113,16 +121,23 @@ func (t *fdTracker) deleteProcFdCache(fd int32, pid uint32) { t.deleteCacheKey(procFdCacheKey(pid, fd)) } -func (t *fdTracker) deleteProcFdCacheFrom(first int32, pid uint32) { +// deleteProcFdCacheRange drops cached procfs resolutions for pid's fds in the +// inclusive range [first, last]. A negative last means "no upper bound" (see +// closeRange for why close_range's last argument can arrive negative). +func (t *fdTracker) deleteProcFdCacheRange(first, last int32, pid uint32) { if t.procFdCache == nil { return } for key := range t.procFdCache { cachePid := uint32(key >> 32) cacheFd := int32(uint32(key)) - if cachePid == pid && cacheFd >= first { - t.deleteCacheKey(key) + if cachePid != pid || cacheFd < first { + continue + } + if last >= 0 && cacheFd > last { + continue } + t.deleteCacheKey(key) } } -- cgit v1.2.3