Issue #22391 has been reported by ioquatix (Samuel Williams). ---------------------------------------- Bug #22391: Fix propagation of `ERRNO` in `rb_io_maybe_wait`. https://bugs.ruby-lang.org/issues/22391 * Author: ioquatix (Samuel Williams) * Status: Open * Assignee: ioquatix (Samuel Williams) * Backport: 3.3: REQUIRED, 3.4: REQUIRED, 4.0: REQUIRED ---------------------------------------- When a write returns `EAGAIN`, we call `rb_io_wait()`: io_write() io_fwrite() io_binwrite() io_binwrite_string() io_binwrite_string_internal() ... rb_io_maybe_wait_writable() rb_io_maybe_wait() return rb_io_wait(io, events, timeout) if this wait also fails, it bubbles up to io_write() which reports it: io_write() rb_sys_fail_on_write() rb_syserr_new_path_in() rb_syserr_new_path(errno, ...) `rb_syserr_new_path_in` (after macro resolution) checks for a 0 error code and aborts in that case: if (n == 0) { const char *s = !NIL_P(path) ? RSTRING_PTR(path) : ""; if (!func_name) func_name = "(null)"; rb_bug("rb_sys_fail_path_in(%s, %s) - errno == 0", func_name, s); } Unfortunately, `rb_io_wait()` can invoke the fiber scheduler, running arbitrary code that can clobber `errno` and trigger this `rb_bug()`. Fix this by preserving `errno` explicitly across the `rb_io_wait()` call. https://github.com/ruby/ruby/pull/19121 -- https://bugs.ruby-lang.org/