From cd251661f04de2de7efb5623969bb6644c1ad472 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Wed, 18 Oct 2023 10:11:44 -0500 Subject: [PATCH] Only waitReadable if errno was EAGAINish This code previously assumed that all -1 return values from read meant EAGAIN and that we should proceed to selection. If the read result was actually equivalent to EAGAIN, this was correct. If the read result was some other error, we still would proceed to the selection, and in most cases the same or similar error would be raised at that point. However at least one particular case: a "Connection reset" event caused by the other end sending RST (due in this case to SO_LINGER=0), the selection operation did *not* raise any error, and appeared to be readable. As a result we went back to the read, another "Connection reset" was triggered, we assumed it was EAGAIN, and so on. This commit checks the errno for exactly matching EAGAIN or EWOULDBLOCK before performing the selection, otherwise raising an error for the failed read. Fixes #7961 --- core/src/main/java/org/jruby/util/io/OpenFile.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/jruby/util/io/OpenFile.java b/core/src/main/java/org/jruby/util/io/OpenFile.java index 416658c8104e..71523212f826 100644 --- a/core/src/main/java/org/jruby/util/io/OpenFile.java +++ b/core/src/main/java/org/jruby/util/io/OpenFile.java @@ -1295,10 +1295,12 @@ public int fillbuf(ThreadContext context) { r = readInternal(context, this, fd, rbuf.ptr, 0, rbuf.capa); if (r < 0) { - if (waitReadable(context, fd)) { + Errno errno = posix.getErrno(); + if (errno == Errno.EAGAIN || errno == Errno.EWOULDBLOCK + && waitReadable(context, fd)) { continue retry; } - throw context.runtime.newErrnoFromErrno(posix.getErrno(), "channel: " + fd + (pathv != null ? " " + pathv : "")); + throw context.runtime.newErrnoFromErrno(errno, "channel: " + fd + (pathv != null ? " " + pathv : "")); } break; }