Skip to content

Commit

Permalink
Avoid direct access to IO internals. (#301)
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix authored Jun 2, 2023
1 parent 779500b commit 3c1f9b8
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 17 deletions.
35 changes: 27 additions & 8 deletions ext/nio4r/bytebuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,26 @@ static VALUE NIO_ByteBuffer_inspect(VALUE self);

#define MARK_UNSET -1

/* Compatibility for Ruby <= 3.1 */
#ifndef HAVE_RB_IO_DESCRIPTOR
static int
io_descriptor_fallback(VALUE io)
{
rb_io_t *fptr;
GetOpenFile(io, fptr);
return fptr->fd;
}
#define rb_io_descriptor io_descriptor_fallback
#endif

static void
io_set_nonblock(VALUE io)
{
rb_io_t *fptr;
GetOpenFile(io, fptr);
rb_io_set_nonblock(fptr);
}

void Init_NIO_ByteBuffer()
{
mNIO = rb_define_module("NIO");
Expand Down Expand Up @@ -281,19 +301,19 @@ static VALUE NIO_ByteBuffer_put(VALUE self, VALUE string)
static VALUE NIO_ByteBuffer_read_from(VALUE self, VALUE io)
{
struct NIO_ByteBuffer *buffer;
rb_io_t *fptr;
ssize_t nbytes, bytes_read;

Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
rb_io_set_nonblock(fptr);

io = rb_convert_type(io, T_FILE, "IO", "to_io");
io_set_nonblock(io);

nbytes = buffer->limit - buffer->position;
if (nbytes == 0) {
rb_raise(cNIO_ByteBuffer_OverflowError, "buffer is full");
}

bytes_read = read(FPTR_TO_FD(fptr), buffer->buffer + buffer->position, nbytes);
bytes_read = read(rb_io_descriptor(io), buffer->buffer + buffer->position, nbytes);

if (bytes_read < 0) {
if (errno == EAGAIN) {
Expand All @@ -311,19 +331,18 @@ static VALUE NIO_ByteBuffer_read_from(VALUE self, VALUE io)
static VALUE NIO_ByteBuffer_write_to(VALUE self, VALUE io)
{
struct NIO_ByteBuffer *buffer;
rb_io_t *fptr;
ssize_t nbytes, bytes_written;

Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
rb_io_set_nonblock(fptr);
io = rb_convert_type(io, T_FILE, "IO", "to_io");
io_set_nonblock(io);

nbytes = buffer->limit - buffer->position;
if (nbytes == 0) {
rb_raise(cNIO_ByteBuffer_UnderflowError, "no data remaining in buffer");
}

bytes_written = write(FPTR_TO_FD(fptr), buffer->buffer + buffer->position, nbytes);
bytes_written = write(rb_io_descriptor(io), buffer->buffer + buffer->position, nbytes);

if (bytes_written < 0) {
if (errno == EAGAIN) {
Expand Down
1 change: 1 addition & 0 deletions ext/nio4r/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
require "mkmf"

have_header("unistd.h")
have_func("rb_io_descriptor")

$defs << "-DEV_USE_LINUXAIO" if have_header("linux/aio_abi.h")
$defs << "-DEV_USE_IOURING" if have_header("linux/io_uring.h")
Expand Down
17 changes: 14 additions & 3 deletions ext/nio4r/monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ static VALUE NIO_Monitor_readiness(VALUE self);
static int NIO_Monitor_symbol2interest(VALUE interests);
static void NIO_Monitor_update_interests(VALUE self, int interests);

/* Compatibility for Ruby <= 3.1 */
#ifndef HAVE_RB_IO_DESCRIPTOR
static int
io_descriptor_fallback(VALUE io)
{
rb_io_t *fptr;
GetOpenFile(io, fptr);
return fptr->fd;
}
#define rb_io_descriptor io_descriptor_fallback
#endif

/* Monitor control how a channel is being waited for by a monitor */
void Init_NIO_Monitor()
{
Expand Down Expand Up @@ -81,7 +93,6 @@ static VALUE NIO_Monitor_initialize(VALUE self, VALUE io, VALUE interests, VALUE
struct NIO_Monitor *monitor;
struct NIO_Selector *selector;
ID interests_id;
rb_io_t *fptr;

interests_id = SYM2ID(interests);

Expand All @@ -97,8 +108,8 @@ static VALUE NIO_Monitor_initialize(VALUE self, VALUE io, VALUE interests, VALUE
rb_raise(rb_eArgError, "invalid event type %s (must be :r, :w, or :rw)", RSTRING_PTR(rb_funcall(interests, rb_intern("inspect"), 0)));
}

GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
ev_io_init(&monitor->ev_io, NIO_Selector_monitor_callback, FPTR_TO_FD(fptr), monitor->interests);
io = rb_convert_type(io, T_FILE, "IO", "to_io");
ev_io_init(&monitor->ev_io, NIO_Selector_monitor_callback, rb_io_descriptor(io), monitor->interests);

rb_ivar_set(self, rb_intern("io"), io);
rb_ivar_set(self, rb_intern("interests"), interests);
Expand Down
6 changes: 0 additions & 6 deletions ext/nio4r/nio4r.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,6 @@ struct NIO_ByteBuffer {
int position, limit, capacity, mark;
};

#ifdef GetReadFile
#define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr)))
#else
#define FPTR_TO_FD(fptr) fptr->fd
#endif /* GetReadFile */

/* Thunk between libev callbacks in NIO::Monitors and NIO::Selectors */
void NIO_Selector_monitor_callback(struct ev_loop *ev_loop, struct ev_io *io, int revents);

Expand Down

0 comments on commit 3c1f9b8

Please sign in to comment.