From b168cc894037620cab82fa82f3ab37a3aab81570 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 5 Oct 2010 15:26:57 -0700 Subject: [PATCH] add kgio_read! methods which may raise EOFError Except EOFError is gently raised to not include a huge backtrace. Large backtraces can be a performance problem on busy servers that malicious clients may exploit to deny service. --- ext/kgio/read_write.c | 38 ++++++++++++++++++++++++++++++++++++++ test/lib_read_write.rb | 10 ++++++++++ 2 files changed, 48 insertions(+) diff --git a/ext/kgio/read_write.c b/ext/kgio/read_write.c index 7f1748a..7466c91 100644 --- a/ext/kgio/read_write.c +++ b/ext/kgio/read_write.c @@ -10,6 +10,17 @@ static VALUE mKgio_WaitReadable, mKgio_WaitWritable; # define USE_MSG_DONTWAIT #endif +NORETURN(static void my_eof_error(void)); + +static void my_eof_error(void) +{ + VALUE exc = rb_exc_new2(rb_eEOFError, ""); + VALUE bt = rb_ary_new(); + + rb_funcall(exc, rb_intern("set_backtrace"), 1, bt); + rb_exc_raise(exc); +} + static void prepare_read(struct io_args *a, int argc, VALUE *argv, VALUE io) { VALUE length; @@ -91,6 +102,18 @@ static VALUE kgio_read(int argc, VALUE *argv, VALUE io) } /* + * Same as Kgio::PipeMethods#kgio_read, except EOFError is raised + * on EOF without a backtrace + */ +static VALUE kgio_read_bang(int argc, VALUE *argv, VALUE io) +{ + VALUE rv = my_read(1, argc, argv, io); + + if (NIL_P(rv)) my_eof_error(); + return rv; +} + +/* * call-seq: * * io.kgio_tryread(maxlen) -> buffer @@ -133,6 +156,18 @@ static VALUE kgio_recv(int argc, VALUE *argv, VALUE io) } /* + * Same as Kgio::SocketMethods#kgio_read, except EOFError is raised + * on EOF without a backtrace + */ +static VALUE kgio_recv_bang(int argc, VALUE *argv, VALUE io) +{ + VALUE rv = my_recv(1, argc, argv, io); + + if (NIL_P(rv)) my_eof_error(); + return rv; +} + +/* * This method may be optimized on some systems (e.g. GNU/Linux) to use * MSG_DONTWAIT to avoid explicitly setting the O_NONBLOCK flag via fcntl. * Otherwise this is the same as Kgio::PipeMethods#kgio_tryread @@ -143,6 +178,7 @@ static VALUE kgio_tryrecv(int argc, VALUE *argv, VALUE io) } #else /* ! USE_MSG_DONTWAIT */ # define kgio_recv kgio_read +# define kgio_recv_bang kgio_read_bang # define kgio_tryrecv kgio_tryread #endif /* USE_MSG_DONTWAIT */ @@ -299,6 +335,7 @@ void init_kgio_read_write(VALUE mKgio) */ mPipeMethods = rb_define_module_under(mKgio, "PipeMethods"); rb_define_method(mPipeMethods, "kgio_read", kgio_read, -1); + rb_define_method(mPipeMethods, "kgio_read!", kgio_read_bang, -1); rb_define_method(mPipeMethods, "kgio_write", kgio_write, 1); rb_define_method(mPipeMethods, "kgio_tryread", kgio_tryread, -1); rb_define_method(mPipeMethods, "kgio_trywrite", kgio_trywrite, 1); @@ -312,6 +349,7 @@ void init_kgio_read_write(VALUE mKgio) */ mSocketMethods = rb_define_module_under(mKgio, "SocketMethods"); rb_define_method(mSocketMethods, "kgio_read", kgio_recv, -1); + rb_define_method(mSocketMethods, "kgio_read!", kgio_recv_bang, -1); rb_define_method(mSocketMethods, "kgio_write", kgio_send, 1); rb_define_method(mSocketMethods, "kgio_tryread", kgio_tryrecv, -1); rb_define_method(mSocketMethods, "kgio_trywrite", kgio_trysend, 1); diff --git a/test/lib_read_write.rb b/test/lib_read_write.rb index 1c8088f..bb5ec42 100644 --- a/test/lib_read_write.rb +++ b/test/lib_read_write.rb @@ -21,6 +21,16 @@ module LibReadWriteTest assert_nil @rd.kgio_read(5) end + def test_read_bang_eof + @wr.close + begin + @rd.kgio_read!(5) + assert false, "should never get here (line:#{__LINE__})" + rescue EOFError => e + assert_equal [], e.backtrace + end + end + def test_tryread_eof @wr.close assert_nil @rd.kgio_tryread(5) -- 2.11.4.GIT