Project

General

Profile

Actions

Bug #22391

closed

Fix propagation of `errno` in `rb_io_maybe_wait`.

Bug #22391: Fix propagation of `errno` in `rb_io_maybe_wait`.

Added by ioquatix (Samuel Williams) about 7 hours ago. Updated about 7 hours ago.

Status:
Closed
Target version:
-
[ruby-core:126882]

Description

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

Actions

Also available in: PDF Atom